aboutsummaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
-rw-r--r--fs/lockd/svclock.c73
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 */
230static int 231static int
231nlmsvc_delete_block(struct nlm_block *block, int unlock) 232nlmsvc_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
297nlmsvc_lock(struct svc_rqst *rqstp, struct nlm_file *file, 297nlmsvc_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
316again: 314again:
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;
363out_unlock:
364 up(&file->f_sema);
365out: 368out:
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 }