diff options
author | Trond Myklebust <Trond.Myklebust@netapp.com> | 2006-03-20 13:44:38 -0500 |
---|---|---|
committer | Trond Myklebust <Trond.Myklebust@netapp.com> | 2006-03-20 13:44:38 -0500 |
commit | 09c7938c5640a6f22bef074ca6b803dccfdb93e3 (patch) | |
tree | 71a6a0f66349ae46a0f816de8c8ddf952070af87 /fs | |
parent | 0996905f9301c2ff4c021982c42a15b35e74bf1c (diff) |
lockd: Fix server-side lock blocking code
Signed-off-by: Trond Myklebust <Trond.Myklebust@netapp.com>
Diffstat (limited to 'fs')
-rw-r--r-- | fs/lockd/svclock.c | 73 |
1 files changed, 40 insertions, 33 deletions
diff --git a/fs/lockd/svclock.c b/fs/lockd/svclock.c index d50946dcddd9..1d3a74df93f3 100644 --- a/fs/lockd/svclock.c +++ b/fs/lockd/svclock.c | |||
@@ -193,6 +193,7 @@ nlmsvc_create_block(struct svc_rqst *rqstp, struct nlm_file *file, | |||
193 | goto failed_free; | 193 | goto failed_free; |
194 | 194 | ||
195 | /* Set notifier function for VFS, and init args */ | 195 | /* Set notifier function for VFS, and init args */ |
196 | block->b_call.a_args.lock.fl.fl_flags |= FL_SLEEP; | ||
196 | block->b_call.a_args.lock.fl.fl_lmops = &nlmsvc_lock_operations; | 197 | block->b_call.a_args.lock.fl.fl_lmops = &nlmsvc_lock_operations; |
197 | block->b_call.a_args.cookie = *cookie; /* see above */ | 198 | block->b_call.a_args.cookie = *cookie; /* see above */ |
198 | 199 | ||
@@ -228,19 +229,18 @@ failed: | |||
228 | * can be closed hereafter. | 229 | * can be closed hereafter. |
229 | */ | 230 | */ |
230 | static int | 231 | static int |
231 | nlmsvc_delete_block(struct nlm_block *block, int unlock) | 232 | nlmsvc_delete_block(struct nlm_block *block) |
232 | { | 233 | { |
233 | struct file_lock *fl = &block->b_call.a_args.lock.fl; | 234 | struct file_lock *fl = &block->b_call.a_args.lock.fl; |
234 | struct nlm_file *file = block->b_file; | 235 | struct nlm_file *file = block->b_file; |
235 | struct nlm_block **bp; | 236 | struct nlm_block **bp; |
236 | int status = 0; | 237 | int status; |
237 | 238 | ||
238 | dprintk("lockd: deleting block %p...\n", block); | 239 | dprintk("lockd: deleting block %p...\n", block); |
239 | 240 | ||
240 | /* Remove block from list */ | 241 | /* Remove block from list */ |
241 | nlmsvc_remove_block(block); | 242 | nlmsvc_remove_block(block); |
242 | if (unlock) | 243 | status = posix_unblock_lock(file->f_file, fl); |
243 | status = posix_unblock_lock(file->f_file, fl); | ||
244 | 244 | ||
245 | /* If the block is in the middle of a GRANT callback, | 245 | /* If the block is in the middle of a GRANT callback, |
246 | * don't kill it yet. */ | 246 | * don't kill it yet. */ |
@@ -282,7 +282,7 @@ nlmsvc_traverse_blocks(struct nlm_host *host, struct nlm_file *file, int action) | |||
282 | block->b_host->h_inuse = 1; | 282 | block->b_host->h_inuse = 1; |
283 | else if (action == NLM_ACT_UNLOCK) { | 283 | else if (action == NLM_ACT_UNLOCK) { |
284 | if (host == NULL || host == block->b_host) | 284 | if (host == NULL || host == block->b_host) |
285 | nlmsvc_delete_block(block, 1); | 285 | nlmsvc_delete_block(block); |
286 | } | 286 | } |
287 | } | 287 | } |
288 | up(&file->f_sema); | 288 | up(&file->f_sema); |
@@ -297,7 +297,7 @@ u32 | |||
297 | nlmsvc_lock(struct svc_rqst *rqstp, struct nlm_file *file, | 297 | nlmsvc_lock(struct svc_rqst *rqstp, struct nlm_file *file, |
298 | struct nlm_lock *lock, int wait, struct nlm_cookie *cookie) | 298 | struct nlm_lock *lock, int wait, struct nlm_cookie *cookie) |
299 | { | 299 | { |
300 | struct nlm_block *block; | 300 | struct nlm_block *block, *newblock = NULL; |
301 | int error; | 301 | int error; |
302 | u32 ret; | 302 | u32 ret; |
303 | 303 | ||
@@ -310,59 +310,65 @@ nlmsvc_lock(struct svc_rqst *rqstp, struct nlm_file *file, | |||
310 | wait); | 310 | wait); |
311 | 311 | ||
312 | 312 | ||
313 | /* Get existing block (in case client is busy-waiting) */ | 313 | lock->fl.fl_flags &= ~FL_SLEEP; |
314 | block = nlmsvc_lookup_block(file, lock, 0); | ||
315 | |||
316 | again: | 314 | again: |
317 | /* Lock file against concurrent access */ | 315 | /* Lock file against concurrent access */ |
318 | down(&file->f_sema); | 316 | down(&file->f_sema); |
317 | /* Get existing block (in case client is busy-waiting) */ | ||
318 | block = nlmsvc_lookup_block(file, lock, 0); | ||
319 | if (block == NULL) { | ||
320 | if (newblock != NULL) | ||
321 | lock = &newblock->b_call.a_args.lock.fl; | ||
322 | } else | ||
323 | lock = &block->b_call.a_args.lock.fl; | ||
319 | 324 | ||
320 | error = posix_lock_file(file->f_file, &lock->fl); | 325 | error = posix_lock_file(file->f_file, &lock->fl); |
326 | lock->fl.fl_flags &= ~FL_SLEEP; | ||
321 | 327 | ||
322 | dprintk("lockd: posix_lock_file returned %d\n", error); | 328 | dprintk("lockd: posix_lock_file returned %d\n", error); |
323 | 329 | ||
324 | if (error != -EAGAIN) { | 330 | switch(error) { |
325 | if (block) | ||
326 | nlmsvc_delete_block(block, 0); | ||
327 | up(&file->f_sema); | ||
328 | |||
329 | switch(-error) { | ||
330 | case 0: | 331 | case 0: |
331 | ret = nlm_granted; | 332 | ret = nlm_granted; |
332 | goto out; | 333 | goto out; |
333 | case EDEADLK: | 334 | case -EAGAIN: |
335 | break; | ||
336 | case -EDEADLK: | ||
334 | ret = nlm_deadlock; | 337 | ret = nlm_deadlock; |
335 | goto out; | 338 | goto out; |
336 | default: /* includes ENOLCK */ | 339 | default: /* includes ENOLCK */ |
337 | ret = nlm_lck_denied_nolocks; | 340 | ret = nlm_lck_denied_nolocks; |
338 | goto out; | 341 | goto out; |
339 | } | ||
340 | } | 342 | } |
341 | 343 | ||
342 | if (!wait) { | 344 | ret = nlm_lck_denied; |
343 | ret = nlm_lck_denied; | 345 | if (!wait) |
344 | goto out_unlock; | 346 | goto out; |
345 | } | 347 | |
348 | ret = nlm_lck_blocked; | ||
349 | if (block != NULL) | ||
350 | goto out; | ||
346 | 351 | ||
347 | /* If we don't have a block, create and initialize it. Then | 352 | /* If we don't have a block, create and initialize it. Then |
348 | * retry because we may have slept in kmalloc. */ | 353 | * retry because we may have slept in kmalloc. */ |
349 | /* We have to release f_sema as nlmsvc_create_block may try to | 354 | /* We have to release f_sema as nlmsvc_create_block may try to |
350 | * to claim it while doing host garbage collection */ | 355 | * to claim it while doing host garbage collection */ |
351 | if (block == NULL) { | 356 | if (newblock == NULL) { |
352 | up(&file->f_sema); | 357 | up(&file->f_sema); |
353 | dprintk("lockd: blocking on this lock (allocating).\n"); | 358 | dprintk("lockd: blocking on this lock (allocating).\n"); |
354 | if (!(block = nlmsvc_create_block(rqstp, file, lock, cookie))) | 359 | if (!(newblock = nlmsvc_create_block(rqstp, file, lock, cookie))) |
355 | return nlm_lck_denied_nolocks; | 360 | return nlm_lck_denied_nolocks; |
356 | goto again; | 361 | goto again; |
357 | } | 362 | } |
358 | 363 | ||
359 | /* Append to list of blocked */ | 364 | /* Append to list of blocked */ |
360 | nlmsvc_insert_block(block, NLM_NEVER); | 365 | nlmsvc_insert_block(newblock, NLM_NEVER); |
366 | newblock = NULL; | ||
361 | 367 | ||
362 | ret = nlm_lck_blocked; | ||
363 | out_unlock: | ||
364 | up(&file->f_sema); | ||
365 | out: | 368 | out: |
369 | up(&file->f_sema); | ||
370 | if (newblock != NULL) | ||
371 | nlmsvc_delete_block(newblock); | ||
366 | dprintk("lockd: nlmsvc_lock returned %u\n", ret); | 372 | dprintk("lockd: nlmsvc_lock returned %u\n", ret); |
367 | return ret; | 373 | return ret; |
368 | } | 374 | } |
@@ -445,7 +451,7 @@ nlmsvc_cancel_blocked(struct nlm_file *file, struct nlm_lock *lock) | |||
445 | 451 | ||
446 | down(&file->f_sema); | 452 | down(&file->f_sema); |
447 | if ((block = nlmsvc_lookup_block(file, lock, 1)) != NULL) | 453 | if ((block = nlmsvc_lookup_block(file, lock, 1)) != NULL) |
448 | status = nlmsvc_delete_block(block, 1); | 454 | status = nlmsvc_delete_block(block); |
449 | up(&file->f_sema); | 455 | up(&file->f_sema); |
450 | return status ? nlm_lck_denied : nlm_granted; | 456 | return status ? nlm_lck_denied : nlm_granted; |
451 | } | 457 | } |
@@ -519,7 +525,11 @@ nlmsvc_grant_blocked(struct nlm_block *block) | |||
519 | } | 525 | } |
520 | 526 | ||
521 | /* Try the lock operation again */ | 527 | /* Try the lock operation again */ |
528 | posix_unblock_lock(file->f_file, &lock->fl); | ||
529 | lock->fl.fl_flags |= FL_SLEEP; | ||
522 | error = posix_lock_file(file->f_file, &lock->fl); | 530 | error = posix_lock_file(file->f_file, &lock->fl); |
531 | lock->fl.fl_flags &= ~FL_SLEEP; | ||
532 | |||
523 | switch (error) { | 533 | switch (error) { |
524 | case 0: | 534 | case 0: |
525 | break; | 535 | break; |
@@ -630,11 +640,8 @@ nlmsvc_grant_reply(struct svc_rqst *rqstp, struct nlm_cookie *cookie, u32 status | |||
630 | } else { | 640 | } else { |
631 | /* Lock is now held by client, or has been rejected. | 641 | /* Lock is now held by client, or has been rejected. |
632 | * In both cases, the block should be removed. */ | 642 | * In both cases, the block should be removed. */ |
643 | nlmsvc_delete_block(block); | ||
633 | up(&file->f_sema); | 644 | up(&file->f_sema); |
634 | if (status == NLM_LCK_GRANTED) | ||
635 | nlmsvc_delete_block(block, 0); | ||
636 | else | ||
637 | nlmsvc_delete_block(block, 1); | ||
638 | } | 645 | } |
639 | } | 646 | } |
640 | nlm_release_file(file); | 647 | nlm_release_file(file); |
@@ -661,7 +668,7 @@ nlmsvc_retry_blocked(void) | |||
661 | dprintk("nlmsvc_retry_blocked(%p, when=%ld, done=%d)\n", | 668 | dprintk("nlmsvc_retry_blocked(%p, when=%ld, done=%d)\n", |
662 | block, block->b_when, block->b_done); | 669 | block, block->b_when, block->b_done); |
663 | if (block->b_done) | 670 | if (block->b_done) |
664 | nlmsvc_delete_block(block, 0); | 671 | nlmsvc_delete_block(block); |
665 | else | 672 | else |
666 | nlmsvc_grant_blocked(block); | 673 | nlmsvc_grant_blocked(block); |
667 | } | 674 | } |