new helper: __legitimize_mnt()

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>
This commit is contained in:
Al Viro 2015-05-08 11:43:53 -04:00
parent 31956502dd
commit 294d71ff2f
2 changed files with 20 additions and 8 deletions

View 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(struct vfsmount *, struct dentry *);
extern struct mount *__lookup_mnt_last(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 bool legitimize_mnt(struct vfsmount *, unsigned);
extern void __detach_mounts(struct dentry *dentry); extern void __detach_mounts(struct dentry *dentry);

View File

@ -590,24 +590,35 @@ static void delayed_free_vfsmnt(struct rcu_head *head)
} }
/* call under rcu_read_lock */ /* call under rcu_read_lock */
bool legitimize_mnt(struct vfsmount *bastard, unsigned seq) int __legitimize_mnt(struct vfsmount *bastard, unsigned seq)
{ {
struct mount *mnt; struct mount *mnt;
if (read_seqretry(&mount_lock, seq)) if (read_seqretry(&mount_lock, seq))
return false; return 1;
if (bastard == NULL) if (bastard == NULL)
return true; return 0;
mnt = real_mount(bastard); mnt = real_mount(bastard);
mnt_add_count(mnt, 1); mnt_add_count(mnt, 1);
if (likely(!read_seqretry(&mount_lock, seq))) if (likely(!read_seqretry(&mount_lock, seq)))
return true; return 0;
if (bastard->mnt_flags & MNT_SYNC_UMOUNT) { if (bastard->mnt_flags & MNT_SYNC_UMOUNT) {
mnt_add_count(mnt, -1); 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; return false;
} }