diff --git a/fs/nfs/delegation.c b/fs/nfs/delegation.c index 44135af9894c..3976c177a7d0 100644 --- a/fs/nfs/delegation.c +++ b/fs/nfs/delegation.c @@ -31,11 +31,42 @@ static void nfs_free_delegation(struct nfs_delegation *delegation) kfree(delegation); } +static int nfs_delegation_claim_locks(struct nfs_open_context *ctx, struct nfs4_state *state) +{ + struct inode *inode = state->inode; + struct file_lock *fl; + int status; + + for (fl = inode->i_flock; fl != 0; fl = fl->fl_next) { + if (!(fl->fl_flags & (FL_POSIX|FL_FLOCK))) + continue; + if ((struct nfs_open_context *)fl->fl_file->private_data != ctx) + continue; + status = nfs4_lock_delegation_recall(state, fl); + if (status >= 0) + continue; + switch (status) { + default: + printk(KERN_ERR "%s: unhandled error %d.\n", + __FUNCTION__, status); + case -NFS4ERR_EXPIRED: + /* kill_proc(fl->fl_pid, SIGLOST, 1); */ + case -NFS4ERR_STALE_CLIENTID: + nfs4_schedule_state_recovery(NFS_SERVER(inode)->nfs4_state); + goto out_err; + } + } + return 0; +out_err: + return status; +} + static void nfs_delegation_claim_opens(struct inode *inode) { struct nfs_inode *nfsi = NFS_I(inode); struct nfs_open_context *ctx; struct nfs4_state *state; + int err; again: spin_lock(&inode->i_lock); @@ -47,9 +78,12 @@ again: continue; get_nfs_open_context(ctx); spin_unlock(&inode->i_lock); - if (nfs4_open_delegation_recall(ctx->dentry, state) < 0) - return; + err = nfs4_open_delegation_recall(ctx->dentry, state); + if (err >= 0) + err = nfs_delegation_claim_locks(ctx, state); put_nfs_open_context(ctx); + if (err != 0) + return; goto again; } spin_unlock(&inode->i_lock); diff --git a/fs/nfs/delegation.h b/fs/nfs/delegation.h index 8017846b561f..2fcc30de924b 100644 --- a/fs/nfs/delegation.h +++ b/fs/nfs/delegation.h @@ -38,6 +38,7 @@ void nfs_delegation_reap_unclaimed(struct nfs4_client *clp); /* NFSv4 delegation-related procedures */ int nfs4_proc_delegreturn(struct inode *inode, struct rpc_cred *cred, const nfs4_stateid *stateid); int nfs4_open_delegation_recall(struct dentry *dentry, struct nfs4_state *state); +int nfs4_lock_delegation_recall(struct nfs4_state *state, struct file_lock *fl); static inline int nfs_have_delegation(struct inode *inode, int flags) { diff --git a/fs/nfs/nfs4proc.c b/fs/nfs/nfs4proc.c index 54ff465cf7cf..e6a9322a321f 100644 --- a/fs/nfs/nfs4proc.c +++ b/fs/nfs/nfs4proc.c @@ -3124,6 +3124,24 @@ nfs4_proc_lock(struct file *filp, int cmd, struct file_lock *request) return status; } +int nfs4_lock_delegation_recall(struct nfs4_state *state, struct file_lock *fl) +{ + struct nfs_server *server = NFS_SERVER(state->inode); + struct nfs4_exception exception = { }; + int err; + + err = nfs4_set_lock_state(state, fl); + if (err != 0) + goto out; + do { + err = _nfs4_do_setlk(state, F_SETLK, fl, 0); + if (err != -NFS4ERR_DELAY) + break; + err = nfs4_handle_exception(server, err, &exception); + } while (exception.retry); +out: + return err; +} #define XATTR_NAME_NFSV4_ACL "system.nfs4_acl"