aboutsummaryrefslogtreecommitdiffstats
path: root/fs/btrfs/tree-log.c
diff options
context:
space:
mode:
authorJosef Bacik <jbacik@fusionio.com>2012-10-11 16:54:30 -0400
committerChris Mason <chris.mason@fusionio.com>2012-12-16 20:46:24 -0500
commit70c8a91ce21b83ccd2d9e7c968775430ead4353d (patch)
treedc1e83734b08836fc278ae2d763c5d75cc3d4de0 /fs/btrfs/tree-log.c
parentd6393786cd40f67709324bc4f08d7e4b911153fe (diff)
Btrfs: log changed inodes based on the extent map tree
We don't really need to copy extents from the source tree since we have all of the information already available to us in the extent_map tree. So instead just write the extents straight to the log tree and don't bother to copy the extent items from the source tree. Signed-off-by: Josef Bacik <jbacik@fusionio.com> Signed-off-by: Chris Mason <chris.mason@fusionio.com>
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;