diff options
Diffstat (limited to 'fs/jffs2/nodemgmt.c')
-rw-r--r-- | fs/jffs2/nodemgmt.c | 196 |
1 files changed, 84 insertions, 112 deletions
diff --git a/fs/jffs2/nodemgmt.c b/fs/jffs2/nodemgmt.c index 49127a1f0458..8bedfd2ff689 100644 --- a/fs/jffs2/nodemgmt.c +++ b/fs/jffs2/nodemgmt.c | |||
@@ -23,13 +23,12 @@ | |||
23 | * jffs2_reserve_space - request physical space to write nodes to flash | 23 | * jffs2_reserve_space - request physical space to write nodes to flash |
24 | * @c: superblock info | 24 | * @c: superblock info |
25 | * @minsize: Minimum acceptable size of allocation | 25 | * @minsize: Minimum acceptable size of allocation |
26 | * @ofs: Returned value of node offset | ||
27 | * @len: Returned value of allocation length | 26 | * @len: Returned value of allocation length |
28 | * @prio: Allocation type - ALLOC_{NORMAL,DELETION} | 27 | * @prio: Allocation type - ALLOC_{NORMAL,DELETION} |
29 | * | 28 | * |
30 | * Requests a block of physical space on the flash. Returns zero for success | 29 | * Requests a block of physical space on the flash. Returns zero for success |
31 | * and puts 'ofs' and 'len' into the appriopriate place, or returns -ENOSPC | 30 | * and puts 'len' into the appropriate place, or returns -ENOSPC or other |
32 | * or other error if appropriate. | 31 | * error if appropriate. Doesn't return len since that's |
33 | * | 32 | * |
34 | * If it returns zero, jffs2_reserve_space() also downs the per-filesystem | 33 | * If it returns zero, jffs2_reserve_space() also downs the per-filesystem |
35 | * allocation semaphore, to prevent more than one allocation from being | 34 | * allocation semaphore, to prevent more than one allocation from being |
@@ -40,9 +39,9 @@ | |||
40 | */ | 39 | */ |
41 | 40 | ||
42 | static int jffs2_do_reserve_space(struct jffs2_sb_info *c, uint32_t minsize, | 41 | static int jffs2_do_reserve_space(struct jffs2_sb_info *c, uint32_t minsize, |
43 | uint32_t *ofs, uint32_t *len, uint32_t sumsize); | 42 | uint32_t *len, uint32_t sumsize); |
44 | 43 | ||
45 | int jffs2_reserve_space(struct jffs2_sb_info *c, uint32_t minsize, uint32_t *ofs, | 44 | int jffs2_reserve_space(struct jffs2_sb_info *c, uint32_t minsize, |
46 | uint32_t *len, int prio, uint32_t sumsize) | 45 | uint32_t *len, int prio, uint32_t sumsize) |
47 | { | 46 | { |
48 | int ret = -EAGAIN; | 47 | int ret = -EAGAIN; |
@@ -132,19 +131,21 @@ int jffs2_reserve_space(struct jffs2_sb_info *c, uint32_t minsize, uint32_t *ofs | |||
132 | spin_lock(&c->erase_completion_lock); | 131 | spin_lock(&c->erase_completion_lock); |
133 | } | 132 | } |
134 | 133 | ||
135 | ret = jffs2_do_reserve_space(c, minsize, ofs, len, sumsize); | 134 | ret = jffs2_do_reserve_space(c, minsize, len, sumsize); |
136 | if (ret) { | 135 | if (ret) { |
137 | D1(printk(KERN_DEBUG "jffs2_reserve_space: ret is %d\n", ret)); | 136 | D1(printk(KERN_DEBUG "jffs2_reserve_space: ret is %d\n", ret)); |
138 | } | 137 | } |
139 | } | 138 | } |
140 | spin_unlock(&c->erase_completion_lock); | 139 | spin_unlock(&c->erase_completion_lock); |
140 | if (!ret) | ||
141 | ret = jffs2_prealloc_raw_node_refs(c, c->nextblock, 1); | ||
141 | if (ret) | 142 | if (ret) |
142 | up(&c->alloc_sem); | 143 | up(&c->alloc_sem); |
143 | return ret; | 144 | return ret; |
144 | } | 145 | } |
145 | 146 | ||
146 | int jffs2_reserve_space_gc(struct jffs2_sb_info *c, uint32_t minsize, uint32_t *ofs, | 147 | int jffs2_reserve_space_gc(struct jffs2_sb_info *c, uint32_t minsize, |
147 | uint32_t *len, uint32_t sumsize) | 148 | uint32_t *len, uint32_t sumsize) |
148 | { | 149 | { |
149 | int ret = -EAGAIN; | 150 | int ret = -EAGAIN; |
150 | minsize = PAD(minsize); | 151 | minsize = PAD(minsize); |
@@ -153,12 +154,15 @@ int jffs2_reserve_space_gc(struct jffs2_sb_info *c, uint32_t minsize, uint32_t * | |||
153 | 154 | ||
154 | spin_lock(&c->erase_completion_lock); | 155 | spin_lock(&c->erase_completion_lock); |
155 | while(ret == -EAGAIN) { | 156 | while(ret == -EAGAIN) { |
156 | ret = jffs2_do_reserve_space(c, minsize, ofs, len, sumsize); | 157 | ret = jffs2_do_reserve_space(c, minsize, len, sumsize); |
157 | if (ret) { | 158 | if (ret) { |
158 | D1(printk(KERN_DEBUG "jffs2_reserve_space_gc: looping, ret is %d\n", ret)); | 159 | D1(printk(KERN_DEBUG "jffs2_reserve_space_gc: looping, ret is %d\n", ret)); |
159 | } | 160 | } |
160 | } | 161 | } |
161 | spin_unlock(&c->erase_completion_lock); | 162 | spin_unlock(&c->erase_completion_lock); |
163 | if (!ret) | ||
164 | ret = jffs2_prealloc_raw_node_refs(c, c->nextblock, 1); | ||
165 | |||
162 | return ret; | 166 | return ret; |
163 | } | 167 | } |
164 | 168 | ||
@@ -259,10 +263,11 @@ static int jffs2_find_nextblock(struct jffs2_sb_info *c) | |||
259 | } | 263 | } |
260 | 264 | ||
261 | /* Called with alloc sem _and_ erase_completion_lock */ | 265 | /* Called with alloc sem _and_ erase_completion_lock */ |
262 | static int jffs2_do_reserve_space(struct jffs2_sb_info *c, uint32_t minsize, uint32_t *ofs, uint32_t *len, uint32_t sumsize) | 266 | static int jffs2_do_reserve_space(struct jffs2_sb_info *c, uint32_t minsize, |
267 | uint32_t *len, uint32_t sumsize) | ||
263 | { | 268 | { |
264 | struct jffs2_eraseblock *jeb = c->nextblock; | 269 | struct jffs2_eraseblock *jeb = c->nextblock; |
265 | uint32_t reserved_size; /* for summary information at the end of the jeb */ | 270 | uint32_t reserved_size; /* for summary information at the end of the jeb */ |
266 | int ret; | 271 | int ret; |
267 | 272 | ||
268 | restart: | 273 | restart: |
@@ -312,6 +317,8 @@ static int jffs2_do_reserve_space(struct jffs2_sb_info *c, uint32_t minsize, uin | |||
312 | } | 317 | } |
313 | } else { | 318 | } else { |
314 | if (jeb && minsize > jeb->free_size) { | 319 | if (jeb && minsize > jeb->free_size) { |
320 | uint32_t waste; | ||
321 | |||
315 | /* Skip the end of this block and file it as having some dirty space */ | 322 | /* Skip the end of this block and file it as having some dirty space */ |
316 | /* If there's a pending write to it, flush now */ | 323 | /* If there's a pending write to it, flush now */ |
317 | 324 | ||
@@ -324,10 +331,26 @@ static int jffs2_do_reserve_space(struct jffs2_sb_info *c, uint32_t minsize, uin | |||
324 | goto restart; | 331 | goto restart; |
325 | } | 332 | } |
326 | 333 | ||
327 | c->wasted_size += jeb->free_size; | 334 | spin_unlock(&c->erase_completion_lock); |
328 | c->free_size -= jeb->free_size; | 335 | |
329 | jeb->wasted_size += jeb->free_size; | 336 | ret = jffs2_prealloc_raw_node_refs(c, jeb, 1); |
330 | jeb->free_size = 0; | 337 | if (ret) |
338 | return ret; | ||
339 | /* Just lock it again and continue. Nothing much can change because | ||
340 | we hold c->alloc_sem anyway. In fact, it's not entirely clear why | ||
341 | we hold c->erase_completion_lock in the majority of this function... | ||
342 | but that's a question for another (more caffeine-rich) day. */ | ||
343 | spin_lock(&c->erase_completion_lock); | ||
344 | |||
345 | waste = jeb->free_size; | ||
346 | jffs2_link_node_ref(c, jeb, | ||
347 | (jeb->offset + c->sector_size - waste) | REF_OBSOLETE, | ||
348 | waste, NULL); | ||
349 | /* FIXME: that made it count as dirty. Convert to wasted */ | ||
350 | jeb->dirty_size -= waste; | ||
351 | c->dirty_size -= waste; | ||
352 | jeb->wasted_size += waste; | ||
353 | c->wasted_size += waste; | ||
331 | 354 | ||
332 | jffs2_close_nextblock(c, jeb); | 355 | jffs2_close_nextblock(c, jeb); |
333 | jeb = NULL; | 356 | jeb = NULL; |
@@ -349,7 +372,6 @@ static int jffs2_do_reserve_space(struct jffs2_sb_info *c, uint32_t minsize, uin | |||
349 | } | 372 | } |
350 | /* OK, jeb (==c->nextblock) is now pointing at a block which definitely has | 373 | /* OK, jeb (==c->nextblock) is now pointing at a block which definitely has |
351 | enough space */ | 374 | enough space */ |
352 | *ofs = jeb->offset + (c->sector_size - jeb->free_size); | ||
353 | *len = jeb->free_size - reserved_size; | 375 | *len = jeb->free_size - reserved_size; |
354 | 376 | ||
355 | if (c->cleanmarker_size && jeb->used_size == c->cleanmarker_size && | 377 | if (c->cleanmarker_size && jeb->used_size == c->cleanmarker_size && |
@@ -365,7 +387,8 @@ static int jffs2_do_reserve_space(struct jffs2_sb_info *c, uint32_t minsize, uin | |||
365 | spin_lock(&c->erase_completion_lock); | 387 | spin_lock(&c->erase_completion_lock); |
366 | } | 388 | } |
367 | 389 | ||
368 | D1(printk(KERN_DEBUG "jffs2_do_reserve_space(): Giving 0x%x bytes at 0x%x\n", *len, *ofs)); | 390 | D1(printk(KERN_DEBUG "jffs2_do_reserve_space(): Giving 0x%x bytes at 0x%x\n", |
391 | *len, jeb->offset + (c->sector_size - jeb->free_size))); | ||
369 | return 0; | 392 | return 0; |
370 | } | 393 | } |
371 | 394 | ||
@@ -374,7 +397,6 @@ static int jffs2_do_reserve_space(struct jffs2_sb_info *c, uint32_t minsize, uin | |||
374 | * @c: superblock info | 397 | * @c: superblock info |
375 | * @new: new node reference to add | 398 | * @new: new node reference to add |
376 | * @len: length of this physical node | 399 | * @len: length of this physical node |
377 | * @dirty: dirty flag for new node | ||
378 | * | 400 | * |
379 | * Should only be used to report nodes for which space has been allocated | 401 | * Should only be used to report nodes for which space has been allocated |
380 | * by jffs2_reserve_space. | 402 | * by jffs2_reserve_space. |
@@ -382,42 +404,30 @@ static int jffs2_do_reserve_space(struct jffs2_sb_info *c, uint32_t minsize, uin | |||
382 | * Must be called with the alloc_sem held. | 404 | * Must be called with the alloc_sem held. |
383 | */ | 405 | */ |
384 | 406 | ||
385 | int jffs2_add_physical_node_ref(struct jffs2_sb_info *c, struct jffs2_raw_node_ref *new) | 407 | struct jffs2_raw_node_ref *jffs2_add_physical_node_ref(struct jffs2_sb_info *c, |
408 | uint32_t ofs, uint32_t len, | ||
409 | struct jffs2_inode_cache *ic) | ||
386 | { | 410 | { |
387 | struct jffs2_eraseblock *jeb; | 411 | struct jffs2_eraseblock *jeb; |
388 | uint32_t len; | 412 | struct jffs2_raw_node_ref *new; |
389 | 413 | ||
390 | jeb = &c->blocks[new->flash_offset / c->sector_size]; | 414 | jeb = &c->blocks[ofs / c->sector_size]; |
391 | len = ref_totlen(c, jeb, new); | ||
392 | 415 | ||
393 | D1(printk(KERN_DEBUG "jffs2_add_physical_node_ref(): Node at 0x%x(%d), size 0x%x\n", ref_offset(new), ref_flags(new), len)); | 416 | D1(printk(KERN_DEBUG "jffs2_add_physical_node_ref(): Node at 0x%x(%d), size 0x%x\n", |
417 | ofs & ~3, ofs & 3, len)); | ||
394 | #if 1 | 418 | #if 1 |
395 | /* we could get some obsolete nodes after nextblock was refiled | 419 | /* Allow non-obsolete nodes only to be added at the end of c->nextblock, |
396 | in wbuf.c */ | 420 | if c->nextblock is set. Note that wbuf.c will file obsolete nodes |
397 | if ((c->nextblock || !ref_obsolete(new)) | 421 | even after refiling c->nextblock */ |
398 | &&(jeb != c->nextblock || ref_offset(new) != jeb->offset + (c->sector_size - jeb->free_size))) { | 422 | if ((c->nextblock || ((ofs & 3) != REF_OBSOLETE)) |
423 | && (jeb != c->nextblock || (ofs & ~3) != jeb->offset + (c->sector_size - jeb->free_size))) { | ||
399 | printk(KERN_WARNING "argh. node added in wrong place\n"); | 424 | printk(KERN_WARNING "argh. node added in wrong place\n"); |
400 | jffs2_free_raw_node_ref(new); | 425 | return ERR_PTR(-EINVAL); |
401 | return -EINVAL; | ||
402 | } | 426 | } |
403 | #endif | 427 | #endif |
404 | spin_lock(&c->erase_completion_lock); | 428 | spin_lock(&c->erase_completion_lock); |
405 | 429 | ||
406 | if (!jeb->first_node) | 430 | new = jffs2_link_node_ref(c, jeb, ofs, len, ic); |
407 | jeb->first_node = new; | ||
408 | if (jeb->last_node) | ||
409 | jeb->last_node->next_phys = new; | ||
410 | jeb->last_node = new; | ||
411 | |||
412 | jeb->free_size -= len; | ||
413 | c->free_size -= len; | ||
414 | if (ref_obsolete(new)) { | ||
415 | jeb->dirty_size += len; | ||
416 | c->dirty_size += len; | ||
417 | } else { | ||
418 | jeb->used_size += len; | ||
419 | c->used_size += len; | ||
420 | } | ||
421 | 431 | ||
422 | if (!jeb->free_size && !jeb->dirty_size && !ISDIRTY(jeb->wasted_size)) { | 432 | if (!jeb->free_size && !jeb->dirty_size && !ISDIRTY(jeb->wasted_size)) { |
423 | /* If it lives on the dirty_list, jffs2_reserve_space will put it there */ | 433 | /* If it lives on the dirty_list, jffs2_reserve_space will put it there */ |
@@ -438,7 +448,7 @@ int jffs2_add_physical_node_ref(struct jffs2_sb_info *c, struct jffs2_raw_node_r | |||
438 | 448 | ||
439 | spin_unlock(&c->erase_completion_lock); | 449 | spin_unlock(&c->erase_completion_lock); |
440 | 450 | ||
441 | return 0; | 451 | return new; |
442 | } | 452 | } |
443 | 453 | ||
444 | 454 | ||
@@ -470,8 +480,9 @@ void jffs2_mark_node_obsolete(struct jffs2_sb_info *c, struct jffs2_raw_node_ref | |||
470 | struct jffs2_unknown_node n; | 480 | struct jffs2_unknown_node n; |
471 | int ret, addedsize; | 481 | int ret, addedsize; |
472 | size_t retlen; | 482 | size_t retlen; |
483 | uint32_t freed_len; | ||
473 | 484 | ||
474 | if(!ref) { | 485 | if(unlikely(!ref)) { |
475 | printk(KERN_NOTICE "EEEEEK. jffs2_mark_node_obsolete called with NULL node\n"); | 486 | printk(KERN_NOTICE "EEEEEK. jffs2_mark_node_obsolete called with NULL node\n"); |
476 | return; | 487 | return; |
477 | } | 488 | } |
@@ -499,32 +510,34 @@ void jffs2_mark_node_obsolete(struct jffs2_sb_info *c, struct jffs2_raw_node_ref | |||
499 | 510 | ||
500 | spin_lock(&c->erase_completion_lock); | 511 | spin_lock(&c->erase_completion_lock); |
501 | 512 | ||
513 | freed_len = ref_totlen(c, jeb, ref); | ||
514 | |||
502 | if (ref_flags(ref) == REF_UNCHECKED) { | 515 | if (ref_flags(ref) == REF_UNCHECKED) { |
503 | D1(if (unlikely(jeb->unchecked_size < ref_totlen(c, jeb, ref))) { | 516 | D1(if (unlikely(jeb->unchecked_size < freed_len)) { |
504 | printk(KERN_NOTICE "raw unchecked node of size 0x%08x freed from erase block %d at 0x%08x, but unchecked_size was already 0x%08x\n", | 517 | printk(KERN_NOTICE "raw unchecked node of size 0x%08x freed from erase block %d at 0x%08x, but unchecked_size was already 0x%08x\n", |
505 | ref_totlen(c, jeb, ref), blocknr, ref->flash_offset, jeb->used_size); | 518 | freed_len, blocknr, ref->flash_offset, jeb->used_size); |
506 | BUG(); | 519 | BUG(); |
507 | }) | 520 | }) |
508 | D1(printk(KERN_DEBUG "Obsoleting previously unchecked node at 0x%08x of len %x: ", ref_offset(ref), ref_totlen(c, jeb, ref))); | 521 | D1(printk(KERN_DEBUG "Obsoleting previously unchecked node at 0x%08x of len %x: ", ref_offset(ref), freed_len)); |
509 | jeb->unchecked_size -= ref_totlen(c, jeb, ref); | 522 | jeb->unchecked_size -= freed_len; |
510 | c->unchecked_size -= ref_totlen(c, jeb, ref); | 523 | c->unchecked_size -= freed_len; |
511 | } else { | 524 | } else { |
512 | D1(if (unlikely(jeb->used_size < ref_totlen(c, jeb, ref))) { | 525 | D1(if (unlikely(jeb->used_size < freed_len)) { |
513 | printk(KERN_NOTICE "raw node of size 0x%08x freed from erase block %d at 0x%08x, but used_size was already 0x%08x\n", | 526 | printk(KERN_NOTICE "raw node of size 0x%08x freed from erase block %d at 0x%08x, but used_size was already 0x%08x\n", |
514 | ref_totlen(c, jeb, ref), blocknr, ref->flash_offset, jeb->used_size); | 527 | freed_len, blocknr, ref->flash_offset, jeb->used_size); |
515 | BUG(); | 528 | BUG(); |
516 | }) | 529 | }) |
517 | D1(printk(KERN_DEBUG "Obsoleting node at 0x%08x of len %#x: ", ref_offset(ref), ref_totlen(c, jeb, ref))); | 530 | D1(printk(KERN_DEBUG "Obsoleting node at 0x%08x of len %#x: ", ref_offset(ref), freed_len)); |
518 | jeb->used_size -= ref_totlen(c, jeb, ref); | 531 | jeb->used_size -= freed_len; |
519 | c->used_size -= ref_totlen(c, jeb, ref); | 532 | c->used_size -= freed_len; |
520 | } | 533 | } |
521 | 534 | ||
522 | // Take care, that wasted size is taken into concern | 535 | // Take care, that wasted size is taken into concern |
523 | if ((jeb->dirty_size || ISDIRTY(jeb->wasted_size + ref_totlen(c, jeb, ref))) && jeb != c->nextblock) { | 536 | if ((jeb->dirty_size || ISDIRTY(jeb->wasted_size + freed_len)) && jeb != c->nextblock) { |
524 | D1(printk(KERN_DEBUG "Dirtying\n")); | 537 | D1(printk("Dirtying\n")); |
525 | addedsize = ref_totlen(c, jeb, ref); | 538 | addedsize = freed_len; |
526 | jeb->dirty_size += ref_totlen(c, jeb, ref); | 539 | jeb->dirty_size += freed_len; |
527 | c->dirty_size += ref_totlen(c, jeb, ref); | 540 | c->dirty_size += freed_len; |
528 | 541 | ||
529 | /* Convert wasted space to dirty, if not a bad block */ | 542 | /* Convert wasted space to dirty, if not a bad block */ |
530 | if (jeb->wasted_size) { | 543 | if (jeb->wasted_size) { |
@@ -543,10 +556,10 @@ void jffs2_mark_node_obsolete(struct jffs2_sb_info *c, struct jffs2_raw_node_ref | |||
543 | } | 556 | } |
544 | } | 557 | } |
545 | } else { | 558 | } else { |
546 | D1(printk(KERN_DEBUG "Wasting\n")); | 559 | D1(printk("Wasting\n")); |
547 | addedsize = 0; | 560 | addedsize = 0; |
548 | jeb->wasted_size += ref_totlen(c, jeb, ref); | 561 | jeb->wasted_size += freed_len; |
549 | c->wasted_size += ref_totlen(c, jeb, ref); | 562 | c->wasted_size += freed_len; |
550 | } | 563 | } |
551 | ref->flash_offset = ref_offset(ref) | REF_OBSOLETE; | 564 | ref->flash_offset = ref_offset(ref) | REF_OBSOLETE; |
552 | 565 | ||
@@ -622,7 +635,7 @@ void jffs2_mark_node_obsolete(struct jffs2_sb_info *c, struct jffs2_raw_node_ref | |||
622 | /* The erase_free_sem is locked, and has been since before we marked the node obsolete | 635 | /* The erase_free_sem is locked, and has been since before we marked the node obsolete |
623 | and potentially put its eraseblock onto the erase_pending_list. Thus, we know that | 636 | and potentially put its eraseblock onto the erase_pending_list. Thus, we know that |
624 | the block hasn't _already_ been erased, and that 'ref' itself hasn't been freed yet | 637 | the block hasn't _already_ been erased, and that 'ref' itself hasn't been freed yet |
625 | by jffs2_free_all_node_refs() in erase.c. Which is nice. */ | 638 | by jffs2_free_jeb_node_refs() in erase.c. Which is nice. */ |
626 | 639 | ||
627 | D1(printk(KERN_DEBUG "obliterating obsoleted node at 0x%08x\n", ref_offset(ref))); | 640 | D1(printk(KERN_DEBUG "obliterating obsoleted node at 0x%08x\n", ref_offset(ref))); |
628 | ret = jffs2_flash_read(c, ref_offset(ref), sizeof(n), &retlen, (char *)&n); | 641 | ret = jffs2_flash_read(c, ref_offset(ref), sizeof(n), &retlen, (char *)&n); |
@@ -634,8 +647,8 @@ void jffs2_mark_node_obsolete(struct jffs2_sb_info *c, struct jffs2_raw_node_ref | |||
634 | printk(KERN_WARNING "Short read from obsoleted node at 0x%08x: %zd\n", ref_offset(ref), retlen); | 647 | printk(KERN_WARNING "Short read from obsoleted node at 0x%08x: %zd\n", ref_offset(ref), retlen); |
635 | goto out_erase_sem; | 648 | goto out_erase_sem; |
636 | } | 649 | } |
637 | if (PAD(je32_to_cpu(n.totlen)) != PAD(ref_totlen(c, jeb, ref))) { | 650 | if (PAD(je32_to_cpu(n.totlen)) != PAD(freed_len)) { |
638 | printk(KERN_WARNING "Node totlen on flash (0x%08x) != totlen from node ref (0x%08x)\n", je32_to_cpu(n.totlen), ref_totlen(c, jeb, ref)); | 651 | printk(KERN_WARNING "Node totlen on flash (0x%08x) != totlen from node ref (0x%08x)\n", je32_to_cpu(n.totlen), freed_len); |
639 | goto out_erase_sem; | 652 | goto out_erase_sem; |
640 | } | 653 | } |
641 | if (!(je16_to_cpu(n.nodetype) & JFFS2_NODE_ACCURATE)) { | 654 | if (!(je16_to_cpu(n.nodetype) & JFFS2_NODE_ACCURATE)) { |
@@ -671,6 +684,10 @@ void jffs2_mark_node_obsolete(struct jffs2_sb_info *c, struct jffs2_raw_node_ref | |||
671 | spin_lock(&c->erase_completion_lock); | 684 | spin_lock(&c->erase_completion_lock); |
672 | 685 | ||
673 | ic = jffs2_raw_ref_to_ic(ref); | 686 | ic = jffs2_raw_ref_to_ic(ref); |
687 | /* It seems we should never call jffs2_mark_node_obsolete() for | ||
688 | XATTR nodes.... yet. Make sure we notice if/when we change | ||
689 | that :) */ | ||
690 | BUG_ON(ic->class != RAWNODE_CLASS_INODE_CACHE); | ||
674 | for (p = &ic->nodes; (*p) != ref; p = &((*p)->next_in_ino)) | 691 | for (p = &ic->nodes; (*p) != ref; p = &((*p)->next_in_ino)) |
675 | ; | 692 | ; |
676 | 693 | ||
@@ -683,51 +700,6 @@ void jffs2_mark_node_obsolete(struct jffs2_sb_info *c, struct jffs2_raw_node_ref | |||
683 | spin_unlock(&c->erase_completion_lock); | 700 | spin_unlock(&c->erase_completion_lock); |
684 | } | 701 | } |
685 | 702 | ||
686 | |||
687 | /* Merge with the next node in the physical list, if there is one | ||
688 | and if it's also obsolete and if it doesn't belong to any inode */ | ||
689 | if (ref->next_phys && ref_obsolete(ref->next_phys) && | ||
690 | !ref->next_phys->next_in_ino) { | ||
691 | struct jffs2_raw_node_ref *n = ref->next_phys; | ||
692 | |||
693 | spin_lock(&c->erase_completion_lock); | ||
694 | |||
695 | ref->__totlen += n->__totlen; | ||
696 | ref->next_phys = n->next_phys; | ||
697 | if (jeb->last_node == n) jeb->last_node = ref; | ||
698 | if (jeb->gc_node == n) { | ||
699 | /* gc will be happy continuing gc on this node */ | ||
700 | jeb->gc_node=ref; | ||
701 | } | ||
702 | spin_unlock(&c->erase_completion_lock); | ||
703 | |||
704 | jffs2_free_raw_node_ref(n); | ||
705 | } | ||
706 | |||
707 | /* Also merge with the previous node in the list, if there is one | ||
708 | and that one is obsolete */ | ||
709 | if (ref != jeb->first_node ) { | ||
710 | struct jffs2_raw_node_ref *p = jeb->first_node; | ||
711 | |||
712 | spin_lock(&c->erase_completion_lock); | ||
713 | |||
714 | while (p->next_phys != ref) | ||
715 | p = p->next_phys; | ||
716 | |||
717 | if (ref_obsolete(p) && !ref->next_in_ino) { | ||
718 | p->__totlen += ref->__totlen; | ||
719 | if (jeb->last_node == ref) { | ||
720 | jeb->last_node = p; | ||
721 | } | ||
722 | if (jeb->gc_node == ref) { | ||
723 | /* gc will be happy continuing gc on this node */ | ||
724 | jeb->gc_node=p; | ||
725 | } | ||
726 | p->next_phys = ref->next_phys; | ||
727 | jffs2_free_raw_node_ref(ref); | ||
728 | } | ||
729 | spin_unlock(&c->erase_completion_lock); | ||
730 | } | ||
731 | out_erase_sem: | 703 | out_erase_sem: |
732 | up(&c->erase_free_sem); | 704 | up(&c->erase_free_sem); |
733 | } | 705 | } |