NLM,NFSv4: Wait on local locks before we put RPC calls on the wire

Use FL_ACCESS flag to test and/or wait for local locks before we try
requesting a lock from the server

Signed-off-by: Trond Myklebust <Trond.Myklebust@netapp.com>

+31 -12
+7 -1
fs/lockd/clntproc.c
··· 496 496 struct nlm_host *host = req->a_host; 497 497 struct nlm_res *resp = &req->a_res; 498 498 struct nlm_wait *block = NULL; 499 + unsigned char fl_flags = fl->fl_flags; 499 500 int status = -ENOLCK; 500 501 501 502 if (!host->h_monitored && nsm_monitor(host) < 0) { ··· 504 503 host->h_name); 505 504 goto out; 506 505 } 506 + fl->fl_flags |= FL_ACCESS; 507 + status = do_vfs_lock(fl); 508 + if (status < 0) 509 + goto out; 507 510 508 511 block = nlmclnt_prepare_block(host, fl); 509 512 again: ··· 542 537 up_read(&host->h_rwsem); 543 538 goto again; 544 539 } 545 - fl->fl_flags |= FL_SLEEP; 546 540 /* Ensure the resulting lock will get added to granted list */ 541 + fl->fl_flags = fl_flags | FL_SLEEP; 547 542 if (do_vfs_lock(fl) < 0) 548 543 printk(KERN_WARNING "%s: VFS is out of sync with lock manager!\n", __FUNCTION__); 549 544 up_read(&host->h_rwsem); ··· 556 551 nlmclnt_cancel(host, req->a_args.block, fl); 557 552 out: 558 553 nlm_release_call(req); 554 + fl->fl_flags = fl_flags; 559 555 return status; 560 556 } 561 557
+24 -11
fs/nfs/nfs4proc.c
··· 3489 3489 static int _nfs4_proc_setlk(struct nfs4_state *state, int cmd, struct file_lock *request) 3490 3490 { 3491 3491 struct nfs4_client *clp = state->owner->so_client; 3492 + unsigned char fl_flags = request->fl_flags; 3492 3493 int status; 3493 3494 3494 3495 /* Is this a delegated open? */ 3495 - if (NFS_I(state->inode)->delegation_state != 0) { 3496 - /* Yes: cache locks! */ 3497 - status = do_vfs_lock(request->fl_file, request); 3498 - /* ...but avoid races with delegation recall... */ 3499 - if (status < 0 || test_bit(NFS_DELEGATED_STATE, &state->flags)) 3500 - return status; 3501 - } 3502 - down_read(&clp->cl_sem); 3503 3496 status = nfs4_set_lock_state(state, request); 3504 3497 if (status != 0) 3505 3498 goto out; 3499 + request->fl_flags |= FL_ACCESS; 3500 + status = do_vfs_lock(request->fl_file, request); 3501 + if (status < 0) 3502 + goto out; 3503 + down_read(&clp->cl_sem); 3504 + if (test_bit(NFS_DELEGATED_STATE, &state->flags)) { 3505 + struct nfs_inode *nfsi = NFS_I(state->inode); 3506 + /* Yes: cache locks! */ 3507 + down_read(&nfsi->rwsem); 3508 + /* ...but avoid races with delegation recall... */ 3509 + if (test_bit(NFS_DELEGATED_STATE, &state->flags)) { 3510 + request->fl_flags = fl_flags & ~FL_SLEEP; 3511 + status = do_vfs_lock(request->fl_file, request); 3512 + up_read(&nfsi->rwsem); 3513 + goto out_unlock; 3514 + } 3515 + up_read(&nfsi->rwsem); 3516 + } 3506 3517 status = _nfs4_do_setlk(state, cmd, request, 0); 3507 3518 if (status != 0) 3508 - goto out; 3519 + goto out_unlock; 3509 3520 /* Note: we always want to sleep here! */ 3510 - request->fl_flags |= FL_SLEEP; 3521 + request->fl_flags = fl_flags | FL_SLEEP; 3511 3522 if (do_vfs_lock(request->fl_file, request) < 0) 3512 3523 printk(KERN_WARNING "%s: VFS is out of sync with lock manager!\n", __FUNCTION__); 3513 - out: 3524 + out_unlock: 3514 3525 up_read(&clp->cl_sem); 3526 + out: 3527 + request->fl_flags = fl_flags; 3515 3528 return status; 3516 3529 } 3517 3530