Skip to content

Commit 1e9c75f

Browse files
bcodding-rhebiederm
authored andcommitted
mnt: fix __detach_mounts infinite loop
Since commit ff17fa5 ("d_invalidate(): unhash immediately") immediately unhashes the dentry, we'll never return the mountpoint in lookup_mountpoint(), which can lead to an unbreakable loop in d_invalidate(). I have reports of NFS clients getting into this condition after the server removes an export of an existing mount created through follow_automount(), but I suspect there are various other ways to produce this problem if we hunt down users of d_invalidate(). For example, it is possible to get into this state by using XFS' d_invalidate() call in xfs_vn_unlink(): truncate -s 100m img{1,2} mkfs.xfs -q -n version=ci img1 mkfs.xfs -q -n version=ci img2 mkdir -p /mnt/xfs mount img1 /mnt/xfs mkdir /mnt/xfs/sub1 mount img2 /mnt/xfs/sub1 cat > /mnt/xfs/sub1/foo & umount -l /mnt/xfs/sub1 mount img2 /mnt/xfs/sub1 mount --make-private /mnt/xfs mkdir /mnt/xfs/sub2 mount --move /mnt/xfs/sub1 /mnt/xfs/sub2 rmdir /mnt/xfs/sub1 Fix this by moving the check for an unlinked dentry out of the detach_mounts() path. Fixes: ff17fa5 ("d_invalidate(): unhash immediately") Cc: [email protected] Reviewed-by: "Eric W. Biederman" <[email protected]> Signed-off-by: Benjamin Coddington <[email protected]> Signed-off-by: Eric W. Biederman <[email protected]>
1 parent 9c8e0a1 commit 1e9c75f

File tree

1 file changed

+3
-3
lines changed

1 file changed

+3
-3
lines changed

fs/namespace.c

Lines changed: 3 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -695,9 +695,6 @@ static struct mountpoint *lookup_mountpoint(struct dentry *dentry)
695695

696696
hlist_for_each_entry(mp, chain, m_hash) {
697697
if (mp->m_dentry == dentry) {
698-
/* might be worth a WARN_ON() */
699-
if (d_unlinked(dentry))
700-
return ERR_PTR(-ENOENT);
701698
mp->m_count++;
702699
return mp;
703700
}
@@ -711,6 +708,9 @@ static struct mountpoint *get_mountpoint(struct dentry *dentry)
711708
int ret;
712709

713710
if (d_mountpoint(dentry)) {
711+
/* might be worth a WARN_ON() */
712+
if (d_unlinked(dentry))
713+
return ERR_PTR(-ENOENT);
714714
mountpoint:
715715
read_seqlock_excl(&mount_lock);
716716
mp = lookup_mountpoint(dentry);

0 commit comments

Comments
 (0)