File: /usr/src/linux/fs/lockd/svclock.c
1 /*
2 * linux/fs/lockd/svclock.c
3 *
4 * Handling of server-side locks, mostly of the blocked variety.
5 * This is the ugliest part of lockd because we tread on very thin ice.
6 * GRANT and CANCEL calls may get stuck, meet in mid-flight, etc.
7 * IMNSHO introducing the grant callback into the NLM protocol was one
8 * of the worst ideas Sun ever had. Except maybe for the idea of doing
9 * NFS file locking at all.
10 *
11 * I'm trying hard to avoid race conditions by protecting most accesses
12 * to a file's list of blocked locks through a semaphore. The global
13 * list of blocked locks is not protected in this fashion however.
14 * Therefore, some functions (such as the RPC callback for the async grant
15 * call) move blocked locks towards the head of the list *while some other
16 * process might be traversing it*. This should not be a problem in
17 * practice, because this will only cause functions traversing the list
18 * to visit some blocks twice.
19 *
20 * Copyright (C) 1996, Olaf Kirch <okir@monad.swb.de>
21 */
22
23 #include <linux/config.h>
24 #include <linux/types.h>
25 #include <linux/errno.h>
26 #include <linux/kernel.h>
27 #include <linux/sched.h>
28 #include <linux/smp_lock.h>
29 #include <linux/sunrpc/clnt.h>
30 #include <linux/sunrpc/svc.h>
31 #include <linux/lockd/nlm.h>
32 #include <linux/lockd/lockd.h>
33
34
35 #define NLMDBG_FACILITY NLMDBG_SVCLOCK
36
37 static void nlmsvc_insert_block(struct nlm_block *block, unsigned long);
38 static int nlmsvc_remove_block(struct nlm_block *block);
39 static void nlmsvc_grant_callback(struct rpc_task *task);
40 static void nlmsvc_notify_blocked(struct file_lock *);
41
42 /*
43 * The list of blocked locks to retry
44 */
45 static struct nlm_block * nlm_blocked;
46
47 /*
48 * Insert a blocked lock into the global list
49 */
50 static void
51 nlmsvc_insert_block(struct nlm_block *block, unsigned long when)
52 {
53 struct nlm_block **bp, *b;
54
55 dprintk("lockd: nlmsvc_insert_block(%p, %ld)\n", block, when);
56 if (block->b_queued)
57 nlmsvc_remove_block(block);
58 bp = &nlm_blocked;
59 if (when != NLM_NEVER) {
60 if ((when += jiffies) == NLM_NEVER)
61 when ++;
62 while ((b = *bp) && time_before_eq(b->b_when,when))
63 bp = &b->b_next;
64 } else
65 while ((b = *bp))
66 bp = &b->b_next;
67
68 block->b_queued = 1;
69 block->b_when = when;
70 block->b_next = b;
71 *bp = block;
72 }
73
74 /*
75 * Remove a block from the global list
76 */
77 static int
78 nlmsvc_remove_block(struct nlm_block *block)
79 {
80 struct nlm_block **bp, *b;
81
82 if (!block->b_queued)
83 return 1;
84 for (bp = &nlm_blocked; (b = *bp); bp = &b->b_next) {
85 if (b == block) {
86 *bp = block->b_next;
87 block->b_queued = 0;
88 return 1;
89 }
90 }
91
92 return 0;
93 }
94
95 /*
96 * Find a block for a given lock and optionally remove it from
97 * the list.
98 */
99 static struct nlm_block *
100 nlmsvc_lookup_block(struct nlm_file *file, struct nlm_lock *lock, int remove)
101 {
102 struct nlm_block **head, *block;
103 struct file_lock *fl;
104
105 dprintk("lockd: nlmsvc_lookup_block f=%p pd=%d %Ld-%Ld ty=%d\n",
106 file, lock->fl.fl_pid,
107 (long long)lock->fl.fl_start,
108 (long long)lock->fl.fl_end, lock->fl.fl_type);
109 for (head = &nlm_blocked; (block = *head); head = &block->b_next) {
110 fl = &block->b_call.a_args.lock.fl;
111 dprintk("lockd: check f=%p pd=%d %Ld-%Ld ty=%d cookie=%x\n",
112 block->b_file, fl->fl_pid,
113 (long long)fl->fl_start,
114 (long long)fl->fl_end, fl->fl_type,
115 *(unsigned int*)(block->b_call.a_args.cookie.data));
116 if (block->b_file == file && nlm_compare_locks(fl, &lock->fl)) {
117 if (remove) {
118 *head = block->b_next;
119 block->b_queued = 0;
120 }
121 return block;
122 }
123 }
124
125 return NULL;
126 }
127
128 static inline int nlm_cookie_match(struct nlm_cookie *a, struct nlm_cookie *b)
129 {
130 if(a->len != b->len)
131 return 0;
132 if(memcmp(a->data,b->data,a->len))
133 return 0;
134 return 1;
135 }
136
137 /*
138 * Find a block with a given NLM cookie.
139 */
140 static inline struct nlm_block *
141 nlmsvc_find_block(struct nlm_cookie *cookie)
142 {
143 struct nlm_block *block;
144
145 for (block = nlm_blocked; block; block = block->b_next) {
146 dprintk("cookie: head of blocked queue %p, block %p\n",
147 nlm_blocked, block);
148 if (nlm_cookie_match(&block->b_call.a_args.cookie,cookie))
149 break;
150 }
151
152 return block;
153 }
154
155 /*
156 * Create a block and initialize it.
157 *
158 * Note: we explicitly set the cookie of the grant reply to that of
159 * the blocked lock request. The spec explicitly mentions that the client
160 * should _not_ rely on the callback containing the same cookie as the
161 * request, but (as I found out later) that's because some implementations
162 * do just this. Never mind the standards comittees, they support our
163 * logging industries.
164 */
165 static inline struct nlm_block *
166 nlmsvc_create_block(struct svc_rqst *rqstp, struct nlm_file *file,
167 struct nlm_lock *lock, struct nlm_cookie *cookie)
168 {
169 struct nlm_block *block;
170 struct nlm_host *host;
171 struct nlm_rqst *call;
172
173 /* Create host handle for callback */
174 host = nlmclnt_lookup_host(&rqstp->rq_addr,
175 rqstp->rq_prot, rqstp->rq_vers);
176 if (host == NULL)
177 return NULL;
178
179 /* Allocate memory for block, and initialize arguments */
180 if (!(block = (struct nlm_block *) kmalloc(sizeof(*block), GFP_KERNEL)))
181 goto failed;
182 memset(block, 0, sizeof(*block));
183 locks_init_lock(&block->b_call.a_args.lock.fl);
184 locks_init_lock(&block->b_call.a_res.lock.fl);
185
186 if (!nlmclnt_setgrantargs(&block->b_call, lock))
187 goto failed_free;
188
189 /* Set notifier function for VFS, and init args */
190 block->b_call.a_args.lock.fl.fl_notify = nlmsvc_notify_blocked;
191 block->b_call.a_args.cookie = *cookie; /* see above */
192
193 dprintk("lockd: created block %p...\n", block);
194
195 /* Create and initialize the block */
196 block->b_daemon = rqstp->rq_server;
197 block->b_host = host;
198 block->b_file = file;
199
200 /* Add to file's list of blocks */
201 block->b_fnext = file->f_blocks;
202 file->f_blocks = block;
203
204 /* Set up RPC arguments for callback */
205 call = &block->b_call;
206 call->a_host = host;
207 call->a_flags = RPC_TASK_ASYNC;
208
209 return block;
210
211 failed_free:
212 kfree(block);
213 failed:
214 nlm_release_host(host);
215 return NULL;
216 }
217
218 /*
219 * Delete a block. If the lock was cancelled or the grant callback
220 * failed, unlock is set to 1.
221 * It is the caller's responsibility to check whether the file
222 * can be closed hereafter.
223 */
224 static void
225 nlmsvc_delete_block(struct nlm_block *block, int unlock)
226 {
227 struct file_lock *fl = &block->b_call.a_args.lock.fl;
228 struct nlm_file *file = block->b_file;
229 struct nlm_block **bp;
230
231 dprintk("lockd: deleting block %p...\n", block);
232
233 /* Remove block from list */
234 nlmsvc_remove_block(block);
235
236 /* If granted, unlock it, else remove from inode block list */
237 if (unlock && block->b_granted) {
238 dprintk("lockd: deleting granted lock\n");
239 fl->fl_type = F_UNLCK;
240 posix_lock_file(&block->b_file->f_file, fl, 0);
241 block->b_granted = 0;
242 } else {
243 dprintk("lockd: unblocking blocked lock\n");
244 posix_unblock_lock(fl);
245 }
246
247 /* If the block is in the middle of a GRANT callback,
248 * don't kill it yet. */
249 if (block->b_incall) {
250 nlmsvc_insert_block(block, NLM_NEVER);
251 block->b_done = 1;
252 return;
253 }
254
255 /* Remove block from file's list of blocks */
256 for (bp = &file->f_blocks; *bp; bp = &(*bp)->b_fnext) {
257 if (*bp == block) {
258 *bp = block->b_fnext;
259 break;
260 }
261 }
262
263 if (block->b_host)
264 nlm_release_host(block->b_host);
265 nlmclnt_freegrantargs(&block->b_call);
266 kfree(block);
267 }
268
269 /*
270 * Loop over all blocks and perform the action specified.
271 * (NLM_ACT_CHECK handled by nlmsvc_inspect_file).
272 */
273 int
274 nlmsvc_traverse_blocks(struct nlm_host *host, struct nlm_file *file, int action)
275 {
276 struct nlm_block *block, *next;
277
278 down(&file->f_sema);
279 for (block = file->f_blocks; block; block = next) {
280 next = block->b_fnext;
281 if (action == NLM_ACT_MARK)
282 block->b_host->h_inuse = 1;
283 else if (action == NLM_ACT_UNLOCK) {
284 if (host == NULL || host == block->b_host)
285 nlmsvc_delete_block(block, 1);
286 }
287 }
288 up(&file->f_sema);
289 return 0;
290 }
291
292 /*
293 * Attempt to establish a lock, and if it can't be granted, block it
294 * if required.
295 */
296 u32
297 nlmsvc_lock(struct svc_rqst *rqstp, struct nlm_file *file,
298 struct nlm_lock *lock, int wait, struct nlm_cookie *cookie)
299 {
300 struct file_lock *conflock;
301 struct nlm_block *block;
302 int error;
303
304 dprintk("lockd: nlmsvc_lock(%04x/%ld, ty=%d, pi=%d, %Ld-%Ld, bl=%d)\n",
305 file->f_file.f_dentry->d_inode->i_dev,
306 file->f_file.f_dentry->d_inode->i_ino,
307 lock->fl.fl_type, lock->fl.fl_pid,
308 (long long)lock->fl.fl_start,
309 (long long)lock->fl.fl_end,
310 wait);
311
312 /* Lock file against concurrent access */
313 down(&file->f_sema);
314
315 /* Get existing block (in case client is busy-waiting) */
316 block = nlmsvc_lookup_block(file, lock, 0);
317
318 lock->fl.fl_flags |= FL_LOCKD;
319
320 again:
321 if (!(conflock = posix_test_lock(&file->f_file, &lock->fl))) {
322 error = posix_lock_file(&file->f_file, &lock->fl, 0);
323
324 if (block)
325 nlmsvc_delete_block(block, 0);
326 up(&file->f_sema);
327
328 dprintk("lockd: posix_lock_file returned %d\n", -error);
329 switch(-error) {
330 case 0:
331 return nlm_granted;
332 case EDEADLK:
333 #ifdef CONFIG_LOCKD_V4
334 return nlm4_deadlock; /* will be downgraded to lck_deined if this
335 * is a NLMv1,3 request */
336 #else
337 /* no applicable NLM status */
338 #endif
339 case EAGAIN:
340 return nlm_lck_denied;
341 default: /* includes ENOLCK */
342 return nlm_lck_denied_nolocks;
343 }
344 }
345
346 if (!wait) {
347 up(&file->f_sema);
348 return nlm_lck_denied;
349 }
350
351 /* If we don't have a block, create and initialize it. Then
352 * retry because we may have slept in kmalloc. */
353 if (block == NULL) {
354 dprintk("lockd: blocking on this lock (allocating).\n");
355 if (!(block = nlmsvc_create_block(rqstp, file, lock, cookie)))
356 return nlm_lck_denied_nolocks;
357 goto again;
358 }
359
360 /* Append to list of blocked */
361 nlmsvc_insert_block(block, NLM_NEVER);
362
363 if (list_empty(&block->b_call.a_args.lock.fl.fl_block)) {
364 /* Now add block to block list of the conflicting lock
365 if we haven't done so. */
366 dprintk("lockd: blocking on this lock.\n");
367 posix_block_lock(conflock, &block->b_call.a_args.lock.fl);
368 }
369
370 up(&file->f_sema);
371 return nlm_lck_blocked;
372 }
373
374 /*
375 * Test for presence of a conflicting lock.
376 */
377 u32
378 nlmsvc_testlock(struct nlm_file *file, struct nlm_lock *lock,
379 struct nlm_lock *conflock)
380 {
381 struct file_lock *fl;
382
383 dprintk("lockd: nlmsvc_testlock(%04x/%ld, ty=%d, %Ld-%Ld)\n",
384 file->f_file.f_dentry->d_inode->i_dev,
385 file->f_file.f_dentry->d_inode->i_ino,
386 lock->fl.fl_type,
387 (long long)lock->fl.fl_start,
388 (long long)lock->fl.fl_end);
389
390 if ((fl = posix_test_lock(&file->f_file, &lock->fl)) != NULL) {
391 dprintk("lockd: conflicting lock(ty=%d, %Ld-%Ld)\n",
392 fl->fl_type, (long long)fl->fl_start,
393 (long long)fl->fl_end);
394 conflock->caller = "somehost"; /* FIXME */
395 conflock->oh.len = 0; /* don't return OH info */
396 conflock->fl = *fl;
397 return nlm_lck_denied;
398 }
399
400 return nlm_granted;
401 }
402
403 /*
404 * Remove a lock.
405 * This implies a CANCEL call: We send a GRANT_MSG, the client replies
406 * with a GRANT_RES call which gets lost, and calls UNLOCK immediately
407 * afterwards. In this case the block will still be there, and hence
408 * must be removed.
409 */
410 u32
411 nlmsvc_unlock(struct nlm_file *file, struct nlm_lock *lock)
412 {
413 int error;
414
415 dprintk("lockd: nlmsvc_unlock(%04x/%ld, pi=%d, %Ld-%Ld)\n",
416 file->f_file.f_dentry->d_inode->i_dev,
417 file->f_file.f_dentry->d_inode->i_ino,
418 lock->fl.fl_pid,
419 (long long)lock->fl.fl_start,
420 (long long)lock->fl.fl_end);
421
422 /* First, cancel any lock that might be there */
423 nlmsvc_cancel_blocked(file, lock);
424
425 lock->fl.fl_type = F_UNLCK;
426 error = posix_lock_file(&file->f_file, &lock->fl, 0);
427
428 return (error < 0)? nlm_lck_denied_nolocks : nlm_granted;
429 }
430
431 /*
432 * Cancel a previously blocked request.
433 *
434 * A cancel request always overrides any grant that may currently
435 * be in progress.
436 * The calling procedure must check whether the file can be closed.
437 */
438 u32
439 nlmsvc_cancel_blocked(struct nlm_file *file, struct nlm_lock *lock)
440 {
441 struct nlm_block *block;
442
443 dprintk("lockd: nlmsvc_cancel(%04x/%ld, pi=%d, %Ld-%Ld)\n",
444 file->f_file.f_dentry->d_inode->i_dev,
445 file->f_file.f_dentry->d_inode->i_ino,
446 lock->fl.fl_pid,
447 (long long)lock->fl.fl_start,
448 (long long)lock->fl.fl_end);
449
450 down(&file->f_sema);
451 if ((block = nlmsvc_lookup_block(file, lock, 1)) != NULL)
452 nlmsvc_delete_block(block, 1);
453 up(&file->f_sema);
454 return nlm_granted;
455 }
456
457 /*
458 * Unblock a blocked lock request. This is a callback invoked from the
459 * VFS layer when a lock on which we blocked is removed.
460 *
461 * This function doesn't grant the blocked lock instantly, but rather moves
462 * the block to the head of nlm_blocked where it can be picked up by lockd.
463 */
464 static void
465 nlmsvc_notify_blocked(struct file_lock *fl)
466 {
467 struct nlm_block **bp, *block;
468
469 dprintk("lockd: VFS unblock notification for block %p\n", fl);
470 posix_unblock_lock(fl);
471 for (bp = &nlm_blocked; (block = *bp); bp = &block->b_next) {
472 if (nlm_compare_locks(&block->b_call.a_args.lock.fl, fl)) {
473 nlmsvc_insert_block(block, 0);
474 svc_wake_up(block->b_daemon);
475 return;
476 }
477 }
478
479 printk(KERN_WARNING "lockd: notification for unknown block!\n");
480 }
481
482 /*
483 * Try to claim a lock that was previously blocked.
484 *
485 * Note that we use both the RPC_GRANTED_MSG call _and_ an async
486 * RPC thread when notifying the client. This seems like overkill...
487 * Here's why:
488 * - we don't want to use a synchronous RPC thread, otherwise
489 * we might find ourselves hanging on a dead portmapper.
490 * - Some lockd implementations (e.g. HP) don't react to
491 * RPC_GRANTED calls; they seem to insist on RPC_GRANTED_MSG calls.
492 */
493 static void
494 nlmsvc_grant_blocked(struct nlm_block *block)
495 {
496 struct nlm_file *file = block->b_file;
497 struct nlm_lock *lock = &block->b_call.a_args.lock;
498 struct file_lock *conflock;
499 int error;
500
501 dprintk("lockd: grant blocked lock %p\n", block);
502
503 /* First thing is lock the file */
504 down(&file->f_sema);
505
506 /* Unlink block request from list */
507 nlmsvc_remove_block(block);
508
509 /* If b_granted is true this means we've been here before.
510 * Just retry the grant callback, possibly refreshing the RPC
511 * binding */
512 if (block->b_granted) {
513 nlm_rebind_host(block->b_host);
514 goto callback;
515 }
516
517 /* Try the lock operation again */
518 if ((conflock = posix_test_lock(&file->f_file, &lock->fl)) != NULL) {
519 /* Bummer, we blocked again */
520 dprintk("lockd: lock still blocked\n");
521 nlmsvc_insert_block(block, NLM_NEVER);
522 posix_block_lock(conflock, &lock->fl);
523 up(&file->f_sema);
524 return;
525 }
526
527 /* Alright, no conflicting lock. Now lock it for real. If the
528 * following yields an error, this is most probably due to low
529 * memory. Retry the lock in a few seconds.
530 */
531 if ((error = posix_lock_file(&file->f_file, &lock->fl, 0)) < 0) {
532 printk(KERN_WARNING "lockd: unexpected error %d in %s!\n",
533 -error, __FUNCTION__);
534 nlmsvc_insert_block(block, 10 * HZ);
535 up(&file->f_sema);
536 return;
537 }
538
539 callback:
540 /* Lock was granted by VFS. */
541 dprintk("lockd: GRANTing blocked lock.\n");
542 block->b_granted = 1;
543 block->b_incall = 1;
544
545 /* Schedule next grant callback in 30 seconds */
546 nlmsvc_insert_block(block, 30 * HZ);
547
548 /* Call the client */
549 nlm_get_host(block->b_call.a_host);
550 if (nlmsvc_async_call(&block->b_call, NLMPROC_GRANTED_MSG,
551 nlmsvc_grant_callback) < 0)
552 nlm_release_host(block->b_call.a_host);
553 up(&file->f_sema);
554 }
555
556 /*
557 * This is the callback from the RPC layer when the NLM_GRANTED_MSG
558 * RPC call has succeeded or timed out.
559 * Like all RPC callbacks, it is invoked by the rpciod process, so it
560 * better not sleep. Therefore, we put the blocked lock on the nlm_blocked
561 * chain once more in order to have it removed by lockd itself (which can
562 * then sleep on the file semaphore without disrupting e.g. the nfs client).
563 */
564 static void
565 nlmsvc_grant_callback(struct rpc_task *task)
566 {
567 struct nlm_rqst *call = (struct nlm_rqst *) task->tk_calldata;
568 struct nlm_block *block;
569 unsigned long timeout;
570
571 dprintk("lockd: GRANT_MSG RPC callback\n");
572 dprintk("callback: looking for cookie %x \n",
573 *(unsigned int *)(call->a_args.cookie.data));
574 if (!(block = nlmsvc_find_block(&call->a_args.cookie))) {
575 dprintk("lockd: no block for cookie %x\n", *(u32 *)(call->a_args.cookie.data));
576 return;
577 }
578
579 /* Technically, we should down the file semaphore here. Since we
580 * move the block towards the head of the queue only, no harm
581 * can be done, though. */
582 if (task->tk_status < 0) {
583 /* RPC error: Re-insert for retransmission */
584 timeout = 10 * HZ;
585 } else if (block->b_done) {
586 /* Block already removed, kill it for real */
587 timeout = 0;
588 } else {
589 /* Call was successful, now wait for client callback */
590 timeout = 60 * HZ;
591 }
592 nlmsvc_insert_block(block, timeout);
593 svc_wake_up(block->b_daemon);
594 block->b_incall = 0;
595
596 nlm_release_host(call->a_host);
597 }
598
599 /*
600 * We received a GRANT_RES callback. Try to find the corresponding
601 * block.
602 */
603 void
604 nlmsvc_grant_reply(struct nlm_cookie *cookie, u32 status)
605 {
606 struct nlm_block *block;
607 struct nlm_file *file;
608
609 if (!(block = nlmsvc_find_block(cookie)))
610 return;
611 file = block->b_file;
612
613 file->f_count++;
614 down(&file->f_sema);
615 if ((block = nlmsvc_find_block(cookie)) != NULL) {
616 if (status == NLM_LCK_DENIED_GRACE_PERIOD) {
617 /* Try again in a couple of seconds */
618 nlmsvc_insert_block(block, 10 * HZ);
619 block = NULL;
620 } else {
621 /* Lock is now held by client, or has been rejected.
622 * In both cases, the block should be removed. */
623 file->f_count++;
624 up(&file->f_sema);
625 if (status == NLM_LCK_GRANTED)
626 nlmsvc_delete_block(block, 0);
627 else
628 nlmsvc_delete_block(block, 1);
629 }
630 }
631 if (!block)
632 up(&file->f_sema);
633 nlm_release_file(file);
634 }
635
636 /*
637 * Retry all blocked locks that have been notified. This is where lockd
638 * picks up locks that can be granted, or grant notifications that must
639 * be retransmitted.
640 */
641 unsigned long
642 nlmsvc_retry_blocked(void)
643 {
644 struct nlm_block *block;
645
646 dprintk("nlmsvc_retry_blocked(%p, when=%ld)\n",
647 nlm_blocked,
648 nlm_blocked? nlm_blocked->b_when : 0);
649 while ((block = nlm_blocked)) {
650 if (block->b_when == NLM_NEVER)
651 break;
652 if (time_after(block->b_when,jiffies))
653 break;
654 dprintk("nlmsvc_retry_blocked(%p, when=%ld, done=%d)\n",
655 block, block->b_when, block->b_done);
656 if (block->b_done)
657 nlmsvc_delete_block(block, 0);
658 else
659 nlmsvc_grant_blocked(block);
660 }
661
662 if ((block = nlm_blocked) && block->b_when != NLM_NEVER)
663 return (block->b_when - jiffies);
664
665 return MAX_SCHEDULE_TIMEOUT;
666 }
667