aboutsummaryrefslogtreecommitdiffstats
path: root/fs
diff options
context:
space:
mode:
authorTao Ma <tao.ma@oracle.com>2008-09-19 10:17:41 -0400
committerMark Fasheh <mfasheh@suse.com>2008-10-13 20:02:43 -0400
commit5a09561199e7f8d3feaaa01c39372050e140b775 (patch)
tree5affae979a564bae543e81d70abc58015ce44f80 /fs
parent06b240d8af21ddee4cfec3b0f02b81d9f168a98a (diff)
ocfs2: Add empty bucket support in xattr.
As Mark mentioned, it may be time-consuming when we remove the empty xattr bucket, so this patch try to let empty bucket exist in xattr operation. The modification includes: 1. Remove the functin of bucket and extent record deletion during xattr delete. 2. In xattr set: 1) Don't clean the last entry so that if the bucket is empty, the hash value of the bucket is the hash value of the entry which is deleted last. 2) During insert, if we meet with an empty bucket, just use the 1st entry. 3. In binary search of xattr bucket, use the bucket hash value(which stored in the 1st xattr entry) to find the right place. Signed-off-by: Tao Ma <tao.ma@oracle.com> Signed-off-by: Mark Fasheh <mfasheh@suse.com>
Diffstat (limited to 'fs')
-rw-r--r--fs/ocfs2/xattr.c197
1 files changed, 43 insertions, 154 deletions
diff --git a/fs/ocfs2/xattr.c b/fs/ocfs2/xattr.c
index b1f2a164e7dc..64700c3fc244 100644
--- a/fs/ocfs2/xattr.c
+++ b/fs/ocfs2/xattr.c
@@ -2301,9 +2301,12 @@ static int ocfs2_xattr_bucket_find(struct inode *inode,
2301 2301
2302 /* 2302 /*
2303 * Check whether the hash of the last entry in our 2303 * Check whether the hash of the last entry in our
2304 * bucket is larger than the search one. 2304 * bucket is larger than the search one. for an empty
2305 * bucket, the last one is also the first one.
2305 */ 2306 */
2306 xe = &xh->xh_entries[le16_to_cpu(xh->xh_count) - 1]; 2307 if (xh->xh_count)
2308 xe = &xh->xh_entries[le16_to_cpu(xh->xh_count) - 1];
2309
2307 last_hash = le32_to_cpu(xe->xe_name_hash); 2310 last_hash = le32_to_cpu(xe->xe_name_hash);
2308 2311
2309 /* record lower_bh which may be the insert place. */ 2312 /* record lower_bh which may be the insert place. */
@@ -2450,7 +2453,8 @@ static int ocfs2_iterate_xattr_buckets(struct inode *inode,
2450 if (i == 0) 2453 if (i == 0)
2451 num_buckets = le16_to_cpu(bucket.xh->xh_num_buckets); 2454 num_buckets = le16_to_cpu(bucket.xh->xh_num_buckets);
2452 2455
2453 mlog(0, "iterating xattr bucket %llu\n", blkno); 2456 mlog(0, "iterating xattr bucket %llu, first hash %u\n", blkno,
2457 le32_to_cpu(bucket.xh->xh_entries[0].xe_name_hash));
2454 if (func) { 2458 if (func) {
2455 ret = func(inode, &bucket, para); 2459 ret = func(inode, &bucket, para);
2456 if (ret) { 2460 if (ret) {
@@ -3915,8 +3919,6 @@ static inline char *ocfs2_xattr_bucket_get_val(struct inode *inode,
3915 3919
3916/* 3920/*
3917 * Handle the normal xattr set, including replace, delete and new. 3921 * Handle the normal xattr set, including replace, delete and new.
3918 * When the bucket is empty, "is_empty" is set and the caller can
3919 * free this bucket.
3920 * 3922 *
3921 * Note: "local" indicates the real data's locality. So we can't 3923 * Note: "local" indicates the real data's locality. So we can't
3922 * just its bucket locality by its length. 3924 * just its bucket locality by its length.
@@ -3925,8 +3927,7 @@ static void ocfs2_xattr_set_entry_normal(struct inode *inode,
3925 struct ocfs2_xattr_info *xi, 3927 struct ocfs2_xattr_info *xi,
3926 struct ocfs2_xattr_search *xs, 3928 struct ocfs2_xattr_search *xs,
3927 u32 name_hash, 3929 u32 name_hash,
3928 int local, 3930 int local)
3929 int *is_empty)
3930{ 3931{
3931 struct ocfs2_xattr_entry *last, *xe; 3932 struct ocfs2_xattr_entry *last, *xe;
3932 int name_len = strlen(xi->name); 3933 int name_len = strlen(xi->name);
@@ -3979,14 +3980,23 @@ static void ocfs2_xattr_set_entry_normal(struct inode *inode,
3979 ocfs2_xattr_set_local(xe, local); 3980 ocfs2_xattr_set_local(xe, local);
3980 return; 3981 return;
3981 } else { 3982 } else {
3982 /* Remove the old entry. */ 3983 /*
3984 * Remove the old entry if there is more than one.
3985 * We don't remove the last entry so that we can
3986 * use it to indicate the hash value of the empty
3987 * bucket.
3988 */
3983 last -= 1; 3989 last -= 1;
3984 memmove(xe, xe + 1,
3985 (void *)last - (void *)xe);
3986 memset(last, 0, sizeof(struct ocfs2_xattr_entry));
3987 le16_add_cpu(&xh->xh_count, -1); 3990 le16_add_cpu(&xh->xh_count, -1);
3988 if (xh->xh_count == 0 && is_empty) 3991 if (xh->xh_count) {
3989 *is_empty = 1; 3992 memmove(xe, xe + 1,
3993 (void *)last - (void *)xe);
3994 memset(last, 0,
3995 sizeof(struct ocfs2_xattr_entry));
3996 } else
3997 xh->xh_free_start =
3998 cpu_to_le16(OCFS2_XATTR_BUCKET_SIZE);
3999
3990 return; 4000 return;
3991 } 4001 }
3992 } else { 4002 } else {
@@ -3994,7 +4004,7 @@ static void ocfs2_xattr_set_entry_normal(struct inode *inode,
3994 int low = 0, high = count - 1, tmp; 4004 int low = 0, high = count - 1, tmp;
3995 struct ocfs2_xattr_entry *tmp_xe; 4005 struct ocfs2_xattr_entry *tmp_xe;
3996 4006
3997 while (low <= high) { 4007 while (low <= high && count) {
3998 tmp = (low + high) / 2; 4008 tmp = (low + high) / 2;
3999 tmp_xe = &xh->xh_entries[tmp]; 4009 tmp_xe = &xh->xh_entries[tmp];
4000 4010
@@ -4090,8 +4100,7 @@ static int ocfs2_xattr_set_entry_in_bucket(struct inode *inode,
4090 struct ocfs2_xattr_info *xi, 4100 struct ocfs2_xattr_info *xi,
4091 struct ocfs2_xattr_search *xs, 4101 struct ocfs2_xattr_search *xs,
4092 u32 name_hash, 4102 u32 name_hash,
4093 int local, 4103 int local)
4094 int *bucket_empty)
4095{ 4104{
4096 int i, ret; 4105 int i, ret;
4097 handle_t *handle = NULL; 4106 handle_t *handle = NULL;
@@ -4130,8 +4139,7 @@ static int ocfs2_xattr_set_entry_in_bucket(struct inode *inode,
4130 } 4139 }
4131 } 4140 }
4132 4141
4133 ocfs2_xattr_set_entry_normal(inode, xi, xs, name_hash, 4142 ocfs2_xattr_set_entry_normal(inode, xi, xs, name_hash, local);
4134 local, bucket_empty);
4135 4143
4136 /*Only dirty the blocks we have touched in set xattr. */ 4144 /*Only dirty the blocks we have touched in set xattr. */
4137 ret = ocfs2_xattr_bucket_handle_journal(inode, handle, xs, 4145 ret = ocfs2_xattr_bucket_handle_journal(inode, handle, xs,
@@ -4280,69 +4288,6 @@ static int ocfs2_xattr_bucket_set_value_outside(struct inode *inode,
4280 return __ocfs2_xattr_set_value_outside(inode, xv, val, value_len); 4288 return __ocfs2_xattr_set_value_outside(inode, xv, val, value_len);
4281} 4289}
4282 4290
4283/*
4284 * Remove the xattr bucket pointed by bucket_bh.
4285 * All the buckets after it in the same xattr extent rec will be
4286 * move forward one by one.
4287 */
4288static int ocfs2_rm_xattr_bucket(struct inode *inode,
4289 struct buffer_head *first_bh,
4290 struct ocfs2_xattr_bucket *bucket)
4291{
4292 int ret = 0, credits;
4293 struct ocfs2_xattr_header *xh =
4294 (struct ocfs2_xattr_header *)first_bh->b_data;
4295 u16 bucket_num = le16_to_cpu(xh->xh_num_buckets);
4296 u64 end, start = bucket->bhs[0]->b_blocknr;
4297 struct ocfs2_super *osb = OCFS2_SB(inode->i_sb);
4298 handle_t *handle;
4299 u16 blk_per_bucket = ocfs2_blocks_per_xattr_bucket(inode->i_sb);
4300
4301 end = first_bh->b_blocknr + (bucket_num - 1) * blk_per_bucket;
4302
4303 mlog(0, "rm xattr bucket %llu\n", start);
4304 /*
4305 * We need to update the first xattr_header and all the buckets starting
4306 * from start in this xattr rec.
4307 *
4308 * XXX: Should we empty the old last bucket here?
4309 */
4310 credits = 1 + end - start;
4311 handle = ocfs2_start_trans(osb, credits);
4312 if (IS_ERR(handle)) {
4313 ret = PTR_ERR(handle);
4314 mlog_errno(ret);
4315 return ret;
4316 }
4317
4318 ret = ocfs2_journal_access(handle, inode, first_bh,
4319 OCFS2_JOURNAL_ACCESS_WRITE);
4320 if (ret) {
4321 mlog_errno(ret);
4322 goto out_commit;
4323 }
4324
4325
4326 while (start < end) {
4327 ret = ocfs2_cp_xattr_bucket(inode, handle,
4328 start + blk_per_bucket,
4329 start, 0);
4330 if (ret) {
4331 mlog_errno(ret);
4332 goto out_commit;
4333 }
4334 start += blk_per_bucket;
4335 }
4336
4337 /* update the first_bh. */
4338 xh->xh_num_buckets = cpu_to_le16(bucket_num - 1);
4339 ocfs2_journal_dirty(handle, first_bh);
4340
4341out_commit:
4342 ocfs2_commit_trans(osb, handle);
4343 return ret;
4344}
4345
4346static int ocfs2_rm_xattr_cluster(struct inode *inode, 4291static int ocfs2_rm_xattr_cluster(struct inode *inode,
4347 struct buffer_head *root_bh, 4292 struct buffer_head *root_bh,
4348 u64 blkno, 4293 u64 blkno,
@@ -4432,57 +4377,6 @@ out:
4432 return ret; 4377 return ret;
4433} 4378}
4434 4379
4435/*
4436 * Free the xattr bucket indicated by xs->bucket and if all the buckets
4437 * in the clusters is free, free the clusters also.
4438 */
4439static int ocfs2_xattr_bucket_shrink(struct inode *inode,
4440 struct ocfs2_xattr_info *xi,
4441 struct ocfs2_xattr_search *xs,
4442 u32 name_hash)
4443{
4444 int ret;
4445 u32 e_cpos, num_clusters;
4446 u64 p_blkno;
4447 struct buffer_head *first_bh = NULL;
4448 struct ocfs2_xattr_header *first_xh;
4449 struct ocfs2_xattr_block *xb =
4450 (struct ocfs2_xattr_block *)xs->xattr_bh->b_data;
4451
4452 BUG_ON(xs->header->xh_count != 0);
4453
4454 ret = ocfs2_xattr_get_rec(inode, name_hash, &p_blkno,
4455 &e_cpos, &num_clusters,
4456 &xb->xb_attrs.xb_root.xt_list);
4457 if (ret) {
4458 mlog_errno(ret);
4459 return ret;
4460 }
4461
4462 ret = ocfs2_read_block(OCFS2_SB(inode->i_sb), p_blkno,
4463 &first_bh, OCFS2_BH_CACHED, inode);
4464 if (ret) {
4465 mlog_errno(ret);
4466 return ret;
4467 }
4468
4469 ret = ocfs2_rm_xattr_bucket(inode, first_bh, &xs->bucket);
4470 if (ret) {
4471 mlog_errno(ret);
4472 goto out;
4473 }
4474
4475 first_xh = (struct ocfs2_xattr_header *)first_bh->b_data;
4476 if (first_xh->xh_num_buckets == 0)
4477 ret = ocfs2_rm_xattr_cluster(inode, xs->xattr_bh,
4478 p_blkno, e_cpos,
4479 num_clusters);
4480
4481out:
4482 brelse(first_bh);
4483 return ret;
4484}
4485
4486static void ocfs2_xattr_bucket_remove_xs(struct inode *inode, 4380static void ocfs2_xattr_bucket_remove_xs(struct inode *inode,
4487 struct ocfs2_xattr_search *xs) 4381 struct ocfs2_xattr_search *xs)
4488{ 4382{
@@ -4534,7 +4428,7 @@ static int ocfs2_xattr_set_in_bucket(struct inode *inode,
4534 struct ocfs2_xattr_info *xi, 4428 struct ocfs2_xattr_info *xi,
4535 struct ocfs2_xattr_search *xs) 4429 struct ocfs2_xattr_search *xs)
4536{ 4430{
4537 int ret, local = 1, bucket_empty = 0; 4431 int ret, local = 1;
4538 size_t value_len; 4432 size_t value_len;
4539 char *val = (char *)xi->value; 4433 char *val = (char *)xi->value;
4540 struct ocfs2_xattr_entry *xe = xs->here; 4434 struct ocfs2_xattr_entry *xe = xs->here;
@@ -4580,34 +4474,29 @@ static int ocfs2_xattr_set_in_bucket(struct inode *inode,
4580 xi->value_len = OCFS2_XATTR_ROOT_SIZE; 4474 xi->value_len = OCFS2_XATTR_ROOT_SIZE;
4581 } 4475 }
4582 4476
4583 ret = ocfs2_xattr_set_entry_in_bucket(inode, xi, xs, name_hash, 4477 ret = ocfs2_xattr_set_entry_in_bucket(inode, xi, xs, name_hash, local);
4584 local, &bucket_empty);
4585 if (ret) { 4478 if (ret) {
4586 mlog_errno(ret); 4479 mlog_errno(ret);
4587 goto out; 4480 goto out;
4588 } 4481 }
4589 4482
4590 if (value_len > OCFS2_XATTR_INLINE_SIZE) { 4483 if (value_len <= OCFS2_XATTR_INLINE_SIZE)
4591 /* allocate the space now for the outside block storage. */ 4484 goto out;
4592 ret = ocfs2_xattr_bucket_value_truncate_xs(inode, xs,
4593 value_len);
4594 if (ret) {
4595 mlog_errno(ret);
4596 4485
4597 if (xs->not_found) { 4486 /* allocate the space now for the outside block storage. */
4598 /* 4487 ret = ocfs2_xattr_bucket_value_truncate_xs(inode, xs,
4599 * We can't allocate enough clusters for outside 4488 value_len);
4600 * storage and we have allocated xattr already, 4489 if (ret) {
4601 * so need to remove it. 4490 mlog_errno(ret);
4602 */ 4491
4603 ocfs2_xattr_bucket_remove_xs(inode, xs); 4492 if (xs->not_found) {
4604 } 4493 /*
4605 goto out; 4494 * We can't allocate enough clusters for outside
4495 * storage and we have allocated xattr already,
4496 * so need to remove it.
4497 */
4498 ocfs2_xattr_bucket_remove_xs(inode, xs);
4606 } 4499 }
4607 } else {
4608 if (bucket_empty)
4609 ret = ocfs2_xattr_bucket_shrink(inode, xi,
4610 xs, name_hash);
4611 goto out; 4500 goto out;
4612 } 4501 }
4613 4502