@@ -3546,12 +3546,20 @@ out_fput:
return status;
}
-static int nfs4_set_delegation(struct nfs4_delegation *dp, struct nfs4_file *fp)
+static struct nfs4_delegation *
+nfs4_set_delegation(struct nfs4_client *clp, struct svc_fh *fh,
+ struct nfs4_file *fp)
{
- int status = 0;
+ int status;
+ struct nfs4_delegation *dp;
if (fp->fi_had_conflict)
- return -EAGAIN;
+ return ERR_PTR(-EAGAIN);
+
+ dp = alloc_init_deleg(clp, fh);
+ if (!dp)
+ return ERR_PTR(-ENOMEM);
+
get_nfs4_file(fp);
spin_lock(&state_lock);
spin_lock(&fp->fi_lock);
@@ -3559,7 +3567,8 @@ static int nfs4_set_delegation(struct nfs4_delegation *dp, struct nfs4_file *fp)
if (!fp->fi_lease) {
spin_unlock(&fp->fi_lock);
spin_unlock(&state_lock);
- return nfs4_setlease(dp);
+ status = nfs4_setlease(dp);
+ goto out;
}
atomic_inc(&fp->fi_delegees);
if (fp->fi_had_conflict) {
@@ -3567,10 +3576,16 @@ static int nfs4_set_delegation(struct nfs4_delegation *dp, struct nfs4_file *fp)
goto out_unlock;
}
hash_delegation_locked(dp, fp);
+ status = 0;
out_unlock:
spin_unlock(&fp->fi_lock);
spin_unlock(&state_lock);
- return status;
+out:
+ if (status) {
+ nfs4_put_delegation(dp);
+ return ERR_PTR(status);
+ }
+ return dp;
}
static void nfsd4_open_deleg_none_ext(struct nfsd4_open *open, int status)
@@ -3644,12 +3659,9 @@ nfs4_open_delegation(struct svc_fh *fh, struct nfsd4_open *open,
default:
goto out_no_deleg;
}
- dp = alloc_init_deleg(clp, fh);
- if (dp == NULL)
+ dp = nfs4_set_delegation(clp, fh, stp->st_file);
+ if (IS_ERR(dp))
goto out_no_deleg;
- status = nfs4_set_delegation(dp, stp->st_file);
- if (status)
- goto out_free;
memcpy(&open->op_delegate_stateid, &dp->dl_stid.sc_stateid, sizeof(dp->dl_stid.sc_stateid));
@@ -3657,8 +3669,6 @@ nfs4_open_delegation(struct svc_fh *fh, struct nfsd4_open *open,
STATEID_VAL(&dp->dl_stid.sc_stateid));
open->op_delegate_type = NFS4_OPEN_DELEGATE_READ;
return;
-out_free:
- nfs4_put_delegation(dp);
out_no_deleg:
open->op_delegate_type = NFS4_OPEN_DELEGATE_NONE;
if (open->op_claim_type == NFS4_OPEN_CLAIM_PREVIOUS &&