diff options
Diffstat (limited to 'drivers/ieee1394/csr1212.c')
-rw-r--r-- | drivers/ieee1394/csr1212.c | 57 |
1 files changed, 30 insertions, 27 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 | ||
333 | int csr1212_attach_keyval_to_directory(struct csr1212_keyval *dir, | 331 | static 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 | ||
360 | int 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. */ |
489 | static void csr1212_destroy_keyval(struct csr1212_keyval *kv) | 494 | void 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 | ||
539 | void 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 | |||
547 | void csr1212_destroy_csr(struct csr1212_csr *csr) | 546 | void 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); |
1187 | out: | 1190 | out: |
1188 | if (ret != CSR1212_SUCCESS && k != NULL) | 1191 | if (ret != CSR1212_SUCCESS && k != NULL) |
1189 | free_keyval(k); | 1192 | free_keyval(k); |