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, |