aboutsummaryrefslogtreecommitdiffstats
path: root/fs
diff options
context:
space:
mode:
Diffstat (limited to 'fs')
-rw-r--r--fs/mount.h3
-rw-r--r--fs/namei.c4
-rw-r--r--fs/namespace.c42
-rw-r--r--fs/pnode.c6
4 files changed, 30 insertions, 25 deletions
diff --git a/fs/mount.h b/fs/mount.h
index 7076f25af35d..f0866076de6e 100644
--- a/fs/mount.h
+++ b/fs/mount.h
@@ -77,7 +77,8 @@ static inline int is_mounted(struct vfsmount *mnt)
77 return !IS_ERR_OR_NULL(real_mount(mnt)); 77 return !IS_ERR_OR_NULL(real_mount(mnt));
78} 78}
79 79
80extern struct mount *__lookup_mnt(struct vfsmount *, struct dentry *, int); 80extern struct mount *__lookup_mnt(struct vfsmount *, struct dentry *);
81extern struct mount *__lookup_mnt_last(struct vfsmount *, struct dentry *);
81 82
82static inline void get_mnt_ns(struct mnt_namespace *ns) 83static inline void get_mnt_ns(struct mnt_namespace *ns)
83{ 84{
diff --git a/fs/namei.c b/fs/namei.c
index 645268f23eb6..1f844fbfce72 100644
--- a/fs/namei.c
+++ b/fs/namei.c
@@ -1111,7 +1111,7 @@ static bool __follow_mount_rcu(struct nameidata *nd, struct path *path,
1111 if (!d_mountpoint(path->dentry)) 1111 if (!d_mountpoint(path->dentry))
1112 break; 1112 break;
1113 1113
1114 mounted = __lookup_mnt(path->mnt, path->dentry, 1); 1114 mounted = __lookup_mnt(path->mnt, path->dentry);
1115 if (!mounted) 1115 if (!mounted)
1116 break; 1116 break;
1117 path->mnt = &mounted->mnt; 1117 path->mnt = &mounted->mnt;
@@ -1132,7 +1132,7 @@ static void follow_mount_rcu(struct nameidata *nd)
1132{ 1132{
1133 while (d_mountpoint(nd->path.dentry)) { 1133 while (d_mountpoint(nd->path.dentry)) {
1134 struct mount *mounted; 1134 struct mount *mounted;
1135 mounted = __lookup_mnt(nd->path.mnt, nd->path.dentry, 1); 1135 mounted = __lookup_mnt(nd->path.mnt, nd->path.dentry);
1136 if (!mounted) 1136 if (!mounted)
1137 break; 1137 break;
1138 nd->path.mnt = &mounted->mnt; 1138 nd->path.mnt = &mounted->mnt;
diff --git a/fs/namespace.c b/fs/namespace.c
index 5cbe8cefadb5..500202ce10db 100644
--- a/fs/namespace.c
+++ b/fs/namespace.c
@@ -548,29 +548,33 @@ static void free_vfsmnt(struct mount *mnt)
548} 548}
549 549
550/* 550/*
551 * find the first or last mount at @dentry on vfsmount @mnt depending on 551 * find the first mount at @dentry on vfsmount @mnt.
552 * @dir. If @dir is set return the first mount else return the last mount.
553 * vfsmount_lock must be held for read or write. 552 * vfsmount_lock must be held for read or write.
554 */ 553 */
555struct mount *__lookup_mnt(struct vfsmount *mnt, struct dentry *dentry, 554struct mount *__lookup_mnt(struct vfsmount *mnt, struct dentry *dentry)
556 int dir)
557{ 555{
558 struct list_head *head = mount_hashtable + hash(mnt, dentry); 556 struct list_head *head = mount_hashtable + hash(mnt, dentry);
559 struct list_head *tmp = head; 557 struct mount *p;
560 struct mount *p, *found = NULL;
561 558
562 for (;;) { 559 list_for_each_entry(p, head, mnt_hash)
563 tmp = dir ? tmp->next : tmp->prev; 560 if (&p->mnt_parent->mnt == mnt && p->mnt_mountpoint == dentry)
564 p = NULL; 561 return p;
565 if (tmp == head) 562 return NULL;
566 break; 563}
567 p = list_entry(tmp, struct mount, mnt_hash); 564
568 if (&p->mnt_parent->mnt == mnt && p->mnt_mountpoint == dentry) { 565/*
569 found = p; 566 * find the last mount at @dentry on vfsmount @mnt.
570 break; 567 * vfsmount_lock must be held for read or write.
571 } 568 */
572 } 569struct mount *__lookup_mnt_last(struct vfsmount *mnt, struct dentry *dentry)
573 return found; 570{
571 struct list_head *head = mount_hashtable + hash(mnt, dentry);
572 struct mount *p;
573
574 list_for_each_entry_reverse(p, head, mnt_hash)
575 if (&p->mnt_parent->mnt == mnt && p->mnt_mountpoint == dentry)
576 return p;
577 return NULL;
574} 578}
575 579
576/* 580/*
@@ -594,7 +598,7 @@ struct vfsmount *lookup_mnt(struct path *path)
594 struct mount *child_mnt; 598 struct mount *child_mnt;
595 599
596 br_read_lock(&vfsmount_lock); 600 br_read_lock(&vfsmount_lock);
597 child_mnt = __lookup_mnt(path->mnt, path->dentry, 1); 601 child_mnt = __lookup_mnt(path->mnt, path->dentry);
598 if (child_mnt) { 602 if (child_mnt) {
599 mnt_add_count(child_mnt, 1); 603 mnt_add_count(child_mnt, 1);
600 br_read_unlock(&vfsmount_lock); 604 br_read_unlock(&vfsmount_lock);
diff --git a/fs/pnode.c b/fs/pnode.c
index 58933fd149ad..c7221bb19801 100644
--- a/fs/pnode.c
+++ b/fs/pnode.c
@@ -310,7 +310,7 @@ int propagate_mount_busy(struct mount *mnt, int refcnt)
310 310
311 for (m = propagation_next(parent, parent); m; 311 for (m = propagation_next(parent, parent); m;
312 m = propagation_next(m, parent)) { 312 m = propagation_next(m, parent)) {
313 child = __lookup_mnt(&m->mnt, mnt->mnt_mountpoint, 0); 313 child = __lookup_mnt_last(&m->mnt, mnt->mnt_mountpoint);
314 if (child && list_empty(&child->mnt_mounts) && 314 if (child && list_empty(&child->mnt_mounts) &&
315 (ret = do_refcount_check(child, 1))) 315 (ret = do_refcount_check(child, 1)))
316 break; 316 break;
@@ -332,8 +332,8 @@ static void __propagate_umount(struct mount *mnt)
332 for (m = propagation_next(parent, parent); m; 332 for (m = propagation_next(parent, parent); m;
333 m = propagation_next(m, parent)) { 333 m = propagation_next(m, parent)) {
334 334
335 struct mount *child = __lookup_mnt(&m->mnt, 335 struct mount *child = __lookup_mnt_last(&m->mnt,
336 mnt->mnt_mountpoint, 0); 336 mnt->mnt_mountpoint);
337 /* 337 /*
338 * umount the child only if the child has no 338 * umount the child only if the child has no
339 * other children 339 * other children