Skip to content

Commit b2c7ce1

Browse files
Trond Myklebustopsiff
authored andcommitted
NFS: Avoid flushing data while holding directory locks in nfs_rename()
[ Upstream commit dcd21b6 ] The Linux client assumes that all filehandles are non-volatile for renames within the same directory (otherwise sillyrename cannot work). However, the existence of the Linux 'subtree_check' export option has meant that nfs_rename() has always assumed it needs to flush writes before attempting to rename. Since NFSv4 does allow the client to query whether or not the server exhibits this behaviour, and since knfsd does actually set the appropriate flag when 'subtree_check' is enabled on an export, it should be OK to optimise away the write flushing behaviour in the cases where it is clearly not needed. Signed-off-by: Trond Myklebust <trond.myklebust@hammerspace.com> Reviewed-by: Jeff Layton <jlayton@kernel.org> Signed-off-by: Sasha Levin <sashal@kernel.org> (cherry picked from commit af7243148f2eba8d351afbc5afbe8903a03b8945)
1 parent 1066954 commit b2c7ce1

3 files changed

Lines changed: 25 additions & 4 deletions

File tree

fs/nfs/client.c

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1080,6 +1080,8 @@ struct nfs_server *nfs_create_server(struct fs_context *fc)
10801080
if (server->namelen == 0 || server->namelen > NFS2_MAXNAMLEN)
10811081
server->namelen = NFS2_MAXNAMLEN;
10821082
}
1083+
/* Linux 'subtree_check' borkenness mandates this setting */
1084+
server->fh_expire_type = NFS_FH_VOL_RENAME;
10831085

10841086
if (!(fattr->valid & NFS_ATTR_FATTR)) {
10851087
error = ctx->nfs_mod->rpc_ops->getattr(server, ctx->mntfh,

fs/nfs/dir.c

Lines changed: 14 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -2642,6 +2642,18 @@ nfs_unblock_rename(struct rpc_task *task, struct nfs_renamedata *data)
26422642
unblock_revalidate(new_dentry);
26432643
}
26442644

2645+
static bool nfs_rename_is_unsafe_cross_dir(struct dentry *old_dentry,
2646+
struct dentry *new_dentry)
2647+
{
2648+
struct nfs_server *server = NFS_SB(old_dentry->d_sb);
2649+
2650+
if (old_dentry->d_parent != new_dentry->d_parent)
2651+
return false;
2652+
if (server->fh_expire_type & NFS_FH_RENAME_UNSAFE)
2653+
return !(server->fh_expire_type & NFS_FH_NOEXPIRE_WITH_OPEN);
2654+
return true;
2655+
}
2656+
26452657
/*
26462658
* RENAME
26472659
* FIXME: Some nfsds, like the Linux user space nfsd, may generate a
@@ -2729,7 +2741,8 @@ int nfs_rename(struct mnt_idmap *idmap, struct inode *old_dir,
27292741

27302742
}
27312743

2732-
if (S_ISREG(old_inode->i_mode))
2744+
if (S_ISREG(old_inode->i_mode) &&
2745+
nfs_rename_is_unsafe_cross_dir(old_dentry, new_dentry))
27332746
nfs_sync_inode(old_inode);
27342747
task = nfs_async_rename(old_dir, new_dir, old_dentry, new_dentry,
27352748
must_unblock ? nfs_unblock_rename : NULL);

include/linux/nfs_fs_sb.h

Lines changed: 9 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -199,6 +199,15 @@ struct nfs_server {
199199
char *fscache_uniq; /* Uniquifier (or NULL) */
200200
#endif
201201

202+
/* The following #defines numerically match the NFSv4 equivalents */
203+
#define NFS_FH_NOEXPIRE_WITH_OPEN (0x1)
204+
#define NFS_FH_VOLATILE_ANY (0x2)
205+
#define NFS_FH_VOL_MIGRATION (0x4)
206+
#define NFS_FH_VOL_RENAME (0x8)
207+
#define NFS_FH_RENAME_UNSAFE (NFS_FH_VOLATILE_ANY | NFS_FH_VOL_RENAME)
208+
u32 fh_expire_type; /* V4 bitmask representing file
209+
handle volatility type for
210+
this filesystem */
202211
u32 pnfs_blksize; /* layout_blksize attr */
203212
#if IS_ENABLED(CONFIG_NFS_V4)
204213
u32 attr_bitmask[3];/* V4 bitmask representing the set
@@ -222,9 +231,6 @@ struct nfs_server {
222231
u32 acl_bitmask; /* V4 bitmask representing the ACEs
223232
that are supported on this
224233
filesystem */
225-
u32 fh_expire_type; /* V4 bitmask representing file
226-
handle volatility type for
227-
this filesystem */
228234
struct pnfs_layoutdriver_type *pnfs_curr_ld; /* Active layout driver */
229235
struct rpc_wait_queue roc_rpcwaitq;
230236
void *pnfs_ld_data; /* per mount point data */

0 commit comments

Comments
 (0)