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

nfsd: fix initial getattr on write delegation

At this point in compound processing, currentfh refers to the parent of
the file, not the file itself. Get the correct dentry from the delegation
stateid instead.

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 a078a7dc
...@@ -5914,6 +5914,28 @@ static void nfsd4_open_deleg_none_ext(struct nfsd4_open *open, int status) ...@@ -5914,6 +5914,28 @@ static void nfsd4_open_deleg_none_ext(struct nfsd4_open *open, int status)
} }
} }
static bool
nfs4_delegation_stat(struct nfs4_delegation *dp, struct svc_fh *currentfh,
struct kstat *stat)
{
struct nfsd_file *nf = find_rw_file(dp->dl_stid.sc_file);
struct path path;
int rc;
if (!nf)
return false;
path.mnt = currentfh->fh_export->ex_path.mnt;
path.dentry = file_dentry(nf->nf_file);
rc = vfs_getattr(&path, stat,
(STATX_SIZE | STATX_CTIME | STATX_CHANGE_COOKIE),
AT_STATX_SYNC_AS_STAT);
nfsd_file_put(nf);
return rc == 0;
}
/* /*
* The Linux NFS server does not offer write delegations to NFSv4.0 * The Linux NFS server does not offer write delegations to NFSv4.0
* clients in order to avoid conflicts between write delegations and * clients in order to avoid conflicts between write delegations and
...@@ -5949,7 +5971,6 @@ nfs4_open_delegation(struct nfsd4_open *open, struct nfs4_ol_stateid *stp, ...@@ -5949,7 +5971,6 @@ nfs4_open_delegation(struct nfsd4_open *open, struct nfs4_ol_stateid *stp,
int cb_up; int cb_up;
int status = 0; int status = 0;
struct kstat stat; struct kstat stat;
struct path path;
cb_up = nfsd4_cb_channel_good(oo->oo_owner.so_client); cb_up = nfsd4_cb_channel_good(oo->oo_owner.so_client);
open->op_recall = false; open->op_recall = false;
...@@ -5985,20 +6006,16 @@ nfs4_open_delegation(struct nfsd4_open *open, struct nfs4_ol_stateid *stp, ...@@ -5985,20 +6006,16 @@ nfs4_open_delegation(struct nfsd4_open *open, struct nfs4_ol_stateid *stp,
memcpy(&open->op_delegate_stateid, &dp->dl_stid.sc_stateid, sizeof(dp->dl_stid.sc_stateid)); memcpy(&open->op_delegate_stateid, &dp->dl_stid.sc_stateid, sizeof(dp->dl_stid.sc_stateid));
if (open->op_share_access & NFS4_SHARE_ACCESS_WRITE) { if (open->op_share_access & NFS4_SHARE_ACCESS_WRITE) {
open->op_delegate_type = NFS4_OPEN_DELEGATE_WRITE; if (!nfs4_delegation_stat(dp, currentfh, &stat)) {
trace_nfsd_deleg_write(&dp->dl_stid.sc_stateid);
path.mnt = currentfh->fh_export->ex_path.mnt;
path.dentry = currentfh->fh_dentry;
if (vfs_getattr(&path, &stat,
(STATX_SIZE | STATX_CTIME | STATX_CHANGE_COOKIE),
AT_STATX_SYNC_AS_STAT)) {
nfs4_put_stid(&dp->dl_stid); nfs4_put_stid(&dp->dl_stid);
destroy_delegation(dp); destroy_delegation(dp);
goto out_no_deleg; goto out_no_deleg;
} }
open->op_delegate_type = NFS4_OPEN_DELEGATE_WRITE;
dp->dl_cb_fattr.ncf_cur_fsize = stat.size; dp->dl_cb_fattr.ncf_cur_fsize = stat.size;
dp->dl_cb_fattr.ncf_initial_cinfo = dp->dl_cb_fattr.ncf_initial_cinfo =
nfsd4_change_attribute(&stat, d_inode(currentfh->fh_dentry)); nfsd4_change_attribute(&stat, d_inode(currentfh->fh_dentry));
trace_nfsd_deleg_write(&dp->dl_stid.sc_stateid);
} else { } else {
open->op_delegate_type = NFS4_OPEN_DELEGATE_READ; open->op_delegate_type = NFS4_OPEN_DELEGATE_READ;
trace_nfsd_deleg_read(&dp->dl_stid.sc_stateid); trace_nfsd_deleg_read(&dp->dl_stid.sc_stateid);
......
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