Skip to content

Commit dcabad6

Browse files
Trond Myklebustgregkh
authored andcommitted
NFS: Avoid flushing data while holding directory locks in nfs_rename()
[ Upstream commit dcd21b609d4abc7303f8683bce4f35d78d7d6830 ] 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 <[email protected]> Reviewed-by: Jeff Layton <[email protected]> Signed-off-by: Sasha Levin <[email protected]>
1 parent e114326 commit dcabad6

File tree

3 files changed

+25
-4
lines changed

3 files changed

+25
-4
lines changed

fs/nfs/client.c

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1052,6 +1052,8 @@ struct nfs_server *nfs_create_server(struct fs_context *fc)
10521052
if (server->namelen == 0 || server->namelen > NFS2_MAXNAMLEN)
10531053
server->namelen = NFS2_MAXNAMLEN;
10541054
}
1055+
/* Linux 'subtree_check' borkenness mandates this setting */
1056+
server->fh_expire_type = NFS_FH_VOL_RENAME;
10551057

10561058
if (!(fattr->valid & NFS_ATTR_FATTR)) {
10571059
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
@@ -2632,6 +2632,18 @@ nfs_unblock_rename(struct rpc_task *task, struct nfs_renamedata *data)
26322632
unblock_revalidate(new_dentry);
26332633
}
26342634

2635+
static bool nfs_rename_is_unsafe_cross_dir(struct dentry *old_dentry,
2636+
struct dentry *new_dentry)
2637+
{
2638+
struct nfs_server *server = NFS_SB(old_dentry->d_sb);
2639+
2640+
if (old_dentry->d_parent != new_dentry->d_parent)
2641+
return false;
2642+
if (server->fh_expire_type & NFS_FH_RENAME_UNSAFE)
2643+
return !(server->fh_expire_type & NFS_FH_NOEXPIRE_WITH_OPEN);
2644+
return true;
2645+
}
2646+
26352647
/*
26362648
* RENAME
26372649
* FIXME: Some nfsds, like the Linux user space nfsd, may generate a
@@ -2719,7 +2731,8 @@ int nfs_rename(struct user_namespace *mnt_userns, struct inode *old_dir,
27192731

27202732
}
27212733

2722-
if (S_ISREG(old_inode->i_mode))
2734+
if (S_ISREG(old_inode->i_mode) &&
2735+
nfs_rename_is_unsafe_cross_dir(old_dentry, new_dentry))
27232736
nfs_sync_inode(old_inode);
27242737
task = nfs_async_rename(old_dir, new_dir, old_dentry, new_dentry,
27252738
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
@@ -196,6 +196,15 @@ struct nfs_server {
196196
char *fscache_uniq; /* Uniquifier (or NULL) */
197197
#endif
198198

199+
/* The following #defines numerically match the NFSv4 equivalents */
200+
#define NFS_FH_NOEXPIRE_WITH_OPEN (0x1)
201+
#define NFS_FH_VOLATILE_ANY (0x2)
202+
#define NFS_FH_VOL_MIGRATION (0x4)
203+
#define NFS_FH_VOL_RENAME (0x8)
204+
#define NFS_FH_RENAME_UNSAFE (NFS_FH_VOLATILE_ANY | NFS_FH_VOL_RENAME)
205+
u32 fh_expire_type; /* V4 bitmask representing file
206+
handle volatility type for
207+
this filesystem */
199208
u32 pnfs_blksize; /* layout_blksize attr */
200209
#if IS_ENABLED(CONFIG_NFS_V4)
201210
u32 attr_bitmask[3];/* V4 bitmask representing the set
@@ -219,9 +228,6 @@ struct nfs_server {
219228
u32 acl_bitmask; /* V4 bitmask representing the ACEs
220229
that are supported on this
221230
filesystem */
222-
u32 fh_expire_type; /* V4 bitmask representing file
223-
handle volatility type for
224-
this filesystem */
225231
struct pnfs_layoutdriver_type *pnfs_curr_ld; /* Active layout driver */
226232
struct rpc_wait_queue roc_rpcwaitq;
227233
void *pnfs_ld_data; /* per mount point data */

0 commit comments

Comments
 (0)