Branch data Line data Source code
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/types.h>
24 : : #include <linux/slab.h>
25 : : #include <linux/errno.h>
26 : : #include <linux/kernel.h>
27 : : #include <linux/sched.h>
28 : : #include <linux/sunrpc/clnt.h>
29 : : #include <linux/sunrpc/svc_xprt.h>
30 : : #include <linux/lockd/nlm.h>
31 : : #include <linux/lockd/lockd.h>
32 : : #include <linux/kthread.h>
33 : :
34 : : #define NLMDBG_FACILITY NLMDBG_SVCLOCK
35 : :
36 : : #ifdef CONFIG_LOCKD_V4
37 : : #define nlm_deadlock nlm4_deadlock
38 : : #else
39 : : #define nlm_deadlock nlm_lck_denied
40 : : #endif
41 : :
42 : : static void nlmsvc_release_block(struct nlm_block *block);
43 : : static void nlmsvc_insert_block(struct nlm_block *block, unsigned long);
44 : : static void nlmsvc_remove_block(struct nlm_block *block);
45 : :
46 : : static int nlmsvc_setgrantargs(struct nlm_rqst *call, struct nlm_lock *lock);
47 : : static void nlmsvc_freegrantargs(struct nlm_rqst *call);
48 : : static const struct rpc_call_ops nlmsvc_grant_ops;
49 : :
50 : : /*
51 : : * The list of blocked locks to retry
52 : : */
53 : : static LIST_HEAD(nlm_blocked);
54 : : static DEFINE_SPINLOCK(nlm_blocked_lock);
55 : :
56 : : #ifdef LOCKD_DEBUG
57 : : static const char *nlmdbg_cookie2a(const struct nlm_cookie *cookie)
58 : : {
59 : : /*
60 : : * We can get away with a static buffer because we're only
61 : : * called with BKL held.
62 : : */
63 : : static char buf[2*NLM_MAXCOOKIELEN+1];
64 : : unsigned int i, len = sizeof(buf);
65 : : char *p = buf;
66 : :
67 : : len--; /* allow for trailing \0 */
68 : : if (len < 3)
69 : : return "???";
70 : : for (i = 0 ; i < cookie->len ; i++) {
71 : : if (len < 2) {
72 : : strcpy(p-3, "...");
73 : : break;
74 : : }
75 : : sprintf(p, "%02x", cookie->data[i]);
76 : : p += 2;
77 : : len -= 2;
78 : : }
79 : : *p = '\0';
80 : :
81 : : return buf;
82 : : }
83 : : #endif
84 : :
85 : : /*
86 : : * Insert a blocked lock into the global list
87 : : */
88 : : static void
89 : 0 : nlmsvc_insert_block_locked(struct nlm_block *block, unsigned long when)
90 : : {
91 : : struct nlm_block *b;
92 : : struct list_head *pos;
93 : :
94 : : dprintk("lockd: nlmsvc_insert_block(%p, %ld)\n", block, when);
95 [ # # ]: 0 : if (list_empty(&block->b_list)) {
96 : : kref_get(&block->b_count);
97 : : } else {
98 : : list_del_init(&block->b_list);
99 : : }
100 : :
101 : : pos = &nlm_blocked;
102 [ # # ]: 0 : if (when != NLM_NEVER) {
103 [ # # ]: 0 : if ((when += jiffies) == NLM_NEVER)
104 : 0 : when ++;
105 [ # # ]: 0 : list_for_each(pos, &nlm_blocked) {
106 : : b = list_entry(pos, struct nlm_block, b_list);
107 [ # # ][ # # ]: 0 : if (time_after(b->b_when,when) || b->b_when == NLM_NEVER)
108 : : break;
109 : : }
110 : : /* On normal exit from the loop, pos == &nlm_blocked,
111 : : * so we will be adding to the end of the list - good
112 : : */
113 : : }
114 : :
115 : : list_add_tail(&block->b_list, pos);
116 : 0 : block->b_when = when;
117 : 0 : }
118 : :
119 : 0 : static void nlmsvc_insert_block(struct nlm_block *block, unsigned long when)
120 : : {
121 : : spin_lock(&nlm_blocked_lock);
122 : 0 : nlmsvc_insert_block_locked(block, when);
123 : : spin_unlock(&nlm_blocked_lock);
124 : 0 : }
125 : :
126 : : /*
127 : : * Remove a block from the global list
128 : : */
129 : : static inline void
130 : : nlmsvc_remove_block(struct nlm_block *block)
131 : : {
132 [ # # ]: 0 : if (!list_empty(&block->b_list)) {
133 : : spin_lock(&nlm_blocked_lock);
134 : : list_del_init(&block->b_list);
135 : : spin_unlock(&nlm_blocked_lock);
136 : 0 : nlmsvc_release_block(block);
137 : : }
138 : : }
139 : :
140 : : /*
141 : : * Find a block for a given lock
142 : : */
143 : : static struct nlm_block *
144 : 0 : nlmsvc_lookup_block(struct nlm_file *file, struct nlm_lock *lock)
145 : : {
146 : : struct nlm_block *block;
147 : : struct file_lock *fl;
148 : :
149 : : dprintk("lockd: nlmsvc_lookup_block f=%p pd=%d %Ld-%Ld ty=%d\n",
150 : : file, lock->fl.fl_pid,
151 : : (long long)lock->fl.fl_start,
152 : : (long long)lock->fl.fl_end, lock->fl.fl_type);
153 [ # # ]: 0 : list_for_each_entry(block, &nlm_blocked, b_list) {
154 : 0 : fl = &block->b_call->a_args.lock.fl;
155 : : dprintk("lockd: check f=%p pd=%d %Ld-%Ld ty=%d cookie=%s\n",
156 : : block->b_file, fl->fl_pid,
157 : : (long long)fl->fl_start,
158 : : (long long)fl->fl_end, fl->fl_type,
159 : : nlmdbg_cookie2a(&block->b_call->a_args.cookie));
160 [ # # ][ # # ]: 0 : if (block->b_file == file && nlm_compare_locks(fl, &lock->fl)) {
161 : : kref_get(&block->b_count);
162 : 0 : return block;
163 : : }
164 : : }
165 : :
166 : : return NULL;
167 : : }
168 : :
169 : : static inline int nlm_cookie_match(struct nlm_cookie *a, struct nlm_cookie *b)
170 : : {
171 [ # # ]: 0 : if (a->len != b->len)
172 : : return 0;
173 [ # # ]: 0 : if (memcmp(a->data, b->data, a->len))
174 : : return 0;
175 : : return 1;
176 : : }
177 : :
178 : : /*
179 : : * Find a block with a given NLM cookie.
180 : : */
181 : : static inline struct nlm_block *
182 : : nlmsvc_find_block(struct nlm_cookie *cookie)
183 : : {
184 : : struct nlm_block *block;
185 : :
186 [ # # ]: 0 : list_for_each_entry(block, &nlm_blocked, b_list) {
187 [ # # ]: 0 : if (nlm_cookie_match(&block->b_call->a_args.cookie,cookie))
188 : : goto found;
189 : : }
190 : :
191 : : return NULL;
192 : :
193 : : found:
194 : : dprintk("nlmsvc_find_block(%s): block=%p\n", nlmdbg_cookie2a(cookie), block);
195 : : kref_get(&block->b_count);
196 : : return block;
197 : : }
198 : :
199 : : /*
200 : : * Create a block and initialize it.
201 : : *
202 : : * Note: we explicitly set the cookie of the grant reply to that of
203 : : * the blocked lock request. The spec explicitly mentions that the client
204 : : * should _not_ rely on the callback containing the same cookie as the
205 : : * request, but (as I found out later) that's because some implementations
206 : : * do just this. Never mind the standards comittees, they support our
207 : : * logging industries.
208 : : *
209 : : * 10 years later: I hope we can safely ignore these old and broken
210 : : * clients by now. Let's fix this so we can uniquely identify an incoming
211 : : * GRANTED_RES message by cookie, without having to rely on the client's IP
212 : : * address. --okir
213 : : */
214 : : static struct nlm_block *
215 : 0 : nlmsvc_create_block(struct svc_rqst *rqstp, struct nlm_host *host,
216 : : struct nlm_file *file, struct nlm_lock *lock,
217 : : struct nlm_cookie *cookie)
218 : : {
219 : : struct nlm_block *block;
220 : : struct nlm_rqst *call = NULL;
221 : :
222 : 0 : call = nlm_alloc_call(host);
223 [ # # ]: 0 : if (call == NULL)
224 : : return NULL;
225 : :
226 : : /* Allocate memory for block, and initialize arguments */
227 : : block = kzalloc(sizeof(*block), GFP_KERNEL);
228 [ # # ]: 0 : if (block == NULL)
229 : : goto failed;
230 : : kref_init(&block->b_count);
231 : 0 : INIT_LIST_HEAD(&block->b_list);
232 : 0 : INIT_LIST_HEAD(&block->b_flist);
233 : :
234 [ # # ]: 0 : if (!nlmsvc_setgrantargs(call, lock))
235 : : goto failed_free;
236 : :
237 : : /* Set notifier function for VFS, and init args */
238 : 0 : call->a_args.lock.fl.fl_flags |= FL_SLEEP;
239 : 0 : call->a_args.lock.fl.fl_lmops = &nlmsvc_lock_operations;
240 : 0 : nlmclnt_next_cookie(&call->a_args.cookie);
241 : :
242 : : dprintk("lockd: created block %p...\n", block);
243 : :
244 : : /* Create and initialize the block */
245 : 0 : block->b_daemon = rqstp->rq_server;
246 : 0 : block->b_host = host;
247 : 0 : block->b_file = file;
248 : 0 : block->b_fl = NULL;
249 : 0 : file->f_count++;
250 : :
251 : : /* Add to file's list of blocks */
252 : 0 : list_add(&block->b_flist, &file->f_blocks);
253 : :
254 : : /* Set up RPC arguments for callback */
255 : 0 : block->b_call = call;
256 : 0 : call->a_flags = RPC_TASK_ASYNC;
257 : 0 : call->a_block = block;
258 : :
259 : : return block;
260 : :
261 : : failed_free:
262 : 0 : kfree(block);
263 : : failed:
264 : 0 : nlmsvc_release_call(call);
265 : : return NULL;
266 : : }
267 : :
268 : : /*
269 : : * Delete a block.
270 : : * It is the caller's responsibility to check whether the file
271 : : * can be closed hereafter.
272 : : */
273 : 0 : static int nlmsvc_unlink_block(struct nlm_block *block)
274 : : {
275 : : int status;
276 : : dprintk("lockd: unlinking block %p...\n", block);
277 : :
278 : : /* Remove block from list */
279 : 0 : status = posix_unblock_lock(&block->b_call->a_args.lock.fl);
280 : : nlmsvc_remove_block(block);
281 : 0 : return status;
282 : : }
283 : :
284 : 0 : static void nlmsvc_free_block(struct kref *kref)
285 : : {
286 : : struct nlm_block *block = container_of(kref, struct nlm_block, b_count);
287 : 0 : struct nlm_file *file = block->b_file;
288 : :
289 : : dprintk("lockd: freeing block %p...\n", block);
290 : :
291 : : /* Remove block from file's list of blocks */
292 : 0 : list_del_init(&block->b_flist);
293 : 0 : mutex_unlock(&file->f_mutex);
294 : :
295 : 0 : nlmsvc_freegrantargs(block->b_call);
296 : 0 : nlmsvc_release_call(block->b_call);
297 : 0 : nlm_release_file(block->b_file);
298 : 0 : kfree(block->b_fl);
299 : 0 : kfree(block);
300 : 0 : }
301 : :
302 : 0 : static void nlmsvc_release_block(struct nlm_block *block)
303 : : {
304 [ # # ]: 0 : if (block != NULL)
305 : 0 : kref_put_mutex(&block->b_count, nlmsvc_free_block, &block->b_file->f_mutex);
306 : 0 : }
307 : :
308 : : /*
309 : : * Loop over all blocks and delete blocks held by
310 : : * a matching host.
311 : : */
312 : 0 : void nlmsvc_traverse_blocks(struct nlm_host *host,
313 : : struct nlm_file *file,
314 : : nlm_host_match_fn_t match)
315 : : {
316 : : struct nlm_block *block, *next;
317 : :
318 : : restart:
319 : 0 : mutex_lock(&file->f_mutex);
320 [ # # ]: 0 : list_for_each_entry_safe(block, next, &file->f_blocks, b_flist) {
321 [ # # ]: 0 : if (!match(block->b_host, host))
322 : 0 : continue;
323 : : /* Do not destroy blocks that are not on
324 : : * the global retry list - why? */
325 [ # # ]: 0 : if (list_empty(&block->b_list))
326 : 0 : continue;
327 : : kref_get(&block->b_count);
328 : 0 : mutex_unlock(&file->f_mutex);
329 : 0 : nlmsvc_unlink_block(block);
330 : 0 : nlmsvc_release_block(block);
331 : 0 : goto restart;
332 : : }
333 : 0 : mutex_unlock(&file->f_mutex);
334 : 0 : }
335 : :
336 : : /*
337 : : * Initialize arguments for GRANTED call. The nlm_rqst structure
338 : : * has been cleared already.
339 : : */
340 : 0 : static int nlmsvc_setgrantargs(struct nlm_rqst *call, struct nlm_lock *lock)
341 : : {
342 : 0 : locks_copy_lock(&call->a_args.lock.fl, &lock->fl);
343 : 0 : memcpy(&call->a_args.lock.fh, &lock->fh, sizeof(call->a_args.lock.fh));
344 : 0 : call->a_args.lock.caller = utsname()->nodename;
345 : 0 : call->a_args.lock.oh.len = lock->oh.len;
346 : :
347 : : /* set default data area */
348 : 0 : call->a_args.lock.oh.data = call->a_owner;
349 : 0 : call->a_args.lock.svid = lock->fl.fl_pid;
350 : :
351 [ # # ]: 0 : if (lock->oh.len > NLMCLNT_OHSIZE) {
352 : : void *data = kmalloc(lock->oh.len, GFP_KERNEL);
353 [ # # ]: 0 : if (!data)
354 : : return 0;
355 : 0 : call->a_args.lock.oh.data = (u8 *) data;
356 : : }
357 : :
358 : 0 : memcpy(call->a_args.lock.oh.data, lock->oh.data, lock->oh.len);
359 : 0 : return 1;
360 : : }
361 : :
362 : 0 : static void nlmsvc_freegrantargs(struct nlm_rqst *call)
363 : : {
364 [ # # ]: 0 : if (call->a_args.lock.oh.data != call->a_owner)
365 : 0 : kfree(call->a_args.lock.oh.data);
366 : :
367 : 0 : locks_release_private(&call->a_args.lock.fl);
368 : 0 : }
369 : :
370 : : /*
371 : : * Deferred lock request handling for non-blocking lock
372 : : */
373 : : static __be32
374 : 0 : nlmsvc_defer_lock_rqst(struct svc_rqst *rqstp, struct nlm_block *block)
375 : : {
376 : : __be32 status = nlm_lck_denied_nolocks;
377 : :
378 : 0 : block->b_flags |= B_QUEUED;
379 : :
380 : 0 : nlmsvc_insert_block(block, NLM_TIMEOUT);
381 : :
382 : 0 : block->b_cache_req = &rqstp->rq_chandle;
383 [ # # ]: 0 : if (rqstp->rq_chandle.defer) {
384 : 0 : block->b_deferred_req =
385 : 0 : rqstp->rq_chandle.defer(block->b_cache_req);
386 [ # # ]: 0 : if (block->b_deferred_req != NULL)
387 : : status = nlm_drop_reply;
388 : : }
389 : : dprintk("lockd: nlmsvc_defer_lock_rqst block %p flags %d status %d\n",
390 : : block, block->b_flags, ntohl(status));
391 : :
392 : 0 : return status;
393 : : }
394 : :
395 : : /*
396 : : * Attempt to establish a lock, and if it can't be granted, block it
397 : : * if required.
398 : : */
399 : : __be32
400 : 0 : nlmsvc_lock(struct svc_rqst *rqstp, struct nlm_file *file,
401 : : struct nlm_host *host, struct nlm_lock *lock, int wait,
402 : : struct nlm_cookie *cookie, int reclaim)
403 : : {
404 : : struct nlm_block *block = NULL;
405 : : int error;
406 : : __be32 ret;
407 : :
408 : : dprintk("lockd: nlmsvc_lock(%s/%ld, ty=%d, pi=%d, %Ld-%Ld, bl=%d)\n",
409 : : file_inode(file->f_file)->i_sb->s_id,
410 : : file_inode(file->f_file)->i_ino,
411 : : lock->fl.fl_type, lock->fl.fl_pid,
412 : : (long long)lock->fl.fl_start,
413 : : (long long)lock->fl.fl_end,
414 : : wait);
415 : :
416 : : /* Lock file against concurrent access */
417 : 0 : mutex_lock(&file->f_mutex);
418 : : /* Get existing block (in case client is busy-waiting)
419 : : * or create new block
420 : : */
421 : 0 : block = nlmsvc_lookup_block(file, lock);
422 [ # # ]: 0 : if (block == NULL) {
423 : 0 : block = nlmsvc_create_block(rqstp, host, file, lock, cookie);
424 : : ret = nlm_lck_denied_nolocks;
425 [ # # ]: 0 : if (block == NULL)
426 : : goto out;
427 : 0 : lock = &block->b_call->a_args.lock;
428 : : } else
429 : 0 : lock->fl.fl_flags &= ~FL_SLEEP;
430 : :
431 [ # # ]: 0 : if (block->b_flags & B_QUEUED) {
432 : : dprintk("lockd: nlmsvc_lock deferred block %p flags %d\n",
433 : : block, block->b_flags);
434 [ # # ]: 0 : if (block->b_granted) {
435 : 0 : nlmsvc_unlink_block(block);
436 : : ret = nlm_granted;
437 : 0 : goto out;
438 : : }
439 [ # # ]: 0 : if (block->b_flags & B_TIMED_OUT) {
440 : 0 : nlmsvc_unlink_block(block);
441 : : ret = nlm_lck_denied;
442 : 0 : goto out;
443 : : }
444 : : ret = nlm_drop_reply;
445 : : goto out;
446 : : }
447 : :
448 [ # # ][ # # ]: 0 : if (locks_in_grace(SVC_NET(rqstp)) && !reclaim) {
449 : : ret = nlm_lck_denied_grace_period;
450 : : goto out;
451 : : }
452 [ # # ][ # # ]: 0 : if (reclaim && !locks_in_grace(SVC_NET(rqstp))) {
453 : : ret = nlm_lck_denied_grace_period;
454 : : goto out;
455 : : }
456 : :
457 [ # # ]: 0 : if (!wait)
458 : 0 : lock->fl.fl_flags &= ~FL_SLEEP;
459 : 0 : error = vfs_lock_file(file->f_file, F_SETLK, &lock->fl, NULL);
460 : 0 : lock->fl.fl_flags &= ~FL_SLEEP;
461 : :
462 : : dprintk("lockd: vfs_lock_file returned %d\n", error);
463 [ # # # # : 0 : switch (error) {
# ]
464 : : case 0:
465 : : ret = nlm_granted;
466 : : goto out;
467 : : case -EAGAIN:
468 : : /*
469 : : * If this is a blocking request for an
470 : : * already pending lock request then we need
471 : : * to put it back on lockd's block list
472 : : */
473 [ # # ]: 0 : if (wait)
474 : : break;
475 : : ret = nlm_lck_denied;
476 : : goto out;
477 : : case FILE_LOCK_DEFERRED:
478 [ # # ]: 0 : if (wait)
479 : : break;
480 : : /* Filesystem lock operation is in progress
481 : : Add it to the queue waiting for callback */
482 : 0 : ret = nlmsvc_defer_lock_rqst(rqstp, block);
483 : 0 : goto out;
484 : : case -EDEADLK:
485 : : ret = nlm_deadlock;
486 : 0 : goto out;
487 : : default: /* includes ENOLCK */
488 : : ret = nlm_lck_denied_nolocks;
489 : 0 : goto out;
490 : : }
491 : :
492 : : ret = nlm_lck_blocked;
493 : :
494 : : /* Append to list of blocked */
495 : 0 : nlmsvc_insert_block(block, NLM_NEVER);
496 : : out:
497 : 0 : mutex_unlock(&file->f_mutex);
498 : 0 : nlmsvc_release_block(block);
499 : : dprintk("lockd: nlmsvc_lock returned %u\n", ret);
500 : 0 : return ret;
501 : : }
502 : :
503 : : /*
504 : : * Test for presence of a conflicting lock.
505 : : */
506 : : __be32
507 : 0 : nlmsvc_testlock(struct svc_rqst *rqstp, struct nlm_file *file,
508 : : struct nlm_host *host, struct nlm_lock *lock,
509 : : struct nlm_lock *conflock, struct nlm_cookie *cookie)
510 : : {
511 : : struct nlm_block *block = NULL;
512 : : int error;
513 : : __be32 ret;
514 : :
515 : : dprintk("lockd: nlmsvc_testlock(%s/%ld, ty=%d, %Ld-%Ld)\n",
516 : : file_inode(file->f_file)->i_sb->s_id,
517 : : file_inode(file->f_file)->i_ino,
518 : : lock->fl.fl_type,
519 : : (long long)lock->fl.fl_start,
520 : : (long long)lock->fl.fl_end);
521 : :
522 : : /* Get existing block (in case client is busy-waiting) */
523 : 0 : block = nlmsvc_lookup_block(file, lock);
524 : :
525 [ # # ]: 0 : if (block == NULL) {
526 : : struct file_lock *conf = kzalloc(sizeof(*conf), GFP_KERNEL);
527 : :
528 [ # # ]: 0 : if (conf == NULL)
529 : : return nlm_granted;
530 : 0 : block = nlmsvc_create_block(rqstp, host, file, lock, cookie);
531 [ # # ]: 0 : if (block == NULL) {
532 : 0 : kfree(conf);
533 : 0 : return nlm_granted;
534 : : }
535 : 0 : block->b_fl = conf;
536 : : }
537 [ # # ]: 0 : if (block->b_flags & B_QUEUED) {
538 : : dprintk("lockd: nlmsvc_testlock deferred block %p flags %d fl %p\n",
539 : : block, block->b_flags, block->b_fl);
540 [ # # ]: 0 : if (block->b_flags & B_TIMED_OUT) {
541 : 0 : nlmsvc_unlink_block(block);
542 : : ret = nlm_lck_denied;
543 : 0 : goto out;
544 : : }
545 [ # # ]: 0 : if (block->b_flags & B_GOT_CALLBACK) {
546 : 0 : nlmsvc_unlink_block(block);
547 [ # # ]: 0 : if (block->b_fl != NULL
548 [ # # ]: 0 : && block->b_fl->fl_type != F_UNLCK) {
549 : 0 : lock->fl = *block->b_fl;
550 : 0 : goto conf_lock;
551 : : } else {
552 : : ret = nlm_granted;
553 : : goto out;
554 : : }
555 : : }
556 : : ret = nlm_drop_reply;
557 : : goto out;
558 : : }
559 : :
560 [ # # ]: 0 : if (locks_in_grace(SVC_NET(rqstp))) {
561 : : ret = nlm_lck_denied_grace_period;
562 : : goto out;
563 : : }
564 : 0 : error = vfs_test_lock(file->f_file, &lock->fl);
565 [ # # ]: 0 : if (error == FILE_LOCK_DEFERRED) {
566 : 0 : ret = nlmsvc_defer_lock_rqst(rqstp, block);
567 : 0 : goto out;
568 : : }
569 [ # # ]: 0 : if (error) {
570 : : ret = nlm_lck_denied_nolocks;
571 : : goto out;
572 : : }
573 [ # # ]: 0 : if (lock->fl.fl_type == F_UNLCK) {
574 : : ret = nlm_granted;
575 : : goto out;
576 : : }
577 : :
578 : : conf_lock:
579 : : dprintk("lockd: conflicting lock(ty=%d, %Ld-%Ld)\n",
580 : : lock->fl.fl_type, (long long)lock->fl.fl_start,
581 : : (long long)lock->fl.fl_end);
582 : 0 : conflock->caller = "somehost"; /* FIXME */
583 : 0 : conflock->len = strlen(conflock->caller);
584 : 0 : conflock->oh.len = 0; /* don't return OH info */
585 : 0 : conflock->svid = lock->fl.fl_pid;
586 : 0 : conflock->fl.fl_type = lock->fl.fl_type;
587 : 0 : conflock->fl.fl_start = lock->fl.fl_start;
588 : 0 : conflock->fl.fl_end = lock->fl.fl_end;
589 : : ret = nlm_lck_denied;
590 : : out:
591 [ # # ]: 0 : if (block)
592 : 0 : nlmsvc_release_block(block);
593 : 0 : return ret;
594 : : }
595 : :
596 : : /*
597 : : * Remove a lock.
598 : : * This implies a CANCEL call: We send a GRANT_MSG, the client replies
599 : : * with a GRANT_RES call which gets lost, and calls UNLOCK immediately
600 : : * afterwards. In this case the block will still be there, and hence
601 : : * must be removed.
602 : : */
603 : : __be32
604 : 0 : nlmsvc_unlock(struct net *net, struct nlm_file *file, struct nlm_lock *lock)
605 : : {
606 : : int error;
607 : :
608 : : dprintk("lockd: nlmsvc_unlock(%s/%ld, pi=%d, %Ld-%Ld)\n",
609 : : file_inode(file->f_file)->i_sb->s_id,
610 : : file_inode(file->f_file)->i_ino,
611 : : lock->fl.fl_pid,
612 : : (long long)lock->fl.fl_start,
613 : : (long long)lock->fl.fl_end);
614 : :
615 : : /* First, cancel any lock that might be there */
616 : 0 : nlmsvc_cancel_blocked(net, file, lock);
617 : :
618 : 0 : lock->fl.fl_type = F_UNLCK;
619 : 0 : error = vfs_lock_file(file->f_file, F_SETLK, &lock->fl, NULL);
620 : :
621 [ # # ]: 0 : return (error < 0)? nlm_lck_denied_nolocks : nlm_granted;
622 : : }
623 : :
624 : : /*
625 : : * Cancel a previously blocked request.
626 : : *
627 : : * A cancel request always overrides any grant that may currently
628 : : * be in progress.
629 : : * The calling procedure must check whether the file can be closed.
630 : : */
631 : : __be32
632 : 0 : nlmsvc_cancel_blocked(struct net *net, struct nlm_file *file, struct nlm_lock *lock)
633 : : {
634 : : struct nlm_block *block;
635 : : int status = 0;
636 : :
637 : : dprintk("lockd: nlmsvc_cancel(%s/%ld, pi=%d, %Ld-%Ld)\n",
638 : : file_inode(file->f_file)->i_sb->s_id,
639 : : file_inode(file->f_file)->i_ino,
640 : : lock->fl.fl_pid,
641 : : (long long)lock->fl.fl_start,
642 : : (long long)lock->fl.fl_end);
643 : :
644 [ # # ]: 0 : if (locks_in_grace(net))
645 : : return nlm_lck_denied_grace_period;
646 : :
647 : 0 : mutex_lock(&file->f_mutex);
648 : 0 : block = nlmsvc_lookup_block(file, lock);
649 : 0 : mutex_unlock(&file->f_mutex);
650 [ # # ]: 0 : if (block != NULL) {
651 : 0 : vfs_cancel_lock(block->b_file->f_file,
652 : 0 : &block->b_call->a_args.lock.fl);
653 : 0 : status = nlmsvc_unlink_block(block);
654 : 0 : nlmsvc_release_block(block);
655 : : }
656 [ # # ]: 0 : return status ? nlm_lck_denied : nlm_granted;
657 : : }
658 : :
659 : : /*
660 : : * This is a callback from the filesystem for VFS file lock requests.
661 : : * It will be used if lm_grant is defined and the filesystem can not
662 : : * respond to the request immediately.
663 : : * For GETLK request it will copy the reply to the nlm_block.
664 : : * For SETLK or SETLKW request it will get the local posix lock.
665 : : * In all cases it will move the block to the head of nlm_blocked q where
666 : : * nlmsvc_retry_blocked() can send back a reply for SETLKW or revisit the
667 : : * deferred rpc for GETLK and SETLK.
668 : : */
669 : : static void
670 : 0 : nlmsvc_update_deferred_block(struct nlm_block *block, struct file_lock *conf,
671 : : int result)
672 : : {
673 : 0 : block->b_flags |= B_GOT_CALLBACK;
674 [ # # ]: 0 : if (result == 0)
675 : 0 : block->b_granted = 1;
676 : : else
677 : 0 : block->b_flags |= B_TIMED_OUT;
678 [ # # ]: 0 : if (conf) {
679 [ # # ]: 0 : if (block->b_fl)
680 : 0 : __locks_copy_lock(block->b_fl, conf);
681 : : }
682 : 0 : }
683 : :
684 : 0 : static int nlmsvc_grant_deferred(struct file_lock *fl, struct file_lock *conf,
685 : : int result)
686 : : {
687 : : struct nlm_block *block;
688 : : int rc = -ENOENT;
689 : :
690 : : spin_lock(&nlm_blocked_lock);
691 [ # # ]: 0 : list_for_each_entry(block, &nlm_blocked, b_list) {
692 [ # # ]: 0 : if (nlm_compare_locks(&block->b_call->a_args.lock.fl, fl)) {
693 : : dprintk("lockd: nlmsvc_notify_blocked block %p flags %d\n",
694 : : block, block->b_flags);
695 [ # # ]: 0 : if (block->b_flags & B_QUEUED) {
696 [ # # ]: 0 : if (block->b_flags & B_TIMED_OUT) {
697 : : rc = -ENOLCK;
698 : : break;
699 : : }
700 : 0 : nlmsvc_update_deferred_block(block, conf, result);
701 [ # # ]: 0 : } else if (result == 0)
702 : 0 : block->b_granted = 1;
703 : :
704 : 0 : nlmsvc_insert_block_locked(block, 0);
705 : 0 : svc_wake_up(block->b_daemon);
706 : : rc = 0;
707 : 0 : break;
708 : : }
709 : : }
710 : : spin_unlock(&nlm_blocked_lock);
711 [ # # ]: 0 : if (rc == -ENOENT)
712 : 0 : printk(KERN_WARNING "lockd: grant for unknown block\n");
713 : 0 : return rc;
714 : : }
715 : :
716 : : /*
717 : : * Unblock a blocked lock request. This is a callback invoked from the
718 : : * VFS layer when a lock on which we blocked is removed.
719 : : *
720 : : * This function doesn't grant the blocked lock instantly, but rather moves
721 : : * the block to the head of nlm_blocked where it can be picked up by lockd.
722 : : */
723 : : static void
724 : 0 : nlmsvc_notify_blocked(struct file_lock *fl)
725 : : {
726 : : struct nlm_block *block;
727 : :
728 : : dprintk("lockd: VFS unblock notification for block %p\n", fl);
729 : : spin_lock(&nlm_blocked_lock);
730 [ # # ]: 0 : list_for_each_entry(block, &nlm_blocked, b_list) {
731 [ # # ]: 0 : if (nlm_compare_locks(&block->b_call->a_args.lock.fl, fl)) {
732 : 0 : nlmsvc_insert_block_locked(block, 0);
733 : : spin_unlock(&nlm_blocked_lock);
734 : 0 : svc_wake_up(block->b_daemon);
735 : 0 : return;
736 : : }
737 : : }
738 : : spin_unlock(&nlm_blocked_lock);
739 : 0 : printk(KERN_WARNING "lockd: notification for unknown block!\n");
740 : : }
741 : :
742 : 0 : static int nlmsvc_same_owner(struct file_lock *fl1, struct file_lock *fl2)
743 : : {
744 [ # # ][ # # ]: 0 : return fl1->fl_owner == fl2->fl_owner && fl1->fl_pid == fl2->fl_pid;
745 : : }
746 : :
747 : : /*
748 : : * Since NLM uses two "keys" for tracking locks, we need to hash them down
749 : : * to one for the blocked_hash. Here, we're just xor'ing the host address
750 : : * with the pid in order to create a key value for picking a hash bucket.
751 : : */
752 : : static unsigned long
753 : 0 : nlmsvc_owner_key(struct file_lock *fl)
754 : : {
755 : 0 : return (unsigned long)fl->fl_owner ^ (unsigned long)fl->fl_pid;
756 : : }
757 : :
758 : : const struct lock_manager_operations nlmsvc_lock_operations = {
759 : : .lm_compare_owner = nlmsvc_same_owner,
760 : : .lm_owner_key = nlmsvc_owner_key,
761 : : .lm_notify = nlmsvc_notify_blocked,
762 : : .lm_grant = nlmsvc_grant_deferred,
763 : : };
764 : :
765 : : /*
766 : : * Try to claim a lock that was previously blocked.
767 : : *
768 : : * Note that we use both the RPC_GRANTED_MSG call _and_ an async
769 : : * RPC thread when notifying the client. This seems like overkill...
770 : : * Here's why:
771 : : * - we don't want to use a synchronous RPC thread, otherwise
772 : : * we might find ourselves hanging on a dead portmapper.
773 : : * - Some lockd implementations (e.g. HP) don't react to
774 : : * RPC_GRANTED calls; they seem to insist on RPC_GRANTED_MSG calls.
775 : : */
776 : : static void
777 : 0 : nlmsvc_grant_blocked(struct nlm_block *block)
778 : : {
779 : 0 : struct nlm_file *file = block->b_file;
780 : 0 : struct nlm_lock *lock = &block->b_call->a_args.lock;
781 : : int error;
782 : :
783 : : dprintk("lockd: grant blocked lock %p\n", block);
784 : :
785 : : kref_get(&block->b_count);
786 : :
787 : : /* Unlink block request from list */
788 : 0 : nlmsvc_unlink_block(block);
789 : :
790 : : /* If b_granted is true this means we've been here before.
791 : : * Just retry the grant callback, possibly refreshing the RPC
792 : : * binding */
793 [ # # ]: 0 : if (block->b_granted) {
794 : 0 : nlm_rebind_host(block->b_host);
795 : 0 : goto callback;
796 : : }
797 : :
798 : : /* Try the lock operation again */
799 : 0 : lock->fl.fl_flags |= FL_SLEEP;
800 : 0 : error = vfs_lock_file(file->f_file, F_SETLK, &lock->fl, NULL);
801 : 0 : lock->fl.fl_flags &= ~FL_SLEEP;
802 : :
803 [ # # # ]: 0 : switch (error) {
804 : : case 0:
805 : : break;
806 : : case FILE_LOCK_DEFERRED:
807 : : dprintk("lockd: lock still blocked error %d\n", error);
808 : 0 : nlmsvc_insert_block(block, NLM_NEVER);
809 : 0 : nlmsvc_release_block(block);
810 : 0 : return;
811 : : default:
812 : 0 : printk(KERN_WARNING "lockd: unexpected error %d in %s!\n",
813 : : -error, __func__);
814 : 0 : nlmsvc_insert_block(block, 10 * HZ);
815 : 0 : nlmsvc_release_block(block);
816 : 0 : return;
817 : : }
818 : :
819 : : callback:
820 : : /* Lock was granted by VFS. */
821 : : dprintk("lockd: GRANTing blocked lock.\n");
822 : 0 : block->b_granted = 1;
823 : :
824 : : /* keep block on the list, but don't reattempt until the RPC
825 : : * completes or the submission fails
826 : : */
827 : 0 : nlmsvc_insert_block(block, NLM_NEVER);
828 : :
829 : : /* Call the client -- use a soft RPC task since nlmsvc_retry_blocked
830 : : * will queue up a new one if this one times out
831 : : */
832 : 0 : error = nlm_async_call(block->b_call, NLMPROC_GRANTED_MSG,
833 : : &nlmsvc_grant_ops);
834 : :
835 : : /* RPC submission failed, wait a bit and retry */
836 [ # # ]: 0 : if (error < 0)
837 : 0 : nlmsvc_insert_block(block, 10 * HZ);
838 : : }
839 : :
840 : : /*
841 : : * This is the callback from the RPC layer when the NLM_GRANTED_MSG
842 : : * RPC call has succeeded or timed out.
843 : : * Like all RPC callbacks, it is invoked by the rpciod process, so it
844 : : * better not sleep. Therefore, we put the blocked lock on the nlm_blocked
845 : : * chain once more in order to have it removed by lockd itself (which can
846 : : * then sleep on the file semaphore without disrupting e.g. the nfs client).
847 : : */
848 : 0 : static void nlmsvc_grant_callback(struct rpc_task *task, void *data)
849 : : {
850 : : struct nlm_rqst *call = data;
851 : 0 : struct nlm_block *block = call->a_block;
852 : : unsigned long timeout;
853 : :
854 : : dprintk("lockd: GRANT_MSG RPC callback\n");
855 : :
856 : : spin_lock(&nlm_blocked_lock);
857 : : /* if the block is not on a list at this point then it has
858 : : * been invalidated. Don't try to requeue it.
859 : : *
860 : : * FIXME: it's possible that the block is removed from the list
861 : : * after this check but before the nlmsvc_insert_block. In that
862 : : * case it will be added back. Perhaps we need better locking
863 : : * for nlm_blocked?
864 : : */
865 [ # # ]: 0 : if (list_empty(&block->b_list))
866 : : goto out;
867 : :
868 : : /* Technically, we should down the file semaphore here. Since we
869 : : * move the block towards the head of the queue only, no harm
870 : : * can be done, though. */
871 [ # # ]: 0 : if (task->tk_status < 0) {
872 : : /* RPC error: Re-insert for retransmission */
873 : : timeout = 10 * HZ;
874 : : } else {
875 : : /* Call was successful, now wait for client callback */
876 : : timeout = 60 * HZ;
877 : : }
878 : 0 : nlmsvc_insert_block_locked(block, timeout);
879 : 0 : svc_wake_up(block->b_daemon);
880 : : out:
881 : : spin_unlock(&nlm_blocked_lock);
882 : 0 : }
883 : :
884 : : /*
885 : : * FIXME: nlmsvc_release_block() grabs a mutex. This is not allowed for an
886 : : * .rpc_release rpc_call_op
887 : : */
888 : 0 : static void nlmsvc_grant_release(void *data)
889 : : {
890 : : struct nlm_rqst *call = data;
891 : 0 : nlmsvc_release_block(call->a_block);
892 : 0 : }
893 : :
894 : : static const struct rpc_call_ops nlmsvc_grant_ops = {
895 : : .rpc_call_done = nlmsvc_grant_callback,
896 : : .rpc_release = nlmsvc_grant_release,
897 : : };
898 : :
899 : : /*
900 : : * We received a GRANT_RES callback. Try to find the corresponding
901 : : * block.
902 : : */
903 : : void
904 : 0 : nlmsvc_grant_reply(struct nlm_cookie *cookie, __be32 status)
905 : : {
906 : : struct nlm_block *block;
907 : :
908 : : dprintk("grant_reply: looking for cookie %x, s=%d \n",
909 : : *(unsigned int *)(cookie->data), status);
910 [ # # ]: 0 : if (!(block = nlmsvc_find_block(cookie)))
911 : 0 : return;
912 : :
913 [ # # ]: 0 : if (block) {
914 [ # # ]: 0 : if (status == nlm_lck_denied_grace_period) {
915 : : /* Try again in a couple of seconds */
916 : 0 : nlmsvc_insert_block(block, 10 * HZ);
917 : : } else {
918 : : /* Lock is now held by client, or has been rejected.
919 : : * In both cases, the block should be removed. */
920 : 0 : nlmsvc_unlink_block(block);
921 : : }
922 : : }
923 : 0 : nlmsvc_release_block(block);
924 : : }
925 : :
926 : : /* Helper function to handle retry of a deferred block.
927 : : * If it is a blocking lock, call grant_blocked.
928 : : * For a non-blocking lock or test lock, revisit the request.
929 : : */
930 : : static void
931 : 0 : retry_deferred_block(struct nlm_block *block)
932 : : {
933 [ # # ]: 0 : if (!(block->b_flags & B_GOT_CALLBACK))
934 : 0 : block->b_flags |= B_TIMED_OUT;
935 : 0 : nlmsvc_insert_block(block, NLM_TIMEOUT);
936 : : dprintk("revisit block %p flags %d\n", block, block->b_flags);
937 [ # # ]: 0 : if (block->b_deferred_req) {
938 : 0 : block->b_deferred_req->revisit(block->b_deferred_req, 0);
939 : 0 : block->b_deferred_req = NULL;
940 : : }
941 : 0 : }
942 : :
943 : : /*
944 : : * Retry all blocked locks that have been notified. This is where lockd
945 : : * picks up locks that can be granted, or grant notifications that must
946 : : * be retransmitted.
947 : : */
948 : : unsigned long
949 : 0 : nlmsvc_retry_blocked(void)
950 : : {
951 : : unsigned long timeout = MAX_SCHEDULE_TIMEOUT;
952 : : struct nlm_block *block;
953 : :
954 : : spin_lock(&nlm_blocked_lock);
955 [ # # ][ # # ]: 0 : while (!list_empty(&nlm_blocked) && !kthread_should_stop()) {
956 : 0 : block = list_entry(nlm_blocked.next, struct nlm_block, b_list);
957 : :
958 [ # # ]: 0 : if (block->b_when == NLM_NEVER)
959 : : break;
960 [ # # ]: 0 : if (time_after(block->b_when, jiffies)) {
961 : 0 : timeout = block->b_when - jiffies;
962 : 0 : break;
963 : : }
964 : : spin_unlock(&nlm_blocked_lock);
965 : :
966 : : dprintk("nlmsvc_retry_blocked(%p, when=%ld)\n",
967 : : block, block->b_when);
968 [ # # ]: 0 : if (block->b_flags & B_QUEUED) {
969 : : dprintk("nlmsvc_retry_blocked delete block (%p, granted=%d, flags=%d)\n",
970 : : block, block->b_granted, block->b_flags);
971 : 0 : retry_deferred_block(block);
972 : : } else
973 : 0 : nlmsvc_grant_blocked(block);
974 : : spin_lock(&nlm_blocked_lock);
975 : : }
976 : : spin_unlock(&nlm_blocked_lock);
977 : :
978 : 0 : return timeout;
979 : : }
|