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 | ||
