refcount tree should use its own caching info so that when we downconvert the refcount tree lock, we can drop all the cached buffer head.
Signed-off-by: Tao Ma <[email protected]> --- fs/ocfs2/refcounttree.c | 124 +++++++++++++++++++++++++++++++++++++++++----- fs/ocfs2/refcounttree.h | 12 +++++ 2 files changed, 122 insertions(+), 14 deletions(-) diff --git a/fs/ocfs2/refcounttree.c b/fs/ocfs2/refcounttree.c index 56c8c52..4ef6bd2 100644 --- a/fs/ocfs2/refcounttree.c +++ b/fs/ocfs2/refcounttree.c @@ -54,8 +54,11 @@ struct ocfs2_cow_context { u32 cow_len; }; +static const struct ocfs2_caching_operations ocfs2_refcount_caching_ops; static void ocfs2_delete_refcount_tree(struct ocfs2_super *osb, struct ocfs2_refcount_tree *tree); +static int ocfs2_get_refcount_tree(struct ocfs2_super *osb, u64 rf_blkno, + struct ocfs2_refcount_tree **ret_tree); static int ocfs2_validate_refcount_block(struct super_block *sb, struct buffer_head *bh) @@ -142,6 +145,7 @@ int ocfs2_create_refcount_tree(struct inode *inode, struct buffer_head *di_bh) struct ocfs2_super *osb = OCFS2_SB(inode->i_sb); struct buffer_head *new_bh = NULL; struct ocfs2_refcount_block *rb; + struct ocfs2_refcount_tree *tree; u16 suballoc_bit_start; u32 num_got; u64 first_blkno; @@ -179,10 +183,16 @@ int ocfs2_create_refcount_tree(struct inode *inode, struct buffer_head *di_bh) goto out_commit; } + ret = ocfs2_get_refcount_tree(osb, first_blkno, &tree); + if (ret) { + mlog_errno(ret); + goto out_commit; + } + new_bh = sb_getblk(inode->i_sb, first_blkno); - ocfs2_set_new_buffer_uptodate(INODE_CACHE(inode), new_bh); + ocfs2_set_new_buffer_uptodate(&tree->rf_ci, new_bh); - ret = ocfs2_journal_access_rb(handle, INODE_CACHE(inode), new_bh, + ret = ocfs2_journal_access_rb(handle, &tree->rf_ci, new_bh, OCFS2_JOURNAL_ACCESS_CREATE); if (ret) { mlog_errno(ret); @@ -261,7 +271,7 @@ int ocfs2_set_refcount_tree(struct inode *inode, goto out_commit; } - ret = ocfs2_journal_access_rb(handle, INODE_CACHE(inode), ref_root_bh, + ret = ocfs2_journal_access_rb(handle, &ref_tree->rf_ci, ref_root_bh, OCFS2_JOURNAL_ACCESS_WRITE); if (ret) { mlog_errno(ret); @@ -280,6 +290,7 @@ int ocfs2_set_refcount_tree(struct inode *inode, spin_unlock(&oi->ip_lock); ocfs2_journal_dirty(handle, di_bh); + ocfs2_set_ci_lock_trans(osb->journal, &ref_tree->rf_ci); out_commit: ocfs2_commit_trans(osb, handle); out: @@ -352,6 +363,8 @@ int ocfs2_remove_refcount_tree(struct inode *inode, struct buffer_head *di_bh) goto out_unlock; } + ocfs2_set_ci_lock_trans(osb->journal, &ref_tree->rf_ci); + ret = ocfs2_journal_access_di(handle, INODE_CACHE(inode), di_bh, OCFS2_JOURNAL_ACCESS_WRITE); if (ret) { @@ -359,7 +372,7 @@ int ocfs2_remove_refcount_tree(struct inode *inode, struct buffer_head *di_bh) goto out_commit; } - ret = ocfs2_journal_access_rb(handle, INODE_CACHE(inode), blk_bh, + ret = ocfs2_journal_access_rb(handle, &ref_tree->rf_ci, blk_bh, OCFS2_JOURNAL_ACCESS_WRITE); if (ret) { mlog_errno(ret); @@ -1333,6 +1346,8 @@ static int __ocfs2_increase_refcount(handle_t *handle, } out: + ocfs2_set_ci_lock_trans( + OCFS2_SB(ocfs2_metadata_cache_get_super(ci))->journal, ci); brelse(ref_leaf_bh); return ret; } @@ -1518,6 +1533,7 @@ out: return ret; } +/* Caller must hold refcount tree lock. */ int ocfs2_decrease_refcount(struct inode *inode, struct buffer_head *di_bh, handle_t *handle, u32 cpos, u32 len, struct ocfs2_alloc_context *meta_ac, @@ -1528,11 +1544,19 @@ int ocfs2_decrease_refcount(struct inode *inode, struct buffer_head *di_bh, struct ocfs2_inode_info *oi = OCFS2_I(inode); struct buffer_head *ref_root_bh = NULL; struct ocfs2_dinode *di = (struct ocfs2_dinode *)di_bh->b_data; + struct ocfs2_refcount_tree *tree; BUG_ON(!(oi->ip_dyn_features & OCFS2_HAS_REFCOUNT_FL)); BUG_ON(!di->i_refcount_loc); - ret = ocfs2_read_refcount_block(INODE_CACHE(inode), + ret = ocfs2_get_refcount_tree(OCFS2_SB(inode->i_sb), + le64_to_cpu(di->i_refcount_loc), &tree); + if (ret) { + mlog_errno(ret); + goto out; + } + + ret = ocfs2_read_refcount_block(&tree->rf_ci, le64_to_cpu(di->i_refcount_loc), &ref_root_bh); if (ret) { @@ -1540,7 +1564,7 @@ int ocfs2_decrease_refcount(struct inode *inode, struct buffer_head *di_bh, goto out; } - ret = __ocfs2_decrease_refcount(handle, INODE_CACHE(inode), ref_root_bh, + ret = __ocfs2_decrease_refcount(handle, &tree->rf_ci, ref_root_bh, cpos, len, meta_ac, dealloc, delete); if (ret) mlog_errno(ret); @@ -1725,6 +1749,8 @@ out: * continguous also, so that we can get the number easily. * As for meta_ac, we will at most add split 2 refcount record and * 2 more refcount block, so just check it in a rough way. + * + * Caller must hold refcount tree lock. */ int ocfs2_prepare_refcount_change_for_del(struct inode *inode, struct buffer_head *di_bh, @@ -1737,6 +1763,7 @@ int ocfs2_prepare_refcount_change_for_del(struct inode *inode, struct ocfs2_dinode *di = (struct ocfs2_dinode *)di_bh->b_data; struct ocfs2_inode_info *oi = OCFS2_I(inode); struct buffer_head *ref_root_bh = NULL; + struct ocfs2_refcount_tree *tree; u64 start_cpos = ocfs2_blocks_to_clusters(inode->i_sb, phys_blkno); if (!ocfs2_refcount_tree(OCFS2_SB(inode->i_sb))) { @@ -1750,7 +1777,14 @@ int ocfs2_prepare_refcount_change_for_del(struct inode *inode, BUG_ON(!(oi->ip_dyn_features & OCFS2_HAS_REFCOUNT_FL)); BUG_ON(!di->i_refcount_loc); - ret = ocfs2_read_refcount_block(INODE_CACHE(inode), + ret = ocfs2_get_refcount_tree(OCFS2_SB(inode->i_sb), + le64_to_cpu(di->i_refcount_loc), &tree); + if (ret) { + mlog_errno(ret); + goto out; + } + + ret = ocfs2_read_refcount_block(&tree->rf_ci, le64_to_cpu(di->i_refcount_loc), &ref_root_bh); if (ret) { @@ -1759,7 +1793,7 @@ int ocfs2_prepare_refcount_change_for_del(struct inode *inode, } ret = ocfs2_calc_refcount_meta_credits(inode->i_sb, - INODE_CACHE(inode), + &tree->rf_ci, ref_root_bh, start_cpos, clusters, &ref_blocks, credits); @@ -2187,6 +2221,9 @@ static int ocfs2_clear_ext_refcount(handle_t *handle, mlog_errno(ret); out: + ocfs2_set_ci_lock_trans( + OCFS2_SB(ocfs2_metadata_cache_get_super(et->et_ci))->journal, + et->et_ci); ocfs2_free_path(path); return ret; } @@ -2348,6 +2385,7 @@ out: static int ocfs2_replace_cow(struct inode *inode, struct buffer_head *di_bh, struct buffer_head *ref_root_bh, + struct ocfs2_caching_info *ref_ci, u32 cow_start, u32 cow_len, struct page **pages, int num_pages) @@ -2372,7 +2410,7 @@ static int ocfs2_replace_cow(struct inode *inode, context.num_pages = num_pages; context.cow_start = cow_start; context.cow_len = cow_len; - context.ref_ci = INODE_CACHE(inode); + context.ref_ci = ref_ci; context.ref_root_bh = ref_root_bh; context.bhs = kcalloc(ocfs2_clusters_to_blocks(inode->i_sb, 1), @@ -2480,7 +2518,7 @@ int ocfs2_refcount_cow(struct inode *inode, goto out; } - ret = ocfs2_replace_cow(inode, di_bh, ref_root_bh, + ret = ocfs2_replace_cow(inode, di_bh, ref_root_bh, &ref_tree->rf_ci, cow_start, cow_len, pages, num_pages); if (ret) mlog_errno(ret); @@ -2611,7 +2649,7 @@ static int ocfs2_attach_refcount_tree(struct inode *inode, continue; ret = ocfs2_add_refcount_flag(inode, &di_et, - INODE_CACHE(inode), ref_root_bh, + &ref_tree->rf_ci, ref_root_bh, cpos - num_clusters, p_cluster, num_clusters, &dealloc); @@ -2694,6 +2732,7 @@ out: static int ocfs2_duplicate_extent_list(struct inode *s_inode, struct inode *t_inode, struct buffer_head *t_bh, + struct ocfs2_caching_info *ref_ci, struct buffer_head *ref_root_bh, struct ocfs2_cached_dealloc_ctxt *dealloc) { @@ -2715,8 +2754,7 @@ static int ocfs2_duplicate_extent_list(struct inode *s_inode, if (p_cluster) { ret = ocfs2_add_refcounted_extent(t_inode, &et, - INODE_CACHE(t_inode), - ref_root_bh, + ref_ci, ref_root_bh, cpos, p_cluster, num_clusters, ext_flags, @@ -2806,7 +2844,8 @@ static int ocfs2_create_reflink_node(struct inode *s_inode, el = &di->id2.i_list; ret = ocfs2_duplicate_extent_list(s_inode, t_inode, t_bh, - ref_root_bh, &dealloc); + &ref_tree->rf_ci, ref_root_bh, + &dealloc); if (ret) { mlog_errno(ret); goto out_unlock_refcount; @@ -3076,6 +3115,7 @@ static void ocfs2_insert_refcount_tree(struct ocfs2_super *osb, static void ocfs2_free_refcount_tree(struct ocfs2_super *osb, struct ocfs2_refcount_tree *tree) { + ocfs2_metadata_cache_exit(&tree->rf_ci); ocfs2_simple_drop_lockres(osb, &tree->rf_lockres); ocfs2_lock_res_free(&tree->rf_lockres); kfree(tree); @@ -3113,8 +3153,12 @@ static int ocfs2_get_refcount_tree(struct ocfs2_super *osb, u64 rf_blkno, } new->rf_blkno = rf_blkno; + new->rf_sb = osb->sb; + spin_lock_init(&new->rf_lock); + mutex_init(&new->rf_io_mutex); init_rwsem(&new->rf_sem); ocfs2_refcount_lock_res_init(&new->rf_lockres, osb, rf_blkno); + ocfs2_metadata_cache_init(&new->rf_ci, &ocfs2_refcount_caching_ops); spin_lock(&osb->osb_lock); tree = ocfs2_find_refcount_tree(osb, rf_blkno); @@ -3208,3 +3252,55 @@ void ocfs2_purge_refcount_tree(struct ocfs2_super *osb) ocfs2_free_refcount_tree(osb, tree); } } + +static u64 ocfs2_refcount_cache_owner(struct ocfs2_caching_info *ci) +{ + struct ocfs2_refcount_tree *rf = cache_info_to_refcount(ci); + + return rf->rf_blkno; +} + +static struct super_block * +ocfs2_refcount_cache_get_super(struct ocfs2_caching_info *ci) +{ + struct ocfs2_refcount_tree *rf = cache_info_to_refcount(ci); + + return rf->rf_sb; +} + +static void ocfs2_refcount_cache_lock(struct ocfs2_caching_info *ci) +{ + struct ocfs2_refcount_tree *rf = cache_info_to_refcount(ci); + + spin_lock(&rf->rf_lock); +} + +static void ocfs2_refcount_cache_unlock(struct ocfs2_caching_info *ci) +{ + struct ocfs2_refcount_tree *rf = cache_info_to_refcount(ci); + + spin_unlock(&rf->rf_lock); +} + +static void ocfs2_refcount_cache_io_lock(struct ocfs2_caching_info *ci) +{ + struct ocfs2_refcount_tree *rf = cache_info_to_refcount(ci); + + mutex_lock(&rf->rf_io_mutex); +} + +static void ocfs2_refcount_cache_io_unlock(struct ocfs2_caching_info *ci) +{ + struct ocfs2_refcount_tree *rf = cache_info_to_refcount(ci); + + mutex_unlock(&rf->rf_io_mutex); +} + +static const struct ocfs2_caching_operations ocfs2_refcount_caching_ops = { + .co_owner = ocfs2_refcount_cache_owner, + .co_get_super = ocfs2_refcount_cache_get_super, + .co_cache_lock = ocfs2_refcount_cache_lock, + .co_cache_unlock = ocfs2_refcount_cache_unlock, + .co_io_lock = ocfs2_refcount_cache_io_lock, + .co_io_unlock = ocfs2_refcount_cache_io_unlock, +}; diff --git a/fs/ocfs2/refcounttree.h b/fs/ocfs2/refcounttree.h index 5590127..b7fb077 100644 --- a/fs/ocfs2/refcounttree.h +++ b/fs/ocfs2/refcounttree.h @@ -22,7 +22,13 @@ struct ocfs2_refcount_tree { u64 rf_blkno; struct rw_semaphore rf_sem; struct ocfs2_lock_res rf_lockres; + + /* the following 4 fields are used by caching_info. */ struct ocfs2_caching_info rf_ci; + spinlock_t rf_lock; + struct mutex rf_io_mutex; + struct super_block *rf_sb; + }; static inline struct ocfs2_refcount_tree * @@ -31,6 +37,12 @@ OCFS2_REF_ITEM(struct ocfs2_lock_res *res) return container_of(res, struct ocfs2_refcount_tree, rf_lockres); } +static inline struct ocfs2_refcount_tree * +cache_info_to_refcount(struct ocfs2_caching_info *ci) +{ + return container_of(ci, struct ocfs2_refcount_tree, rf_ci); +} + int ocfs2_create_refcount_tree(struct inode *inode, struct buffer_head *di_bh); int ocfs2_set_refcount_tree(struct inode *inode, struct buffer_head *di_bh, -- 1.6.2.rc2.16.gf474c _______________________________________________ Ocfs2-devel mailing list [email protected] http://oss.oracle.com/mailman/listinfo/ocfs2-devel
