diff options
| author | Ryusuke Konishi <konishi.ryusuke@lab.ntt.co.jp> | 2010-09-05 23:05:43 -0400 |
|---|---|---|
| committer | Ryusuke Konishi <konishi.ryusuke@lab.ntt.co.jp> | 2010-10-22 20:24:37 -0400 |
| commit | ebdfed4dc59d177cf26013a0c9b8ee9652e9a140 (patch) | |
| tree | 6ef90f068ae41c55234181c93d8e30a303126c43 | |
| parent | a8070dd365dd995f6139a2fc3aeee10159bdcc45 (diff) | |
nilfs2: add routines to roll back state of DAT file
This adds optional function to metadata files which makes a copy of
bmap, page caches, and b-tree node cache, and rolls back to the copy
as needed.
This enhancement is intended to displace gcdat inode that provides a
similar function in a different way.
In this patch, nilfs_shadow_map structure is added to store a copy of
the foregoing states. nilfs_mdt_setup_shadow_map relates this
structure to a metadata file. And, nilfs_mdt_save_to_shadow_map() and
nilfs_mdt_restore_from_shadow_map() provides save and restore
functions respectively. Finally, nilfs_mdt_clear_shadow_map() clears
states of nilfs_shadow_map.
The copy of b-tree node cache and page cache is made by duplicating
only dirty pages into corresponding caches in nilfs_shadow_map. Their
restoration is done by clearing dirty pages from original caches and
by copying dirty pages back from nilfs_shadow_map.
Signed-off-by: Ryusuke Konishi <konishi.ryusuke@lab.ntt.co.jp>
| -rw-r--r-- | fs/nilfs2/btnode.c | 17 | ||||
| -rw-r--r-- | fs/nilfs2/mdt.c | 104 | ||||
| -rw-r--r-- | fs/nilfs2/mdt.h | 14 | ||||
| -rw-r--r-- | fs/nilfs2/page.c | 25 | ||||
| -rw-r--r-- | fs/nilfs2/page.h | 4 |
5 files changed, 145 insertions, 19 deletions
diff --git a/fs/nilfs2/btnode.c b/fs/nilfs2/btnode.c index f78ab1044d1d..5115814cb745 100644 --- a/fs/nilfs2/btnode.c +++ b/fs/nilfs2/btnode.c | |||
| @@ -37,15 +37,7 @@ | |||
| 37 | 37 | ||
| 38 | void nilfs_btnode_cache_init_once(struct address_space *btnc) | 38 | void nilfs_btnode_cache_init_once(struct address_space *btnc) |
| 39 | { | 39 | { |
| 40 | memset(btnc, 0, sizeof(*btnc)); | 40 | nilfs_mapping_init_once(btnc); |
| 41 | INIT_RADIX_TREE(&btnc->page_tree, GFP_ATOMIC); | ||
| 42 | spin_lock_init(&btnc->tree_lock); | ||
| 43 | INIT_LIST_HEAD(&btnc->private_list); | ||
| 44 | spin_lock_init(&btnc->private_lock); | ||
| 45 | |||
| 46 | spin_lock_init(&btnc->i_mmap_lock); | ||
| 47 | INIT_RAW_PRIO_TREE_ROOT(&btnc->i_mmap); | ||
| 48 | INIT_LIST_HEAD(&btnc->i_mmap_nonlinear); | ||
| 49 | } | 41 | } |
| 50 | 42 | ||
| 51 | static const struct address_space_operations def_btnode_aops = { | 43 | static const struct address_space_operations def_btnode_aops = { |
| @@ -55,12 +47,7 @@ static const struct address_space_operations def_btnode_aops = { | |||
| 55 | void nilfs_btnode_cache_init(struct address_space *btnc, | 47 | void nilfs_btnode_cache_init(struct address_space *btnc, |
| 56 | struct backing_dev_info *bdi) | 48 | struct backing_dev_info *bdi) |
| 57 | { | 49 | { |
| 58 | btnc->host = NULL; /* can safely set to host inode ? */ | 50 | nilfs_mapping_init(btnc, bdi, &def_btnode_aops); |
| 59 | btnc->flags = 0; | ||
| 60 | mapping_set_gfp_mask(btnc, GFP_NOFS); | ||
| 61 | btnc->assoc_mapping = NULL; | ||
| 62 | btnc->backing_dev_info = bdi; | ||
| 63 | btnc->a_ops = &def_btnode_aops; | ||
| 64 | } | 51 | } |
| 65 | 52 | ||
| 66 | void nilfs_btnode_cache_clear(struct address_space *btnc) | 53 | void nilfs_btnode_cache_clear(struct address_space *btnc) |
diff --git a/fs/nilfs2/mdt.c b/fs/nilfs2/mdt.c index 73e5da3b097e..0066468609da 100644 --- a/fs/nilfs2/mdt.c +++ b/fs/nilfs2/mdt.c | |||
| @@ -398,16 +398,22 @@ int nilfs_mdt_fetch_dirty(struct inode *inode) | |||
| 398 | static int | 398 | static int |
| 399 | nilfs_mdt_write_page(struct page *page, struct writeback_control *wbc) | 399 | nilfs_mdt_write_page(struct page *page, struct writeback_control *wbc) |
| 400 | { | 400 | { |
| 401 | struct inode *inode = container_of(page->mapping, | 401 | struct inode *inode; |
| 402 | struct inode, i_data); | 402 | struct super_block *sb; |
| 403 | struct super_block *sb = inode->i_sb; | 403 | struct the_nilfs *nilfs; |
| 404 | struct the_nilfs *nilfs = NILFS_MDT(inode)->mi_nilfs; | ||
| 405 | struct nilfs_sb_info *writer = NULL; | 404 | struct nilfs_sb_info *writer = NULL; |
| 406 | int err = 0; | 405 | int err = 0; |
| 407 | 406 | ||
| 408 | redirty_page_for_writepage(wbc, page); | 407 | redirty_page_for_writepage(wbc, page); |
| 409 | unlock_page(page); | 408 | unlock_page(page); |
| 410 | 409 | ||
| 410 | inode = page->mapping->host; | ||
| 411 | if (!inode) | ||
| 412 | return 0; | ||
| 413 | |||
| 414 | sb = inode->i_sb; | ||
| 415 | nilfs = NILFS_MDT(inode)->mi_nilfs; | ||
| 416 | |||
| 411 | if (page->mapping->assoc_mapping) | 417 | if (page->mapping->assoc_mapping) |
| 412 | return 0; /* Do not request flush for shadow page cache */ | 418 | return 0; /* Do not request flush for shadow page cache */ |
| 413 | if (!sb) { | 419 | if (!sb) { |
| @@ -567,6 +573,96 @@ void nilfs_mdt_set_shadow(struct inode *orig, struct inode *shadow) | |||
| 567 | &NILFS_I(orig)->i_btnode_cache; | 573 | &NILFS_I(orig)->i_btnode_cache; |
| 568 | } | 574 | } |
| 569 | 575 | ||
| 576 | static const struct address_space_operations shadow_map_aops = { | ||
| 577 | .sync_page = block_sync_page, | ||
| 578 | }; | ||
| 579 | |||
| 580 | /** | ||
| 581 | * nilfs_mdt_setup_shadow_map - setup shadow map and bind it to metadata file | ||
| 582 | * @inode: inode of the metadata file | ||
| 583 | * @shadow: shadow mapping | ||
| 584 | */ | ||
| 585 | int nilfs_mdt_setup_shadow_map(struct inode *inode, | ||
| 586 | struct nilfs_shadow_map *shadow) | ||
| 587 | { | ||
| 588 | struct nilfs_mdt_info *mi = NILFS_MDT(inode); | ||
| 589 | struct backing_dev_info *bdi = NILFS_I_NILFS(inode)->ns_bdi; | ||
| 590 | |||
| 591 | INIT_LIST_HEAD(&shadow->frozen_buffers); | ||
| 592 | nilfs_mapping_init_once(&shadow->frozen_data); | ||
| 593 | nilfs_mapping_init(&shadow->frozen_data, bdi, &shadow_map_aops); | ||
| 594 | nilfs_mapping_init_once(&shadow->frozen_btnodes); | ||
| 595 | nilfs_mapping_init(&shadow->frozen_btnodes, bdi, &shadow_map_aops); | ||
| 596 | mi->mi_shadow = shadow; | ||
| 597 | return 0; | ||
| 598 | } | ||
| 599 | |||
| 600 | /** | ||
| 601 | * nilfs_mdt_save_to_shadow_map - copy bmap and dirty pages to shadow map | ||
| 602 | * @inode: inode of the metadata file | ||
| 603 | */ | ||
| 604 | int nilfs_mdt_save_to_shadow_map(struct inode *inode) | ||
| 605 | { | ||
| 606 | struct nilfs_mdt_info *mi = NILFS_MDT(inode); | ||
| 607 | struct nilfs_inode_info *ii = NILFS_I(inode); | ||
| 608 | struct nilfs_shadow_map *shadow = mi->mi_shadow; | ||
| 609 | int ret; | ||
| 610 | |||
| 611 | ret = nilfs_copy_dirty_pages(&shadow->frozen_data, inode->i_mapping); | ||
| 612 | if (ret) | ||
| 613 | goto out; | ||
| 614 | |||
| 615 | ret = nilfs_copy_dirty_pages(&shadow->frozen_btnodes, | ||
| 616 | &ii->i_btnode_cache); | ||
| 617 | if (ret) | ||
| 618 | goto out; | ||
| 619 | |||
| 620 | nilfs_bmap_save(ii->i_bmap, &shadow->bmap_store); | ||
| 621 | out: | ||
| 622 | return ret; | ||
| 623 | } | ||
| 624 | |||
| 625 | /** | ||
| 626 | * nilfs_mdt_restore_from_shadow_map - restore dirty pages and bmap state | ||
| 627 | * @inode: inode of the metadata file | ||
| 628 | */ | ||
| 629 | void nilfs_mdt_restore_from_shadow_map(struct inode *inode) | ||
| 630 | { | ||
| 631 | struct nilfs_mdt_info *mi = NILFS_MDT(inode); | ||
| 632 | struct nilfs_inode_info *ii = NILFS_I(inode); | ||
| 633 | struct nilfs_shadow_map *shadow = mi->mi_shadow; | ||
| 634 | |||
| 635 | down_write(&mi->mi_sem); | ||
| 636 | |||
| 637 | if (mi->mi_palloc_cache) | ||
| 638 | nilfs_palloc_clear_cache(inode); | ||
| 639 | |||
| 640 | nilfs_clear_dirty_pages(inode->i_mapping); | ||
| 641 | nilfs_copy_back_pages(inode->i_mapping, &shadow->frozen_data); | ||
| 642 | |||
| 643 | nilfs_clear_dirty_pages(&ii->i_btnode_cache); | ||
| 644 | nilfs_copy_back_pages(&ii->i_btnode_cache, &shadow->frozen_btnodes); | ||
| 645 | |||
| 646 | nilfs_bmap_restore(ii->i_bmap, &shadow->bmap_store); | ||
| 647 | |||
| 648 | up_write(&mi->mi_sem); | ||
| 649 | } | ||
| 650 | |||
| 651 | /** | ||
| 652 | * nilfs_mdt_clear_shadow_map - truncate pages in shadow map caches | ||
| 653 | * @inode: inode of the metadata file | ||
| 654 | */ | ||
| 655 | void nilfs_mdt_clear_shadow_map(struct inode *inode) | ||
| 656 | { | ||
| 657 | struct nilfs_mdt_info *mi = NILFS_MDT(inode); | ||
| 658 | struct nilfs_shadow_map *shadow = mi->mi_shadow; | ||
| 659 | |||
| 660 | down_write(&mi->mi_sem); | ||
| 661 | truncate_inode_pages(&shadow->frozen_data, 0); | ||
| 662 | truncate_inode_pages(&shadow->frozen_btnodes, 0); | ||
| 663 | up_write(&mi->mi_sem); | ||
| 664 | } | ||
| 665 | |||
| 570 | static void nilfs_mdt_clear(struct inode *inode) | 666 | static void nilfs_mdt_clear(struct inode *inode) |
| 571 | { | 667 | { |
| 572 | struct nilfs_inode_info *ii = NILFS_I(inode); | 668 | struct nilfs_inode_info *ii = NILFS_I(inode); |
diff --git a/fs/nilfs2/mdt.h b/fs/nilfs2/mdt.h index f44560224bd1..e7f0d158c527 100644 --- a/fs/nilfs2/mdt.h +++ b/fs/nilfs2/mdt.h | |||
| @@ -28,6 +28,13 @@ | |||
| 28 | #include "nilfs.h" | 28 | #include "nilfs.h" |
| 29 | #include "page.h" | 29 | #include "page.h" |
| 30 | 30 | ||
| 31 | struct nilfs_shadow_map { | ||
| 32 | struct nilfs_bmap_store bmap_store; | ||
| 33 | struct address_space frozen_data; | ||
| 34 | struct address_space frozen_btnodes; | ||
| 35 | struct list_head frozen_buffers; | ||
| 36 | }; | ||
| 37 | |||
| 31 | /** | 38 | /** |
| 32 | * struct nilfs_mdt_info - on-memory private data of meta data files | 39 | * struct nilfs_mdt_info - on-memory private data of meta data files |
| 33 | * @mi_nilfs: back pointer to the_nilfs struct | 40 | * @mi_nilfs: back pointer to the_nilfs struct |
| @@ -37,6 +44,7 @@ | |||
| 37 | * @mi_first_entry_offset: offset to the first entry | 44 | * @mi_first_entry_offset: offset to the first entry |
| 38 | * @mi_entries_per_block: number of entries in a block | 45 | * @mi_entries_per_block: number of entries in a block |
| 39 | * @mi_palloc_cache: persistent object allocator cache | 46 | * @mi_palloc_cache: persistent object allocator cache |
| 47 | * @mi_shadow: shadow of bmap and page caches | ||
| 40 | * @mi_blocks_per_group: number of blocks in a group | 48 | * @mi_blocks_per_group: number of blocks in a group |
| 41 | * @mi_blocks_per_desc_block: number of blocks per descriptor block | 49 | * @mi_blocks_per_desc_block: number of blocks per descriptor block |
| 42 | */ | 50 | */ |
| @@ -48,6 +56,7 @@ struct nilfs_mdt_info { | |||
| 48 | unsigned mi_first_entry_offset; | 56 | unsigned mi_first_entry_offset; |
| 49 | unsigned long mi_entries_per_block; | 57 | unsigned long mi_entries_per_block; |
| 50 | struct nilfs_palloc_cache *mi_palloc_cache; | 58 | struct nilfs_palloc_cache *mi_palloc_cache; |
| 59 | struct nilfs_shadow_map *mi_shadow; | ||
| 51 | unsigned long mi_blocks_per_group; | 60 | unsigned long mi_blocks_per_group; |
| 52 | unsigned long mi_blocks_per_desc_block; | 61 | unsigned long mi_blocks_per_desc_block; |
| 53 | }; | 62 | }; |
| @@ -86,6 +95,11 @@ void nilfs_mdt_destroy(struct inode *); | |||
| 86 | void nilfs_mdt_set_entry_size(struct inode *, unsigned, unsigned); | 95 | void nilfs_mdt_set_entry_size(struct inode *, unsigned, unsigned); |
| 87 | void nilfs_mdt_set_shadow(struct inode *, struct inode *); | 96 | void nilfs_mdt_set_shadow(struct inode *, struct inode *); |
| 88 | 97 | ||
| 98 | int nilfs_mdt_setup_shadow_map(struct inode *inode, | ||
| 99 | struct nilfs_shadow_map *shadow); | ||
| 100 | int nilfs_mdt_save_to_shadow_map(struct inode *inode); | ||
| 101 | void nilfs_mdt_restore_from_shadow_map(struct inode *inode); | ||
| 102 | void nilfs_mdt_clear_shadow_map(struct inode *inode); | ||
| 89 | 103 | ||
| 90 | #define nilfs_mdt_mark_buffer_dirty(bh) nilfs_mark_buffer_dirty(bh) | 104 | #define nilfs_mdt_mark_buffer_dirty(bh) nilfs_mark_buffer_dirty(bh) |
| 91 | 105 | ||
diff --git a/fs/nilfs2/page.c b/fs/nilfs2/page.c index aab11db2cb08..6384ac14c0c8 100644 --- a/fs/nilfs2/page.c +++ b/fs/nilfs2/page.c | |||
| @@ -513,6 +513,31 @@ unsigned nilfs_page_count_clean_buffers(struct page *page, | |||
| 513 | } | 513 | } |
| 514 | return nc; | 514 | return nc; |
| 515 | } | 515 | } |
| 516 | |||
| 517 | void nilfs_mapping_init_once(struct address_space *mapping) | ||
| 518 | { | ||
| 519 | memset(mapping, 0, sizeof(*mapping)); | ||
| 520 | INIT_RADIX_TREE(&mapping->page_tree, GFP_ATOMIC); | ||
| 521 | spin_lock_init(&mapping->tree_lock); | ||
| 522 | INIT_LIST_HEAD(&mapping->private_list); | ||
| 523 | spin_lock_init(&mapping->private_lock); | ||
| 524 | |||
| 525 | spin_lock_init(&mapping->i_mmap_lock); | ||
| 526 | INIT_RAW_PRIO_TREE_ROOT(&mapping->i_mmap); | ||
| 527 | INIT_LIST_HEAD(&mapping->i_mmap_nonlinear); | ||
| 528 | } | ||
| 529 | |||
| 530 | void nilfs_mapping_init(struct address_space *mapping, | ||
| 531 | struct backing_dev_info *bdi, | ||
| 532 | const struct address_space_operations *aops) | ||
| 533 | { | ||
| 534 | mapping->host = NULL; | ||
| 535 | mapping->flags = 0; | ||
| 536 | mapping_set_gfp_mask(mapping, GFP_NOFS); | ||
| 537 | mapping->assoc_mapping = NULL; | ||
| 538 | mapping->backing_dev_info = bdi; | ||
| 539 | mapping->a_ops = aops; | ||
| 540 | } | ||
| 516 | 541 | ||
| 517 | /* | 542 | /* |
| 518 | * NILFS2 needs clear_page_dirty() in the following two cases: | 543 | * NILFS2 needs clear_page_dirty() in the following two cases: |
diff --git a/fs/nilfs2/page.h b/fs/nilfs2/page.h index f53d8da41ed7..6ec4f498fc2b 100644 --- a/fs/nilfs2/page.h +++ b/fs/nilfs2/page.h | |||
| @@ -59,6 +59,10 @@ void nilfs_free_private_page(struct page *); | |||
| 59 | int nilfs_copy_dirty_pages(struct address_space *, struct address_space *); | 59 | int nilfs_copy_dirty_pages(struct address_space *, struct address_space *); |
| 60 | void nilfs_copy_back_pages(struct address_space *, struct address_space *); | 60 | void nilfs_copy_back_pages(struct address_space *, struct address_space *); |
| 61 | void nilfs_clear_dirty_pages(struct address_space *); | 61 | void nilfs_clear_dirty_pages(struct address_space *); |
| 62 | void nilfs_mapping_init_once(struct address_space *mapping); | ||
| 63 | void nilfs_mapping_init(struct address_space *mapping, | ||
| 64 | struct backing_dev_info *bdi, | ||
| 65 | const struct address_space_operations *aops); | ||
| 62 | unsigned nilfs_page_count_clean_buffers(struct page *, unsigned, unsigned); | 66 | unsigned nilfs_page_count_clean_buffers(struct page *, unsigned, unsigned); |
| 63 | 67 | ||
| 64 | #define NILFS_PAGE_BUG(page, m, a...) \ | 68 | #define NILFS_PAGE_BUG(page, m, a...) \ |
