aboutsummaryrefslogtreecommitdiffstats
path: root/fs/btrfs/tree-log.c
diff options
context:
space:
mode:
Diffstat (limited to 'fs/btrfs/tree-log.c')
-rw-r--r--fs/btrfs/tree-log.c338
1 files changed, 194 insertions, 144 deletions
diff --git a/fs/btrfs/tree-log.c b/fs/btrfs/tree-log.c
index ab7168ee618f..72444811d275 100644
--- a/fs/btrfs/tree-log.c
+++ b/fs/btrfs/tree-log.c
@@ -3150,145 +3150,220 @@ static int extent_cmp(void *priv, struct list_head *a, struct list_head *b)
3150 return 0; 3150 return 0;
3151} 3151}
3152 3152
3153struct log_args { 3153static int drop_adjacent_extents(struct btrfs_trans_handle *trans,
3154 struct extent_buffer *src; 3154 struct btrfs_root *root, struct inode *inode,
3155 u64 next_offset; 3155 struct extent_map *em,
3156 int start_slot; 3156 struct btrfs_path *path)
3157 int nr; 3157{
3158}; 3158 struct btrfs_file_extent_item *fi;
3159 struct extent_buffer *leaf;
3160 struct btrfs_key key, new_key;
3161 struct btrfs_map_token token;
3162 u64 extent_end;
3163 u64 extent_offset = 0;
3164 int extent_type;
3165 int del_slot = 0;
3166 int del_nr = 0;
3167 int ret = 0;
3168
3169 while (1) {
3170 btrfs_init_map_token(&token);
3171 leaf = path->nodes[0];
3172 path->slots[0]++;
3173 if (path->slots[0] >= btrfs_header_nritems(leaf)) {
3174 if (del_nr) {
3175 ret = btrfs_del_items(trans, root, path,
3176 del_slot, del_nr);
3177 if (ret)
3178 return ret;
3179 del_nr = 0;
3180 }
3181
3182 ret = btrfs_next_leaf_write(trans, root, path, 1);
3183 if (ret < 0)
3184 return ret;
3185 if (ret > 0)
3186 return 0;
3187 leaf = path->nodes[0];
3188 }
3189
3190 btrfs_item_key_to_cpu(leaf, &key, path->slots[0]);
3191 if (key.objectid != btrfs_ino(inode) ||
3192 key.type != BTRFS_EXTENT_DATA_KEY ||
3193 key.offset >= em->start + em->len)
3194 break;
3195
3196 fi = btrfs_item_ptr(leaf, path->slots[0],
3197 struct btrfs_file_extent_item);
3198 extent_type = btrfs_token_file_extent_type(leaf, fi, &token);
3199 if (extent_type == BTRFS_FILE_EXTENT_REG ||
3200 extent_type == BTRFS_FILE_EXTENT_PREALLOC) {
3201 extent_offset = btrfs_token_file_extent_offset(leaf,
3202 fi, &token);
3203 extent_end = key.offset +
3204 btrfs_token_file_extent_num_bytes(leaf, fi,
3205 &token);
3206 } else if (extent_type == BTRFS_FILE_EXTENT_INLINE) {
3207 extent_end = key.offset +
3208 btrfs_file_extent_inline_len(leaf, fi);
3209 } else {
3210 BUG();
3211 }
3212
3213 if (extent_end <= em->len + em->start) {
3214 if (!del_nr) {
3215 del_slot = path->slots[0];
3216 }
3217 del_nr++;
3218 continue;
3219 }
3220
3221 /*
3222 * Ok so we'll ignore previous items if we log a new extent,
3223 * which can lead to overlapping extents, so if we have an
3224 * existing extent we want to adjust we _have_ to check the next
3225 * guy to make sure we even need this extent anymore, this keeps
3226 * us from panicing in set_item_key_safe.
3227 */
3228 if (path->slots[0] < btrfs_header_nritems(leaf) - 1) {
3229 struct btrfs_key tmp_key;
3230
3231 btrfs_item_key_to_cpu(leaf, &tmp_key,
3232 path->slots[0] + 1);
3233 if (tmp_key.objectid == btrfs_ino(inode) &&
3234 tmp_key.type == BTRFS_EXTENT_DATA_KEY &&
3235 tmp_key.offset <= em->start + em->len) {
3236 if (!del_nr)
3237 del_slot = path->slots[0];
3238 del_nr++;
3239 continue;
3240 }
3241 }
3242
3243 BUG_ON(extent_type == BTRFS_FILE_EXTENT_INLINE);
3244 memcpy(&new_key, &key, sizeof(new_key));
3245 new_key.offset = em->start + em->len;
3246 btrfs_set_item_key_safe(trans, root, path, &new_key);
3247 extent_offset += em->start + em->len - key.offset;
3248 btrfs_set_token_file_extent_offset(leaf, fi, extent_offset,
3249 &token);
3250 btrfs_set_token_file_extent_num_bytes(leaf, fi, extent_end -
3251 (em->start + em->len),
3252 &token);
3253 btrfs_mark_buffer_dirty(leaf);
3254 }
3255
3256 if (del_nr)
3257 ret = btrfs_del_items(trans, root, path, del_slot, del_nr);
3258
3259 return ret;
3260}
3159 3261
3160static int log_one_extent(struct btrfs_trans_handle *trans, 3262static int log_one_extent(struct btrfs_trans_handle *trans,
3161 struct inode *inode, struct btrfs_root *root, 3263 struct inode *inode, struct btrfs_root *root,
3162 struct extent_map *em, struct btrfs_path *path, 3264 struct extent_map *em, struct btrfs_path *path)
3163 struct btrfs_path *dst_path, struct log_args *args)
3164{ 3265{
3165 struct btrfs_root *log = root->log_root; 3266 struct btrfs_root *log = root->log_root;
3267 struct btrfs_file_extent_item *fi;
3268 struct extent_buffer *leaf;
3269 struct list_head ordered_sums;
3166 struct btrfs_key key; 3270 struct btrfs_key key;
3167 u64 start = em->mod_start; 3271 u64 csum_offset = em->mod_start - em->start;
3168 u64 search_start = start; 3272 u64 csum_len = em->mod_len;
3169 u64 len = em->mod_len; 3273 u64 extent_offset = em->start - em->orig_start;
3170 u64 num_bytes; 3274 u64 block_len;
3171 int nritems;
3172 int ret; 3275 int ret;
3276 bool skip_csum = BTRFS_I(inode)->flags & BTRFS_INODE_NODATASUM;
3173 3277
3174 if (BTRFS_I(inode)->logged_trans == trans->transid) { 3278 INIT_LIST_HEAD(&ordered_sums);
3175 ret = __btrfs_drop_extents(trans, log, inode, dst_path, start, 3279 key.objectid = btrfs_ino(inode);
3176 start + len, NULL, 0); 3280 key.type = BTRFS_EXTENT_DATA_KEY;
3177 if (ret) 3281 key.offset = em->start;
3178 return ret; 3282 path->really_keep_locks = 1;
3283
3284 ret = btrfs_insert_empty_item(trans, log, path, &key, sizeof(*fi));
3285 if (ret && ret != -EEXIST) {
3286 path->really_keep_locks = 0;
3287 return ret;
3288 }
3289 leaf = path->nodes[0];
3290 fi = btrfs_item_ptr(leaf, path->slots[0],
3291 struct btrfs_file_extent_item);
3292 btrfs_set_file_extent_generation(leaf, fi, em->generation);
3293 if (test_bit(EXTENT_FLAG_PREALLOC, &em->flags)) {
3294 skip_csum = true;
3295 btrfs_set_file_extent_type(leaf, fi,
3296 BTRFS_FILE_EXTENT_PREALLOC);
3297 } else {
3298 btrfs_set_file_extent_type(leaf, fi, BTRFS_FILE_EXTENT_REG);
3299 if (em->block_start == 0)
3300 skip_csum = true;
3301 }
3302
3303 block_len = max(em->block_len, em->orig_block_len);
3304 if (em->compress_type != BTRFS_COMPRESS_NONE) {
3305 btrfs_set_file_extent_disk_bytenr(leaf, fi, em->block_start);
3306 btrfs_set_file_extent_disk_num_bytes(leaf, fi, block_len);
3307 } else if (em->block_start < EXTENT_MAP_LAST_BYTE) {
3308 btrfs_set_file_extent_disk_bytenr(leaf, fi,
3309 em->block_start -
3310 extent_offset);
3311 btrfs_set_file_extent_disk_num_bytes(leaf, fi, block_len);
3312 } else {
3313 btrfs_set_file_extent_disk_bytenr(leaf, fi, 0);
3314 btrfs_set_file_extent_disk_num_bytes(leaf, fi, 0);
3179 } 3315 }
3180 3316
3181 while (len) { 3317 btrfs_set_file_extent_offset(leaf, fi, em->start - em->orig_start);
3182 if (args->nr) 3318 btrfs_set_file_extent_num_bytes(leaf, fi, em->len);
3183 goto next_slot; 3319 btrfs_set_file_extent_ram_bytes(leaf, fi, em->len);
3184again: 3320 btrfs_set_file_extent_compression(leaf, fi, em->compress_type);
3185 key.objectid = btrfs_ino(inode); 3321 btrfs_set_file_extent_encryption(leaf, fi, 0);
3186 key.type = BTRFS_EXTENT_DATA_KEY; 3322 btrfs_set_file_extent_other_encoding(leaf, fi, 0);
3187 key.offset = search_start; 3323 btrfs_mark_buffer_dirty(leaf);
3188
3189 ret = btrfs_search_slot(NULL, root, &key, path, 0, 0);
3190 if (ret < 0)
3191 return ret;
3192
3193 if (ret) {
3194 /*
3195 * A rare case were we can have an em for a section of a
3196 * larger extent so we need to make sure that this em
3197 * falls within the extent we've found. If not we just
3198 * bail and go back to ye-olde way of doing things but
3199 * it happens often enough in testing that we need to do
3200 * this dance to make sure.
3201 */
3202 do {
3203 if (path->slots[0] == 0) {
3204 btrfs_release_path(path);
3205 if (search_start == 0)
3206 return -ENOENT;
3207 search_start--;
3208 goto again;
3209 }
3210 3324
3211 path->slots[0]--; 3325 /*
3212 btrfs_item_key_to_cpu(path->nodes[0], &key, 3326 * Have to check the extent to the right of us to make sure it doesn't
3213 path->slots[0]); 3327 * fall in our current range. We're ok if the previous extent is in our
3214 if (key.objectid != btrfs_ino(inode) || 3328 * range since the recovery stuff will run us in key order and thus just
3215 key.type != BTRFS_EXTENT_DATA_KEY) { 3329 * drop the part we overwrote.
3216 btrfs_release_path(path); 3330 */
3217 return -ENOENT; 3331 ret = drop_adjacent_extents(trans, log, inode, em, path);
3218 } 3332 btrfs_release_path(path);
3219 } while (key.offset > start); 3333 path->really_keep_locks = 0;
3334 if (ret) {
3335 return ret;
3336 }
3220 3337
3221 num_bytes = btrfs_file_extent_length(path); 3338 if (skip_csum)
3222 if (key.offset + num_bytes <= start) { 3339 return 0;
3223 btrfs_release_path(path);
3224 return -ENOENT;
3225 }
3226 }
3227 args->src = path->nodes[0];
3228next_slot:
3229 btrfs_item_key_to_cpu(path->nodes[0], &key, path->slots[0]);
3230 num_bytes = btrfs_file_extent_length(path);
3231 if (args->nr &&
3232 args->start_slot + args->nr == path->slots[0]) {
3233 args->nr++;
3234 } else if (args->nr) {
3235 ret = copy_items(trans, inode, dst_path, args->src,
3236 args->start_slot, args->nr,
3237 LOG_INODE_ALL);
3238 if (ret)
3239 return ret;
3240 args->nr = 1;
3241 args->start_slot = path->slots[0];
3242 } else if (!args->nr) {
3243 args->nr = 1;
3244 args->start_slot = path->slots[0];
3245 }
3246 nritems = btrfs_header_nritems(path->nodes[0]);
3247 path->slots[0]++;
3248 if (len < num_bytes) {
3249 /* I _think_ this is ok, envision we write to a
3250 * preallocated space that is adjacent to a previously
3251 * written preallocated space that gets merged when we
3252 * mark this preallocated space written. If we do not
3253 * have the adjacent extent in cache then when we copy
3254 * this extent it could end up being larger than our EM
3255 * thinks it is, which is a-ok, so just set len to 0.
3256 */
3257 len = 0;
3258 } else {
3259 len -= num_bytes;
3260 }
3261 start = key.offset + num_bytes;
3262 args->next_offset = start;
3263 search_start = start;
3264 3340
3265 if (path->slots[0] < nritems) { 3341 /* block start is already adjusted for the file extent offset. */
3266 if (len) 3342 ret = btrfs_lookup_csums_range(log->fs_info->csum_root,
3267 goto next_slot; 3343 em->block_start + csum_offset,
3268 break; 3344 em->block_start + csum_offset +
3269 } 3345 csum_len - 1, &ordered_sums, 0);
3346 if (ret)
3347 return ret;
3270 3348
3271 if (args->nr) { 3349 while (!list_empty(&ordered_sums)) {
3272 ret = copy_items(trans, inode, dst_path, args->src, 3350 struct btrfs_ordered_sum *sums = list_entry(ordered_sums.next,
3273 args->start_slot, args->nr, 3351 struct btrfs_ordered_sum,
3274 LOG_INODE_ALL); 3352 list);
3275 if (ret) 3353 if (!ret)
3276 return ret; 3354 ret = btrfs_csum_file_blocks(trans, log, sums);
3277 args->nr = 0; 3355 list_del(&sums->list);
3278 btrfs_release_path(path); 3356 kfree(sums);
3279 }
3280 } 3357 }
3281 3358
3282 return 0; 3359 return ret;
3283} 3360}
3284 3361
3285static int btrfs_log_changed_extents(struct btrfs_trans_handle *trans, 3362static int btrfs_log_changed_extents(struct btrfs_trans_handle *trans,
3286 struct btrfs_root *root, 3363 struct btrfs_root *root,
3287 struct inode *inode, 3364 struct inode *inode,
3288 struct btrfs_path *path, 3365 struct btrfs_path *path)
3289 struct btrfs_path *dst_path)
3290{ 3366{
3291 struct log_args args;
3292 struct extent_map *em, *n; 3367 struct extent_map *em, *n;
3293 struct list_head extents; 3368 struct list_head extents;
3294 struct extent_map_tree *tree = &BTRFS_I(inode)->extent_tree; 3369 struct extent_map_tree *tree = &BTRFS_I(inode)->extent_tree;
@@ -3297,8 +3372,6 @@ static int btrfs_log_changed_extents(struct btrfs_trans_handle *trans,
3297 3372
3298 INIT_LIST_HEAD(&extents); 3373 INIT_LIST_HEAD(&extents);
3299 3374
3300 memset(&args, 0, sizeof(args));
3301
3302 write_lock(&tree->lock); 3375 write_lock(&tree->lock);
3303 test_gen = root->fs_info->last_trans_committed; 3376 test_gen = root->fs_info->last_trans_committed;
3304 3377
@@ -3331,34 +3404,13 @@ static int btrfs_log_changed_extents(struct btrfs_trans_handle *trans,
3331 3404
3332 write_unlock(&tree->lock); 3405 write_unlock(&tree->lock);
3333 3406
3334 /* 3407 ret = log_one_extent(trans, inode, root, em, path);
3335 * If the previous EM and the last extent we left off on aren't
3336 * sequential then we need to copy the items we have and redo
3337 * our search
3338 */
3339 if (args.nr && em->mod_start != args.next_offset) {
3340 ret = copy_items(trans, inode, dst_path, args.src,
3341 args.start_slot, args.nr,
3342 LOG_INODE_ALL);
3343 if (ret) {
3344 free_extent_map(em);
3345 write_lock(&tree->lock);
3346 continue;
3347 }
3348 btrfs_release_path(path);
3349 args.nr = 0;
3350 }
3351
3352 ret = log_one_extent(trans, inode, root, em, path, dst_path, &args);
3353 free_extent_map(em); 3408 free_extent_map(em);
3354 write_lock(&tree->lock); 3409 write_lock(&tree->lock);
3355 } 3410 }
3356 WARN_ON(!list_empty(&extents)); 3411 WARN_ON(!list_empty(&extents));
3357 write_unlock(&tree->lock); 3412 write_unlock(&tree->lock);
3358 3413
3359 if (!ret && args.nr)
3360 ret = copy_items(trans, inode, dst_path, args.src,
3361 args.start_slot, args.nr, LOG_INODE_ALL);
3362 btrfs_release_path(path); 3414 btrfs_release_path(path);
3363 return ret; 3415 return ret;
3364} 3416}
@@ -3551,10 +3603,8 @@ next_slot:
3551 3603
3552log_extents: 3604log_extents:
3553 if (fast_search) { 3605 if (fast_search) {
3554 btrfs_release_path(path);
3555 btrfs_release_path(dst_path); 3606 btrfs_release_path(dst_path);
3556 ret = btrfs_log_changed_extents(trans, root, inode, path, 3607 ret = btrfs_log_changed_extents(trans, root, inode, dst_path);
3557 dst_path);
3558 if (ret) { 3608 if (ret) {
3559 err = ret; 3609 err = ret;
3560 goto out_unlock; 3610 goto out_unlock;