Skip to content

Commit

Permalink
NFS: Add a helper to remove case-insensitive aliases
Browse files Browse the repository at this point in the history
When dealing with case insensitive names, the client has no idea how the
server performs the mapping, so cannot collapse the dentries into a
single representative. So both rename and unlink need to deal with the
fact that there could be several dentries representing the file, and
have to somehow force them to be revalidated. Use d_prune_aliases() as a
big hammer approach.

Signed-off-by: Trond Myklebust <trond.myklebust@hammerspace.com>
Signed-off-by: Anna Schumaker <Anna.Schumaker@Netapp.com>
  • Loading branch information
Trond Myklebust authored and Anna Schumaker committed Jan 6, 2022
1 parent 8ce37ab commit 00bdadc
Show file tree
Hide file tree
Showing 3 changed files with 16 additions and 2 deletions.
12 changes: 11 additions & 1 deletion fs/nfs/dir.c
Original file line number Diff line number Diff line change
Expand Up @@ -1819,6 +1819,14 @@ struct dentry *nfs_lookup(struct inode *dir, struct dentry * dentry, unsigned in
}
EXPORT_SYMBOL_GPL(nfs_lookup);

void nfs_d_prune_case_insensitive_aliases(struct inode *inode)
{
/* Case insensitive server? Revalidate dentries */
if (inode && nfs_server_capable(inode, NFS_CAP_CASE_INSENSITIVE))
d_prune_aliases(inode);
}
EXPORT_SYMBOL_GPL(nfs_d_prune_case_insensitive_aliases);

#if IS_ENABLED(CONFIG_NFS_V4)
static int nfs4_lookup_revalidate(struct dentry *, unsigned int);

Expand Down Expand Up @@ -2199,8 +2207,10 @@ static void nfs_dentry_remove_handle_error(struct inode *dir,
switch (error) {
case -ENOENT:
d_delete(dentry);
fallthrough;
nfs_set_verifier(dentry, nfs_save_change_attribute(dir));
break;
case 0:
nfs_d_prune_case_insensitive_aliases(d_inode(dentry));
nfs_set_verifier(dentry, nfs_save_change_attribute(dir));
}
}
Expand Down
1 change: 1 addition & 0 deletions fs/nfs/internal.h
Original file line number Diff line number Diff line change
Expand Up @@ -373,6 +373,7 @@ extern unsigned long nfs_access_cache_count(struct shrinker *shrink,
extern unsigned long nfs_access_cache_scan(struct shrinker *shrink,
struct shrink_control *sc);
struct dentry *nfs_lookup(struct inode *, struct dentry *, unsigned int);
void nfs_d_prune_case_insensitive_aliases(struct inode *inode);
int nfs_create(struct user_namespace *, struct inode *, struct dentry *,
umode_t, bool);
int nfs_mkdir(struct user_namespace *, struct inode *, struct dentry *,
Expand Down
5 changes: 4 additions & 1 deletion fs/nfs/nfs4proc.c
Original file line number Diff line number Diff line change
Expand Up @@ -4670,8 +4670,10 @@ static void nfs4_proc_unlink_setup(struct rpc_message *msg,

nfs_fattr_init(res->dir_attr);

if (inode)
if (inode) {
nfs4_inode_return_delegation(inode);
nfs_d_prune_case_insensitive_aliases(inode);
}
}

static void nfs4_proc_unlink_rpc_prepare(struct rpc_task *task, struct nfs_unlinkdata *data)
Expand Down Expand Up @@ -4737,6 +4739,7 @@ static int nfs4_proc_rename_done(struct rpc_task *task, struct inode *old_dir,
return 0;

if (task->tk_status == 0) {
nfs_d_prune_case_insensitive_aliases(d_inode(data->old_dentry));
if (new_dir != old_dir) {
/* Note: If we moved a directory, nlink will change */
nfs4_update_changeattr(old_dir, &res->old_cinfo,
Expand Down

0 comments on commit 00bdadc

Please sign in to comment.