mirror of
https://git.kernel.org/pub/scm/linux/kernel/git/torvalds/linux.git
synced 2026-05-10 21:14:56 -04:00
NFSD: Return NFS4ERR_FILE_OPEN only when renaming over an open file
RFC 8881 Section 18.26.4 paragraphs 1 - 3 tell us that RENAME should return NFS4ERR_FILE_OPEN only when the target object is a file that is currently open. If the target is a directory, some other status must be returned. Generally I expect that a delegation recall will be triggered in some of these circumstances. In other cases, the VFS might return -EBUSY for other reasons, and NFSD has to ensure that errno does not leak to clients as a status code that is not permitted by spec. There are some error flows where the target dentry hasn't been found yet. The default value for @type therefore is S_IFDIR to return an alternate status code in those cases. Reviewed-by: Jeff Layton <jlayton@kernel.org> Signed-off-by: Chuck Lever <chuck.lever@oracle.com>
This commit is contained in:
@@ -1794,9 +1794,19 @@ nfsd_has_cached_files(struct dentry *dentry)
|
||||
return ret;
|
||||
}
|
||||
|
||||
/*
|
||||
* Rename a file
|
||||
* N.B. After this call _both_ ffhp and tfhp need an fh_put
|
||||
/**
|
||||
* nfsd_rename - rename a directory entry
|
||||
* @rqstp: RPC transaction context
|
||||
* @ffhp: the file handle of parent directory containing the entry to be renamed
|
||||
* @fname: the filename of directory entry to be renamed
|
||||
* @flen: the length of @fname in octets
|
||||
* @tfhp: the file handle of parent directory to contain the renamed entry
|
||||
* @tname: the filename of the new entry
|
||||
* @tlen: the length of @tlen in octets
|
||||
*
|
||||
* After this call _both_ ffhp and tfhp need an fh_put.
|
||||
*
|
||||
* Returns a generic NFS status code in network byte-order.
|
||||
*/
|
||||
__be32
|
||||
nfsd_rename(struct svc_rqst *rqstp, struct svc_fh *ffhp, char *fname, int flen,
|
||||
@@ -1804,6 +1814,7 @@ nfsd_rename(struct svc_rqst *rqstp, struct svc_fh *ffhp, char *fname, int flen,
|
||||
{
|
||||
struct dentry *fdentry, *tdentry, *odentry, *ndentry, *trap;
|
||||
struct inode *fdir, *tdir;
|
||||
int type = S_IFDIR;
|
||||
__be32 err;
|
||||
int host_err;
|
||||
bool close_cached = false;
|
||||
@@ -1861,11 +1872,14 @@ nfsd_rename(struct svc_rqst *rqstp, struct svc_fh *ffhp, char *fname, int flen,
|
||||
host_err = -EINVAL;
|
||||
if (odentry == trap)
|
||||
goto out_dput_old;
|
||||
type = d_inode(odentry)->i_mode & S_IFMT;
|
||||
|
||||
ndentry = lookup_one_len(tname, tdentry, tlen);
|
||||
host_err = PTR_ERR(ndentry);
|
||||
if (IS_ERR(ndentry))
|
||||
goto out_dput_old;
|
||||
if (d_inode(ndentry))
|
||||
type = d_inode(ndentry)->i_mode & S_IFMT;
|
||||
host_err = -ENOTEMPTY;
|
||||
if (ndentry == trap)
|
||||
goto out_dput_new;
|
||||
@@ -1903,7 +1917,18 @@ nfsd_rename(struct svc_rqst *rqstp, struct svc_fh *ffhp, char *fname, int flen,
|
||||
out_dput_old:
|
||||
dput(odentry);
|
||||
out_nfserr:
|
||||
err = nfserrno(host_err);
|
||||
if (host_err == -EBUSY) {
|
||||
/*
|
||||
* See RFC 8881 Section 18.26.4 para 1-3: NFSv4 RENAME
|
||||
* wants a status unique to the object type.
|
||||
*/
|
||||
if (type != S_IFDIR)
|
||||
err = nfserr_file_open;
|
||||
else
|
||||
err = nfserr_acces;
|
||||
} else {
|
||||
err = nfserrno(host_err);
|
||||
}
|
||||
|
||||
if (!close_cached) {
|
||||
fh_fill_post_attrs(ffhp);
|
||||
|
||||
Reference in New Issue
Block a user