diff options
Diffstat (limited to 'fs/ocfs2/xattr.c')
-rw-r--r-- | fs/ocfs2/xattr.c | 197 |
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 | */ | ||
4288 | static 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 | |||
4341 | out_commit: | ||
4342 | ocfs2_commit_trans(osb, handle); | ||
4343 | return ret; | ||
4344 | } | ||
4345 | |||
4346 | static int ocfs2_rm_xattr_cluster(struct inode *inode, | 4291 | static 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 | */ | ||
4439 | static 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 | |||
4481 | out: | ||
4482 | brelse(first_bh); | ||
4483 | return ret; | ||
4484 | } | ||
4485 | |||
4486 | static void ocfs2_xattr_bucket_remove_xs(struct inode *inode, | 4380 | static 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 | ||