aboutsummaryrefslogtreecommitdiffstats
path: root/net/netlink
diff options
context:
space:
mode:
authorThomas Graf <tgraf@suug.ch>2015-01-02 17:00:20 -0500
committerDavid S. Miller <davem@davemloft.net>2015-01-03 14:32:57 -0500
commit97defe1ecf868b8127f8e62395499d6a06e4c4b1 (patch)
treed3ed6d3db4943e01b1ae58e73580537ba1642d9e /net/netlink
parent113948d841e8d78039e5dbbb5248f5b73e99eafa (diff)
rhashtable: Per bucket locks & deferred expansion/shrinking
Introduces an array of spinlocks to protect bucket mutations. The number of spinlocks per CPU is configurable and selected based on the hash of the bucket. This allows for parallel insertions and removals of entries which do not share a lock. The patch also defers expansion and shrinking to a worker queue which allows insertion and removal from atomic context. Insertions and deletions may occur in parallel to it and are only held up briefly while the particular bucket is linked or unzipped. Mutations of the bucket table pointer is protected by a new mutex, read access is RCU protected. In the event of an expansion or shrinking, the new bucket table allocated is exposed as a so called future table as soon as the resize process starts. Lookups, deletions, and insertions will briefly use both tables. The future table becomes the main table after an RCU grace period and initial linking of the old to the new table was performed. Optimization of the chains to make use of the new number of buckets follows only the new table is in use. The side effect of this is that during that RCU grace period, a bucket traversal using any rht_for_each() variant on the main table will not see any insertions performed during the RCU grace period which would at that point land in the future table. The lookup will see them as it searches both tables if needed. Having multiple insertions and removals occur in parallel requires nelems to become an atomic counter. Signed-off-by: Thomas Graf <tgraf@suug.ch> Signed-off-by: David S. Miller <davem@davemloft.net>
Diffstat (limited to 'net/netlink')
-rw-r--r--net/netlink/af_netlink.c15
1 files changed, 2 insertions, 13 deletions
diff --git a/net/netlink/af_netlink.c b/net/netlink/af_netlink.c
index 57449b6089c2..738c3bfaa564 100644
--- a/net/netlink/af_netlink.c
+++ b/net/netlink/af_netlink.c
@@ -114,15 +114,6 @@ static atomic_t nl_table_users = ATOMIC_INIT(0);
114DEFINE_MUTEX(nl_sk_hash_lock); 114DEFINE_MUTEX(nl_sk_hash_lock);
115EXPORT_SYMBOL_GPL(nl_sk_hash_lock); 115EXPORT_SYMBOL_GPL(nl_sk_hash_lock);
116 116
117#ifdef CONFIG_PROVE_LOCKING
118static int lockdep_nl_sk_hash_is_held(void *parent)
119{
120 if (debug_locks)
121 return lockdep_is_held(&nl_sk_hash_lock) || lockdep_is_held(&nl_table_lock);
122 return 1;
123}
124#endif
125
126static ATOMIC_NOTIFIER_HEAD(netlink_chain); 117static ATOMIC_NOTIFIER_HEAD(netlink_chain);
127 118
128static DEFINE_SPINLOCK(netlink_tap_lock); 119static DEFINE_SPINLOCK(netlink_tap_lock);
@@ -1063,7 +1054,8 @@ static int netlink_insert(struct sock *sk, struct net *net, u32 portid)
1063 goto err; 1054 goto err;
1064 1055
1065 err = -ENOMEM; 1056 err = -ENOMEM;
1066 if (BITS_PER_LONG > 32 && unlikely(table->hash.nelems >= UINT_MAX)) 1057 if (BITS_PER_LONG > 32 &&
1058 unlikely(atomic_read(&table->hash.nelems) >= UINT_MAX))
1067 goto err; 1059 goto err;
1068 1060
1069 nlk_sk(sk)->portid = portid; 1061 nlk_sk(sk)->portid = portid;
@@ -3122,9 +3114,6 @@ static int __init netlink_proto_init(void)
3122 .max_shift = 16, /* 64K */ 3114 .max_shift = 16, /* 64K */
3123 .grow_decision = rht_grow_above_75, 3115 .grow_decision = rht_grow_above_75,
3124 .shrink_decision = rht_shrink_below_30, 3116 .shrink_decision = rht_shrink_below_30,
3125#ifdef CONFIG_PROVE_LOCKING
3126 .mutex_is_held = lockdep_nl_sk_hash_is_held,
3127#endif
3128 }; 3117 };
3129 3118
3130 if (err != 0) 3119 if (err != 0)