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
;
115 * Find a block with a given NLM cookie.
117 static inline struct nlm_block
*
118 nlmsvc_find_block(u32 cookie
)
120 struct nlm_block
*block
;
122 for (block
= nlm_blocked
; block
; block
= block
->b_next
) {
123 if (block
->b_call
.a_args
.cookie
== cookie
)
131 * Create a block and initialize it.
133 * Note: we explicitly set the cookie of the grant reply to that of
134 * the blocked lock request. The spec explicitly mentions that the client
135 * should _not_ rely on the callback containing the same cookie as the
136 * request, but (as I found out later) that's because some implementations
137 * do just this. Never mind the standards comittees, they support our
138 * logging industries.
140 static inline struct nlm_block
*
141 nlmsvc_create_block(struct svc_rqst
*rqstp
, struct nlm_file
*file
,
142 struct nlm_lock
*lock
, u32 cookie
)
144 struct nlm_block
*block
;
145 struct nlm_host
*host
;
146 struct nlm_rqst
*call
;
148 /* Create host handle for callback */
149 host
= nlmclnt_lookup_host(&rqstp
->rq_addr
,
150 rqstp
->rq_prot
, rqstp
->rq_vers
);
154 /* Allocate memory for block, and initialize arguments */
155 if (!(block
= (struct nlm_block
*) kmalloc(sizeof(*block
), GFP_KERNEL
)))
157 memset(block
, 0, sizeof(*block
));
159 /* Set notifier function for VFS, and init args */
160 lock
->fl
.fl_notify
= nlmsvc_notify_blocked
;
161 if (!nlmclnt_setgrantargs(&block
->b_call
, lock
))
163 block
->b_call
.a_args
.cookie
= cookie
; /* see above */
165 dprintk("lockd: created block %p...\n", block
);
167 /* Create and initialize the block */
168 block
->b_daemon
= rqstp
->rq_server
;
169 block
->b_host
= host
;
170 block
->b_file
= file
;
172 /* Add to file's list of blocks */
173 block
->b_fnext
= file
->f_blocks
;
174 file
->f_blocks
= block
;
176 /* Set up RPC arguments for callback */
177 call
= &block
->b_call
;
179 call
->a_flags
= RPC_TASK_ASYNC
;
186 nlm_release_host(host
);
191 * Delete a block. If the lock was cancelled or the grant callback
192 * failed, unlock is set to 1.
193 * It is the caller's responsibility to check whether the file
194 * can be closed hereafter.
197 nlmsvc_delete_block(struct nlm_block
*block
, int unlock
)
199 struct file_lock
*fl
= &block
->b_call
.a_args
.lock
.fl
;
200 struct nlm_file
*file
= block
->b_file
;
201 struct nlm_block
**bp
;
203 dprintk("lockd: deleting block %p...\n", block
);
205 /* Remove block from list */
206 nlmsvc_remove_block(block
);
208 /* If granted, unlock it, else remove from inode block list */
209 if (unlock
&& block
->b_granted
) {
210 dprintk("lockd: deleting granted lock\n");
211 fl
->fl_type
= F_UNLCK
;
212 posix_lock_file(&block
->b_file
->f_file
, fl
, 0);
213 block
->b_granted
= 0;
215 dprintk("lockd: unblocking blocked lock\n");
216 posix_unblock_lock(fl
);
219 /* If the block is in the middle of a GRANT callback,
220 * don't kill it yet. */
221 if (block
->b_incall
) {
222 nlmsvc_insert_block(block
, NLM_NEVER
);
227 /* Remove block from file's list of blocks */
228 for (bp
= &file
->f_blocks
; *bp
; bp
= &(*bp
)->b_fnext
) {
230 *bp
= block
->b_fnext
;
236 nlm_release_host(block
->b_host
);
237 nlmclnt_freegrantargs(&block
->b_call
);
242 * Loop over all blocks and perform the action specified.
243 * (NLM_ACT_CHECK handled by nlmsvc_inspect_file).
246 nlmsvc_traverse_blocks(struct nlm_host
*host
, struct nlm_file
*file
, int action
)
248 struct nlm_block
*block
, *next
;
251 for (block
= file
->f_blocks
; block
; block
= next
) {
252 next
= block
->b_fnext
;
253 if (action
== NLM_ACT_MARK
)
254 block
->b_host
->h_inuse
= 1;
255 else if (action
== NLM_ACT_UNLOCK
) {
256 if (host
== NULL
|| host
== block
->b_host
)
257 nlmsvc_delete_block(block
, 1);
265 * Attempt to establish a lock, and if it can't be granted, block it
269 nlmsvc_lock(struct svc_rqst
*rqstp
, struct nlm_file
*file
,
270 struct nlm_lock
*lock
, int wait
, u32 cookie
)
272 struct file_lock
*conflock
;
273 struct nlm_block
*block
;
276 dprintk("lockd: nlmsvc_lock(%04x/%ld, ty=%d, pi=%d, %ld-%ld, bl=%d)\n",
277 file
->f_file
.f_dentry
->d_inode
->i_dev
,
278 file
->f_file
.f_dentry
->d_inode
->i_ino
,
279 lock
->fl
.fl_type
, lock
->fl
.fl_pid
,
284 /* Lock file against concurrent access */
287 /* Get existing block (in case client is busy-waiting) */
288 block
= nlmsvc_lookup_block(file
, lock
, 0);
290 lock
->fl
.fl_flags
|= FL_LOCKD
;
293 if (!(conflock
= posix_test_lock(&file
->f_file
, &lock
->fl
))) {
294 error
= posix_lock_file(&file
->f_file
, &lock
->fl
, 0);
297 nlmsvc_delete_block(block
, 0);
300 dprintk("lockd: posix_lock_file returned %d\n", -error
);
304 case EDEADLK
: /* no applicable NLM status */
306 return nlm_lck_denied
;
307 default: /* includes ENOLCK */
308 return nlm_lck_denied_nolocks
;
314 return nlm_lck_denied
;
317 /* If we don't have a block, create and initialize it. Then
318 * retry because we may have slept in kmalloc. */
320 dprintk("lockd: blocking on this lock (allocating).\n");
321 if (!(block
= nlmsvc_create_block(rqstp
, file
, lock
, cookie
)))
322 return nlm_lck_denied_nolocks
;
326 /* Append to list of blocked */
327 nlmsvc_insert_block(block
, NLM_NEVER
);
329 /* Now add block to block list of the conflicting lock */
330 dprintk("lockd: blocking on this lock.\n");
331 posix_block_lock(conflock
, &block
->b_call
.a_args
.lock
.fl
);
334 return nlm_lck_blocked
;
338 * Test for presence of a conflicting lock.
341 nlmsvc_testlock(struct nlm_file
*file
, struct nlm_lock
*lock
,
342 struct nlm_lock
*conflock
)
344 struct file_lock
*fl
;
346 dprintk("lockd: nlmsvc_testlock(%04x/%ld, ty=%d, %ld-%ld)\n",
347 file
->f_file
.f_dentry
->d_inode
->i_dev
,
348 file
->f_file
.f_dentry
->d_inode
->i_ino
,
353 if ((fl
= posix_test_lock(&file
->f_file
, &lock
->fl
)) != NULL
) {
354 dprintk("lockd: conflicting lock(ty=%d, %ld-%ld)\n",
355 fl
->fl_type
, fl
->fl_start
, fl
->fl_end
);
356 conflock
->caller
= "somehost"; /* FIXME */
357 conflock
->oh
.len
= 0; /* don't return OH info */
359 return nlm_lck_denied
;
367 * This implies a CANCEL call: We send a GRANT_MSG, the client replies
368 * with a GRANT_RES call which gets lost, and calls UNLOCK immediately
369 * afterwards. In this case the block will still be there, and hence
373 nlmsvc_unlock(struct nlm_file
*file
, struct nlm_lock
*lock
)
377 dprintk("lockd: nlmsvc_unlock(%04x/%ld, pi=%d, %ld-%ld)\n",
378 file
->f_file
.f_dentry
->d_inode
->i_dev
,
379 file
->f_file
.f_dentry
->d_inode
->i_ino
,
384 /* First, cancel any lock that might be there */
385 nlmsvc_cancel_blocked(file
, lock
);
387 lock
->fl
.fl_type
= F_UNLCK
;
388 error
= posix_lock_file(&file
->f_file
, &lock
->fl
, 0);
390 return (error
< 0)? nlm_lck_denied_nolocks
: nlm_granted
;
394 * Cancel a previously blocked request.
396 * A cancel request always overrides any grant that may currently
398 * The calling procedure must check whether the file can be closed.
401 nlmsvc_cancel_blocked(struct nlm_file
*file
, struct nlm_lock
*lock
)
403 struct nlm_block
*block
;
405 dprintk("lockd: nlmsvc_cancel(%04x/%ld, pi=%d, %ld-%ld)\n",
406 file
->f_file
.f_dentry
->d_inode
->i_dev
,
407 file
->f_file
.f_dentry
->d_inode
->i_ino
,
413 if ((block
= nlmsvc_lookup_block(file
, lock
, 1)) != NULL
)
414 nlmsvc_delete_block(block
, 1);
420 * Unblock a blocked lock request. This is a callback invoked from the
421 * VFS layer when a lock on which we blocked is removed.
423 * This function doesn't grant the blocked lock instantly, but rather moves
424 * the block to the head of nlm_blocked where it can be picked up by lockd.
427 nlmsvc_notify_blocked(struct file_lock
*fl
)
429 struct nlm_block
**bp
, *block
;
431 dprintk("lockd: VFS unblock notification for block %p\n", fl
);
432 posix_unblock_lock(fl
);
433 for (bp
= &nlm_blocked
; (block
= *bp
); bp
= &block
->b_next
) {
434 if (&block
->b_call
.a_args
.lock
.fl
== fl
) {
435 svc_wake_up(block
->b_daemon
);
436 nlmsvc_insert_block(block
, 0);
441 printk(KERN_WARNING
"lockd: notification for unknown block!\n");
445 * Try to claim a lock that was previously blocked.
447 * Note that we use both the RPC_GRANTED_MSG call _and_ an async
448 * RPC thread when notifying the client. This seems like overkill...
450 * - we don't want to use a synchronous RPC thread, otherwise
451 * we might find ourselves hanging on a dead portmapper.
452 * - Some lockd implementations (e.g. HP) don't react to
453 * RPC_GRANTED calls; they seem to insist on RPC_GRANTED_MSG calls.
456 nlmsvc_grant_blocked(struct nlm_block
*block
)
458 struct nlm_file
*file
= block
->b_file
;
459 struct nlm_lock
*lock
= &block
->b_call
.a_args
.lock
;
460 struct file_lock
*conflock
;
463 dprintk("lockd: grant blocked lock %p\n", block
);
465 /* First thing is lock the file */
468 /* Unlink block request from list */
469 nlmsvc_remove_block(block
);
471 /* If b_granted is true this means we've been here before.
472 * Just retry the grant callback, possibly refreshing the RPC
474 if (block
->b_granted
) {
475 nlm_rebind_host(block
->b_host
);
479 /* Try the lock operation again */
480 if ((conflock
= posix_test_lock(&file
->f_file
, &lock
->fl
)) != NULL
) {
481 /* Bummer, we blocked again */
482 dprintk("lockd: lock still blocked\n");
483 nlmsvc_insert_block(block
, NLM_NEVER
);
484 posix_block_lock(conflock
, &lock
->fl
);
489 /* Alright, no conflicting lock. Now lock it for real. If the
490 * following yields an error, this is most probably due to low
491 * memory. Retry the lock in a few seconds.
493 if ((error
= posix_lock_file(&file
->f_file
, &lock
->fl
, 0)) < 0) {
494 printk(KERN_WARNING
"lockd: unexpected error %d in %s!\n",
495 -error
, __FUNCTION__
);
496 nlmsvc_insert_block(block
, jiffies
+ 10 * HZ
);
502 /* Lock was granted by VFS. */
503 dprintk("lockd: GRANTing blocked lock.\n");
504 block
->b_granted
= 1;
507 /* Schedule next grant callback in 30 seconds */
508 nlmsvc_insert_block(block
, jiffies
+ 30 * HZ
);
510 /* Call the client */
511 nlmclnt_async_call(&block
->b_call
, NLMPROC_GRANTED_MSG
,
512 nlmsvc_grant_callback
);
517 * This is the callback from the RPC layer when the NLM_GRANTED_MSG
518 * RPC call has succeeded or timed out.
519 * Like all RPC callbacks, it is invoked by the rpciod process, so it
520 * better not sleep. Therefore, we put the blocked lock on the nlm_blocked
521 * chain once more in order to have it removed by lockd itself (which can
522 * then sleep on the file semaphore without disrupting e.g. the nfs client).
525 nlmsvc_grant_callback(struct rpc_task
*task
)
527 struct nlm_rqst
*call
= (struct nlm_rqst
*) task
->tk_calldata
;
528 struct nlm_block
*block
;
529 unsigned long timeout
;
531 dprintk("lockd: GRANT_MSG RPC callback\n");
532 if (!(block
= nlmsvc_find_block(call
->a_args
.cookie
))) {
533 dprintk("lockd: no block for cookie %x\n", call
->a_args
.cookie
);
537 /* Technically, we should down the file semaphore here. Since we
538 * move the block towards the head of the queue only, no harm
539 * can be done, though. */
540 if (task
->tk_status
< 0) {
541 /* RPC error: Re-insert for retransmission */
542 timeout
= jiffies
+ 10 * HZ
;
543 } else if (block
->b_done
) {
544 /* Block already removed, kill it for real */
547 /* Call was successful, now wait for client callback */
548 timeout
= jiffies
+ 60 * HZ
;
550 nlmsvc_insert_block(block
, timeout
);
551 svc_wake_up(block
->b_daemon
);
554 nlm_release_host(call
->a_host
);
555 rpc_release_task(task
);
559 * We received a GRANT_RES callback. Try to find the corresponding
563 nlmsvc_grant_reply(u32 cookie
, u32 status
)
565 struct nlm_block
*block
;
566 struct nlm_file
*file
;
568 if (!(block
= nlmsvc_find_block(cookie
)))
570 file
= block
->b_file
;
574 if ((block
= nlmsvc_find_block(cookie
)) != NULL
) {
575 if (status
== NLM_LCK_DENIED_GRACE_PERIOD
) {
576 /* Try again in a couple of seconds */
577 nlmsvc_insert_block(block
, jiffies
+ 10 * HZ
);
580 /* Lock is now held by client, or has been rejected.
581 * In both cases, the block should be removed. */
584 if (status
== NLM_LCK_GRANTED
)
585 nlmsvc_delete_block(block
, 0);
587 nlmsvc_delete_block(block
, 1);
592 nlm_release_file(file
);
596 * Retry all blocked locks that have been notified. This is where lockd
597 * picks up locks that can be granted, or grant notifications that must
601 nlmsvc_retry_blocked(void)
603 struct nlm_block
*block
;
605 dprintk("nlmsvc_retry_blocked(%p, when=%ld)\n",
607 nlm_blocked
? nlm_blocked
->b_when
: 0);
608 while ((block
= nlm_blocked
) && block
->b_when
< jiffies
) {
609 dprintk("nlmsvc_retry_blocked(%p, when=%ld, done=%d)\n",
610 block
, block
->b_when
, block
->b_done
);
612 nlmsvc_delete_block(block
, 0);
614 nlmsvc_grant_blocked(block
);
617 if ((block
= nlm_blocked
) && block
->b_when
!= NLM_NEVER
)
618 return block
->b_when
;