ocfs2: Attach xattr clusters to refcount tree.

In ocfs2, when xattr's value is larger than OCFS2_XATTR_INLINE_SIZE,
it will be kept outside of the blocks we store xattr entry. And they
are stored in a b-tree also. So this patch try to attach all these
clusters to refcount tree also.

Signed-off-by: Tao Ma <tao.ma@oracle.com>
This commit is contained in:
Tao Ma 2009-09-21 13:04:19 +08:00 committed by Joel Becker
parent 47bca4950b
commit 0129241e2b
4 changed files with 329 additions and 4 deletions

View file

@ -3547,7 +3547,8 @@ int ocfs2_add_refcount_flag(struct inode *inode,
struct ocfs2_caching_info *ref_ci,
struct buffer_head *ref_root_bh,
u32 cpos, u32 p_cluster, u32 num_clusters,
struct ocfs2_cached_dealloc_ctxt *dealloc)
struct ocfs2_cached_dealloc_ctxt *dealloc,
struct ocfs2_post_refcount *post)
{
int ret;
handle_t *handle;
@ -3576,6 +3577,9 @@ int ocfs2_add_refcount_flag(struct inode *inode,
}
}
if (post)
credits += post->credits;
handle = ocfs2_start_trans(osb, credits);
if (IS_ERR(handle)) {
ret = PTR_ERR(handle);
@ -3594,8 +3598,16 @@ int ocfs2_add_refcount_flag(struct inode *inode,
ret = __ocfs2_increase_refcount(handle, ref_ci, ref_root_bh,
p_cluster, num_clusters,
meta_ac, dealloc);
if (ret)
if (ret) {
mlog_errno(ret);
goto out_commit;
}
if (post && post->func) {
ret = post->func(inode, handle, post->para);
if (ret)
mlog_errno(ret);
}
out_commit:
ocfs2_commit_trans(osb, handle);
@ -3688,7 +3700,7 @@ static int ocfs2_attach_refcount_tree(struct inode *inode,
&ref_tree->rf_ci,
ref_root_bh, cpos,
p_cluster, num_clusters,
&dealloc);
&dealloc, NULL);
if (ret) {
mlog_errno(ret);
goto unlock;
@ -3699,6 +3711,17 @@ static int ocfs2_attach_refcount_tree(struct inode *inode,
cpos += num_clusters;
}
if (oi->ip_dyn_features & OCFS2_HAS_XATTR_FL) {
ret = ocfs2_xattr_attach_refcount_tree(inode, di_bh,
&ref_tree->rf_ci,
ref_root_bh,
&dealloc);
if (ret) {
mlog_errno(ret);
goto unlock;
}
}
if (data_changed) {
ret = ocfs2_change_ctime(inode, di_bh);
if (ret)

View file

@ -83,4 +83,11 @@ int ocfs2_refcount_cow_xattr(struct inode *inode,
struct buffer_head *ref_root_bh,
u32 cpos, u32 write_len,
struct ocfs2_post_refcount *post);
int ocfs2_add_refcount_flag(struct inode *inode,
struct ocfs2_extent_tree *data_et,
struct ocfs2_caching_info *ref_ci,
struct buffer_head *ref_root_bh,
u32 cpos, u32 p_cluster, u32 num_clusters,
struct ocfs2_cached_dealloc_ctxt *dealloc,
struct ocfs2_post_refcount *post);
#endif /* OCFS2_REFCOUNTTREE_H */

View file

@ -5550,6 +5550,297 @@ out:
return ret;
}
/*
* Add the REFCOUNTED flags for all the extent rec in ocfs2_xattr_value_root.
* The physical clusters will be added to refcount tree.
*/
static int ocfs2_xattr_value_attach_refcount(struct inode *inode,
struct ocfs2_xattr_value_root *xv,
struct ocfs2_extent_tree *value_et,
struct ocfs2_caching_info *ref_ci,
struct buffer_head *ref_root_bh,
struct ocfs2_cached_dealloc_ctxt *dealloc,
struct ocfs2_post_refcount *refcount)
{
int ret = 0;
u32 clusters = le32_to_cpu(xv->xr_clusters);
u32 cpos, p_cluster, num_clusters;
struct ocfs2_extent_list *el = &xv->xr_list;
unsigned int ext_flags;
cpos = 0;
while (cpos < clusters) {
ret = ocfs2_xattr_get_clusters(inode, cpos, &p_cluster,
&num_clusters, el, &ext_flags);
cpos += num_clusters;
if ((ext_flags & OCFS2_EXT_REFCOUNTED))
continue;
BUG_ON(!p_cluster);
ret = ocfs2_add_refcount_flag(inode, value_et,
ref_ci, ref_root_bh,
cpos - num_clusters,
p_cluster, num_clusters,
dealloc, refcount);
if (ret) {
mlog_errno(ret);
break;
}
}
return ret;
}
/*
* Given a normal ocfs2_xattr_header, refcount all the entries which
* have value stored outside.
* Used for xattrs stored in inode and ocfs2_xattr_block.
*/
static int ocfs2_xattr_attach_refcount_normal(struct inode *inode,
struct ocfs2_xattr_value_buf *vb,
struct ocfs2_xattr_header *header,
struct ocfs2_caching_info *ref_ci,
struct buffer_head *ref_root_bh,
struct ocfs2_cached_dealloc_ctxt *dealloc)
{
struct ocfs2_xattr_entry *xe;
struct ocfs2_xattr_value_root *xv;
struct ocfs2_extent_tree et;
int i, ret = 0;
for (i = 0; i < le16_to_cpu(header->xh_count); i++) {
xe = &header->xh_entries[i];
if (ocfs2_xattr_is_local(xe))
continue;
xv = (struct ocfs2_xattr_value_root *)((void *)header +
le16_to_cpu(xe->xe_name_offset) +
OCFS2_XATTR_SIZE(xe->xe_name_len));
vb->vb_xv = xv;
ocfs2_init_xattr_value_extent_tree(&et, INODE_CACHE(inode), vb);
ret = ocfs2_xattr_value_attach_refcount(inode, xv, &et,
ref_ci, ref_root_bh,
dealloc, NULL);
if (ret) {
mlog_errno(ret);
break;
}
}
return ret;
}
static int ocfs2_xattr_inline_attach_refcount(struct inode *inode,
struct buffer_head *fe_bh,
struct ocfs2_caching_info *ref_ci,
struct buffer_head *ref_root_bh,
struct ocfs2_cached_dealloc_ctxt *dealloc)
{
struct ocfs2_dinode *di = (struct ocfs2_dinode *)fe_bh->b_data;
struct ocfs2_xattr_header *header = (struct ocfs2_xattr_header *)
(fe_bh->b_data + inode->i_sb->s_blocksize -
le16_to_cpu(di->i_xattr_inline_size));
struct ocfs2_xattr_value_buf vb = {
.vb_bh = fe_bh,
.vb_access = ocfs2_journal_access_di,
};
return ocfs2_xattr_attach_refcount_normal(inode, &vb, header,
ref_ci, ref_root_bh, dealloc);
}
struct ocfs2_xattr_tree_value_refcount_para {
struct ocfs2_caching_info *ref_ci;
struct buffer_head *ref_root_bh;
struct ocfs2_cached_dealloc_ctxt *dealloc;
};
static int ocfs2_get_xattr_tree_value_root(struct super_block *sb,
struct ocfs2_xattr_bucket *bucket,
int offset,
struct ocfs2_xattr_value_root **xv,
struct buffer_head **bh)
{
int ret, block_off, name_offset;
struct ocfs2_xattr_header *xh = bucket_xh(bucket);
struct ocfs2_xattr_entry *xe = &xh->xh_entries[offset];
void *base;
ret = ocfs2_xattr_bucket_get_name_value(sb,
bucket_xh(bucket),
offset,
&block_off,
&name_offset);
if (ret) {
mlog_errno(ret);
goto out;
}
base = bucket_block(bucket, block_off);
*xv = (struct ocfs2_xattr_value_root *)(base + name_offset +
OCFS2_XATTR_SIZE(xe->xe_name_len));
if (bh)
*bh = bucket->bu_bhs[block_off];
out:
return ret;
}
/*
* For a given xattr bucket, refcount all the entries which
* have value stored outside.
*/
static int ocfs2_xattr_bucket_value_refcount(struct inode *inode,
struct ocfs2_xattr_bucket *bucket,
void *para)
{
int i, ret = 0;
struct ocfs2_extent_tree et;
struct ocfs2_xattr_tree_value_refcount_para *ref =
(struct ocfs2_xattr_tree_value_refcount_para *)para;
struct ocfs2_xattr_header *xh =
(struct ocfs2_xattr_header *)bucket->bu_bhs[0]->b_data;
struct ocfs2_xattr_entry *xe;
struct ocfs2_xattr_value_buf vb = {
.vb_access = ocfs2_journal_access,
};
struct ocfs2_post_refcount refcount = {
.credits = bucket->bu_blocks,
.para = bucket,
.func = ocfs2_xattr_bucket_post_refcount,
};
struct ocfs2_post_refcount *p = NULL;
/* We only need post_refcount if we support metaecc. */
if (ocfs2_meta_ecc(OCFS2_SB(inode->i_sb)))
p = &refcount;
mlog(0, "refcount bucket %llu, count = %u\n",
(unsigned long long)bucket_blkno(bucket),
le16_to_cpu(xh->xh_count));
for (i = 0; i < le16_to_cpu(xh->xh_count); i++) {
xe = &xh->xh_entries[i];
if (ocfs2_xattr_is_local(xe))
continue;
ret = ocfs2_get_xattr_tree_value_root(inode->i_sb, bucket, i,
&vb.vb_xv, &vb.vb_bh);
if (ret) {
mlog_errno(ret);
break;
}
ocfs2_init_xattr_value_extent_tree(&et,
INODE_CACHE(inode), &vb);
ret = ocfs2_xattr_value_attach_refcount(inode, vb.vb_xv,
&et, ref->ref_ci,
ref->ref_root_bh,
ref->dealloc, p);
if (ret) {
mlog_errno(ret);
break;
}
}
return ret;
}
static int ocfs2_refcount_xattr_tree_rec(struct inode *inode,
struct buffer_head *root_bh,
u64 blkno, u32 cpos, u32 len, void *para)
{
return ocfs2_iterate_xattr_buckets(inode, blkno, len,
ocfs2_xattr_bucket_value_refcount,
para);
}
static int ocfs2_xattr_block_attach_refcount(struct inode *inode,
struct buffer_head *blk_bh,
struct ocfs2_caching_info *ref_ci,
struct buffer_head *ref_root_bh,
struct ocfs2_cached_dealloc_ctxt *dealloc)
{
int ret = 0;
struct ocfs2_xattr_block *xb =
(struct ocfs2_xattr_block *)blk_bh->b_data;
if (!(le16_to_cpu(xb->xb_flags) & OCFS2_XATTR_INDEXED)) {
struct ocfs2_xattr_header *header = &xb->xb_attrs.xb_header;
struct ocfs2_xattr_value_buf vb = {
.vb_bh = blk_bh,
.vb_access = ocfs2_journal_access_xb,
};
ret = ocfs2_xattr_attach_refcount_normal(inode, &vb, header,
ref_ci, ref_root_bh,
dealloc);
} else {
struct ocfs2_xattr_tree_value_refcount_para para = {
.ref_ci = ref_ci,
.ref_root_bh = ref_root_bh,
.dealloc = dealloc,
};
ret = ocfs2_iterate_xattr_index_block(inode, blk_bh,
ocfs2_refcount_xattr_tree_rec,
&para);
}
return ret;
}
int ocfs2_xattr_attach_refcount_tree(struct inode *inode,
struct buffer_head *fe_bh,
struct ocfs2_caching_info *ref_ci,
struct buffer_head *ref_root_bh,
struct ocfs2_cached_dealloc_ctxt *dealloc)
{
int ret = 0;
struct ocfs2_inode_info *oi = OCFS2_I(inode);
struct ocfs2_dinode *di = (struct ocfs2_dinode *)fe_bh->b_data;
struct buffer_head *blk_bh = NULL;
if (oi->ip_dyn_features & OCFS2_INLINE_XATTR_FL) {
ret = ocfs2_xattr_inline_attach_refcount(inode, fe_bh,
ref_ci, ref_root_bh,
dealloc);
if (ret) {
mlog_errno(ret);
goto out;
}
}
if (!di->i_xattr_loc)
goto out;
ret = ocfs2_read_xattr_block(inode, le64_to_cpu(di->i_xattr_loc),
&blk_bh);
if (ret < 0) {
mlog_errno(ret);
goto out;
}
ret = ocfs2_xattr_block_attach_refcount(inode, blk_bh, ref_ci,
ref_root_bh, dealloc);
if (ret)
mlog_errno(ret);
brelse(blk_bh);
out:
return ret;
}
/*
* 'security' attributes support
*/

View file

@ -83,5 +83,9 @@ struct ocfs2_xattr_value_buf {
struct ocfs2_xattr_value_root *vb_xv;
};
int ocfs2_xattr_attach_refcount_tree(struct inode *inode,
struct buffer_head *fe_bh,
struct ocfs2_caching_info *ref_ci,
struct buffer_head *ref_root_bh,
struct ocfs2_cached_dealloc_ctxt *dealloc);
#endif /* OCFS2_XATTR_H */