Skip to content

Commit dcd21b6

Browse files
author
Trond Myklebust
committed
NFS: Avoid flushing data while holding directory locks in nfs_rename()
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>
1 parent 2851150 commit dcd21b6

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
@@ -1105,6 +1105,8 @@ struct nfs_server *nfs_create_server(struct fs_context *fc)
11051105
if (server->namelen == 0 || server->namelen > NFS2_MAXNAMLEN)
11061106
server->namelen = NFS2_MAXNAMLEN;
11071107
}
1108+
/* Linux 'subtree_check' borkenness mandates this setting */
1109+
server->fh_expire_type = NFS_FH_VOL_RENAME;
11081110

11091111
if (!(fattr->valid & NFS_ATTR_FATTR)) {
11101112
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
@@ -2676,6 +2676,18 @@ nfs_unblock_rename(struct rpc_task *task, struct nfs_renamedata *data)
26762676
unblock_revalidate(new_dentry);
26772677
}
26782678

2679+
static bool nfs_rename_is_unsafe_cross_dir(struct dentry *old_dentry,
2680+
struct dentry *new_dentry)
2681+
{
2682+
struct nfs_server *server = NFS_SB(old_dentry->d_sb);
2683+
2684+
if (old_dentry->d_parent != new_dentry->d_parent)
2685+
return false;
2686+
if (server->fh_expire_type & NFS_FH_RENAME_UNSAFE)
2687+
return !(server->fh_expire_type & NFS_FH_NOEXPIRE_WITH_OPEN);
2688+
return true;
2689+
}
2690+
26792691
/*
26802692
* RENAME
26812693
* FIXME: Some nfsds, like the Linux user space nfsd, may generate a
@@ -2763,7 +2775,8 @@ int nfs_rename(struct mnt_idmap *idmap, struct inode *old_dir,
27632775

27642776
}
27652777

2766-
if (S_ISREG(old_inode->i_mode))
2778+
if (S_ISREG(old_inode->i_mode) &&
2779+
nfs_rename_is_unsafe_cross_dir(old_dentry, new_dentry))
27672780
nfs_sync_inode(old_inode);
27682781
task = nfs_async_rename(old_dir, new_dir, old_dentry, new_dentry,
27692782
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
@@ -213,6 +213,15 @@ struct nfs_server {
213213
char *fscache_uniq; /* Uniquifier (or NULL) */
214214
#endif
215215

216+
/* The following #defines numerically match the NFSv4 equivalents */
217+
#define NFS_FH_NOEXPIRE_WITH_OPEN (0x1)
218+
#define NFS_FH_VOLATILE_ANY (0x2)
219+
#define NFS_FH_VOL_MIGRATION (0x4)
220+
#define NFS_FH_VOL_RENAME (0x8)
221+
#define NFS_FH_RENAME_UNSAFE (NFS_FH_VOLATILE_ANY | NFS_FH_VOL_RENAME)
222+
u32 fh_expire_type; /* V4 bitmask representing file
223+
handle volatility type for
224+
this filesystem */
216225
u32 pnfs_blksize; /* layout_blksize attr */
217226
#if IS_ENABLED(CONFIG_NFS_V4)
218227
u32 attr_bitmask[3];/* V4 bitmask representing the set
@@ -236,9 +245,6 @@ struct nfs_server {
236245
u32 acl_bitmask; /* V4 bitmask representing the ACEs
237246
that are supported on this
238247
filesystem */
239-
u32 fh_expire_type; /* V4 bitmask representing file
240-
handle volatility type for
241-
this filesystem */
242248
struct pnfs_layoutdriver_type *pnfs_curr_ld; /* Active layout driver */
243249
struct rpc_wait_queue roc_rpcwaitq;
244250
void *pnfs_ld_data; /* per mount point data */

0 commit comments

Comments
 (0)