Skip to content

Commit

Permalink
ocfs2: duplicate inline data properly during reflink.
Browse files Browse the repository at this point in the history
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: Tao Ma <tao.ma@oracle.com>
Signed-off-by: Joel Becker <joel.becker@oracle.com>
Tested-by: Tristan Ye <tristan.ye@oracle.com>
  • Loading branch information
Tao Ma authored and Joel Becker committed Oct 29, 2009
1 parent 87f4b1b commit 2f48d59
Show file tree
Hide file tree
Showing 2 changed files with 57 additions and 1 deletion.
3 changes: 2 additions & 1 deletion fs/ocfs2/file.c
Original file line number Diff line number Diff line change
Expand Up @@ -1712,7 +1712,8 @@ int ocfs2_check_range_for_refcount(struct inode *inode, loff_t pos,
struct super_block *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;

cpos = pos >> OCFS2_SB(sb)->s_clustersize_bits;
Expand Down
55 changes: 55 additions & 0 deletions fs/ocfs2/refcounttree.c
Original file line number Diff line number Diff line change
Expand Up @@ -3743,6 +3743,9 @@ static int ocfs2_attach_refcount_tree(struct inode *inode,
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);

size = i_size_read(inode);
Expand All @@ -3769,6 +3772,7 @@ static int ocfs2_attach_refcount_tree(struct inode *inode,
cpos += num_clusters;
}

attach_xattr:
if (oi->ip_dyn_features & OCFS2_HAS_XATTR_FL) {
ret = ocfs2_xattr_attach_refcount_tree(inode, di_bh,
&ref_tree->rf_ci,
Expand Down Expand Up @@ -3858,6 +3862,49 @@ static int ocfs2_add_refcounted_extent(struct inode *inode,
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,
struct inode *t_inode,
struct buffer_head *t_bh,
Expand Down Expand Up @@ -3997,6 +4044,14 @@ static int ocfs2_create_reflink_node(struct inode *s_inode,
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),
1, &ref_tree, &ref_root_bh);
if (ret) {
Expand Down

0 comments on commit 2f48d59

Please sign in to comment.