Commit da05ba23 authored by Jeff Layton's avatar Jeff Layton Committed by Chuck Lever

nfsd: hold reference to delegation when updating it for cb_getattr

Once we've dropped the flc_lock, there is nothing that ensures that the
delegation that was found will still be around later. Take a reference
to it while holding the lock and then drop it when we've finished with
the delegation.

Fixes: c5967721 ("NFSD: handle GETATTR conflict with write delegation")
Signed-off-by: default avatarJeff Layton <jlayton@kernel.org>
Signed-off-by: default avatarChuck Lever <chuck.lever@oracle.com>
parent f25d1b5f
...@@ -8837,7 +8837,6 @@ nfsd4_deleg_getattr_conflict(struct svc_rqst *rqstp, struct inode *inode, ...@@ -8837,7 +8837,6 @@ nfsd4_deleg_getattr_conflict(struct svc_rqst *rqstp, struct inode *inode,
struct nfsd_net *nn = net_generic(SVC_NET(rqstp), nfsd_net_id); struct nfsd_net *nn = net_generic(SVC_NET(rqstp), nfsd_net_id);
struct file_lock_context *ctx; struct file_lock_context *ctx;
struct file_lease *fl; struct file_lease *fl;
struct nfs4_delegation *dp;
struct iattr attrs; struct iattr attrs;
struct nfs4_cb_fattr *ncf; struct nfs4_cb_fattr *ncf;
...@@ -8862,7 +8861,8 @@ nfsd4_deleg_getattr_conflict(struct svc_rqst *rqstp, struct inode *inode, ...@@ -8862,7 +8861,8 @@ nfsd4_deleg_getattr_conflict(struct svc_rqst *rqstp, struct inode *inode,
goto break_lease; goto break_lease;
} }
if (type == F_WRLCK) { if (type == F_WRLCK) {
dp = fl->c.flc_owner; struct nfs4_delegation *dp = fl->c.flc_owner;
if (dp->dl_recall.cb_clp == *(rqstp->rq_lease_breaker)) { if (dp->dl_recall.cb_clp == *(rqstp->rq_lease_breaker)) {
spin_unlock(&ctx->flc_lock); spin_unlock(&ctx->flc_lock);
return 0; return 0;
...@@ -8870,6 +8870,7 @@ nfsd4_deleg_getattr_conflict(struct svc_rqst *rqstp, struct inode *inode, ...@@ -8870,6 +8870,7 @@ nfsd4_deleg_getattr_conflict(struct svc_rqst *rqstp, struct inode *inode,
break_lease: break_lease:
nfsd_stats_wdeleg_getattr_inc(nn); nfsd_stats_wdeleg_getattr_inc(nn);
dp = fl->c.flc_owner; dp = fl->c.flc_owner;
refcount_inc(&dp->dl_stid.sc_count);
ncf = &dp->dl_cb_fattr; ncf = &dp->dl_cb_fattr;
nfs4_cb_getattr(&dp->dl_cb_fattr); nfs4_cb_getattr(&dp->dl_cb_fattr);
spin_unlock(&ctx->flc_lock); spin_unlock(&ctx->flc_lock);
...@@ -8879,8 +8880,10 @@ nfsd4_deleg_getattr_conflict(struct svc_rqst *rqstp, struct inode *inode, ...@@ -8879,8 +8880,10 @@ nfsd4_deleg_getattr_conflict(struct svc_rqst *rqstp, struct inode *inode,
/* Recall delegation only if client didn't respond */ /* Recall delegation only if client didn't respond */
status = nfserrno(nfsd_open_break_lease(inode, NFSD_MAY_READ)); status = nfserrno(nfsd_open_break_lease(inode, NFSD_MAY_READ));
if (status != nfserr_jukebox || if (status != nfserr_jukebox ||
!nfsd_wait_for_delegreturn(rqstp, inode)) !nfsd_wait_for_delegreturn(rqstp, inode)) {
nfs4_put_stid(&dp->dl_stid);
return status; return status;
}
} }
if (!ncf->ncf_file_modified && if (!ncf->ncf_file_modified &&
(ncf->ncf_initial_cinfo != ncf->ncf_cb_change || (ncf->ncf_initial_cinfo != ncf->ncf_cb_change ||
...@@ -8900,6 +8903,7 @@ nfsd4_deleg_getattr_conflict(struct svc_rqst *rqstp, struct inode *inode, ...@@ -8900,6 +8903,7 @@ nfsd4_deleg_getattr_conflict(struct svc_rqst *rqstp, struct inode *inode,
*size = ncf->ncf_cur_fsize; *size = ncf->ncf_cur_fsize;
*modified = true; *modified = true;
} }
nfs4_put_stid(&dp->dl_stid);
return 0; return 0;
} }
break; break;
......
Markdown is supported
0%
or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment