Skip to content

Commit

Permalink
Merge branch 'for-chris-4.11' of git://git.kernel.org/pub/scm/linux/k…
Browse files Browse the repository at this point in the history
…ernel/git/fdmanana/linux into for-linus-4.11
  • Loading branch information
masoncl committed Feb 27, 2017
2 parents 6288d6e + 263d399 commit ef6ebf3
Show file tree
Hide file tree
Showing 7 changed files with 188 additions and 30 deletions.
7 changes: 7 additions & 0 deletions fs/btrfs/ctree.c
Original file line number Diff line number Diff line change
Expand Up @@ -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;
Expand Down Expand Up @@ -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)
Expand Down
15 changes: 10 additions & 5 deletions fs/btrfs/disk-io.c
Original file line number Diff line number Diff line change
Expand Up @@ -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);
Expand All @@ -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)
Expand Down Expand Up @@ -3261,14 +3266,14 @@ int open_ctree(struct super_block *sb,

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);
invalidate_inode_pages2(fs_info->btree_inode->i_mapping);

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);
Expand Down Expand Up @@ -3977,15 +3982,15 @@ 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.
*/
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);

Expand Down
9 changes: 6 additions & 3 deletions fs/btrfs/extent-tree.c
Original file line number Diff line number Diff line change
Expand Up @@ -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;
Expand Down Expand Up @@ -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.
Expand All @@ -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));
Expand Down
28 changes: 27 additions & 1 deletion fs/btrfs/file-item.c
Original file line number Diff line number Diff line change
Expand Up @@ -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)
Expand Down
29 changes: 14 additions & 15 deletions fs/btrfs/inode.c
Original file line number Diff line number Diff line change
Expand Up @@ -1331,10 +1331,16 @@ static noinline int run_delalloc_nocow(struct inode *inode,
* 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 +
Expand Down Expand Up @@ -4412,19 +4418,8 @@ int btrfs_truncate_inode_items(struct btrfs_trans_handle *trans,
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
Expand Down Expand Up @@ -4607,8 +4602,12 @@ int btrfs_truncate_inode_items(struct btrfs_trans_handle *trans,
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);

Expand Down
125 changes: 119 additions & 6 deletions fs/btrfs/send.c
Original file line number Diff line number Diff line change
Expand Up @@ -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;
Expand Down Expand Up @@ -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)
Expand Down Expand Up @@ -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);
Expand Down Expand Up @@ -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;
Expand All @@ -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
Expand All @@ -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,
Expand All @@ -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:
Expand Down Expand Up @@ -5277,6 +5306,81 @@ static int get_last_extent(struct send_ctx *sctx, u64 offset)
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)
{
Expand Down Expand Up @@ -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;
}
Expand Down
Loading

0 comments on commit ef6ebf3

Please sign in to comment.