2 * linux/fs/lockd/svclock.c
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.
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.
20 * Copyright (C) 1996, Olaf Kirch <okir@monad.swb.de>
23 #include <linux/types.h>
24 #include <linux/errno.h>
25 #include <linux/kernel.h>
26 #include <linux/sunrpc/clnt.h>
27 #include <linux/sunrpc/svc.h>
28 #include <linux/lockd/nlm.h>
29 #include <linux/lockd/lockd.h>
32 #define NLMDBG_FACILITY NLMDBG_SVCLOCK
34 static void nlmsvc_insert_block(struct nlm_block
*block
, unsigned long);
35 static int nlmsvc_remove_block(struct nlm_block
*block
);
36 static void nlmsvc_grant_callback(struct rpc_task
*task
);
37 static void nlmsvc_notify_blocked(struct file_lock
*);
40 * The list of blocked locks to retry
42 static struct nlm_block
* nlm_blocked
= NULL
;
45 * Insert a blocked lock into the global list
48 nlmsvc_insert_block(struct nlm_block
*block
, unsigned long when
)
50 struct nlm_block
**bp
, *b
;
52 dprintk("lockd: nlmsvc_insert_block(%p, %ld)\n", block
, when
);
54 nlmsvc_remove_block(block
);
55 for (bp
= &nlm_blocked
; (b
= *bp
); bp
= &b
->b_next
)
66 * Remove a block from the global list
69 nlmsvc_remove_block(struct nlm_block
*block
)
71 struct nlm_block
**bp
, *b
;
75 for (bp
= &nlm_blocked
; (b
= *bp
); bp
= &b
->b_next
) {
87 * Find a block for a given lock and optionally remove it from
90 static struct nlm_block
*
91 nlmsvc_lookup_block(struct nlm_file
*file
, struct nlm_lock
*lock
, int remove
)
93 struct nlm_block
**head
, *block
;
96 dprintk("lockd: nlmsvc_lookup_block f=%p pd=%d %ld-%ld ty=%d\n",
97 file
, lock
->fl
.fl_pid
, lock
->fl
.fl_start
,
98 lock
->fl
.fl_end
, lock
->fl
.fl_type
);
99 for (head
= &nlm_blocked
; (block
= *head
); head
= &block
->b_next
) {
100 fl
= &block
->b_call
.a_args
.lock
.fl
;
101 dprintk(" check f=%p pd=%d %ld-%ld ty=%d\n",
102 block
->b_file
, fl
->fl_pid
, fl
->fl_start
,
103 fl
->fl_end
, fl
->fl_type
);
104 if (block
->b_file
== file
&& nlm_compare_locks(fl
, &lock
->fl
)) {
106 *head
= block
->b_next
;
114 static inline int nlm_cookie_match(struct nlm_cookie
*a
, struct nlm_cookie
*b
)
118 if(memcmp(a
->data
,b
->data
,a
->len
))
124 * Find a block with a given NLM cookie.
126 static inline struct nlm_block
*
127 nlmsvc_find_block(struct nlm_cookie
*cookie
)
129 struct nlm_block
*block
;
131 for (block
= nlm_blocked
; block
; block
= block
->b_next
) {
132 if (nlm_cookie_match(&block
->b_call
.a_args
.cookie
,cookie
))
140 * Create a block and initialize it.
142 * Note: we explicitly set the cookie of the grant reply to that of
143 * the blocked lock request. The spec explicitly mentions that the client
144 * should _not_ rely on the callback containing the same cookie as the
145 * request, but (as I found out later) that's because some implementations
146 * do just this. Never mind the standards comittees, they support our
147 * logging industries.
149 static inline struct nlm_block
*
150 nlmsvc_create_block(struct svc_rqst
*rqstp
, struct nlm_file
*file
,
151 struct nlm_lock
*lock
, struct nlm_cookie
*cookie
)
153 struct nlm_block
*block
;
154 struct nlm_host
*host
;
155 struct nlm_rqst
*call
;
157 /* Create host handle for callback */
158 host
= nlmclnt_lookup_host(&rqstp
->rq_addr
,
159 rqstp
->rq_prot
, rqstp
->rq_vers
);
163 /* Allocate memory for block, and initialize arguments */
164 if (!(block
= (struct nlm_block
*) kmalloc(sizeof(*block
), GFP_KERNEL
)))
166 memset(block
, 0, sizeof(*block
));
168 /* Set notifier function for VFS, and init args */
169 lock
->fl
.fl_notify
= nlmsvc_notify_blocked
;
170 if (!nlmclnt_setgrantargs(&block
->b_call
, lock
))
172 block
->b_call
.a_args
.cookie
= *cookie
; /* see above */
174 dprintk("lockd: created block %p...\n", block
);
176 /* Create and initialize the block */
177 block
->b_daemon
= rqstp
->rq_server
;
178 block
->b_host
= host
;
179 block
->b_file
= file
;
181 /* Add to file's list of blocks */
182 block
->b_fnext
= file
->f_blocks
;
183 file
->f_blocks
= block
;
185 /* Set up RPC arguments for callback */
186 call
= &block
->b_call
;
188 call
->a_flags
= RPC_TASK_ASYNC
;
195 nlm_release_host(host
);
200 * Delete a block. If the lock was cancelled or the grant callback
201 * failed, unlock is set to 1.
202 * It is the caller's responsibility to check whether the file
203 * can be closed hereafter.
206 nlmsvc_delete_block(struct nlm_block
*block
, int unlock
)
208 struct file_lock
*fl
= &block
->b_call
.a_args
.lock
.fl
;
209 struct nlm_file
*file
= block
->b_file
;
210 struct nlm_block
**bp
;
212 dprintk("lockd: deleting block %p...\n", block
);
214 /* Remove block from list */
215 nlmsvc_remove_block(block
);
217 /* If granted, unlock it, else remove from inode block list */
218 if (unlock
&& block
->b_granted
) {
219 dprintk("lockd: deleting granted lock\n");
220 fl
->fl_type
= F_UNLCK
;
221 posix_lock_file(&block
->b_file
->f_file
, fl
, 0);
222 block
->b_granted
= 0;
224 dprintk("lockd: unblocking blocked lock\n");
225 posix_unblock_lock(fl
);
228 /* If the block is in the middle of a GRANT callback,
229 * don't kill it yet. */
230 if (block
->b_incall
) {
231 nlmsvc_insert_block(block
, NLM_NEVER
);
236 /* Remove block from file's list of blocks */
237 for (bp
= &file
->f_blocks
; *bp
; bp
= &(*bp
)->b_fnext
) {
239 *bp
= block
->b_fnext
;
245 nlm_release_host(block
->b_host
);
246 nlmclnt_freegrantargs(&block
->b_call
);
251 * Loop over all blocks and perform the action specified.
252 * (NLM_ACT_CHECK handled by nlmsvc_inspect_file).
255 nlmsvc_traverse_blocks(struct nlm_host
*host
, struct nlm_file
*file
, int action
)
257 struct nlm_block
*block
, *next
;
260 for (block
= file
->f_blocks
; block
; block
= next
) {
261 next
= block
->b_fnext
;
262 if (action
== NLM_ACT_MARK
)
263 block
->b_host
->h_inuse
= 1;
264 else if (action
== NLM_ACT_UNLOCK
) {
265 if (host
== NULL
|| host
== block
->b_host
)
266 nlmsvc_delete_block(block
, 1);
274 * Attempt to establish a lock, and if it can't be granted, block it
278 nlmsvc_lock(struct svc_rqst
*rqstp
, struct nlm_file
*file
,
279 struct nlm_lock
*lock
, int wait
, struct nlm_cookie
*cookie
)
281 struct file_lock
*conflock
;
282 struct nlm_block
*block
;
285 dprintk("lockd: nlmsvc_lock(%04x/%ld, ty=%d, pi=%d, %ld-%ld, bl=%d)\n",
286 file
->f_file
.f_dentry
->d_inode
->i_dev
,
287 file
->f_file
.f_dentry
->d_inode
->i_ino
,
288 lock
->fl
.fl_type
, lock
->fl
.fl_pid
,
293 /* Lock file against concurrent access */
296 /* Get existing block (in case client is busy-waiting) */
297 block
= nlmsvc_lookup_block(file
, lock
, 0);
299 lock
->fl
.fl_flags
|= FL_LOCKD
;
302 if (!(conflock
= posix_test_lock(&file
->f_file
, &lock
->fl
))) {
303 error
= posix_lock_file(&file
->f_file
, &lock
->fl
, 0);
306 nlmsvc_delete_block(block
, 0);
309 dprintk("lockd: posix_lock_file returned %d\n", -error
);
313 case EDEADLK
: /* no applicable NLM status */
315 return nlm_lck_denied
;
316 default: /* includes ENOLCK */
317 return nlm_lck_denied_nolocks
;
323 return nlm_lck_denied
;
326 /* If we don't have a block, create and initialize it. Then
327 * retry because we may have slept in kmalloc. */
329 dprintk("lockd: blocking on this lock (allocating).\n");
330 if (!(block
= nlmsvc_create_block(rqstp
, file
, lock
, cookie
)))
331 return nlm_lck_denied_nolocks
;
335 /* Append to list of blocked */
336 nlmsvc_insert_block(block
, NLM_NEVER
);
338 if (!block
->b_call
.a_args
.lock
.fl
.fl_prevblock
) {
339 /* Now add block to block list of the conflicting lock
340 if we haven't done so. */
341 dprintk("lockd: blocking on this lock.\n");
342 posix_block_lock(conflock
, &block
->b_call
.a_args
.lock
.fl
);
346 return nlm_lck_blocked
;
350 * Test for presence of a conflicting lock.
353 nlmsvc_testlock(struct nlm_file
*file
, struct nlm_lock
*lock
,
354 struct nlm_lock
*conflock
)
356 struct file_lock
*fl
;
358 dprintk("lockd: nlmsvc_testlock(%04x/%ld, ty=%d, %ld-%ld)\n",
359 file
->f_file
.f_dentry
->d_inode
->i_dev
,
360 file
->f_file
.f_dentry
->d_inode
->i_ino
,
365 if ((fl
= posix_test_lock(&file
->f_file
, &lock
->fl
)) != NULL
) {
366 dprintk("lockd: conflicting lock(ty=%d, %ld-%ld)\n",
367 fl
->fl_type
, fl
->fl_start
, fl
->fl_end
);
368 conflock
->caller
= "somehost"; /* FIXME */
369 conflock
->oh
.len
= 0; /* don't return OH info */
371 return nlm_lck_denied
;
379 * This implies a CANCEL call: We send a GRANT_MSG, the client replies
380 * with a GRANT_RES call which gets lost, and calls UNLOCK immediately
381 * afterwards. In this case the block will still be there, and hence
385 nlmsvc_unlock(struct nlm_file
*file
, struct nlm_lock
*lock
)
389 dprintk("lockd: nlmsvc_unlock(%04x/%ld, pi=%d, %ld-%ld)\n",
390 file
->f_file
.f_dentry
->d_inode
->i_dev
,
391 file
->f_file
.f_dentry
->d_inode
->i_ino
,
396 /* First, cancel any lock that might be there */
397 nlmsvc_cancel_blocked(file
, lock
);
399 lock
->fl
.fl_type
= F_UNLCK
;
400 error
= posix_lock_file(&file
->f_file
, &lock
->fl
, 0);
402 return (error
< 0)? nlm_lck_denied_nolocks
: nlm_granted
;
406 * Cancel a previously blocked request.
408 * A cancel request always overrides any grant that may currently
410 * The calling procedure must check whether the file can be closed.
413 nlmsvc_cancel_blocked(struct nlm_file
*file
, struct nlm_lock
*lock
)
415 struct nlm_block
*block
;
417 dprintk("lockd: nlmsvc_cancel(%04x/%ld, pi=%d, %ld-%ld)\n",
418 file
->f_file
.f_dentry
->d_inode
->i_dev
,
419 file
->f_file
.f_dentry
->d_inode
->i_ino
,
425 if ((block
= nlmsvc_lookup_block(file
, lock
, 1)) != NULL
)
426 nlmsvc_delete_block(block
, 1);
432 * Unblock a blocked lock request. This is a callback invoked from the
433 * VFS layer when a lock on which we blocked is removed.
435 * This function doesn't grant the blocked lock instantly, but rather moves
436 * the block to the head of nlm_blocked where it can be picked up by lockd.
439 nlmsvc_notify_blocked(struct file_lock
*fl
)
441 struct nlm_block
**bp
, *block
;
443 dprintk("lockd: VFS unblock notification for block %p\n", fl
);
444 posix_unblock_lock(fl
);
445 for (bp
= &nlm_blocked
; (block
= *bp
); bp
= &block
->b_next
) {
446 if (nlm_compare_locks(&block
->b_call
.a_args
.lock
.fl
, fl
)) {
447 svc_wake_up(block
->b_daemon
);
448 nlmsvc_insert_block(block
, 0);
453 printk(KERN_WARNING
"lockd: notification for unknown block!\n");
457 * Try to claim a lock that was previously blocked.
459 * Note that we use both the RPC_GRANTED_MSG call _and_ an async
460 * RPC thread when notifying the client. This seems like overkill...
462 * - we don't want to use a synchronous RPC thread, otherwise
463 * we might find ourselves hanging on a dead portmapper.
464 * - Some lockd implementations (e.g. HP) don't react to
465 * RPC_GRANTED calls; they seem to insist on RPC_GRANTED_MSG calls.
468 nlmsvc_grant_blocked(struct nlm_block
*block
)
470 struct nlm_file
*file
= block
->b_file
;
471 struct nlm_lock
*lock
= &block
->b_call
.a_args
.lock
;
472 struct file_lock
*conflock
;
475 dprintk("lockd: grant blocked lock %p\n", block
);
477 /* First thing is lock the file */
480 /* Unlink block request from list */
481 nlmsvc_remove_block(block
);
483 /* If b_granted is true this means we've been here before.
484 * Just retry the grant callback, possibly refreshing the RPC
486 if (block
->b_granted
) {
487 nlm_rebind_host(block
->b_host
);
491 /* Try the lock operation again */
492 if ((conflock
= posix_test_lock(&file
->f_file
, &lock
->fl
)) != NULL
) {
493 /* Bummer, we blocked again */
494 dprintk("lockd: lock still blocked\n");
495 nlmsvc_insert_block(block
, NLM_NEVER
);
496 posix_block_lock(conflock
, &lock
->fl
);
501 /* Alright, no conflicting lock. Now lock it for real. If the
502 * following yields an error, this is most probably due to low
503 * memory. Retry the lock in a few seconds.
505 if ((error
= posix_lock_file(&file
->f_file
, &lock
->fl
, 0)) < 0) {
506 printk(KERN_WARNING
"lockd: unexpected error %d in %s!\n",
507 -error
, __FUNCTION__
);
508 nlmsvc_insert_block(block
, jiffies
+ 10 * HZ
);
514 /* Lock was granted by VFS. */
515 dprintk("lockd: GRANTing blocked lock.\n");
516 block
->b_granted
= 1;
519 /* Schedule next grant callback in 30 seconds */
520 nlmsvc_insert_block(block
, jiffies
+ 30 * HZ
);
522 /* Call the client */
523 nlmclnt_async_call(&block
->b_call
, NLMPROC_GRANTED_MSG
,
524 nlmsvc_grant_callback
);
529 * This is the callback from the RPC layer when the NLM_GRANTED_MSG
530 * RPC call has succeeded or timed out.
531 * Like all RPC callbacks, it is invoked by the rpciod process, so it
532 * better not sleep. Therefore, we put the blocked lock on the nlm_blocked
533 * chain once more in order to have it removed by lockd itself (which can
534 * then sleep on the file semaphore without disrupting e.g. the nfs client).
537 nlmsvc_grant_callback(struct rpc_task
*task
)
539 struct nlm_rqst
*call
= (struct nlm_rqst
*) task
->tk_calldata
;
540 struct nlm_block
*block
;
541 unsigned long timeout
;
543 dprintk("lockd: GRANT_MSG RPC callback\n");
544 if (!(block
= nlmsvc_find_block(&call
->a_args
.cookie
))) {
545 dprintk("lockd: no block for cookie %x\n", *(u32
*)(call
->a_args
.cookie
.data
));
549 /* Technically, we should down the file semaphore here. Since we
550 * move the block towards the head of the queue only, no harm
551 * can be done, though. */
552 if (task
->tk_status
< 0) {
553 /* RPC error: Re-insert for retransmission */
554 timeout
= jiffies
+ 10 * HZ
;
555 } else if (block
->b_done
) {
556 /* Block already removed, kill it for real */
559 /* Call was successful, now wait for client callback */
560 timeout
= jiffies
+ 60 * HZ
;
562 nlmsvc_insert_block(block
, timeout
);
563 svc_wake_up(block
->b_daemon
);
566 nlm_release_host(call
->a_host
);
567 rpc_release_task(task
);
571 * We received a GRANT_RES callback. Try to find the corresponding
575 nlmsvc_grant_reply(struct nlm_cookie
*cookie
, u32 status
)
577 struct nlm_block
*block
;
578 struct nlm_file
*file
;
580 if (!(block
= nlmsvc_find_block(cookie
)))
582 file
= block
->b_file
;
586 if ((block
= nlmsvc_find_block(cookie
)) != NULL
) {
587 if (status
== NLM_LCK_DENIED_GRACE_PERIOD
) {
588 /* Try again in a couple of seconds */
589 nlmsvc_insert_block(block
, jiffies
+ 10 * HZ
);
592 /* Lock is now held by client, or has been rejected.
593 * In both cases, the block should be removed. */
596 if (status
== NLM_LCK_GRANTED
)
597 nlmsvc_delete_block(block
, 0);
599 nlmsvc_delete_block(block
, 1);
604 nlm_release_file(file
);
608 * Retry all blocked locks that have been notified. This is where lockd
609 * picks up locks that can be granted, or grant notifications that must
613 nlmsvc_retry_blocked(void)
615 struct nlm_block
*block
;
617 dprintk("nlmsvc_retry_blocked(%p, when=%ld)\n",
619 nlm_blocked
? nlm_blocked
->b_when
: 0);
620 while ((block
= nlm_blocked
) && block
->b_when
< jiffies
) {
621 dprintk("nlmsvc_retry_blocked(%p, when=%ld, done=%d)\n",
622 block
, block
->b_when
, block
->b_done
);
624 nlmsvc_delete_block(block
, 0);
626 nlmsvc_grant_blocked(block
);
629 if ((block
= nlm_blocked
) && block
->b_when
!= NLM_NEVER
)
630 return (block
->b_when
- jiffies
);
632 return MAX_SCHEDULE_TIMEOUT
;