aboutsummaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorTrond Myklebust <Trond.Myklebust@netapp.com>2006-03-20 13:44:39 -0500
committerTrond Myklebust <Trond.Myklebust@netapp.com>2006-03-20 13:44:39 -0500
commit6849c0cab69f5d1a0fc7b05fa5bfb3dec53f86df (patch)
tree8bf595be663cc641b000846737c3ba1b6419eb6a
parent09c7938c5640a6f22bef074ca6b803dccfdb93e3 (diff)
lockd: Add refcounting to struct nlm_block
Otherwise, the block may disappear from underneath us when in nlmsvc_retry_blocked. Signed-off-by: Trond Myklebust <Trond.Myklebust@netapp.com>
-rw-r--r--fs/lockd/svclock.c94
-rw-r--r--include/linux/lockd/lockd.h3
2 files changed, 47 insertions, 50 deletions
diff --git a/fs/lockd/svclock.c b/fs/lockd/svclock.c
index 1d3a74df93f3..20caeceffb14 100644
--- a/fs/lockd/svclock.c
+++ b/fs/lockd/svclock.c
@@ -39,6 +39,7 @@
39#define nlm_deadlock nlm_lck_denied 39#define nlm_deadlock nlm_lck_denied
40#endif 40#endif
41 41
42static void nlmsvc_release_block(struct nlm_block *block);
42static void nlmsvc_insert_block(struct nlm_block *block, unsigned long); 43static void nlmsvc_insert_block(struct nlm_block *block, unsigned long);
43static int nlmsvc_remove_block(struct nlm_block *block); 44static int nlmsvc_remove_block(struct nlm_block *block);
44 45
@@ -58,6 +59,7 @@ nlmsvc_insert_block(struct nlm_block *block, unsigned long when)
58 struct nlm_block **bp, *b; 59 struct nlm_block **bp, *b;
59 60
60 dprintk("lockd: nlmsvc_insert_block(%p, %ld)\n", block, when); 61 dprintk("lockd: nlmsvc_insert_block(%p, %ld)\n", block, when);
62 kref_get(&block->b_count);
61 if (block->b_queued) 63 if (block->b_queued)
62 nlmsvc_remove_block(block); 64 nlmsvc_remove_block(block);
63 bp = &nlm_blocked; 65 bp = &nlm_blocked;
@@ -90,6 +92,7 @@ nlmsvc_remove_block(struct nlm_block *block)
90 if (b == block) { 92 if (b == block) {
91 *bp = block->b_next; 93 *bp = block->b_next;
92 block->b_queued = 0; 94 block->b_queued = 0;
95 nlmsvc_release_block(block);
93 return 1; 96 return 1;
94 } 97 }
95 } 98 }
@@ -123,6 +126,7 @@ nlmsvc_lookup_block(struct nlm_file *file, struct nlm_lock *lock, int remove)
123 *head = block->b_next; 126 *head = block->b_next;
124 block->b_queued = 0; 127 block->b_queued = 0;
125 } 128 }
129 kref_get(&block->b_count);
126 return block; 130 return block;
127 } 131 }
128 } 132 }
@@ -155,6 +159,8 @@ nlmsvc_find_block(struct nlm_cookie *cookie, struct sockaddr_in *sin)
155 break; 159 break;
156 } 160 }
157 161
162 if (block != NULL)
163 kref_get(&block->b_count);
158 return block; 164 return block;
159} 165}
160 166
@@ -188,6 +194,7 @@ nlmsvc_create_block(struct svc_rqst *rqstp, struct nlm_file *file,
188 memset(block, 0, sizeof(*block)); 194 memset(block, 0, sizeof(*block));
189 locks_init_lock(&block->b_call.a_args.lock.fl); 195 locks_init_lock(&block->b_call.a_args.lock.fl);
190 locks_init_lock(&block->b_call.a_res.lock.fl); 196 locks_init_lock(&block->b_call.a_res.lock.fl);
197 kref_init(&block->b_count);
191 198
192 if (!nlmclnt_setgrantargs(&block->b_call, lock)) 199 if (!nlmclnt_setgrantargs(&block->b_call, lock))
193 goto failed_free; 200 goto failed_free;
@@ -228,27 +235,24 @@ failed:
228 * It is the caller's responsibility to check whether the file 235 * It is the caller's responsibility to check whether the file
229 * can be closed hereafter. 236 * can be closed hereafter.
230 */ 237 */
231static int 238static int nlmsvc_unlink_block(struct nlm_block *block)
232nlmsvc_delete_block(struct nlm_block *block)
233{ 239{
234 struct file_lock *fl = &block->b_call.a_args.lock.fl;
235 struct nlm_file *file = block->b_file;
236 struct nlm_block **bp;
237 int status; 240 int status;
238 241 dprintk("lockd: unlinking block %p...\n", block);
239 dprintk("lockd: deleting block %p...\n", block);
240 242
241 /* Remove block from list */ 243 /* Remove block from list */
244 status = posix_unblock_lock(block->b_file->f_file, &block->b_call.a_args.lock.fl);
242 nlmsvc_remove_block(block); 245 nlmsvc_remove_block(block);
243 status = posix_unblock_lock(file->f_file, fl); 246 return status;
247}
244 248
245 /* If the block is in the middle of a GRANT callback, 249static void nlmsvc_free_block(struct kref *kref)
246 * don't kill it yet. */ 250{
247 if (block->b_incall) { 251 struct nlm_block *block = container_of(kref, struct nlm_block, b_count);
248 nlmsvc_insert_block(block, NLM_NEVER); 252 struct nlm_file *file = block->b_file;
249 block->b_done = 1; 253 struct nlm_block **bp;
250 return status; 254
251 } 255 dprintk("lockd: freeing block %p...\n", block);
252 256
253 /* Remove block from file's list of blocks */ 257 /* Remove block from file's list of blocks */
254 for (bp = &file->f_blocks; *bp; bp = &(*bp)->b_fnext) { 258 for (bp = &file->f_blocks; *bp; bp = &(*bp)->b_fnext) {
@@ -262,7 +266,12 @@ nlmsvc_delete_block(struct nlm_block *block)
262 nlm_release_host(block->b_host); 266 nlm_release_host(block->b_host);
263 nlmclnt_freegrantargs(&block->b_call); 267 nlmclnt_freegrantargs(&block->b_call);
264 kfree(block); 268 kfree(block);
265 return status; 269}
270
271static void nlmsvc_release_block(struct nlm_block *block)
272{
273 if (block != NULL)
274 kref_put(&block->b_count, nlmsvc_free_block);
266} 275}
267 276
268/* 277/*
@@ -282,7 +291,7 @@ nlmsvc_traverse_blocks(struct nlm_host *host, struct nlm_file *file, int action)
282 block->b_host->h_inuse = 1; 291 block->b_host->h_inuse = 1;
283 else if (action == NLM_ACT_UNLOCK) { 292 else if (action == NLM_ACT_UNLOCK) {
284 if (host == NULL || host == block->b_host) 293 if (host == NULL || host == block->b_host)
285 nlmsvc_delete_block(block); 294 nlmsvc_unlink_block(block);
286 } 295 }
287 } 296 }
288 up(&file->f_sema); 297 up(&file->f_sema);
@@ -318,9 +327,9 @@ again:
318 block = nlmsvc_lookup_block(file, lock, 0); 327 block = nlmsvc_lookup_block(file, lock, 0);
319 if (block == NULL) { 328 if (block == NULL) {
320 if (newblock != NULL) 329 if (newblock != NULL)
321 lock = &newblock->b_call.a_args.lock.fl; 330 lock = &newblock->b_call.a_args.lock;
322 } else 331 } else
323 lock = &block->b_call.a_args.lock.fl; 332 lock = &block->b_call.a_args.lock;
324 333
325 error = posix_lock_file(file->f_file, &lock->fl); 334 error = posix_lock_file(file->f_file, &lock->fl);
326 lock->fl.fl_flags &= ~FL_SLEEP; 335 lock->fl.fl_flags &= ~FL_SLEEP;
@@ -363,12 +372,10 @@ again:
363 372
364 /* Append to list of blocked */ 373 /* Append to list of blocked */
365 nlmsvc_insert_block(newblock, NLM_NEVER); 374 nlmsvc_insert_block(newblock, NLM_NEVER);
366 newblock = NULL;
367
368out: 375out:
369 up(&file->f_sema); 376 up(&file->f_sema);
370 if (newblock != NULL) 377 nlmsvc_release_block(newblock);
371 nlmsvc_delete_block(newblock); 378 nlmsvc_release_block(block);
372 dprintk("lockd: nlmsvc_lock returned %u\n", ret); 379 dprintk("lockd: nlmsvc_lock returned %u\n", ret);
373 return ret; 380 return ret;
374} 381}
@@ -450,8 +457,10 @@ nlmsvc_cancel_blocked(struct nlm_file *file, struct nlm_lock *lock)
450 (long long)lock->fl.fl_end); 457 (long long)lock->fl.fl_end);
451 458
452 down(&file->f_sema); 459 down(&file->f_sema);
453 if ((block = nlmsvc_lookup_block(file, lock, 1)) != NULL) 460 if ((block = nlmsvc_lookup_block(file, lock, 1)) != NULL) {
454 status = nlmsvc_delete_block(block); 461 status = nlmsvc_unlink_block(block);
462 nlmsvc_release_block(block);
463 }
455 up(&file->f_sema); 464 up(&file->f_sema);
456 return status ? nlm_lck_denied : nlm_granted; 465 return status ? nlm_lck_denied : nlm_granted;
457} 466}
@@ -514,7 +523,7 @@ nlmsvc_grant_blocked(struct nlm_block *block)
514 down(&file->f_sema); 523 down(&file->f_sema);
515 524
516 /* Unlink block request from list */ 525 /* Unlink block request from list */
517 nlmsvc_remove_block(block); 526 nlmsvc_unlink_block(block);
518 527
519 /* If b_granted is true this means we've been here before. 528 /* If b_granted is true this means we've been here before.
520 * Just retry the grant callback, possibly refreshing the RPC 529 * Just retry the grant callback, possibly refreshing the RPC
@@ -525,7 +534,6 @@ nlmsvc_grant_blocked(struct nlm_block *block)
525 } 534 }
526 535
527 /* Try the lock operation again */ 536 /* Try the lock operation again */
528 posix_unblock_lock(file->f_file, &lock->fl);
529 lock->fl.fl_flags |= FL_SLEEP; 537 lock->fl.fl_flags |= FL_SLEEP;
530 error = posix_lock_file(file->f_file, &lock->fl); 538 error = posix_lock_file(file->f_file, &lock->fl);
531 lock->fl.fl_flags &= ~FL_SLEEP; 539 lock->fl.fl_flags &= ~FL_SLEEP;
@@ -548,16 +556,15 @@ callback:
548 /* Lock was granted by VFS. */ 556 /* Lock was granted by VFS. */