aboutsummaryrefslogtreecommitdiffstats
path: root/fs/btrfs/transaction.c
diff options
context:
space:
mode:
authorYan <zheng.yan@oracle.com>2008-07-30 16:29:20 -0400
committerChris Mason <chris.mason@oracle.com>2008-09-25 11:04:05 -0400
commitbcc63abbf3e9bf948a1b0129b3e6120ec7d7f698 (patch)
tree1c66dc210f948f79c86786368d2c75b57482875d /fs/btrfs/transaction.c
parent33958dc6d38fb4ca7e62273855fcb2db7e616263 (diff)
Btrfs: implement memory reclaim for leaf reference cache
The memory reclaiming issue happens when snapshot exists. In that case, some cache entries may not be used during old snapshot dropping, so they will remain in the cache until umount. The patch adds a field to struct btrfs_leaf_ref to record create time. Besides, the patch makes all dead roots of a given snapshot linked together in order of create time. After a old snapshot was completely dropped, we check the dead root list and remove all cache entries created before the oldest dead root in the list. Signed-off-by: Chris Mason <chris.mason@oracle.com>
Diffstat (limited to 'fs/btrfs/transaction.c')
-rw-r--r--fs/btrfs/transaction.c40
1 files changed, 30 insertions, 10 deletions
diff --git a/fs/btrfs/transaction.c b/fs/btrfs/transaction.c
index 216f31571620..52c5524896a3 100644
--- a/fs/btrfs/transaction.c
+++ b/fs/btrfs/transaction.c
@@ -98,20 +98,24 @@ static noinline int record_root_in_trans(struct btrfs_root *root)
98 BUG_ON(!dirty); 98 BUG_ON(!dirty);
99 dirty->root = kmalloc(sizeof(*dirty->root), GFP_NOFS); 99 dirty->root = kmalloc(sizeof(*dirty->root), GFP_NOFS);
100 BUG_ON(!dirty->root); 100 BUG_ON(!dirty->root);
101
102 dirty->latest_root = root; 101 dirty->latest_root = root;
103 INIT_LIST_HEAD(&dirty->list); 102 INIT_LIST_HEAD(&dirty->list);
104 103
105 root->commit_root = btrfs_root_node(root); 104 root->commit_root = btrfs_root_node(root);
106 root->dirty_root = dirty;
107 105
108 memcpy(dirty->root, root, sizeof(*root)); 106 memcpy(dirty->root, root, sizeof(*root));
109 dirty->root->ref_tree = &root->ref_tree_struct;
110
111 spin_lock_init(&dirty->root->node_lock); 107 spin_lock_init(&dirty->root->node_lock);
108 spin_lock_init(&dirty->root->list_lock);
112 mutex_init(&dirty->root->objectid_mutex); 109 mutex_init(&dirty->root->objectid_mutex);
110 INIT_LIST_HEAD(&dirty->root->dead_list);
113 dirty->root->node = root->commit_root; 111 dirty->root->node = root->commit_root;
114 dirty->root->commit_root = NULL; 112 dirty->root->commit_root = NULL;
113
114 spin_lock(&root->list_lock);
115 list_add(&dirty->root->dead_list, &root->dead_list);
116 spin_unlock(&root->list_lock);
117
118 root->dirty_root = dirty;
115 } else { 119 } else {
116 WARN_ON(1); 120 WARN_ON(1);
117 } 121 }
@@ -356,8 +360,6 @@ int btrfs_commit_tree_roots(struct btrfs_trans_handle *trans,
356 list_del_init(next); 360 list_del_init(next);
357 root = list_entry(next, struct btrfs_root, dirty_list); 361 root = list_entry(next, struct btrfs_root, dirty_list);
358 update_cowonly_root(trans, root); 362 update_cowonly_root(trans, root);
359 if (root->fs_info->closing)
360 btrfs_remove_leaf_refs(root);
361 } 363 }
362 return 0; 364 return 0;
363} 365}
@@ -410,7 +412,11 @@ static noinline int add_dirty_roots(struct btrfs_trans_handle *trans,
410 412
411 free_extent_buffer(root->commit_root); 413 free_extent_buffer(root->commit_root);
412 root->commit_root = NULL; 414 root->commit_root = NULL;
413 415
416 spin_lock(&root->list_lock);
417 list_del_init(&dirty->root->dead_list);
418 spin_unlock(&root->list_lock);
419
414 kfree(dirty->root); 420 kfree(dirty->root);
415 kfree(dirty); 421 kfree(dirty);
416 422
@@ -497,6 +503,7 @@ static noinline int drop_dirty_roots(struct btrfs_root *tree_root,
497 unsigned long nr; 503 unsigned long nr;
498 u64 num_bytes; 504 u64 num_bytes;
499 u64 bytes_used; 505 u64 bytes_used;
506 u64 max_useless;
500 int ret = 0; 507 int ret = 0;
501 int err; 508 int err;
502 509
@@ -554,10 +561,25 @@ static noinline int drop_dirty_roots(struct btrfs_root *tree_root,
554 } 561 }
555 mutex_unlock(&root->fs_info->drop_mutex); 562 mutex_unlock(&root->fs_info->drop_mutex);
556 563
564 spin_lock(&root->list_lock);
565 list_del_init(&dirty->root->dead_list);
566 if (!list_empty(&root->dead_list)) {
567 struct btrfs_root *oldest;
568 oldest = list_entry(root->dead_list.prev,
569 struct btrfs_root, dead_list);
570 max_useless = oldest->root_key.offset - 1;
571 } else {
572 max_useless = root->root_key.offset - 1;
573 }
574 spin_unlock(&root->list_lock);
575
557 nr = trans->blocks_used; 576 nr = trans->blocks_used;
558 ret = btrfs_end_transaction(trans, tree_root); 577 ret = btrfs_end_transaction(trans, tree_root);
559 BUG_ON(ret); 578 BUG_ON(ret);
560 579
580 ret = btrfs_remove_leaf_refs(root, max_useless);
581 BUG_ON(ret);
582
561 free_extent_buffer(dirty->root->node); 583 free_extent_buffer(dirty->root->node);
562 kfree(dirty->root); 584 kfree(dirty->root);
563 kfree(dirty); 585 kfree(dirty);
@@ -785,10 +807,9 @@ int btrfs_commit_transaction(struct btrfs_trans_handle *trans,
785 put_transaction(cur_trans); 807 put_transaction(cur_trans);
786 put_transaction(cur_trans); 808 put_transaction(cur_trans);
787 809
810 list_splice_init(&dirty_fs_roots, &root->fs_info->dead_roots);
788 if (root->fs_info->closing) 811 if (root->fs_info->closing)
789 list_splice_init(&root->fs_info->dead_roots, &dirty_fs_roots); 812 list_splice_init(&root->fs_info->dead_roots, &dirty_fs_roots);
790 else
791 list_splice_init(&dirty_fs_roots, &root->fs_info->dead_roots);
792 813
793 mutex_unlock(&root->fs_info->trans_mutex); 814 mutex_unlock(&root->fs_info->trans_mutex);
794 kmem_cache_free(btrfs_trans_handle_cachep, trans); 815 kmem_cache_free(btrfs_trans_handle_cachep, trans);
@@ -814,4 +835,3 @@ again:
814 } 835 }
815 return 0; 836 return 0;
816} 837}
817