Commit 2f48d593 authored by Tao Ma's avatar Tao Ma Committed by Joel Becker

ocfs2: duplicate inline data properly during reflink.

The old reflink fails to handle inodes with inline data and will oops
if it encounters them.  This patch copies inline data to the new inode.
Extended attributes may still be refcounted.
Signed-off-by: default avatarTao Ma <tao.ma@oracle.com>
Signed-off-by: default avatarJoel Becker <joel.becker@oracle.com>
Tested-by: default avatarTristan Ye <tristan.ye@oracle.com>
parent 87f4b1bb
...@@ -1712,7 +1712,8 @@ int ocfs2_check_range_for_refcount(struct inode *inode, loff_t pos, ...@@ -1712,7 +1712,8 @@ int ocfs2_check_range_for_refcount(struct inode *inode, loff_t pos,
struct super_block *sb = inode->i_sb; struct super_block *sb = inode->i_sb;
if (!ocfs2_refcount_tree(OCFS2_SB(inode->i_sb)) || if (!ocfs2_refcount_tree(OCFS2_SB(inode->i_sb)) ||
!(OCFS2_I(inode)->ip_dyn_features & OCFS2_HAS_REFCOUNT_FL)) !(OCFS2_I(inode)->ip_dyn_features & OCFS2_HAS_REFCOUNT_FL) ||
OCFS2_I(inode)->ip_dyn_features & OCFS2_INLINE_DATA_FL)
return 0; return 0;
cpos = pos >> OCFS2_SB(sb)->s_clustersize_bits; cpos = pos >> OCFS2_SB(sb)->s_clustersize_bits;
......
...@@ -3743,6 +3743,9 @@ static int ocfs2_attach_refcount_tree(struct inode *inode, ...@@ -3743,6 +3743,9 @@ static int ocfs2_attach_refcount_tree(struct inode *inode,
goto out; goto out;
} }
if (oi->ip_dyn_features & OCFS2_INLINE_DATA_FL)
goto attach_xattr;
ocfs2_init_dinode_extent_tree(&di_et, INODE_CACHE(inode), di_bh); ocfs2_init_dinode_extent_tree(&di_et, INODE_CACHE(inode), di_bh);
size = i_size_read(inode); size = i_size_read(inode);
...@@ -3769,6 +3772,7 @@ static int ocfs2_attach_refcount_tree(struct inode *inode, ...@@ -3769,6 +3772,7 @@ static int ocfs2_attach_refcount_tree(struct inode *inode,
cpos += num_clusters; cpos += num_clusters;
} }
attach_xattr:
if (oi->ip_dyn_features & OCFS2_HAS_XATTR_FL) { if (oi->ip_dyn_features & OCFS2_HAS_XATTR_FL) {
ret = ocfs2_xattr_attach_refcount_tree(inode, di_bh, ret = ocfs2_xattr_attach_refcount_tree(inode, di_bh,
&ref_tree->rf_ci, &ref_tree->rf_ci,
...@@ -3858,6 +3862,49 @@ out: ...@@ -3858,6 +3862,49 @@ out:
return ret; return ret;
} }
static int ocfs2_duplicate_inline_data(struct inode *s_inode,
struct buffer_head *s_bh,
struct inode *t_inode,
struct buffer_head *t_bh)
{
int ret;
handle_t *handle;
struct ocfs2_super *osb = OCFS2_SB(s_inode->i_sb);
struct ocfs2_dinode *s_di = (struct ocfs2_dinode *)s_bh->b_data;
struct ocfs2_dinode *t_di = (struct ocfs2_dinode *)t_bh->b_data;
BUG_ON(!(OCFS2_I(s_inode)->ip_dyn_features & OCFS2_INLINE_DATA_FL));
handle = ocfs2_start_trans(osb, OCFS2_INODE_UPDATE_CREDITS);
if (IS_ERR(handle)) {
ret = PTR_ERR(handle);
mlog_errno(ret);
goto out;
}
ret = ocfs2_journal_access_di(handle, INODE_CACHE(t_inode), t_bh,
OCFS2_JOURNAL_ACCESS_WRITE);
if (ret) {
mlog_errno(ret);
goto out_commit;
}
t_di->id2.i_data.id_count = s_di->id2.i_data.id_count;
memcpy(t_di->id2.i_data.id_data, s_di->id2.i_data.id_data,
le16_to_cpu(s_di->id2.i_data.id_count));
spin_lock(&OCFS2_I(t_inode)->ip_lock);
OCFS2_I(t_inode)->ip_dyn_features |= OCFS2_INLINE_DATA_FL;
t_di->i_dyn_features = cpu_to_le16(OCFS2_I(t_inode)->ip_dyn_features);
spin_unlock(&OCFS2_I(t_inode)->ip_lock);
ocfs2_journal_dirty(handle, t_bh);
out_commit:
ocfs2_commit_trans(osb, handle);
out:
return ret;
}
static int ocfs2_duplicate_extent_list(struct inode *s_inode, static int ocfs2_duplicate_extent_list(struct inode *s_inode,
struct inode *t_inode, struct inode *t_inode,
struct buffer_head *t_bh, struct buffer_head *t_bh,
...@@ -3997,6 +4044,14 @@ static int ocfs2_create_reflink_node(struct inode *s_inode, ...@@ -3997,6 +4044,14 @@ static int ocfs2_create_reflink_node(struct inode *s_inode,
goto out; goto out;
} }
if (OCFS2_I(s_inode)->ip_dyn_features & OCFS2_INLINE_DATA_FL) {
ret = ocfs2_duplicate_inline_data(s_inode, s_bh,
t_inode, t_bh);
if (ret)
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) {
......
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