aboutsummaryrefslogtreecommitdiffstats
path: root/fs/nfsd/nfs4state.c
diff options
context:
space:
mode:
authorJ. Bruce Fields <bfields@redhat.com>2014-03-03 12:19:18 -0500
committerJ. Bruce Fields <bfields@redhat.com>2014-05-21 12:17:17 -0400
commitcbf7a75bc58a2458bd6e47476e47819ba3f40b00 (patch)
tree65e42946837a0c4d3506c4d246f11ee7bd884f47 /fs/nfsd/nfs4state.c
parentNFSD: Don't clear SUID/SGID after root writing data (diff)
downloadlinux-dev-cbf7a75bc58a2458bd6e47476e47819ba3f40b00.tar.xz
linux-dev-cbf7a75bc58a2458bd6e47476e47819ba3f40b00.zip
nfsd4: fix delegation cleanup on error
We're not cleaning up everything we need to on error. In particular, we're not removing our lease. Among other problems this can cause the struct nfs4_file used as fl_owner to be referenced after it has been destroyed. Signed-off-by: J. Bruce Fields <bfields@redhat.com>
Diffstat (limited to 'fs/nfsd/nfs4state.c')
-rw-r--r--fs/nfsd/nfs4state.c32
1 files changed, 12 insertions, 20 deletions
diff --git a/fs/nfsd/nfs4state.c b/fs/nfsd/nfs4state.c
index fac26836e4ac..c6ded9feaef9 100644
--- a/fs/nfsd/nfs4state.c
+++ b/fs/nfsd/nfs4state.c
@@ -418,6 +418,8 @@ nfs4_put_delegation(struct nfs4_delegation *dp)
static void nfs4_put_deleg_lease(struct nfs4_file *fp)
{
+ if (!fp->fi_lease)
+ return;
if (atomic_dec_and_test(&fp->fi_delegees)) {
vfs_setlease(fp->fi_deleg_file, F_UNLCK, &fp->fi_lease);
fp->fi_lease = NULL;
@@ -440,9 +442,11 @@ unhash_delegation(struct nfs4_delegation *dp)
list_del_init(&dp->dl_perfile);
list_del_init(&dp->dl_recall_lru);
spin_unlock(&recall_lock);
- nfs4_put_deleg_lease(dp->dl_file);
- put_nfs4_file(dp->dl_file);
- dp->dl_file = NULL;
+ if (dp->dl_file) {
+ nfs4_put_deleg_lease(dp->dl_file);
+ put_nfs4_file(dp->dl_file);
+ dp->dl_file = NULL;
+ }
}
@@ -3060,33 +3064,22 @@ out_free:
static int nfs4_set_delegation(struct nfs4_delegation *dp, struct nfs4_file *fp)
{
- int status;
-
if (fp->fi_had_conflict)
return -EAGAIN;
get_nfs4_file(fp);
dp->dl_file = fp;
- if (!fp->fi_lease) {
- status = nfs4_setlease(dp);
- if (status)
- goto out_free;
- return 0;
- }
+ if (!fp->fi_lease)
+ return nfs4_setlease(dp);
spin_lock(&recall_lock);
+ atomic_inc(&fp->fi_delegees);
if (fp->fi_had_conflict) {
spin_unlock(&recall_lock);
- status = -EAGAIN;
- goto out_free;
+ return -EAGAIN;
}
- atomic_inc(&fp->fi_delegees);
list_add(&dp->dl_perfile, &fp->fi_delegations);
spin_unlock(&recall_lock);
list_add(&dp->dl_perclnt, &dp->dl_stid.sc_client->cl_delegations);
return 0;
-out_free:
- put_nfs4_file(fp);
- dp->dl_file = fp;
- return status;
}
static void nfsd4_open_deleg_none_ext(struct nfsd4_open *open, int status)
@@ -3173,8 +3166,7 @@ nfs4_open_delegation(struct net *net, struct svc_fh *fh,
open->op_delegate_type = NFS4_OPEN_DELEGATE_READ;
return;
out_free:
- remove_stid(&dp->dl_stid);
- nfs4_put_delegation(dp);
+ destroy_delegation(dp);
out_no_deleg:
open->op_delegate_type = NFS4_OPEN_DELEGATE_NONE;
if (open->op_claim_type == NFS4_OPEN_CLAIM_PREVIOUS &&