diff options
| -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 | ||
