mirror of
https://github.com/ukui/kernel.git
synced 2026-03-09 10:07:04 -07:00
Merge branch 'for-chris-4.11' of git://git.kernel.org/pub/scm/linux/kernel/git/fdmanana/linux into for-linus-4.11
This commit is contained in:
@@ -4159,6 +4159,9 @@ static noinline int push_for_double_split(struct btrfs_trans_handle *trans,
|
||||
|
||||
/* try to push all the items before our slot into the next leaf */
|
||||
slot = path->slots[0];
|
||||
space_needed = data_size;
|
||||
if (slot > 0)
|
||||
space_needed -= btrfs_leaf_free_space(fs_info, path->nodes[0]);
|
||||
ret = push_leaf_left(trans, root, path, 1, space_needed, 0, slot);
|
||||
if (ret < 0)
|
||||
return ret;
|
||||
@@ -4214,6 +4217,10 @@ static noinline int split_leaf(struct btrfs_trans_handle *trans,
|
||||
if (wret < 0)
|
||||
return wret;
|
||||
if (wret) {
|
||||
space_needed = data_size;
|
||||
if (slot > 0)
|
||||
space_needed -= btrfs_leaf_free_space(fs_info,
|
||||
l);
|
||||
wret = push_leaf_left(trans, root, path, space_needed,
|
||||
space_needed, 0, (u32)-1);
|
||||
if (wret < 0)
|
||||
|
||||
@@ -2205,11 +2205,9 @@ static void btrfs_stop_all_workers(struct btrfs_fs_info *fs_info)
|
||||
btrfs_destroy_workqueue(fs_info->delalloc_workers);
|
||||
btrfs_destroy_workqueue(fs_info->workers);
|
||||
btrfs_destroy_workqueue(fs_info->endio_workers);
|
||||
btrfs_destroy_workqueue(fs_info->endio_meta_workers);
|
||||
btrfs_destroy_workqueue(fs_info->endio_raid56_workers);
|
||||
btrfs_destroy_workqueue(fs_info->endio_repair_workers);
|
||||
btrfs_destroy_workqueue(fs_info->rmw_workers);
|
||||
btrfs_destroy_workqueue(fs_info->endio_meta_write_workers);
|
||||
btrfs_destroy_workqueue(fs_info->endio_write_workers);
|
||||
btrfs_destroy_workqueue(fs_info->endio_freespace_worker);
|
||||
btrfs_destroy_workqueue(fs_info->submit_workers);
|
||||
@@ -2219,6 +2217,13 @@ static void btrfs_stop_all_workers(struct btrfs_fs_info *fs_info)
|
||||
btrfs_destroy_workqueue(fs_info->flush_workers);
|
||||
btrfs_destroy_workqueue(fs_info->qgroup_rescan_workers);
|
||||
btrfs_destroy_workqueue(fs_info->extent_workers);
|
||||
/*
|
||||
* Now that all other work queues are destroyed, we can safely destroy
|
||||
* the queues used for metadata I/O, since tasks from those other work
|
||||
* queues can do metadata I/O operations.
|
||||
*/
|
||||
btrfs_destroy_workqueue(fs_info->endio_meta_workers);
|
||||
btrfs_destroy_workqueue(fs_info->endio_meta_write_workers);
|
||||
}
|
||||
|
||||
static void free_root_extent_buffers(struct btrfs_root *root)
|
||||
@@ -3261,7 +3266,6 @@ fail_fsdev_sysfs:
|
||||
|
||||
fail_block_groups:
|
||||
btrfs_put_block_group_cache(fs_info);
|
||||
btrfs_free_block_groups(fs_info);
|
||||
|
||||
fail_tree_roots:
|
||||
free_root_pointers(fs_info, 1);
|
||||
@@ -3269,6 +3273,7 @@ fail_tree_roots:
|
||||
|
||||
fail_sb_buffer:
|
||||
btrfs_stop_all_workers(fs_info);
|
||||
btrfs_free_block_groups(fs_info);
|
||||
fail_alloc:
|
||||
fail_iput:
|
||||
btrfs_mapping_tree_free(&fs_info->mapping_tree);
|
||||
@@ -3977,8 +3982,6 @@ void close_ctree(struct btrfs_fs_info *fs_info)
|
||||
|
||||
btrfs_put_block_group_cache(fs_info);
|
||||
|
||||
btrfs_free_block_groups(fs_info);
|
||||
|
||||
/*
|
||||
* we must make sure there is not any read request to
|
||||
* submit after we stopping all workers.
|
||||
@@ -3986,6 +3989,8 @@ void close_ctree(struct btrfs_fs_info *fs_info)
|
||||
invalidate_inode_pages2(fs_info->btree_inode->i_mapping);
|
||||
btrfs_stop_all_workers(fs_info);
|
||||
|
||||
btrfs_free_block_groups(fs_info);
|
||||
|
||||
clear_bit(BTRFS_FS_OPEN, &fs_info->flags);
|
||||
free_root_pointers(fs_info, 1);
|
||||
|
||||
|
||||
@@ -9740,6 +9740,11 @@ void btrfs_put_block_group_cache(struct btrfs_fs_info *info)
|
||||
}
|
||||
}
|
||||
|
||||
/*
|
||||
* Must be called only after stopping all workers, since we could have block
|
||||
* group caching kthreads running, and therefore they could race with us if we
|
||||
* freed the block groups before stopping them.
|
||||
*/
|
||||
int btrfs_free_block_groups(struct btrfs_fs_info *info)
|
||||
{
|
||||
struct btrfs_block_group_cache *block_group;
|
||||
@@ -9779,9 +9784,6 @@ int btrfs_free_block_groups(struct btrfs_fs_info *info)
|
||||
list_del(&block_group->list);
|
||||
up_write(&block_group->space_info->groups_sem);
|
||||
|
||||
if (block_group->cached == BTRFS_CACHE_STARTED)
|
||||
wait_block_group_cache_done(block_group);
|
||||
|
||||
/*
|
||||
* We haven't cached this block group, which means we could
|
||||
* possibly have excluded extents on this block group.
|
||||
@@ -9791,6 +9793,7 @@ int btrfs_free_block_groups(struct btrfs_fs_info *info)
|
||||
free_excluded_extents(info, block_group);
|
||||
|
||||
btrfs_remove_free_space_cache(block_group);
|
||||
ASSERT(block_group->cached != BTRFS_CACHE_STARTED);
|
||||
ASSERT(list_empty(&block_group->dirty_list));
|
||||
ASSERT(list_empty(&block_group->io_list));
|
||||
ASSERT(list_empty(&block_group->bg_list));
|
||||
|
||||
@@ -643,7 +643,33 @@ int btrfs_del_csums(struct btrfs_trans_handle *trans,
|
||||
|
||||
/* delete the entire item, it is inside our range */
|
||||
if (key.offset >= bytenr && csum_end <= end_byte) {
|
||||
ret = btrfs_del_item(trans, root, path);
|
||||
int del_nr = 1;
|
||||
|
||||
/*
|
||||
* Check how many csum items preceding this one in this
|
||||
* leaf correspond to our range and then delete them all
|
||||
* at once.
|
||||
*/
|
||||
if (key.offset > bytenr && path->slots[0] > 0) {
|
||||
int slot = path->slots[0] - 1;
|
||||
|
||||
while (slot >= 0) {
|
||||
struct btrfs_key pk;
|
||||
|
||||
btrfs_item_key_to_cpu(leaf, &pk, slot);
|
||||
if (pk.offset < bytenr ||
|
||||
pk.type != BTRFS_EXTENT_CSUM_KEY ||
|
||||
pk.objectid !=
|
||||
BTRFS_EXTENT_CSUM_OBJECTID)
|
||||
break;
|
||||
path->slots[0] = slot;
|
||||
del_nr++;
|
||||
key.offset = pk.offset;
|
||||
slot--;
|
||||
}
|
||||
}
|
||||
ret = btrfs_del_items(trans, root, path,
|
||||
path->slots[0], del_nr);
|
||||
if (ret)
|
||||
goto out;
|
||||
if (key.offset == bytenr)
|
||||
|
||||
@@ -1331,10 +1331,16 @@ next_slot:
|
||||
* either valid or do not exist.
|
||||
*/
|
||||
if (csum_exist_in_range(fs_info, disk_bytenr,
|
||||
num_bytes))
|
||||
num_bytes)) {
|
||||
if (!nolock)
|
||||
btrfs_end_write_no_snapshoting(root);
|
||||
goto out_check;
|
||||
if (!btrfs_inc_nocow_writers(fs_info, disk_bytenr))
|
||||
}
|
||||
if (!btrfs_inc_nocow_writers(fs_info, disk_bytenr)) {
|
||||
if (!nolock)
|
||||
btrfs_end_write_no_snapshoting(root);
|
||||
goto out_check;
|
||||
}
|
||||
nocow = 1;
|
||||
} else if (extent_type == BTRFS_FILE_EXTENT_INLINE) {
|
||||
extent_end = found_key.offset +
|
||||
@@ -4412,19 +4418,8 @@ search_again:
|
||||
if (found_type > min_type) {
|
||||
del_item = 1;
|
||||
} else {
|
||||
if (item_end < new_size) {
|
||||
/*
|
||||
* With NO_HOLES mode, for the following mapping
|
||||
*
|
||||
* [0-4k][hole][8k-12k]
|
||||
*
|
||||
* if truncating isize down to 6k, it ends up
|
||||
* isize being 8k.
|
||||
*/
|
||||
if (btrfs_fs_incompat(root->fs_info, NO_HOLES))
|
||||
last_size = new_size;
|
||||
if (item_end < new_size)
|
||||
break;
|
||||
}
|
||||
if (found_key.offset >= new_size)
|
||||
del_item = 1;
|
||||
else
|
||||
@@ -4607,8 +4602,12 @@ out:
|
||||
btrfs_abort_transaction(trans, ret);
|
||||
}
|
||||
error:
|
||||
if (root->root_key.objectid != BTRFS_TREE_LOG_OBJECTID)
|
||||
if (root->root_key.objectid != BTRFS_TREE_LOG_OBJECTID) {
|
||||
ASSERT(last_size >= new_size);
|
||||
if (!err && last_size > new_size)
|
||||
last_size = new_size;
|
||||
btrfs_ordered_update_i_size(inode, last_size, NULL);
|
||||
}
|
||||
|
||||
btrfs_free_path(path);
|
||||
|
||||
|
||||
125
fs/btrfs/send.c
125
fs/btrfs/send.c
@@ -1681,6 +1681,9 @@ static int is_inode_existent(struct send_ctx *sctx, u64 ino, u64 gen)
|
||||
{
|
||||
int ret;
|
||||
|
||||
if (ino == BTRFS_FIRST_FREE_OBJECTID)
|
||||
return 1;
|
||||
|
||||
ret = get_cur_inode_state(sctx, ino, gen);
|
||||
if (ret < 0)
|
||||
goto out;
|
||||
@@ -1866,7 +1869,7 @@ static int will_overwrite_ref(struct send_ctx *sctx, u64 dir, u64 dir_gen,
|
||||
* not deleted and then re-created, if it was then we have no overwrite
|
||||
* and we can just unlink this entry.
|
||||
*/
|
||||
if (sctx->parent_root) {
|
||||
if (sctx->parent_root && dir != BTRFS_FIRST_FREE_OBJECTID) {
|
||||
ret = get_inode_info(sctx->parent_root, dir, NULL, &gen, NULL,
|
||||
NULL, NULL, NULL);
|
||||
if (ret < 0 && ret != -ENOENT)
|
||||
@@ -1934,6 +1937,19 @@ static int did_overwrite_ref(struct send_ctx *sctx,
|
||||
if (ret <= 0)
|
||||
goto out;
|
||||
|
||||
if (dir != BTRFS_FIRST_FREE_OBJECTID) {
|
||||
ret = get_inode_info(sctx->send_root, dir, NULL, &gen, NULL,
|
||||
NULL, NULL, NULL);
|
||||
if (ret < 0 && ret != -ENOENT)
|
||||
goto out;
|
||||
if (ret) {
|
||||
ret = 0;
|
||||
goto out;
|
||||
}
|
||||
if (gen != dir_gen)
|
||||
goto out;
|
||||
}
|
||||
|
||||
/* check if the ref was overwritten by another ref */
|
||||
ret = lookup_dir_item_inode(sctx->send_root, dir, name, name_len,
|
||||
&ow_inode, &other_type);
|
||||
@@ -3556,6 +3572,7 @@ static int wait_for_parent_move(struct send_ctx *sctx,
|
||||
{
|
||||
int ret = 0;
|
||||
u64 ino = parent_ref->dir;
|
||||
u64 ino_gen = parent_ref->dir_gen;
|
||||
u64 parent_ino_before, parent_ino_after;
|
||||
struct fs_path *path_before = NULL;
|
||||
struct fs_path *path_after = NULL;
|
||||
@@ -3576,6 +3593,8 @@ static int wait_for_parent_move(struct send_ctx *sctx,
|
||||
* at get_cur_path()).
|
||||
*/
|
||||
while (ino > BTRFS_FIRST_FREE_OBJECTID) {
|
||||
u64 parent_ino_after_gen;
|
||||
|
||||
if (is_waiting_for_move(sctx, ino)) {
|
||||
/*
|
||||
* If the current inode is an ancestor of ino in the
|
||||
@@ -3598,7 +3617,7 @@ static int wait_for_parent_move(struct send_ctx *sctx,
|
||||
fs_path_reset(path_after);
|
||||
|
||||
ret = get_first_ref(sctx->send_root, ino, &parent_ino_after,
|
||||
NULL, path_after);
|
||||
&parent_ino_after_gen, path_after);
|
||||
if (ret < 0)
|
||||
goto out;
|
||||
ret = get_first_ref(sctx->parent_root, ino, &parent_ino_before,
|
||||
@@ -3615,10 +3634,20 @@ static int wait_for_parent_move(struct send_ctx *sctx,
|
||||
if (ino > sctx->cur_ino &&
|
||||
(parent_ino_before != parent_ino_after || len1 != len2 ||
|
||||
memcmp(path_before->start, path_after->start, len1))) {
|
||||
ret = 1;
|
||||
break;
|
||||
u64 parent_ino_gen;
|
||||
|
||||
ret = get_inode_info(sctx->parent_root, ino, NULL,
|
||||
&parent_ino_gen, NULL, NULL, NULL,
|
||||
NULL);
|
||||
if (ret < 0)
|
||||
goto out;
|
||||
if (ino_gen == parent_ino_gen) {
|
||||
ret = 1;
|
||||
break;
|
||||
}
|
||||
}
|
||||
ino = parent_ino_after;
|
||||
ino_gen = parent_ino_after_gen;
|
||||
}
|
||||
|
||||
out:
|
||||
@@ -5277,6 +5306,81 @@ out:
|
||||
return ret;
|
||||
}
|
||||
|
||||
static int range_is_hole_in_parent(struct send_ctx *sctx,
|
||||
const u64 start,
|
||||
const u64 end)
|
||||
{
|
||||
struct btrfs_path *path;
|
||||
struct btrfs_key key;
|
||||
struct btrfs_root *root = sctx->parent_root;
|
||||
u64 search_start = start;
|
||||
int ret;
|
||||
|
||||
path = alloc_path_for_send();
|
||||
if (!path)
|
||||
return -ENOMEM;
|
||||
|
||||
key.objectid = sctx->cur_ino;
|
||||
key.type = BTRFS_EXTENT_DATA_KEY;
|
||||
key.offset = search_start;
|
||||
ret = btrfs_search_slot(NULL, root, &key, path, 0, 0);
|
||||
if (ret < 0)
|
||||
goto out;
|
||||
if (ret > 0 && path->slots[0] > 0)
|
||||
path->slots[0]--;
|
||||
|
||||
while (search_start < end) {
|
||||
struct extent_buffer *leaf = path->nodes[0];
|
||||
int slot = path->slots[0];
|
||||
struct btrfs_file_extent_item *fi;
|
||||
u64 extent_end;
|
||||
|
||||
if (slot >= btrfs_header_nritems(leaf)) {
|
||||
ret = btrfs_next_leaf(root, path);
|
||||
if (ret < 0)
|
||||
goto out;
|
||||
else if (ret > 0)
|
||||
break;
|
||||
continue;
|
||||
}
|
||||
|
||||
btrfs_item_key_to_cpu(leaf, &key, slot);
|
||||
if (key.objectid < sctx->cur_ino ||
|
||||
key.type < BTRFS_EXTENT_DATA_KEY)
|
||||
goto next;
|
||||
if (key.objectid > sctx->cur_ino ||
|
||||
key.type > BTRFS_EXTENT_DATA_KEY ||
|
||||
key.offset >= end)
|
||||
break;
|
||||
|
||||
fi = btrfs_item_ptr(leaf, slot, struct btrfs_file_extent_item);
|
||||
if (btrfs_file_extent_type(leaf, fi) ==
|
||||
BTRFS_FILE_EXTENT_INLINE) {
|
||||
u64 size = btrfs_file_extent_inline_len(leaf, slot, fi);
|
||||
|
||||
extent_end = ALIGN(key.offset + size,
|
||||
root->fs_info->sectorsize);
|
||||
} else {
|
||||
extent_end = key.offset +
|
||||
btrfs_file_extent_num_bytes(leaf, fi);
|
||||
}
|
||||
if (extent_end <= start)
|
||||
goto next;
|
||||
if (btrfs_file_extent_disk_bytenr(leaf, fi) == 0) {
|
||||
search_start = extent_end;
|
||||
goto next;
|
||||
}
|
||||
ret = 0;
|
||||
goto out;
|
||||
next:
|
||||
path->slots[0]++;
|
||||
}
|
||||
ret = 1;
|
||||
out:
|
||||
btrfs_free_path(path);
|
||||
return ret;
|
||||
}
|
||||
|
||||
static int maybe_send_hole(struct send_ctx *sctx, struct btrfs_path *path,
|
||||
struct btrfs_key *key)
|
||||
{
|
||||
@@ -5321,8 +5425,17 @@ static int maybe_send_hole(struct send_ctx *sctx, struct btrfs_path *path,
|
||||
return ret;
|
||||
}
|
||||
|
||||
if (sctx->cur_inode_last_extent < key->offset)
|
||||
ret = send_hole(sctx, key->offset);
|
||||
if (sctx->cur_inode_last_extent < key->offset) {
|
||||
ret = range_is_hole_in_parent(sctx,
|
||||
sctx->cur_inode_last_extent,
|
||||
key->offset);
|
||||
if (ret < 0)
|
||||
return ret;
|
||||
else if (ret == 0)
|
||||
ret = send_hole(sctx, key->offset);
|
||||
else
|
||||
ret = 0;
|
||||
}
|
||||
sctx->cur_inode_last_extent = extent_end;
|
||||
return ret;
|
||||
}
|
||||
|
||||
@@ -673,6 +673,10 @@ static noinline int replay_one_extent(struct btrfs_trans_handle *trans,
|
||||
unsigned long dest_offset;
|
||||
struct btrfs_key ins;
|
||||
|
||||
if (btrfs_file_extent_disk_bytenr(eb, item) == 0 &&
|
||||
btrfs_fs_incompat(fs_info, NO_HOLES))
|
||||
goto update_inode;
|
||||
|
||||
ret = btrfs_insert_empty_item(trans, root, path, key,
|
||||
sizeof(*item));
|
||||
if (ret)
|
||||
@@ -825,6 +829,7 @@ static noinline int replay_one_extent(struct btrfs_trans_handle *trans,
|
||||
}
|
||||
|
||||
inode_add_bytes(inode, nbytes);
|
||||
update_inode:
|
||||
ret = btrfs_update_inode(trans, root, inode);
|
||||
out:
|
||||
if (inode)
|
||||
|
||||
Reference in New Issue
Block a user