aboutsummaryrefslogtreecommitdiffstats
path: root/net/tipc/ref.c
diff options
context:
space:
mode:
authorJon Paul Maloy <jon.maloy@ericsson.com>2014-08-22 18:09:16 -0400
committerDavid S. Miller <davem@davemloft.net>2014-08-23 14:18:34 -0400
commit6c9808ce09f778a1de7b207b82cfc36a59cda2d3 (patch)
treedce467a4bd4be90896e7243f87335e1b41cded75 /net/tipc/ref.c
parent9b50fd087a9f1454d6a8b613fff376dfb6d6ea93 (diff)
tipc: remove port_lock
In previous commits we have reduced usage of port_lock to a minimum, and complemented it with usage of bh_lock_sock() at the remaining locations. The purpose has been to remove this lock altogether, since it largely duplicates the role of bh_lock_sock. We are now ready to do this. However, we still need to protect the BH callers from inadvertent release of the socket while they hold a reference to it. We do this by replacing port_lock by a combination of a rw-lock protecting the reference table as such, and updating the socket reference counter while the socket is referenced from BH. This technique is more standard and comprehensible than the previous approach, and turns out to have a positive effect on overall performance. Signed-off-by: Jon Maloy <jon.maloy@ericsson.com> Reviewed-by: Erik Hugne <erik.hugne@ericsson.com> Reviewed-by: Ying Xue <ying.xue@windriver.com> Signed-off-by: David S. Miller <davem@davemloft.net>
Diffstat (limited to 'net/tipc/ref.c')
-rw-r--r--net/tipc/ref.c158
1 files changed, 71 insertions, 87 deletions
diff --git a/net/tipc/ref.c b/net/tipc/ref.c
index 7fc2740846e3..ea981bed967b 100644
--- a/net/tipc/ref.c
+++ b/net/tipc/ref.c
@@ -1,7 +1,7 @@
1/* 1/*
2 * net/tipc/ref.c: TIPC object registry code 2 * net/tipc/ref.c: TIPC socket registry code
3 * 3 *
4 * Copyright (c) 1991-2006, Ericsson AB 4 * Copyright (c) 1991-2006, 2014, Ericsson AB
5 * Copyright (c) 2004-2007, Wind River Systems 5 * Copyright (c) 2004-2007, Wind River Systems
6 * All rights reserved. 6 * All rights reserved.
7 * 7 *
@@ -38,24 +38,22 @@
38#include "ref.h" 38#include "ref.h"
39 39
40/** 40/**
41 * struct reference - TIPC object reference entry 41 * struct reference - TIPC socket reference entry
42 * @object: pointer to object associated with reference entry 42 * @tsk: pointer to socket associated with reference entry
43 * @lock: spinlock controlling access to object 43 * @ref: reference value for socket (combines instance & array index info)
44 * @ref: reference value for object (combines instance & array index info)
45 */ 44 */
46struct reference { 45struct reference {
47 void *object; 46 struct tipc_sock *tsk;
48 spinlock_t lock;
49 u32 ref; 47 u32 ref;
50}; 48};
51 49
52/** 50/**
53 * struct tipc_ref_table - table of TIPC object reference entries 51 * struct tipc_ref_table - table of TIPC socket reference entries
54 * @entries: pointer to array of reference entries 52 * @entries: pointer to array of reference entries
55 * @capacity: array index of first unusable entry 53 * @capacity: array index of first unusable entry
56 * @init_point: array index of first uninitialized entry 54 * @init_point: array index of first uninitialized entry
57 * @first_free: array index of first unused object reference entry 55 * @first_free: array index of first unused socket reference entry
58 * @last_free: array index of last unused object reference entry 56 * @last_free: array index of last unused socket reference entry
59 * @index_mask: bitmask for array index portion of reference values 57 * @index_mask: bitmask for array index portion of reference values
60 * @start_mask: initial value for instance value portion of reference values 58 * @start_mask: initial value for instance value portion of reference values
61 */ 59 */
@@ -70,9 +68,9 @@ struct ref_table {
70}; 68};
71 69
72/* 70/*
73 * Object reference table consists of 2**N entries. 71 * Socket reference table consists of 2**N entries.
74 * 72 *
75 * State Object ptr Reference 73 * State Socket ptr Reference
76 * ----- ---------- --------- 74 * ----- ---------- ---------
77 * In use non-NULL XXXX|own index 75 * In use non-NULL XXXX|own index
78 * (XXXX changes each time entry is acquired) 76 * (XXXX changes each time entry is acquired)
@@ -89,10 +87,10 @@ struct ref_table {
89 87
90static struct ref_table tipc_ref_table; 88static struct ref_table tipc_ref_table;
91 89
92static DEFINE_SPINLOCK(ref_table_lock); 90static DEFINE_RWLOCK(ref_table_lock);
93 91
94/** 92/**
95 * tipc_ref_table_init - create reference table for objects 93 * tipc_ref_table_init - create reference table for sockets
96 */ 94 */
97int tipc_ref_table_init(u32 requested_size, u32 start) 95int tipc_ref_table_init(u32 requested_size, u32 start)
98{ 96{
@@ -122,84 +120,69 @@ int tipc_ref_table_init(u32 requested_size, u32 start)
122} 120}
123 121
124/** 122/**
125 * tipc_ref_table_stop - destroy reference table for objects 123 * tipc_ref_table_stop - destroy reference table for sockets
126 */ 124 */
127void tipc_ref_table_stop(void) 125void tipc_ref_table_stop(void)
128{ 126{
127 if (!tipc_ref_table.entries)
128 return;
129 vfree(tipc_ref_table.entries); 129 vfree(tipc_ref_table.entries);
130 tipc_ref_table.entries = NULL; 130 tipc_ref_table.entries = NULL;
131} 131}
132 132
133/** 133/* tipc_ref_acquire - create reference to a socket
134 * tipc_ref_acquire - create reference to an object
135 * 134 *
136 * Register an object pointer in reference table and lock the object. 135 * Register an socket pointer in the reference table.
137 * Returns a unique reference value that is used from then on to retrieve the 136 * Returns a unique reference value that is used from then on to retrieve the
138 * object pointer, or to determine that the object has been deregistered. 137 * socket pointer, or to determine if the socket has been deregistered.
139 *
140 * Note: The object is returned in the locked state so that the caller can
141 * register a partially initialized object, without running the risk that
142 * the object will be accessed before initialization is complete.
143 */ 138 */
144u32 tipc_ref_acquire(void *object, spinlock_t **lock) 139u32 tipc_ref_acquire(struct tipc_sock *tsk)
145{ 140{
146 u32 index; 141 u32 index;
147 u32 index_mask; 142 u32 index_mask;
148 u32 next_plus_upper; 143 u32 next_plus_upper;
149 u32 ref; 144 u32 ref = 0;
150 struct reference *entry = NULL; 145 struct reference *entry;
151 146
152 if (!object) { 147 if (unlikely(!tsk)) {
153 pr_err("Attempt to acquire ref. to non-existent obj\n"); 148 pr_err("Attempt to acquire ref. to non-existent obj\n");
154 return 0; 149 return 0;
155 } 150 }
156 if (!tipc_ref_table.entries) { 151 if (unlikely(!tipc_ref_table.entries)) {
157 pr_err("Ref. table not found in acquisition attempt\n"); 152 pr_err("Ref. table not found in acquisition attempt\n");
158 return 0; 153 return 0;
159 } 154 }
160 155
161 /* take a free entry, if available; otherwise initialize a new entry */ 156 /* Take a free entry, if available; otherwise initialize a new one */
162 spin_lock_bh(&ref_table_lock); 157 write_lock_bh(&ref_table_lock);
163 if (tipc_ref_table.first_free) { 158 index = tipc_ref_table.first_free;
159 entry = &tipc_ref_table.entries[index];
160
161 if (likely(index)) {
164 index = tipc_ref_table.first_free; 162 index = tipc_ref_table.first_free;
165 entry = &(tipc_ref_table.entries[index]); 163 entry = &(tipc_ref_table.entries[index]);
166 index_mask = tipc_ref_table.index_mask; 164 index_mask = tipc_ref_table.index_mask;
167 next_plus_upper = entry->ref; 165 next_plus_upper = entry->ref;
168 tipc_ref_table.first_free = next_plus_upper & index_mask; 166 tipc_ref_table.first_free = next_plus_upper & index_mask;
169 ref = (next_plus_upper & ~index_mask) + index; 167 ref = (next_plus_upper & ~index_mask) + index;
168 entry->tsk = tsk;
170 } else if (tipc_ref_table.init_point < tipc_ref_table.capacity) { 169 } else if (tipc_ref_table.init_point < tipc_ref_table.capacity) {
171 index = tipc_ref_table.init_point++; 170 index = tipc_ref_table.init_point++;
172 entry = &(tipc_ref_table.entries[index]); 171 entry = &(tipc_ref_table.entries[index]);
173 spin_lock_init(&entry->lock);
174 ref = tipc_ref_table.start_mask + index; 172 ref = tipc_ref_table.start_mask + index;
175 } else {
176 ref = 0;
177 } 173 }
178 spin_unlock_bh(&ref_table_lock);
179 174
180 /* 175 if (ref) {
181 * Grab the lock so no one else can modify this entry
182 * While we assign its ref value & object pointer
183 */
184 if (entry) {
185 spin_lock_bh(&entry->lock);
186 entry->ref = ref; 176 entry->ref = ref;
187 entry->object = object; 177 entry->tsk = tsk;
188 *lock = &entry->lock;
189 /*
190 * keep it locked, the caller is responsible
191 * for unlocking this when they're done with it
192 */
193 } 178 }
194 179 write_unlock_bh(&ref_table_lock);
195 return ref; 180 return ref;
196} 181}
197 182
198/** 183/* tipc_ref_discard - invalidate reference to an socket
199 * tipc_ref_discard - invalidate references to an object
200 * 184 *
201 * Disallow future references to an object and free up the entry for re-use. 185 * Disallow future references to an socket and free up the entry for re-use.
202 * Note: The entry's spin_lock may still be busy after discard
203 */ 186 */
204void tipc_ref_discard(u32 ref) 187void tipc_ref_discard(u32 ref)
205{ 188{
@@ -207,7 +190,7 @@ void tipc_ref_discard(u32 ref)
207 u32 index; 190 u32 index;
208 u32 index_mask; 191 u32 index_mask;
209 192
210 if (!tipc_ref_table.entries) { 193 if (unlikely(!tipc_ref_table.entries)) {
211 pr_err("Ref. table not found during discard attempt\n"); 194 pr_err("Ref. table not found during discard attempt\n");
212 return; 195 return;
213 } 196 }
@@ -216,71 +199,72 @@ void tipc_ref_discard(u32 ref)
216 index = ref & index_mask; 199 index = ref & index_mask;
217 entry = &(tipc_ref_table.entries[index]); 200 entry = &(tipc_ref_table.entries[index]);
218 201
219 spin_lock_bh(&ref_table_lock); 202 write_lock_bh(&ref_table_lock);
220 203
221 if (!entry->object) { 204 if (unlikely(!entry->tsk)) {
222 pr_err("Attempt to discard ref. to non-existent obj\n"); 205 pr_err("Attempt to discard ref. to non-existent socket\n");
223 goto exit; 206 goto exit;
224 } 207 }
225 if (entry->ref != ref) { 208 if (unlikely(entry->ref != ref)) {
226 pr_err("Attempt to discard non-existent reference\n"); 209 pr_err("Attempt to discard non-existent reference\n");
227 goto exit; 210 goto exit;
228 } 211 }
229 212
230 /* 213 /*
231 * mark entry as unused; increment instance part of entry's reference 214 * Mark entry as unused; increment instance part of entry's reference
232 * to invalidate any subsequent references 215 * to invalidate any subsequent references
233 */ 216 */
234 entry->object = NULL; 217 entry->tsk = NULL;
235 entry->ref = (ref & ~index_mask) + (index_mask + 1); 218 entry->ref = (ref & ~index_mask) + (index_mask + 1);
236 219
237 /* append entry to free entry list */ 220 /* Append entry to free entry list */
238 if (tipc_ref_table.first_free == 0) 221 if (unlikely(tipc_ref_table.first_free == 0))
239 tipc_ref_table.first_free = index; 222 tipc_ref_table.first_free = index;
240 else 223 else
241 tipc_ref_table.entries[tipc_ref_table.last_free].ref |= index; 224 tipc_ref_table.entries[tipc_ref_table.last_free].ref |= index;
242 tipc_ref_table.last_free = index; 225 tipc_ref_table.last_free = index;
243
244exit: 226exit:
245 spin_unlock_bh(&ref_table_lock); 227 write_unlock_bh(&ref_table_lock);
246} 228}
247 229
248/** 230/* tipc_sk_get - find referenced socket and return pointer to it
249 * tipc_ref_lock - lock referenced object and return pointer to it
250 */ 231 */
251void *tipc_ref_lock(u32 ref) 232struct tipc_sock *tipc_sk_get(u32 ref)
252{ 233{
253 if (likely(tipc_ref_table.entries)) { 234 struct reference *entry;
254 struct reference *entry; 235 struct tipc_sock *tsk;
255 236
256 entry = &tipc_ref_table.entries[ref & 237 if (unlikely(!tipc_ref_table.entries))
257 tipc_ref_table.index_mask]; 238 return NULL;
258 if (likely(entry->ref != 0)) { 239 read_lock_bh(&ref_table_lock);
259 spin_lock_bh(&entry->lock); 240 entry = &tipc_ref_table.entries[ref & tipc_ref_table.index_mask];
260 if (likely((entry->ref == ref) && (entry->object))) 241 tsk = entry->tsk;
261 return entry->object; 242 if (likely(tsk && (entry->ref == ref)))
262 spin_unlock_bh(&entry->lock); 243 sock_hold(&tsk->sk);
263 } 244 else
264 } 245 tsk = NULL;
265 return NULL; 246 read_unlock_bh(&ref_table_lock);
247 return tsk;
266} 248}
267 249
268/* tipc_ref_lock_next - lock & return next object after referenced one 250/* tipc_sk_get_next - lock & return next socket after referenced one
269*/ 251*/
270void *tipc_ref_lock_next(u32 *ref) 252struct tipc_sock *tipc_sk_get_next(u32 *ref)
271{ 253{
272 struct reference *entry; 254 struct reference *entry;
255 struct tipc_sock *tsk = NULL;
273 uint index = *ref & tipc_ref_table.index_mask; 256 uint index = *ref & tipc_ref_table.index_mask;
274 257
258 read_lock_bh(&ref_table_lock);
275 while (++index < tipc_ref_table.capacity) { 259 while (++index < tipc_ref_table.capacity) {
276 entry = &tipc_ref_table.entries[index]; 260 entry = &tipc_ref_table.entries[index];
277 if (!entry->object) 261 if (!entry->tsk)
278 continue; 262 continue;
279 spin_lock_bh(&entry->lock); 263 tsk = entry->tsk;
264 sock_hold(&tsk->sk);
280 *ref = entry->ref; 265 *ref = entry->ref;
281 if (entry->object) 266 break;
282 return entry->object;
283 spin_unlock_bh(&entry->lock);
284 } 267 }
285 return NULL; 268 read_unlock_bh(&ref_table_lock);
269 return tsk;
286} 270}