diff options
Diffstat (limited to 'fs/namespace.c')
-rw-r--r-- | fs/namespace.c | 177 |
1 files changed, 115 insertions, 62 deletions
diff --git a/fs/namespace.c b/fs/namespace.c index 22e536705c45..2ffc5a2905d4 100644 --- a/fs/namespace.c +++ b/fs/namespace.c | |||
@@ -23,11 +23,34 @@ | |||
23 | #include <linux/uaccess.h> | 23 | #include <linux/uaccess.h> |
24 | #include <linux/proc_ns.h> | 24 | #include <linux/proc_ns.h> |
25 | #include <linux/magic.h> | 25 | #include <linux/magic.h> |
26 | #include <linux/bootmem.h> | ||
26 | #include "pnode.h" | 27 | #include "pnode.h" |
27 | #include "internal.h" | 28 | #include "internal.h" |
28 | 29 | ||
29 | #define HASH_SHIFT ilog2(PAGE_SIZE / sizeof(struct list_head)) | 30 | static unsigned int m_hash_mask __read_mostly; |
30 | #define HASH_SIZE (1UL << HASH_SHIFT) | 31 | static unsigned int m_hash_shift __read_mostly; |
32 | static unsigned int mp_hash_mask __read_mostly; | ||
33 | static unsigned int mp_hash_shift __read_mostly; | ||
34 | |||
35 | static __initdata unsigned long mhash_entries; | ||
36 | static int __init set_mhash_entries(char *str) | ||
37 | { | ||
38 | if (!str) | ||
39 | return 0; | ||
40 | mhash_entries = simple_strtoul(str, &str, 0); | ||
41 | return 1; | ||
42 | } | ||
43 | __setup("mhash_entries=", set_mhash_entries); | ||
44 | |||
45 | static __initdata unsigned long mphash_entries; | ||
46 | static int __init set_mphash_entries(char *str) | ||
47 | { | ||
48 | if (!str) | ||
49 | return 0; | ||
50 | mphash_entries = simple_strtoul(str, &str, 0); | ||
51 | return 1; | ||
52 | } | ||
53 | __setup("mphash_entries=", set_mphash_entries); | ||
31 | 54 | ||
32 | static int event; | 55 | static int event; |
33 | static DEFINE_IDA(mnt_id_ida); | 56 | static DEFINE_IDA(mnt_id_ida); |
@@ -36,8 +59,8 @@ static DEFINE_SPINLOCK(mnt_id_lock); | |||
36 | static int mnt_id_start = 0; | 59 | static int mnt_id_start = 0; |
37 | static int mnt_group_start = 1; | 60 | static int mnt_group_start = 1; |
38 | 61 | ||
39 | static struct list_head *mount_hashtable __read_mostly; | 62 | static struct hlist_head *mount_hashtable __read_mostly; |
40 | static struct list_head *mountpoint_hashtable __read_mostly; | 63 | static struct hlist_head *mountpoint_hashtable __read_mostly; |
41 | static struct kmem_cache *mnt_cache __read_mostly; | 64 | static struct kmem_cache *mnt_cache __read_mostly; |
42 | static DECLARE_RWSEM(namespace_sem); | 65 | static DECLARE_RWSEM(namespace_sem); |
43 | 66 | ||
@@ -55,12 +78,19 @@ EXPORT_SYMBOL_GPL(fs_kobj); | |||
55 | */ | 78 | */ |
56 | __cacheline_aligned_in_smp DEFINE_SEQLOCK(mount_lock); | 79 | __cacheline_aligned_in_smp DEFINE_SEQLOCK(mount_lock); |
57 | 80 | ||
58 | static inline unsigned long hash(struct vfsmount *mnt, struct dentry *dentry) | 81 | static inline struct hlist_head *m_hash(struct vfsmount *mnt, struct dentry *dentry) |
59 | { | 82 | { |
60 | unsigned long tmp = ((unsigned long)mnt / L1_CACHE_BYTES); | 83 | unsigned long tmp = ((unsigned long)mnt / L1_CACHE_BYTES); |
61 | tmp += ((unsigned long)dentry / L1_CACHE_BYTES); | 84 | tmp += ((unsigned long)dentry / L1_CACHE_BYTES); |
62 | tmp = tmp + (tmp >> HASH_SHIFT); | 85 | tmp = tmp + (tmp >> m_hash_shift); |
63 | return tmp & (HASH_SIZE - 1); | 86 | return &mount_hashtable[tmp & m_hash_mask]; |
87 | } | ||
88 | |||
89 | static inline struct hlist_head *mp_hash(struct dentry *dentry) | ||
90 | { | ||
91 | unsigned long tmp = ((unsigned long)dentry / L1_CACHE_BYTES); | ||
92 | tmp = tmp + (tmp >> mp_hash_shift); | ||
93 | return &mountpoint_hashtable[tmp & mp_hash_mask]; | ||
64 | } | 94 | } |
65 | 95 | ||
66 | /* | 96 | /* |
@@ -187,7 +217,7 @@ static struct mount *alloc_vfsmnt(const char *name) | |||
187 | mnt->mnt_writers = 0; | 217 | mnt->mnt_writers = 0; |
188 | #endif | 218 | #endif |
189 | 219 | ||
190 | INIT_LIST_HEAD(&mnt->mnt_hash); | 220 | INIT_HLIST_NODE(&mnt->mnt_hash); |
191 | INIT_LIST_HEAD(&mnt->mnt_child); | 221 | INIT_LIST_HEAD(&mnt->mnt_child); |
192 | INIT_LIST_HEAD(&mnt->mnt_mounts); | 222 | INIT_LIST_HEAD(&mnt->mnt_mounts); |
193 | INIT_LIST_HEAD(&mnt->mnt_list); | 223 | INIT_LIST_HEAD(&mnt->mnt_list); |
@@ -575,10 +605,10 @@ bool legitimize_mnt(struct vfsmount *bastard, unsigned seq) | |||
575 | */ | 605 | */ |
576 | struct mount *__lookup_mnt(struct vfsmount *mnt, struct dentry *dentry) | 606 | struct mount *__lookup_mnt(struct vfsmount *mnt, struct dentry *dentry) |
577 | { | 607 | { |
578 | struct list_head *head = mount_hashtable + hash(mnt, dentry); | 608 | struct hlist_head *head = m_hash(mnt, dentry); |
579 | struct mount *p; | 609 | struct mount *p; |
580 | 610 | ||
581 | list_for_each_entry_rcu(p, head, mnt_hash) | 611 | hlist_for_each_entry_rcu(p, head, mnt_hash) |
582 | if (&p->mnt_parent->mnt == mnt && p->mnt_mountpoint == dentry) | 612 | if (&p->mnt_parent->mnt == mnt && p->mnt_mountpoint == dentry) |
583 | return p; | 613 | return p; |
584 | return NULL; | 614 | return NULL; |
@@ -590,13 +620,17 @@ struct mount *__lookup_mnt(struct vfsmount *mnt, struct dentry *dentry) | |||
590 | */ | 620 | */ |
591 | struct mount *__lookup_mnt_last(struct vfsmount *mnt, struct dentry *dentry) | 621 | struct mount *__lookup_mnt_last(struct vfsmount *mnt, struct dentry *dentry) |
592 | { | 622 | { |
593 | struct list_head *head = mount_hashtable + hash(mnt, dentry); | 623 | struct mount *p, *res; |
594 | struct mount *p; | 624 | res = p = __lookup_mnt(mnt, dentry); |
595 | 625 | if (!p) | |
596 | list_for_each_entry_reverse(p, head, mnt_hash) | 626 | goto out; |
597 | if (&p->mnt_parent->mnt == mnt && p->mnt_mountpoint == dentry) | 627 | hlist_for_each_entry_continue(p, mnt_hash) { |
598 | return p; | 628 | if (&p->mnt_parent->mnt != mnt || p->mnt_mountpoint != dentry) |
599 | return NULL; | 629 | break; |
630 | res = p; | ||
631 | } | ||
632 | out: | ||
633 | return res; | ||
600 | } | 634 | } |
601 | 635 | ||
602 | /* | 636 | /* |
@@ -633,11 +667,11 @@ struct vfsmount *lookup_mnt(struct path *path) | |||
633 | 667 | ||
634 | static struct mountpoint *new_mountpoint(struct dentry *dentry) | 668 | static struct mountpoint *new_mountpoint(struct dentry *dentry) |
635 | { | 669 | { |
636 | struct list_head *chain = mountpoint_hashtable + hash(NULL, dentry); | 670 | struct hlist_head *chain = mp_hash(dentry); |
637 | struct mountpoint *mp; | 671 | struct mountpoint *mp; |
638 | int ret; | 672 | int ret; |
639 | 673 | ||
640 | list_for_each_entry(mp, chain, m_hash) { | 674 | hlist_for_each_entry(mp, chain, m_hash) { |
641 | if (mp->m_dentry == dentry) { | 675 | if (mp->m_dentry == dentry) { |
642 | /* might be worth a WARN_ON() */ | 676 | /* might be worth a WARN_ON() */ |
643 | if (d_unlinked(dentry)) | 677 | if (d_unlinked(dentry)) |
@@ -659,7 +693,7 @@ static struct mountpoint *new_mountpoint(struct dentry *dentry) | |||
659 | 693 | ||
660 | mp->m_dentry = dentry; | 694 | mp->m_dentry = dentry; |
661 | mp->m_count = 1; | 695 | mp->m_count = 1; |
662 | list_add(&mp->m_hash, chain); | 696 | hlist_add_head(&mp->m_hash, chain); |
663 | return mp; | 697 | return mp; |
664 | } | 698 | } |
665 | 699 | ||
@@ -670,7 +704,7 @@ static void put_mountpoint(struct mountpoint *mp) | |||
670 | spin_lock(&dentry->d_lock); | 704 | spin_lock(&dentry->d_lock); |
671 | dentry->d_flags &= ~DCACHE_MOUNTED; | 705 | dentry->d_flags &= ~DCACHE_MOUNTED; |
672 | spin_unlock(&dentry->d_lock); | 706 | spin_unlock(&dentry->d_lock); |
673 | list_del(&mp->m_hash); | 707 | hlist_del(&mp->m_hash); |
674 | kfree(mp); | 708 | kfree(mp); |
675 | } | 709 | } |
676 | } | 710 | } |
@@ -712,7 +746,7 @@ static void detach_mnt(struct mount *mnt, struct path *old_path) | |||
712 | mnt->mnt_parent = mnt; | 746 | mnt->mnt_parent = mnt; |
713 | mnt->mnt_mountpoint = mnt->mnt.mnt_root; | 747 | mnt->mnt_mountpoint = mnt->mnt.mnt_root; |
714 | list_del_init(&mnt->mnt_child); | 748 | list_del_init(&mnt->mnt_child); |
715 | list_del_init(&mnt->mnt_hash); | 749 | hlist_del_init_rcu(&mnt->mnt_hash); |
716 | put_mountpoint(mnt->mnt_mp); | 750 | put_mountpoint(mnt->mnt_mp); |
717 | mnt->mnt_mp = NULL; | 751 | mnt->mnt_mp = NULL; |
718 | } | 752 | } |
@@ -739,15 +773,14 @@ static void attach_mnt(struct mount *mnt, | |||
739 | struct mountpoint *mp) | 773 | struct mountpoint *mp) |
740 | { | 774 | { |
741 | mnt_set_mountpoint(parent, mp, mnt); | 775 | mnt_set_mountpoint(parent, mp, mnt); |
742 | list_add_tail(&mnt->mnt_hash, mount_hashtable + | 776 | hlist_add_head_rcu(&mnt->mnt_hash, m_hash(&parent->mnt, mp->m_dentry)); |
743 | hash(&parent->mnt, mp->m_dentry)); | ||
744 | list_add_tail(&mnt->mnt_child, &parent->mnt_mounts); | 777 | list_add_tail(&mnt->mnt_child, &parent->mnt_mounts); |
745 | } | 778 | } |
746 | 779 | ||
747 | /* | 780 | /* |
748 | * vfsmount lock must be held for write | 781 | * vfsmount lock must be held for write |
749 | */ | 782 | */ |
750 | static void commit_tree(struct mount *mnt) | 783 | static void commit_tree(struct mount *mnt, struct mount *shadows) |
751 | { | 784 | { |
752 | struct mount *parent = mnt->mnt_parent; | 785 | struct mount *parent = mnt->mnt_parent; |
753 | struct mount *m; | 786 | struct mount *m; |
@@ -762,8 +795,11 @@ static void commit_tree(struct mount *mnt) | |||
762 | 795 | ||
763 | list_splice(&head, n->list.prev); | 796 | list_splice(&head, n->list.prev); |
764 | 797 | ||
765 | list_add_tail(&mnt->mnt_hash, mount_hashtable + | 798 | if (shadows) |
766 | hash(&parent->mnt, mnt->mnt_mountpoint)); | 799 | hlist_add_after_rcu(&shadows->mnt_hash, &mnt->mnt_hash); |
800 | else | ||
801 | hlist_add_head_rcu(&mnt->mnt_hash, | ||
802 | m_hash(&parent->mnt, mnt->mnt_mountpoint)); | ||
767 | list_add_tail(&mnt->mnt_child, &parent->mnt_mounts); | 803 | list_add_tail(&mnt->mnt_child, &parent->mnt_mounts); |
768 | touch_mnt_namespace(n); | 804 | touch_mnt_namespace(n); |
769 | } | 805 | } |
@@ -1153,26 +1189,28 @@ int may_umount(struct vfsmount *mnt) | |||
1153 | 1189 | ||
1154 | EXPORT_SYMBOL(may_umount); | 1190 | EXPORT_SYMBOL(may_umount); |
1155 | 1191 | ||
1156 | static LIST_HEAD(unmounted); /* protected by namespace_sem */ | 1192 | static HLIST_HEAD(unmounted); /* protected by namespace_sem */ |
1157 | 1193 | ||
1158 | static void namespace_unlock(void) | 1194 | static void namespace_unlock(void) |
1159 | { | 1195 | { |
1160 | struct mount *mnt; | 1196 | struct mount *mnt; |
1161 | LIST_HEAD(head); | 1197 | struct hlist_head head = unmounted; |
1162 | 1198 | ||
1163 | if (likely(list_empty(&unmounted))) { | 1199 | if (likely(hlist_empty(&head))) { |
1164 | up_write(&namespace_sem); | 1200 | up_write(&namespace_sem); |
1165 | return; | 1201 | return; |
1166 | } | 1202 | } |
1167 | 1203 | ||
1168 | list_splice_init(&unmounted, &head); | 1204 | head.first->pprev = &head.first; |
1205 | INIT_HLIST_HEAD(&unmounted); | ||
1206 | |||
1169 | up_write(&namespace_sem); | 1207 | up_write(&namespace_sem); |
1170 | 1208 | ||
1171 | synchronize_rcu(); | 1209 | synchronize_rcu(); |
1172 | 1210 | ||
1173 | while (!list_empty(&head)) { | 1211 | while (!hlist_empty(&head)) { |
1174 | mnt = list_first_entry(&head, struct mount, mnt_hash); | 1212 | mnt = hlist_entry(head.first, struct mount, mnt_hash); |
1175 | list_del_init(&mnt->mnt_hash); | 1213 | hlist_del_init(&mnt->mnt_hash); |
1176 | if (mnt->mnt_ex_mountpoint.mnt) | 1214 | if (mnt->mnt_ex_mountpoint.mnt) |
1177 | path_put(&mnt->mnt_ex_mountpoint); | 1215 | path_put(&mnt->mnt_ex_mountpoint); |
1178 | mntput(&mnt->mnt); | 1216 | mntput(&mnt->mnt); |
@@ -1193,16 +1231,19 @@ static inline void namespace_lock(void) | |||
1193 | */ | 1231 | */ |
1194 | void umount_tree(struct mount *mnt, int how) | 1232 | void umount_tree(struct mount *mnt, int how) |
1195 | { | 1233 | { |
1196 | LIST_HEAD(tmp_list); | 1234 | HLIST_HEAD(tmp_list); |
1197 | struct mount *p; | 1235 | struct mount *p; |
1236 | struct mount *last = NULL; | ||
1198 | 1237 | ||
1199 | for (p = mnt; p; p = next_mnt(p, mnt)) | 1238 | for (p = mnt; p; p = next_mnt(p, mnt)) { |
1200 | list_move(&p->mnt_hash, &tmp_list); | 1239 | hlist_del_init_rcu(&p->mnt_hash); |
1240 | hlist_add_head(&p->mnt_hash, &tmp_list); | ||
1241 | } | ||
1201 | 1242 | ||
1202 | if (how) | 1243 | if (how) |
1203 | propagate_umount(&tmp_list); | 1244 | propagate_umount(&tmp_list); |
1204 | 1245 | ||
1205 | list_for_each_entry(p, &tmp_list, mnt_hash) { | 1246 | hlist_for_each_entry(p, &tmp_list, mnt_hash) { |
1206 | list_del_init(&p->mnt_expire); | 1247 | list_del_init(&p->mnt_expire); |
1207 | list_del_init(&p->mnt_list); | 1248 | list_del_init(&p->mnt_list); |
1208 | __touch_mnt_namespace(p->mnt_ns); | 1249 | __touch_mnt_namespace(p->mnt_ns); |
@@ -1220,8 +1261,13 @@ void umount_tree(struct mount *mnt, int how) | |||
1220 | p->mnt_mp = NULL; | 1261 | p->mnt_mp = NULL; |
1221 | } | 1262 | } |
1222 | change_mnt_propagation(p, MS_PRIVATE); | 1263 | change_mnt_propagation(p, MS_PRIVATE); |
1264 | last = p; | ||
1265 | } | ||
1266 | if (last) { | ||
1267 | last->mnt_hash.next = unmounted.first; | ||
1268 | unmounted.first = tmp_list.first; | ||
1269 | unmounted.first->pprev = &unmounted.first; | ||
1223 | } | 1270 | } |
1224 | list_splice(&tmp_list, &unmounted); | ||
1225 | } | 1271 | } |
1226 | 1272 | ||
1227 | static void shrink_submounts(struct mount *mnt); | 1273 | static void shrink_submounts(struct mount *mnt); |
@@ -1605,24 +1651,23 @@ static int attach_recursive_mnt(struct mount *source_mnt, | |||
1605 | struct mountpoint *dest_mp, | 1651 | struct mountpoint *dest_mp, |
1606 | struct path *parent_path) | 1652 | struct path *parent_path) |
1607 | { | 1653 | { |
1608 | LIST_HEAD(tree_list); | 1654 | HLIST_HEAD(tree_list); |
1609 | struct mount *child, *p; | 1655 | struct mount *child, *p; |
1656 | struct hlist_node *n; | ||
1610 | int err; | 1657 | int err; |
1611 | 1658 | ||
1612 | if (IS_MNT_SHARED(dest_mnt)) { | 1659 | if (IS_MNT_SHARED(dest_mnt)) { |
1613 | err = invent_group_ids(source_mnt, true); | 1660 | err = invent_group_ids(source_mnt, true); |
1614 | if (err) | 1661 | if (err) |
1615 | goto out; | 1662 | goto out; |
1616 | } | 1663 | err = propagate_mnt(dest_mnt, dest_mp, source_mnt, &tree_list); |
1617 | err = propagate_mnt(dest_mnt, dest_mp, source_mnt, &tree_list); | 1664 | if (err) |
1618 | if (err) | 1665 | goto out_cleanup_ids; |
1619 | goto out_cleanup_ids; | 1666 | lock_mount_hash(); |
1620 | |||
1621 | lock_mount_hash(); | ||
1622 | |||
1623 | if (IS_MNT_SHARED(dest_mnt)) { | ||
1624 | for (p = source_mnt; p; p = next_mnt(p, source_mnt)) | 1667 | for (p = source_mnt; p; p = next_mnt(p, source_mnt)) |
1625 | set_mnt_shared(p); | 1668 | set_mnt_shared(p); |
1669 | } else { | ||
1670 | lock_mount_hash(); | ||
1626 | } | 1671 | } |
1627 | if (parent_path) { | 1672 | if (parent_path) { |
1628 | detach_mnt(source_mnt, parent_path); | 1673 | detach_mnt(source_mnt, parent_path); |
@@ -1630,20 +1675,22 @@ static int attach_recursive_mnt(struct mount *source_mnt, | |||
1630 | touch_mnt_namespace(source_mnt->mnt_ns); | 1675 | touch_mnt_namespace(source_mnt->mnt_ns); |
1631 | } else { | 1676 | } else { |
1632 | mnt_set_mountpoint(dest_mnt, dest_mp, source_mnt); | 1677 | mnt_set_mountpoint(dest_mnt, dest_mp, source_mnt); |
1633 | commit_tree(source_mnt); | 1678 | commit_tree(source_mnt, NULL); |
1634 | } | 1679 | } |
1635 | 1680 | ||
1636 | list_for_each_entry_safe(child, p, &tree_list, mnt_hash) { | 1681 | hlist_for_each_entry_safe(child, n, &tree_list, mnt_hash) { |
1637 | list_del_init(&child->mnt_hash); | 1682 | struct mount *q; |
1638 | commit_tree(child); | 1683 | hlist_del_init(&child->mnt_hash); |
1684 | q = __lookup_mnt_last(&child->mnt_parent->mnt, | ||
1685 | child->mnt_mountpoint); | ||
1686 | commit_tree(child, q); | ||
1639 | } | 1687 | } |
1640 | unlock_mount_hash(); | 1688 | unlock_mount_hash(); |
1641 | 1689 | ||
1642 | return 0; | 1690 | return 0; |
1643 | 1691 | ||
1644 | out_cleanup_ids: | 1692 | out_cleanup_ids: |
1645 | if (IS_MNT_SHARED(dest_mnt)) | 1693 | cleanup_group_ids(source_mnt, NULL); |
1646 | cleanup_group_ids(source_mnt, NULL); | ||
1647 | out: | 1694 | out: |
1648 | return err; | 1695 | return err; |
1649 | } | 1696 | } |
@@ -2777,18 +2824,24 @@ void __init mnt_init(void) | |||
2777 | mnt_cache = kmem_cache_create("mnt_cache", sizeof(struct mount), | 2824 | mnt_cache = kmem_cache_create("mnt_cache", sizeof(struct mount), |
2778 | 0, SLAB_HWCACHE_ALIGN | SLAB_PANIC, NULL); | 2825 | 0, SLAB_HWCACHE_ALIGN | SLAB_PANIC, NULL); |
2779 | 2826 | ||
2780 | mount_hashtable = (struct list_head *)__get_free_page(GFP_ATOMIC); | 2827 | mount_hashtable = alloc_large_system_hash("Mount-cache", |
2781 | mountpoint_hashtable = (struct list_head *)__get_free_page(GFP_ATOMIC); | 2828 | sizeof(struct hlist_head), |
2829 | mhash_entries, 19, | ||
2830 | 0, | ||
2831 | &m_hash_shift, &m_hash_mask, 0, 0); | ||
2832 | mountpoint_hashtable = alloc_large_system_hash("Mountpoint-cache", | ||
2833 | sizeof(struct hlist_head), | ||
2834 | mphash_entries, 19, | ||
2835 | 0, | ||
2836 | &mp_hash_shift, &mp_hash_mask, 0, 0); | ||
2782 | 2837 | ||
2783 | if (!mount_hashtable || !mountpoint_hashtable) | 2838 | if (!mount_hashtable || !mountpoint_hashtable) |
2784 | panic("Failed to allocate mount hash table\n"); | 2839 | panic("Failed to allocate mount hash table\n"); |
2785 | 2840 | ||
2786 | printk(KERN_INFO "Mount-cache hash table entries: %lu\n", HASH_SIZE); | 2841 | for (u = 0; u <= m_hash_mask; u++) |
2787 | 2842 | INIT_HLIST_HEAD(&mount_hashtable[u]); | |
2788 | for (u = 0; u < HASH_SIZE; u++) | 2843 | for (u = 0; u <= mp_hash_mask; u++) |
2789 | INIT_LIST_HEAD(&mount_hashtable[u]); | 2844 | INIT_HLIST_HEAD(&mountpoint_hashtable[u]); |
2790 | for (u = 0; u < HASH_SIZE; u++) | ||
2791 | INIT_LIST_HEAD(&mountpoint_hashtable[u]); | ||
2792 | 2845 | ||
2793 | kernfs_init(); | 2846 | kernfs_init(); |
2794 | 2847 | ||