diff options
Diffstat (limited to 'fs/btrfs/tree-log.c')
-rw-r--r-- | fs/btrfs/tree-log.c | 485 |
1 files changed, 297 insertions, 188 deletions
diff --git a/fs/btrfs/tree-log.c b/fs/btrfs/tree-log.c index 81e407d9677a..9027bb1e7466 100644 --- a/fs/btrfs/tree-log.c +++ b/fs/btrfs/tree-log.c | |||
@@ -2952,33 +2952,9 @@ static void fill_inode_item(struct btrfs_trans_handle *trans, | |||
2952 | struct btrfs_inode_item *item, | 2952 | struct btrfs_inode_item *item, |
2953 | struct inode *inode, int log_inode_only) | 2953 | struct inode *inode, int log_inode_only) |
2954 | { | 2954 | { |
2955 | btrfs_set_inode_uid(leaf, item, i_uid_read(inode)); | 2955 | struct btrfs_map_token token; |
2956 | btrfs_set_inode_gid(leaf, item, i_gid_read(inode)); | 2956 | |
2957 | btrfs_set_inode_mode(leaf, item, inode->i_mode); | 2957 | btrfs_init_map_token(&token); |
2958 | btrfs_set_inode_nlink(leaf, item, inode->i_nlink); | ||
2959 | |||
2960 | btrfs_set_timespec_sec(leaf, btrfs_inode_atime(item), | ||
2961 | inode->i_atime.tv_sec); | ||
2962 | btrfs_set_timespec_nsec(leaf, btrfs_inode_atime(item), | ||
2963 | inode->i_atime.tv_nsec); | ||
2964 | |||
2965 | btrfs_set_timespec_sec(leaf, btrfs_inode_mtime(item), | ||
2966 | inode->i_mtime.tv_sec); | ||
2967 | btrfs_set_timespec_nsec(leaf, btrfs_inode_mtime(item), | ||
2968 | inode->i_mtime.tv_nsec); | ||
2969 | |||
2970 | btrfs_set_timespec_sec(leaf, btrfs_inode_ctime(item), | ||
2971 | inode->i_ctime.tv_sec); | ||
2972 | btrfs_set_timespec_nsec(leaf, btrfs_inode_ctime(item), | ||
2973 | inode->i_ctime.tv_nsec); | ||
2974 | |||
2975 | btrfs_set_inode_nbytes(leaf, item, inode_get_bytes(inode)); | ||
2976 | |||
2977 | btrfs_set_inode_sequence(leaf, item, inode->i_version); | ||
2978 | btrfs_set_inode_transid(leaf, item, trans->transid); | ||
2979 | btrfs_set_inode_rdev(leaf, item, inode->i_rdev); | ||
2980 | btrfs_set_inode_flags(leaf, item, BTRFS_I(inode)->flags); | ||
2981 | btrfs_set_inode_block_group(leaf, item, 0); | ||
2982 | 2958 | ||
2983 | if (log_inode_only) { | 2959 | if (log_inode_only) { |
2984 | /* set the generation to zero so the recover code | 2960 | /* set the generation to zero so the recover code |
@@ -2986,14 +2962,63 @@ static void fill_inode_item(struct btrfs_trans_handle *trans, | |||
2986 | * just to say 'this inode exists' and a logging | 2962 | * just to say 'this inode exists' and a logging |
2987 | * to say 'update this inode with these values' | 2963 | * to say 'update this inode with these values' |
2988 | */ | 2964 | */ |
2989 | btrfs_set_inode_generation(leaf, item, 0); | 2965 | btrfs_set_token_inode_generation(leaf, item, 0, &token); |
2990 | btrfs_set_inode_size(leaf, item, 0); | 2966 | btrfs_set_token_inode_size(leaf, item, 0, &token); |
2991 | } else { | 2967 | } else { |
2992 | btrfs_set_inode_generation(leaf, item, | 2968 | btrfs_set_token_inode_generation(leaf, item, |
2993 | BTRFS_I(inode)->generation); | 2969 | BTRFS_I(inode)->generation, |
2994 | btrfs_set_inode_size(leaf, item, inode->i_size); | 2970 | &token); |
2995 | } | 2971 | btrfs_set_token_inode_size(leaf, item, inode->i_size, &token); |
2972 | } | ||
2973 | |||
2974 | btrfs_set_token_inode_uid(leaf, item, i_uid_read(inode), &token); | ||
2975 | btrfs_set_token_inode_gid(leaf, item, i_gid_read(inode), &token); | ||
2976 | btrfs_set_token_inode_mode(leaf, item, inode->i_mode, &token); | ||
2977 | btrfs_set_token_inode_nlink(leaf, item, inode->i_nlink, &token); | ||
2978 | |||
2979 | btrfs_set_token_timespec_sec(leaf, btrfs_inode_atime(item), | ||
2980 | inode->i_atime.tv_sec, &token); | ||
2981 | btrfs_set_token_timespec_nsec(leaf, btrfs_inode_atime(item), | ||
2982 | inode->i_atime.tv_nsec, &token); | ||
2983 | |||
2984 | btrfs_set_token_timespec_sec(leaf, btrfs_inode_mtime(item), | ||
2985 | inode->i_mtime.tv_sec, &token); | ||
2986 | btrfs_set_token_timespec_nsec(leaf, btrfs_inode_mtime(item), | ||
2987 | inode->i_mtime.tv_nsec, &token); | ||
2988 | |||
2989 | btrfs_set_token_timespec_sec(leaf, btrfs_inode_ctime(item), | ||
2990 | inode->i_ctime.tv_sec, &token); | ||
2991 | btrfs_set_token_timespec_nsec(leaf, btrfs_inode_ctime(item), | ||
2992 | inode->i_ctime.tv_nsec, &token); | ||
2993 | |||
2994 | btrfs_set_token_inode_nbytes(leaf, item, inode_get_bytes(inode), | ||
2995 | &token); | ||
2996 | |||
2997 | btrfs_set_token_inode_sequence(leaf, item, inode->i_version, &token); | ||
2998 | btrfs_set_token_inode_transid(leaf, item, trans->transid, &token); | ||
2999 | btrfs_set_token_inode_rdev(leaf, item, inode->i_rdev, &token); | ||
3000 | btrfs_set_token_inode_flags(leaf, item, BTRFS_I(inode)->flags, &token); | ||
3001 | btrfs_set_token_inode_block_group(leaf, item, 0, &token); | ||
3002 | } | ||
2996 | 3003 | ||
3004 | static int log_inode_item(struct btrfs_trans_handle *trans, | ||
3005 | struct btrfs_root *log, struct btrfs_path *path, | ||
3006 | struct inode *inode) | ||
3007 | { | ||
3008 | struct btrfs_inode_item *inode_item; | ||
3009 | struct btrfs_key key; | ||
3010 | int ret; | ||
3011 | |||
3012 | memcpy(&key, &BTRFS_I(inode)->location, sizeof(key)); | ||
3013 | ret = btrfs_insert_empty_item(trans, log, path, &key, | ||
3014 | sizeof(*inode_item)); | ||
3015 | if (ret && ret != -EEXIST) | ||
3016 | return ret; | ||
3017 | inode_item = btrfs_item_ptr(path->nodes[0], path->slots[0], | ||
3018 | struct btrfs_inode_item); | ||
3019 | fill_inode_item(trans, path->nodes[0], inode_item, inode, 0); | ||
3020 | btrfs_release_path(path); | ||
3021 | return 0; | ||
2997 | } | 3022 | } |
2998 | 3023 | ||
2999 | static noinline int copy_items(struct btrfs_trans_handle *trans, | 3024 | static noinline int copy_items(struct btrfs_trans_handle *trans, |
@@ -3130,151 +3155,239 @@ static int extent_cmp(void *priv, struct list_head *a, struct list_head *b) | |||
3130 | return 0; | 3155 | return 0; |
3131 | } | 3156 | } |
3132 | 3157 | ||
3133 | struct log_args { | 3158 | static int drop_adjacent_extents(struct btrfs_trans_handle *trans, |
3134 | struct extent_buffer *src; | 3159 | struct btrfs_root *root, struct inode *inode, |
3135 | u64 next_offset; | 3160 | struct extent_map *em, |
3136 | int start_slot; | 3161 | struct btrfs_path *path) |
3137 | int nr; | 3162 | { |
3138 | }; | 3163 | struct btrfs_file_extent_item *fi; |
3164 | struct extent_buffer *leaf; | ||
3165 | struct btrfs_key key, new_key; | ||
3166 | struct btrfs_map_token token; | ||
3167 | u64 extent_end; | ||
3168 | u64 extent_offset = 0; | ||
3169 | int extent_type; | ||
3170 | int del_slot = 0; | ||
3171 | int del_nr = 0; | ||
3172 | int ret = 0; | ||
3173 | |||
3174 | while (1) { | ||
3175 | btrfs_init_map_token(&token); | ||
3176 | leaf = path->nodes[0]; | ||
3177 | path->slots[0]++; | ||
3178 | if (path->slots[0] >= btrfs_header_nritems(leaf)) { | ||
3179 | if (del_nr) { | ||
3180 | ret = btrfs_del_items(trans, root, path, | ||
3181 | del_slot, del_nr); | ||
3182 | if (ret) | ||
3183 | return ret; | ||
3184 | del_nr = 0; | ||
3185 | } | ||
3186 | |||
3187 | ret = btrfs_next_leaf_write(trans, root, path, 1); | ||
3188 | if (ret < 0) | ||
3189 | return ret; | ||
3190 | if (ret > 0) | ||
3191 | return 0; | ||
3192 | leaf = path->nodes[0]; | ||
3193 | } | ||
3194 | |||
3195 | btrfs_item_key_to_cpu(leaf, &key, path->slots[0]); | ||
3196 | if (key.objectid != btrfs_ino(inode) || | ||
3197 | key.type != BTRFS_EXTENT_DATA_KEY || | ||
3198 | key.offset >= em->start + em->len) | ||
3199 | break; | ||
3200 | |||
3201 | fi = btrfs_item_ptr(leaf, path->slots[0], | ||
3202 | struct btrfs_file_extent_item); | ||
3203 | extent_type = btrfs_token_file_extent_type(leaf, fi, &token); | ||
3204 | if (extent_type == BTRFS_FILE_EXTENT_REG || | ||
3205 | extent_type == BTRFS_FILE_EXTENT_PREALLOC) { | ||
3206 | extent_offset = btrfs_token_file_extent_offset(leaf, | ||
3207 | fi, &token); | ||
3208 | extent_end = key.offset + | ||
3209 | btrfs_token_file_extent_num_bytes(leaf, fi, | ||
3210 | &token); | ||
3211 | } else if (extent_type == BTRFS_FILE_EXTENT_INLINE) { | ||
3212 | extent_end = key.offset + | ||
3213 | btrfs_file_extent_inline_len(leaf, fi); | ||
3214 | } else { | ||
3215 | BUG(); | ||
3216 | } | ||
3217 | |||
3218 | if (extent_end <= em->len + em->start) { | ||
3219 | if (!del_nr) { | ||
3220 | del_slot = path->slots[0]; | ||
3221 | } | ||
3222 | del_nr++; | ||
3223 | continue; | ||
3224 | } | ||
3225 | |||
3226 | /* | ||
3227 | * Ok so we'll ignore previous items if we log a new extent, | ||
3228 | * which can lead to overlapping extents, so if we have an | ||
3229 | * existing extent we want to adjust we _have_ to check the next | ||
3230 | * guy to make sure we even need this extent anymore, this keeps | ||
3231 | * us from panicing in set_item_key_safe. | ||
3232 | */ | ||
3233 | if (path->slots[0] < btrfs_header_nritems(leaf) - 1) { | ||
3234 | struct btrfs_key tmp_key; | ||
3235 | |||
3236 | btrfs_item_key_to_cpu(leaf, &tmp_key, | ||
3237 | path->slots[0] + 1); | ||
3238 | if (tmp_key.objectid == btrfs_ino(inode) && | ||
3239 | tmp_key.type == BTRFS_EXTENT_DATA_KEY && | ||
3240 | tmp_key.offset <= em->start + em->len) { | ||
3241 | if (!del_nr) | ||
3242 | del_slot = path->slots[0]; | ||
3243 | del_nr++; | ||
3244 | continue; | ||
3245 | } | ||
3246 | } | ||
3247 | |||
3248 | BUG_ON(extent_type == BTRFS_FILE_EXTENT_INLINE); | ||
3249 | memcpy(&new_key, &key, sizeof(new_key)); | ||
3250 | new_key.offset = em->start + em->len; | ||
3251 | btrfs_set_item_key_safe(trans, root, path, &new_key); | ||
3252 | extent_offset += em->start + em->len - key.offset; | ||
3253 | btrfs_set_token_file_extent_offset(leaf, fi, extent_offset, | ||
3254 | &token); | ||
3255 | btrfs_set_token_file_extent_num_bytes(leaf, fi, extent_end - | ||
3256 | (em->start + em->len), | ||
3257 | &token); | ||
3258 | btrfs_mark_buffer_dirty(leaf); | ||
3259 | } | ||
3260 | |||
3261 | if (del_nr) | ||
3262 | ret = btrfs_del_items(trans, root, path, del_slot, del_nr); | ||
3263 | |||
3264 | return ret; | ||
3265 | } | ||
3139 | 3266 | ||
3140 | static int log_one_extent(struct btrfs_trans_handle *trans, | 3267 | static int log_one_extent(struct btrfs_trans_handle *trans, |
3141 | struct inode *inode, struct btrfs_root *root, | 3268 | struct inode *inode, struct btrfs_root *root, |
3142 | struct extent_map *em, struct btrfs_path *path, | 3269 | struct extent_map *em, struct btrfs_path *path) |
3143 | struct btrfs_path *dst_path, struct log_args *args) | ||
3144 | { | 3270 | { |
3145 | struct btrfs_root *log = root->log_root; | 3271 | struct btrfs_root *log = root->log_root; |
3146 | struct btrfs_file_extent_item *fi; | 3272 | struct btrfs_file_extent_item *fi; |
3273 | struct extent_buffer *leaf; | ||
3274 | struct list_head ordered_sums; | ||
3275 | struct btrfs_map_token token; | ||
3147 | struct btrfs_key key; | 3276 | struct btrfs_key key; |
3148 | u64 start = em->mod_start; | 3277 | u64 csum_offset = em->mod_start - em->start; |
3149 | u64 search_start = start; | 3278 | u64 csum_len = em->mod_len; |
3150 | u64 len = em->mod_len; | 3279 | u64 extent_offset = em->start - em->orig_start; |
3151 | u64 num_bytes; | 3280 | u64 block_len; |
3152 | int nritems; | ||
3153 | int ret; | 3281 | int ret; |
3282 | bool skip_csum = BTRFS_I(inode)->flags & BTRFS_INODE_NODATASUM; | ||
3154 | 3283 | ||
3155 | if (BTRFS_I(inode)->logged_trans == trans->transid) { | 3284 | INIT_LIST_HEAD(&ordered_sums); |
3156 | ret = __btrfs_drop_extents(trans, log, inode, dst_path, start, | 3285 | btrfs_init_map_token(&token); |
3157 | start + len, NULL, 0); | 3286 | key.objectid = btrfs_ino(inode); |
3158 | if (ret) | 3287 | key.type = BTRFS_EXTENT_DATA_KEY; |
3159 | return ret; | 3288 | key.offset = em->start; |
3289 | path->really_keep_locks = 1; | ||
3290 | |||
3291 | ret = btrfs_insert_empty_item(trans, log, path, &key, sizeof(*fi)); | ||
3292 | if (ret && ret != -EEXIST) { | ||
3293 | path->really_keep_locks = 0; | ||
3294 | return ret; | ||
3160 | } | 3295 | } |
3296 | leaf = path->nodes[0]; | ||
3297 | fi = btrfs_item_ptr(leaf, path->slots[0], | ||
3298 | struct btrfs_file_extent_item); | ||
3299 | btrfs_set_token_file_extent_generation(leaf, fi, em->generation, | ||
3300 | &token); | ||
3301 | if (test_bit(EXTENT_FLAG_PREALLOC, &em->flags)) { | ||
3302 | skip_csum = true; | ||
3303 | btrfs_set_token_file_extent_type(leaf, fi, | ||
3304 | BTRFS_FILE_EXTENT_PREALLOC, | ||
3305 | &token); | ||
3306 | } else { | ||
3307 | btrfs_set_token_file_extent_type(leaf, fi, | ||
3308 | BTRFS_FILE_EXTENT_REG, | ||
3309 | &token); | ||
3310 | if (em->block_start == 0) | ||
3311 | skip_csum = true; | ||
3312 | } | ||
3313 | |||
3314 | block_len = max(em->block_len, em->orig_block_len); | ||
3315 | if (em->compress_type != BTRFS_COMPRESS_NONE) { | ||
3316 | btrfs_set_token_file_extent_disk_bytenr(leaf, fi, | ||
3317 | em->block_start, | ||
3318 | &token); | ||
3319 | btrfs_set_token_file_extent_disk_num_bytes(leaf, fi, block_len, | ||
3320 | &token); | ||
3321 | } else if (em->block_start < EXTENT_MAP_LAST_BYTE) { | ||
3322 | btrfs_set_token_file_extent_disk_bytenr(leaf, fi, | ||
3323 | em->block_start - | ||
3324 | extent_offset, &token); | ||
3325 | btrfs_set_token_file_extent_disk_num_bytes(leaf, fi, block_len, | ||
3326 | &token); | ||
3327 | } else { | ||
3328 | btrfs_set_token_file_extent_disk_bytenr(leaf, fi, 0, &token); | ||
3329 | btrfs_set_token_file_extent_disk_num_bytes(leaf, fi, 0, | ||
3330 | &token); | ||
3331 | } | ||
3332 | |||
3333 | btrfs_set_token_file_extent_offset(leaf, fi, | ||
3334 | em->start - em->orig_start, | ||
3335 | &token); | ||
3336 | btrfs_set_token_file_extent_num_bytes(leaf, fi, em->len, &token); | ||
3337 | btrfs_set_token_file_extent_ram_bytes(leaf, fi, em->len, &token); | ||
3338 | btrfs_set_token_file_extent_compression(leaf, fi, em->compress_type, | ||
3339 | &token); | ||
3340 | btrfs_set_token_file_extent_encryption(leaf, fi, 0, &token); | ||
3341 | btrfs_set_token_file_extent_other_encoding(leaf, fi, 0, &token); | ||
3342 | btrfs_mark_buffer_dirty(leaf); | ||
3161 | 3343 | ||
3162 | while (len) { | 3344 | /* |
3163 | if (args->nr) | 3345 | * Have to check the extent to the right of us to make sure it doesn't |
3164 | goto next_slot; | 3346 | * fall in our current range. We're ok if the previous extent is in our |
3165 | again: | 3347 | * range since the recovery stuff will run us in key order and thus just |
3166 | key.objectid = btrfs_ino(inode); | 3348 | * drop the part we overwrote. |
3167 | key.type = BTRFS_EXTENT_DATA_KEY; | 3349 | */ |
3168 | key.offset = search_start; | 3350 | ret = drop_adjacent_extents(trans, log, inode, em, path); |
3169 | 3351 | btrfs_release_path(path); | |
3170 | ret = btrfs_search_slot(NULL, root, &key, path, 0, 0); | 3352 | path->really_keep_locks = 0; |
3171 | if (ret < 0) | 3353 | if (ret) { |
3172 | return ret; | 3354 | return ret; |
3173 | 3355 | } | |
3174 | if (ret) { | ||
3175 | /* | ||
3176 | * A rare case were we can have an em for a section of a | ||
3177 | * larger extent so we need to make sure that this em | ||
3178 | * falls within the extent we've found. If not we just | ||
3179 | * bail and go back to ye-olde way of doing things but | ||
3180 | * it happens often enough in testing that we need to do | ||
3181 | * this dance to make sure. | ||
3182 | */ | ||
3183 | do { | ||
3184 | if (path->slots[0] == 0) { | ||
3185 | btrfs_release_path(path); | ||
3186 | if (search_start == 0) | ||
3187 | return -ENOENT; | ||
3188 | search_start--; | ||
3189 | goto again; | ||
3190 | } | ||
3191 | 3356 | ||
3192 | path->slots[0]--; | 3357 | if (skip_csum) |
3193 | btrfs_item_key_to_cpu(path->nodes[0], &key, | 3358 | return 0; |
3194 | path->slots[0]); | ||
3195 | if (key.objectid != btrfs_ino(inode) || | ||
3196 | key.type != BTRFS_EXTENT_DATA_KEY) { | ||
3197 | btrfs_release_path(path); | ||
3198 | return -ENOENT; | ||
3199 | } | ||
3200 | } while (key.offset > start); | ||
3201 | 3359 | ||
3202 | fi = btrfs_item_ptr(path->nodes[0], path->slots[0], | 3360 | if (em->compress_type) { |
3203 | struct btrfs_file_extent_item); | 3361 | csum_offset = 0; |
3204 | num_bytes = btrfs_file_extent_num_bytes(path->nodes[0], | 3362 | csum_len = block_len; |
3205 | fi); | 3363 | } |
3206 | if (key.offset + num_bytes <= start) { | ||
3207 | btrfs_release_path(path); | ||
3208 | return -ENOENT; | ||
3209 | } | ||
3210 | } | ||
3211 | args->src = path->nodes[0]; | ||
3212 | next_slot: | ||
3213 | btrfs_item_key_to_cpu(path->nodes[0], &key, path->slots[0]); | ||
3214 | fi = btrfs_item_ptr(args->src, path->slots[0], | ||
3215 | struct btrfs_file_extent_item); | ||
3216 | if (args->nr && | ||
3217 | args->start_slot + args->nr == path->slots[0]) { | ||
3218 | args->nr++; | ||
3219 | } else if (args->nr) { | ||
3220 | ret = copy_items(trans, inode, dst_path, args->src, | ||
3221 | args->start_slot, args->nr, | ||
3222 | LOG_INODE_ALL); | ||
3223 | if (ret) | ||
3224 | return ret; | ||
3225 | args->nr = 1; | ||
3226 | args->start_slot = path->slots[0]; | ||
3227 | } else if (!args->nr) { | ||
3228 | args->nr = 1; | ||
3229 | args->start_slot = path->slots[0]; | ||
3230 | } | ||
3231 | nritems = btrfs_header_nritems(path->nodes[0]); | ||
3232 | path->slots[0]++; | ||
3233 | num_bytes = btrfs_file_extent_num_bytes(args->src, fi); | ||
3234 | if (len < num_bytes) { | ||
3235 | /* I _think_ this is ok, envision we write to a | ||
3236 | * preallocated space that is adjacent to a previously | ||
3237 | * written preallocated space that gets merged when we | ||
3238 | * mark this preallocated space written. If we do not | ||
3239 | * have the adjacent extent in cache then when we copy | ||
3240 | * this extent it could end up being larger than our EM | ||
3241 | * thinks it is, which is a-ok, so just set len to 0. | ||
3242 | */ | ||
3243 | len = 0; | ||
3244 | } else { | ||
3245 | len -= num_bytes; | ||
3246 | } | ||
3247 | start = key.offset + num_bytes; | ||
3248 | args->next_offset = start; | ||
3249 | search_start = start; | ||
3250 | 3364 | ||
3251 | if (path->slots[0] < nritems) { | 3365 | /* block start is already adjusted for the file extent offset. */ |
3252 | if (len) | 3366 | ret = btrfs_lookup_csums_range(log->fs_info->csum_root, |
3253 | goto next_slot; | 3367 | em->block_start + csum_offset, |
3254 | break; | 3368 | em->block_start + csum_offset + |
3255 | } | 3369 | csum_len - 1, &ordered_sums, 0); |
3370 | if (ret) | ||
3371 | return ret; | ||
3256 | 3372 | ||
3257 | if (args->nr) { | 3373 | while (!list_empty(&ordered_sums)) { |
3258 | ret = copy_items(trans, inode, dst_path, args->src, | 3374 | struct btrfs_ordered_sum *sums = list_entry(ordered_sums.next, |
3259 | args->start_slot, args->nr, | 3375 | struct btrfs_ordered_sum, |
3260 | LOG_INODE_ALL); | 3376 | list); |
3261 | if (ret) | 3377 | if (!ret) |
3262 | return ret; | 3378 | ret = btrfs_csum_file_blocks(trans, log, sums); |
3263 | args->nr = 0; | 3379 | list_del(&sums->list); |
3264 | btrfs_release_path(path); | 3380 | kfree(sums); |
3265 | } | ||
3266 | } | 3381 | } |
3267 | 3382 | ||
3268 | return 0; | 3383 | return ret; |
3269 | } | 3384 | } |
3270 | 3385 | ||
3271 | static int btrfs_log_changed_extents(struct btrfs_trans_handle *trans, | 3386 | static int btrfs_log_changed_extents(struct btrfs_trans_handle *trans, |
3272 | struct btrfs_root *root, | 3387 | struct btrfs_root *root, |
3273 | struct inode *inode, | 3388 | struct inode *inode, |
3274 | struct btrfs_path *path, | 3389 | struct btrfs_path *path) |
3275 | struct btrfs_path *dst_path) | ||
3276 | { | 3390 | { |
3277 | struct log_args args; | ||
3278 | struct extent_map *em, *n; | 3391 | struct extent_map *em, *n; |
3279 | struct list_head extents; | 3392 | struct list_head extents; |
3280 | struct extent_map_tree *tree = &BTRFS_I(inode)->extent_tree; | 3393 | struct extent_map_tree *tree = &BTRFS_I(inode)->extent_tree; |
@@ -3283,8 +3396,6 @@ static int btrfs_log_changed_extents(struct btrfs_trans_handle *trans, | |||
3283 | 3396 | ||
3284 | INIT_LIST_HEAD(&extents); | 3397 | INIT_LIST_HEAD(&extents); |
3285 | 3398 | ||
3286 | memset(&args, 0, sizeof(args)); | ||
3287 | |||
3288 | write_lock(&tree->lock); | 3399 | write_lock(&tree->lock); |
3289 | test_gen = root->fs_info->last_trans_committed; | 3400 | test_gen = root->fs_info->last_trans_committed; |
3290 | 3401 | ||
@@ -3304,47 +3415,27 @@ static int btrfs_log_changed_extents(struct btrfs_trans_handle *trans, | |||
3304 | em = list_entry(extents.next, struct extent_map, list); | 3415 | em = list_entry(extents.next, struct extent_map, list); |
3305 | 3416 | ||
3306 | list_del_init(&em->list); | 3417 | list_del_init(&em->list); |
3307 | clear_bit(EXTENT_FLAG_LOGGING, &em->flags); | ||
3308 | 3418 | ||
3309 | /* | 3419 | /* |
3310 | * If we had an error we just need to delete everybody from our | 3420 | * If we had an error we just need to delete everybody from our |
3311 | * private list. | 3421 | * private list. |
3312 | */ | 3422 | */ |
3313 | if (ret) { | 3423 | if (ret) { |
3424 | clear_em_logging(tree, em); | ||
3314 | free_extent_map(em); | 3425 | free_extent_map(em); |
3315 | continue; | 3426 | continue; |
3316 | } | 3427 | } |
3317 | 3428 | ||
3318 | write_unlock(&tree->lock); | 3429 | write_unlock(&tree->lock); |
3319 | 3430 | ||
3320 | /* | 3431 | ret = log_one_extent(trans, inode, root, em, path); |
3321 | * If the previous EM and the last extent we left off on aren't | ||
3322 | * sequential then we need to copy the items we have and redo | ||
3323 | * our search | ||
3324 | */ | ||
3325 | if (args.nr && em->mod_start != args.next_offset) { | ||
3326 | ret = copy_items(trans, inode, dst_path, args.src, | ||
3327 | args.start_slot, args.nr, | ||
3328 | LOG_INODE_ALL); | ||
3329 | if (ret) { | ||
3330 | free_extent_map(em); | ||
3331 | write_lock(&tree->lock); | ||
3332 | continue; | ||
3333 | } | ||
3334 | btrfs_release_path(path); | ||
3335 | args.nr = 0; | ||
3336 | } | ||
3337 | |||
3338 | ret = log_one_extent(trans, inode, root, em, path, dst_path, &args); | ||
3339 | free_extent_map(em); | ||
3340 | write_lock(&tree->lock); | 3432 | write_lock(&tree->lock); |
3433 | clear_em_logging(tree, em); | ||
3434 | free_extent_map(em); | ||
3341 | } | 3435 | } |
3342 | WARN_ON(!list_empty(&extents)); | 3436 | WARN_ON(!list_empty(&extents)); |
3343 | write_unlock(&tree->lock); | 3437 | write_unlock(&tree->lock); |
3344 | 3438 | ||
3345 | if (!ret && args.nr) | ||
3346 | ret = copy_items(trans, inode, dst_path, args.src, | ||
3347 | args.start_slot, args.nr, LOG_INODE_ALL); | ||
3348 | btrfs_release_path(path); | 3439 | btrfs_release_path(path); |
3349 | return ret; | 3440 | return ret; |
3350 | } | 3441 | } |
@@ -3400,7 +3491,10 @@ static int btrfs_log_inode(struct btrfs_trans_handle *trans, | |||
3400 | 3491 | ||
3401 | 3492 | ||
3402 | /* today the code can only do partial logging of directories */ | 3493 | /* today the code can only do partial logging of directories */ |
3403 | if (inode_only == LOG_INODE_EXISTS || S_ISDIR(inode->i_mode)) | 3494 | if (S_ISDIR(inode->i_mode) || |
3495 | (!test_bit(BTRFS_INODE_NEEDS_FULL_SYNC, | ||
3496 | &BTRFS_I(inode)->runtime_flags) && | ||
3497 | inode_only == LOG_INODE_EXISTS)) | ||
3404 | max_key.type = BTRFS_XATTR_ITEM_KEY; | 3498 | max_key.type = BTRFS_XATTR_ITEM_KEY; |
3405 | else | 3499 | else |
3406 | max_key.type = (u8)-1; | 3500 | max_key.type = (u8)-1; |
@@ -3432,14 +3526,28 @@ static int btrfs_log_inode(struct btrfs_trans_handle *trans, | |||
3432 | } else { | 3526 | } else { |
3433 | if (test_and_clear_bit(BTRFS_INODE_NEEDS_FULL_SYNC, | 3527 | if (test_and_clear_bit(BTRFS_INODE_NEEDS_FULL_SYNC, |
3434 | &BTRFS_I(inode)->runtime_flags)) { | 3528 | &BTRFS_I(inode)->runtime_flags)) { |
3529 | clear_bit(BTRFS_INODE_COPY_EVERYTHING, | ||
3530 | &BTRFS_I(inode)->runtime_flags); | ||
3435 | ret = btrfs_truncate_inode_items(trans, log, | 3531 | ret = btrfs_truncate_inode_items(trans, log, |
3436 | inode, 0, 0); | 3532 | inode, 0, 0); |
3437 | } else { | 3533 | } else if (test_and_clear_bit(BTRFS_INODE_COPY_EVERYTHING, |
3438 | fast_search = true; | 3534 | &BTRFS_I(inode)->runtime_flags)) { |
3535 | if (inode_only == LOG_INODE_ALL) | ||
3536 | fast_search = true; | ||
3439 | max_key.type = BTRFS_XATTR_ITEM_KEY; | 3537 | max_key.type = BTRFS_XATTR_ITEM_KEY; |
3440 | ret = drop_objectid_items(trans, log, path, ino, | 3538 | ret = drop_objectid_items(trans, log, path, ino, |
3441 | BTRFS_XATTR_ITEM_KEY); | 3539 | max_key.type); |
3540 | } else { | ||
3541 | if (inode_only == LOG_INODE_ALL) | ||
3542 | fast_search = true; | ||
3543 | ret = log_inode_item(trans, log, dst_path, inode); | ||
3544 | if (ret) { | ||
3545 | err = ret; | ||
3546 | goto out_unlock; | ||
3547 | } | ||
3548 | goto log_extents; | ||
3442 | } | 3549 | } |
3550 | |||
3443 | } | 3551 | } |
3444 | if (ret) { | 3552 | if (ret) { |
3445 | err = ret; | 3553 | err = ret; |
@@ -3518,11 +3626,10 @@ next_slot: | |||
3518 | ins_nr = 0; | 3626 | ins_nr = 0; |
3519 | } | 3627 | } |
3520 | 3628 | ||
3629 | log_extents: | ||
3521 | if (fast_search) { | 3630 | if (fast_search) { |
3522 | btrfs_release_path(path); | ||
3523 | btrfs_release_path(dst_path); | 3631 | btrfs_release_path(dst_path); |
3524 | ret = btrfs_log_changed_extents(trans, root, inode, path, | 3632 | ret = btrfs_log_changed_extents(trans, root, inode, dst_path); |
3525 | dst_path); | ||
3526 | if (ret) { | 3633 | if (ret) { |
3527 | err = ret; | 3634 | err = ret; |
3528 | goto out_unlock; | 3635 | goto out_unlock; |
@@ -3531,8 +3638,10 @@ next_slot: | |||
3531 | struct extent_map_tree *tree = &BTRFS_I(inode)->extent_tree; | 3638 | struct extent_map_tree *tree = &BTRFS_I(inode)->extent_tree; |
3532 | struct extent_map *em, *n; | 3639 | struct extent_map *em, *n; |
3533 | 3640 | ||
3641 | write_lock(&tree->lock); | ||
3534 | list_for_each_entry_safe(em, n, &tree->modified_extents, list) | 3642 | list_for_each_entry_safe(em, n, &tree->modified_extents, list) |
3535 | list_del_init(&em->list); | 3643 | list_del_init(&em->list); |
3644 | write_unlock(&tree->lock); | ||
3536 | } | 3645 | } |
3537 | 3646 | ||
3538 | if (inode_only == LOG_INODE_ALL && S_ISDIR(inode->i_mode)) { | 3647 | if (inode_only == LOG_INODE_ALL && S_ISDIR(inode->i_mode)) { |