Commit 913580b4 authored by Tao Ma's avatar Tao Ma Committed by Joel Becker

ocfs2: Abstract duplicate clusters process in CoW.

We currently use pagecache to duplicate clusters in CoW,
but it isn't suitable for xattr case. So abstract it out
so that the caller can decide which method it use.
Signed-off-by: default avatarTao Ma <tao.ma@oracle.com>
parent 1061f9c1
...@@ -45,12 +45,20 @@ struct ocfs2_cow_context { ...@@ -45,12 +45,20 @@ struct ocfs2_cow_context {
struct inode *inode; struct inode *inode;
u32 cow_start; u32 cow_start;
u32 cow_len; u32 cow_len;
struct ocfs2_extent_tree di_et; struct ocfs2_extent_tree data_et;
struct ocfs2_caching_info *ref_ci; struct ocfs2_refcount_tree *ref_tree;
struct buffer_head *ref_root_bh; struct buffer_head *ref_root_bh;
struct ocfs2_alloc_context *meta_ac; struct ocfs2_alloc_context *meta_ac;
struct ocfs2_alloc_context *data_ac; struct ocfs2_alloc_context *data_ac;
struct ocfs2_cached_dealloc_ctxt dealloc; struct ocfs2_cached_dealloc_ctxt dealloc;
int (*get_clusters)(struct ocfs2_cow_context *context,
u32 v_cluster, u32 *p_cluster,
u32 *num_clusters,
unsigned int *extent_flags);
int (*cow_duplicate_clusters)(handle_t *handle,
struct ocfs2_cow_context *context,
u32 cpos, u32 old_cluster,
u32 new_cluster, u32 new_len);
}; };
static inline struct ocfs2_refcount_tree * static inline struct ocfs2_refcount_tree *
...@@ -2489,7 +2497,7 @@ static inline unsigned int ocfs2_cow_align_length(struct super_block *sb, ...@@ -2489,7 +2497,7 @@ static inline unsigned int ocfs2_cow_align_length(struct super_block *sb,
* get good I/O from the resulting extent tree. * get good I/O from the resulting extent tree.
*/ */
static int ocfs2_refcount_cal_cow_clusters(struct inode *inode, static int ocfs2_refcount_cal_cow_clusters(struct inode *inode,
struct buffer_head *di_bh, struct ocfs2_extent_list *el,
u32 cpos, u32 cpos,
u32 write_len, u32 write_len,
u32 max_cpos, u32 max_cpos,
...@@ -2497,8 +2505,6 @@ static int ocfs2_refcount_cal_cow_clusters(struct inode *inode, ...@@ -2497,8 +2505,6 @@ static int ocfs2_refcount_cal_cow_clusters(struct inode *inode,
u32 *cow_len) u32 *cow_len)
{ {
int ret = 0; int ret = 0;
struct ocfs2_dinode *di = (struct ocfs2_dinode *) di_bh->b_data;
struct ocfs2_extent_list *el = &di->id2.i_list;
int tree_height = le16_to_cpu(el->l_tree_depth), i; int tree_height = le16_to_cpu(el->l_tree_depth), i;
struct buffer_head *eb_bh = NULL; struct buffer_head *eb_bh = NULL;
struct ocfs2_extent_block *eb = NULL; struct ocfs2_extent_block *eb = NULL;
...@@ -2769,13 +2775,13 @@ static int ocfs2_clear_cow_buffer(handle_t *handle, struct buffer_head *bh) ...@@ -2769,13 +2775,13 @@ static int ocfs2_clear_cow_buffer(handle_t *handle, struct buffer_head *bh)
return 0; return 0;
} }
static int ocfs2_duplicate_clusters(handle_t *handle, static int ocfs2_duplicate_clusters_by_page(handle_t *handle,
struct ocfs2_cow_context *context, struct ocfs2_cow_context *context,
u32 cpos, u32 old_cluster, u32 cpos, u32 old_cluster,
u32 new_cluster, u32 new_len) u32 new_cluster, u32 new_len)
{ {
int ret = 0, partial; int ret = 0, partial;
struct ocfs2_caching_info *ci = context->di_et.et_ci; struct ocfs2_caching_info *ci = context->data_et.et_ci;
struct super_block *sb = ocfs2_metadata_cache_get_super(ci); struct super_block *sb = ocfs2_metadata_cache_get_super(ci);
u64 new_block = ocfs2_clusters_to_blocks(sb, new_cluster); u64 new_block = ocfs2_clusters_to_blocks(sb, new_cluster);
struct page *page; struct page *page;
...@@ -2909,7 +2915,7 @@ static int ocfs2_replace_clusters(handle_t *handle, ...@@ -2909,7 +2915,7 @@ static int ocfs2_replace_clusters(handle_t *handle,
unsigned int ext_flags) unsigned int ext_flags)
{ {
int ret; int ret;
struct ocfs2_caching_info *ci = context->di_et.et_ci; struct ocfs2_caching_info *ci = context->data_et.et_ci;
u64 ino = ocfs2_metadata_cache_owner(ci); u64 ino = ocfs2_metadata_cache_owner(ci);
mlog(0, "inode %llu, cpos %u, old %u, new %u, len %u, ext_flags %u\n", mlog(0, "inode %llu, cpos %u, old %u, new %u, len %u, ext_flags %u\n",
...@@ -2917,15 +2923,15 @@ static int ocfs2_replace_clusters(handle_t *handle, ...@@ -2917,15 +2923,15 @@ static int ocfs2_replace_clusters(handle_t *handle,
/*If the old clusters is unwritten, no need to duplicate. */ /*If the old clusters is unwritten, no need to duplicate. */
if (!(ext_flags & OCFS2_EXT_UNWRITTEN)) { if (!(ext_flags & OCFS2_EXT_UNWRITTEN)) {
ret = ocfs2_duplicate_clusters(handle, context, cpos, ret = context->cow_duplicate_clusters(handle, context, cpos,
old, new, len); old, new, len);
if (ret) { if (ret) {
mlog_errno(ret); mlog_errno(ret);
goto out; goto out;
} }
} }
ret = ocfs2_clear_ext_refcount(handle, &context->di_et, ret = ocfs2_clear_ext_refcount(handle, &context->data_et,
cpos, new, len, ext_flags, cpos, new, len, ext_flags,
context->meta_ac, &context->dealloc); context->meta_ac, &context->dealloc);
if (ret) if (ret)
...@@ -2983,6 +2989,15 @@ static int ocfs2_cow_sync_writeback(struct super_block *sb, ...@@ -2983,6 +2989,15 @@ static int ocfs2_cow_sync_writeback(struct super_block *sb,
return ret; return ret;
} }
static int ocfs2_di_get_clusters(struct ocfs2_cow_context *context,
u32 v_cluster, u32 *p_cluster,
u32 *num_clusters,
unsigned int *extent_flags)
{
return ocfs2_get_clusters(context->inode, v_cluster, p_cluster,
num_clusters, extent_flags);
}
static int ocfs2_make_clusters_writable(struct super_block *sb, static int ocfs2_make_clusters_writable(struct super_block *sb,
struct ocfs2_cow_context *context, struct ocfs2_cow_context *context,
u32 cpos, u32 p_cluster, u32 cpos, u32 p_cluster,
...@@ -2994,14 +3009,15 @@ static int ocfs2_make_clusters_writable(struct super_block *sb, ...@@ -2994,14 +3009,15 @@ static int ocfs2_make_clusters_writable(struct super_block *sb,
struct ocfs2_super *osb = OCFS2_SB(sb); struct ocfs2_super *osb = OCFS2_SB(sb);
handle_t *handle; handle_t *handle;
struct buffer_head *ref_leaf_bh = NULL; struct buffer_head *ref_leaf_bh = NULL;
struct ocfs2_caching_info *ref_ci = &context->ref_tree->rf_ci;
struct ocfs2_refcount_rec rec; struct ocfs2_refcount_rec rec;
mlog(0, "cpos %u, p_cluster %u, num_clusters %u, e_flags %u\n", mlog(0, "cpos %u, p_cluster %u, num_clusters %u, e_flags %u\n",
cpos, p_cluster, num_clusters, e_flags); cpos, p_cluster, num_clusters, e_flags);
ret = ocfs2_lock_refcount_allocators(sb, p_cluster, num_clusters, ret = ocfs2_lock_refcount_allocators(sb, p_cluster, num_clusters,
&context->di_et, &context->data_et,
context->ref_ci, ref_ci,
context->ref_root_bh, context->ref_root_bh,
&context->meta_ac, &context->meta_ac,
&context->data_ac, &credits); &context->data_ac, &credits);
...@@ -3018,8 +3034,7 @@ static int ocfs2_make_clusters_writable(struct super_block *sb, ...@@ -3018,8 +3034,7 @@ static int ocfs2_make_clusters_writable(struct super_block *sb,
} }
while (num_clusters) { while (num_clusters) {
ret = ocfs2_get_refcount_rec(context->ref_ci, ret = ocfs2_get_refcount_rec(ref_ci, context->ref_root_bh,
context->ref_root_bh,
p_cluster, num_clusters, p_cluster, num_clusters,
&rec, &index, &ref_leaf_bh); &rec, &index, &ref_leaf_bh);
if (ret) { if (ret) {
...@@ -3041,7 +3056,8 @@ static int ocfs2_make_clusters_writable(struct super_block *sb, ...@@ -3041,7 +3056,8 @@ static int ocfs2_make_clusters_writable(struct super_block *sb,
*/ */
if (le32_to_cpu(rec.r_refcount) == 1) { if (le32_to_cpu(rec.r_refcount) == 1) {
delete = 0; delete = 0;
ret = ocfs2_clear_ext_refcount(handle, &context->di_et, ret = ocfs2_clear_ext_refcount(handle,
&context->data_et,
cpos, p_cluster, cpos, p_cluster,
set_len, e_flags, set_len, e_flags,
context->meta_ac, context->meta_ac,
...@@ -3072,7 +3088,7 @@ static int ocfs2_make_clusters_writable(struct super_block *sb, ...@@ -3072,7 +3088,7 @@ static int ocfs2_make_clusters_writable(struct super_block *sb,
set_len = new_len; set_len = new_len;
} }
ret = __ocfs2_decrease_refcount(handle, context->ref_ci, ret = __ocfs2_decrease_refcount(handle, ref_ci,
context->ref_root_bh, context->ref_root_bh,
p_cluster, set_len, p_cluster, set_len,
context->meta_ac, context->meta_ac,
...@@ -3114,17 +3130,14 @@ static int ocfs2_make_clusters_writable(struct super_block *sb, ...@@ -3114,17 +3130,14 @@ static int ocfs2_make_clusters_writable(struct super_block *sb,
return ret; return ret;
} }
static int ocfs2_replace_cow(struct inode *inode, static int ocfs2_replace_cow(struct ocfs2_cow_context *context)
struct buffer_head *di_bh,
struct buffer_head *ref_root_bh,
struct ocfs2_caching_info *ref_ci,
u32 cow_start, u32 cow_len)
{ {
int ret = 0; int ret = 0;
u32 p_cluster, num_clusters, start = cow_start; struct inode *inode = context->inode;
u32 cow_start = context->cow_start, cow_len = context->cow_len;
u32 p_cluster, num_clusters;
unsigned int ext_flags; unsigned int ext_flags;
struct ocfs2_super *osb = OCFS2_SB(inode->i_sb); struct ocfs2_super *osb = OCFS2_SB(inode->i_sb);
struct ocfs2_cow_context *context;
if (!ocfs2_refcount_tree(OCFS2_SB(inode->i_sb))) { if (!ocfs2_refcount_tree(OCFS2_SB(inode->i_sb))) {
ocfs2_error(inode->i_sb, "Inode %lu want to use refcount " ocfs2_error(inode->i_sb, "Inode %lu want to use refcount "
...@@ -3133,26 +3146,11 @@ static int ocfs2_replace_cow(struct inode *inode, ...@@ -3133,26 +3146,11 @@ static int ocfs2_replace_cow(struct inode *inode,
return -EROFS; return -EROFS;
} }
context = kzalloc(sizeof(struct ocfs2_cow_context), GFP_NOFS);
if (!context) {
ret = -ENOMEM;
mlog_errno(ret);
return ret;
}
context->inode = inode;
context->cow_start = cow_start;
context->cow_len = cow_len;
context->ref_ci = ref_ci;
context->ref_root_bh = ref_root_bh;
ocfs2_init_dealloc_ctxt(&context->dealloc); ocfs2_init_dealloc_ctxt(&context->dealloc);
ocfs2_init_dinode_extent_tree(&context->di_et,
INODE_CACHE(inode), di_bh);
while (cow_len) { while (cow_len) {
ret = ocfs2_get_clusters(inode, cow_start, &p_cluster, ret = context->get_clusters(context, cow_start, &p_cluster,
&num_clusters, &ext_flags); &num_clusters, &ext_flags);
if (ret) { if (ret) {
mlog_errno(ret); mlog_errno(ret);
break; break;
...@@ -3175,20 +3173,11 @@ static int ocfs2_replace_cow(struct inode *inode, ...@@ -3175,20 +3173,11 @@ static int ocfs2_replace_cow(struct inode *inode,
cow_start += num_clusters; cow_start += num_clusters;
} }
/*
* truncate the extent map here since no matter whether we meet with
* any error during the action, we shouldn't trust cached extent map
* any more.
*/
ocfs2_extent_map_trunc(inode, start);
if (ocfs2_dealloc_has_cluster(&context->dealloc)) { if (ocfs2_dealloc_has_cluster(&context->dealloc)) {
ocfs2_schedule_truncate_log_flush(osb, 1); ocfs2_schedule_truncate_log_flush(osb, 1);
ocfs2_run_deallocs(osb, &context->dealloc); ocfs2_run_deallocs(osb, &context->dealloc);
} }
kfree(context);
return ret; return ret;
} }
...@@ -3208,10 +3197,11 @@ static int ocfs2_refcount_cow_hunk(struct inode *inode, ...@@ -3208,10 +3197,11 @@ static int ocfs2_refcount_cow_hunk(struct inode *inode,
struct ocfs2_dinode *di = (struct ocfs2_dinode *)di_bh->b_data; struct ocfs2_dinode *di = (struct ocfs2_dinode *)di_bh->b_data;
struct buffer_head *ref_root_bh = NULL; struct buffer_head *ref_root_bh = NULL;
struct ocfs2_refcount_tree *ref_tree; struct ocfs2_refcount_tree *ref_tree;
struct ocfs2_cow_context *context = NULL;
BUG_ON(!(oi->ip_dyn_features & OCFS2_HAS_REFCOUNT_FL)); BUG_ON(!(oi->ip_dyn_features & OCFS2_HAS_REFCOUNT_FL));
ret = ocfs2_refcount_cal_cow_clusters(inode, di_bh, ret = ocfs2_refcount_cal_cow_clusters(inode, &di->id2.i_list,
cpos, write_len, max_cpos, cpos, write_len, max_cpos,
&cow_start, &cow_len); &cow_start, &cow_len);
if (ret) { if (ret) {
...@@ -3225,6 +3215,13 @@ static int ocfs2_refcount_cow_hunk(struct inode *inode, ...@@ -3225,6 +3215,13 @@ static int ocfs2_refcount_cow_hunk(struct inode *inode,
BUG_ON(cow_len == 0); BUG_ON(cow_len == 0);
context = kzalloc(sizeof(struct ocfs2_cow_context), GFP_NOFS);
if (!context) {
ret = -ENOMEM;
mlog_errno(ret);
goto out;
}
ret = ocfs2_lock_refcount_tree(osb, le64_to_cpu(di->i_refcount_loc), ret = ocfs2_lock_refcount_tree(osb, le64_to_cpu(di->i_refcount_loc),
1, &ref_tree, &ref_root_bh); 1, &ref_tree, &ref_root_bh);
if (ret) { if (ret) {
...@@ -3232,14 +3229,32 @@ static int ocfs2_refcount_cow_hunk(struct inode *inode, ...@@ -3232,14 +3229,32 @@ static int ocfs2_refcount_cow_hunk(struct inode *inode,
goto out; goto out;
} }
ret = ocfs2_replace_cow(inode, di_bh, ref_root_bh, &ref_tree->rf_ci, context->inode = inode;
cow_start, cow_len); context->cow_start = cow_start;
context->cow_len = cow_len;
context->ref_tree = ref_tree;
context->ref_root_bh = ref_root_bh;
context->cow_duplicate_clusters = ocfs2_duplicate_clusters_by_page;
context->get_clusters = ocfs2_di_get_clusters;
ocfs2_init_dinode_extent_tree(&context->data_et,
INODE_CACHE(inode), di_bh);
ret = ocfs2_replace_cow(context);
if (ret) if (ret)
mlog_errno(ret); mlog_errno(ret);
/*
* truncate the extent map here since no matter whether we meet with
* any error during the action, we shouldn't trust cached extent map
* any more.
*/
ocfs2_extent_map_trunc(inode, cow_start);
ocfs2_unlock_refcount_tree(osb, ref_tree, 1); ocfs2_unlock_refcount_tree(osb, ref_tree, 1);
brelse(ref_root_bh); brelse(ref_root_bh);
out: out:
kfree(context);
return ret; return ret;
} }
......
Markdown is supported
0%
or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment