diff options
| author | Tao Ma <tao.ma@oracle.com> | 2009-08-17 23:43:17 -0400 |
|---|---|---|
| committer | Joel Becker <joel.becker@oracle.com> | 2009-09-22 23:09:41 -0400 |
| commit | 492a8a33e1cb966fa0b5756c5fc11d30c8f8848e (patch) | |
| tree | eacf691b07c8fa3e81c11ff1d6b8773c2dbb9e77 /fs | |
| parent | 913580b4cd445c4fb25d7cf167911a8cf6bdb1eb (diff) | |
ocfs2: Add CoW support for xattr.
In order to make 2 transcation(xattr and cow) independent with each other,
we CoW the whole xattr out in case we are setting them.
Signed-off-by: Tao Ma <tao.ma@oracle.com>
Diffstat (limited to 'fs')
| -rw-r--r-- | fs/ocfs2/refcounttree.c | 246 | ||||
| -rw-r--r-- | fs/ocfs2/refcounttree.h | 29 | ||||
| -rw-r--r-- | fs/ocfs2/xattr.c | 234 |
3 files changed, 494 insertions, 15 deletions
diff --git a/fs/ocfs2/refcounttree.c b/fs/ocfs2/refcounttree.c index 40de7bb9e9a6..a5b5bef054a7 100644 --- a/fs/ocfs2/refcounttree.c +++ b/fs/ocfs2/refcounttree.c | |||
| @@ -32,6 +32,7 @@ | |||
| 32 | #include "dlmglue.h" | 32 | #include "dlmglue.h" |
| 33 | #include "extent_map.h" | 33 | #include "extent_map.h" |
| 34 | #include "aops.h" | 34 | #include "aops.h" |
| 35 | #include "xattr.h" | ||
| 35 | 36 | ||
| 36 | #include <linux/bio.h> | 37 | #include <linux/bio.h> |
| 37 | #include <linux/blkdev.h> | 38 | #include <linux/blkdev.h> |
| @@ -51,6 +52,9 @@ struct ocfs2_cow_context { | |||
| 51 | struct ocfs2_alloc_context *meta_ac; | 52 | struct ocfs2_alloc_context *meta_ac; |
| 52 | struct ocfs2_alloc_context *data_ac; | 53 | struct ocfs2_alloc_context *data_ac; |
| 53 | struct ocfs2_cached_dealloc_ctxt dealloc; | 54 | struct ocfs2_cached_dealloc_ctxt dealloc; |
| 55 | void *cow_object; | ||
| 56 | struct ocfs2_post_refcount *post_refcount; | ||
| 57 | int extra_credits; | ||
| 54 | int (*get_clusters)(struct ocfs2_cow_context *context, | 58 | int (*get_clusters)(struct ocfs2_cow_context *context, |
| 55 | u32 v_cluster, u32 *p_cluster, | 59 | u32 v_cluster, u32 *p_cluster, |
| 56 | u32 *num_clusters, | 60 | u32 *num_clusters, |
| @@ -2848,6 +2852,65 @@ unlock: | |||
| 2848 | return ret; | 2852 | return ret; |
| 2849 | } | 2853 | } |
| 2850 | 2854 | ||
| 2855 | static int ocfs2_duplicate_clusters_by_jbd(handle_t *handle, | ||
| 2856 | struct ocfs2_cow_context *context, | ||
| 2857 | u32 cpos, u32 old_cluster, | ||
| 2858 | u32 new_cluster, u32 new_len) | ||
| 2859 | { | ||
| 2860 | int ret = 0; | ||
| 2861 | struct super_block *sb = context->inode->i_sb; | ||
| 2862 | struct ocfs2_caching_info *ci = context->data_et.et_ci; | ||
| 2863 | int i, blocks = ocfs2_clusters_to_blocks(sb, new_len); | ||
| 2864 | u64 old_block = ocfs2_clusters_to_blocks(sb, old_cluster); | ||
| 2865 | u64 new_block = ocfs2_clusters_to_blocks(sb, new_cluster); | ||
| 2866 | struct ocfs2_super *osb = OCFS2_SB(sb); | ||
| 2867 | struct buffer_head *old_bh = NULL; | ||
| 2868 | struct buffer_head *new_bh = NULL; | ||
| 2869 | |||
| 2870 | mlog(0, "old_cluster %u, new %u, len %u\n", old_cluster, | ||
| 2871 | new_cluster, new_len); | ||
| 2872 | |||
| 2873 | for (i = 0; i < blocks; i++, old_block++, new_block++) { | ||
| 2874 | new_bh = sb_getblk(osb->sb, new_block); | ||
| 2875 | if (new_bh == NULL) { | ||
| 2876 | ret = -EIO; | ||
| 2877 | mlog_errno(ret); | ||
| 2878 | break; | ||
| 2879 | } | ||
| 2880 | |||
| 2881 | ocfs2_set_new_buffer_uptodate(ci, new_bh); | ||
| 2882 | |||
| 2883 | ret = ocfs2_read_block(ci, old_block, &old_bh, NULL); | ||
| 2884 | if (ret) { | ||
| 2885 | mlog_errno(ret); | ||
| 2886 | break; | ||
| 2887 | } | ||
| 2888 | |||
| 2889 | ret = ocfs2_journal_access(handle, ci, new_bh, | ||
| 2890 | OCFS2_JOURNAL_ACCESS_CREATE); | ||
| 2891 | if (ret) { | ||
| 2892 | mlog_errno(ret); | ||
| 2893 | break; | ||
| 2894 | } | ||
| 2895 | |||
| 2896 | memcpy(new_bh->b_data, old_bh->b_data, sb->s_blocksize); | ||
| 2897 | ret = ocfs2_journal_dirty(handle, new_bh); | ||
| 2898 | if (ret) { | ||
| 2899 | mlog_errno(ret); | ||
| 2900 | break; | ||
| 2901 | } | ||
| 2902 | |||
| 2903 | brelse(new_bh); | ||
| 2904 | brelse(old_bh); | ||
| 2905 | new_bh = NULL; | ||
| 2906 | old_bh = NULL; | ||
| 2907 | } | ||
| 2908 | |||
| 2909 | brelse(new_bh); | ||
| 2910 | brelse(old_bh); | ||
| 2911 | return ret; | ||
| 2912 | } | ||
| 2913 | |||
| 2851 | static int ocfs2_clear_ext_refcount(handle_t *handle, | 2914 | static int ocfs2_clear_ext_refcount(handle_t *handle, |
| 2852 | struct ocfs2_extent_tree *et, | 2915 | struct ocfs2_extent_tree *et, |
| 2853 | u32 cpos, u32 p_cluster, u32 len, | 2916 | u32 cpos, u32 p_cluster, u32 len, |
| @@ -3026,6 +3089,10 @@ static int ocfs2_make_clusters_writable(struct super_block *sb, | |||
| 3026 | return ret; | 3089 | return ret; |
| 3027 | } | 3090 | } |
| 3028 | 3091 | ||
| 3092 | if (context->post_refcount) | ||
| 3093 | credits += context->post_refcount->credits; | ||
| 3094 | |||
| 3095 | credits += context->extra_credits; | ||
| 3029 | handle = ocfs2_start_trans(osb, credits); | 3096 | handle = ocfs2_start_trans(osb, credits); |
| 3030 | if (IS_ERR(handle)) { | 3097 | if (IS_ERR(handle)) { |
| 3031 | ret = PTR_ERR(handle); | 3098 | ret = PTR_ERR(handle); |
| @@ -3105,13 +3172,25 @@ static int ocfs2_make_clusters_writable(struct super_block *sb, | |||
| 3105 | ref_leaf_bh = NULL; | 3172 | ref_leaf_bh = NULL; |
| 3106 | } | 3173 | } |
| 3107 | 3174 | ||
| 3175 | /* handle any post_cow action. */ | ||
| 3176 | if (context->post_refcount && context->post_refcount->func) { | ||
| 3177 | ret = context->post_refcount->func(context->inode, handle, | ||
| 3178 | context->post_refcount->para); | ||
| 3179 | if (ret) { | ||
| 3180 | mlog_errno(ret); | ||
| 3181 | goto out_commit; | ||
| 3182 | } | ||
| 3183 | } | ||
| 3184 | |||
| 3108 | /* | 3185 | /* |
| 3109 | * Here we should write the new page out first if we are | 3186 | * Here we should write the new page out first if we are |
| 3110 | * in write-back mode. | 3187 | * in write-back mode. |
| 3111 | */ | 3188 | */ |
| 3112 | ret = ocfs2_cow_sync_writeback(sb, context, cpos, num_clusters); | 3189 | if (context->get_clusters == ocfs2_di_get_clusters) { |
| 3113 | if (ret) | 3190 | ret = ocfs2_cow_sync_writeback(sb, context, cpos, num_clusters); |
| 3114 | mlog_errno(ret); | 3191 | if (ret) |
| 3192 | mlog_errno(ret); | ||
| 3193 | } | ||
| 3115 | 3194 | ||
| 3116 | out_commit: | 3195 | out_commit: |
| 3117 | ocfs2_commit_trans(osb, handle); | 3196 | ocfs2_commit_trans(osb, handle); |
| @@ -3298,6 +3377,167 @@ int ocfs2_refcount_cow(struct inode *inode, | |||
| 3298 | return ret; | 3377 | return ret; |
| 3299 | } | 3378 | } |
| 3300 | 3379 | ||
| 3380 | static int ocfs2_xattr_value_get_clusters(struct ocfs2_cow_context *context, | ||
| 3381 | u32 v_cluster, u32 *p_cluster, | ||
| 3382 | u32 *num_clusters, | ||
| 3383 | unsigned int *extent_flags) | ||
| 3384 | { | ||
| 3385 | struct inode *inode = context->inode; | ||
| 3386 | struct ocfs2_xattr_value_root *xv = context->cow_object; | ||
| 3387 | |||
| 3388 | return ocfs2_xattr_get_clusters(inode, v_cluster, p_cluster, | ||
| 3389 | num_clusters, &xv->xr_list, | ||
| 3390 | extent_flags); | ||
| 3391 | } | ||
| 3392 | |||
| 3393 | /* | ||
| 3394 | * Given a xattr value root, calculate the most meta/credits we need for | ||
| 3395 | * refcount tree change if we truncate it to 0. | ||
| 3396 | */ | ||
| 3397 | int ocfs2_refcounted_xattr_delete_need(struct inode *inode, | ||
| 3398 | struct ocfs2_caching_info *ref_ci, | ||
| 3399 | struct buffer_head *ref_root_bh, | ||
| 3400 | struct ocfs2_xattr_value_root *xv, | ||
| 3401 | int *meta_add, int *credits) | ||
| 3402 | { | ||
| 3403 | int ret = 0, index, ref_blocks = 0; | ||
| 3404 | u32 p_cluster, num_clusters; | ||
| 3405 | u32 cpos = 0, clusters = le32_to_cpu(xv->xr_clusters); | ||
| 3406 | struct ocfs2_refcount_block *rb; | ||
| 3407 | struct ocfs2_refcount_rec rec; | ||
| 3408 | struct buffer_head *ref_leaf_bh = NULL; | ||
| 3409 | |||
| 3410 | while (cpos < clusters) { | ||
| 3411 | ret = ocfs2_xattr_get_clusters(inode, cpos, &p_cluster, | ||
| 3412 | &num_clusters, &xv->xr_list, | ||
| 3413 | NULL); | ||
| 3414 | if (ret) { | ||
| 3415 | mlog_errno(ret); | ||
| 3416 | goto out; | ||
| 3417 | } | ||
| 3418 | |||
| 3419 | cpos += num_clusters; | ||
| 3420 | |||
| 3421 | while (num_clusters) { | ||
| 3422 | ret = ocfs2_get_refcount_rec(ref_ci, ref_root_bh, | ||
| 3423 | p_cluster, num_clusters, | ||
| 3424 | &rec, &index, | ||
| 3425 | &ref_leaf_bh); | ||
| 3426 | if (ret) { | ||
| 3427 | mlog_errno(ret); | ||
| 3428 | goto out; | ||
| 3429 | } | ||
| 3430 | |||
| 3431 | BUG_ON(!rec.r_refcount); | ||
| 3432 | |||
| 3433 | rb = (struct ocfs2_refcount_block *)ref_leaf_bh->b_data; | ||
| 3434 | |||
| 3435 | /* | ||
| 3436 | * We really don't know whether the other clusters is in | ||
| 3437 | * this refcount block or not, so just take the worst | ||
| 3438 | * case that all the clusters are in this block and each | ||
| 3439 | * one will split a refcount rec, so totally we need | ||
| 3440 | * clusters * 2 new refcount rec. | ||
| 3441 | */ | ||
| 3442 | if (le64_to_cpu(rb->rf_records.rl_used) + clusters * 2 > | ||
| 3443 | le16_to_cpu(rb->rf_records.rl_count)) | ||
| 3444 | ref_blocks++; | ||
| 3445 | |||
| 3446 | *credits += 1; | ||
| 3447 | brelse(ref_leaf_bh); | ||
| 3448 | ref_leaf_bh = NULL; | ||
| 3449 | |||
| 3450 | if (num_clusters <= le32_to_cpu(rec.r_clusters)) | ||
| 3451 | break; | ||
| 3452 | else | ||
| 3453 | num_clusters -= le32_to_cpu(rec.r_clusters); | ||
| 3454 | p_cluster += num_clusters; | ||
| 3455 | } | ||
| 3456 | } | ||
| 3457 | |||
| 3458 | *meta_add += ref_blocks; | ||
| 3459 | if (!ref_blocks) | ||
| 3460 | goto out; | ||
| 3461 | |||
| 3462 | rb = (struct ocfs2_refcount_block *)ref_root_bh->b_data; | ||
| 3463 | if (le32_to_cpu(rb->rf_flags) & OCFS2_REFCOUNT_TREE_FL) | ||
| 3464 | *credits += OCFS2_EXPAND_REFCOUNT_TREE_CREDITS; | ||
| 3465 | else { | ||
| 3466 | struct ocfs2_extent_tree et; | ||
| 3467 | |||
| 3468 | ocfs2_init_refcount_extent_tree(&et, ref_ci, ref_root_bh); | ||
| 3469 | *credits += ocfs2_calc_extend_credits(inode->i_sb, | ||
| 3470 | et.et_root_el, | ||
| 3471 | ref_blocks); | ||
| 3472 | } | ||
| 3473 | |||
| 3474 | out: | ||
| 3475 | brelse(ref_leaf_bh); | ||
| 3476 | return ret; | ||
| 3477 | } | ||
| 3478 | |||
| 3479 | /* | ||
| 3480 | * Do CoW for xattr. | ||
| 3481 | */ | ||
| 3482 | int ocfs2_refcount_cow_xattr(struct inode *inode, | ||
| 3483 | struct ocfs2_dinode *di, | ||
| 3484 | struct ocfs2_xattr_value_buf *vb, | ||
| 3485 | struct ocfs2_refcount_tree *ref_tree, | ||
| 3486 | struct buffer_head *ref_root_bh, | ||
| 3487 | u32 cpos, u32 write_len, | ||
| 3488 | struct ocfs2_post_refcount *post) | ||
| 3489 | { | ||
| 3490 | int ret; | ||
| 3491 | struct ocfs2_xattr_value_root *xv = vb->vb_xv; | ||
| 3492 | struct ocfs2_inode_info *oi = OCFS2_I(inode); | ||
| 3493 | struct ocfs2_cow_context *context = NULL; | ||
| 3494 | u32 cow_start, cow_len; | ||
| 3495 | |||
| 3496 | BUG_ON(!(oi->ip_dyn_features & OCFS2_HAS_REFCOUNT_FL)); | ||
| 3497 | |||
| 3498 | ret = ocfs2_refcount_cal_cow_clusters(inode, &xv->xr_list, | ||
| 3499 | cpos, write_len, UINT_MAX, | ||
| 3500 | &cow_start, &cow_len); | ||
| 3501 | if (ret) { | ||
| 3502 | mlog_errno(ret); | ||
| 3503 | goto out; | ||
| 3504 | } | ||
| 3505 | |||
| 3506 | BUG_ON(cow_len == 0); | ||
| 3507 | |||
| 3508 | context = kzalloc(sizeof(struct ocfs2_cow_context), GFP_NOFS); | ||
| 3509 | if (!context) { | ||
| 3510 | ret = -ENOMEM; | ||
| 3511 | mlog_errno(ret); | ||
| 3512 | goto out; | ||
| 3513 | } | ||
| 3514 | |||
| 3515 | context->inode = inode; | ||
| 3516 | context->cow_start = cow_start; | ||
| 3517 | context->cow_len = cow_len; | ||
| 3518 | context->ref_tree = ref_tree; | ||
| 3519 | context->ref_root_bh = ref_root_bh;; | ||
| 3520 | context->cow_object = xv; | ||
| 3521 | |||
| 3522 | context->cow_duplicate_clusters = ocfs2_duplicate_clusters_by_jbd; | ||
| 3523 | /* We need the extra credits for duplicate_clusters by jbd. */ | ||
| 3524 | context->extra_credits = | ||
| 3525 | ocfs2_clusters_to_blocks(inode->i_sb, 1) * cow_len; | ||
| 3526 | context->get_clusters = ocfs2_xattr_value_get_clusters; | ||
| 3527 | context->post_refcount = post; | ||
| 3528 | |||
| 3529 | ocfs2_init_xattr_value_extent_tree(&context->data_et, | ||
| 3530 | INODE_CACHE(inode), vb); | ||
| 3531 | |||
| 3532 | ret = ocfs2_replace_cow(context); | ||
| 3533 | if (ret) | ||
| 3534 | mlog_errno(ret); | ||
| 3535 | |||
| 3536 | out: | ||
| 3537 | kfree(context); | ||
| 3538 | return ret; | ||
| 3539 | } | ||
| 3540 | |||
| 3301 | /* | 3541 | /* |
| 3302 | * Insert a new extent into refcount tree and mark a extent rec | 3542 | * Insert a new extent into refcount tree and mark a extent rec |
| 3303 | * as refcounted in the dinode tree. | 3543 | * as refcounted in the dinode tree. |
diff --git a/fs/ocfs2/refcounttree.h b/fs/ocfs2/refcounttree.h index 356f99c85635..d09d64b29810 100644 --- a/fs/ocfs2/refcounttree.h +++ b/fs/ocfs2/refcounttree.h | |||
| @@ -54,4 +54,33 @@ int ocfs2_prepare_refcount_change_for_del(struct inode *inode, | |||
| 54 | struct ocfs2_alloc_context **meta_ac); | 54 | struct ocfs2_alloc_context **meta_ac); |
| 55 | int ocfs2_refcount_cow(struct inode *inode, struct buffer_head *di_bh, | 55 | int ocfs2_refcount_cow(struct inode *inode, struct buffer_head *di_bh, |
| 56 | u32 cpos, u32 write_len, u32 max_cpos); | 56 | u32 cpos, u32 write_len, u32 max_cpos); |
| 57 | |||
| 58 | typedef int (ocfs2_post_refcount_func)(struct inode *inode, | ||
| 59 | handle_t *handle, | ||
| 60 | void *para); | ||
| 61 | /* | ||
| 62 | * Some refcount caller need to do more work after we modify the data b-tree | ||
| 63 | * during refcount operation(including CoW and add refcount flag), and make the | ||
| 64 | * transaction complete. So it must give us this structure so that we can do it | ||
| 65 | * within our transaction. | ||
| 66 | * | ||
| 67 | */ | ||
| 68 | struct ocfs2_post_refcount { | ||
| 69 | int credits; /* credits it need for journal. */ | ||
| 70 | ocfs2_post_refcount_func *func; /* real function. */ | ||
| 71 | void *para; | ||
| 72 | }; | ||
| 73 | |||
| 74 | int ocfs2_refcounted_xattr_delete_need(struct inode *inode, | ||
| 75 | struct ocfs2_caching_info *ref_ci, | ||
| 76 | struct buffer_head *ref_root_bh, | ||
| 77 | struct ocfs2_xattr_value_root *xv, | ||
| 78 | int *meta_add, int *credits); | ||
| 79 | int ocfs2_refcount_cow_xattr(struct inode *inode, | ||
| 80 | struct ocfs2_dinode *di, | ||
| 81 | struct ocfs2_xattr_value_buf *vb, | ||
| 82 | struct ocfs2_refcount_tree *ref_tree, | ||
| 83 | struct buffer_head *ref_root_bh, | ||
| 84 | u32 cpos, u32 write_len, | ||
| 85 | struct ocfs2_post_refcount *post); | ||
| 57 | #endif /* OCFS2_REFCOUNTTREE_H */ | 86 | #endif /* OCFS2_REFCOUNTTREE_H */ |
diff --git a/fs/ocfs2/xattr.c b/fs/ocfs2/xattr.c index dda49c00362a..a538cebbe9c5 100644 --- a/fs/ocfs2/xattr.c +++ b/fs/ocfs2/xattr.c | |||
| @@ -55,7 +55,7 @@ | |||
| 55 | #include "buffer_head_io.h" | 55 | #include "buffer_head_io.h" |
| 56 | #include "super.h" | 56 | #include "super.h" |
| 57 | #include "xattr.h" | 57 | #include "xattr.h" |
| 58 | 58 | #include "refcounttree.h" | |
| 59 | 59 | ||
| 60 | struct ocfs2_xattr_def_value_root { | 60 | struct ocfs2_xattr_def_value_root { |
| 61 | struct ocfs2_xattr_value_root xv; | 61 | struct ocfs2_xattr_value_root xv; |
| @@ -176,6 +176,14 @@ static int ocfs2_mv_xattr_buckets(struct inode *inode, handle_t *handle, | |||
| 176 | u64 src_blk, u64 last_blk, u64 to_blk, | 176 | u64 src_blk, u64 last_blk, u64 to_blk, |
| 177 | unsigned int start_bucket, | 177 | unsigned int start_bucket, |
| 178 | u32 *first_hash); | 178 | u32 *first_hash); |
| 179 | static int ocfs2_prepare_refcount_xattr(struct inode *inode, | ||
| 180 | struct ocfs2_dinode *di, | ||
| 181 | struct ocfs2_xattr_info *xi, | ||
| 182 | struct ocfs2_xattr_search *xis, | ||
| 183 | struct ocfs2_xattr_search *xbs, | ||
| 184 | struct ocfs2_refcount_tree **ref_tree, | ||
| 185 | int *meta_need, | ||
| 186 | int *credits); | ||
| 179 | 187 | ||
| 180 | static inline u16 ocfs2_xattr_buckets_per_cluster(struct ocfs2_super *osb) | 188 | static inline u16 ocfs2_xattr_buckets_per_cluster(struct ocfs2_super *osb) |
| 181 | { | 189 | { |
| @@ -647,6 +655,7 @@ leave: | |||
| 647 | static int __ocfs2_remove_xattr_range(struct inode *inode, | 655 | static int __ocfs2_remove_xattr_range(struct inode *inode, |
| 648 | struct ocfs2_xattr_value_buf *vb, | 656 | struct ocfs2_xattr_value_buf *vb, |
| 649 | u32 cpos, u32 phys_cpos, u32 len, | 657 | u32 cpos, u32 phys_cpos, u32 len, |
| 658 | unsigned int ext_flags, | ||
| 650 | struct ocfs2_xattr_set_ctxt *ctxt) | 659 | struct ocfs2_xattr_set_ctxt *ctxt) |
| 651 | { | 660 | { |
| 652 | int ret; | 661 | int ret; |
| @@ -678,7 +687,14 @@ static int __ocfs2_remove_xattr_range(struct inode *inode, | |||
| 678 | goto out; | 687 | goto out; |
| 679 | } | 688 | } |
| 680 | 689 | ||
| 681 | ret = ocfs2_cache_cluster_dealloc(&ctxt->dealloc, phys_blkno, len); | 690 | if (ext_flags & OCFS2_EXT_REFCOUNTED) |
| 691 | ret = ocfs2_decrease_refcount(inode, handle, | ||
| 692 | ocfs2_blocks_to_clusters(inode->i_sb, | ||
| 693 | phys_blkno), | ||
| 694 | len, ctxt->meta_ac, &ctxt->dealloc, 1); | ||
| 695 | else | ||
| 696 | ret = ocfs2_cache_cluster_dealloc(&ctxt->dealloc, | ||
| 697 | phys_blkno, len); | ||
| 682 | if (ret) | 698 | if (ret) |
| 683 | mlog_errno(ret); | 699 | mlog_errno(ret); |
| 684 | 700 | ||
| @@ -693,6 +709,7 @@ static int ocfs2_xattr_shrink_size(struct inode *inode, | |||
| 693 | struct ocfs2_xattr_set_ctxt *ctxt) | 709 | struct ocfs2_xattr_set_ctxt *ctxt) |
| 694 | { | 710 | { |
| 695 | int ret = 0; | 711 | int ret = 0; |
| 712 | unsigned int ext_flags; | ||
| 696 | u32 trunc_len, cpos, phys_cpos, alloc_size; | 713 | u32 trunc_len, cpos, phys_cpos, alloc_size; |
| 697 | u64 block; | 714 | u64 block; |
| 698 | 715 | ||
| @@ -704,7 +721,7 @@ static int ocfs2_xattr_shrink_size(struct inode *inode, | |||
| 704 | while (trunc_len) { | 721 | while (trunc_len) { |
| 705 | ret = ocfs2_xattr_get_clusters(inode, cpos, &phys_cpos, | 722 | ret = ocfs2_xattr_get_clusters(inode, cpos, &phys_cpos, |
| 706 | &alloc_size, | 723 | &alloc_size, |
| 707 | &vb->vb_xv->xr_list, NULL); | 724 | &vb->vb_xv->xr_list, &ext_flags); |
| 708 | if (ret) { | 725 | if (ret) { |
| 709 | mlog_errno(ret); | 726 | mlog_errno(ret); |
| 710 | goto out; | 727 | goto out; |
| @@ -715,7 +732,7 @@ static int ocfs2_xattr_shrink_size(struct inode *inode, | |||
| 715 | 732 | ||
| 716 | ret = __ocfs2_remove_xattr_range(inode, vb, cpos, | 733 | ret = __ocfs2_remove_xattr_range(inode, vb, cpos, |
| 717 | phys_cpos, alloc_size, | 734 | phys_cpos, alloc_size, |
| 718 | ctxt); | 735 | ext_flags, ctxt); |
| 719 | if (ret) { | 736 | if (ret) { |
| 720 | mlog_errno(ret); | 737 | mlog_errno(ret); |
| 721 | goto out; | 738 | goto out; |
| @@ -1182,7 +1199,7 @@ static int ocfs2_xattr_get(struct inode *inode, | |||
| 1182 | 1199 | ||
| 1183 | static int __ocfs2_xattr_set_value_outside(struct inode *inode, | 1200 | static int __ocfs2_xattr_set_value_outside(struct inode *inode, |
| 1184 | handle_t *handle, | 1201 | handle_t *handle, |
| 1185 | struct ocfs2_xattr_value_root *xv, | 1202 | struct ocfs2_xattr_value_buf *vb, |
| 1186 | const void *value, | 1203 | const void *value, |
| 1187 | int value_len) | 1204 | int value_len) |
| 1188 | { | 1205 | { |
| @@ -1193,18 +1210,22 @@ static int __ocfs2_xattr_set_value_outside(struct inode *inode, | |||
| 1193 | u32 clusters = ocfs2_clusters_for_bytes(inode->i_sb, value_len); | 1210 | u32 clusters = ocfs2_clusters_for_bytes(inode->i_sb, value_len); |
| 1194 | u64 blkno; | 1211 | u64 blkno; |
| 1195 | struct buffer_head *bh = NULL; | 1212 | struct buffer_head *bh = NULL; |
| 1213 | unsigned int ext_flags; | ||
| 1214 | struct ocfs2_xattr_value_root *xv = vb->vb_xv; | ||
| 1196 | 1215 | ||
| 1197 | BUG_ON(clusters > le32_to_cpu(xv->xr_clusters)); | 1216 | BUG_ON(clusters > le32_to_cpu(xv->xr_clusters)); |
| 1198 | 1217 | ||
| 1199 | while (cpos < clusters) { | 1218 | while (cpos < clusters) { |
| 1200 | ret = ocfs2_xattr_get_clusters(inode, cpos, &p_cluster, | 1219 | ret = ocfs2_xattr_get_clusters(inode, cpos, &p_cluster, |
| 1201 | &num_clusters, &xv->xr_list, | 1220 | &num_clusters, &xv->xr_list, |
| 1202 | NULL); | 1221 | &ext_flags); |
| 1203 | if (ret) { | 1222 | if (ret) { |
| 1204 | mlog_errno(ret); | 1223 | mlog_errno(ret); |
| 1205 | goto out; | 1224 | goto out; |
| 1206 | } | 1225 | } |
| 1207 | 1226 | ||
| 1227 | BUG_ON(ext_flags & OCFS2_EXT_REFCOUNTED); | ||
| 1228 | |||
| 1208 | blkno = ocfs2_clusters_to_blocks(inode->i_sb, p_cluster); | 1229 | blkno = ocfs2_clusters_to_blocks(inode->i_sb, p_cluster); |
| 1209 | 1230 | ||
| 1210 | for (i = 0; i < num_clusters * bpc; i++, blkno++) { | 1231 | for (i = 0; i < num_clusters * bpc; i++, blkno++) { |
| @@ -1356,7 +1377,7 @@ static int ocfs2_xattr_set_value_outside(struct inode *inode, | |||
| 1356 | mlog_errno(ret); | 1377 | mlog_errno(ret); |
| 1357 | return ret; | 1378 | return ret; |
| 1358 | } | 1379 | } |
| 1359 | ret = __ocfs2_xattr_set_value_outside(inode, ctxt->handle, vb->vb_xv, | 1380 | ret = __ocfs2_xattr_set_value_outside(inode, ctxt->handle, vb, |
| 1360 | xi->value, xi->value_len); | 1381 | xi->value, xi->value_len); |
| 1361 | if (ret < 0) | 1382 | if (ret < 0) |
| 1362 | mlog_errno(ret); | 1383 | mlog_errno(ret); |
| @@ -1595,7 +1616,7 @@ static int ocfs2_xattr_set_entry(struct inode *inode, | |||
| 1595 | 1616 | ||
| 1596 | ret = __ocfs2_xattr_set_value_outside(inode, | 1617 | ret = __ocfs2_xattr_set_value_outside(inode, |
| 1597 | handle, | 1618 | handle, |
| 1598 | vb.vb_xv, | 1619 | &vb, |
| 1599 | xi->value, | 1620 | xi->value, |
| 1600 | xi->value_len); | 1621 | xi->value_len); |
| 1601 | if (ret < 0) | 1622 | if (ret < 0) |
| @@ -2431,6 +2452,7 @@ static int ocfs2_init_xattr_set_ctxt(struct inode *inode, | |||
| 2431 | struct ocfs2_xattr_search *xis, | 2452 | struct ocfs2_xattr_search *xis, |
| 2432 | struct ocfs2_xattr_search *xbs, | 2453 | struct ocfs2_xattr_search *xbs, |
| 2433 | struct ocfs2_xattr_set_ctxt *ctxt, | 2454 | struct ocfs2_xattr_set_ctxt *ctxt, |
| 2455 | int extra_meta, | ||
| 2434 | int *credits) | 2456 | int *credits) |
| 2435 | { | 2457 | { |
| 2436 | int clusters_add, meta_add, ret; | 2458 | int clusters_add, meta_add, ret; |
| @@ -2447,6 +2469,7 @@ static int ocfs2_init_xattr_set_ctxt(struct inode *inode, | |||
| 2447 | return ret; | 2469 | return ret; |
| 2448 | } | 2470 | } |
| 2449 | 2471 | ||
| 2472 | meta_add += extra_meta; | ||
| 2450 | mlog(0, "Set xattr %s, reserve meta blocks = %d, clusters = %d, " | 2473 | mlog(0, "Set xattr %s, reserve meta blocks = %d, clusters = %d, " |
| 2451 | "credits = %d\n", xi->name, meta_add, clusters_add, *credits); | 2474 | "credits = %d\n", xi->name, meta_add, clusters_add, *credits); |
| 2452 | 2475 | ||
| @@ -2714,10 +2737,11 @@ int ocfs2_xattr_set(struct inode *inode, | |||
| 2714 | { | 2737 | { |
| 2715 | struct buffer_head *di_bh = NULL; | 2738 | struct buffer_head *di_bh = NULL; |
| 2716 | struct ocfs2_dinode *di; | 2739 | struct ocfs2_dinode *di; |
| 2717 | int ret, credits; | 2740 | int ret, credits, ref_meta = 0, ref_credits = 0; |
| 2718 | struct ocfs2_super *osb = OCFS2_SB(inode->i_sb); | 2741 | struct ocfs2_super *osb = OCFS2_SB(inode->i_sb); |
| 2719 | struct inode *tl_inode = osb->osb_tl_inode; | 2742 | struct inode *tl_inode = osb->osb_tl_inode; |
| 2720 | struct ocfs2_xattr_set_ctxt ctxt = { NULL, NULL, }; | 2743 | struct ocfs2_xattr_set_ctxt ctxt = { NULL, NULL, }; |
| 2744 | struct ocfs2_refcount_tree *ref_tree = NULL; | ||
| 2721 | 2745 | ||
| 2722 | struct ocfs2_xattr_info xi = { | 2746 | struct ocfs2_xattr_info xi = { |
| 2723 | .name_index = name_index, | 2747 | .name_index = name_index, |
| @@ -2782,6 +2806,17 @@ int ocfs2_xattr_set(struct inode *inode, | |||
| 2782 | goto cleanup; | 2806 | goto cleanup; |
| 2783 | } | 2807 | } |
| 2784 | 2808 | ||
| 2809 | /* Check whether the value is refcounted and do some prepartion. */ | ||
| 2810 | if (OCFS2_I(inode)->ip_dyn_features & OCFS2_HAS_REFCOUNT_FL && | ||
| 2811 | (!xis.not_found || !xbs.not_found)) { | ||
| 2812 | ret = ocfs2_prepare_refcount_xattr(inode, di, &xi, | ||
| 2813 | &xis, &xbs, &ref_tree, | ||
| 2814 | &ref_meta, &ref_credits); | ||
| 2815 | if (ret) { | ||
| 2816 | mlog_errno(ret); | ||
| 2817 | goto cleanup; | ||
| 2818 | } | ||
| 2819 | } | ||
| 2785 | 2820 | ||
| 2786 | mutex_lock(&tl_inode->i_mutex); | 2821 | mutex_lock(&tl_inode->i_mutex); |
| 2787 | 2822 | ||
| @@ -2796,7 +2831,7 @@ int ocfs2_xattr_set(struct inode *inode, | |||
| 2796 | mutex_unlock(&tl_inode->i_mutex); | 2831 | mutex_unlock(&tl_inode->i_mutex); |
| 2797 | 2832 | ||
| 2798 | ret = ocfs2_init_xattr_set_ctxt(inode, di, &xi, &xis, | 2833 | ret = ocfs2_init_xattr_set_ctxt(inode, di, &xi, &xis, |
| 2799 | &xbs, &ctxt, &credits); | 2834 | &xbs, &ctxt, ref_meta, &credits); |
| 2800 | if (ret) { | 2835 | if (ret) { |
| 2801 | mlog_errno(ret); | 2836 | mlog_errno(ret); |
| 2802 | goto cleanup; | 2837 | goto cleanup; |
| @@ -2804,7 +2839,7 @@ int ocfs2_xattr_set(struct inode *inode, | |||
| 2804 | 2839 | ||
| 2805 | /* we need to update inode's ctime field, so add credit for it. */ | 2840 | /* we need to update inode's ctime field, so add credit for it. */ |
| 2806 | credits += OCFS2_INODE_UPDATE_CREDITS; | 2841 | credits += OCFS2_INODE_UPDATE_CREDITS; |
| 2807 | ctxt.handle = ocfs2_start_trans(osb, credits); | 2842 | ctxt.handle = ocfs2_start_trans(osb, credits + ref_credits); |
| 2808 | if (IS_ERR(ctxt.handle)) { | 2843 | if (IS_ERR(ctxt.handle)) { |
| 2809 | ret = PTR_ERR(ctxt.handle); | 2844 | ret = PTR_ERR(ctxt.handle); |
| 2810 | mlog_errno(ret); | 2845 | mlog_errno(ret); |
| @@ -2823,6 +2858,8 @@ int ocfs2_xattr_set(struct inode *inode, | |||
| 2823 | ocfs2_schedule_truncate_log_flush(osb, 1); | 2858 | ocfs2_schedule_truncate_log_flush(osb, 1); |
| 2824 | ocfs2_run_deallocs(osb, &ctxt.dealloc); | 2859 | ocfs2_run_deallocs(osb, &ctxt.dealloc); |
| 2825 | cleanup: | 2860 | cleanup: |
| 2861 | if (ref_tree) | ||
| 2862 | ocfs2_unlock_refcount_tree(osb, ref_tree, 1); | ||
| 2826 | up_write(&OCFS2_I(inode)->ip_xattr_sem); | 2863 | up_write(&OCFS2_I(inode)->ip_xattr_sem); |
| 2827 | ocfs2_inode_unlock(inode, 1); | 2864 | ocfs2_inode_unlock(inode, 1); |
| 2828 | cleanup_nolock: | 2865 | cleanup_nolock: |
| @@ -4802,6 +4839,9 @@ static int ocfs2_xattr_bucket_set_value_outside(struct inode *inode, | |||
| 4802 | struct ocfs2_xattr_entry *xe = xs->here; | 4839 | struct ocfs2_xattr_entry *xe = xs->here; |
| 4803 | struct ocfs2_xattr_header *xh = bucket_xh(xs->bucket); | 4840 | struct ocfs2_xattr_header *xh = bucket_xh(xs->bucket); |
| 4804 | void *base; | 4841 | void *base; |
| 4842 | struct ocfs2_xattr_value_buf vb = { | ||
| 4843 | .vb_access = ocfs2_journal_access, | ||
| 4844 | }; | ||
| 4805 | 4845 | ||
| 4806 | BUG_ON(!xs->base || !xe || ocfs2_xattr_is_local(xe)); | 4846 | BUG_ON(!xs->base || !xe || ocfs2_xattr_is_local(xe)); |
| 4807 | 4847 | ||
| @@ -4818,8 +4858,10 @@ static int ocfs2_xattr_bucket_set_value_outside(struct inode *inode, | |||
| 4818 | xv = (struct ocfs2_xattr_value_root *)(base + offset + | 4858 | xv = (struct ocfs2_xattr_value_root *)(base + offset + |
| 4819 | OCFS2_XATTR_SIZE(xe->xe_name_len)); | 4859 | OCFS2_XATTR_SIZE(xe->xe_name_len)); |
| 4820 | 4860 | ||
| 4861 | vb.vb_xv = xv; | ||
| 4862 | vb.vb_bh = xs->bucket->bu_bhs[block_off]; | ||
| 4821 | ret = __ocfs2_xattr_set_value_outside(inode, handle, | 4863 | ret = __ocfs2_xattr_set_value_outside(inode, handle, |
| 4822 | xv, val, value_len); | 4864 | &vb, val, value_len); |
| 4823 | if (ret) | 4865 | if (ret) |
| 4824 | mlog_errno(ret); | 4866 | mlog_errno(ret); |
| 4825 | out: | 4867 | out: |
| @@ -5311,6 +5353,174 @@ out: | |||
| 5311 | } | 5353 | } |
| 5312 | 5354 | ||
| 5313 | /* | 5355 | /* |
| 5356 | * Whenever we modify a xattr value root in the bucket(e.g, CoW | ||
| 5357 | * or change the extent record flag), we need to recalculate | ||
| 5358 | * the metaecc for the whole bucket. So it is done here. | ||
| 5359 | * | ||
| 5360 | * Note: | ||
| 5361 | * We have to give the extra credits for the caller. | ||
| 5362 | */ | ||
| 5363 | static int ocfs2_xattr_bucket_post_refcount(struct inode *inode, | ||
| 5364 | handle_t *handle, | ||
| 5365 | void *para) | ||
| 5366 | { | ||
| 5367 | int ret; | ||
| 5368 | struct ocfs2_xattr_bucket *bucket = | ||
| 5369 | (struct ocfs2_xattr_bucket *)para; | ||
| 5370 | |||
| 5371 | ret = ocfs2_xattr_bucket_journal_access(handle, bucket, | ||
| 5372 | OCFS2_JOURNAL_ACCESS_WRITE); | ||
| 5373 | if (ret) { | ||
| 5374 | mlog_errno(ret); | ||
| 5375 | return ret; | ||
| 5376 | } | ||
| 5377 | |||
| 5378 | ocfs2_xattr_bucket_journal_dirty(handle, bucket); | ||
| 5379 | |||
| 5380 | return 0; | ||
| 5381 | } | ||
| 5382 | |||
| 5383 | /* | ||
| 5384 | * Special action we need if the xattr value is refcounted. | ||
| 5385 | * | ||
| 5386 | * 1. If the xattr is refcounted, lock the tree. | ||
| 5387 | * 2. CoW the xattr if we are setting the new value and the value | ||
| 5388 | * will be stored outside. | ||
| 5389 | * 3. In other case, decrease_refcount will work for us, so just | ||
| 5390 | * lock the refcount tree, calculate the meta and credits is OK. | ||
| 5391 | * | ||
| 5392 | * We have to do CoW before ocfs2_init_xattr_set_ctxt since | ||
| 5393 | * currently CoW is a completed transaction, while this function | ||
| 5394 | * will also lock the allocators and let us deadlock. So we will | ||
| 5395 | * CoW the whole xattr value. | ||
| 5396 | */ | ||
| 5397 | static int ocfs2_prepare_refcount_xattr(struct inode *inode, | ||
| 5398 | struct ocfs2_dinode *di, | ||
| 5399 | struct ocfs2_xattr_info *xi, | ||
| 5400 | struct ocfs2_xattr_search *xis, | ||
| 5401 | struct ocfs2_xattr_search *xbs, | ||
| 5402 | struct ocfs2_refcount_tree **ref_tree, | ||
| 5403 | int *meta_add, | ||
| 5404 | int *credits) | ||
| 5405 | { | ||
| 5406 | int ret = 0; | ||
| 5407 | struct ocfs2_xattr_block *xb; | ||
| 5408 | struct ocfs2_xattr_entry *xe; | ||
| 5409 | char *base; | ||
| 5410 | u32 p_cluster, num_clusters; | ||
| 5411 | unsigned int ext_flags; | ||
| 5412 | int name_offset, name_len; | ||
| 5413 | struct ocfs2_xattr_value_buf vb; | ||
| 5414 | struct ocfs2_xattr_bucket *bucket = NULL; | ||
| 5415 | struct ocfs2_super *osb = OCFS2_SB(inode->i_sb); | ||
| 5416 | struct ocfs2_post_refcount refcount; | ||
| 5417 | struct ocfs2_post_refcount *p = NULL; | ||
| 5418 | struct buffer_head *ref_root_bh = NULL; | ||
| 5419 | |||
| 5420 | if (!xis->not_found) { | ||
| 5421 | xe = xis->here; | ||
| 5422 | name_offset = le16_to_cpu(xe->xe_name_offset); | ||
| 5423 | name_len = OCFS2_XATTR_SIZE(xe->xe_name_len); | ||
| 5424 | base = xis->base; | ||
| 5425 | vb.vb_bh = xis->inode_bh; | ||
| 5426 | vb.vb_access = ocfs2_journal_access_di; | ||
| 5427 | } else { | ||
| 5428 | int i, block_off = 0; | ||
| 5429 | xb = (struct ocfs2_xattr_block *)xbs->xattr_bh->b_data; | ||
| 5430 | xe = xbs->here; | ||
| 5431 | name_offset = le16_to_cpu(xe->xe_name_offset); | ||
| 5432 | name_len = OCFS2_XATTR_SIZE(xe->xe_name_len); | ||
| 5433 | i = xbs->here - xbs->header->xh_entries; | ||
| 5434 | |||
| 5435 | if (le16_to_cpu(xb->xb_flags) & OCFS2_XATTR_INDEXED) { | ||
| 5436 | ret = ocfs2_xattr_bucket_get_name_value(inode, | ||
| 5437 | bucket_xh(xbs->bucket), | ||
| 5438 | i, &block_off, | ||
| 5439 | &name_offset); | ||
| 5440 | if (ret) { | ||
| 5441 | mlog_errno(ret); | ||
| 5442 | goto out; | ||
| 5443 | } | ||
| 5444 | base = bucket_block(xbs->bucket, block_off); | ||
| 5445 | vb.vb_bh = xbs->bucket->bu_bhs[block_off]; | ||
| 5446 | vb.vb_access = ocfs2_journal_access; | ||
| 5447 | |||
| 5448 | if (ocfs2_meta_ecc(osb)) { | ||
| 5449 | /*create parameters for ocfs2_post_refcount. */ | ||
| 5450 | bucket = xbs->bucket; | ||
| 5451 | refcount.credits = bucket->bu_blocks; | ||
| 5452 | refcount.para = bucket; | ||
| 5453 | refcount.func = | ||
| 5454 | ocfs2_xattr_bucket_post_refcount; | ||
| 5455 | p = &refcount; | ||
| 5456 | } | ||
| 5457 | } else { | ||
| 5458 | base = xbs->base; | ||
| 5459 | vb.vb_bh = xbs->xattr_bh; | ||
| 5460 | vb.vb_access = ocfs2_journal_access_xb; | ||
| 5461 | } | ||
| 5462 | } | ||
| 5463 | |||
| 5464 | if (ocfs2_xattr_is_local(xe)) | ||
| 5465 | goto out; | ||
| 5466 | |||
| 5467 | vb.vb_xv = (struct ocfs2_xattr_value_root *) | ||
| 5468 | (base + name_offset + name_len); | ||
| 5469 | |||
| 5470 | ret = ocfs2_xattr_get_clusters(inode, 0, &p_cluster, | ||
| 5471 | &num_clusters, &vb.vb_xv->xr_list, | ||
| 5472 | &ext_flags); | ||
| 5473 | if (ret) { | ||
| 5474 | mlog_errno(ret); | ||
| 5475 | goto out; | ||
| 5476 | } | ||
| 5477 | |||
| 5478 | /* | ||
| 5479 | * We just need to check the 1st extent record, since we always | ||
| 5480 | * CoW the whole xattr. So there shouldn't be a xattr with | ||
| 5481 | * some REFCOUNT extent recs after the 1st one. | ||
| 5482 | */ | ||
| 5483 | if (!(ext_flags & OCFS2_EXT_REFCOUNTED)) | ||
| 5484 | goto out; | ||
| 5485 | |||
| 5486 | ret = ocfs2_lock_refcount_tree(osb, le64_to_cpu(di->i_refcount_loc), | ||
| 5487 | 1, ref_tree, &ref_root_bh); | ||
| 5488 | if (ret) { | ||
| 5489 | mlog_errno(ret); | ||
| 5490 | goto out; | ||
| 5491 | } | ||
| 5492 | |||
| 5493 | /* | ||
| 5494 | * If we are deleting the xattr or the new size will be stored inside, | ||
| 5495 | * cool, leave it there, the xattr truncate process will remove them | ||
| 5496 | * for us(it still needs the refcount tree lock and the meta, credits). | ||
| 5497 | * And the worse case is that every cluster truncate will split the | ||
| 5498 | * refcount tree, and make the original extent become 3. So we will need | ||
| 5499 | * 2 * cluster more extent recs at most. | ||
| 5500 | */ | ||
| 5501 | if (!xi->value || xi->value_len <= OCFS2_XATTR_INLINE_SIZE) { | ||
| 5502 | |||
| 5503 | ret = ocfs2_refcounted_xattr_delete_need(inode, | ||
| 5504 | &(*ref_tree)->rf_ci, | ||
| 5505 | ref_root_bh, vb.vb_xv, | ||
| 5506 | meta_add, credits); | ||
| 5507 | if (ret) | ||
| 5508 | mlog_errno(ret); | ||
| 5509 | goto out; | ||
| 5510 | } | ||
| 5511 | |||
| 5512 | ret = ocfs2_refcount_cow_xattr(inode, di, &vb, | ||
| 5513 | *ref_tree, ref_root_bh, 0, | ||
| 5514 | le32_to_cpu(vb.vb_xv->xr_clusters), p); | ||
| 5515 | if (ret) | ||
| 5516 | mlog_errno(ret); | ||
| 5517 | |||
| 5518 | out: | ||
| 5519 | brelse(ref_root_bh); | ||
| 5520 | return ret; | ||
| 5521 | } | ||
| 5522 | |||
| 5523 | /* | ||
| 5314 | * 'security' attributes support | 5524 | * 'security' attributes support |
| 5315 | */ | 5525 | */ |
| 5316 | static size_t ocfs2_xattr_security_list(struct inode *inode, char *list, | 5526 | static size_t ocfs2_xattr_security_list(struct inode *inode, char *list, |
