Skip to content

Commit

Permalink
NFSD: handle GETATTR conflict with write delegation
Browse files Browse the repository at this point in the history
If the GETATTR request on a file that has write delegation in effect
and the request attributes include the change info and size attribute
then the write delegation is recalled. The server waits a maximum of
90ms for the delegation to be returned before replying NFS4ERR_DELAY
for the GETATTR.

Signed-off-by: Dai Ngo <dai.ngo@oracle.com>
  • Loading branch information
daimngo authored and intel-lab-lkp committed May 26, 2023
1 parent 0d85b27 commit dd8baf3
Show file tree
Hide file tree
Showing 3 changed files with 56 additions and 0 deletions.
48 changes: 48 additions & 0 deletions fs/nfsd/nfs4state.c
Expand Up @@ -8343,3 +8343,51 @@ nfsd4_get_writestateid(struct nfsd4_compound_state *cstate,
{
get_stateid(cstate, &u->write.wr_stateid);
}

/**
* nfsd4_deleg_getattr_conflict - Trigger recall if GETATTR causes conflict
* @rqstp: RPC transaction context
* @inode: file to be checked for a conflict
*
* Returns 0 if there is no conflict; otherwise an nfs_stat
* code is returned.
*/
__be32
nfsd4_deleg_getattr_conflict(struct svc_rqst *rqstp, struct inode *inode)
{
__be32 status;
int cnt;
struct file_lock_context *ctx;
struct file_lock *fl;
struct nfs4_delegation *dp;

ctx = locks_inode_context(inode);
if (!ctx)
return 0;
spin_lock(&ctx->flc_lock);
list_for_each_entry(fl, &ctx->flc_lease, fl_list) {
if (fl->fl_flags == FL_LAYOUT ||
fl->fl_lmops != &nfsd_lease_mng_ops)
continue;
if (fl->fl_type == F_WRLCK) {
dp = fl->fl_owner;
if (dp->dl_recall.cb_clp == *(rqstp->rq_lease_breaker)) {
spin_unlock(&ctx->flc_lock);
return 0;
}
spin_unlock(&ctx->flc_lock);
status = nfserrno(nfsd_open_break_lease(inode, NFSD_MAY_READ));
if (status != nfserr_jukebox)
return status;
for (cnt = 3; cnt > 0; --cnt) {
if (!nfsd_wait_for_delegreturn(rqstp, inode))
continue;
return 0;
}
return status;
}
break;
}
spin_unlock(&ctx->flc_lock);
return 0;
}
5 changes: 5 additions & 0 deletions fs/nfsd/nfs4xdr.c
Expand Up @@ -2966,6 +2966,11 @@ nfsd4_encode_fattr(struct xdr_stream *xdr, struct svc_fh *fhp,
if (status)
goto out;
}
if (bmval0 & (FATTR4_WORD0_CHANGE | FATTR4_WORD0_SIZE)) {
status = nfsd4_deleg_getattr_conflict(rqstp, d_inode(dentry));
if (status)
goto out;
}

err = vfs_getattr(&path, &stat,
STATX_BASIC_STATS | STATX_BTIME | STATX_CHANGE_COOKIE,
Expand Down
3 changes: 3 additions & 0 deletions fs/nfsd/state.h
Expand Up @@ -732,4 +732,7 @@ static inline bool try_to_expire_client(struct nfs4_client *clp)
cmpxchg(&clp->cl_state, NFSD4_COURTESY, NFSD4_EXPIRABLE);
return clp->cl_state == NFSD4_EXPIRABLE;
}

extern __be32 nfsd4_deleg_getattr_conflict(struct svc_rqst *rqstp,
struct inode *inode);
#endif /* NFSD4_STATE_H */

0 comments on commit dd8baf3

Please sign in to comment.