d_splice_alias() - via __d_unalias() - currently assumes that taking a shared lock on the parent directory locks against any change to the parent/name of the dentry. This will no longer be the case with shared-lock updates. We also need a DCACHE_PAR_UPDATE lock on the dentry. This patch adds a call to d_update_trylock() to get this lock -if possible. This lock ensures that the test on ->d_parent and ->d_name in d_update_lock() will not be invalidated by the __d_move() in __d_unalias. Signed-off-by: NeilBrown <neilb@xxxxxxx> --- fs/dcache.c | 10 +++++++++- 1 file changed, 9 insertions(+), 1 deletion(-) diff --git a/fs/dcache.c b/fs/dcache.c index e705696ca57e..fb331596f1b1 100644 --- a/fs/dcache.c +++ b/fs/dcache.c @@ -3036,13 +3036,17 @@ static int __d_unalias(struct dentry *dentry, struct dentry *alias) goto out_err; m2 = &alias->d_parent->d_inode->i_rwsem; out_unalias: + if (!d_update_trylock(dentry, NULL, NULL)) + goto out_err; if (alias->d_op && alias->d_op->d_unalias_trylock && !alias->d_op->d_unalias_trylock(alias)) - goto out_err; + goto out_err2; __d_move(alias, dentry, false); if (alias->d_op && alias->d_op->d_unalias_unlock) alias->d_op->d_unalias_unlock(alias); ret = 0; +out_err2: + d_update_unlock(dentry); out_err: if (m2) up_read(m2); @@ -3073,6 +3077,10 @@ static int __d_unalias(struct dentry *dentry, struct dentry *alias) * In that case, we know that the inode will be a regular file, and also this * will only occur during atomic_open. So we need to check for the dentry * being already hashed only in the final case. + * + * @dentry must have a valid ->d_parent and that directory must be + * locked (i_rwsem) either exclusively or shared. If shared then + * @dentry must have %DCACHE_PAR_LOOKUP or %DCACHE_PAR_UPDATE set. */ struct dentry *d_splice_alias(struct inode *inode, struct dentry *dentry) { -- 2.47.1