diff options
Diffstat (limited to 'fs/f2fs/extent_cache.c')
-rw-r--r-- | fs/f2fs/extent_cache.c | 176 |
1 files changed, 75 insertions, 101 deletions
diff --git a/fs/f2fs/extent_cache.c b/fs/f2fs/extent_cache.c index ccd5c636d3fe..c859bb044728 100644 --- a/fs/f2fs/extent_cache.c +++ b/fs/f2fs/extent_cache.c | |||
@@ -33,6 +33,7 @@ static struct extent_node *__attach_extent_node(struct f2fs_sb_info *sbi, | |||
33 | 33 | ||
34 | en->ei = *ei; | 34 | en->ei = *ei; |
35 | INIT_LIST_HEAD(&en->list); | 35 | INIT_LIST_HEAD(&en->list); |
36 | en->et = et; | ||
36 | 37 | ||
37 | rb_link_node(&en->rb_node, parent, p); | 38 | rb_link_node(&en->rb_node, parent, p); |
38 | rb_insert_color(&en->rb_node, &et->root); | 39 | rb_insert_color(&en->rb_node, &et->root); |
@@ -50,6 +51,24 @@ static void __detach_extent_node(struct f2fs_sb_info *sbi, | |||
50 | 51 | ||
51 | if (et->cached_en == en) | 52 | if (et->cached_en == en) |
52 | et->cached_en = NULL; | 53 | et->cached_en = NULL; |
54 | kmem_cache_free(extent_node_slab, en); | ||
55 | } | ||
56 | |||
57 | /* | ||
58 | * Flow to release an extent_node: | ||
59 | * 1. list_del_init | ||
60 | * 2. __detach_extent_node | ||
61 | * 3. kmem_cache_free. | ||
62 | */ | ||
63 | static void __release_extent_node(struct f2fs_sb_info *sbi, | ||
64 | struct extent_tree *et, struct extent_node *en) | ||
65 | { | ||
66 | spin_lock(&sbi->extent_lock); | ||
67 | f2fs_bug_on(sbi, list_empty(&en->list)); | ||
68 | list_del_init(&en->list); | ||
69 | spin_unlock(&sbi->extent_lock); | ||
70 | |||
71 | __detach_extent_node(sbi, et, en); | ||
53 | } | 72 | } |
54 | 73 | ||
55 | static struct extent_tree *__grab_extent_tree(struct inode *inode) | 74 | static struct extent_tree *__grab_extent_tree(struct inode *inode) |
@@ -129,7 +148,7 @@ static struct extent_node *__init_extent_tree(struct f2fs_sb_info *sbi, | |||
129 | } | 148 | } |
130 | 149 | ||
131 | static unsigned int __free_extent_tree(struct f2fs_sb_info *sbi, | 150 | static unsigned int __free_extent_tree(struct f2fs_sb_info *sbi, |
132 | struct extent_tree *et, bool free_all) | 151 | struct extent_tree *et) |
133 | { | 152 | { |
134 | struct rb_node *node, *next; | 153 | struct rb_node *node, *next; |
135 | struct extent_node *en; | 154 | struct extent_node *en; |
@@ -139,18 +158,7 @@ static unsigned int __free_extent_tree(struct f2fs_sb_info *sbi, | |||
139 | while (node) { | 158 | while (node) { |
140 | next = rb_next(node); | 159 | next = rb_next(node); |
141 | en = rb_entry(node, struct extent_node, rb_node); | 160 | en = rb_entry(node, struct extent_node, rb_node); |
142 | 161 | __release_extent_node(sbi, et, en); | |
143 | if (free_all) { | ||
144 | spin_lock(&sbi->extent_lock); | ||
145 | if (!list_empty(&en->list)) | ||
146 | list_del_init(&en->list); | ||
147 | spin_unlock(&sbi->extent_lock); | ||
148 | } | ||
149 | |||
150 | if (free_all || list_empty(&en->list)) { | ||
151 | __detach_extent_node(sbi, et, en); | ||
152 | kmem_cache_free(extent_node_slab, en); | ||
153 | } | ||
154 | node = next; | 162 | node = next; |
155 | } | 163 | } |
156 | 164 | ||
@@ -232,9 +240,10 @@ static bool f2fs_lookup_extent_tree(struct inode *inode, pgoff_t pgofs, | |||
232 | if (en) { | 240 | if (en) { |
233 | *ei = en->ei; | 241 | *ei = en->ei; |
234 | spin_lock(&sbi->extent_lock); | 242 | spin_lock(&sbi->extent_lock); |
235 | if (!list_empty(&en->list)) | 243 | if (!list_empty(&en->list)) { |
236 | list_move_tail(&en->list, &sbi->extent_list); | 244 | list_move_tail(&en->list, &sbi->extent_list); |
237 | et->cached_en = en; | 245 | et->cached_en = en; |
246 | } | ||
238 | spin_unlock(&sbi->extent_lock); | 247 | spin_unlock(&sbi->extent_lock); |
239 | ret = true; | 248 | ret = true; |
240 | } | 249 | } |
@@ -329,7 +338,6 @@ lookup_neighbors: | |||
329 | 338 | ||
330 | static struct extent_node *__try_merge_extent_node(struct f2fs_sb_info *sbi, | 339 | static struct extent_node *__try_merge_extent_node(struct f2fs_sb_info *sbi, |
331 | struct extent_tree *et, struct extent_info *ei, | 340 | struct extent_tree *et, struct extent_info *ei, |
332 | struct extent_node **den, | ||
333 | struct extent_node *prev_ex, | 341 | struct extent_node *prev_ex, |
334 | struct extent_node *next_ex) | 342 | struct extent_node *next_ex) |
335 | { | 343 | { |
@@ -342,20 +350,25 @@ static struct extent_node *__try_merge_extent_node(struct f2fs_sb_info *sbi, | |||
342 | } | 350 | } |
343 | 351 | ||
344 | if (next_ex && __is_front_mergeable(ei, &next_ex->ei)) { | 352 | if (next_ex && __is_front_mergeable(ei, &next_ex->ei)) { |
345 | if (en) { | 353 | if (en) |
346 | __detach_extent_node(sbi, et, prev_ex); | 354 | __release_extent_node(sbi, et, prev_ex); |
347 | *den = prev_ex; | ||
348 | } | ||
349 | next_ex->ei.fofs = ei->fofs; | 355 | next_ex->ei.fofs = ei->fofs; |
350 | next_ex->ei.blk = ei->blk; | 356 | next_ex->ei.blk = ei->blk; |
351 | next_ex->ei.len += ei->len; | 357 | next_ex->ei.len += ei->len; |
352 | en = next_ex; | 358 | en = next_ex; |
353 | } | 359 | } |
354 | 360 | ||
355 | if (en) { | 361 | if (!en) |
356 | __try_update_largest_extent(et, en); | 362 | return NULL; |
363 | |||
364 | __try_update_largest_extent(et, en); | ||
365 | |||
366 | spin_lock(&sbi->extent_lock); | ||
367 | if (!list_empty(&en->list)) { | ||
368 | list_move_tail(&en->list, &sbi->extent_list); | ||
357 | et->cached_en = en; | 369 | et->cached_en = en; |
358 | } | 370 | } |
371 | spin_unlock(&sbi->extent_lock); | ||
359 | return en; | 372 | return en; |
360 | } | 373 | } |
361 | 374 | ||
@@ -391,7 +404,12 @@ do_insert: | |||
391 | return NULL; | 404 | return NULL; |
392 | 405 | ||
393 | __try_update_largest_extent(et, en); | 406 | __try_update_largest_extent(et, en); |
407 | |||
408 | /* update in global extent list */ | ||
409 | spin_lock(&sbi->extent_lock); | ||
410 | list_add_tail(&en->list, &sbi->extent_list); | ||
394 | et->cached_en = en; | 411 | et->cached_en = en; |
412 | spin_unlock(&sbi->extent_lock); | ||
395 | return en; | 413 | return en; |
396 | } | 414 | } |
397 | 415 | ||
@@ -479,7 +497,7 @@ static unsigned int f2fs_update_extent_tree_range(struct inode *inode, | |||
479 | if (parts) | 497 | if (parts) |
480 | __try_update_largest_extent(et, en); | 498 | __try_update_largest_extent(et, en); |
481 | else | 499 | else |
482 | __detach_extent_node(sbi, et, en); | 500 | __release_extent_node(sbi, et, en); |
483 | 501 | ||
484 | /* | 502 | /* |
485 | * if original extent is split into zero or two parts, extent | 503 | * if original extent is split into zero or two parts, extent |
@@ -490,31 +508,15 @@ static unsigned int f2fs_update_extent_tree_range(struct inode *inode, | |||
490 | insert_p = NULL; | 508 | insert_p = NULL; |
491 | insert_parent = NULL; | 509 | insert_parent = NULL; |
492 | } | 510 | } |
493 | |||
494 | /* update in global extent list */ | ||
495 | spin_lock(&sbi->extent_lock); | ||
496 | if (!parts && !list_empty(&en->list)) | ||
497 | list_del(&en->list); | ||
498 | if (en1) | ||
499 | list_add_tail(&en1->list, &sbi->extent_list); | ||
500 | spin_unlock(&sbi->extent_lock); | ||
501 | |||
502 | /* release extent node */ | ||
503 | if (!parts) | ||
504 | kmem_cache_free(extent_node_slab, en); | ||
505 | |||
506 | en = next_en; | 511 | en = next_en; |
507 | } | 512 | } |
508 | 513 | ||
509 | /* 3. update extent in extent cache */ | 514 | /* 3. update extent in extent cache */ |
510 | if (blkaddr) { | 515 | if (blkaddr) { |
511 | struct extent_node *den = NULL; | ||
512 | 516 | ||
513 | set_extent_info(&ei, fofs, blkaddr, len); | 517 | set_extent_info(&ei, fofs, blkaddr, len); |
514 | en1 = __try_merge_extent_node(sbi, et, &ei, &den, | 518 | if (!__try_merge_extent_node(sbi, et, &ei, prev_en, next_en)) |
515 | prev_en, next_en); | 519 | __insert_extent_tree(sbi, et, &ei, |
516 | if (!en1) | ||
517 | en1 = __insert_extent_tree(sbi, et, &ei, | ||
518 | insert_p, insert_parent); | 520 | insert_p, insert_parent); |
519 | 521 | ||
520 | /* give up extent_cache, if split and small updates happen */ | 522 | /* give up extent_cache, if split and small updates happen */ |
@@ -524,24 +526,10 @@ static unsigned int f2fs_update_extent_tree_range(struct inode *inode, | |||
524 | et->largest.len = 0; | 526 | et->largest.len = 0; |
525 | set_inode_flag(F2FS_I(inode), FI_NO_EXTENT); | 527 | set_inode_flag(F2FS_I(inode), FI_NO_EXTENT); |
526 | } | 528 | } |
527 | |||
528 | spin_lock(&sbi->extent_lock); | ||
529 | if (en1) { | ||
530 | if (list_empty(&en1->list)) | ||
531 | list_add_tail(&en1->list, &sbi->extent_list); | ||
532 | else | ||
533 | list_move_tail(&en1->list, &sbi->extent_list); | ||
534 | } | ||
535 | if (den && !list_empty(&den->list)) | ||
536 | list_del(&den->list); | ||
537 | spin_unlock(&sbi->extent_lock); | ||
538 | |||
539 | if (den) | ||
540 | kmem_cache_free(extent_node_slab, den); | ||
541 | } | 529 | } |
542 | 530 | ||
543 | if (is_inode_flag_set(F2FS_I(inode), FI_NO_EXTENT)) | 531 | if (is_inode_flag_set(F2FS_I(inode), FI_NO_EXTENT)) |
544 | __free_extent_tree(sbi, et, true); | 532 | __free_extent_tree(sbi, et); |
545 | 533 | ||
546 | write_unlock(&et->lock); | 534 | write_unlock(&et->lock); |
547 | 535 | ||
@@ -550,14 +538,10 @@ static unsigned int f2fs_update_extent_tree_range(struct inode *inode, | |||
550 | 538 | ||
551 | unsigned int f2fs_shrink_extent_tree(struct f2fs_sb_info *sbi, int nr_shrink) | 539 | unsigned int f2fs_shrink_extent_tree(struct f2fs_sb_info *sbi, int nr_shrink) |
552 | { | 540 | { |
553 | struct extent_tree *treevec[EXT_TREE_VEC_SIZE]; | ||
554 | struct extent_tree *et, *next; | 541 | struct extent_tree *et, *next; |
555 | struct extent_node *en, *tmp; | 542 | struct extent_node *en; |
556 | unsigned long ino = F2FS_ROOT_INO(sbi); | ||
557 | unsigned int found; | ||
558 | unsigned int node_cnt = 0, tree_cnt = 0; | 543 | unsigned int node_cnt = 0, tree_cnt = 0; |
559 | int remained; | 544 | int remained; |
560 | bool do_free = false; | ||
561 | 545 | ||
562 | if (!test_opt(sbi, EXTENT_CACHE)) | 546 | if (!test_opt(sbi, EXTENT_CACHE)) |
563 | return 0; | 547 | return 0; |
@@ -572,10 +556,10 @@ unsigned int f2fs_shrink_extent_tree(struct f2fs_sb_info *sbi, int nr_shrink) | |||
572 | list_for_each_entry_safe(et, next, &sbi->zombie_list, list) { | 556 | list_for_each_entry_safe(et, next, &sbi->zombie_list, list) { |
573 | if (atomic_read(&et->node_cnt)) { | 557 | if (atomic_read(&et->node_cnt)) { |
574 | write_lock(&et->lock); | 558 | write_lock(&et->lock); |
575 | node_cnt += __free_extent_tree(sbi, et, true); | 559 | node_cnt += __free_extent_tree(sbi, et); |
576 | write_unlock(&et->lock); | 560 | write_unlock(&et->lock); |
577 | } | 561 | } |
578 | 562 | f2fs_bug_on(sbi, atomic_read(&et->node_cnt)); | |
579 | list_del_init(&et->list); | 563 | list_del_init(&et->list); |
580 | radix_tree_delete(&sbi->extent_tree_root, et->ino); | 564 | radix_tree_delete(&sbi->extent_tree_root, et->ino); |
581 | kmem_cache_free(extent_tree_slab, et); | 565 | kmem_cache_free(extent_tree_slab, et); |
@@ -585,6 +569,7 @@ unsigned int f2fs_shrink_extent_tree(struct f2fs_sb_info *sbi, int nr_shrink) | |||
585 | 569 | ||
586 | if (node_cnt + tree_cnt >= nr_shrink) | 570 | if (node_cnt + tree_cnt >= nr_shrink) |
587 | goto unlock_out; | 571 | goto unlock_out; |
572 | cond_resched(); | ||
588 | } | 573 | } |
589 | up_write(&sbi->extent_tree_lock); | 574 | up_write(&sbi->extent_tree_lock); |
590 | 575 | ||
@@ -596,42 +581,29 @@ free_node: | |||
596 | remained = nr_shrink - (node_cnt + tree_cnt); | 581 | remained = nr_shrink - (node_cnt + tree_cnt); |
597 | 582 | ||
598 | spin_lock(&sbi->extent_lock); | 583 | spin_lock(&sbi->extent_lock); |
599 | list_for_each_entry_safe(en, tmp, &sbi->extent_list, list) { | 584 | for (; remained > 0; remained--) { |
600 | if (!remained--) | 585 | if (list_empty(&sbi->extent_list)) |
601 | break; | 586 | break; |
602 | list_del_init(&en->list); | 587 | en = list_first_entry(&sbi->extent_list, |
603 | do_free = true; | 588 | struct extent_node, list); |
604 | } | 589 | et = en->et; |
605 | spin_unlock(&sbi->extent_lock); | 590 | if (!write_trylock(&et->lock)) { |
606 | 591 | /* refresh this extent node's position in extent list */ | |
607 | if (do_free == false) | 592 | list_move_tail(&en->list, &sbi->extent_list); |
608 | goto unlock_out; | 593 | continue; |
609 | 594 | } | |
610 | /* | ||
611 | * reset ino for searching victims from beginning of global extent tree. | ||
612 | */ | ||
613 | ino = F2FS_ROOT_INO(sbi); | ||
614 | |||
615 | while ((found = radix_tree_gang_lookup(&sbi->extent_tree_root, | ||
616 | (void **)treevec, ino, EXT_TREE_VEC_SIZE))) { | ||
617 | unsigned i; | ||
618 | |||
619 | ino = treevec[found - 1]->ino + 1; | ||
620 | for (i = 0; i < found; i++) { | ||
621 | struct extent_tree *et = treevec[i]; | ||
622 | 595 | ||
623 | if (!atomic_read(&et->node_cnt)) | 596 | list_del_init(&en->list); |
624 | continue; | 597 | spin_unlock(&sbi->extent_lock); |
625 | 598 | ||
626 | if (write_trylock(&et->lock)) { | 599 | __detach_extent_node(sbi, et, en); |
627 | node_cnt += __free_extent_tree(sbi, et, false); | ||
628 | write_unlock(&et->lock); | ||
629 | } | ||
630 | 600 | ||
631 | if (node_cnt + tree_cnt >= nr_shrink) | 601 | write_unlock(&et->lock); |
632 | goto unlock_out; | 602 | node_cnt++; |
633 | } | 603 | spin_lock(&sbi->extent_lock); |
634 | } | 604 | } |
605 | spin_unlock(&sbi->extent_lock); | ||
606 | |||
635 | unlock_out: | 607 | unlock_out: |
636 | up_write(&sbi->extent_tree_lock); | 608 | up_write(&sbi->extent_tree_lock); |
637 | out: | 609 | out: |
@@ -650,7 +622,7 @@ unsigned int f2fs_destroy_extent_node(struct inode *inode) | |||
650 | return 0; | 622 | return 0; |
651 | 623 | ||
652 | write_lock(&et->lock); | 624 | write_lock(&et->lock); |
653 | node_cnt = __free_extent_tree(sbi, et, true); | 625 | node_cnt = __free_extent_tree(sbi, et); |
654 | write_unlock(&et->lock); | 626 | write_unlock(&et->lock); |
655 | 627 | ||
656 | return node_cnt; | 628 | return node_cnt; |
@@ -701,19 +673,21 @@ bool f2fs_lookup_extent_cache(struct inode *inode, pgoff_t pgofs, | |||
701 | 673 | ||
702 | void f2fs_update_extent_cache(struct dnode_of_data *dn) | 674 | void f2fs_update_extent_cache(struct dnode_of_data *dn) |
703 | { | 675 | { |
704 | struct f2fs_inode_info *fi = F2FS_I(dn->inode); | ||
705 | pgoff_t fofs; | 676 | pgoff_t fofs; |
677 | block_t blkaddr; | ||
706 | 678 | ||
707 | if (!f2fs_may_extent_tree(dn->inode)) | 679 | if (!f2fs_may_extent_tree(dn->inode)) |
708 | return; | 680 | return; |
709 | 681 | ||
710 | f2fs_bug_on(F2FS_I_SB(dn->inode), dn->data_blkaddr == NEW_ADDR); | 682 | if (dn->data_blkaddr == NEW_ADDR) |
711 | 683 | blkaddr = NULL_ADDR; | |
684 | else | ||
685 | blkaddr = dn->data_blkaddr; | ||
712 | 686 | ||
713 | fofs = start_bidx_of_node(ofs_of_node(dn->node_page), fi) + | 687 | fofs = start_bidx_of_node(ofs_of_node(dn->node_page), dn->inode) + |
714 | dn->ofs_in_node; | 688 | dn->ofs_in_node; |
715 | 689 | ||
716 | if (f2fs_update_extent_tree_range(dn->inode, fofs, dn->data_blkaddr, 1)) | 690 | if (f2fs_update_extent_tree_range(dn->inode, fofs, blkaddr, 1)) |
717 | sync_inode_page(dn); | 691 | sync_inode_page(dn); |
718 | } | 692 | } |
719 | 693 | ||