From: NeilBrown <[email protected]> As afs supports the fhandle interfaces there is a theoretical possibility that the inode created for mkdir could be found by open_by_handle_at() and given a dentry before d_instantiate() is called. This would result in two dentries for the one directory inode, which is not permitted.
So this patch changes afs_mkdir() to use d_splice_alias() and to return the alternate dentry from ->mkdir() if appropriate. Signed-off-by: NeilBrown <[email protected]> --- fs/afs/dir.c | 14 ++++++++++---- fs/afs/internal.h | 1 + 2 files changed, 11 insertions(+), 4 deletions(-) diff --git a/fs/afs/dir.c b/fs/afs/dir.c index 9c57614feccf..1e472768e1f1 100644 --- a/fs/afs/dir.c +++ b/fs/afs/dir.c @@ -1248,7 +1248,7 @@ void afs_check_for_remote_deletion(struct afs_operation *op) /* * Create a new inode for create/mkdir/symlink */ -static void afs_vnode_new_inode(struct afs_operation *op) +static struct dentry *afs_vnode_new_inode(struct afs_operation *op) { struct afs_vnode_param *dvp = &op->file[0]; struct afs_vnode_param *vp = &op->file[1]; @@ -1265,7 +1265,7 @@ static void afs_vnode_new_inode(struct afs_operation *op) * the new directory on the server. */ afs_op_accumulate_error(op, PTR_ERR(inode), 0); - return; + return NULL; } vnode = AFS_FS_I(inode); @@ -1276,7 +1276,7 @@ static void afs_vnode_new_inode(struct afs_operation *op) afs_init_new_symlink(vnode, op); if (!afs_op_error(op)) afs_cache_permit(vnode, op->key, vnode->cb_break, &vp->scb); - d_instantiate(op->dentry, inode); + return d_splice_alias(inode, op->dentry); } static void afs_create_success(struct afs_operation *op) @@ -1285,7 +1285,7 @@ static void afs_create_success(struct afs_operation *op) op->ctime = op->file[0].scb.status.mtime_client; afs_vnode_commit_status(op, &op->file[0]); afs_update_dentry_version(op, &op->file[0], op->dentry); - afs_vnode_new_inode(op); + op->create.ret = afs_vnode_new_inode(op); } static void afs_create_edit_dir(struct afs_operation *op) @@ -1356,6 +1356,12 @@ static struct dentry *afs_mkdir(struct mnt_idmap *idmap, struct inode *dir, op->ops = &afs_mkdir_operation; ret = afs_do_sync_operation(op); afs_dir_unuse_cookie(dvnode, ret); + if (op->create.ret) { + /* Alternate dentry */ + if (ret == 0) + return op->create.ret; + dput(op->create.ret); + } return ERR_PTR(ret); } diff --git a/fs/afs/internal.h b/fs/afs/internal.h index f2898ce9c0e6..ce94f10a14c0 100644 --- a/fs/afs/internal.h +++ b/fs/afs/internal.h @@ -889,6 +889,7 @@ struct afs_operation { int reason; /* enum afs_edit_dir_reason */ mode_t mode; const char *symlink; + struct dentry *ret; } create; struct { struct dentry *unblock; -- 2.50.0.107.gf914562f5916.dirty
