diff options
author | Al Viro <viro@zeniv.linux.org.uk> | 2014-02-28 13:46:44 -0500 |
---|---|---|
committer | Al Viro <viro@zeniv.linux.org.uk> | 2014-03-30 19:18:49 -0400 |
commit | 0818bf27c05b2de56c5b2bd08cfae2a939bd5f52 (patch) | |
tree | 5e66b630daecbd5514f2beb908802ce26cc900ea | |
parent | 981e893ed537cbaa08f8089d480db4165e6d71c0 (diff) |
resizable namespace.c hashes
* switch allocation to alloc_large_system_hash()
* make sizes overridable by boot parameters (mhash_entries=, mphash_entries=)
* switch mountpoint_hashtable from list_head to hlist_head
Cc: stable@vger.kernel.org
Signed-off-by: Al Viro <viro@zeniv.linux.org.uk>
-rw-r--r-- | fs/mount.h | 2 | ||||
-rw-r--r-- | fs/namespace.c | 81 |
2 files changed, 59 insertions, 24 deletions
diff --git a/fs/mount.h b/fs/mount.h index a17458ca6f29..acdb428de393 100644 --- a/fs/mount.h +++ b/fs/mount.h | |||
@@ -19,7 +19,7 @@ struct mnt_pcp { | |||
19 | }; | 19 | }; |
20 | 20 | ||
21 | struct mountpoint { | 21 | struct mountpoint { |
22 | struct list_head m_hash; | 22 | struct hlist_node m_hash; |
23 | struct dentry *m_dentry; | 23 | struct dentry *m_dentry; |
24 | int m_count; | 24 | int m_count; |
25 | }; | 25 | }; |
diff --git a/fs/namespace.c b/fs/namespace.c index 22e536705c45..3b648da55d87 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); |
@@ -37,7 +60,7 @@ 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 list_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 list_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 | /* |
@@ -575,7 +605,7 @@ 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 list_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 | list_for_each_entry_rcu(p, head, mnt_hash) |
@@ -590,7 +620,7 @@ 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 list_head *head = m_hash(mnt, dentry); |
594 | struct mount *p; | 624 | struct mount *p; |
595 | 625 | ||
596 | list_for_each_entry_reverse(p, head, mnt_hash) | 626 | list_for_each_entry_reverse(p, head, mnt_hash) |
@@ -633,11 +663,11 @@ struct vfsmount *lookup_mnt(struct path *path) | |||
633 | 663 | ||
634 | static struct mountpoint *new_mountpoint(struct dentry *dentry) | 664 | static struct mountpoint *new_mountpoint(struct dentry *dentry) |
635 | { | 665 | { |
636 | struct list_head *chain = mountpoint_hashtable + hash(NULL, dentry); | 666 | struct hlist_head *chain = mp_hash(dentry); |
637 | struct mountpoint *mp; | 667 | struct mountpoint *mp; |
638 | int ret; | 668 | int ret; |
639 | 669 | ||
640 | list_for_each_entry(mp, chain, m_hash) { | 670 | hlist_for_each_entry(mp, chain, m_hash) { |
641 | if (mp->m_dentry == dentry) { | 671 | if (mp->m_dentry == dentry) { |
642 | /* might be worth a WARN_ON() */ | 672 | /* might be worth a WARN_ON() */ |
643 | if (d_unlinked(dentry)) | 673 | if (d_unlinked(dentry)) |
@@ -659,7 +689,7 @@ static struct mountpoint *new_mountpoint(struct dentry *dentry) | |||
659 | 689 | ||
660 | mp->m_dentry = dentry; | 690 | mp->m_dentry = dentry; |
661 | mp->m_count = 1; | 691 | mp->m_count = 1; |
662 | list_add(&mp->m_hash, chain); | 692 | hlist_add_head(&mp->m_hash, chain); |
663 | return mp; | 693 | return mp; |
664 | } | 694 | } |
665 | 695 | ||
@@ -670,7 +700,7 @@ static void put_mountpoint(struct mountpoint *mp) | |||
670 | spin_lock(&dentry->d_lock); | 700 | spin_lock(&dentry->d_lock); |
671 | dentry->d_flags &= ~DCACHE_MOUNTED; | 701 | dentry->d_flags &= ~DCACHE_MOUNTED; |
672 | spin_unlock(&dentry->d_lock); | 702 | spin_unlock(&dentry->d_lock); |
673 | list_del(&mp->m_hash); | 703 | hlist_del(&mp->m_hash); |
674 | kfree(mp); | 704 | kfree(mp); |
675 | } | 705 | } |
676 | } | 706 | } |
@@ -739,8 +769,7 @@ static void attach_mnt(struct mount *mnt, | |||
739 | struct mountpoint *mp) | 769 | struct mountpoint *mp) |
740 | { | 770 | { |
741 | mnt_set_mountpoint(parent, mp, mnt); | 771 | mnt_set_mountpoint(parent, mp, mnt); |
742 | list_add_tail(&mnt->mnt_hash, mount_hashtable + | 772 | list_add_tail(&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); | 773 | list_add_tail(&mnt->mnt_child, &parent->mnt_mounts); |
745 | } | 774 | } |
746 | 775 | ||
@@ -762,8 +791,8 @@ static void commit_tree(struct mount *mnt) | |||
762 | 791 | ||
763 | list_splice(&head, n->list.prev); | 792 | list_splice(&head, n->list.prev); |
764 | 793 | ||
765 | list_add_tail(&mnt->mnt_hash, mount_hashtable + | 794 | list_add_tail(&mnt->mnt_hash, |
766 | hash(&parent->mnt, mnt->mnt_mountpoint)); | 795 | m_hash(&parent->mnt, mnt->mnt_mountpoint)); |
767 | list_add_tail(&mnt->mnt_child, &parent->mnt_mounts); | 796 | list_add_tail(&mnt->mnt_child, &parent->mnt_mounts); |
768 | touch_mnt_namespace(n); | 797 | touch_mnt_namespace(n); |
769 | } | 798 | } |
@@ -2777,18 +2806,24 @@ void __init mnt_init(void) | |||
2777 | mnt_cache = kmem_cache_create("mnt_cache", sizeof(struct mount), | 2806 | mnt_cache = kmem_cache_create("mnt_cache", sizeof(struct mount), |
2778 | 0, SLAB_HWCACHE_ALIGN | SLAB_PANIC, NULL); | 2807 | 0, SLAB_HWCACHE_ALIGN | SLAB_PANIC, NULL); |
2779 | 2808 | ||
2780 | mount_hashtable = (struct list_head *)__get_free_page(GFP_ATOMIC); | 2809 | mount_hashtable = alloc_large_system_hash("Mount-cache", |
2781 | mountpoint_hashtable = (struct list_head *)__get_free_page(GFP_ATOMIC); | 2810 | sizeof(struct list_head), |
2811 | mhash_entries, 19, | ||
2812 | 0, | ||
2813 | &m_hash_shift, &m_hash_mask, 0, 0); | ||
2814 | mountpoint_hashtable = alloc_large_system_hash("Mountpoint-cache", | ||
2815 | sizeof(struct hlist_head), | ||
2816 | mphash_entries, 19, | ||
2817 | 0, | ||
2818 | &mp_hash_shift, &mp_hash_mask, 0, 0); | ||
2782 | 2819 | ||
2783 | if (!mount_hashtable || !mountpoint_hashtable) | 2820 | if (!mount_hashtable || !mountpoint_hashtable) |
2784 | panic("Failed to allocate mount hash table\n"); | 2821 | panic("Failed to allocate mount hash table\n"); |
2785 | 2822 | ||
2786 | printk(KERN_INFO "Mount-cache hash table entries: %lu\n", HASH_SIZE); | 2823 | for (u = 0; u <= m_hash_mask; u++) |
2787 | |||
2788 | for (u = 0; u < HASH_SIZE; u++) | ||
2789 | INIT_LIST_HEAD(&mount_hashtable[u]); | 2824 | INIT_LIST_HEAD(&mount_hashtable[u]); |
2790 | for (u = 0; u < HASH_SIZE; u++) | 2825 | for (u = 0; u <= mp_hash_mask; u++) |
2791 | INIT_LIST_HEAD(&mountpoint_hashtable[u]); | 2826 | INIT_HLIST_HEAD(&mountpoint_hashtable[u]); |
2792 | 2827 | ||
2793 | kernfs_init(); | 2828 | kernfs_init(); |
2794 | 2829 | ||