diff options
Diffstat (limited to 'fs/ocfs2/refcounttree.c')
| -rw-r--r-- | fs/ocfs2/refcounttree.c | 127 |
1 files changed, 71 insertions, 56 deletions
diff --git a/fs/ocfs2/refcounttree.c b/fs/ocfs2/refcounttree.c index 62d21c6ce1d9..40de7bb9e9a6 100644 --- a/fs/ocfs2/refcounttree.c +++ b/fs/ocfs2/refcounttree.c | |||
| @@ -45,12 +45,20 @@ struct ocfs2_cow_context { | |||
| 45 | struct inode *inode; | 45 | struct inode *inode; |
| 46 | u32 cow_start; | 46 | u32 cow_start; |
| 47 | u32 cow_len; | 47 | u32 cow_len; |
| 48 | struct ocfs2_extent_tree di_et; | 48 | struct ocfs2_extent_tree data_et; |
| 49 | struct ocfs2_caching_info *ref_ci; | 49 | struct ocfs2_refcount_tree *ref_tree; |
| 50 | struct buffer_head *ref_root_bh; | 50 | struct buffer_head *ref_root_bh; |
| 51 | struct ocfs2_alloc_context *meta_ac; | 51 | struct ocfs2_alloc_context *meta_ac; |
| 52 | struct ocfs2_alloc_context *data_ac; | 52 | struct ocfs2_alloc_context *data_ac; |
| 53 | struct ocfs2_cached_dealloc_ctxt dealloc; | 53 | struct ocfs2_cached_dealloc_ctxt dealloc; |
| 54 | int (*get_clusters)(struct ocfs2_cow_context *context, | ||
| 55 | u32 v_cluster, u32 *p_cluster, | ||
| 56 | u32 *num_clusters, | ||
| 57 | unsigned int *extent_flags); | ||
| 58 | int (*cow_duplicate_clusters)(handle_t *handle, | ||
| 59 | struct ocfs2_cow_context *context, | ||
| 60 | u32 cpos, u32 old_cluster, | ||
| 61 | u32 new_cluster, u32 new_len); | ||
| 54 | }; | 62 | }; |
| 55 | 63 | ||
| 56 | static inline struct ocfs2_refcount_tree * | 64 | static inline struct ocfs2_refcount_tree * |
| @@ -2489,7 +2497,7 @@ static inline unsigned int ocfs2_cow_align_length(struct super_block *sb, | |||
| 2489 | * get good I/O from the resulting extent tree. | 2497 | * get good I/O from the resulting extent tree. |
| 2490 | */ | 2498 | */ |
| 2491 | static int ocfs2_refcount_cal_cow_clusters(struct inode *inode, | 2499 | static int ocfs2_refcount_cal_cow_clusters(struct inode *inode, |
| 2492 | struct buffer_head *di_bh, | 2500 | struct ocfs2_extent_list *el, |
| 2493 | u32 cpos, | 2501 | u32 cpos, |
| 2494 | u32 write_len, | 2502 | u32 write_len, |
| 2495 | u32 max_cpos, | 2503 | u32 max_cpos, |
| @@ -2497,8 +2505,6 @@ static int ocfs2_refcount_cal_cow_clusters(struct inode *inode, | |||
| 2497 | u32 *cow_len) | 2505 | u32 *cow_len) |
| 2498 | { | 2506 | { |
| 2499 | int ret = 0; | 2507 | int ret = 0; |
| 2500 | struct ocfs2_dinode *di = (struct ocfs2_dinode *) di_bh->b_data; | ||
| 2501 | struct ocfs2_extent_list *el = &di->id2.i_list; | ||
| 2502 | int tree_height = le16_to_cpu(el->l_tree_depth), i; | 2508 | int tree_height = le16_to_cpu(el->l_tree_depth), i; |
| 2503 | struct buffer_head *eb_bh = NULL; | 2509 | struct buffer_head *eb_bh = NULL; |
| 2504 | struct ocfs2_extent_block *eb = NULL; | 2510 | struct ocfs2_extent_block *eb = NULL; |
| @@ -2769,13 +2775,13 @@ static int ocfs2_clear_cow_buffer(handle_t *handle, struct buffer_head *bh) | |||
| 2769 | return 0; | 2775 | return 0; |
| 2770 | } | 2776 | } |
| 2771 | 2777 | ||
| 2772 | static int ocfs2_duplicate_clusters(handle_t *handle, | 2778 | static int ocfs2_duplicate_clusters_by_page(handle_t *handle, |
| 2773 | struct ocfs2_cow_context *context, | 2779 | struct ocfs2_cow_context *context, |
| 2774 | u32 cpos, u32 old_cluster, | 2780 | u32 cpos, u32 old_cluster, |
| 2775 | u32 new_cluster, u32 new_len) | 2781 | u32 new_cluster, u32 new_len) |
| 2776 | { | 2782 | { |
| 2777 | int ret = 0, partial; | 2783 | int ret = 0, partial; |
| 2778 | struct ocfs2_caching_info *ci = context->di_et.et_ci; | 2784 | struct ocfs2_caching_info *ci = context->data_et.et_ci; |
| 2779 | struct super_block *sb = ocfs2_metadata_cache_get_super(ci); | 2785 | struct super_block *sb = ocfs2_metadata_cache_get_super(ci); |
| 2780 | u64 new_block = ocfs2_clusters_to_blocks(sb, new_cluster); | 2786 | u64 new_block = ocfs2_clusters_to_blocks(sb, new_cluster); |
| 2781 | struct page *page; | 2787 | struct page *page; |
| @@ -2909,7 +2915,7 @@ static int ocfs2_replace_clusters(handle_t *handle, | |||
| 2909 | unsigned int ext_flags) | 2915 | unsigned int ext_flags) |
| 2910 | { | 2916 | { |
| 2911 | int ret; | 2917 | int ret; |
| 2912 | struct ocfs2_caching_info *ci = context->di_et.et_ci; | 2918 | struct ocfs2_caching_info *ci = context->data_et.et_ci; |
| 2913 | u64 ino = ocfs2_metadata_cache_owner(ci); | 2919 | u64 ino = ocfs2_metadata_cache_owner(ci); |
| 2914 | 2920 | ||
| 2915 | mlog(0, "inode %llu, cpos %u, old %u, new %u, len %u, ext_flags %u\n", | 2921 | mlog(0, "inode %llu, cpos %u, old %u, new %u, len %u, ext_flags %u\n", |
| @@ -2917,15 +2923,15 @@ static int ocfs2_replace_clusters(handle_t *handle, | |||
| 2917 | 2923 | ||
| 2918 | /*If the old clusters is unwritten, no need to duplicate. */ | 2924 | /*If the old clusters is unwritten, no need to duplicate. */ |
| 2919 | if (!(ext_flags & OCFS2_EXT_UNWRITTEN)) { | 2925 | if (!(ext_flags & OCFS2_EXT_UNWRITTEN)) { |
| 2920 | ret = ocfs2_duplicate_clusters(handle, context, cpos, | 2926 | ret = context->cow_duplicate_clusters(handle, context, cpos, |
| 2921 | old, new, len); | 2927 | old, new, len); |
| 2922 | if (ret) { | 2928 | if (ret) { |
| 2923 | mlog_errno(ret); | 2929 | mlog_errno(ret); |
| 2924 | goto out; | 2930 | goto out; |
| 2925 | } | 2931 | } |
| 2926 | } | 2932 | } |
| 2927 | 2933 | ||
| 2928 | ret = ocfs2_clear_ext_refcount(handle, &context->di_et, | 2934 | ret = ocfs2_clear_ext_refcount(handle, &context->data_et, |
| 2929 | cpos, new, len, ext_flags, | 2935 | cpos, new, len, ext_flags, |
| 2930 | context->meta_ac, &context->dealloc); | 2936 | context->meta_ac, &context->dealloc); |
| 2931 | if (ret) | 2937 | if (ret) |
| @@ -2983,6 +2989,15 @@ static int ocfs2_cow_sync_writeback(struct super_block *sb, | |||
| 2983 | return ret; | 2989 | return ret; |
| 2984 | } | 2990 | } |
| 2985 | 2991 | ||
| 2992 | static int ocfs2_di_get_clusters(struct ocfs2_cow_context *context, | ||
| 2993 | u32 v_cluster, u32 *p_cluster, | ||
| 2994 | u32 *num_clusters, | ||
| 2995 | unsigned int *extent_flags) | ||
| 2996 | { | ||
| 2997 | return ocfs2_get_clusters(context->inode, v_cluster, p_cluster, | ||
| 2998 | num_clusters, extent_flags); | ||
| 2999 | } | ||
| 3000 | |||
| 2986 | static int ocfs2_make_clusters_writable(struct super_block *sb, | 3001 | static int ocfs2_make_clusters_writable(struct super_block *sb, |
| 2987 | struct ocfs2_cow_context *context, | 3002 | struct ocfs2_cow_context *context, |
| 2988 | u32 cpos, u32 p_cluster, | 3003 | u32 cpos, u32 p_cluster, |
| @@ -2994,14 +3009,15 @@ static int ocfs2_make_clusters_writable(struct super_block *sb, | |||
| 2994 | struct ocfs2_super *osb = OCFS2_SB(sb); | 3009 | struct ocfs2_super *osb = OCFS2_SB(sb); |
| 2995 | handle_t *handle; | 3010 | handle_t *handle; |
| 2996 | struct buffer_head *ref_leaf_bh = NULL; | 3011 | struct buffer_head *ref_leaf_bh = NULL; |
| 3012 | struct ocfs2_caching_info *ref_ci = &context->ref_tree->rf_ci; | ||
| 2997 | struct ocfs2_refcount_rec rec; | 3013 | struct ocfs2_refcount_rec rec; |
| 2998 | 3014 | ||
| 2999 | mlog(0, "cpos %u, p_cluster %u, num_clusters %u, e_flags %u\n", | 3015 | mlog(0, "cpos %u, p_cluster %u, num_clusters %u, e_flags %u\n", |
| 3000 | cpos, p_cluster, num_clusters, e_flags); | 3016 | cpos, p_cluster, num_clusters, e_flags); |
| 3001 | 3017 | ||
| 3002 | ret = ocfs2_lock_refcount_allocators(sb, p_cluster, num_clusters, | 3018 | ret = ocfs2_lock_refcount_allocators(sb, p_cluster, num_clusters, |
| 3003 | &context->di_et, | 3019 | &context->data_et, |
| 3004 | context->ref_ci, | 3020 | ref_ci, |
| 3005 | context->ref_root_bh, | 3021 | context->ref_root_bh, |
| 3006 | &context->meta_ac, | 3022 | &context->meta_ac, |
| 3007 | &context->data_ac, &credits); | 3023 | &context->data_ac, &credits); |
| @@ -3018,8 +3034,7 @@ static int ocfs2_make_clusters_writable(struct super_block *sb, | |||
| 3018 | } | 3034 | } |
| 3019 | 3035 | ||
| 3020 | while (num_clusters) { | 3036 | while (num_clusters) { |
| 3021 | ret = ocfs2_get_refcount_rec(context->ref_ci, | 3037 | ret = ocfs2_get_refcount_rec(ref_ci, context->ref_root_bh, |
| 3022 | context->ref_root_bh, | ||
| 3023 | p_cluster, num_clusters, | 3038 | p_cluster, num_clusters, |
| 3024 | &rec, &index, &ref_leaf_bh); | 3039 | &rec, &index, &ref_leaf_bh); |
| 3025 | if (ret) { | 3040 | if (ret) { |
| @@ -3041,7 +3056,8 @@ static int ocfs2_make_clusters_writable(struct super_block *sb, | |||
| 3041 | */ | 3056 | */ |
| 3042 | if (le32_to_cpu(rec.r_refcount) == 1) { | 3057 | if (le32_to_cpu(rec.r_refcount) == 1) { |
| 3043 | delete = 0; | 3058 | delete = 0; |
| 3044 | ret = ocfs2_clear_ext_refcount(handle, &context->di_et, | 3059 | ret = ocfs2_clear_ext_refcount(handle, |
| 3060 | &context->data_et, | ||
| 3045 | cpos, p_cluster, | 3061 | cpos, p_cluster, |
| 3046 | set_len, e_flags, | 3062 | set_len, e_flags, |
| 3047 | context->meta_ac, | 3063 | context->meta_ac, |
| @@ -3072,7 +3088,7 @@ static int ocfs2_make_clusters_writable(struct super_block *sb, | |||
| 3072 | set_len = new_len; | 3088 | set_len = new_len; |
| 3073 | } | 3089 | } |
| 3074 | 3090 | ||
| 3075 | ret = __ocfs2_decrease_refcount(handle, context->ref_ci, | 3091 | ret = __ocfs2_decrease_refcount(handle, ref_ci, |
| 3076 | context->ref_root_bh, | 3092 | context->ref_root_bh, |
| 3077 | p_cluster, set_len, | 3093 | p_cluster, set_len, |
| 3078 | context->meta_ac, | 3094 | context->meta_ac, |
| @@ -3114,17 +3130,14 @@ out: | |||
| 3114 | return ret; | 3130 | return ret; |
| 3115 | } | 3131 | } |
| 3116 | 3132 | ||
| 3117 | static int ocfs2_replace_cow(struct inode *inode, | 3133 | static int ocfs2_replace_cow(struct ocfs2_cow_context *context) |
| 3118 | struct buffer_head *di_bh, | ||
| 3119 | struct buffer_head *ref_root_bh, | ||
| 3120 | struct ocfs2_caching_info *ref_ci, | ||
| 3121 | u32 cow_start, u32 cow_len) | ||
| 3122 | { | 3134 | { |
| 3123 | int ret = 0; | 3135 | int ret = 0; |
| 3124 | u32 p_cluster, num_clusters, start = cow_start; | 3136 | struct inode *inode = context->inode; |
| 3137 | u32 cow_start = context->cow_start, cow_len = context->cow_len; | ||
| 3138 | u32 p_cluster, num_clusters; | ||
| 3125 | unsigned int ext_flags; | 3139 | unsigned int ext_flags; |
| 3126 | struct ocfs2_super *osb = OCFS2_SB(inode->i_sb); | 3140 | struct ocfs2_super *osb = OCFS2_SB(inode->i_sb); |
| 3127 | struct ocfs2_cow_context *context; | ||
| 3128 | 3141 | ||
| 3129 | if (!ocfs2_refcount_tree(OCFS2_SB(inode->i_sb))) { | 3142 | if (!ocfs2_refcount_tree(OCFS2_SB(inode->i_sb))) { |
| 3130 | ocfs2_error(inode->i_sb, "Inode %lu want to use refcount " | 3143 | ocfs2_error(inode->i_sb, "Inode %lu want to use refcount " |
| @@ -3133,26 +3146,11 @@ static int ocfs2_replace_cow(struct inode *inode, | |||
| 3133 | return -EROFS; | 3146 | return -EROFS; |
| 3134 | } | 3147 | } |
| 3135 | 3148 | ||
| 3136 | context = kzalloc(sizeof(struct ocfs2_cow_context), GFP_NOFS); | ||
| 3137 | if (!context) { | ||
| 3138 | ret = -ENOMEM; | ||
| 3139 | mlog_errno(ret); | ||
| 3140 | return ret; | ||
| 3141 | } | ||
| 3142 | |||
| 3143 | context->inode = inode; | ||
| 3144 | context->cow_start = cow_start; | ||
| 3145 | context->cow_len = cow_len; | ||
| 3146 | context->ref_ci = ref_ci; | ||
| 3147 | context->ref_root_bh = ref_root_bh; | ||
| 3148 | |||
| 3149 | ocfs2_init_dealloc_ctxt(&context->dealloc); | 3149 | ocfs2_init_dealloc_ctxt(&context->dealloc); |
| 3150 | ocfs2_init_dinode_extent_tree(&context->di_et, | ||
| 3151 | INODE_CACHE(inode), di_bh); | ||
| 3152 | 3150 | ||
| 3153 | while (cow_len) { | 3151 | while (cow_len) { |
| 3154 | ret = ocfs2_get_clusters(inode, cow_start, &p_cluster, | 3152 | ret = context->get_clusters(context, cow_start, &p_cluster, |
| 3155 | &num_clusters, &ext_flags); | 3153 | &num_clusters, &ext_flags); |
| 3156 | if (ret) { | 3154 | if (ret) { |
| 3157 | mlog_errno(ret); | 3155 | mlog_errno(ret); |
| 3158 | break; | 3156 | break; |
| @@ -3175,20 +3173,11 @@ static int ocfs2_replace_cow(struct inode *inode, | |||
| 3175 | cow_start += num_clusters; | 3173 | cow_start += num_clusters; |
| 3176 | } | 3174 | } |
| 3177 | 3175 | ||
| 3178 | |||
| 3179 | /* | ||
| 3180 | * truncate the extent map here since no matter whether we meet with | ||
| 3181 | * any error during the action, we shouldn't trust cached extent map | ||
| 3182 | * any more. | ||
| 3183 | */ | ||
| 3184 | ocfs2_extent_map_trunc(inode, start); | ||
| 3185 | |||
| 3186 | if (ocfs2_dealloc_has_cluster(&context->dealloc)) { | 3176 | if (ocfs2_dealloc_has_cluster(&context->dealloc)) { |
| 3187 | ocfs2_schedule_truncate_log_flush(osb, 1); | 3177 | ocfs2_schedule_truncate_log_flush(osb, 1); |
| 3188 | ocfs2_run_deallocs(osb, &context->dealloc); | 3178 | ocfs2_run_deallocs(osb, &context->dealloc); |
| 3189 | } | 3179 | } |
| 3190 | 3180 | ||
| 3191 | kfree(context); | ||
| 3192 | return ret; | 3181 | return ret; |
| 3193 | } | 3182 | } |
| 3194 | 3183 | ||
| @@ -3208,10 +3197,11 @@ static int ocfs2_refcount_cow_hunk(struct inode *inode, | |||
| 3208 | struct ocfs2_dinode *di = (struct ocfs2_dinode *)di_bh->b_data; | 3197 | struct ocfs2_dinode *di = (struct ocfs2_dinode *)di_bh->b_data; |
| 3209 | struct buffer_head *ref_root_bh = NULL; | 3198 | struct buffer_head *ref_root_bh = NULL; |
| 3210 | struct ocfs2_refcount_tree *ref_tree; | 3199 | struct ocfs2_refcount_tree *ref_tree; |
| 3200 | struct ocfs2_cow_context *context = NULL; | ||
| 3211 | 3201 | ||
| 3212 | BUG_ON(!(oi->ip_dyn_features & OCFS2_HAS_REFCOUNT_FL)); | 3202 | BUG_ON(!(oi->ip_dyn_features & OCFS2_HAS_REFCOUNT_FL)); |
| 3213 | 3203 | ||
| 3214 | ret = ocfs2_refcount_cal_cow_clusters(inode, di_bh, | 3204 | ret = ocfs2_refcount_cal_cow_clusters(inode, &di->id2.i_list, |
| 3215 | cpos, write_len, max_cpos, | 3205 | cpos, write_len, max_cpos, |
| 3216 | &cow_start, &cow_len); | 3206 | &cow_start, &cow_len); |
| 3217 | if (ret) { | 3207 | if (ret) { |
| @@ -3225,6 +3215,13 @@ static int ocfs2_refcount_cow_hunk(struct inode *inode, | |||
| 3225 | 3215 | ||
| 3226 | BUG_ON(cow_len == 0); | 3216 | BUG_ON(cow_len == 0); |
| 3227 | 3217 | ||
| 3218 | context = kzalloc(sizeof(struct ocfs2_cow_context), GFP_NOFS); | ||
| 3219 | if (!context) { | ||
| 3220 | ret = -ENOMEM; | ||
| 3221 | mlog_errno(ret); | ||
| 3222 | goto out; | ||
| 3223 | } | ||
| 3224 | |||
| 3228 | ret = ocfs2_lock_refcount_tree(osb, le64_to_cpu(di->i_refcount_loc), | 3225 | ret = ocfs2_lock_refcount_tree(osb, le64_to_cpu(di->i_refcount_loc), |
| 3229 | 1, &ref_tree, &ref_root_bh); | 3226 | 1, &ref_tree, &ref_root_bh); |
| 3230 | if (ret) { | 3227 | if (ret) { |
| @@ -3232,14 +3229,32 @@ static int ocfs2_refcount_cow_hunk(struct inode *inode, | |||
| 3232 | goto out; | 3229 | goto out; |
| 3233 | } | 3230 | } |
| 3234 | 3231 | ||
| 3235 | ret = ocfs2_replace_cow(inode, di_bh, ref_root_bh, &ref_tree->rf_ci, | 3232 | context->inode = inode; |
| 3236 | cow_start, cow_len); | 3233 | context->cow_start = cow_start; |
| 3234 | context->cow_len = cow_len; | ||
| 3235 | context->ref_tree = ref_tree; | ||
| 3236 | context->ref_root_bh = ref_root_bh; | ||
| 3237 | context->cow_duplicate_clusters = ocfs2_duplicate_clusters_by_page; | ||
| 3238 | context->get_clusters = ocfs2_di_get_clusters; | ||
| 3239 | |||
| 3240 | ocfs2_init_dinode_extent_tree(&context->data_et, | ||
| 3241 | INODE_CACHE(inode), di_bh); | ||
| 3242 | |||
| 3243 | ret = ocfs2_replace_cow(context); | ||
| 3237 | if (ret) | 3244 | if (ret) |
| 3238 | mlog_errno(ret); | 3245 | mlog_errno(ret); |
| 3239 | 3246 | ||
| 3247 | /* | ||
| 3248 | * truncate the extent map here since no matter whether we meet with | ||
| 3249 | * any error during the action, we shouldn't trust cached extent map | ||
| 3250 | * any more. | ||
| 3251 | */ | ||
| 3252 | ocfs2_extent_map_trunc(inode, cow_start); | ||
| 3253 | |||
| 3240 | ocfs2_unlock_refcount_tree(osb, ref_tree, 1); | 3254 | ocfs2_unlock_refcount_tree(osb, ref_tree, 1); |
| 3241 | brelse(ref_root_bh); | 3255 | brelse(ref_root_bh); |
| 3242 | out: | 3256 | out: |
| 3257 | kfree(context); | ||
| 3243 | return ret; | 3258 | return ret; |
| 3244 | } | 3259 | } |
| 3245 | 3260 | ||
