On Mon, 2022-08-29 at 12:57 +0800, xiubli@xxxxxxxxxx wrote: > From: Xiubo Li <xiubli@xxxxxxxxxx> > > When unlinking a file the kclient will send a unlink request to MDS > by holding the dentry reference, and then the MDS will return 2 replies, > which are unsafe reply and a deferred safe reply. > > After the unsafe reply received the kernel will return and succeed > the unlink request to user space apps. > > Only when the safe reply received the dentry's reference will be > released. Or the dentry will only be unhashed from dcache. But when > the open_by_handle_at() begins to open the unlinked files it will > succeed. > > URL: https://tracker.ceph.com/issues/56524 > Signed-off-by: Xiubo Li <xiubli@xxxxxxxxxx> > --- > > V2: > - If the dentry was released and inode is evicted such as by dropping > the caches, it will allocate a new dentry, which is also unhashed. > > > fs/ceph/export.c | 17 ++++++++++++++++- > 1 file changed, 16 insertions(+), 1 deletion(-) > > diff --git a/fs/ceph/export.c b/fs/ceph/export.c > index 0ebf2bd93055..5edc1d31cd79 100644 > --- a/fs/ceph/export.c > +++ b/fs/ceph/export.c > @@ -182,6 +182,7 @@ struct inode *ceph_lookup_inode(struct super_block *sb, u64 ino) > static struct dentry *__fh_to_dentry(struct super_block *sb, u64 ino) > { > struct inode *inode = __lookup_inode(sb, ino); > + struct dentry *dentry; > int err; > > if (IS_ERR(inode)) > @@ -197,7 +198,21 @@ static struct dentry *__fh_to_dentry(struct super_block *sb, u64 ino) > iput(inode); > return ERR_PTR(-ESTALE); > } > - return d_obtain_alias(inode); > + > + /* > + * -ESTALE if the dentry exists and is unhashed, > + * which should be being released > + */ > + dentry = d_find_any_alias(inode); > + if (dentry && unlikely(d_unhashed(dentry))) { > + dput(dentry); > + return ERR_PTR(-ESTALE); > + } > + > + if (!dentry) > + dentry = d_obtain_alias(inode); > + > + return dentry; > } > > static struct dentry *__snapfh_to_dentry(struct super_block *sb, This looks racy. Suppose we have 2 racing tasks calling __fh_to_dentry for the same inode. The first one races in and doesn't find anything. d_obtain alias creates a disconnected dentry and returns it. The next task then finds it, sees that it's disconnected and gets back -ESTALE. I think you may need to detect this situation in a different way. -- Jeff Layton <jlayton@xxxxxxxxxx>