aboutsummaryrefslogtreecommitdiffstats
path: root/drivers/ieee1394
diff options
context:
space:
mode:
authorStefan Richter <stefanr@s5r6.in-berlin.de>2007-09-15 08:50:25 -0400
committerStefan Richter <stefanr@s5r6.in-berlin.de>2007-10-16 17:59:59 -0400
commit17a19b795e9187d65b6e45cb22797725d50f7edb (patch)
tree60db3734335f3956378063c2f8126c036b83bfed /drivers/ieee1394
parent638d5bb8167c2c88552257d5af23f7f65ab4defd (diff)
ieee1394: csr1212: proper refcounting
At least since nodemgr got rid of coarse global locking, accesses to struct csr1212_keyval's reference counter should be atomic and coupled with proper barriers. Also, calls to csr1212_keep_keyval(kv) should occur before kv is being used. (We probably should convert refcnt to struct kref, but how to keep csr1212_destroy_keyval's implementation non-recursively then?) Signed-off-by: Stefan Richter <stefanr@s5r6.in-berlin.de>
Diffstat (limited to 'drivers/ieee1394')
-rw-r--r--drivers/ieee1394/csr1212.c57
-rw-r--r--drivers/ieee1394/csr1212.h6
-rw-r--r--drivers/ieee1394/nodemgr.c4
3 files changed, 36 insertions, 31 deletions
diff --git a/drivers/ieee1394/csr1212.c b/drivers/ieee1394/csr1212.c
index d08166bda1c5..e8122def164d 100644
--- a/drivers/ieee1394/csr1212.c
+++ b/drivers/ieee1394/csr1212.c
@@ -218,12 +218,10 @@ static struct csr1212_keyval *csr1212_new_keyval(u8 type, u8 key)
218 if (!kv) 218 if (!kv)
219 return NULL; 219 return NULL;
220 220
221 atomic_set(&kv->refcnt, 1);
221 kv->key.type = type; 222 kv->key.type = type;
222 kv->key.id = key; 223 kv->key.id = key;
223
224 kv->associate = NULL; 224 kv->associate = NULL;
225 kv->refcnt = 1;
226
227 kv->next = NULL; 225 kv->next = NULL;
228 kv->prev = NULL; 226 kv->prev = NULL;
229 kv->offset = 0; 227 kv->offset = 0;
@@ -326,12 +324,13 @@ void csr1212_associate_keyval(struct csr1212_keyval *kv,
326 if (kv->associate) 324 if (kv->associate)
327 csr1212_release_keyval(kv->associate); 325 csr1212_release_keyval(kv->associate);
328 326
329 associate->refcnt++; 327 csr1212_keep_keyval(associate);
330 kv->associate = associate; 328 kv->associate = associate;
331} 329}
332 330
333int csr1212_attach_keyval_to_directory(struct csr1212_keyval *dir, 331static int __csr1212_attach_keyval_to_directory(struct csr1212_keyval *dir,
334 struct csr1212_keyval *kv) 332 struct csr1212_keyval *kv,
333 bool keep_keyval)
335{ 334{
336 struct csr1212_dentry *dentry; 335 struct csr1212_dentry *dentry;
337 336
@@ -341,10 +340,10 @@ int csr1212_attach_keyval_to_directory(struct csr1212_keyval *dir,
341 if (!dentry) 340 if (!dentry)
342 return -ENOMEM; 341 return -ENOMEM;
343 342
343 if (keep_keyval)
344 csr1212_keep_keyval(kv);
344 dentry->kv = kv; 345 dentry->kv = kv;
345 346
346 kv->refcnt++;
347
348 dentry->next = NULL; 347 dentry->next = NULL;
349 dentry->prev = dir->value.directory.dentries_tail; 348 dentry->prev = dir->value.directory.dentries_tail;
350 349
@@ -358,6 +357,12 @@ int csr1212_attach_keyval_to_directory(struct csr1212_keyval *dir,
358 return CSR1212_SUCCESS; 357 return CSR1212_SUCCESS;
359} 358}
360 359
360int csr1212_attach_keyval_to_directory(struct csr1212_keyval *dir,
361 struct csr1212_keyval *kv)
362{
363 return __csr1212_attach_keyval_to_directory(dir, kv, true);
364}
365
361#define CSR1212_DESCRIPTOR_LEAF_DATA(kv) \ 366#define CSR1212_DESCRIPTOR_LEAF_DATA(kv) \
362 (&((kv)->value.leaf.data[1])) 367 (&((kv)->value.leaf.data[1]))
363 368
@@ -483,15 +488,18 @@ void csr1212_detach_keyval_from_directory(struct csr1212_keyval *dir,
483 488
484/* This function is used to free the memory taken by a keyval. If the given 489/* This function is used to free the memory taken by a keyval. If the given
485 * keyval is a directory type, then any keyvals contained in that directory 490 * keyval is a directory type, then any keyvals contained in that directory
486 * will be destroyed as well if their respective refcnts are 0. By means of 491 * will be destroyed as well if noone holds a reference on them. By means of
487 * list manipulation, this routine will descend a directory structure in a 492 * list manipulation, this routine will descend a directory structure in a
488 * non-recursive manner. */ 493 * non-recursive manner. */
489static void csr1212_destroy_keyval(struct csr1212_keyval *kv) 494void csr1212_release_keyval(struct csr1212_keyval *kv)
490{ 495{
491 struct csr1212_keyval *k, *a; 496 struct csr1212_keyval *k, *a;
492 struct csr1212_dentry dentry; 497 struct csr1212_dentry dentry;
493 struct csr1212_dentry *head, *tail; 498 struct csr1212_dentry *head, *tail;
494 499
500 if (!atomic_dec_and_test(&kv->refcnt))
501 return;
502
495 dentry.kv = kv; 503 dentry.kv = kv;
496 dentry.next = NULL; 504 dentry.next = NULL;
497 dentry.prev = NULL; 505 dentry.prev = NULL;
@@ -503,9 +511,8 @@ static void csr1212_destroy_keyval(struct csr1212_keyval *kv)
503 k = head->kv; 511 k = head->kv;
504 512
505 while (k) { 513 while (k) {
506 k->refcnt--; 514 /* must not dec_and_test kv->refcnt again */
507 515 if (k != kv && !atomic_dec_and_test(&k->refcnt))
508 if (k->refcnt > 0)
509 break; 516 break;
510 517
511 a = k->associate; 518 a = k->associate;
@@ -536,14 +543,6 @@ static void csr1212_destroy_keyval(struct csr1212_keyval *kv)
536 } 543 }
537} 544}
538 545
539void csr1212_release_keyval(struct csr1212_keyval *kv)
540{
541 if (kv->refcnt > 1)
542 kv->refcnt--;
543 else
544 csr1212_destroy_keyval(kv);
545}
546
547void csr1212_destroy_csr(struct csr1212_csr *csr) 546void csr1212_destroy_csr(struct csr1212_csr *csr)
548{ 547{
549 struct csr1212_csr_rom_cache *c, *oc; 548 struct csr1212_csr_rom_cache *c, *oc;
@@ -1126,6 +1125,7 @@ csr1212_parse_dir_entry(struct csr1212_keyval *dir, u32 ki, u32 kv_pos)
1126 int ret = CSR1212_SUCCESS; 1125 int ret = CSR1212_SUCCESS;
1127 struct csr1212_keyval *k = NULL; 1126 struct csr1212_keyval *k = NULL;
1128 u32 offset; 1127 u32 offset;
1128 bool keep_keyval = true;
1129 1129
1130 switch (CSR1212_KV_KEY_TYPE(ki)) { 1130 switch (CSR1212_KV_KEY_TYPE(ki)) {
1131 case CSR1212_KV_TYPE_IMMEDIATE: 1131 case CSR1212_KV_TYPE_IMMEDIATE:
@@ -1135,8 +1135,8 @@ csr1212_parse_dir_entry(struct csr1212_keyval *dir, u32 ki, u32 kv_pos)
1135 ret = -ENOMEM; 1135 ret = -ENOMEM;
1136 goto out; 1136 goto out;
1137 } 1137 }
1138 1138 /* Don't keep local reference when parsing. */
1139 k->refcnt = 0; /* Don't keep local reference when parsing. */ 1139 keep_keyval = false;
1140 break; 1140 break;
1141 1141
1142 case CSR1212_KV_TYPE_CSR_OFFSET: 1142 case CSR1212_KV_TYPE_CSR_OFFSET:
@@ -1146,7 +1146,8 @@ csr1212_parse_dir_entry(struct csr1212_keyval *dir, u32 ki, u32 kv_pos)
1146 ret = -ENOMEM; 1146 ret = -ENOMEM;
1147 goto out; 1147 goto out;
1148 } 1148 }
1149 k->refcnt = 0; /* Don't keep local reference when parsing. */ 1149 /* Don't keep local reference when parsing. */
1150 keep_keyval = false;
1150 break; 1151 break;
1151 1152
1152 default: 1153 default:
@@ -1174,8 +1175,10 @@ csr1212_parse_dir_entry(struct csr1212_keyval *dir, u32 ki, u32 kv_pos)
1174 ret = -ENOMEM; 1175 ret = -ENOMEM;
1175 goto out; 1176 goto out;
1176 } 1177 }
1177 k->refcnt = 0; /* Don't keep local reference when parsing. */ 1178 /* Don't keep local reference when parsing. */
1178 k->valid = 0; /* Contents not read yet so it's not valid. */ 1179 keep_keyval = false;
1180 /* Contents not read yet so it's not valid. */
1181 k->valid = 0;
1179 k->offset = offset; 1182 k->offset = offset;
1180 1183
1181 k->prev = dir; 1184 k->prev = dir;
@@ -1183,7 +1186,7 @@ csr1212_parse_dir_entry(struct csr1212_keyval *dir, u32 ki, u32 kv_pos)
1183 dir->next->prev = k; 1186 dir->next->prev = k;
1184 dir->next = k; 1187 dir->next = k;
1185 } 1188 }
1186 ret = csr1212_attach_keyval_to_directory(dir, k); 1189 ret = __csr1212_attach_keyval_to_directory(dir, k, keep_keyval);
1187out: 1190out:
1188 if (ret != CSR1212_SUCCESS && k != NULL) 1191 if (ret != CSR1212_SUCCESS && k != NULL)
1189 free_keyval(k); 1192 free_keyval(k);
diff --git a/drivers/ieee1394/csr1212.h b/drivers/ieee1394/csr1212.h
index df909ce66304..043039fc63ec 100644
--- a/drivers/ieee1394/csr1212.h
+++ b/drivers/ieee1394/csr1212.h
@@ -32,6 +32,7 @@
32 32
33#include <linux/types.h> 33#include <linux/types.h>
34#include <linux/slab.h> 34#include <linux/slab.h>
35#include <asm/atomic.h>
35 36
36#define CSR1212_MALLOC(size) kmalloc((size), GFP_KERNEL) 37#define CSR1212_MALLOC(size) kmalloc((size), GFP_KERNEL)
37#define CSR1212_FREE(ptr) kfree(ptr) 38#define CSR1212_FREE(ptr) kfree(ptr)
@@ -149,7 +150,7 @@ struct csr1212_keyval {
149 struct csr1212_directory directory; 150 struct csr1212_directory directory;
150 } value; 151 } value;
151 struct csr1212_keyval *associate; 152 struct csr1212_keyval *associate;
152 int refcnt; 153 atomic_t refcnt;
153 154
154 /* used in generating and/or parsing CSR image */ 155 /* used in generating and/or parsing CSR image */
155 struct csr1212_keyval *next, *prev; /* flat list of CSR elements */ 156 struct csr1212_keyval *next, *prev; /* flat list of CSR elements */
@@ -350,7 +351,8 @@ csr1212_get_keyval(struct csr1212_csr *csr, struct csr1212_keyval *kv);
350 * need for code to retain a keyval that has been parsed. */ 351 * need for code to retain a keyval that has been parsed. */
351static inline void csr1212_keep_keyval(struct csr1212_keyval *kv) 352static inline void csr1212_keep_keyval(struct csr1212_keyval *kv)
352{ 353{
353 kv->refcnt++; 354 atomic_inc(&kv->refcnt);
355 smp_mb__after_atomic_inc();
354} 356}
355 357
356 358
diff --git a/drivers/ieee1394/nodemgr.c b/drivers/ieee1394/nodemgr.c
index ec8edd2f19de..90dc75be3418 100644
--- a/drivers/ieee1394/nodemgr.c
+++ b/drivers/ieee1394/nodemgr.c
@@ -1014,13 +1014,13 @@ static struct unit_directory *nodemgr_process_unit_directory
1014 CSR1212_TEXTUAL_DESCRIPTOR_LEAF_LANGUAGE(kv) == 0) { 1014 CSR1212_TEXTUAL_DESCRIPTOR_LEAF_LANGUAGE(kv) == 0) {
1015 switch (last_key_id) { 1015 switch (last_key_id) {
1016 case CSR1212_KV_ID_VENDOR: 1016 case CSR1212_KV_ID_VENDOR:
1017 ud->vendor_name_kv = kv;
1018 csr1212_keep_keyval(kv); 1017 csr1212_keep_keyval(kv);
1018 ud->vendor_name_kv = kv;
1019 break; 1019 break;
1020 1020
1021 case CSR1212_KV_ID_MODEL: 1021 case CSR1212_KV_ID_MODEL:
1022 ud->model_name_kv = kv;
1023 csr1212_keep_keyval(kv); 1022 csr1212_keep_keyval(kv);
1023 ud->model_name_kv = kv;
1024 break; 1024 break;
1025 1025
1026 } 1026 }