diff options
Diffstat (limited to 'fs/namespace.c')
-rw-r--r-- | fs/namespace.c | 195 |
1 files changed, 89 insertions, 106 deletions
diff --git a/fs/namespace.c b/fs/namespace.c index 1e4a5fe3d7b7..c53d3381b0d0 100644 --- a/fs/namespace.c +++ b/fs/namespace.c | |||
@@ -515,8 +515,20 @@ struct mount *__lookup_mnt(struct vfsmount *mnt, struct dentry *dentry, | |||
515 | } | 515 | } |
516 | 516 | ||
517 | /* | 517 | /* |
518 | * lookup_mnt increments the ref count before returning | 518 | * lookup_mnt - Return the first child mount mounted at path |
519 | * the vfsmount struct. | 519 | * |
520 | * "First" means first mounted chronologically. If you create the | ||
521 | * following mounts: | ||
522 | * | ||
523 | * mount /dev/sda1 /mnt | ||
524 | * mount /dev/sda2 /mnt | ||
525 | * mount /dev/sda3 /mnt | ||
526 | * | ||
527 | * Then lookup_mnt() on the base /mnt dentry in the root mount will | ||
528 | * return successively the root dentry and vfsmount of /dev/sda1, then | ||
529 | * /dev/sda2, then /dev/sda3, then NULL. | ||
530 | * | ||
531 | * lookup_mnt takes a reference to the found vfsmount. | ||
520 | */ | 532 | */ |
521 | struct vfsmount *lookup_mnt(struct path *path) | 533 | struct vfsmount *lookup_mnt(struct path *path) |
522 | { | 534 | { |
@@ -621,21 +633,6 @@ static void attach_mnt(struct mount *mnt, struct path *path) | |||
621 | list_add_tail(&mnt->mnt_child, &real_mount(path->mnt)->mnt_mounts); | 633 | list_add_tail(&mnt->mnt_child, &real_mount(path->mnt)->mnt_mounts); |
622 | } | 634 | } |
623 | 635 | ||
624 | static inline void __mnt_make_longterm(struct mount *mnt) | ||
625 | { | ||
626 | #ifdef CONFIG_SMP | ||
627 | atomic_inc(&mnt->mnt_longterm); | ||
628 | #endif | ||
629 | } | ||
630 | |||
631 | /* needs vfsmount lock for write */ | ||
632 | static inline void __mnt_make_shortterm(struct mount *mnt) | ||
633 | { | ||
634 | #ifdef CONFIG_SMP | ||
635 | atomic_dec(&mnt->mnt_longterm); | ||
636 | #endif | ||
637 | } | ||
638 | |||
639 | /* | 636 | /* |
640 | * vfsmount lock must be held for write | 637 | * vfsmount lock must be held for write |
641 | */ | 638 | */ |
@@ -649,10 +646,8 @@ static void commit_tree(struct mount *mnt) | |||
649 | BUG_ON(parent == mnt); | 646 | BUG_ON(parent == mnt); |
650 | 647 | ||
651 | list_add_tail(&head, &mnt->mnt_list); | 648 | list_add_tail(&head, &mnt->mnt_list); |
652 | list_for_each_entry(m, &head, mnt_list) { | 649 | list_for_each_entry(m, &head, mnt_list) |
653 | m->mnt_ns = n; | 650 | m->mnt_ns = n; |
654 | __mnt_make_longterm(m); | ||
655 | } | ||
656 | 651 | ||
657 | list_splice(&head, n->list.prev); | 652 | list_splice(&head, n->list.prev); |
658 | 653 | ||
@@ -725,56 +720,60 @@ static struct mount *clone_mnt(struct mount *old, struct dentry *root, | |||
725 | int flag) | 720 | int flag) |
726 | { | 721 | { |
727 | struct super_block *sb = old->mnt.mnt_sb; | 722 | struct super_block *sb = old->mnt.mnt_sb; |
728 | struct mount *mnt = alloc_vfsmnt(old->mnt_devname); | 723 | struct mount *mnt; |
724 | int err; | ||
729 | 725 | ||
730 | if (mnt) { | 726 | mnt = alloc_vfsmnt(old->mnt_devname); |
731 | if (flag & (CL_SLAVE | CL_PRIVATE)) | 727 | if (!mnt) |
732 | mnt->mnt_group_id = 0; /* not a peer of original */ | 728 | return ERR_PTR(-ENOMEM); |
733 | else | ||
734 | mnt->mnt_group_id = old->mnt_group_id; | ||
735 | |||
736 | if ((flag & CL_MAKE_SHARED) && !mnt->mnt_group_id) { | ||
737 | int err = mnt_alloc_group_id(mnt); | ||
738 | if (err) | ||
739 | goto out_free; | ||
740 | } | ||
741 | 729 | ||
742 | mnt->mnt.mnt_flags = old->mnt.mnt_flags & ~MNT_WRITE_HOLD; | 730 | if (flag & (CL_SLAVE | CL_PRIVATE)) |
743 | atomic_inc(&sb->s_active); | 731 | mnt->mnt_group_id = 0; /* not a peer of original */ |
744 | mnt->mnt.mnt_sb = sb; | 732 | else |
745 | mnt->mnt.mnt_root = dget(root); | 733 | mnt->mnt_group_id = old->mnt_group_id; |
746 | mnt->mnt_mountpoint = mnt->mnt.mnt_root; | ||
747 | mnt->mnt_parent = mnt; | ||
748 | br_write_lock(&vfsmount_lock); | ||
749 | list_add_tail(&mnt->mnt_instance, &sb->s_mounts); | ||
750 | br_write_unlock(&vfsmount_lock); | ||
751 | 734 | ||
752 | if (flag & CL_SLAVE) { | 735 | if ((flag & CL_MAKE_SHARED) && !mnt->mnt_group_id) { |
753 | list_add(&mnt->mnt_slave, &old->mnt_slave_list); | 736 | err = mnt_alloc_group_id(mnt); |
754 | mnt->mnt_master = old; | 737 | if (err) |
755 | CLEAR_MNT_SHARED(mnt); | 738 | goto out_free; |
756 | } else if (!(flag & CL_PRIVATE)) { | ||
757 | if ((flag & CL_MAKE_SHARED) || IS_MNT_SHARED(old)) | ||
758 | list_add(&mnt->mnt_share, &old->mnt_share); | ||
759 | if (IS_MNT_SLAVE(old)) | ||
760 | list_add(&mnt->mnt_slave, &old->mnt_slave); | ||
761 | mnt->mnt_master = old->mnt_master; | ||
762 | } | ||
763 | if (flag & CL_MAKE_SHARED) | ||
764 | set_mnt_shared(mnt); | ||
765 | |||
766 | /* stick the duplicate mount on the same expiry list | ||
767 | * as the original if that was on one */ | ||
768 | if (flag & CL_EXPIRE) { | ||
769 | if (!list_empty(&old->mnt_expire)) | ||
770 | list_add(&mnt->mnt_expire, &old->mnt_expire); | ||
771 | } | ||
772 | } | 739 | } |
740 | |||
741 | mnt->mnt.mnt_flags = old->mnt.mnt_flags & ~MNT_WRITE_HOLD; | ||
742 | atomic_inc(&sb->s_active); | ||
743 | mnt->mnt.mnt_sb = sb; | ||
744 | mnt->mnt.mnt_root = dget(root); | ||
745 | mnt->mnt_mountpoint = mnt->mnt.mnt_root; | ||
746 | mnt->mnt_parent = mnt; | ||
747 | br_write_lock(&vfsmount_lock); | ||
748 | list_add_tail(&mnt->mnt_instance, &sb->s_mounts); | ||
749 | br_write_unlock(&vfsmount_lock); | ||
750 | |||
751 | if (flag & CL_SLAVE) { | ||
752 | list_add(&mnt->mnt_slave, &old->mnt_slave_list); | ||
753 | mnt->mnt_master = old; | ||
754 | CLEAR_MNT_SHARED(mnt); | ||
755 | } else if (!(flag & CL_PRIVATE)) { | ||
756 | if ((flag & CL_MAKE_SHARED) || IS_MNT_SHARED(old)) | ||
757 | list_add(&mnt->mnt_share, &old->mnt_share); | ||
758 | if (IS_MNT_SLAVE(old)) | ||
759 | list_add(&mnt->mnt_slave, &old->mnt_slave); | ||
760 | mnt->mnt_master = old->mnt_master; | ||
761 | } | ||
762 | if (flag & CL_MAKE_SHARED) | ||
763 | set_mnt_shared(mnt); | ||
764 | |||
765 | /* stick the duplicate mount on the same expiry list | ||
766 | * as the original if that was on one */ | ||
767 | if (flag & CL_EXPIRE) { | ||
768 | if (!list_empty(&old->mnt_expire)) | ||
769 | list_add(&mnt->mnt_expire, &old->mnt_expire); | ||
770 | } | ||
771 | |||
773 | return mnt; | 772 | return mnt; |
774 | 773 | ||
775 | out_free: | 774 | out_free: |
776 | free_vfsmnt(mnt); | 775 | free_vfsmnt(mnt); |
777 | return NULL; | 776 | return ERR_PTR(err); |
778 | } | 777 | } |
779 | 778 | ||
780 | static inline void mntfree(struct mount *mnt) | 779 | static inline void mntfree(struct mount *mnt) |
@@ -804,7 +803,8 @@ static void mntput_no_expire(struct mount *mnt) | |||
804 | put_again: | 803 | put_again: |
805 | #ifdef CONFIG_SMP | 804 | #ifdef CONFIG_SMP |
806 | br_read_lock(&vfsmount_lock); | 805 | br_read_lock(&vfsmount_lock); |
807 | if (likely(atomic_read(&mnt->mnt_longterm))) { | 806 | if (likely(mnt->mnt_ns)) { |
807 | /* shouldn't be the last one */ | ||
808 | mnt_add_count(mnt, -1); | 808 | mnt_add_count(mnt, -1); |
809 | br_read_unlock(&vfsmount_lock); | 809 | br_read_unlock(&vfsmount_lock); |
810 | return; | 810 | return; |
@@ -939,7 +939,7 @@ EXPORT_SYMBOL(replace_mount_options); | |||
939 | /* iterator; we want it to have access to namespace_sem, thus here... */ | 939 | /* iterator; we want it to have access to namespace_sem, thus here... */ |
940 | static void *m_start(struct seq_file *m, loff_t *pos) | 940 | static void *m_start(struct seq_file *m, loff_t *pos) |
941 | { | 941 | { |
942 | struct proc_mounts *p = container_of(m, struct proc_mounts, m); | 942 | struct proc_mounts *p = proc_mounts(m); |
943 | 943 | ||
944 | down_read(&namespace_sem); | 944 | down_read(&namespace_sem); |
945 | return seq_list_start(&p->ns->list, *pos); | 945 | return seq_list_start(&p->ns->list, *pos); |
@@ -947,7 +947,7 @@ static void *m_start(struct seq_file *m, loff_t *pos) | |||
947 | 947 | ||
948 | static void *m_next(struct seq_file *m, void *v, loff_t *pos) | 948 | static void *m_next(struct seq_file *m, void *v, loff_t *pos) |
949 | { | 949 | { |
950 | struct proc_mounts *p = container_of(m, struct proc_mounts, m); | 950 | struct proc_mounts *p = proc_mounts(m); |
951 | 951 | ||
952 | return seq_list_next(v, &p->ns->list, pos); | 952 | return seq_list_next(v, &p->ns->list, pos); |
953 | } | 953 | } |
@@ -959,7 +959,7 @@ static void m_stop(struct seq_file *m, void *v) | |||
959 | 959 | ||
960 | static int m_show(struct seq_file *m, void *v) | 960 | static int m_show(struct seq_file *m, void *v) |
961 | { | 961 | { |
962 | struct proc_mounts *p = container_of(m, struct proc_mounts, m); | 962 | struct proc_mounts *p = proc_mounts(m); |
963 | struct mount *r = list_entry(v, struct mount, mnt_list); | 963 | struct mount *r = list_entry(v, struct mount, mnt_list); |
964 | return p->show(m, &r->mnt); | 964 | return p->show(m, &r->mnt); |
965 | } | 965 | } |
@@ -1074,8 +1074,6 @@ void umount_tree(struct mount *mnt, int propagate, struct list_head *kill) | |||
1074 | list_del_init(&p->mnt_expire); | 1074 | list_del_init(&p->mnt_expire); |
1075 | list_del_init(&p->mnt_list); | 1075 | list_del_init(&p->mnt_list); |
1076 | __touch_mnt_namespace(p->mnt_ns); | 1076 | __touch_mnt_namespace(p->mnt_ns); |
1077 | if (p->mnt_ns) | ||
1078 | __mnt_make_shortterm(p); | ||
1079 | p->mnt_ns = NULL; | 1077 | p->mnt_ns = NULL; |
1080 | list_del_init(&p->mnt_child); | 1078 | list_del_init(&p->mnt_child); |
1081 | if (mnt_has_parent(p)) { | 1079 | if (mnt_has_parent(p)) { |
@@ -1260,11 +1258,12 @@ struct mount *copy_tree(struct mount *mnt, struct dentry *dentry, | |||
1260 | struct path path; | 1258 | struct path path; |
1261 | 1259 | ||
1262 | if (!(flag & CL_COPY_ALL) && IS_MNT_UNBINDABLE(mnt)) | 1260 | if (!(flag & CL_COPY_ALL) && IS_MNT_UNBINDABLE(mnt)) |
1263 | return NULL; | 1261 | return ERR_PTR(-EINVAL); |
1264 | 1262 | ||
1265 | res = q = clone_mnt(mnt, dentry, flag); | 1263 | res = q = clone_mnt(mnt, dentry, flag); |
1266 | if (!q) | 1264 | if (IS_ERR(q)) |
1267 | goto Enomem; | 1265 | return q; |
1266 | |||
1268 | q->mnt_mountpoint = mnt->mnt_mountpoint; | 1267 | q->mnt_mountpoint = mnt->mnt_mountpoint; |
1269 | 1268 | ||
1270 | p = mnt; | 1269 | p = mnt; |
@@ -1286,8 +1285,8 @@ struct mount *copy_tree(struct mount *mnt, struct dentry *dentry, | |||
1286 | path.mnt = &q->mnt; | 1285 | path.mnt = &q->mnt; |
1287 | path.dentry = p->mnt_mountpoint; | 1286 | path.dentry = p->mnt_mountpoint; |
1288 | q = clone_mnt(p, p->mnt.mnt_root, flag); | 1287 | q = clone_mnt(p, p->mnt.mnt_root, flag); |
1289 | if (!q) | 1288 | if (IS_ERR(q)) |
1290 | goto Enomem; | 1289 | goto out; |
1291 | br_write_lock(&vfsmount_lock); | 1290 | br_write_lock(&vfsmount_lock); |
1292 | list_add_tail(&q->mnt_list, &res->mnt_list); | 1291 | list_add_tail(&q->mnt_list, &res->mnt_list); |
1293 | attach_mnt(q, &path); | 1292 | attach_mnt(q, &path); |
@@ -1295,7 +1294,7 @@ struct mount *copy_tree(struct mount *mnt, struct dentry *dentry, | |||
1295 | } | 1294 | } |
1296 | } | 1295 | } |
1297 | return res; | 1296 | return res; |
1298 | Enomem: | 1297 | out: |
1299 | if (res) { | 1298 | if (res) { |
1300 | LIST_HEAD(umount_list); | 1299 | LIST_HEAD(umount_list); |
1301 | br_write_lock(&vfsmount_lock); | 1300 | br_write_lock(&vfsmount_lock); |
@@ -1303,9 +1302,11 @@ Enomem: | |||
1303 | br_write_unlock(&vfsmount_lock); | 1302 | br_write_unlock(&vfsmount_lock); |
1304 | release_mounts(&umount_list); | 1303 | release_mounts(&umount_list); |
1305 | } | 1304 | } |
1306 | return NULL; | 1305 | return q; |
1307 | } | 1306 | } |
1308 | 1307 | ||
1308 | /* Caller should check returned pointer for errors */ | ||
1309 | |||
1309 | struct vfsmount *collect_mounts(struct path *path) | 1310 | struct vfsmount *collect_mounts(struct path *path) |
1310 | { | 1311 | { |
1311 | struct mount *tree; | 1312 | struct mount *tree; |
@@ -1313,7 +1314,9 @@ struct vfsmount *collect_mounts(struct path *path) | |||
1313 | tree = copy_tree(real_mount(path->mnt), path->dentry, | 1314 | tree = copy_tree(real_mount(path->mnt), path->dentry, |
1314 | CL_COPY_ALL | CL_PRIVATE); | 1315 | CL_COPY_ALL | CL_PRIVATE); |
1315 | up_write(&namespace_sem); | 1316 | up_write(&namespace_sem); |
1316 | return tree ? &tree->mnt : NULL; | 1317 | if (IS_ERR(tree)) |
1318 | return NULL; | ||
1319 | return &tree->mnt; | ||
1317 | } | 1320 | } |
1318 | 1321 | ||
1319 | void drop_collected_mounts(struct vfsmount *mnt) | 1322 | void drop_collected_mounts(struct vfsmount *mnt) |
@@ -1608,14 +1611,15 @@ static int do_loopback(struct path *path, char *old_name, | |||
1608 | if (!check_mnt(real_mount(path->mnt)) || !check_mnt(old)) | 1611 | if (!check_mnt(real_mount(path->mnt)) || !check_mnt(old)) |
1609 | goto out2; | 1612 | goto out2; |
1610 | 1613 | ||
1611 | err = -ENOMEM; | ||
1612 | if (recurse) | 1614 | if (recurse) |
1613 | mnt = copy_tree(old, old_path.dentry, 0); | 1615 | mnt = copy_tree(old, old_path.dentry, 0); |
1614 | else | 1616 | else |
1615 | mnt = clone_mnt(old, old_path.dentry, 0); | 1617 | mnt = clone_mnt(old, old_path.dentry, 0); |
1616 | 1618 | ||
1617 | if (!mnt) | 1619 | if (IS_ERR(mnt)) { |
1618 | goto out2; | 1620 | err = PTR_ERR(mnt); |
1621 | goto out; | ||
1622 | } | ||
1619 | 1623 | ||
1620 | err = graft_tree(mnt, path); | 1624 | err = graft_tree(mnt, path); |
1621 | if (err) { | 1625 | if (err) { |
@@ -2209,23 +2213,6 @@ static struct mnt_namespace *alloc_mnt_ns(void) | |||
2209 | return new_ns; | 2213 | return new_ns; |
2210 | } | 2214 | } |
2211 | 2215 | ||
2212 | void mnt_make_longterm(struct vfsmount *mnt) | ||
2213 | { | ||
2214 | __mnt_make_longterm(real_mount(mnt)); | ||
2215 | } | ||
2216 | |||
2217 | void mnt_make_shortterm(struct vfsmount *m) | ||
2218 | { | ||
2219 | #ifdef CONFIG_SMP | ||
2220 | struct mount *mnt = real_mount(m); | ||
2221 | if (atomic_add_unless(&mnt->mnt_longterm, -1, 1)) | ||
2222 | return; | ||
2223 | br_write_lock(&vfsmount_lock); | ||
2224 | atomic_dec(&mnt->mnt_longterm); | ||
2225 | br_write_unlock(&vfsmount_lock); | ||
2226 | #endif | ||
2227 | } | ||
2228 | |||
2229 | /* | 2216 | /* |
2230 | * Allocate a new namespace structure and populate it with contents | 2217 | * Allocate a new namespace structure and populate it with contents |
2231 | * copied from the namespace of the passed in task structure. | 2218 | * copied from the namespace of the passed in task structure. |
@@ -2246,10 +2233,10 @@ static struct mnt_namespace *dup_mnt_ns(struct mnt_namespace *mnt_ns, | |||
2246 | down_write(&namespace_sem); | 2233 | down_write(&namespace_sem); |
2247 | /* First pass: copy the tree topology */ | 2234 | /* First pass: copy the tree topology */ |
2248 | new = copy_tree(old, old->mnt.mnt_root, CL_COPY_ALL | CL_EXPIRE); | 2235 | new = copy_tree(old, old->mnt.mnt_root, CL_COPY_ALL | CL_EXPIRE); |
2249 | if (!new) { | 2236 | if (IS_ERR(new)) { |
2250 | up_write(&namespace_sem); | 2237 | up_write(&namespace_sem); |
2251 | kfree(new_ns); | 2238 | kfree(new_ns); |
2252 | return ERR_PTR(-ENOMEM); | 2239 | return ERR_CAST(new); |
2253 | } | 2240 | } |
2254 | new_ns->root = new; | 2241 | new_ns->root = new; |
2255 | br_write_lock(&vfsmount_lock); | 2242 | br_write_lock(&vfsmount_lock); |
@@ -2265,18 +2252,13 @@ static struct mnt_namespace *dup_mnt_ns(struct mnt_namespace *mnt_ns, | |||
2265 | q = new; | 2252 | q = new; |
2266 | while (p) { | 2253 | while (p) { |
2267 | q->mnt_ns = new_ns; | 2254 | q->mnt_ns = new_ns; |
2268 | __mnt_make_longterm(q); | ||
2269 | if (fs) { | 2255 | if (fs) { |
2270 | if (&p->mnt == fs->root.mnt) { | 2256 | if (&p->mnt == fs->root.mnt) { |
2271 | fs->root.mnt = mntget(&q->mnt); | 2257 | fs->root.mnt = mntget(&q->mnt); |
2272 | __mnt_make_longterm(q); | ||
2273 | mnt_make_shortterm(&p->mnt); | ||
2274 | rootmnt = &p->mnt; | 2258 | rootmnt = &p->mnt; |
2275 | } | 2259 | } |
2276 | if (&p->mnt == fs->pwd.mnt) { | 2260 | if (&p->mnt == fs->pwd.mnt) { |
2277 | fs->pwd.mnt = mntget(&q->mnt); | 2261 | fs->pwd.mnt = mntget(&q->mnt); |
2278 | __mnt_make_longterm(q); | ||
2279 | mnt_make_shortterm(&p->mnt); | ||
2280 | pwdmnt = &p->mnt; | 2262 | pwdmnt = &p->mnt; |
2281 | } | 2263 | } |
2282 | } | 2264 | } |
@@ -2320,7 +2302,6 @@ static struct mnt_namespace *create_mnt_ns(struct vfsmount *m) | |||
2320 | if (!IS_ERR(new_ns)) { | 2302 | if (!IS_ERR(new_ns)) { |
2321 | struct mount *mnt = real_mount(m); | 2303 | struct mount *mnt = real_mount(m); |
2322 | mnt->mnt_ns = new_ns; | 2304 | mnt->mnt_ns = new_ns; |
2323 | __mnt_make_longterm(mnt); | ||
2324 | new_ns->root = mnt; | 2305 | new_ns->root = mnt; |
2325 | list_add(&new_ns->list, &mnt->mnt_list); | 2306 | list_add(&new_ns->list, &mnt->mnt_list); |
2326 | } else { | 2307 | } else { |
@@ -2615,7 +2596,7 @@ struct vfsmount *kern_mount_data(struct file_system_type *type, void *data) | |||
2615 | * it is a longterm mount, don't release mnt until | 2596 | * it is a longterm mount, don't release mnt until |
2616 | * we unmount before file sys is unregistered | 2597 | * we unmount before file sys is unregistered |
2617 | */ | 2598 | */ |
2618 | mnt_make_longterm(mnt); | 2599 | real_mount(mnt)->mnt_ns = MNT_NS_INTERNAL; |
2619 | } | 2600 | } |
2620 | return mnt; | 2601 | return mnt; |
2621 | } | 2602 | } |
@@ -2625,7 +2606,9 @@ void kern_unmount(struct vfsmount *mnt) | |||
2625 | { | 2606 | { |
2626 | /* release long term mount so mount point can be released */ | 2607 | /* release long term mount so mount point can be released */ |
2627 | if (!IS_ERR_OR_NULL(mnt)) { | 2608 | if (!IS_ERR_OR_NULL(mnt)) { |
2628 | mnt_make_shortterm(mnt); | 2609 | br_write_lock(&vfsmount_lock); |
2610 | real_mount(mnt)->mnt_ns = NULL; | ||
2611 | br_write_unlock(&vfsmount_lock); | ||
2629 | mntput(mnt); | 2612 | mntput(mnt); |
2630 | } | 2613 | } |
2631 | } | 2614 | } |