Commit 62a7375e5d77d654695297c4b39d5d740d901184

Authored by Ian Kent
Committed by Al Viro
1 parent b81a618dcd

vfs - check non-mountpoint dentry might block in __follow_mount_rcu()

When following a mount in rcu-walk mode we must check if the incoming dentry
is telling us it may need to block, even if it isn't actually a mountpoint.

Signed-off-by: Ian Kent <raven@themaw.net>
Signed-off-by: Al Viro <viro@zeniv.linux.org.uk>

Showing 1 changed file with 18 additions and 5 deletions Side-by-side Diff

... ... @@ -992,6 +992,12 @@
992 992 return 0;
993 993 }
994 994  
  995 +static inline bool managed_dentry_might_block(struct dentry *dentry)
  996 +{
  997 + return (dentry->d_flags & DCACHE_MANAGE_TRANSIT &&
  998 + dentry->d_op->d_manage(dentry, true) < 0);
  999 +}
  1000 +
995 1001 /*
996 1002 * Skip to top of mountpoint pile in rcuwalk mode. We abort the rcu-walk if we
997 1003 * meet a managed dentry and we're not walking to "..". True is returned to
998 1004  
999 1005  
1000 1006  
... ... @@ -1000,19 +1006,26 @@
1000 1006 static bool __follow_mount_rcu(struct nameidata *nd, struct path *path,
1001 1007 struct inode **inode, bool reverse_transit)
1002 1008 {
1003   - while (d_mountpoint(path->dentry)) {
  1009 + for (;;) {
1004 1010 struct vfsmount *mounted;
1005   - if (unlikely(path->dentry->d_flags & DCACHE_MANAGE_TRANSIT) &&
1006   - !reverse_transit &&
1007   - path->dentry->d_op->d_manage(path->dentry, true) < 0)
  1011 + /*
  1012 + * Don't forget we might have a non-mountpoint managed dentry
  1013 + * that wants to block transit.
  1014 + */
  1015 + *inode = path->dentry->d_inode;
  1016 + if (!reverse_transit &&
  1017 + unlikely(managed_dentry_might_block(path->dentry)))
1008 1018 return false;
  1019 +
  1020 + if (!d_mountpoint(path->dentry))
  1021 + break;
  1022 +
1009 1023 mounted = __lookup_mnt(path->mnt, path->dentry, 1);
1010 1024 if (!mounted)
1011 1025 break;
1012 1026 path->mnt = mounted;
1013 1027 path->dentry = mounted->mnt_root;
1014 1028 nd->seq = read_seqcount_begin(&path->dentry->d_seq);
1015   - *inode = path->dentry->d_inode;
1016 1029 }
1017 1030  
1018 1031 if (unlikely(path->dentry->d_flags & DCACHE_NEED_AUTOMOUNT))