new helper: __legitimize_mnt()
authorAl Viro <viro@zeniv.linux.org.uk>
Fri, 8 May 2015 15:43:53 +0000 (11:43 -0400)
committerAl Viro <viro@zeniv.linux.org.uk>
Mon, 11 May 2015 12:13:14 +0000 (08:13 -0400)
same as legitimize_mnt(), except that it does *not* drop and regain
rcu_read_lock; return values are
0  =>  grabbed a reference, we are fine
1  =>  failed, just go away
-1 =>  failed, go away and mntput(bastard) when outside of rcu_read_lock

Signed-off-by: Al Viro <viro@zeniv.linux.org.uk>
fs/mount.h
fs/namespace.c

index 6a61c2b..b5b8082 100644 (file)
@@ -88,6 +88,7 @@ static inline int is_mounted(struct vfsmount *mnt)
 extern struct mount *__lookup_mnt(struct vfsmount *, struct dentry *);
 extern struct mount *__lookup_mnt_last(struct vfsmount *, struct dentry *);
 
+extern int __legitimize_mnt(struct vfsmount *, unsigned);
 extern bool legitimize_mnt(struct vfsmount *, unsigned);
 
 extern void __detach_mounts(struct dentry *dentry);
index 1b9e111..9c1c43d 100644 (file)
@@ -590,24 +590,35 @@ static void delayed_free_vfsmnt(struct rcu_head *head)
 }
 
 /* call under rcu_read_lock */
-bool legitimize_mnt(struct vfsmount *bastard, unsigned seq)
+int __legitimize_mnt(struct vfsmount *bastard, unsigned seq)
 {
        struct mount *mnt;
        if (read_seqretry(&mount_lock, seq))
-               return false;
+               return 1;
        if (bastard == NULL)
-               return true;
+               return 0;
        mnt = real_mount(bastard);
        mnt_add_count(mnt, 1);
        if (likely(!read_seqretry(&mount_lock, seq)))
-               return true;
+               return 0;
        if (bastard->mnt_flags & MNT_SYNC_UMOUNT) {
                mnt_add_count(mnt, -1);
-               return false;
+               return 1;
+       }
+       return -1;
+}
+
+/* call under rcu_read_lock */
+bool legitimize_mnt(struct vfsmount *bastard, unsigned seq)
+{
+       int res = __legitimize_mnt(bastard, seq);
+       if (likely(!res))
+               return true;
+       if (unlikely(res < 0)) {
+               rcu_read_unlock();
+               mntput(bastard);
+               rcu_read_lock();
        }
-       rcu_read_unlock();
-       mntput(bastard);
-       rcu_read_lock();
        return false;
 }