From a944442c2b8a420301e7830f976bab8cc86a2b4d Mon Sep 17 00:00:00 2001 From: Allen Pais Date: Tue, 12 Jun 2018 17:18:25 +0530 Subject: btrfs: replace get_seconds with new 64bit time API The get_seconds() function is deprecated as it truncates the timestamp to 32 bits. Change it to or ktime_get_real_seconds(). Signed-off-by: Allen Pais Reviewed-by: David Sterba [ update changelog ] Signed-off-by: David Sterba --- fs/btrfs/ctree.h | 4 ++-- fs/btrfs/dev-replace.c | 8 ++++---- fs/btrfs/disk-io.c | 4 ++-- fs/btrfs/transaction.c | 2 +- fs/btrfs/transaction.h | 2 +- 5 files changed, 10 insertions(+), 10 deletions(-) (limited to 'fs') diff --git a/fs/btrfs/ctree.h b/fs/btrfs/ctree.h index 118346aceea9..e671a1fcbbec 100644 --- a/fs/btrfs/ctree.h +++ b/fs/btrfs/ctree.h @@ -342,8 +342,8 @@ struct btrfs_path { sizeof(struct btrfs_item)) struct btrfs_dev_replace { u64 replace_state; /* see #define above */ - u64 time_started; /* seconds since 1-Jan-1970 */ - u64 time_stopped; /* seconds since 1-Jan-1970 */ + time64_t time_started; /* seconds since 1-Jan-1970 */ + time64_t time_stopped; /* seconds since 1-Jan-1970 */ atomic64_t num_write_errors; atomic64_t num_uncorrectable_read_errors; diff --git a/fs/btrfs/dev-replace.c b/fs/btrfs/dev-replace.c index e2ba0419297a..1b30c38d05c9 100644 --- a/fs/btrfs/dev-replace.c +++ b/fs/btrfs/dev-replace.c @@ -465,7 +465,7 @@ int btrfs_dev_replace_start(struct btrfs_fs_info *fs_info, * go to the tgtdev as well (refer to btrfs_map_block()). */ dev_replace->replace_state = BTRFS_IOCTL_DEV_REPLACE_STATE_STARTED; - dev_replace->time_started = get_seconds(); + dev_replace->time_started = ktime_get_real_seconds(); dev_replace->cursor_left = 0; dev_replace->committed_cursor_left = 0; dev_replace->cursor_left_last_write_of_item = 0; @@ -618,7 +618,7 @@ static int btrfs_dev_replace_finishing(struct btrfs_fs_info *fs_info, : BTRFS_IOCTL_DEV_REPLACE_STATE_FINISHED; dev_replace->tgtdev = NULL; dev_replace->srcdev = NULL; - dev_replace->time_stopped = get_seconds(); + dev_replace->time_stopped = ktime_get_real_seconds(); dev_replace->item_needs_writeback = 1; /* replace old device with new one in mapping tree */ @@ -807,7 +807,7 @@ int btrfs_dev_replace_cancel(struct btrfs_fs_info *fs_info) break; } dev_replace->replace_state = BTRFS_IOCTL_DEV_REPLACE_STATE_CANCELED; - dev_replace->time_stopped = get_seconds(); + dev_replace->time_stopped = ktime_get_real_seconds(); dev_replace->item_needs_writeback = 1; btrfs_dev_replace_write_unlock(dev_replace); btrfs_scrub_cancel(fs_info); @@ -848,7 +848,7 @@ void btrfs_dev_replace_suspend_for_unmount(struct btrfs_fs_info *fs_info) case BTRFS_IOCTL_DEV_REPLACE_STATE_STARTED: dev_replace->replace_state = BTRFS_IOCTL_DEV_REPLACE_STATE_SUSPENDED; - dev_replace->time_stopped = get_seconds(); + dev_replace->time_stopped = ktime_get_real_seconds(); dev_replace->item_needs_writeback = 1; btrfs_info(fs_info, "suspending dev_replace for unmount"); break; diff --git a/fs/btrfs/disk-io.c b/fs/btrfs/disk-io.c index 205092dc9390..f3224e23d5fa 100644 --- a/fs/btrfs/disk-io.c +++ b/fs/btrfs/disk-io.c @@ -1803,7 +1803,7 @@ static int transaction_kthread(void *arg) struct btrfs_trans_handle *trans; struct btrfs_transaction *cur; u64 transid; - unsigned long now; + time64_t now; unsigned long delay; bool cannot_commit; @@ -1819,7 +1819,7 @@ static int transaction_kthread(void *arg) goto sleep; } - now = get_seconds(); + now = ktime_get_real_seconds(); if (cur->state < TRANS_STATE_BLOCKED && !test_bit(BTRFS_FS_NEED_ASYNC_COMMIT, &fs_info->flags) && (now < cur->start_time || diff --git a/fs/btrfs/transaction.c b/fs/btrfs/transaction.c index ff5f6c719976..56c8bab0b816 100644 --- a/fs/btrfs/transaction.c +++ b/fs/btrfs/transaction.c @@ -241,7 +241,7 @@ loop: refcount_set(&cur_trans->use_count, 2); atomic_set(&cur_trans->pending_ordered, 0); cur_trans->flags = 0; - cur_trans->start_time = get_seconds(); + cur_trans->start_time = ktime_get_real_seconds(); memset(&cur_trans->delayed_refs, 0, sizeof(cur_trans->delayed_refs)); diff --git a/fs/btrfs/transaction.h b/fs/btrfs/transaction.h index 94439482a0ec..4cbb1b55387d 100644 --- a/fs/btrfs/transaction.h +++ b/fs/btrfs/transaction.h @@ -48,7 +48,7 @@ struct btrfs_transaction { int aborted; struct list_head list; struct extent_io_tree dirty_pages; - unsigned long start_time; + time64_t start_time; wait_queue_head_t writer_wait; wait_queue_head_t commit_wait; wait_queue_head_t pending_wait; -- cgit v1.2.3 From 9bebe665c3e4f4af30add8602217938d8c17ee23 Mon Sep 17 00:00:00 2001 From: Qu Wenruo Date: Wed, 6 Jun 2018 13:13:12 +0800 Subject: btrfs: scrub: Remove unused copy_nocow_pages and its callchain Since commit ac0b4145d662a3b9e340 ("btrfs: scrub: Don't use inode pages for device replace") the function is not used and we can remove all functions down the call chain. There was an optimization that reused inode pages to speed up device replace, but broke when there was nodatasum and compressed page. The potential performance gain is small so we don't loose much by removing it and using scrub_pages same as the other pages. Signed-off-by: Qu Wenruo [ update changelog ] Signed-off-by: David Sterba --- fs/btrfs/scrub.c | 365 ------------------------------------------------------- 1 file changed, 365 deletions(-) (limited to 'fs') diff --git a/fs/btrfs/scrub.c b/fs/btrfs/scrub.c index 6702896cdb8f..5bce2330ec64 100644 --- a/fs/btrfs/scrub.c +++ b/fs/btrfs/scrub.c @@ -197,23 +197,6 @@ struct scrub_fixup_nodatasum { int mirror_num; }; -struct scrub_nocow_inode { - u64 inum; - u64 offset; - u64 root; - struct list_head list; -}; - -struct scrub_copy_nocow_ctx { - struct scrub_ctx *sctx; - u64 logical; - u64 len; - int mirror_num; - u64 physical_for_dev_replace; - struct list_head inodes; - struct btrfs_work work; -}; - struct scrub_warning { struct btrfs_path *path; u64 extent_item_size; @@ -277,13 +260,6 @@ static int scrub_add_page_to_wr_bio(struct scrub_ctx *sctx, static void scrub_wr_submit(struct scrub_ctx *sctx); static void scrub_wr_bio_end_io(struct bio *bio); static void scrub_wr_bio_end_io_worker(struct btrfs_work *work); -static int write_page_nocow(struct scrub_ctx *sctx, - u64 physical_for_dev_replace, struct page *page); -static int copy_nocow_pages_for_inode(u64 inum, u64 offset, u64 root, - struct scrub_copy_nocow_ctx *ctx); -static int copy_nocow_pages(struct scrub_ctx *sctx, u64 logical, u64 len, - int mirror_num, u64 physical_for_dev_replace); -static void copy_nocow_pages_worker(struct btrfs_work *work); static void __scrub_blocked_if_needed(struct btrfs_fs_info *fs_info); static void scrub_blocked_if_needed(struct btrfs_fs_info *fs_info); static void scrub_put_ctx(struct scrub_ctx *sctx); @@ -2800,17 +2776,10 @@ static int scrub_extent(struct scrub_ctx *sctx, struct map_lookup *map, have_csum = scrub_find_csum(sctx, logical, csum); if (have_csum == 0) ++sctx->stat.no_csum; - if (0 && sctx->is_dev_replace && !have_csum) { - ret = copy_nocow_pages(sctx, logical, l, - mirror_num, - physical_for_dev_replace); - goto behind_scrub_pages; - } } ret = scrub_pages(sctx, logical, l, physical, dev, flags, gen, mirror_num, have_csum ? csum : NULL, 0, physical_for_dev_replace); -behind_scrub_pages: if (ret) return ret; len -= l; @@ -4072,10 +4041,6 @@ static noinline_for_stack int scrub_workers_get(struct btrfs_fs_info *fs_info, if (!fs_info->scrub_wr_completion_workers) goto fail_scrub_wr_completion_workers; - fs_info->scrub_nocow_workers = - btrfs_alloc_workqueue(fs_info, "scrubnc", flags, 1, 0); - if (!fs_info->scrub_nocow_workers) - goto fail_scrub_nocow_workers; fs_info->scrub_parity_workers = btrfs_alloc_workqueue(fs_info, "scrubparity", flags, max_active, 2); @@ -4086,8 +4051,6 @@ static noinline_for_stack int scrub_workers_get(struct btrfs_fs_info *fs_info, return 0; fail_scrub_parity_workers: - btrfs_destroy_workqueue(fs_info->scrub_nocow_workers); -fail_scrub_nocow_workers: btrfs_destroy_workqueue(fs_info->scrub_wr_completion_workers); fail_scrub_wr_completion_workers: btrfs_destroy_workqueue(fs_info->scrub_workers); @@ -4100,7 +4063,6 @@ static noinline_for_stack void scrub_workers_put(struct btrfs_fs_info *fs_info) if (--fs_info->scrub_workers_refcnt == 0) { btrfs_destroy_workqueue(fs_info->scrub_workers); btrfs_destroy_workqueue(fs_info->scrub_wr_completion_workers); - btrfs_destroy_workqueue(fs_info->scrub_nocow_workers); btrfs_destroy_workqueue(fs_info->scrub_parity_workers); } WARN_ON(fs_info->scrub_workers_refcnt < 0); @@ -4359,330 +4321,3 @@ static void scrub_remap_extent(struct btrfs_fs_info *fs_info, *extent_dev = bbio->stripes[0].dev; btrfs_put_bbio(bbio); } - -static int copy_nocow_pages(struct scrub_ctx *sctx, u64 logical, u64 len, - int mirror_num, u64 physical_for_dev_replace) -{ - struct scrub_copy_nocow_ctx *nocow_ctx; - struct btrfs_fs_info *fs_info = sctx->fs_info; - - nocow_ctx = kzalloc(sizeof(*nocow_ctx), GFP_NOFS); - if (!nocow_ctx) { - spin_lock(&sctx->stat_lock); - sctx->stat.malloc_errors++; - spin_unlock(&sctx->stat_lock); - return -ENOMEM; - } - - scrub_pending_trans_workers_inc(sctx); - - nocow_ctx->sctx = sctx; - nocow_ctx->logical = logical; - nocow_ctx->len = len; - nocow_ctx->mirror_num = mirror_num; - nocow_ctx->physical_for_dev_replace = physical_for_dev_replace; - btrfs_init_work(&nocow_ctx->work, btrfs_scrubnc_helper, - copy_nocow_pages_worker, NULL, NULL); - INIT_LIST_HEAD(&nocow_ctx->inodes); - btrfs_queue_work(fs_info->scrub_nocow_workers, - &nocow_ctx->work); - - return 0; -} - -static int record_inode_for_nocow(u64 inum, u64 offset, u64 root, void *ctx) -{ - struct scrub_copy_nocow_ctx *nocow_ctx = ctx; - struct scrub_nocow_inode *nocow_inode; - - nocow_inode = kzalloc(sizeof(*nocow_inode), GFP_NOFS); - if (!nocow_inode) - return -ENOMEM; - nocow_inode->inum = inum; - nocow_inode->offset = offset; - nocow_inode->root = root; - list_add_tail(&nocow_inode->list, &nocow_ctx->inodes); - return 0; -} - -#define COPY_COMPLETE 1 - -static void copy_nocow_pages_worker(struct btrfs_work *work) -{ - struct scrub_copy_nocow_ctx *nocow_ctx = - container_of(work, struct scrub_copy_nocow_ctx, work); - struct scrub_ctx *sctx = nocow_ctx->sctx; - struct btrfs_fs_info *fs_info = sctx->fs_info; - struct btrfs_root *root = fs_info->extent_root; - u64 logical = nocow_ctx->logical; - u64 len = nocow_ctx->len; - int mirror_num = nocow_ctx->mirror_num; - u64 physical_for_dev_replace = nocow_ctx->physical_for_dev_replace; - int ret; - struct btrfs_trans_handle *trans = NULL; - struct btrfs_path *path; - int not_written = 0; - - path = btrfs_alloc_path(); - if (!path) { - spin_lock(&sctx->stat_lock); - sctx->stat.malloc_errors++; - spin_unlock(&sctx->stat_lock); - not_written = 1; - goto out; - } - - trans = btrfs_join_transaction(root); - if (IS_ERR(trans)) { - not_written = 1; - goto out; - } - - ret = iterate_inodes_from_logical(logical, fs_info, path, - record_inode_for_nocow, nocow_ctx, false); - if (ret != 0 && ret != -ENOENT) { - btrfs_warn(fs_info, - "iterate_inodes_from_logical() failed: log %llu, phys %llu, len %llu, mir %u, ret %d", - logical, physical_for_dev_replace, len, mirror_num, - ret); - not_written = 1; - goto out; - } - - btrfs_end_transaction(trans); - trans = NULL; - while (!list_empty(&nocow_ctx->inodes)) { - struct scrub_nocow_inode *entry; - entry = list_first_entry(&nocow_ctx->inodes, - struct scrub_nocow_inode, - list); - list_del_init(&entry->list); - ret = copy_nocow_pages_for_inode(entry->inum, entry->offset, - entry->root, nocow_ctx); - kfree(entry); - if (ret == COPY_COMPLETE) { - ret = 0; - break; - } else if (ret) { - break; - } - } -out: - while (!list_empty(&nocow_ctx->inodes)) { - struct scrub_nocow_inode *entry; - entry = list_first_entry(&nocow_ctx->inodes, - struct scrub_nocow_inode, - list); - list_del_init(&entry->list); - kfree(entry); - } - if (trans && !IS_ERR(trans)) - btrfs_end_transaction(trans); - if (not_written) - btrfs_dev_replace_stats_inc(&fs_info->dev_replace. - num_uncorrectable_read_errors); - - btrfs_free_path(path); - kfree(nocow_ctx); - - scrub_pending_trans_workers_dec(sctx); -} - -static int check_extent_to_block(struct btrfs_inode *inode, u64 start, u64 len, - u64 logical) -{ - struct extent_state *cached_state = NULL; - struct btrfs_ordered_extent *ordered; - struct extent_io_tree *io_tree; - struct extent_map *em; - u64 lockstart = start, lockend = start + len - 1; - int ret = 0; - - io_tree = &inode->io_tree; - - lock_extent_bits(io_tree, lockstart, lockend, &cached_state); - ordered = btrfs_lookup_ordered_range(inode, lockstart, len); - if (ordered) { - btrfs_put_ordered_extent(ordered); - ret = 1; - goto out_unlock; - } - - em = btrfs_get_extent(inode, NULL, 0, start, len, 0); - if (IS_ERR(em)) { - ret = PTR_ERR(em); - goto out_unlock; - } - - /* - * This extent does not actually cover the logical extent anymore, - * move on to the next inode. - */ - if (em->block_start > logical || - em->block_start + em->block_len < logical + len || - test_bit(EXTENT_FLAG_PREALLOC, &em->flags)) { - free_extent_map(em); - ret = 1; - goto out_unlock; - } - free_extent_map(em); - -out_unlock: - unlock_extent_cached(io_tree, lockstart, lockend, &cached_state); - return ret; -} - -static int copy_nocow_pages_for_inode(u64 inum, u64 offset, u64 root, - struct scrub_copy_nocow_ctx *nocow_ctx) -{ - struct btrfs_fs_info *fs_info = nocow_ctx->sctx->fs_info; - struct btrfs_key key; - struct inode *inode; - struct page *page; - struct btrfs_root *local_root; - struct extent_io_tree *io_tree; - u64 physical_for_dev_replace; - u64 nocow_ctx_logical; - u64 len = nocow_ctx->len; - unsigned long index; - int srcu_index; - int ret = 0; - int err = 0; - - key.objectid = root; - key.type = BTRFS_ROOT_ITEM_KEY; - key.offset = (u64)-1; - - srcu_index = srcu_read_lock(&fs_info->subvol_srcu); - - local_root = btrfs_read_fs_root_no_name(fs_info, &key); - if (IS_ERR(local_root)) { - srcu_read_unlock(&fs_info->subvol_srcu, srcu_index); - return PTR_ERR(local_root); - } - - key.type = BTRFS_INODE_ITEM_KEY; - key.objectid = inum; - key.offset = 0; - inode = btrfs_iget(fs_info->sb, &key, local_root, NULL); - srcu_read_unlock(&fs_info->subvol_srcu, srcu_index); - if (IS_ERR(inode)) - return PTR_ERR(inode); - - /* Avoid truncate/dio/punch hole.. */ - inode_lock(inode); - inode_dio_wait(inode); - - physical_for_dev_replace = nocow_ctx->physical_for_dev_replace; - io_tree = &BTRFS_I(inode)->io_tree; - nocow_ctx_logical = nocow_ctx->logical; - - ret = check_extent_to_block(BTRFS_I(inode), offset, len, - nocow_ctx_logical); - if (ret) { - ret = ret > 0 ? 0 : ret; - goto out; - } - - while (len >= PAGE_SIZE) { - index = offset >> PAGE_SHIFT; -again: - page = find_or_create_page(inode->i_mapping, index, GFP_NOFS); - if (!page) { - btrfs_err(fs_info, "find_or_create_page() failed"); - ret = -ENOMEM; - goto out; - } - - if (PageUptodate(page)) { - if (PageDirty(page)) - goto next_page; - } else { - ClearPageError(page); - err = extent_read_full_page(io_tree, page, - btrfs_get_extent, - nocow_ctx->mirror_num); - if (err) { - ret = err; - goto next_page; - } - - lock_page(page); - /* - * If the page has been remove from the page cache, - * the data on it is meaningless, because it may be - * old one, the new data may be written into the new - * page in the page cache. - */ - if (page->mapping != inode->i_mapping) { - unlock_page(page); - put_page(page); - goto again; - } - if (!PageUptodate(page)) { - ret = -EIO; - goto next_page; - } - } - - ret = check_extent_to_block(BTRFS_I(inode), offset, len, - nocow_ctx_logical); - if (ret) { - ret = ret > 0 ? 0 : ret; - goto next_page; - } - - err = write_page_nocow(nocow_ctx->sctx, - physical_for_dev_replace, page); - if (err) - ret = err; -next_page: - unlock_page(page); - put_page(page); - - if (ret) - break; - - offset += PAGE_SIZE; - physical_for_dev_replace += PAGE_SIZE; - nocow_ctx_logical += PAGE_SIZE; - len -= PAGE_SIZE; - } - ret = COPY_COMPLETE; -out: - inode_unlock(inode); - iput(inode); - return ret; -} - -static int write_page_nocow(struct scrub_ctx *sctx, - u64 physical_for_dev_replace, struct page *page) -{ - struct bio *bio; - struct btrfs_device *dev; - - dev = sctx->wr_tgtdev; - if (!dev) - return -EIO; - if (!dev->bdev) { - btrfs_warn_rl(dev->fs_info, - "scrub write_page_nocow(bdev == NULL) is unexpected"); - return -EIO; - } - bio = btrfs_io_bio_alloc(1); - bio->bi_iter.bi_size = 0; - bio->bi_iter.bi_sector = physical_for_dev_replace >> 9; - bio_set_dev(bio, dev->bdev); - bio->bi_opf = REQ_OP_WRITE | REQ_SYNC; - /* bio_add_page won't fail on a freshly allocated bio */ - bio_add_page(bio, page, PAGE_SIZE, 0); - - if (btrfsic_submit_bio_wait(bio)) { - bio_put(bio); - btrfs_dev_stat_inc_and_print(dev, BTRFS_DEV_STAT_WRITE_ERRS); - return -EIO; - } - - bio_put(bio); - return 0; -} -- cgit v1.2.3 From bd3c685ed9fd3763615a51a70e19ff08a456e3e1 Mon Sep 17 00:00:00 2001 From: Nikolay Borisov Date: Mon, 18 Jun 2018 14:59:25 +0300 Subject: btrfs: Document __btrfs_inc_extent_ref Here is a doc-only patch which tires to deobfuscate the terra-incognita that arguments for delayed refs are. Signed-off-by: Nikolay Borisov Reviewed-by: Qu Wenruo Signed-off-by: David Sterba --- fs/btrfs/extent-tree.c | 34 ++++++++++++++++++++++++++++++++++ 1 file changed, 34 insertions(+) (limited to 'fs') diff --git a/fs/btrfs/extent-tree.c b/fs/btrfs/extent-tree.c index 3d9fe58c0080..2c55f3dce27b 100644 --- a/fs/btrfs/extent-tree.c +++ b/fs/btrfs/extent-tree.c @@ -2207,6 +2207,40 @@ int btrfs_inc_extent_ref(struct btrfs_trans_handle *trans, return ret; } +/* + * __btrfs_inc_extent_ref - insert backreference for a given extent + * + * @trans: Handle of transaction + * + * @node: The delayed ref node used to get the bytenr/length for + * extent whose references are incremented. + * + * @parent: If this is a shared extent (BTRFS_SHARED_DATA_REF_KEY/ + * BTRFS_SHARED_BLOCK_REF_KEY) then it holds the logical + * bytenr of the parent block. Since new extents are always + * created with indirect references, this will only be the case + * when relocating a shared extent. In that case, root_objectid + * will be BTRFS_TREE_RELOC_OBJECTID. Otheriwse, parent must + * be 0 + * + * @root_objectid: The id of the root where this modification has originated, + * this can be either one of the well-known metadata trees or + * the subvolume id which references this extent. + * + * @owner: For data extents it is the inode number of the owning file. + * For metadata extents this parameter holds the level in the + * tree of the extent. + * + * @offset: For metadata extents the offset is ignored and is currently + * always passed as 0. For data extents it is the fileoffset + * this extent belongs to. + * + * @refs_to_add Number of references to add + * + * @extent_op Pointer to a structure, holding information necessary when + * updating a tree block's flags + * + */ static int __btrfs_inc_extent_ref(struct btrfs_trans_handle *trans, struct btrfs_fs_info *fs_info, struct btrfs_delayed_ref_node *node, -- cgit v1.2.3 From 16d1c062c7de2999ea7be61d31070fa4ce3d99c4 Mon Sep 17 00:00:00 2001 From: Nikolay Borisov Date: Mon, 18 Jun 2018 14:59:26 +0300 Subject: btrfs: Fix comment in lookup_inline_extent_backref The comment wrongfully states that the owner parameter is the level of the parent block. In fact owner is the level of the current block and by adding 1 to it we can eventually get to the parent/root. Signed-off-by: Nikolay Borisov Signed-off-by: David Sterba --- fs/btrfs/extent-tree.c | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) (limited to 'fs') diff --git a/fs/btrfs/extent-tree.c b/fs/btrfs/extent-tree.c index 2c55f3dce27b..bdd5091433ab 100644 --- a/fs/btrfs/extent-tree.c +++ b/fs/btrfs/extent-tree.c @@ -1635,8 +1635,8 @@ int lookup_inline_extent_backref(struct btrfs_trans_handle *trans, extra_size = -1; /* - * Owner is our parent level, so we can just add one to get the level - * for the block we are interested in. + * Owner is our level, so we can just add one to get the level for the + * block we are interested in. */ if (skinny_metadata && owner < BTRFS_FIRST_FREE_OBJECTID) { key.type = BTRFS_METADATA_ITEM_KEY; -- cgit v1.2.3 From b5e6c3e170b77025b5f6174258c7ad71eed2d4de Mon Sep 17 00:00:00 2001 From: Josef Bacik Date: Wed, 23 May 2018 11:58:33 -0400 Subject: btrfs: always wait on ordered extents at fsync time There's a priority inversion that exists currently with btrfs fsync. In some cases we will collect outstanding ordered extents onto a list and only wait on them at the very last second. However this "very last second" falls inside of a transaction handle, so if we are in a lower priority cgroup we can end up holding the transaction open for longer than needed, so if a high priority cgroup is also trying to fsync() it'll see latency. Signed-off-by: Josef Bacik Reviewed-by: Filipe Manana Signed-off-by: David Sterba --- fs/btrfs/file.c | 56 ++++---------------------------------------------------- 1 file changed, 4 insertions(+), 52 deletions(-) (limited to 'fs') diff --git a/fs/btrfs/file.c b/fs/btrfs/file.c index 51e77d72068a..d5be80fb427c 100644 --- a/fs/btrfs/file.c +++ b/fs/btrfs/file.c @@ -2068,53 +2068,12 @@ int btrfs_sync_file(struct file *file, loff_t start, loff_t end, int datasync) atomic_inc(&root->log_batch); full_sync = test_bit(BTRFS_INODE_NEEDS_FULL_SYNC, &BTRFS_I(inode)->runtime_flags); + /* - * We might have have had more pages made dirty after calling - * start_ordered_ops and before acquiring the inode's i_mutex. + * We have to do this here to avoid the priority inversion of waiting on + * IO of a lower priority task while holding a transaciton open. */ - if (full_sync) { - /* - * For a full sync, we need to make sure any ordered operations - * start and finish before we start logging the inode, so that - * all extents are persisted and the respective file extent - * items are in the fs/subvol btree. - */ - ret = btrfs_wait_ordered_range(inode, start, len); - } else { - /* - * Start any new ordered operations before starting to log the - * inode. We will wait for them to finish in btrfs_sync_log(). - * - * Right before acquiring the inode's mutex, we might have new - * writes dirtying pages, which won't immediately start the - * respective ordered operations - that is done through the - * fill_delalloc callbacks invoked from the writepage and - * writepages address space operations. So make sure we start - * all ordered operations before starting to log our inode. Not - * doing this means that while logging the inode, writeback - * could start and invoke writepage/writepages, which would call - * the fill_delalloc callbacks (cow_file_range, - * submit_compressed_extents). These callbacks add first an - * extent map to the modified list of extents and then create - * the respective ordered operation, which means in - * tree-log.c:btrfs_log_inode() we might capture all existing - * ordered operations (with btrfs_get_logged_extents()) before - * the fill_delalloc callback adds its ordered operation, and by - * the time we visit the modified list of extent maps (with - * btrfs_log_changed_extents()), we see and process the extent - * map they created. We then use the extent map to construct a - * file extent item for logging without waiting for the - * respective ordered operation to finish - this file extent - * item points to a disk location that might not have yet been - * written to, containing random data - so after a crash a log - * replay will make our inode have file extent items that point - * to disk locations containing invalid data, as we returned - * success to userspace without waiting for the respective - * ordered operation to finish, because it wasn't captured by - * btrfs_get_logged_extents(). - */ - ret = start_ordered_ops(inode, start, end); - } + ret = btrfs_wait_ordered_range(inode, start, len); if (ret) { inode_unlock(inode); goto out; @@ -2239,13 +2198,6 @@ int btrfs_sync_file(struct file *file, loff_t start, loff_t end, int datasync) goto out; } } - if (!full_sync) { - ret = btrfs_wait_ordered_range(inode, start, len); - if (ret) { - btrfs_end_transaction(trans); - goto out; - } - } ret = btrfs_commit_transaction(trans); } else { ret = btrfs_end_transaction(trans); -- cgit v1.2.3 From e7175a692765940f3ac3f0c005b9a766a59303d7 Mon Sep 17 00:00:00 2001 From: Josef Bacik Date: Wed, 23 May 2018 11:58:34 -0400 Subject: btrfs: remove the wait ordered logic in the log_one_extent path Since we are waiting on all ordered extents at the start of the fsync() path we don't need to wait on any logged ordered extents, and we don't need to look up the checksums on the ordered extents as they will already be on disk prior to getting here. Rework this so we're only looking up and copying the on-disk checksums for the extent range we care about. Signed-off-by: Josef Bacik Reviewed-by: Filipe Manana Signed-off-by: David Sterba --- fs/btrfs/tree-log.c | 118 +++++----------------------------------------------- 1 file changed, 10 insertions(+), 108 deletions(-) (limited to 'fs') diff --git a/fs/btrfs/tree-log.c b/fs/btrfs/tree-log.c index f8220ec02036..98cbb31ec5a8 100644 --- a/fs/btrfs/tree-log.c +++ b/fs/btrfs/tree-log.c @@ -4078,127 +4078,30 @@ static int extent_cmp(void *priv, struct list_head *a, struct list_head *b) return 0; } -static int wait_ordered_extents(struct btrfs_trans_handle *trans, - struct inode *inode, - struct btrfs_root *root, - const struct extent_map *em, - const struct list_head *logged_list, - bool *ordered_io_error) +static int log_extent_csums(struct btrfs_trans_handle *trans, + struct btrfs_inode *inode, + struct btrfs_root *root, + const struct extent_map *em) { struct btrfs_fs_info *fs_info = root->fs_info; - struct btrfs_ordered_extent *ordered; struct btrfs_root *log = root->log_root; - u64 mod_start = em->mod_start; - u64 mod_len = em->mod_len; - const bool skip_csum = BTRFS_I(inode)->flags & BTRFS_INODE_NODATASUM; u64 csum_offset; u64 csum_len; LIST_HEAD(ordered_sums); int ret = 0; - *ordered_io_error = false; - - if (test_bit(EXTENT_FLAG_PREALLOC, &em->flags) || + if (inode->flags & BTRFS_INODE_NODATASUM || + test_bit(EXTENT_FLAG_PREALLOC, &em->flags) || em->block_start == EXTENT_MAP_HOLE) return 0; - /* - * Wait far any ordered extent that covers our extent map. If it - * finishes without an error, first check and see if our csums are on - * our outstanding ordered extents. - */ - list_for_each_entry(ordered, logged_list, log_list) { - struct btrfs_ordered_sum *sum; - - if (!mod_len) - break; - - if (ordered->file_offset + ordered->len <= mod_start || - mod_start + mod_len <= ordered->file_offset) - continue; - - if (!test_bit(BTRFS_ORDERED_IO_DONE, &ordered->flags) && - !test_bit(BTRFS_ORDERED_IOERR, &ordered->flags) && - !test_bit(BTRFS_ORDERED_DIRECT, &ordered->flags)) { - const u64 start = ordered->file_offset; - const u64 end = ordered->file_offset + ordered->len - 1; - - WARN_ON(ordered->inode != inode); - filemap_fdatawrite_range(inode->i_mapping, start, end); - } - - wait_event(ordered->wait, - (test_bit(BTRFS_ORDERED_IO_DONE, &ordered->flags) || - test_bit(BTRFS_ORDERED_IOERR, &ordered->flags))); - - if (test_bit(BTRFS_ORDERED_IOERR, &ordered->flags)) { - /* - * Clear the AS_EIO/AS_ENOSPC flags from the inode's - * i_mapping flags, so that the next fsync won't get - * an outdated io error too. - */ - filemap_check_errors(inode->i_mapping); - *ordered_io_error = true; - break; - } - /* - * We are going to copy all the csums on this ordered extent, so - * go ahead and adjust mod_start and mod_len in case this - * ordered extent has already been logged. - */ - if (ordered->file_offset > mod_start) { - if (ordered->file_offset + ordered->len >= - mod_start + mod_len) - mod_len = ordered->file_offset - mod_start; - /* - * If we have this case - * - * |--------- logged extent ---------| - * |----- ordered extent ----| - * - * Just don't mess with mod_start and mod_len, we'll - * just end up logging more csums than we need and it - * will be ok. - */ - } else { - if (ordered->file_offset + ordered->len < - mod_start + mod_len) { - mod_len = (mod_start + mod_len) - - (ordered->file_offset + ordered->len); - mod_start = ordered->file_offset + - ordered->len; - } else { - mod_len = 0; - } - } - - if (skip_csum) - continue; - - /* - * To keep us from looping for the above case of an ordered - * extent that falls inside of the logged extent. - */ - if (test_and_set_bit(BTRFS_ORDERED_LOGGED_CSUM, - &ordered->flags)) - continue; - - list_for_each_entry(sum, &ordered->list, list) { - ret = btrfs_csum_file_blocks(trans, log, sum); - if (ret) - break; - } - } - - if (*ordered_io_error || !mod_len || ret || skip_csum) - return ret; - + /* If we're compressed we have to save the entire range of csums. */ if (em->compress_type) { csum_offset = 0; csum_len = max(em->block_len, em->orig_block_len); } else { - csum_offset = mod_start - em->start; - csum_len = mod_len; + csum_offset = em->mod_start - em->start; + csum_len = em->mod_len; } /* block start is already adjusted for the file extent offset. */ @@ -4240,8 +4143,7 @@ static int log_one_extent(struct btrfs_trans_handle *trans, int extent_inserted = 0; bool ordered_io_err = false; - ret = wait_ordered_extents(trans, &inode->vfs_inode, root, em, - logged_list, &ordered_io_err); + ret = log_extent_csums(trans, inode, root, em); if (ret) return ret; -- cgit v1.2.3 From a2120a473a80905e0275df9b0427fa7fa1187b72 Mon Sep 17 00:00:00 2001 From: Josef Bacik Date: Wed, 23 May 2018 11:58:35 -0400 Subject: btrfs: clean up the left over logged_list usage We no longer use this list we've passed around so remove it everywhere. Also remove the extra checks for ordered/filemap errors as this is handled higher up now that we're waiting on ordered_extents before getting to the tree log code. Signed-off-by: Josef Bacik Reviewed-by: Filipe Manana Signed-off-by: David Sterba --- fs/btrfs/tree-log.c | 32 ++------------------------------ 1 file changed, 2 insertions(+), 30 deletions(-) (limited to 'fs') diff --git a/fs/btrfs/tree-log.c b/fs/btrfs/tree-log.c index 98cbb31ec5a8..dce499071c86 100644 --- a/fs/btrfs/tree-log.c +++ b/fs/btrfs/tree-log.c @@ -4129,7 +4129,6 @@ static int log_one_extent(struct btrfs_trans_handle *trans, struct btrfs_inode *inode, struct btrfs_root *root, const struct extent_map *em, struct btrfs_path *path, - const struct list_head *logged_list, struct btrfs_log_ctx *ctx) { struct btrfs_root *log = root->log_root; @@ -4141,17 +4140,11 @@ static int log_one_extent(struct btrfs_trans_handle *trans, u64 block_len; int ret; int extent_inserted = 0; - bool ordered_io_err = false; ret = log_extent_csums(trans, inode, root, em); if (ret) return ret; - if (ordered_io_err) { - ctx->io_err = -EIO; - return ctx->io_err; - } - btrfs_init_map_token(&token); ret = __btrfs_drop_extents(trans, log, &inode->vfs_inode, path, em->start, @@ -4326,7 +4319,6 @@ static int btrfs_log_changed_extents(struct btrfs_trans_handle *trans, struct btrfs_root *root, struct btrfs_inode *inode, struct btrfs_path *path, - struct list_head *logged_list, struct btrfs_log_ctx *ctx, const u64 start, const u64 end) @@ -4382,20 +4374,6 @@ static int btrfs_log_changed_extents(struct btrfs_trans_handle *trans, } list_sort(NULL, &extents, extent_cmp); - btrfs_get_logged_extents(inode, logged_list, logged_start, logged_end); - /* - * Some ordered extents started by fsync might have completed - * before we could collect them into the list logged_list, which - * means they're gone, not in our logged_list nor in the inode's - * ordered tree. We want the application/user space to know an - * error happened while attempting to persist file data so that - * it can take proper action. If such error happened, we leave - * without writing to the log tree and the fsync must report the - * file data write error and not commit the current transaction. - */ - ret = filemap_check_errors(inode->vfs_inode.i_mapping); - if (ret) - ctx->io_err = ret; process: while (!list_empty(&extents)) { em = list_entry(extents.next, struct extent_map, list); @@ -4414,8 +4392,7 @@ process: write_unlock(&tree->lock); - ret = log_one_extent(trans, inode, root, em, path, logged_list, - ctx); + ret = log_one_extent(trans, inode, root, em, path, ctx); write_lock(&tree->lock); clear_em_logging(tree, em); free_extent_map(em); @@ -4800,7 +4777,6 @@ static int btrfs_log_inode(struct btrfs_trans_handle *trans, struct btrfs_key min_key; struct btrfs_key max_key; struct btrfs_root *log = root->log_root; - LIST_HEAD(logged_list); u64 last_extent = 0; int err = 0; int ret; @@ -5137,7 +5113,7 @@ log_extents: } if (fast_search) { ret = btrfs_log_changed_extents(trans, root, inode, dst_path, - &logged_list, ctx, start, end); + ctx, start, end); if (ret) { err = ret; goto out_unlock; @@ -5188,10 +5164,6 @@ log_extents: inode->last_log_commit = inode->last_sub_trans; spin_unlock(&inode->lock); out_unlock: - if (unlikely(err)) - btrfs_put_logged_extents(&logged_list); - else - btrfs_submit_logged_extents(&logged_list, log); mutex_unlock(&inode->log_mutex); btrfs_free_path(path); -- cgit v1.2.3 From 5636cf7d6dc86f47fd66757dae088e35014da464 Mon Sep 17 00:00:00 2001 From: Josef Bacik Date: Wed, 23 May 2018 11:58:36 -0400 Subject: btrfs: remove the logged extents infrastructure This is no longer used anywhere, remove all of it. Signed-off-by: Josef Bacik Reviewed-by: Filipe Manana Signed-off-by: David Sterba --- fs/btrfs/ordered-data.c | 123 ------------------------------------------------ fs/btrfs/ordered-data.h | 20 ++------ fs/btrfs/tree-log.c | 16 ------- 3 files changed, 3 insertions(+), 156 deletions(-) (limited to 'fs') diff --git a/fs/btrfs/ordered-data.c b/fs/btrfs/ordered-data.c index 2e1a1694a33d..c35d2aed5ff8 100644 --- a/fs/btrfs/ordered-data.c +++ b/fs/btrfs/ordered-data.c @@ -421,129 +421,6 @@ out: return ret == 0; } -/* Needs to either be called under a log transaction or the log_mutex */ -void btrfs_get_logged_extents(struct btrfs_inode *inode, - struct list_head *logged_list, - const loff_t start, - const loff_t end) -{ - struct btrfs_ordered_inode_tree *tree; - struct btrfs_ordered_extent *ordered; - struct rb_node *n; - struct rb_node *prev; - - tree = &inode->ordered_tree; - spin_lock_irq(&tree->lock); - n = __tree_search(&tree->tree, end, &prev); - if (!n) - n = prev; - for (; n; n = rb_prev(n)) { - ordered = rb_entry(n, struct btrfs_ordered_extent, rb_node); - if (ordered->file_offset > end) - continue; - if (entry_end(ordered) <= start) - break; - if (test_and_set_bit(BTRFS_ORDERED_LOGGED, &ordered->flags)) - continue; - list_add(&ordered->log_list, logged_list); - refcount_inc(&ordered->refs); - } - spin_unlock_irq(&tree->lock); -} - -void btrfs_put_logged_extents(struct list_head *logged_list) -{ - struct btrfs_ordered_extent *ordered; - - while (!list_empty(logged_list)) { - ordered = list_first_entry(logged_list, - struct btrfs_ordered_extent, - log_list); - list_del_init(&ordered->log_list); - btrfs_put_ordered_extent(ordered); - } -} - -void btrfs_submit_logged_extents(struct list_head *logged_list, - struct btrfs_root *log) -{ - int index = log->log_transid % 2; - - spin_lock_irq(&log->log_extents_lock[index]); - list_splice_tail(logged_list, &log->logged_list[index]); - spin_unlock_irq(&log->log_extents_lock[index]); -} - -void btrfs_wait_logged_extents(struct btrfs_trans_handle *trans, - struct btrfs_root *log, u64 transid) -{ - struct btrfs_ordered_extent *ordered; - int index = transid % 2; - - spin_lock_irq(&log->log_extents_lock[index]); - while (!list_empty(&log->logged_list[index])) { - struct inode *inode; - ordered = list_first_entry(&log->logged_list[index], - struct btrfs_ordered_extent, - log_list); - list_del_init(&ordered->log_list); - inode = ordered->inode; - spin_unlock_irq(&log->log_extents_lock[index]); - - if (!test_bit(BTRFS_ORDERED_IO_DONE, &ordered->flags) && - !test_bit(BTRFS_ORDERED_DIRECT, &ordered->flags)) { - u64 start = ordered->file_offset; - u64 end = ordered->file_offset + ordered->len - 1; - - WARN_ON(!inode); - filemap_fdatawrite_range(inode->i_mapping, start, end); - } - wait_event(ordered->wait, test_bit(BTRFS_ORDERED_IO_DONE, - &ordered->flags)); - - /* - * In order to keep us from losing our ordered extent - * information when committing the transaction we have to make - * sure that any logged extents are completed when we go to - * commit the transaction. To do this we simply increase the - * current transactions pending_ordered counter and decrement it - * when the ordered extent completes. - */ - if (!test_bit(BTRFS_ORDERED_COMPLETE, &ordered->flags)) { - struct btrfs_ordered_inode_tree *tree; - - tree = &BTRFS_I(inode)->ordered_tree; - spin_lock_irq(&tree->lock); - if (!test_bit(BTRFS_ORDERED_COMPLETE, &ordered->flags)) { - set_bit(BTRFS_ORDERED_PENDING, &ordered->flags); - atomic_inc(&trans->transaction->pending_ordered); - } - spin_unlock_irq(&tree->lock); - } - btrfs_put_ordered_extent(ordered); - spin_lock_irq(&log->log_extents_lock[index]); - } - spin_unlock_irq(&log->log_extents_lock[index]); -} - -void btrfs_free_logged_extents(struct btrfs_root *log, u64 transid) -{ - struct btrfs_ordered_extent *ordered; - int index = transid % 2; - - spin_lock_irq(&log->log_extents_lock[index]); - while (!list_empty(&log->logged_list[index])) { - ordered = list_first_entry(&log->logged_list[index], - struct btrfs_ordered_extent, - log_list); - list_del_init(&ordered->log_list); - spin_unlock_irq(&log->log_extents_lock[index]); - btrfs_put_ordered_extent(ordered); - spin_lock_irq(&log->log_extents_lock[index]); - } - spin_unlock_irq(&log->log_extents_lock[index]); -} - /* * used to drop a reference on an ordered extent. This will free * the extent if the last reference is dropped diff --git a/fs/btrfs/ordered-data.h b/fs/btrfs/ordered-data.h index 3be443fb3001..b2d3f6a091f7 100644 --- a/fs/btrfs/ordered-data.h +++ b/fs/btrfs/ordered-data.h @@ -54,15 +54,11 @@ struct btrfs_ordered_sum { #define BTRFS_ORDERED_UPDATED_ISIZE 7 /* indicates whether this ordered extent * has done its due diligence in updating * the isize. */ -#define BTRFS_ORDERED_LOGGED_CSUM 8 /* We've logged the csums on this ordered - ordered extent */ -#define BTRFS_ORDERED_TRUNCATED 9 /* Set when we have to truncate an extent */ +#define BTRFS_ORDERED_TRUNCATED 8 /* Set when we have to truncate an extent */ -#define BTRFS_ORDERED_LOGGED 10 /* Set when we've waited on this ordered extent - * in the logging code. */ -#define BTRFS_ORDERED_PENDING 11 /* We are waiting for this ordered extent to +#define BTRFS_ORDERED_PENDING 9 /* We are waiting for this ordered extent to * complete in the current transaction. */ -#define BTRFS_ORDERED_REGULAR 12 /* Regular IO for COW */ +#define BTRFS_ORDERED_REGULAR 10 /* Regular IO for COW */ struct btrfs_ordered_extent { /* logical offset in the file */ @@ -193,16 +189,6 @@ u64 btrfs_wait_ordered_extents(struct btrfs_root *root, u64 nr, const u64 range_start, const u64 range_len); u64 btrfs_wait_ordered_roots(struct btrfs_fs_info *fs_info, u64 nr, const u64 range_start, const u64 range_len); -void btrfs_get_logged_extents(struct btrfs_inode *inode, - struct list_head *logged_list, - const loff_t start, - const loff_t end); -void btrfs_put_logged_extents(struct list_head *logged_list); -void btrfs_submit_logged_extents(struct list_head *logged_list, - struct btrfs_root *log); -void btrfs_wait_logged_extents(struct btrfs_trans_handle *trans, - struct btrfs_root *log, u64 transid); -void btrfs_free_logged_extents(struct btrfs_root *log, u64 transid); int __init ordered_data_init(void); void __cold ordered_data_exit(void); diff --git a/fs/btrfs/tree-log.c b/fs/btrfs/tree-log.c index dce499071c86..daf32dc94dc3 100644 --- a/fs/btrfs/tree-log.c +++ b/fs/btrfs/tree-log.c @@ -2933,7 +2933,6 @@ int btrfs_sync_log(struct btrfs_trans_handle *trans, /* bail out if we need to do a full commit */ if (btrfs_need_log_full_commit(fs_info, trans)) { ret = -EAGAIN; - btrfs_free_logged_extents(log, log_transid); mutex_unlock(&root->log_mutex); goto out; } @@ -2951,7 +2950,6 @@ int btrfs_sync_log(struct btrfs_trans_handle *trans, if (ret) { blk_finish_plug(&plug); btrfs_abort_transaction(trans, ret); - btrfs_free_logged_extents(log, log_transid); btrfs_set_log_full_commit(fs_info, trans); mutex_unlock(&root->log_mutex); goto out; @@ -3002,7 +3000,6 @@ int btrfs_sync_log(struct btrfs_trans_handle *trans, goto out; } btrfs_wait_tree_log_extents(log, mark); - btrfs_free_logged_extents(log, log_transid); mutex_unlock(&log_root_tree->log_mutex); ret = -EAGAIN; goto out; @@ -3020,7 +3017,6 @@ int btrfs_sync_log(struct btrfs_trans_handle *trans, if (atomic_read(&log_root_tree->log_commit[index2])) { blk_finish_plug(&plug); ret = btrfs_wait_tree_log_extents(log, mark); - btrfs_wait_logged_extents(trans, log, log_transid); wait_log_commit(log_root_tree, root_log_ctx.log_transid); mutex_unlock(&log_root_tree->log_mutex); @@ -3045,7 +3041,6 @@ int btrfs_sync_log(struct btrfs_trans_handle *trans, if (btrfs_need_log_full_commit(fs_info, trans)) { blk_finish_plug(&plug); btrfs_wait_tree_log_extents(log, mark); - btrfs_free_logged_extents(log, log_transid); mutex_unlock(&log_root_tree->log_mutex); ret = -EAGAIN; goto out_wake_log_root; @@ -3058,7 +3053,6 @@ int btrfs_sync_log(struct btrfs_trans_handle *trans, if (ret) { btrfs_set_log_full_commit(fs_info, trans); btrfs_abort_transaction(trans, ret); - btrfs_free_logged_extents(log, log_transid); mutex_unlock(&log_root_tree->log_mutex); goto out_wake_log_root; } @@ -3068,11 +3062,9 @@ int btrfs_sync_log(struct btrfs_trans_handle *trans, EXTENT_NEW | EXTENT_DIRTY); if (ret) { btrfs_set_log_full_commit(fs_info, trans); - btrfs_free_logged_extents(log, log_transid); mutex_unlock(&log_root_tree->log_mutex); goto out_wake_log_root; } - btrfs_wait_logged_extents(trans, log, log_transid); btrfs_set_super_log_root(fs_info->super_for_commit, log_root_tree->node->start); @@ -3159,14 +3151,6 @@ static void free_log_tree(struct btrfs_trans_handle *trans, EXTENT_DIRTY | EXTENT_NEW | EXTENT_NEED_WAIT); } - /* - * We may have short-circuited the log tree with the full commit logic - * and left ordered extents on our list, so clear these out to keep us - * from leaking inodes and memory. - */ - btrfs_free_logged_extents(log, 0); - btrfs_free_logged_extents(log, 1); - free_extent_buffer(log->node); kfree(log); } -- cgit v1.2.3 From ca5788aba3e8153da38cf99ca3ce2294f032fb51 Mon Sep 17 00:00:00 2001 From: David Sterba Date: Thu, 19 Jul 2018 15:27:46 +0200 Subject: btrfs: remove remaing full_sync logic from btrfs_sync_file The logic to check if the inode is already in the log can now be simplified since we always wait for the ordered extents to complete before deciding whether the inode needs to be logged. The big comment about it can go away too. CC: Filipe Manana Suggested-by: Filipe Manana [ code and changelog copied from mail discussion ] Signed-off-by: David Sterba --- fs/btrfs/file.c | 37 +------------------------------------ fs/btrfs/ordered-data.c | 14 -------------- fs/btrfs/ordered-data.h | 3 --- 3 files changed, 1 insertion(+), 53 deletions(-) (limited to 'fs') diff --git a/fs/btrfs/file.c b/fs/btrfs/file.c index d5be80fb427c..975c590c50d8 100644 --- a/fs/btrfs/file.c +++ b/fs/btrfs/file.c @@ -2042,7 +2042,6 @@ int btrfs_sync_file(struct file *file, loff_t start, loff_t end, int datasync) struct btrfs_trans_handle *trans; struct btrfs_log_ctx ctx; int ret = 0, err; - bool full_sync = false; u64 len; /* @@ -2066,8 +2065,6 @@ int btrfs_sync_file(struct file *file, loff_t start, loff_t end, int datasync) inode_lock(inode); atomic_inc(&root->log_batch); - full_sync = test_bit(BTRFS_INODE_NEEDS_FULL_SYNC, - &BTRFS_I(inode)->runtime_flags); /* * We have to do this here to avoid the priority inversion of waiting on @@ -2080,41 +2077,9 @@ int btrfs_sync_file(struct file *file, loff_t start, loff_t end, int datasync) } atomic_inc(&root->log_batch); - /* - * If the last transaction that changed this file was before the current - * transaction and we have the full sync flag set in our inode, we can - * bail out now without any syncing. - * - * Note that we can't bail out if the full sync flag isn't set. This is - * because when the full sync flag is set we start all ordered extents - * and wait for them to fully complete - when they complete they update - * the inode's last_trans field through: - * - * btrfs_finish_ordered_io() -> - * btrfs_update_inode_fallback() -> - * btrfs_update_inode() -> - * btrfs_set_inode_last_trans() - * - * So we are sure that last_trans is up to date and can do this check to - * bail out safely. For the fast path, when the full sync flag is not - * set in our inode, we can not do it because we start only our ordered - * extents and don't wait for them to complete (that is when - * btrfs_finish_ordered_io runs), so here at this point their last_trans - * value might be less than or equals to fs_info->last_trans_committed, - * and setting a speculative last_trans for an inode when a buffered - * write is made (such as fs_info->generation + 1 for example) would not - * be reliable since after setting the value and before fsync is called - * any number of transactions can start and commit (transaction kthread - * commits the current transaction periodically), and a transaction - * commit does not start nor waits for ordered extents to complete. - */ smp_mb(); if (btrfs_inode_in_log(BTRFS_I(inode), fs_info->generation) || - (full_sync && BTRFS_I(inode)->last_trans <= - fs_info->last_trans_committed) || - (!btrfs_have_ordered_extents_in_range(inode, start, len) && - BTRFS_I(inode)->last_trans - <= fs_info->last_trans_committed)) { + BTRFS_I(inode)->last_trans <= fs_info->last_trans_committed) { /* * We've had everything committed since the last time we were * modified so clear this flag in case it was set for whatever diff --git a/fs/btrfs/ordered-data.c b/fs/btrfs/ordered-data.c index c35d2aed5ff8..e173b252d795 100644 --- a/fs/btrfs/ordered-data.c +++ b/fs/btrfs/ordered-data.c @@ -790,20 +790,6 @@ out: return entry; } -bool btrfs_have_ordered_extents_in_range(struct inode *inode, - u64 file_offset, - u64 len) -{ - struct btrfs_ordered_extent *oe; - - oe = btrfs_lookup_ordered_range(BTRFS_I(inode), file_offset, len); - if (oe) { - btrfs_put_ordered_extent(oe); - return true; - } - return false; -} - /* * lookup and return any extent before 'file_offset'. NULL is returned * if none is found diff --git a/fs/btrfs/ordered-data.h b/fs/btrfs/ordered-data.h index b2d3f6a091f7..02d813aaa261 100644 --- a/fs/btrfs/ordered-data.h +++ b/fs/btrfs/ordered-data.h @@ -178,9 +178,6 @@ struct btrfs_ordered_extent *btrfs_lookup_ordered_range( struct btrfs_inode *inode, u64 file_offset, u64 len); -bool btrfs_have_ordered_extents_in_range(struct inode *inode, - u64 file_offset, - u64 len); int btrfs_ordered_update_i_size(struct inode *inode, u64 offset, struct btrfs_ordered_extent *ordered); int btrfs_find_ordered_sum(struct inode *inode, u64 offset, u64 disk_bytenr, -- cgit v1.2.3 From a9ecb653b0ac9ed95671aa494015bbb705bf3eae Mon Sep 17 00:00:00 2001 From: Nikolay Borisov Date: Wed, 20 Jun 2018 17:26:42 +0300 Subject: btrfs: Streamline log_extent_csums a bit Currently this function takes the root as an argument only to get the log_root from it. Simplify this by directly passing the log root from the caller. Also eliminate the fs_info local variable, since it's used only once, so directly reference it from the transaction handle. Signed-off-by: Nikolay Borisov Reviewed-by: David Sterba Signed-off-by: David Sterba --- fs/btrfs/tree-log.c | 10 ++++------ 1 file changed, 4 insertions(+), 6 deletions(-) (limited to 'fs') diff --git a/fs/btrfs/tree-log.c b/fs/btrfs/tree-log.c index daf32dc94dc3..7f6aaeb4bd22 100644 --- a/fs/btrfs/tree-log.c +++ b/fs/btrfs/tree-log.c @@ -4064,11 +4064,9 @@ static int extent_cmp(void *priv, struct list_head *a, struct list_head *b) static int log_extent_csums(struct btrfs_trans_handle *trans, struct btrfs_inode *inode, - struct btrfs_root *root, + struct btrfs_root *log_root, const struct extent_map *em) { - struct btrfs_fs_info *fs_info = root->fs_info; - struct btrfs_root *log = root->log_root; u64 csum_offset; u64 csum_len; LIST_HEAD(ordered_sums); @@ -4089,7 +4087,7 @@ static int log_extent_csums(struct btrfs_trans_handle *trans, } /* block start is already adjusted for the file extent offset. */ - ret = btrfs_lookup_csums_range(fs_info->csum_root, + ret = btrfs_lookup_csums_range(trans->fs_info->csum_root, em->block_start + csum_offset, em->block_start + csum_offset + csum_len - 1, &ordered_sums, 0); @@ -4101,7 +4099,7 @@ static int log_extent_csums(struct btrfs_trans_handle *trans, struct btrfs_ordered_sum, list); if (!ret) - ret = btrfs_csum_file_blocks(trans, log, sums); + ret = btrfs_csum_file_blocks(trans, log_root, sums); list_del(&sums->list); kfree(sums); } @@ -4125,7 +4123,7 @@ static int log_one_extent(struct btrfs_trans_handle *trans, int ret; int extent_inserted = 0; - ret = log_extent_csums(trans, inode, root, em); + ret = log_extent_csums(trans, inode, log, em); if (ret) return ret; -- cgit v1.2.3 From bece2e8239331d382f98b381f90e425a11157653 Mon Sep 17 00:00:00 2001 From: Bart Van Assche Date: Wed, 20 Jun 2018 10:03:31 -0700 Subject: btrfs: Fix misleading indentation reported by smatch This patch avoids that building the BTRFS source code with smatch triggers complaints about inconsistent indenting. Signed-off-by: Bart Van Assche Signed-off-by: David Sterba --- fs/btrfs/extent-tree.c | 4 ++-- fs/btrfs/ioctl.c | 4 ++-- fs/btrfs/reada.c | 2 +- 3 files changed, 5 insertions(+), 5 deletions(-) (limited to 'fs') diff --git a/fs/btrfs/extent-tree.c b/fs/btrfs/extent-tree.c index bdd5091433ab..e0e0f3dad206 100644 --- a/fs/btrfs/extent-tree.c +++ b/fs/btrfs/extent-tree.c @@ -6313,7 +6313,7 @@ static int update_block_group(struct btrfs_trans_handle *trans, if (list_empty(&cache->dirty_list)) { list_add_tail(&cache->dirty_list, &trans->transaction->dirty_bgs); - trans->transaction->num_dirty_bgs++; + trans->transaction->num_dirty_bgs++; btrfs_get_block_group(cache); } spin_unlock(&trans->transaction->dirty_bgs_lock); @@ -7568,7 +7568,7 @@ search: * for the proper type. */ if (!block_group_bits(block_group, flags)) { - u64 extra = BTRFS_BLOCK_GROUP_DUP | + u64 extra = BTRFS_BLOCK_GROUP_DUP | BTRFS_BLOCK_GROUP_RAID1 | BTRFS_BLOCK_GROUP_RAID5 | BTRFS_BLOCK_GROUP_RAID6 | diff --git a/fs/btrfs/ioctl.c b/fs/btrfs/ioctl.c index b077544b5232..0c4b9f364e84 100644 --- a/fs/btrfs/ioctl.c +++ b/fs/btrfs/ioctl.c @@ -2507,8 +2507,8 @@ out: static noinline int btrfs_ioctl_ino_lookup(struct file *file, void __user *argp) { - struct btrfs_ioctl_ino_lookup_args *args; - struct inode *inode; + struct btrfs_ioctl_ino_lookup_args *args; + struct inode *inode; int ret = 0; args = memdup_user(argp, sizeof(*args)); diff --git a/fs/btrfs/reada.c b/fs/btrfs/reada.c index 40f1bcef394d..4be425f70c2d 100644 --- a/fs/btrfs/reada.c +++ b/fs/btrfs/reada.c @@ -355,7 +355,7 @@ static struct reada_extent *reada_find_extent(struct btrfs_fs_info *fs_info, dev = bbio->stripes[nzones].dev; /* cannot read ahead on missing device. */ - if (!dev->bdev) + if (!dev->bdev) continue; zone = reada_find_zone(dev, logical, bbio); -- cgit v1.2.3 From acd43e3cdffcb2e361e8b481c72e057d34fcd780 Mon Sep 17 00:00:00 2001 From: Bart Van Assche Date: Wed, 20 Jun 2018 10:03:32 -0700 Subject: btrfs: Annotate fall-through when parsing mount option This patch avoids that the compiler complains that a fall-through annotation is missing when building with W=1. Signed-off-by: Bart Van Assche Signed-off-by: David Sterba --- fs/btrfs/super.c | 1 + 1 file changed, 1 insertion(+) (limited to 'fs') diff --git a/fs/btrfs/super.c b/fs/btrfs/super.c index 81107ad49f3a..3e298f26a383 100644 --- a/fs/btrfs/super.c +++ b/fs/btrfs/super.c @@ -760,6 +760,7 @@ int btrfs_parse_options(struct btrfs_fs_info *info, char *options, case Opt_recovery: btrfs_warn(info, "'recovery' is deprecated, use 'usebackuproot' instead"); + /* fall through */ case Opt_usebackuproot: btrfs_info(info, "trying to use backup root at mount time"); -- cgit v1.2.3 From edf57cbf2b030781885e339f32e35a470d2f8eba Mon Sep 17 00:00:00 2001 From: Bart Van Assche Date: Wed, 20 Jun 2018 10:03:33 -0700 Subject: btrfs: Fix a C compliance issue The C programming language does not allow to use preprocessor statements inside macro arguments (pr_info() is defined as a macro). Hence rework the pr_info() statement in btrfs_print_mod_info() such that it becomes compliant. This patch allows tools like sparse to analyze the BTRFS source code. Fixes: 62e855771dac ("btrfs: convert printk(KERN_* to use pr_* calls") Signed-off-by: Bart Van Assche Reviewed-by: David Sterba Signed-off-by: David Sterba --- fs/btrfs/super.c | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) (limited to 'fs') diff --git a/fs/btrfs/super.c b/fs/btrfs/super.c index 3e298f26a383..3c5f221b5303 100644 --- a/fs/btrfs/super.c +++ b/fs/btrfs/super.c @@ -2370,7 +2370,7 @@ static __cold void btrfs_interface_exit(void) static void __init btrfs_print_mod_info(void) { - pr_info("Btrfs loaded, crc32c=%s" + static const char options[] = "" #ifdef CONFIG_BTRFS_DEBUG ", debug=on" #endif @@ -2383,8 +2383,8 @@ static void __init btrfs_print_mod_info(void) #ifdef CONFIG_BTRFS_FS_REF_VERIFY ", ref-verify=on" #endif - "\n", - crc32c_impl()); + ; + pr_info("Btrfs loaded, crc32c=%s%s\n", crc32c_impl(), options); } static int __init init_btrfs_fs(void) -- cgit v1.2.3 From 10728404c6f64a570f5be95cd5b237c69d94d818 Mon Sep 17 00:00:00 2001 From: Nikolay Borisov Date: Wed, 20 Jun 2018 15:48:43 +0300 Subject: btrfs: Remove fs_info from insert_tree_block_ref This function is always called with a valid transaction so there is no need to duplicate the fs_info, we can reference it directly from the trans handle. No functional changes. Signed-off-by: Nikolay Borisov Reviewed-by: Qu Wenruo Signed-off-by: David Sterba --- fs/btrfs/extent-tree.c | 7 +++---- 1 file changed, 3 insertions(+), 4 deletions(-) (limited to 'fs') diff --git a/fs/btrfs/extent-tree.c b/fs/btrfs/extent-tree.c index e0e0f3dad206..082e9f1c1f1a 100644 --- a/fs/btrfs/extent-tree.c +++ b/fs/btrfs/extent-tree.c @@ -1523,7 +1523,6 @@ static noinline int lookup_tree_block_ref(struct btrfs_trans_handle *trans, } static noinline int insert_tree_block_ref(struct btrfs_trans_handle *trans, - struct btrfs_fs_info *fs_info, struct btrfs_path *path, u64 bytenr, u64 parent, u64 root_objectid) @@ -1540,7 +1539,7 @@ static noinline int insert_tree_block_ref(struct btrfs_trans_handle *trans, key.offset = root_objectid; } - ret = btrfs_insert_empty_item(trans, fs_info->extent_root, + ret = btrfs_insert_empty_item(trans, trans->fs_info->extent_root, path, &key, 0); btrfs_release_path(path); return ret; @@ -2000,8 +1999,8 @@ static int insert_extent_backref(struct btrfs_trans_handle *trans, int ret; if (owner < BTRFS_FIRST_FREE_OBJECTID) { BUG_ON(refs_to_add != 1); - ret = insert_tree_block_ref(trans, fs_info, path, bytenr, - parent, root_objectid); + ret = insert_tree_block_ref(trans, path, bytenr, parent, + root_objectid); } else { ret = insert_extent_data_ref(trans, fs_info, path, bytenr, parent, root_objectid, -- cgit v1.2.3 From 62b895af4022017c11855087801b0575a442ccc6 Mon Sep 17 00:00:00 2001 From: Nikolay Borisov Date: Wed, 20 Jun 2018 15:48:44 +0300 Subject: btrfs: Remove fs_info from insert_extent_data_ref This function is always called with a valid transaction handle from where fs_info can be referenced. So remove the redundant argument. No functional changes. Signed-off-by: Nikolay Borisov Reviewed-by: Qu Wenruo Signed-off-by: David Sterba --- fs/btrfs/extent-tree.c | 9 ++++----- 1 file changed, 4 insertions(+), 5 deletions(-) (limited to 'fs') diff --git a/fs/btrfs/extent-tree.c b/fs/btrfs/extent-tree.c index 082e9f1c1f1a..bb89522c0de6 100644 --- a/fs/btrfs/extent-tree.c +++ b/fs/btrfs/extent-tree.c @@ -1304,13 +1304,12 @@ fail: } static noinline int insert_extent_data_ref(struct btrfs_trans_handle *trans, - struct btrfs_fs_info *fs_info, struct btrfs_path *path, u64 bytenr, u64 parent, u64 root_objectid, u64 owner, u64 offset, int refs_to_add) { - struct btrfs_root *root = fs_info->extent_root; + struct btrfs_root *root = trans->fs_info->extent_root; struct btrfs_key key; struct extent_buffer *leaf; u32 size; @@ -2002,9 +2001,9 @@ static int insert_extent_backref(struct btrfs_trans_handle *trans, ret = insert_tree_block_ref(trans, path, bytenr, parent, root_objectid); } else { - ret = insert_extent_data_ref(trans, fs_info, path, bytenr, - parent, root_objectid, - owner, offset, refs_to_add); + ret = insert_extent_data_ref(trans, path, bytenr, parent, + root_objectid, owner, offset, + refs_to_add); } return ret; } -- cgit v1.2.3 From 375934105c97476f88eefe5f836808dd0cfc3eeb Mon Sep 17 00:00:00 2001 From: Nikolay Borisov Date: Wed, 20 Jun 2018 15:48:45 +0300 Subject: btrfs: Remove fs_info argument from insert_extent_backref This function is always called with a valid transaction handle from where fs_info can be referenced. No functional changes. Signed-off-by: Nikolay Borisov Reviewed-by: Qu Wenruo Signed-off-by: David Sterba --- fs/btrfs/extent-tree.c | 5 ++--- 1 file changed, 2 insertions(+), 3 deletions(-) (limited to 'fs') diff --git a/fs/btrfs/extent-tree.c b/fs/btrfs/extent-tree.c index bb89522c0de6..9d08bd65ed44 100644 --- a/fs/btrfs/extent-tree.c +++ b/fs/btrfs/extent-tree.c @@ -1990,7 +1990,6 @@ int insert_inline_extent_backref(struct btrfs_trans_handle *trans, } static int insert_extent_backref(struct btrfs_trans_handle *trans, - struct btrfs_fs_info *fs_info, struct btrfs_path *path, u64 bytenr, u64 parent, u64 root_objectid, u64 owner, u64 offset, int refs_to_add) @@ -2288,8 +2287,8 @@ static int __btrfs_inc_extent_ref(struct btrfs_trans_handle *trans, path->reada = READA_FORWARD; path->leave_spinning = 1; /* now insert the actual backref */ - ret = insert_extent_backref(trans, fs_info, path, bytenr, parent, - root_objectid, owner, offset, refs_to_add); + ret = insert_extent_backref(trans, path, bytenr, parent, root_objectid, + owner, offset, refs_to_add); if (ret) btrfs_abort_transaction(trans, ret); out: -- cgit v1.2.3 From e9f6290d593a8b2f6a3cf90e4ffd446ca25faea9 Mon Sep 17 00:00:00 2001 From: Nikolay Borisov Date: Wed, 20 Jun 2018 15:48:46 +0300 Subject: btrfs: Remove fs_info from remove_extent_data_ref This function is always called with a valid transaction from where the fs_info can be referenced. No functional change. Signed-off-by: Nikolay Borisov Reviewed-by: Qu Wenruo Signed-off-by: David Sterba --- fs/btrfs/extent-tree.c | 5 ++--- 1 file changed, 2 insertions(+), 3 deletions(-) (limited to 'fs') diff --git a/fs/btrfs/extent-tree.c b/fs/btrfs/extent-tree.c index 9d08bd65ed44..64346986f6f0 100644 --- a/fs/btrfs/extent-tree.c +++ b/fs/btrfs/extent-tree.c @@ -1383,7 +1383,6 @@ fail: } static noinline int remove_extent_data_ref(struct btrfs_trans_handle *trans, - struct btrfs_fs_info *fs_info, struct btrfs_path *path, int refs_to_drop, int *last_ref) { @@ -1420,7 +1419,7 @@ static noinline int remove_extent_data_ref(struct btrfs_trans_handle *trans, num_refs -= refs_to_drop; if (num_refs == 0) { - ret = btrfs_del_item(trans, fs_info->extent_root, path); + ret = btrfs_del_item(trans, trans->fs_info->extent_root, path); *last_ref = 1; } else { if (key.type == BTRFS_EXTENT_DATA_REF_KEY) @@ -2020,7 +2019,7 @@ static int remove_extent_backref(struct btrfs_trans_handle *trans, update_inline_extent_backref(fs_info, path, iref, -refs_to_drop, NULL, last_ref); } else if (is_data) { - ret = remove_extent_data_ref(trans, fs_info, path, refs_to_drop, + ret = remove_extent_data_ref(trans, path, refs_to_drop, last_ref); } else { *last_ref = 1; -- cgit v1.2.3 From b167fa9152015c91fef9489d059e9dd80d1032fd Mon Sep 17 00:00:00 2001 From: Nikolay Borisov Date: Wed, 20 Jun 2018 15:48:47 +0300 Subject: btrfs: Remove fs_info from fixup_low_keys This argument is unused. No functional changes. Signed-off-by: Nikolay Borisov Reviewed-by: Qu Wenruo Signed-off-by: David Sterba --- fs/btrfs/ctree.c | 18 ++++++++---------- 1 file changed, 8 insertions(+), 10 deletions(-) (limited to 'fs') diff --git a/fs/btrfs/ctree.c b/fs/btrfs/ctree.c index 4bc326df472e..18fd80e2f278 100644 --- a/fs/btrfs/ctree.c +++ b/fs/btrfs/ctree.c @@ -3128,8 +3128,7 @@ again: * higher levels * */ -static void fixup_low_keys(struct btrfs_fs_info *fs_info, - struct btrfs_path *path, +static void fixup_low_keys(struct btrfs_path *path, struct btrfs_disk_key *key, int level) { int i; @@ -3181,7 +3180,7 @@ void btrfs_set_item_key_safe(struct btrfs_fs_info *fs_info, btrfs_set_item_key(eb, &disk_key, slot); btrfs_mark_buffer_dirty(eb); if (slot == 0) - fixup_low_keys(fs_info, path, &disk_key, 1); + fixup_low_keys(path, &disk_key, 1); } /* @@ -3945,7 +3944,7 @@ static noinline int __push_leaf_left(struct btrfs_fs_info *fs_info, clean_tree_block(fs_info, right); btrfs_item_key(right, &disk_key, 0); - fixup_low_keys(fs_info, path, &disk_key, 1); + fixup_low_keys(path, &disk_key, 1); /* then fixup the leaf pointer in the path */ if (path->slots[0] < push_items) { @@ -4320,7 +4319,7 @@ again: path->nodes[0] = right; path->slots[0] = 0; if (path->slots[1] == 0) - fixup_low_keys(fs_info, path, &disk_key, 1); + fixup_low_keys(path, &disk_key, 1); } /* * We create a new leaf 'right' for the required ins_len and @@ -4642,7 +4641,7 @@ void btrfs_truncate_item(struct btrfs_fs_info *fs_info, btrfs_set_disk_key_offset(&disk_key, offset + size_diff); btrfs_set_item_key(leaf, &disk_key, slot); if (slot == 0) - fixup_low_keys(fs_info, path, &disk_key, 1); + fixup_low_keys(path, &disk_key, 1); } item = btrfs_item_nr(slot); @@ -4744,7 +4743,7 @@ void setup_items_for_insert(struct btrfs_root *root, struct btrfs_path *path, if (path->slots[0] == 0) { btrfs_cpu_key_to_disk(&disk_key, cpu_key); - fixup_low_keys(fs_info, path, &disk_key, 1); + fixup_low_keys(path, &disk_key, 1); } btrfs_unlock_up_safe(path, 1); @@ -4886,7 +4885,6 @@ int btrfs_insert_item(struct btrfs_trans_handle *trans, struct btrfs_root *root, static void del_ptr(struct btrfs_root *root, struct btrfs_path *path, int level, int slot) { - struct btrfs_fs_info *fs_info = root->fs_info; struct extent_buffer *parent = path->nodes[level]; u32 nritems; int ret; @@ -4919,7 +4917,7 @@ static void del_ptr(struct btrfs_root *root, struct btrfs_path *path, struct btrfs_disk_key disk_key; btrfs_node_key(parent, &disk_key, 0); - fixup_low_keys(fs_info, path, &disk_key, level + 1); + fixup_low_keys(path, &disk_key, level + 1); } btrfs_mark_buffer_dirty(parent); } @@ -5022,7 +5020,7 @@ int btrfs_del_items(struct btrfs_trans_handle *trans, struct btrfs_root *root, struct btrfs_disk_key disk_key; btrfs_item_key(leaf, &disk_key, 0); - fixup_low_keys(fs_info, path, &disk_key, 1); + fixup_low_keys(path, &disk_key, 1); } /* delete the leaf if it is mostly empty */ -- cgit v1.2.3 From 867cc1fbebea7029ee5f95ea7e54f927ef7972b6 Mon Sep 17 00:00:00 2001 From: Nikolay Borisov Date: Wed, 20 Jun 2018 15:48:48 +0300 Subject: btrfs: Remove fs_info from lookup_inline_extent_backref This function is always called with a valid transaction handle from where the fs_info can be referenced. No functional changes. Signed-off-by: Nikolay Borisov Reviewed-by: Qu Wenruo Signed-off-by: David Sterba --- fs/btrfs/extent-tree.c | 14 +++++++------- 1 file changed, 7 insertions(+), 7 deletions(-) (limited to 'fs') diff --git a/fs/btrfs/extent-tree.c b/fs/btrfs/extent-tree.c index 64346986f6f0..99e6a70b8fe5 100644 --- a/fs/btrfs/extent-tree.c +++ b/fs/btrfs/extent-tree.c @@ -1596,13 +1596,13 @@ static int find_next_key(struct btrfs_path *path, int level, */ static noinline_for_stack int lookup_inline_extent_backref(struct btrfs_trans_handle *trans, - struct btrfs_fs_info *fs_info, struct btrfs_path *path, struct btrfs_extent_inline_ref **ref_ret, u64 bytenr, u64 num_bytes, u64 parent, u64 root_objectid, u64 owner, u64 offset, int insert) { + struct btrfs_fs_info *fs_info = trans->fs_info; struct btrfs_root *root = fs_info->extent_root; struct btrfs_key key; struct extent_buffer *leaf; @@ -1868,9 +1868,9 @@ static int lookup_extent_backref(struct btrfs_trans_handle *trans, { int ret; - ret = lookup_inline_extent_backref(trans, fs_info, path, ref_ret, - bytenr, num_bytes, parent, - root_objectid, owner, offset, 0); + ret = lookup_inline_extent_backref(trans, path, ref_ret, bytenr, + num_bytes, parent, root_objectid, + owner, offset, 0); if (ret != -ENOENT) return ret; @@ -1972,9 +1972,9 @@ int insert_inline_extent_backref(struct btrfs_trans_handle *trans, struct btrfs_extent_inline_ref *iref; int ret; - ret = lookup_inline_extent_backref(trans, fs_info, path, &iref, - bytenr, num_bytes, parent, - root_objectid, owner, offset, 1); + ret = lookup_inline_extent_backref(trans, path, &iref, bytenr, + num_bytes, parent, root_objectid, + owner, offset, 1); if (ret == 0) { BUG_ON(owner < BTRFS_FIRST_FREE_OBJECTID); update_inline_extent_backref(fs_info, path, iref, -- cgit v1.2.3 From 61a18f1c66636c3226598719935eca06e81976ca Mon Sep 17 00:00:00 2001 From: Nikolay Borisov Date: Wed, 20 Jun 2018 15:48:49 +0300 Subject: btrfs: Remove fs_info argument from update_inline_extent_backref This function always uses the leaf's extent_buffer which already contains a reference to the fs_info. No functional changes. Signed-off-by: Nikolay Borisov Reviewed-by: Qu Wenruo Signed-off-by: David Sterba --- fs/btrfs/extent-tree.c | 15 +++++++-------- 1 file changed, 7 insertions(+), 8 deletions(-) (limited to 'fs') diff --git a/fs/btrfs/extent-tree.c b/fs/btrfs/extent-tree.c index 99e6a70b8fe5..102911286497 100644 --- a/fs/btrfs/extent-tree.c +++ b/fs/btrfs/extent-tree.c @@ -1892,14 +1892,14 @@ static int lookup_extent_backref(struct btrfs_trans_handle *trans, * helper to update/remove inline back ref */ static noinline_for_stack -void update_inline_extent_backref(struct btrfs_fs_info *fs_info, - struct btrfs_path *path, +void update_inline_extent_backref(struct btrfs_path *path, struct btrfs_extent_inline_ref *iref, int refs_to_mod, struct btrfs_delayed_extent_op *extent_op, int *last_ref) { - struct extent_buffer *leaf; + struct extent_buffer *leaf = path->nodes[0]; + struct btrfs_fs_info *fs_info = leaf->fs_info; struct btrfs_extent_item *ei; struct btrfs_extent_data_ref *dref = NULL; struct btrfs_shared_data_ref *sref = NULL; @@ -1910,7 +1910,6 @@ void update_inline_extent_backref(struct btrfs_fs_info *fs_info, int type; u64 refs; - leaf = path->nodes[0]; ei = btrfs_item_ptr(leaf, path->slots[0], struct btrfs_extent_item); refs = btrfs_extent_refs(leaf, ei); WARN_ON(refs_to_mod < 0 && refs + refs_to_mod <= 0); @@ -1977,8 +1976,8 @@ int insert_inline_extent_backref(struct btrfs_trans_handle *trans, owner, offset, 1); if (ret == 0) { BUG_ON(owner < BTRFS_FIRST_FREE_OBJECTID); - update_inline_extent_backref(fs_info, path, iref, - refs_to_add, extent_op, NULL); + update_inline_extent_backref(path, iref, refs_to_add, + extent_op, NULL); } else if (ret == -ENOENT) { setup_inline_extent_backref(fs_info, path, iref, parent, root_objectid, owner, offset, @@ -2016,8 +2015,8 @@ static int remove_extent_backref(struct btrfs_trans_handle *trans, BUG_ON(!is_data && refs_to_drop != 1); if (iref) { - update_inline_extent_backref(fs_info, path, iref, - -refs_to_drop, NULL, last_ref); + update_inline_extent_backref(path, iref, -refs_to_drop, NULL, + last_ref); } else if (is_data) { ret = remove_extent_data_ref(trans, path, refs_to_drop, last_ref); -- cgit v1.2.3 From b8582eeabb727f24ad0f128141558e4eb0928aec Mon Sep 17 00:00:00 2001 From: Nikolay Borisov Date: Wed, 20 Jun 2018 15:48:50 +0300 Subject: btrfs: Remove fs_info argument from lookup_tree_block_ref This function is always called with a valid transaction handle from where the fs_info can be referenced. No functional changes. Signed-off-by: Nikolay Borisov Reviewed-by: Qu Wenruo Signed-off-by: David Sterba --- fs/btrfs/extent-tree.c | 7 +++---- 1 file changed, 3 insertions(+), 4 deletions(-) (limited to 'fs') diff --git a/fs/btrfs/extent-tree.c b/fs/btrfs/extent-tree.c index 102911286497..85e1b54bc2ea 100644 --- a/fs/btrfs/extent-tree.c +++ b/fs/btrfs/extent-tree.c @@ -1487,12 +1487,11 @@ static noinline u32 extent_data_ref_count(struct btrfs_path *path, } static noinline int lookup_tree_block_ref(struct btrfs_trans_handle *trans, - struct btrfs_fs_info *fs_info, struct btrfs_path *path, u64 bytenr, u64 parent, u64 root_objectid) { - struct btrfs_root *root = fs_info->extent_root; + struct btrfs_root *root = trans->fs_info->extent_root; struct btrfs_key key; int ret; @@ -1878,8 +1877,8 @@ static int lookup_extent_backref(struct btrfs_trans_handle *trans, *ref_ret = NULL; if (owner < BTRFS_FIRST_FREE_OBJECTID) { - ret = lookup_tree_block_ref(trans, fs_info, path, bytenr, - parent, root_objectid); + ret = lookup_tree_block_ref(trans, path, bytenr, parent, + root_objectid); } else { ret = lookup_extent_data_ref(trans, fs_info, path, bytenr, parent, root_objectid, owner, -- cgit v1.2.3 From bd1d53ef358d584a0aa9dbd304c807fcc5e3dd5f Mon Sep 17 00:00:00 2001 From: Nikolay Borisov Date: Wed, 20 Jun 2018 15:48:51 +0300 Subject: btrfs: Remove fs_info argument from lookup_extent_data_ref This function is always called with a valid transaction handle from where fs_info can be referenced. No functional changes. Signed-off-by: Nikolay Borisov Reviewed-by: Qu Wenruo Signed-off-by: David Sterba --- fs/btrfs/extent-tree.c | 8 +++----- 1 file changed, 3 insertions(+), 5 deletions(-) (limited to 'fs') diff --git a/fs/btrfs/extent-tree.c b/fs/btrfs/extent-tree.c index 85e1b54bc2ea..2fc879a0a2b7 100644 --- a/fs/btrfs/extent-tree.c +++ b/fs/btrfs/extent-tree.c @@ -1216,13 +1216,12 @@ static int match_extent_data_ref(struct extent_buffer *leaf, } static noinline int lookup_extent_data_ref(struct btrfs_trans_handle *trans, - struct btrfs_fs_info *fs_info, struct btrfs_path *path, u64 bytenr, u64 parent, u64 root_objectid, u64 owner, u64 offset) { - struct btrfs_root *root = fs_info->extent_root; + struct btrfs_root *root = trans->fs_info->extent_root; struct btrfs_key key; struct btrfs_extent_data_ref *ref; struct extent_buffer *leaf; @@ -1880,9 +1879,8 @@ static int lookup_extent_backref(struct btrfs_trans_handle *trans, ret = lookup_tree_block_ref(trans, path, bytenr, parent, root_objectid); } else { - ret = lookup_extent_data_ref(trans, fs_info, path, bytenr, - parent, root_objectid, owner, - offset); + ret = lookup_extent_data_ref(trans, path, bytenr, parent, + root_objectid, owner, offset); } return ret; } -- cgit v1.2.3 From fbe4801b26c3ca4192e679f04c0cf0dda32a6cda Mon Sep 17 00:00:00 2001 From: Nikolay Borisov Date: Wed, 20 Jun 2018 15:48:52 +0300 Subject: btrfs: Remove fs_info from lookup_extent_backref This argument is unused. No functional changes. Signed-off-by: Nikolay Borisov Reviewed-by: Qu Wenruo Signed-off-by: David Sterba --- fs/btrfs/extent-tree.c | 6 ++---- 1 file changed, 2 insertions(+), 4 deletions(-) (limited to 'fs') diff --git a/fs/btrfs/extent-tree.c b/fs/btrfs/extent-tree.c index 2fc879a0a2b7..19239ad3c6d1 100644 --- a/fs/btrfs/extent-tree.c +++ b/fs/btrfs/extent-tree.c @@ -1858,7 +1858,6 @@ void setup_inline_extent_backref(struct btrfs_fs_info *fs_info, } static int lookup_extent_backref(struct btrfs_trans_handle *trans, - struct btrfs_fs_info *fs_info, struct btrfs_path *path, struct btrfs_extent_inline_ref **ref_ret, u64 bytenr, u64 num_bytes, u64 parent, @@ -6878,9 +6877,8 @@ static int __btrfs_free_extent(struct btrfs_trans_handle *trans, if (is_data) skinny_metadata = false; - ret = lookup_extent_backref(trans, info, path, &iref, - bytenr, num_bytes, parent, - root_objectid, owner_objectid, + ret = lookup_extent_backref(trans, path, &iref, bytenr, num_bytes, + parent, root_objectid, owner_objectid, owner_offset); if (ret == 0) { extent_slot = path->slots[0]; -- cgit v1.2.3 From 44e1c47d5c3f31a9f5c883834eb9e29d0b165ea8 Mon Sep 17 00:00:00 2001 From: Nikolay Borisov Date: Wed, 20 Jun 2018 15:48:53 +0300 Subject: btrfs: Remove fs_info from btrfs_add_delayed_tree_ref This function is always called with a valid transaction handle from where fs_info can be referenced. No functional changes. Signed-off-by: Nikolay Borisov Reviewed-by: Qu Wenruo Signed-off-by: David Sterba --- fs/btrfs/delayed-ref.c | 4 ++-- fs/btrfs/delayed-ref.h | 3 +-- fs/btrfs/extent-tree.c | 8 ++++---- 3 files changed, 7 insertions(+), 8 deletions(-) (limited to 'fs') diff --git a/fs/btrfs/delayed-ref.c b/fs/btrfs/delayed-ref.c index 03dec673d12a..82ac1273c65f 100644 --- a/fs/btrfs/delayed-ref.c +++ b/fs/btrfs/delayed-ref.c @@ -709,13 +709,13 @@ static void init_delayed_ref_common(struct btrfs_fs_info *fs_info, * to make sure the delayed ref is eventually processed before this * transaction commits. */ -int btrfs_add_delayed_tree_ref(struct btrfs_fs_info *fs_info, - struct btrfs_trans_handle *trans, +int btrfs_add_delayed_tree_ref(struct btrfs_trans_handle *trans, u64 bytenr, u64 num_bytes, u64 parent, u64 ref_root, int level, int action, struct btrfs_delayed_extent_op *extent_op, int *old_ref_mod, int *new_ref_mod) { + struct btrfs_fs_info *fs_info = trans->fs_info; struct btrfs_delayed_tree_ref *ref; struct btrfs_delayed_ref_head *head_ref; struct btrfs_delayed_ref_root *delayed_refs; diff --git a/fs/btrfs/delayed-ref.h b/fs/btrfs/delayed-ref.h index ea1aecb6a50d..31729302c827 100644 --- a/fs/btrfs/delayed-ref.h +++ b/fs/btrfs/delayed-ref.h @@ -234,8 +234,7 @@ static inline void btrfs_put_delayed_ref_head(struct btrfs_delayed_ref_head *hea kmem_cache_free(btrfs_delayed_ref_head_cachep, head); } -int btrfs_add_delayed_tree_ref(struct btrfs_fs_info *fs_info, - struct btrfs_trans_handle *trans, +int btrfs_add_delayed_tree_ref(struct btrfs_trans_handle *trans, u64 bytenr, u64 num_bytes, u64 parent, u64 ref_root, int level, int action, struct btrfs_delayed_extent_op *extent_op, diff --git a/fs/btrfs/extent-tree.c b/fs/btrfs/extent-tree.c index 19239ad3c6d1..6b74ffc47ae4 100644 --- a/fs/btrfs/extent-tree.c +++ b/fs/btrfs/extent-tree.c @@ -2176,7 +2176,7 @@ int btrfs_inc_extent_ref(struct btrfs_trans_handle *trans, owner, offset, BTRFS_ADD_DELAYED_REF); if (owner < BTRFS_FIRST_FREE_OBJECTID) { - ret = btrfs_add_delayed_tree_ref(fs_info, trans, bytenr, + ret = btrfs_add_delayed_tree_ref(trans, bytenr, num_bytes, parent, root_objectid, (int)owner, BTRFS_ADD_DELAYED_REF, NULL, @@ -7196,7 +7196,7 @@ void btrfs_free_tree_block(struct btrfs_trans_handle *trans, root->root_key.objectid, btrfs_header_level(buf), 0, BTRFS_DROP_DELAYED_REF); - ret = btrfs_add_delayed_tree_ref(fs_info, trans, buf->start, + ret = btrfs_add_delayed_tree_ref(trans, buf->start, buf->len, parent, root->root_key.objectid, btrfs_header_level(buf), @@ -7275,7 +7275,7 @@ int btrfs_free_extent(struct btrfs_trans_handle *trans, old_ref_mod = new_ref_mod = 0; ret = 0; } else if (owner < BTRFS_FIRST_FREE_OBJECTID) { - ret = btrfs_add_delayed_tree_ref(fs_info, trans, bytenr, + ret = btrfs_add_delayed_tree_ref(trans, bytenr, num_bytes, parent, root_objectid, (int)owner, BTRFS_DROP_DELAYED_REF, NULL, @@ -8491,7 +8491,7 @@ struct extent_buffer *btrfs_alloc_tree_block(struct btrfs_trans_handle *trans, btrfs_ref_tree_mod(root, ins.objectid, ins.offset, parent, root_objectid, level, 0, BTRFS_ADD_DELAYED_EXTENT); - ret = btrfs_add_delayed_tree_ref(fs_info, trans, ins.objectid, + ret = btrfs_add_delayed_tree_ref(trans, ins.objectid, ins.offset, parent, root_objectid, level, BTRFS_ADD_DELAYED_EXTENT, -- cgit v1.2.3 From 88a979c615d0d9da19498b3b7692e725fb2f387e Mon Sep 17 00:00:00 2001 From: Nikolay Borisov Date: Wed, 20 Jun 2018 15:48:54 +0300 Subject: btrfs: Remove fs_info from btrfs_add_delayed_data_ref This function is always called with a valid transaction handle from where fs_info can be referenced. No functional changes. Signed-off-by: Nikolay Borisov Reviewed-by: Qu Wenruo Signed-off-by: David Sterba --- fs/btrfs/delayed-ref.c | 4 ++-- fs/btrfs/delayed-ref.h | 3 +-- fs/btrfs/extent-tree.c | 7 +++---- 3 files changed, 6 insertions(+), 8 deletions(-) (limited to 'fs') diff --git a/fs/btrfs/delayed-ref.c b/fs/btrfs/delayed-ref.c index 82ac1273c65f..6eb00eb65d76 100644 --- a/fs/btrfs/delayed-ref.c +++ b/fs/btrfs/delayed-ref.c @@ -791,13 +791,13 @@ free_ref: /* * add a delayed data ref. it's similar to btrfs_add_delayed_tree_ref. */ -int btrfs_add_delayed_data_ref(struct btrfs_fs_info *fs_info, - struct btrfs_trans_handle *trans, +int btrfs_add_delayed_data_ref(struct btrfs_trans_handle *trans, u64 bytenr, u64 num_bytes, u64 parent, u64 ref_root, u64 owner, u64 offset, u64 reserved, int action, int *old_ref_mod, int *new_ref_mod) { + struct btrfs_fs_info *fs_info = trans->fs_info; struct btrfs_delayed_data_ref *ref; struct btrfs_delayed_ref_head *head_ref; struct btrfs_delayed_ref_root *delayed_refs; diff --git a/fs/btrfs/delayed-ref.h b/fs/btrfs/delayed-ref.h index 31729302c827..d9f2a4ebd5db 100644 --- a/fs/btrfs/delayed-ref.h +++ b/fs/btrfs/delayed-ref.h @@ -239,8 +239,7 @@ int btrfs_add_delayed_tree_ref(struct btrfs_trans_handle *trans, u64 ref_root, int level, int action, struct btrfs_delayed_extent_op *extent_op, int *old_ref_mod, int *new_ref_mod); -int btrfs_add_delayed_data_ref(struct btrfs_fs_info *fs_info, - struct btrfs_trans_handle *trans, +int btrfs_add_delayed_data_ref(struct btrfs_trans_handle *trans, u64 bytenr, u64 num_bytes, u64 parent, u64 ref_root, u64 owner, u64 offset, u64 reserved, int action, diff --git a/fs/btrfs/extent-tree.c b/fs/btrfs/extent-tree.c index 6b74ffc47ae4..10586687753c 100644 --- a/fs/btrfs/extent-tree.c +++ b/fs/btrfs/extent-tree.c @@ -2182,7 +2182,7 @@ int btrfs_inc_extent_ref(struct btrfs_trans_handle *trans, BTRFS_ADD_DELAYED_REF, NULL, &old_ref_mod, &new_ref_mod); } else { - ret = btrfs_add_delayed_data_ref(fs_info, trans, bytenr, + ret = btrfs_add_delayed_data_ref(trans, bytenr, num_bytes, parent, root_objectid, owner, offset, 0, BTRFS_ADD_DELAYED_REF, @@ -7281,7 +7281,7 @@ int btrfs_free_extent(struct btrfs_trans_handle *trans, BTRFS_DROP_DELAYED_REF, NULL, &old_ref_mod, &new_ref_mod); } else { - ret = btrfs_add_delayed_data_ref(fs_info, trans, bytenr, + ret = btrfs_add_delayed_data_ref(trans, bytenr, num_bytes, parent, root_objectid, owner, offset, 0, BTRFS_DROP_DELAYED_REF, @@ -8255,7 +8255,6 @@ int btrfs_alloc_reserved_file_extent(struct btrfs_trans_handle *trans, u64 offset, u64 ram_bytes, struct btrfs_key *ins) { - struct btrfs_fs_info *fs_info = root->fs_info; int ret; BUG_ON(root->root_key.objectid == BTRFS_TREE_LOG_OBJECTID); @@ -8264,7 +8263,7 @@ int btrfs_alloc_reserved_file_extent(struct btrfs_trans_handle *trans, root->root_key.objectid, owner, offset, BTRFS_ADD_DELAYED_EXTENT); - ret = btrfs_add_delayed_data_ref(fs_info, trans, ins->objectid, + ret = btrfs_add_delayed_data_ref(trans, ins->objectid, ins->offset, 0, root->root_key.objectid, owner, offset, ram_bytes, -- cgit v1.2.3 From e7e02096d98388a003323c4223630d011ba1b382 Mon Sep 17 00:00:00 2001 From: Nikolay Borisov Date: Wed, 20 Jun 2018 15:48:55 +0300 Subject: btrfs: Remove fs_info from btrfs_make_block_group This function is always called with a valid transaction handle from where we can reference the fs_info. No functional changes. Signed-off-by: Nikolay Borisov Reviewed-by: Qu Wenruo Signed-off-by: David Sterba --- fs/btrfs/ctree.h | 4 ++-- fs/btrfs/extent-tree.c | 4 ++-- fs/btrfs/volumes.c | 4 ++-- 3 files changed, 6 insertions(+), 6 deletions(-) (limited to 'fs') diff --git a/fs/btrfs/ctree.h b/fs/btrfs/ctree.h index e671a1fcbbec..b77f9ac699c1 100644 --- a/fs/btrfs/ctree.h +++ b/fs/btrfs/ctree.h @@ -2716,8 +2716,8 @@ int btrfs_free_block_groups(struct btrfs_fs_info *info); int btrfs_read_block_groups(struct btrfs_fs_info *info); int btrfs_can_relocate(struct btrfs_fs_info *fs_info, u64 bytenr); int btrfs_make_block_group(struct btrfs_trans_handle *trans, - struct btrfs_fs_info *fs_info, u64 bytes_used, - u64 type, u64 chunk_offset, u64 size); + u64 bytes_used, u64 type, u64 chunk_offset, + u64 size); void btrfs_add_raid_kobjects(struct btrfs_fs_info *fs_info); struct btrfs_trans_handle *btrfs_start_trans_remove_block_group( struct btrfs_fs_info *fs_info, diff --git a/fs/btrfs/extent-tree.c b/fs/btrfs/extent-tree.c index 10586687753c..fa78a0175f80 100644 --- a/fs/btrfs/extent-tree.c +++ b/fs/btrfs/extent-tree.c @@ -10241,10 +10241,10 @@ next: trans->can_flush_pending_bgs = can_flush_pending_bgs; } -int btrfs_make_block_group(struct btrfs_trans_handle *trans, - struct btrfs_fs_info *fs_info, u64 bytes_used, +int btrfs_make_block_group(struct btrfs_trans_handle *trans, u64 bytes_used, u64 type, u64 chunk_offset, u64 size) { + struct btrfs_fs_info *fs_info = trans->fs_info; struct btrfs_block_group_cache *cache; int ret; diff --git a/fs/btrfs/volumes.c b/fs/btrfs/volumes.c index 1da162928d1a..e806669dc43a 100644 --- a/fs/btrfs/volumes.c +++ b/fs/btrfs/volumes.c @@ -4900,7 +4900,7 @@ static int __btrfs_alloc_chunk(struct btrfs_trans_handle *trans, refcount_inc(&em->refs); write_unlock(&em_tree->lock); - ret = btrfs_make_block_group(trans, info, 0, type, start, num_bytes); + ret = btrfs_make_block_group(trans, 0, type, start, num_bytes); if (ret) goto error_del_extent; @@ -5175,7 +5175,7 @@ int btrfs_num_copies(struct btrfs_fs_info *fs_info, u64 logical, u64 len) /* * There could be two corrupted data stripes, we need * to loop retry in order to rebuild the correct data. - * + * * Fail a stripe at a time on every retry except the * stripe under reconstruction. */ -- cgit v1.2.3 From 5a98ec0141805a0ff9adb18fd18834a906637f2f Mon Sep 17 00:00:00 2001 From: Nikolay Borisov Date: Wed, 20 Jun 2018 15:48:56 +0300 Subject: btrfs: Remove fs_info from btrfs_remove_block_group This function is always called with a valid transaction handle from where we can reference fs_info. No functional changes. Signed-off-by: Nikolay Borisov Reviewed-by: Qu Wenruo Signed-off-by: David Sterba --- fs/btrfs/ctree.h | 3 +-- fs/btrfs/extent-tree.c | 4 ++-- fs/btrfs/volumes.c | 2 +- 3 files changed, 4 insertions(+), 5 deletions(-) (limited to 'fs') diff --git a/fs/btrfs/ctree.h b/fs/btrfs/ctree.h index b77f9ac699c1..7df6739e8eca 100644 --- a/fs/btrfs/ctree.h +++ b/fs/btrfs/ctree.h @@ -2723,8 +2723,7 @@ struct btrfs_trans_handle *btrfs_start_trans_remove_block_group( struct btrfs_fs_info *fs_info, const u64 chunk_offset); int btrfs_remove_block_group(struct btrfs_trans_handle *trans, - struct btrfs_fs_info *fs_info, u64 group_start, - struct extent_map *em); + u64 group_start, struct extent_map *em); void btrfs_delete_unused_bgs(struct btrfs_fs_info *fs_info); void btrfs_get_block_group_trimming(struct btrfs_block_group_cache *cache); void btrfs_put_block_group_trimming(struct btrfs_block_group_cache *cache); diff --git a/fs/btrfs/extent-tree.c b/fs/btrfs/extent-tree.c index fa78a0175f80..cb1716caf11b 100644 --- a/fs/btrfs/extent-tree.c +++ b/fs/btrfs/extent-tree.c @@ -10334,9 +10334,9 @@ static void clear_avail_alloc_bits(struct btrfs_fs_info *fs_info, u64 flags) } int btrfs_remove_block_group(struct btrfs_trans_handle *trans, - struct btrfs_fs_info *fs_info, u64 group_start, - struct extent_map *em) + u64 group_start, struct extent_map *em) { + struct btrfs_fs_info *fs_info = trans->fs_info; struct btrfs_root *root = fs_info->extent_root; struct btrfs_path *path; struct btrfs_block_group_cache *block_group; diff --git a/fs/btrfs/volumes.c b/fs/btrfs/volumes.c index e806669dc43a..ff7c8cdacd85 100644 --- a/fs/btrfs/volumes.c +++ b/fs/btrfs/volumes.c @@ -2885,7 +2885,7 @@ int btrfs_remove_chunk(struct btrfs_trans_handle *trans, } } - ret = btrfs_remove_block_group(trans, fs_info, chunk_offset, em); + ret = btrfs_remove_block_group(trans, chunk_offset, em); if (ret) { btrfs_abort_transaction(trans, ret); goto out; -- cgit v1.2.3 From e72cb9235d26e5b7360a38a702e644a24d8975e6 Mon Sep 17 00:00:00 2001 From: Nikolay Borisov Date: Wed, 20 Jun 2018 15:48:57 +0300 Subject: btrfs: Remove fs_info from __btrfs_free_extent This function is always called with a valid transaction handle so we can reference the fs_info from there. No functional changes. Signed-off-by: Nikolay Borisov Reviewed-by: Qu Wenruo Signed-off-by: David Sterba --- fs/btrfs/extent-tree.c | 24 +++++++++++------------- 1 file changed, 11 insertions(+), 13 deletions(-) (limited to 'fs') diff --git a/fs/btrfs/extent-tree.c b/fs/btrfs/extent-tree.c index cb1716caf11b..67a3aa8bc283 100644 --- a/fs/btrfs/extent-tree.c +++ b/fs/btrfs/extent-tree.c @@ -52,11 +52,10 @@ enum { }; static int __btrfs_free_extent(struct btrfs_trans_handle *trans, - struct btrfs_fs_info *fs_info, - struct btrfs_delayed_ref_node *node, u64 parent, - u64 root_objectid, u64 owner_objectid, - u64 owner_offset, int refs_to_drop, - struct btrfs_delayed_extent_op *extra_op); + struct btrfs_delayed_ref_node *node, u64 parent, + u64 root_objectid, u64 owner_objectid, + u64 owner_offset, int refs_to_drop, + struct btrfs_delayed_extent_op *extra_op); static void __run_delayed_extent_op(struct btrfs_delayed_extent_op *extent_op, struct extent_buffer *leaf, struct btrfs_extent_item *ei); @@ -2327,7 +2326,7 @@ static int run_delayed_data_ref(struct btrfs_trans_handle *trans, ref->offset, node->ref_mod, extent_op); } else if (node->action == BTRFS_DROP_DELAYED_REF) { - ret = __btrfs_free_extent(trans, fs_info, node, parent, + ret = __btrfs_free_extent(trans, node, parent, ref_root, ref->objectid, ref->offset, node->ref_mod, extent_op); @@ -2480,8 +2479,7 @@ static int run_delayed_tree_ref(struct btrfs_trans_handle *trans, ref->level, 0, 1, extent_op); } else if (node->action == BTRFS_DROP_DELAYED_REF) { - ret = __btrfs_free_extent(trans, fs_info, node, - parent, ref_root, + ret = __btrfs_free_extent(trans, node, parent, ref_root, ref->level, 0, 1, extent_op); } else { BUG(); @@ -6840,12 +6838,12 @@ int btrfs_finish_extent_commit(struct btrfs_trans_handle *trans) } static int __btrfs_free_extent(struct btrfs_trans_handle *trans, - struct btrfs_fs_info *info, - struct btrfs_delayed_ref_node *node, u64 parent, - u64 root_objectid, u64 owner_objectid, - u64 owner_offset, int refs_to_drop, - struct btrfs_delayed_extent_op *extent_op) + struct btrfs_delayed_ref_node *node, u64 parent, + u64 root_objectid, u64 owner_objectid, + u64 owner_offset, int refs_to_drop, + struct btrfs_delayed_extent_op *extent_op) { + struct btrfs_fs_info *info = trans->fs_info; struct btrfs_key key; struct btrfs_path *path; struct btrfs_root *extent_root = info->extent_root; -- cgit v1.2.3 From ef89b8245bc77a29f31cad2dec5be5f50d3a7c2b Mon Sep 17 00:00:00 2001 From: Nikolay Borisov Date: Wed, 20 Jun 2018 15:48:58 +0300 Subject: btrfs: Remove fs_info from alloc_reserved_file_extent fs_info can be referenced from the transaction handle, which is always valid. No functional changes. Signed-off-by: Nikolay Borisov Reviewed-by: Qu Wenruo Signed-off-by: David Sterba --- fs/btrfs/extent-tree.c | 15 +++++++-------- 1 file changed, 7 insertions(+), 8 deletions(-) (limited to 'fs') diff --git a/fs/btrfs/extent-tree.c b/fs/btrfs/extent-tree.c index 67a3aa8bc283..f9f5c8f06021 100644 --- a/fs/btrfs/extent-tree.c +++ b/fs/btrfs/extent-tree.c @@ -60,7 +60,6 @@ static void __run_delayed_extent_op(struct btrfs_delayed_extent_op *extent_op, struct extent_buffer *leaf, struct btrfs_extent_item *ei); static int alloc_reserved_file_extent(struct btrfs_trans_handle *trans, - struct btrfs_fs_info *fs_info, u64 parent, u64 root_objectid, u64 flags, u64 owner, u64 offset, struct btrfs_key *ins, int ref_mod); @@ -2316,10 +2315,10 @@ static int run_delayed_data_ref(struct btrfs_trans_handle *trans, if (node->action == BTRFS_ADD_DELAYED_REF && insert_reserved) { if (extent_op) flags |= extent_op->flags_to_set; - ret = alloc_reserved_file_extent(trans, fs_info, - parent, ref_root, flags, - ref->objectid, ref->offset, - &ins, node->ref_mod); + ret = alloc_reserved_file_extent(trans, parent, ref_root, + flags, ref->objectid, + ref->offset, &ins, + node->ref_mod); } else if (node->action == BTRFS_ADD_DELAYED_REF) { ret = __btrfs_inc_extent_ref(trans, fs_info, node, parent, ref_root, ref->objectid, @@ -8075,11 +8074,11 @@ int btrfs_free_and_pin_reserved_extent(struct btrfs_fs_info *fs_info, } static int alloc_reserved_file_extent(struct btrfs_trans_handle *trans, - struct btrfs_fs_info *fs_info, u64 parent, u64 root_objectid, u64 flags, u64 owner, u64 offset, struct btrfs_key *ins, int ref_mod) { + struct btrfs_fs_info *fs_info = trans->fs_info; int ret; struct btrfs_extent_item *extent_item; struct btrfs_extent_inline_ref *iref; @@ -8306,8 +8305,8 @@ int btrfs_alloc_logged_file_extent(struct btrfs_trans_handle *trans, spin_unlock(&block_group->lock); spin_unlock(&space_info->lock); - ret = alloc_reserved_file_extent(trans, fs_info, 0, root_objectid, - 0, owner, offset, ins, 1); + ret = alloc_reserved_file_extent(trans, 0, root_objectid, 0, owner, + offset, ins, 1); btrfs_put_block_group(block_group); return ret; } -- cgit v1.2.3 From 2590d0f155c7c133b0c05048526ccc0a8dd5e9e4 Mon Sep 17 00:00:00 2001 From: Nikolay Borisov Date: Wed, 20 Jun 2018 15:48:59 +0300 Subject: btrfs: Remove fs_info argument from __btrfs_inc_extent_ref This function already takes a transaction which holds a reference to the fs_info struct. Use that reference and remove the extra arg. No functional changes. Signed-off-by: Nikolay Borisov Reviewed-by: Qu Wenruo Signed-off-by: David Sterba --- fs/btrfs/extent-tree.c | 15 ++++++--------- 1 file changed, 6 insertions(+), 9 deletions(-) (limited to 'fs') diff --git a/fs/btrfs/extent-tree.c b/fs/btrfs/extent-tree.c index f9f5c8f06021..15fd8223344c 100644 --- a/fs/btrfs/extent-tree.c +++ b/fs/btrfs/extent-tree.c @@ -2231,12 +2231,12 @@ int btrfs_inc_extent_ref(struct btrfs_trans_handle *trans, * */ static int __btrfs_inc_extent_ref(struct btrfs_trans_handle *trans, - struct btrfs_fs_info *fs_info, struct btrfs_delayed_ref_node *node, u64 parent, u64 root_objectid, u64 owner, u64 offset, int refs_to_add, struct btrfs_delayed_extent_op *extent_op) { + struct btrfs_fs_info *fs_info = trans->fs_info; struct btrfs_path *path; struct extent_buffer *leaf; struct btrfs_extent_item *item; @@ -2320,10 +2320,9 @@ static int run_delayed_data_ref(struct btrfs_trans_handle *trans, ref->offset, &ins, node->ref_mod); } else if (node->action == BTRFS_ADD_DELAYED_REF) { - ret = __btrfs_inc_extent_ref(trans, fs_info, node, parent, - ref_root, ref->objectid, - ref->offset, node->ref_mod, - extent_op); + ret = __btrfs_inc_extent_ref(trans, node, parent, ref_root, + ref->objectid, ref->offset, + node->ref_mod, extent_op); } else if (node->action == BTRFS_DROP_DELAYED_REF) { ret = __btrfs_free_extent(trans, node, parent, ref_root, ref->objectid, @@ -2473,10 +2472,8 @@ static int run_delayed_tree_ref(struct btrfs_trans_handle *trans, BUG_ON(!extent_op || !extent_op->update_flags); ret = alloc_reserved_tree_block(trans, node, extent_op); } else if (node->action == BTRFS_ADD_DELAYED_REF) { - ret = __btrfs_inc_extent_ref(trans, fs_info, node, - parent, ref_root, - ref->level, 0, 1, - extent_op); + ret = __btrfs_inc_extent_ref(trans, node, parent, ref_root, + ref->level, 0, 1, extent_op); } else if (node->action == BTRFS_DROP_DELAYED_REF) { ret = __btrfs_free_extent(trans, node, parent, ref_root, ref->level, 0, 1, extent_op); -- cgit v1.2.3 From 2bf98ef35f7fd4b5222b0d82e3abd3a27eb49a50 Mon Sep 17 00:00:00 2001 From: Nikolay Borisov Date: Wed, 20 Jun 2018 15:49:00 +0300 Subject: btrfs: Remove fs_info from run_delayed_data_ref This function is always called with a valid transaction from where fs_info can be referenced. No functional changes. Signed-off-by: Nikolay Borisov Reviewed-by: Qu Wenruo Signed-off-by: David Sterba --- fs/btrfs/extent-tree.c | 5 ++--- 1 file changed, 2 insertions(+), 3 deletions(-) (limited to 'fs') diff --git a/fs/btrfs/extent-tree.c b/fs/btrfs/extent-tree.c index 15fd8223344c..dbc936ff52a4 100644 --- a/fs/btrfs/extent-tree.c +++ b/fs/btrfs/extent-tree.c @@ -2289,7 +2289,6 @@ out: } static int run_delayed_data_ref(struct btrfs_trans_handle *trans, - struct btrfs_fs_info *fs_info, struct btrfs_delayed_ref_node *node, struct btrfs_delayed_extent_op *extent_op, int insert_reserved) @@ -2306,7 +2305,7 @@ static int run_delayed_data_ref(struct btrfs_trans_handle *trans, ins.type = BTRFS_EXTENT_ITEM_KEY; ref = btrfs_delayed_node_to_data_ref(node); - trace_run_delayed_data_ref(fs_info, node, ref, node->action); + trace_run_delayed_data_ref(trans->fs_info, node, ref, node->action); if (node->type == BTRFS_SHARED_DATA_REF_KEY) parent = ref->parent; @@ -2505,7 +2504,7 @@ static int run_one_delayed_ref(struct btrfs_trans_handle *trans, insert_reserved); else if (node->type == BTRFS_EXTENT_DATA_REF_KEY || node->type == BTRFS_SHARED_DATA_REF_KEY) - ret = run_delayed_data_ref(trans, fs_info, node, extent_op, + ret = run_delayed_data_ref(trans, node, extent_op, insert_reserved); else BUG(); -- cgit v1.2.3 From 20b9a2d670fa9f06d9f682cc414f3d1cb0adf440 Mon Sep 17 00:00:00 2001 From: Nikolay Borisov Date: Wed, 20 Jun 2018 15:49:01 +0300 Subject: btrfs: Remove fs_info from run_delayed_extent_op This function is always called with a valid transaction handle so fs_info can be referenced from there. No functional changes. Signed-off-by: Nikolay Borisov Reviewed-by: Qu Wenruo Signed-off-by: David Sterba --- fs/btrfs/extent-tree.c | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) (limited to 'fs') diff --git a/fs/btrfs/extent-tree.c b/fs/btrfs/extent-tree.c index dbc936ff52a4..1c6c9ed1f7d2 100644 --- a/fs/btrfs/extent-tree.c +++ b/fs/btrfs/extent-tree.c @@ -2352,10 +2352,10 @@ static void __run_delayed_extent_op(struct btrfs_delayed_extent_op *extent_op, } static int run_delayed_extent_op(struct btrfs_trans_handle *trans, - struct btrfs_fs_info *fs_info, struct btrfs_delayed_ref_head *head, struct btrfs_delayed_extent_op *extent_op) { + struct btrfs_fs_info *fs_info = trans->fs_info; struct btrfs_key key; struct btrfs_path *path; struct btrfs_extent_item *ei; @@ -2560,7 +2560,7 @@ static int cleanup_extent_op(struct btrfs_trans_handle *trans, return 0; } spin_unlock(&head->lock); - ret = run_delayed_extent_op(trans, fs_info, head, extent_op); + ret = run_delayed_extent_op(trans, head, extent_op); btrfs_free_delayed_extent_op(extent_op); return ret ? ret : 1; } -- cgit v1.2.3 From c4d56d4a1688e9cb926fd4abb428e5a9c1f963b9 Mon Sep 17 00:00:00 2001 From: Nikolay Borisov Date: Wed, 20 Jun 2018 15:49:02 +0300 Subject: btrfs: Remove unused fs_info from cleanup_extent_op The argument is no longer used so remove it. Signed-off-by: Nikolay Borisov Reviewed-by: Qu Wenruo Signed-off-by: David Sterba --- fs/btrfs/extent-tree.c | 3 +-- 1 file changed, 1 insertion(+), 2 deletions(-) (limited to 'fs') diff --git a/fs/btrfs/extent-tree.c b/fs/btrfs/extent-tree.c index 1c6c9ed1f7d2..25a6202be4e3 100644 --- a/fs/btrfs/extent-tree.c +++ b/fs/btrfs/extent-tree.c @@ -2546,7 +2546,6 @@ static void unselect_delayed_ref_head(struct btrfs_delayed_ref_root *delayed_ref } static int cleanup_extent_op(struct btrfs_trans_handle *trans, - struct btrfs_fs_info *fs_info, struct btrfs_delayed_ref_head *head) { struct btrfs_delayed_extent_op *extent_op = head->extent_op; @@ -2574,7 +2573,7 @@ static int cleanup_ref_head(struct btrfs_trans_handle *trans, delayed_refs = &trans->transaction->delayed_refs; - ret = cleanup_extent_op(trans, fs_info, head); + ret = cleanup_extent_op(trans, head); if (ret < 0) { unselect_delayed_ref_head(delayed_refs, head); btrfs_debug(fs_info, "run_delayed_extent_op returned %d", ret); -- cgit v1.2.3 From f9871eddd9cb1acff770e03344a4cf12c343546f Mon Sep 17 00:00:00 2001 From: Nikolay Borisov Date: Wed, 20 Jun 2018 15:49:03 +0300 Subject: btrfs: Remove fs_info from cleanup_ref_head fs_info can be refenreced from the transaction handle, since it's always valid. No functional changes. Signed-off-by: Nikolay Borisov Reviewed-by: Qu Wenruo Signed-off-by: David Sterba --- fs/btrfs/extent-tree.c | 5 +++-- 1 file changed, 3 insertions(+), 2 deletions(-) (limited to 'fs') diff --git a/fs/btrfs/extent-tree.c b/fs/btrfs/extent-tree.c index 25a6202be4e3..9f630298ea11 100644 --- a/fs/btrfs/extent-tree.c +++ b/fs/btrfs/extent-tree.c @@ -2565,9 +2565,10 @@ static int cleanup_extent_op(struct btrfs_trans_handle *trans, } static int cleanup_ref_head(struct btrfs_trans_handle *trans, - struct btrfs_fs_info *fs_info, struct btrfs_delayed_ref_head *head) { + + struct btrfs_fs_info *fs_info = trans->fs_info; struct btrfs_delayed_ref_root *delayed_refs; int ret; @@ -2722,7 +2723,7 @@ static noinline int __btrfs_run_delayed_refs(struct btrfs_trans_handle *trans, * up and move on to the next ref_head. */ if (!ref) { - ret = cleanup_ref_head(trans, fs_info, locked_ref); + ret = cleanup_ref_head(trans, locked_ref); if (ret > 0 ) { /* We dropped our lock, we need to loop. */ ret = 0; -- cgit v1.2.3 From f97806f2eefdd762304e078fdbb2f8b994942ea6 Mon Sep 17 00:00:00 2001 From: Nikolay Borisov Date: Wed, 20 Jun 2018 15:49:04 +0300 Subject: btrfs: Remove fs_info from run_delayed_tree_ref It can always be referneced from the passed transaction handle since it's always valid. No functional changes. Signed-off-by: Nikolay Borisov Reviewed-by: Qu Wenruo Signed-off-by: David Sterba --- fs/btrfs/extent-tree.c | 7 +++---- 1 file changed, 3 insertions(+), 4 deletions(-) (limited to 'fs') diff --git a/fs/btrfs/extent-tree.c b/fs/btrfs/extent-tree.c index 9f630298ea11..c7a66dd434fc 100644 --- a/fs/btrfs/extent-tree.c +++ b/fs/btrfs/extent-tree.c @@ -2443,7 +2443,6 @@ out: } static int run_delayed_tree_ref(struct btrfs_trans_handle *trans, - struct btrfs_fs_info *fs_info, struct btrfs_delayed_ref_node *node, struct btrfs_delayed_extent_op *extent_op, int insert_reserved) @@ -2454,14 +2453,14 @@ static int run_delayed_tree_ref(struct btrfs_trans_handle *trans, u64 ref_root = 0; ref = btrfs_delayed_node_to_tree_ref(node); - trace_run_delayed_tree_ref(fs_info, node, ref, node->action); + trace_run_delayed_tree_ref(trans->fs_info, node, ref, node->action); if (node->type == BTRFS_SHARED_BLOCK_REF_KEY) parent = ref->parent; ref_root = ref->root; if (node->ref_mod != 1) { - btrfs_err(fs_info, + btrfs_err(trans->fs_info, "btree block(%llu) has %d references rather than 1: action %d ref_root %llu parent %llu", node->bytenr, node->ref_mod, node->action, ref_root, parent); @@ -2500,7 +2499,7 @@ static int run_one_delayed_ref(struct btrfs_trans_handle *trans, if (node->type == BTRFS_TREE_BLOCK_REF_KEY || node->type == BTRFS_SHARED_BLOCK_REF_KEY) - ret = run_delayed_tree_ref(trans, fs_info, node, extent_op, + ret = run_delayed_tree_ref(trans, node, extent_op, insert_reserved); else if (node->type == BTRFS_EXTENT_DATA_REF_KEY || node->type == BTRFS_SHARED_DATA_REF_KEY) -- cgit v1.2.3 From 01458828bb420d6a8f9aa09af2376caab71660b3 Mon Sep 17 00:00:00 2001 From: Nikolay Borisov Date: Wed, 20 Jun 2018 15:49:05 +0300 Subject: btrfs: Remove fs_info from do_chunk_alloc This function is always called with a valid transaction handle from where fs_info can be referenced. No functional changes. Signed-off-by: Nikolay Borisov Reviewed-by: Qu Wenruo Signed-off-by: David Sterba --- fs/btrfs/extent-tree.c | 22 ++++++++++------------ 1 file changed, 10 insertions(+), 12 deletions(-) (limited to 'fs') diff --git a/fs/btrfs/extent-tree.c b/fs/btrfs/extent-tree.c index c7a66dd434fc..556b93c05ee3 100644 --- a/fs/btrfs/extent-tree.c +++ b/fs/btrfs/extent-tree.c @@ -66,8 +66,7 @@ static int alloc_reserved_file_extent(struct btrfs_trans_handle *trans, static int alloc_reserved_tree_block(struct btrfs_trans_handle *trans, struct btrfs_delayed_ref_node *node, struct btrfs_delayed_extent_op *extent_op); -static int do_chunk_alloc(struct btrfs_trans_handle *trans, - struct btrfs_fs_info *fs_info, u64 flags, +static int do_chunk_alloc(struct btrfs_trans_handle *trans, u64 flags, int force); static int find_next_key(struct btrfs_path *path, int level, struct btrfs_key *key); @@ -4306,7 +4305,7 @@ again: if (IS_ERR(trans)) return PTR_ERR(trans); - ret = do_chunk_alloc(trans, fs_info, alloc_target, + ret = do_chunk_alloc(trans, alloc_target, CHUNK_ALLOC_NO_FORCE); btrfs_end_transaction(trans); if (ret < 0) { @@ -4590,9 +4589,10 @@ void check_system_chunk(struct btrfs_trans_handle *trans, * - return 1 if it successfully allocates a chunk, * - return errors including -ENOSPC otherwise. */ -static int do_chunk_alloc(struct btrfs_trans_handle *trans, - struct btrfs_fs_info *fs_info, u64 flags, int force) +static int do_chunk_alloc(struct btrfs_trans_handle *trans, u64 flags, + int force) { + struct btrfs_fs_info *fs_info = trans->fs_info; struct btrfs_space_info *space_info; int wait_for_alloc = 0; int ret = 0; @@ -5001,7 +5001,7 @@ static void flush_space(struct btrfs_fs_info *fs_info, ret = PTR_ERR(trans); break; } - ret = do_chunk_alloc(trans, fs_info, + ret = do_chunk_alloc(trans, btrfs_metadata_alloc_profile(fs_info), CHUNK_ALLOC_NO_FORCE); btrfs_end_transaction(trans); @@ -7842,8 +7842,7 @@ loop: goto out; } - ret = do_chunk_alloc(trans, fs_info, flags, - CHUNK_ALLOC_FORCE); + ret = do_chunk_alloc(trans, flags, CHUNK_ALLOC_FORCE); /* * If we can't allocate a new chunk we've already looped @@ -9469,7 +9468,7 @@ again: */ alloc_flags = update_block_group_flags(fs_info, cache->flags); if (alloc_flags != cache->flags) { - ret = do_chunk_alloc(trans, fs_info, alloc_flags, + ret = do_chunk_alloc(trans, alloc_flags, CHUNK_ALLOC_FORCE); /* * ENOSPC is allowed here, we may have enough space @@ -9486,8 +9485,7 @@ again: if (!ret) goto out; alloc_flags = get_alloc_profile(fs_info, cache->space_info->flags); - ret = do_chunk_alloc(trans, fs_info, alloc_flags, - CHUNK_ALLOC_FORCE); + ret = do_chunk_alloc(trans, alloc_flags, CHUNK_ALLOC_FORCE); if (ret < 0) goto out; ret = inc_block_group_ro(cache, 0); @@ -9509,7 +9507,7 @@ int btrfs_force_chunk_alloc(struct btrfs_trans_handle *trans, { u64 alloc_flags = get_alloc_profile(fs_info, type); - return do_chunk_alloc(trans, fs_info, alloc_flags, CHUNK_ALLOC_FORCE); + return do_chunk_alloc(trans, alloc_flags, CHUNK_ALLOC_FORCE); } /* -- cgit v1.2.3 From c216b2039aa06f9be23a9f385cb2d2f6434927d7 Mon Sep 17 00:00:00 2001 From: Nikolay Borisov Date: Wed, 20 Jun 2018 15:49:06 +0300 Subject: btrfs: Remove fs_info from btrfs_alloc_chunk It can be referenced from trans since the function is always called within a transaction. Signed-off-by: Nikolay Borisov Reviewed-by: Qu Wenruo Signed-off-by: David Sterba --- fs/btrfs/extent-tree.c | 4 ++-- fs/btrfs/volumes.c | 7 +++---- fs/btrfs/volumes.h | 3 +-- 3 files changed, 6 insertions(+), 8 deletions(-) (limited to 'fs') diff --git a/fs/btrfs/extent-tree.c b/fs/btrfs/extent-tree.c index 556b93c05ee3..c0928fcb3f32 100644 --- a/fs/btrfs/extent-tree.c +++ b/fs/btrfs/extent-tree.c @@ -4568,7 +4568,7 @@ void check_system_chunk(struct btrfs_trans_handle *trans, * the paths we visit in the chunk tree (they were already COWed * or created in the current transaction for example). */ - ret = btrfs_alloc_chunk(trans, fs_info, flags); + ret = btrfs_alloc_chunk(trans, flags); } if (!ret) { @@ -4670,7 +4670,7 @@ again: */ check_system_chunk(trans, fs_info, flags); - ret = btrfs_alloc_chunk(trans, fs_info, flags); + ret = btrfs_alloc_chunk(trans, flags); trans->allocating_chunk = false; spin_lock(&space_info->lock); diff --git a/fs/btrfs/volumes.c b/fs/btrfs/volumes.c index ff7c8cdacd85..4a7423294270 100644 --- a/fs/btrfs/volumes.c +++ b/fs/btrfs/volumes.c @@ -5038,13 +5038,12 @@ out: * require modifying the chunk tree. This division is important for the * bootstrap process of adding storage to a seed btrfs. */ -int btrfs_alloc_chunk(struct btrfs_trans_handle *trans, - struct btrfs_fs_info *fs_info, u64 type) +int btrfs_alloc_chunk(struct btrfs_trans_handle *trans, u64 type) { u64 chunk_offset; - lockdep_assert_held(&fs_info->chunk_mutex); - chunk_offset = find_next_chunk(fs_info); + lockdep_assert_held(&trans->fs_info->chunk_mutex); + chunk_offset = find_next_chunk(trans->fs_info); return __btrfs_alloc_chunk(trans, chunk_offset, type); } diff --git a/fs/btrfs/volumes.h b/fs/btrfs/volumes.h index 5139ec8daf4c..df2d8bdf8c9a 100644 --- a/fs/btrfs/volumes.h +++ b/fs/btrfs/volumes.h @@ -396,8 +396,7 @@ int btrfs_rmap_block(struct btrfs_fs_info *fs_info, u64 chunk_start, u64 physical, u64 **logical, int *naddrs, int *stripe_len); int btrfs_read_sys_array(struct btrfs_fs_info *fs_info); int btrfs_read_chunk_tree(struct btrfs_fs_info *fs_info); -int btrfs_alloc_chunk(struct btrfs_trans_handle *trans, - struct btrfs_fs_info *fs_info, u64 type); +int btrfs_alloc_chunk(struct btrfs_trans_handle *trans, u64 type); void btrfs_mapping_init(struct btrfs_mapping_tree *tree); void btrfs_mapping_tree_free(struct btrfs_mapping_tree *tree); blk_status_t btrfs_map_bio(struct btrfs_fs_info *fs_info, struct bio *bio, -- cgit v1.2.3 From 451a2c130342125ca44dbbf3b62521c3f0041cfb Mon Sep 17 00:00:00 2001 From: Nikolay Borisov Date: Wed, 20 Jun 2018 15:49:07 +0300 Subject: btrfs: Remove fs_info from check_system_chunk It can be referenced from trans since the function is always called within a transaction. Signed-off-by: Nikolay Borisov Reviewed-by: Qu Wenruo Signed-off-by: David Sterba --- fs/btrfs/ctree.h | 3 +-- fs/btrfs/extent-tree.c | 8 ++++---- fs/btrfs/volumes.c | 2 +- 3 files changed, 6 insertions(+), 7 deletions(-) (limited to 'fs') diff --git a/fs/btrfs/ctree.h b/fs/btrfs/ctree.h index 7df6739e8eca..db97e34aa113 100644 --- a/fs/btrfs/ctree.h +++ b/fs/btrfs/ctree.h @@ -2821,8 +2821,7 @@ int btrfs_delayed_refs_qgroup_accounting(struct btrfs_trans_handle *trans, int btrfs_start_write_no_snapshotting(struct btrfs_root *root); void btrfs_end_write_no_snapshotting(struct btrfs_root *root); void btrfs_wait_for_snapshot_creation(struct btrfs_root *root); -void check_system_chunk(struct btrfs_trans_handle *trans, - struct btrfs_fs_info *fs_info, const u64 type); +void check_system_chunk(struct btrfs_trans_handle *trans, const u64 type); u64 add_new_free_space(struct btrfs_block_group_cache *block_group, u64 start, u64 end); diff --git a/fs/btrfs/extent-tree.c b/fs/btrfs/extent-tree.c index c0928fcb3f32..ca88a86b1c73 100644 --- a/fs/btrfs/extent-tree.c +++ b/fs/btrfs/extent-tree.c @@ -4527,9 +4527,9 @@ static u64 get_profile_num_devs(struct btrfs_fs_info *fs_info, u64 type) * for allocating a chunk, otherwise if it's false, reserve space necessary for * removing a chunk. */ -void check_system_chunk(struct btrfs_trans_handle *trans, - struct btrfs_fs_info *fs_info, u64 type) +void check_system_chunk(struct btrfs_trans_handle *trans, u64 type) { + struct btrfs_fs_info *fs_info = trans->fs_info; struct btrfs_space_info *info; u64 left; u64 thresh; @@ -4668,7 +4668,7 @@ again: * Check if we have enough space in SYSTEM chunk because we may need * to update devices. */ - check_system_chunk(trans, fs_info, flags); + check_system_chunk(trans, flags); ret = btrfs_alloc_chunk(trans, flags); trans->allocating_chunk = false; @@ -9493,7 +9493,7 @@ out: if (cache->flags & BTRFS_BLOCK_GROUP_SYSTEM) { alloc_flags = update_block_group_flags(fs_info, cache->flags); mutex_lock(&fs_info->chunk_mutex); - check_system_chunk(trans, fs_info, alloc_flags); + check_system_chunk(trans, alloc_flags); mutex_unlock(&fs_info->chunk_mutex); } mutex_unlock(&fs_info->ro_block_group_mutex); diff --git a/fs/btrfs/volumes.c b/fs/btrfs/volumes.c index 4a7423294270..9795d5079907 100644 --- a/fs/btrfs/volumes.c +++ b/fs/btrfs/volumes.c @@ -2829,7 +2829,7 @@ int btrfs_remove_chunk(struct btrfs_trans_handle *trans, } map = em->map_lookup; mutex_lock(&fs_info->chunk_mutex); - check_system_chunk(trans, fs_info, map->type); + check_system_chunk(trans, map->type); mutex_unlock(&fs_info->chunk_mutex); /* -- cgit v1.2.3 From 9e715da86001cdbb2d802f1ac8eb5e12c6eb0d08 Mon Sep 17 00:00:00 2001 From: Nikolay Borisov Date: Wed, 20 Jun 2018 15:49:08 +0300 Subject: btrfs: Remove fs_info from free_excluded_extents It can be referenced from the passed block group. Signed-off-by: Nikolay Borisov Reviewed-by: Qu Wenruo Signed-off-by: David Sterba --- fs/btrfs/extent-tree.c | 22 +++++++++++----------- 1 file changed, 11 insertions(+), 11 deletions(-) (limited to 'fs') diff --git a/fs/btrfs/extent-tree.c b/fs/btrfs/extent-tree.c index ca88a86b1c73..86c57b70ed28 100644 --- a/fs/btrfs/extent-tree.c +++ b/fs/btrfs/extent-tree.c @@ -217,9 +217,9 @@ static int add_excluded_extent(struct btrfs_fs_info *fs_info, return 0; } -static void free_excluded_extents(struct btrfs_fs_info *fs_info, - struct btrfs_block_group_cache *cache) +static void free_excluded_extents(struct btrfs_block_group_cache *cache) { + struct btrfs_fs_info *fs_info = cache->fs_info; u64 start, end; start = cache->key.objectid; @@ -555,7 +555,7 @@ static noinline void caching_thread(struct btrfs_work *work) caching_ctl->progress = (u64)-1; up_read(&fs_info->commit_root_sem); - free_excluded_extents(fs_info, block_group); + free_excluded_extents(block_group); mutex_unlock(&caching_ctl->mutex); wake_up(&caching_ctl->wait); @@ -663,7 +663,7 @@ static int cache_block_group(struct btrfs_block_group_cache *cache, wake_up(&caching_ctl->wait); if (ret == 1) { put_caching_control(caching_ctl); - free_excluded_extents(fs_info, cache); + free_excluded_extents(cache); return 0; } } else { @@ -9860,7 +9860,7 @@ int btrfs_free_block_groups(struct btrfs_fs_info *info) */ if (block_group->cached == BTRFS_CACHE_NO || block_group->cached == BTRFS_CACHE_ERROR) - free_excluded_extents(info, block_group); + free_excluded_extents(block_group); btrfs_remove_free_space_cache(block_group); ASSERT(block_group->cached != BTRFS_CACHE_STARTED); @@ -10108,7 +10108,7 @@ int btrfs_read_block_groups(struct btrfs_fs_info *info) * We may have excluded something, so call this just in * case. */ - free_excluded_extents(info, cache); + free_excluded_extents(cache); btrfs_put_block_group(cache); goto error; } @@ -10123,14 +10123,14 @@ int btrfs_read_block_groups(struct btrfs_fs_info *info) if (found_key.offset == btrfs_block_group_used(&cache->item)) { cache->last_byte_to_unpin = (u64)-1; cache->cached = BTRFS_CACHE_FINISHED; - free_excluded_extents(info, cache); + free_excluded_extents(cache); } else if (btrfs_block_group_used(&cache->item) == 0) { cache->last_byte_to_unpin = (u64)-1; cache->cached = BTRFS_CACHE_FINISHED; add_new_free_space(cache, found_key.objectid, found_key.objectid + found_key.offset); - free_excluded_extents(info, cache); + free_excluded_extents(cache); } ret = btrfs_add_block_group_cache(info, cache); @@ -10259,14 +10259,14 @@ int btrfs_make_block_group(struct btrfs_trans_handle *trans, u64 bytes_used, * We may have excluded something, so call this just in * case. */ - free_excluded_extents(fs_info, cache); + free_excluded_extents(cache); btrfs_put_block_group(cache); return ret; } add_new_free_space(cache, chunk_offset, chunk_offset + size); - free_excluded_extents(fs_info, cache); + free_excluded_extents(cache); #ifdef CONFIG_BTRFS_DEBUG if (btrfs_should_fragment_free_space(cache)) { @@ -10350,7 +10350,7 @@ int btrfs_remove_block_group(struct btrfs_trans_handle *trans, * Free the reserved super bytes from this block group before * remove it. */ - free_excluded_extents(fs_info, block_group); + free_excluded_extents(block_group); btrfs_free_ref_tree_range(fs_info, block_group->key.objectid, block_group->key.offset); -- cgit v1.2.3 From 3c4da6574e7749353be6d5e9f06d17388c241469 Mon Sep 17 00:00:00 2001 From: Nikolay Borisov Date: Wed, 20 Jun 2018 15:49:09 +0300 Subject: btrfs: Remove fs_info from exclude_super_stripes It can be referenced from the passed block group. Signed-off-by: Nikolay Borisov Reviewed-by: Qu Wenruo Signed-off-by: David Sterba --- fs/btrfs/extent-tree.c | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) (limited to 'fs') diff --git a/fs/btrfs/extent-tree.c b/fs/btrfs/extent-tree.c index 86c57b70ed28..18f51478242b 100644 --- a/fs/btrfs/extent-tree.c +++ b/fs/btrfs/extent-tree.c @@ -231,9 +231,9 @@ static void free_excluded_extents(struct btrfs_block_group_cache *cache) start, end, EXTENT_UPTODATE); } -static int exclude_super_stripes(struct btrfs_fs_info *fs_info, - struct btrfs_block_group_cache *cache) +static int exclude_super_stripes(struct btrfs_block_group_cache *cache) { + struct btrfs_fs_info *fs_info = cache->fs_info; u64 bytenr; u64 *logical; int stripe_len; @@ -10102,7 +10102,7 @@ int btrfs_read_block_groups(struct btrfs_fs_info *info) * info has super bytes accounted for, otherwise we'll think * we have more space than we actually do. */ - ret = exclude_super_stripes(info, cache); + ret = exclude_super_stripes(cache); if (ret) { /* * We may have excluded something, so call this just in @@ -10253,7 +10253,7 @@ int btrfs_make_block_group(struct btrfs_trans_handle *trans, u64 bytes_used, cache->last_byte_to_unpin = (u64)-1; cache->cached = BTRFS_CACHE_FINISHED; cache->needs_free_space = 1; - ret = exclude_super_stripes(fs_info, cache); + ret = exclude_super_stripes(cache); if (ret) { /* * We may have excluded something, so call this just in -- cgit v1.2.3 From a639cdeba3486883be9f016c96d03bbb31063f11 Mon Sep 17 00:00:00 2001 From: Nikolay Borisov Date: Wed, 20 Jun 2018 15:49:10 +0300 Subject: btrfs: Remove fs_info from insert_inline_extent_backref It can be referenced from the passed transaction handle, since it's always valid. Signed-off-by: Nikolay Borisov Reviewed-by: Qu Wenruo Signed-off-by: David Sterba --- fs/btrfs/extent-tree.c | 11 ++++------- 1 file changed, 4 insertions(+), 7 deletions(-) (limited to 'fs') diff --git a/fs/btrfs/extent-tree.c b/fs/btrfs/extent-tree.c index 18f51478242b..283a3e967184 100644 --- a/fs/btrfs/extent-tree.c +++ b/fs/btrfs/extent-tree.c @@ -1954,7 +1954,6 @@ void update_inline_extent_backref(struct btrfs_path *path, static noinline_for_stack int insert_inline_extent_backref(struct btrfs_trans_handle *trans, - struct btrfs_fs_info *fs_info, struct btrfs_path *path, u64 bytenr, u64 num_bytes, u64 parent, u64 root_objectid, u64 owner, @@ -1972,7 +1971,7 @@ int insert_inline_extent_backref(struct btrfs_trans_handle *trans, update_inline_extent_backref(path, iref, refs_to_add, extent_op, NULL); } else if (ret == -ENOENT) { - setup_inline_extent_backref(fs_info, path, iref, parent, + setup_inline_extent_backref(trans->fs_info, path, iref, parent, root_objectid, owner, offset, refs_to_add, extent_op); ret = 0; @@ -2235,7 +2234,6 @@ static int __btrfs_inc_extent_ref(struct btrfs_trans_handle *trans, u64 owner, u64 offset, int refs_to_add, struct btrfs_delayed_extent_op *extent_op) { - struct btrfs_fs_info *fs_info = trans->fs_info; struct btrfs_path *path; struct extent_buffer *leaf; struct btrfs_extent_item *item; @@ -2252,10 +2250,9 @@ static int __btrfs_inc_extent_ref(struct btrfs_trans_handle *trans, path->reada = READA_FORWARD; path->leave_spinning = 1; /* this will setup the path even if it fails to insert the back ref */ - ret = insert_inline_extent_backref(trans, fs_info, path, bytenr, - num_bytes, parent, root_objectid, - owner, offset, - refs_to_add, extent_op); + ret = insert_inline_extent_backref(trans, path, bytenr, num_bytes, + parent, root_objectid, owner, + offset, refs_to_add, extent_op); if ((ret < 0 && ret != -EAGAIN) || !ret) goto out; -- cgit v1.2.3 From 5fac7f9ee142a3f498137669931265bc7207135d Mon Sep 17 00:00:00 2001 From: Nikolay Borisov Date: Wed, 20 Jun 2018 15:49:11 +0300 Subject: btrfs: Remove fs_info from run_one_delayed_ref It can be referenced from the passed transaction handle, since it's always valid. Signed-off-by: Nikolay Borisov Reviewed-by: Qu Wenruo Signed-off-by: David Sterba --- fs/btrfs/extent-tree.c | 5 ++--- 1 file changed, 2 insertions(+), 3 deletions(-) (limited to 'fs') diff --git a/fs/btrfs/extent-tree.c b/fs/btrfs/extent-tree.c index 283a3e967184..781e8529e9a3 100644 --- a/fs/btrfs/extent-tree.c +++ b/fs/btrfs/extent-tree.c @@ -2479,7 +2479,6 @@ static int run_delayed_tree_ref(struct btrfs_trans_handle *trans, /* helper function to actually process a single delayed ref entry */ static int run_one_delayed_ref(struct btrfs_trans_handle *trans, - struct btrfs_fs_info *fs_info, struct btrfs_delayed_ref_node *node, struct btrfs_delayed_extent_op *extent_op, int insert_reserved) @@ -2488,7 +2487,7 @@ static int run_one_delayed_ref(struct btrfs_trans_handle *trans, if (trans->aborted) { if (insert_reserved) - btrfs_pin_extent(fs_info, node->bytenr, + btrfs_pin_extent(trans->fs_info, node->bytenr, node->num_bytes, 1); return 0; } @@ -2765,7 +2764,7 @@ static noinline int __btrfs_run_delayed_refs(struct btrfs_trans_handle *trans, locked_ref->extent_op = NULL; spin_unlock(&locked_ref->lock); - ret = run_one_delayed_ref(trans, fs_info, ref, extent_op, + ret = run_one_delayed_ref(trans, ref, extent_op, must_insert_reserved); btrfs_free_delayed_extent_op(extent_op); -- cgit v1.2.3 From 87cc7a8a2afbe806bb18ef440277c4f2e58224fa Mon Sep 17 00:00:00 2001 From: Nikolay Borisov Date: Wed, 20 Jun 2018 15:49:12 +0300 Subject: btrfs: Remove fs_info from remove_extent_backref It can be referenced directly from the transaction handle since it's always valid. Signed-off-by: Nikolay Borisov Reviewed-by: Qu Wenruo Signed-off-by: David Sterba --- fs/btrfs/extent-tree.c | 11 +++++------ 1 file changed, 5 insertions(+), 6 deletions(-) (limited to 'fs') diff --git a/fs/btrfs/extent-tree.c b/fs/btrfs/extent-tree.c index 781e8529e9a3..004c4e0fce36 100644 --- a/fs/btrfs/extent-tree.c +++ b/fs/btrfs/extent-tree.c @@ -1998,7 +1998,6 @@ static int insert_extent_backref(struct btrfs_trans_handle *trans, } static int remove_extent_backref(struct btrfs_trans_handle *trans, - struct btrfs_fs_info *fs_info, struct btrfs_path *path, struct btrfs_extent_inline_ref *iref, int refs_to_drop, int is_data, int *last_ref) @@ -2014,7 +2013,7 @@ static int remove_extent_backref(struct btrfs_trans_handle *trans, last_ref); } else { *last_ref = 1; - ret = btrfs_del_item(trans, fs_info->extent_root, path); + ret = btrfs_del_item(trans, trans->fs_info->extent_root, path); } return ret; } @@ -6896,7 +6895,7 @@ static int __btrfs_free_extent(struct btrfs_trans_handle *trans, #endif if (!found_extent) { BUG_ON(iref); - ret = remove_extent_backref(trans, info, path, NULL, + ret = remove_extent_backref(trans, path, NULL, refs_to_drop, is_data, &last_ref); if (ret) { @@ -7040,9 +7039,9 @@ static int __btrfs_free_extent(struct btrfs_trans_handle *trans, btrfs_mark_buffer_dirty(leaf); } if (found_extent) { - ret = remove_extent_backref(trans, info, path, - iref, refs_to_drop, - is_data, &last_ref); + ret = remove_extent_backref(trans, path, iref, + refs_to_drop, is_data, + &last_ref); if (ret) { btrfs_abort_transaction(trans, ret); goto out; -- cgit v1.2.3 From 61da2abfcad9c7e1a9c2f74ae7af8637d9fba36e Mon Sep 17 00:00:00 2001 From: Nikolay Borisov Date: Wed, 20 Jun 2018 15:49:13 +0300 Subject: btrfs: Remove fs_info from btrfs_alloc_logged_file_extent It can be referenced from trans since the function is always called within a valid transaction. Signed-off-by: Nikolay Borisov Reviewed-by: Qu Wenruo Signed-off-by: David Sterba --- fs/btrfs/ctree.h | 1 - fs/btrfs/extent-tree.c | 2 +- fs/btrfs/tree-log.c | 1 - 3 files changed, 1 insertion(+), 3 deletions(-) (limited to 'fs') diff --git a/fs/btrfs/ctree.h b/fs/btrfs/ctree.h index db97e34aa113..bc4bb275e339 100644 --- a/fs/btrfs/ctree.h +++ b/fs/btrfs/ctree.h @@ -2676,7 +2676,6 @@ int btrfs_alloc_reserved_file_extent(struct btrfs_trans_handle *trans, u64 offset, u64 ram_bytes, struct btrfs_key *ins); int btrfs_alloc_logged_file_extent(struct btrfs_trans_handle *trans, - struct btrfs_fs_info *fs_info, u64 root_objectid, u64 owner, u64 offset, struct btrfs_key *ins); int btrfs_reserve_extent(struct btrfs_root *root, u64 ram_bytes, u64 num_bytes, diff --git a/fs/btrfs/extent-tree.c b/fs/btrfs/extent-tree.c index 004c4e0fce36..c27215dc8b84 100644 --- a/fs/btrfs/extent-tree.c +++ b/fs/btrfs/extent-tree.c @@ -8263,10 +8263,10 @@ int btrfs_alloc_reserved_file_extent(struct btrfs_trans_handle *trans, * space cache bits as well */ int btrfs_alloc_logged_file_extent(struct btrfs_trans_handle *trans, - struct btrfs_fs_info *fs_info, u64 root_objectid, u64 owner, u64 offset, struct btrfs_key *ins) { + struct btrfs_fs_info *fs_info = trans->fs_info; int ret; struct btrfs_block_group_cache *block_group; struct btrfs_space_info *space_info; diff --git a/fs/btrfs/tree-log.c b/fs/btrfs/tree-log.c index 7f6aaeb4bd22..b3b1d424f2d8 100644 --- a/fs/btrfs/tree-log.c +++ b/fs/btrfs/tree-log.c @@ -715,7 +715,6 @@ static noinline int replay_one_extent(struct btrfs_trans_handle *trans, * allocation tree */ ret = btrfs_alloc_logged_file_extent(trans, - fs_info, root->root_key.objectid, key->objectid, offset, &ins); if (ret) -- cgit v1.2.3 From c83488afc5a772e424d8f159236bcf805b3c249c Mon Sep 17 00:00:00 2001 From: Nikolay Borisov Date: Wed, 20 Jun 2018 15:49:14 +0300 Subject: btrfs: Remove fs_info from btrfs_inc_block_group_ro It can be referenced from the passed bg cache. Signed-off-by: Nikolay Borisov Reviewed-by: Qu Wenruo Signed-off-by: David Sterba --- fs/btrfs/ctree.h | 3 +-- fs/btrfs/extent-tree.c | 4 ++-- fs/btrfs/relocation.c | 2 +- fs/btrfs/scrub.c | 2 +- 4 files changed, 5 insertions(+), 6 deletions(-) (limited to 'fs') diff --git a/fs/btrfs/ctree.h b/fs/btrfs/ctree.h index bc4bb275e339..5bb083de8f2c 100644 --- a/fs/btrfs/ctree.h +++ b/fs/btrfs/ctree.h @@ -2801,8 +2801,7 @@ int btrfs_cond_migrate_bytes(struct btrfs_fs_info *fs_info, void btrfs_block_rsv_release(struct btrfs_fs_info *fs_info, struct btrfs_block_rsv *block_rsv, u64 num_bytes); -int btrfs_inc_block_group_ro(struct btrfs_fs_info *fs_info, - struct btrfs_block_group_cache *cache); +int btrfs_inc_block_group_ro(struct btrfs_block_group_cache *cache); void btrfs_dec_block_group_ro(struct btrfs_block_group_cache *cache); void btrfs_put_block_group_cache(struct btrfs_fs_info *info); u64 btrfs_account_ro_block_groups_free_space(struct btrfs_space_info *sinfo); diff --git a/fs/btrfs/extent-tree.c b/fs/btrfs/extent-tree.c index c27215dc8b84..5e15b0c319f5 100644 --- a/fs/btrfs/extent-tree.c +++ b/fs/btrfs/extent-tree.c @@ -9426,10 +9426,10 @@ out: return ret; } -int btrfs_inc_block_group_ro(struct btrfs_fs_info *fs_info, - struct btrfs_block_group_cache *cache) +int btrfs_inc_block_group_ro(struct btrfs_block_group_cache *cache) { + struct btrfs_fs_info *fs_info = cache->fs_info; struct btrfs_trans_handle *trans; u64 alloc_flags; int ret; diff --git a/fs/btrfs/relocation.c b/fs/btrfs/relocation.c index 879b76fa881a..ef1b5aad035e 100644 --- a/fs/btrfs/relocation.c +++ b/fs/btrfs/relocation.c @@ -4375,7 +4375,7 @@ int btrfs_relocate_block_group(struct btrfs_fs_info *fs_info, u64 group_start) rc->block_group = btrfs_lookup_block_group(fs_info, group_start); BUG_ON(!rc->block_group); - ret = btrfs_inc_block_group_ro(fs_info, rc->block_group); + ret = btrfs_inc_block_group_ro(rc->block_group); if (ret) { err = ret; goto out; diff --git a/fs/btrfs/scrub.c b/fs/btrfs/scrub.c index 5bce2330ec64..67bb003323e7 100644 --- a/fs/btrfs/scrub.c +++ b/fs/btrfs/scrub.c @@ -3832,7 +3832,7 @@ int scrub_enumerate_chunks(struct scrub_ctx *sctx, * -> btrfs_scrub_pause() */ scrub_pause_on(fs_info); - ret = btrfs_inc_block_group_ro(fs_info, cache); + ret = btrfs_inc_block_group_ro(cache); if (!ret && is_dev_replace) { /* * If we are doing a device replace wait for any tasks -- cgit v1.2.3 From 43a7e99db6788110fb2bd97bdad5aa5c0c004aff Mon Sep 17 00:00:00 2001 From: Nikolay Borisov Date: Wed, 20 Jun 2018 15:49:15 +0300 Subject: btrfs: Remove fs_info from btrfs_force_chunk_alloc It can be referenced from the passed transaction handle. Signed-off-by: Nikolay Borisov Reviewed-by: Qu Wenruo Signed-off-by: David Sterba --- fs/btrfs/ctree.h | 3 +-- fs/btrfs/extent-tree.c | 5 ++--- fs/btrfs/relocation.c | 3 +-- fs/btrfs/volumes.c | 2 +- 4 files changed, 5 insertions(+), 8 deletions(-) (limited to 'fs') diff --git a/fs/btrfs/ctree.h b/fs/btrfs/ctree.h index 5bb083de8f2c..12cb327cd16e 100644 --- a/fs/btrfs/ctree.h +++ b/fs/btrfs/ctree.h @@ -2809,8 +2809,7 @@ int btrfs_error_unpin_extent_range(struct btrfs_fs_info *fs_info, u64 start, u64 end); int btrfs_discard_extent(struct btrfs_fs_info *fs_info, u64 bytenr, u64 num_bytes, u64 *actual_bytes); -int btrfs_force_chunk_alloc(struct btrfs_trans_handle *trans, - struct btrfs_fs_info *fs_info, u64 type); +int btrfs_force_chunk_alloc(struct btrfs_trans_handle *trans, u64 type); int btrfs_trim_fs(struct btrfs_fs_info *fs_info, struct fstrim_range *range); int btrfs_init_space_info(struct btrfs_fs_info *fs_info); diff --git a/fs/btrfs/extent-tree.c b/fs/btrfs/extent-tree.c index 5e15b0c319f5..472872a6cc27 100644 --- a/fs/btrfs/extent-tree.c +++ b/fs/btrfs/extent-tree.c @@ -9497,10 +9497,9 @@ out: return ret; } -int btrfs_force_chunk_alloc(struct btrfs_trans_handle *trans, - struct btrfs_fs_info *fs_info, u64 type) +int btrfs_force_chunk_alloc(struct btrfs_trans_handle *trans, u64 type) { - u64 alloc_flags = get_alloc_profile(fs_info, type); + u64 alloc_flags = get_alloc_profile(trans->fs_info, type); return do_chunk_alloc(trans, alloc_flags, CHUNK_ALLOC_FORCE); } diff --git a/fs/btrfs/relocation.c b/fs/btrfs/relocation.c index ef1b5aad035e..22214033a4a2 100644 --- a/fs/btrfs/relocation.c +++ b/fs/btrfs/relocation.c @@ -4169,8 +4169,7 @@ restart: } } if (trans && progress && err == -ENOSPC) { - ret = btrfs_force_chunk_alloc(trans, fs_info, - rc->block_group->flags); + ret = btrfs_force_chunk_alloc(trans, rc->block_group->flags); if (ret == 1) { err = 0; progress = 0; diff --git a/fs/btrfs/volumes.c b/fs/btrfs/volumes.c index 9795d5079907..fe497937933f 100644 --- a/fs/btrfs/volumes.c +++ b/fs/btrfs/volumes.c @@ -3059,7 +3059,7 @@ static int btrfs_may_alloc_data_chunk(struct btrfs_fs_info *fs_info, if (IS_ERR(trans)) return PTR_ERR(trans); - ret = btrfs_force_chunk_alloc(trans, fs_info, + ret = btrfs_force_chunk_alloc(trans, BTRFS_BLOCK_GROUP_DATA); btrfs_end_transaction(trans); if (ret < 0) -- cgit v1.2.3 From 9912bbf6440ba0555e91d3306520da01872c7c1d Mon Sep 17 00:00:00 2001 From: Qu Wenruo Date: Wed, 20 Jun 2018 15:38:58 +0800 Subject: btrfs: check-integrity: Fix NULL pointer dereference for degraded mount Commit f8f84b2dfda5 ("btrfs: index check-integrity state hash by a dev_t") changed how btrfsic indexes device state. Now we need to access device->bdev->bd_dev, while for degraded mount it's completely possible to have device->bdev as NULL, thus it will trigger a NULL pointer dereference at mount time. Fix it by checking if the device is degraded before accessing device->bdev->bd_dev. There are a lot of other places accessing device->bdev->bd_dev, however the other call sites have either checked device->bdev, or the device->bdev is passed from btrfsic_map_block(), so it won't cause harm. Fixes: f8f84b2dfda5 ("btrfs: index check-integrity state hash by a dev_t") Signed-off-by: Qu Wenruo Reviewed-by: David Sterba Signed-off-by: David Sterba --- fs/btrfs/check-integrity.c | 7 ++++++- 1 file changed, 6 insertions(+), 1 deletion(-) (limited to 'fs') diff --git a/fs/btrfs/check-integrity.c b/fs/btrfs/check-integrity.c index a3fdb4fe967d..daf45472bef9 100644 --- a/fs/btrfs/check-integrity.c +++ b/fs/btrfs/check-integrity.c @@ -1539,7 +1539,12 @@ static int btrfsic_map_block(struct btrfsic_state *state, u64 bytenr, u32 len, } device = multi->stripes[0].dev; - block_ctx_out->dev = btrfsic_dev_state_lookup(device->bdev->bd_dev); + if (test_bit(BTRFS_DEV_STATE_MISSING, &device->dev_state) || + !device->bdev || !device->name) + block_ctx_out->dev = NULL; + else + block_ctx_out->dev = btrfsic_dev_state_lookup( + device->bdev->bd_dev); block_ctx_out->dev_bytenr = multi->stripes[0].physical; block_ctx_out->start = bytenr; block_ctx_out->len = len; -- cgit v1.2.3 From bc877d285ca3dba24c52406946a4a69847cc7422 Mon Sep 17 00:00:00 2001 From: Nikolay Borisov Date: Mon, 18 Jun 2018 14:13:19 +0300 Subject: btrfs: Deduplicate extent_buffer init code When a new extent buffer is allocated there are a few mandatory fields which need to be set in order for the buffer to be sane: level, generation, bytenr, backref_rev, owner and FSID/UUID. Currently this is open coded in the callers of btrfs_alloc_tree_block, meaning it's fairly high in the abstraction hierarchy of operations. This patch solves this by simply moving this init code in btrfs_init_new_buffer, since this is the function which initializes a newly allocated extent buffer. No functional changes. Signed-off-by: Nikolay Borisov Reviewed-by: David Sterba Signed-off-by: David Sterba --- fs/btrfs/ctree.c | 29 +---------------------------- fs/btrfs/disk-io.c | 14 -------------- fs/btrfs/extent-tree.c | 16 ++++++++++++---- fs/btrfs/ioctl.c | 8 -------- 4 files changed, 13 insertions(+), 54 deletions(-) (limited to 'fs') diff --git a/fs/btrfs/ctree.c b/fs/btrfs/ctree.c index 18fd80e2f278..18f1ca1c5bd9 100644 --- a/fs/btrfs/ctree.c +++ b/fs/btrfs/ctree.c @@ -3358,17 +3358,7 @@ static noinline int insert_new_root(struct btrfs_trans_handle *trans, root_add_used(root, fs_info->nodesize); - memzero_extent_buffer(c, 0, sizeof(struct btrfs_header)); btrfs_set_header_nritems(c, 1); - btrfs_set_header_level(c, level); - btrfs_set_header_bytenr(c, c->start); - btrfs_set_header_generation(c, trans->transid); - btrfs_set_header_backref_rev(c, BTRFS_MIXED_BACKREF_REV); - btrfs_set_header_owner(c, root->root_key.objectid); - - write_extent_buffer_fsid(c, fs_info->fsid); - write_extent_buffer_chunk_tree_uuid(c, fs_info->chunk_tree_uuid); - btrfs_set_node_key(c, &lower_key, 0); btrfs_set_node_blockptr(c, 0, lower->start); lower_gen = btrfs_header_generation(lower); @@ -3497,15 +3487,7 @@ static noinline int split_node(struct btrfs_trans_handle *trans, return PTR_ERR(split); root_add_used(root, fs_info->nodesize); - - memzero_extent_buffer(split, 0, sizeof(struct btrfs_header)); - btrfs_set_header_level(split, btrfs_header_level(c)); - btrfs_set_header_bytenr(split, split->start); - btrfs_set_header_generation(split, trans->transid); - btrfs_set_header_backref_rev(split, BTRFS_MIXED_BACKREF_REV); - btrfs_set_header_owner(split, root->root_key.objectid); - write_extent_buffer_fsid(split, fs_info->fsid); - write_extent_buffer_chunk_tree_uuid(split, fs_info->chunk_tree_uuid); + ASSERT(btrfs_header_level(c) == level); ret = tree_mod_log_eb_copy(fs_info, split, c, 0, mid, c_nritems - mid); if (ret) { @@ -4291,15 +4273,6 @@ again: root_add_used(root, fs_info->nodesize); - memzero_extent_buffer(right, 0, sizeof(struct btrfs_header)); - btrfs_set_header_bytenr(right, right->start); - btrfs_set_header_generation(right, trans->transid); - btrfs_set_header_backref_rev(right, BTRFS_MIXED_BACKREF_REV); - btrfs_set_header_owner(right, root->root_key.objectid); - btrfs_set_header_level(right, 0); - write_extent_buffer_fsid(right, fs_info->fsid); - write_extent_buffer_chunk_tree_uuid(right, fs_info->chunk_tree_uuid); - if (split == 0) { if (mid <= slot) { btrfs_set_header_nritems(right, 0); diff --git a/fs/btrfs/disk-io.c b/fs/btrfs/disk-io.c index f3224e23d5fa..6318ac2539d3 100644 --- a/fs/btrfs/disk-io.c +++ b/fs/btrfs/disk-io.c @@ -1292,15 +1292,7 @@ struct btrfs_root *btrfs_create_tree(struct btrfs_trans_handle *trans, goto fail; } - memzero_extent_buffer(leaf, 0, sizeof(struct btrfs_header)); - btrfs_set_header_bytenr(leaf, leaf->start); - btrfs_set_header_generation(leaf, trans->transid); - btrfs_set_header_backref_rev(leaf, BTRFS_MIXED_BACKREF_REV); - btrfs_set_header_owner(leaf, objectid); root->node = leaf; - - write_extent_buffer_fsid(leaf, fs_info->fsid); - write_extent_buffer_chunk_tree_uuid(leaf, fs_info->chunk_tree_uuid); btrfs_mark_buffer_dirty(leaf); root->commit_root = btrfs_root_node(root); @@ -1374,14 +1366,8 @@ static struct btrfs_root *alloc_log_tree(struct btrfs_trans_handle *trans, return ERR_CAST(leaf); } - memzero_extent_buffer(leaf, 0, sizeof(struct btrfs_header)); - btrfs_set_header_bytenr(leaf, leaf->start); - btrfs_set_header_generation(leaf, trans->transid); - btrfs_set_header_backref_rev(leaf, BTRFS_MIXED_BACKREF_REV); - btrfs_set_header_owner(leaf, BTRFS_TREE_LOG_OBJECTID); root->node = leaf; - write_extent_buffer_fsid(root->node, fs_info->fsid); btrfs_mark_buffer_dirty(root->node); btrfs_tree_unlock(root->node); return root; diff --git a/fs/btrfs/extent-tree.c b/fs/btrfs/extent-tree.c index 472872a6cc27..0ca3999356c7 100644 --- a/fs/btrfs/extent-tree.c +++ b/fs/btrfs/extent-tree.c @@ -8302,7 +8302,7 @@ int btrfs_alloc_logged_file_extent(struct btrfs_trans_handle *trans, static struct extent_buffer * btrfs_init_new_buffer(struct btrfs_trans_handle *trans, struct btrfs_root *root, - u64 bytenr, int level) + u64 bytenr, int level, u64 owner) { struct btrfs_fs_info *fs_info = root->fs_info; struct extent_buffer *buf; @@ -8311,7 +8311,6 @@ btrfs_init_new_buffer(struct btrfs_trans_handle *trans, struct btrfs_root *root, if (IS_ERR(buf)) return buf; - btrfs_set_header_generation(buf, trans->transid); btrfs_set_buffer_lockdep_class(root->root_key.objectid, buf, level); btrfs_tree_lock(buf); clean_tree_block(fs_info, buf); @@ -8320,6 +8319,14 @@ btrfs_init_new_buffer(struct btrfs_trans_handle *trans, struct btrfs_root *root, btrfs_set_lock_blocking(buf); set_extent_buffer_uptodate(buf); + memzero_extent_buffer(buf, 0, sizeof(struct btrfs_header)); + btrfs_set_header_level(buf, level); + btrfs_set_header_bytenr(buf, buf->start); + btrfs_set_header_generation(buf, trans->transid); + btrfs_set_header_backref_rev(buf, BTRFS_MIXED_BACKREF_REV); + btrfs_set_header_owner(buf, owner); + write_extent_buffer_fsid(buf, fs_info->fsid); + write_extent_buffer_chunk_tree_uuid(buf, fs_info->chunk_tree_uuid); if (root->root_key.objectid == BTRFS_TREE_LOG_OBJECTID) { buf->log_index = root->log_transid % 2; /* @@ -8428,7 +8435,7 @@ struct extent_buffer *btrfs_alloc_tree_block(struct btrfs_trans_handle *trans, #ifdef CONFIG_BTRFS_FS_RUN_SANITY_TESTS if (btrfs_is_testing(fs_info)) { buf = btrfs_init_new_buffer(trans, root, root->alloc_bytenr, - level); + level, root_objectid); if (!IS_ERR(buf)) root->alloc_bytenr += blocksize; return buf; @@ -8444,7 +8451,8 @@ struct extent_buffer *btrfs_alloc_tree_block(struct btrfs_trans_handle *trans, if (ret) goto out_unuse; - buf = btrfs_init_new_buffer(trans, root, ins.objectid, level); + buf = btrfs_init_new_buffer(trans, root, ins.objectid, level, + root_objectid); if (IS_ERR(buf)) { ret = PTR_ERR(buf); goto out_free_reserved; diff --git a/fs/btrfs/ioctl.c b/fs/btrfs/ioctl.c index 0c4b9f364e84..08b8c0b346b3 100644 --- a/fs/btrfs/ioctl.c +++ b/fs/btrfs/ioctl.c @@ -616,14 +616,6 @@ static noinline int create_subvol(struct inode *dir, goto fail; } - memzero_extent_buffer(leaf, 0, sizeof(struct btrfs_header)); - btrfs_set_header_bytenr(leaf, leaf->start); - btrfs_set_header_generation(leaf, trans->transid); - btrfs_set_header_backref_rev(leaf, BTRFS_MIXED_BACKREF_REV); - btrfs_set_header_owner(leaf, objectid); - - write_extent_buffer_fsid(leaf, fs_info->fsid); - write_extent_buffer_chunk_tree_uuid(leaf, fs_info->chunk_tree_uuid); btrfs_mark_buffer_dirty(leaf); inode_item = &root_item->inode; -- cgit v1.2.3 From e41ca5897489b1c18af75ff0cc8f5c80260b3281 Mon Sep 17 00:00:00 2001 From: Qu Wenruo Date: Wed, 6 Jun 2018 15:41:49 +0800 Subject: btrfs: Get rid of the confusing btrfs_file_extent_inline_len We used to call btrfs_file_extent_inline_len() to get the uncompressed data size of an inlined extent. However this function is hiding evil, for compressed extent, it has no choice but to directly read out ram_bytes from btrfs_file_extent_item. While for uncompressed extent, it uses item size to calculate the real data size, and ignoring ram_bytes completely. In fact, for corrupted ram_bytes, due to above behavior kernel btrfs_print_leaf() can't even print correct ram_bytes to expose the bug. Since we have the tree-checker to verify all EXTENT_DATA, such mismatch can be detected pretty easily, thus we can trust ram_bytes without the evil btrfs_file_extent_inline_len(). Signed-off-by: Qu Wenruo Reviewed-by: David Sterba Signed-off-by: David Sterba --- fs/btrfs/ctree.h | 26 -------------------------- fs/btrfs/file-item.c | 2 +- fs/btrfs/file.c | 3 +-- fs/btrfs/inode.c | 12 ++++++------ fs/btrfs/print-tree.c | 4 ++-- fs/btrfs/send.c | 17 +++++++---------- fs/btrfs/tree-log.c | 12 ++++-------- 7 files changed, 21 insertions(+), 55 deletions(-) (limited to 'fs') diff --git a/fs/btrfs/ctree.h b/fs/btrfs/ctree.h index 12cb327cd16e..41ba770b9db9 100644 --- a/fs/btrfs/ctree.h +++ b/fs/btrfs/ctree.h @@ -2428,32 +2428,6 @@ static inline u32 btrfs_file_extent_inline_item_len( return btrfs_item_size(eb, e) - BTRFS_FILE_EXTENT_INLINE_DATA_START; } -/* this returns the number of file bytes represented by the inline item. - * If an item is compressed, this is the uncompressed size - */ -static inline u32 btrfs_file_extent_inline_len(const struct extent_buffer *eb, - int slot, - const struct btrfs_file_extent_item *fi) -{ - struct btrfs_map_token token; - - btrfs_init_map_token(&token); - /* - * return the space used on disk if this item isn't - * compressed or encoded - */ - if (btrfs_token_file_extent_compression(eb, fi, &token) == 0 && - btrfs_token_file_extent_encryption(eb, fi, &token) == 0 && - btrfs_token_file_extent_other_encoding(eb, fi, &token) == 0) { - return btrfs_file_extent_inline_item_len(eb, - btrfs_item_nr(slot)); - } - - /* otherwise use the ram bytes field */ - return btrfs_token_file_extent_ram_bytes(eb, fi, &token); -} - - /* btrfs_dev_stats_item */ static inline u64 btrfs_dev_stats_value(const struct extent_buffer *eb, const struct btrfs_dev_stats_item *ptr, diff --git a/fs/btrfs/file-item.c b/fs/btrfs/file-item.c index f9dd6d1836a3..8c3cd7072caf 100644 --- a/fs/btrfs/file-item.c +++ b/fs/btrfs/file-item.c @@ -942,7 +942,7 @@ void btrfs_extent_item_to_extent_map(struct btrfs_inode *inode, btrfs_file_extent_num_bytes(leaf, fi); } else if (type == BTRFS_FILE_EXTENT_INLINE) { size_t size; - size = btrfs_file_extent_inline_len(leaf, slot, fi); + size = btrfs_file_extent_ram_bytes(leaf, fi); extent_end = ALIGN(extent_start + size, fs_info->sectorsize); } diff --git a/fs/btrfs/file.c b/fs/btrfs/file.c index 975c590c50d8..4cd8af14f915 100644 --- a/fs/btrfs/file.c +++ b/fs/btrfs/file.c @@ -833,8 +833,7 @@ next_slot: btrfs_file_extent_num_bytes(leaf, fi); } else if (extent_type == BTRFS_FILE_EXTENT_INLINE) { extent_end = key.offset + - btrfs_file_extent_inline_len(leaf, - path->slots[0], fi); + btrfs_file_extent_ram_bytes(leaf, fi); } else { /* can't happen */ BUG(); diff --git a/fs/btrfs/inode.c b/fs/btrfs/inode.c index eba61bcb9bb3..1ade43c02b81 100644 --- a/fs/btrfs/inode.c +++ b/fs/btrfs/inode.c @@ -1443,8 +1443,7 @@ next_slot: nocow = 1; } else if (extent_type == BTRFS_FILE_EXTENT_INLINE) { extent_end = found_key.offset + - btrfs_file_extent_inline_len(leaf, - path->slots[0], fi); + btrfs_file_extent_ram_bytes(leaf, fi); extent_end = ALIGN(extent_end, fs_info->sectorsize); } else { @@ -4643,8 +4642,8 @@ search_again: BTRFS_I(inode), leaf, fi, found_key.offset); } else if (extent_type == BTRFS_FILE_EXTENT_INLINE) { - item_end += btrfs_file_extent_inline_len(leaf, - path->slots[0], fi); + item_end += btrfs_file_extent_ram_bytes(leaf, + fi); trace_btrfs_truncate_show_fi_inline( BTRFS_I(inode), leaf, fi, path->slots[0], @@ -6943,7 +6942,8 @@ struct extent_map *btrfs_get_extent(struct btrfs_inode *inode, extent_start); } else if (found_type == BTRFS_FILE_EXTENT_INLINE) { size_t size; - size = btrfs_file_extent_inline_len(leaf, path->slots[0], item); + + size = btrfs_file_extent_ram_bytes(leaf, item); extent_end = ALIGN(extent_start + size, fs_info->sectorsize); @@ -6994,7 +6994,7 @@ next: if (new_inline) goto out; - size = btrfs_file_extent_inline_len(leaf, path->slots[0], item); + size = btrfs_file_extent_ram_bytes(leaf, item); extent_offset = page_offset(page) + pg_offset - extent_start; copy_size = min_t(u64, PAGE_SIZE - pg_offset, size - extent_offset); diff --git a/fs/btrfs/print-tree.c b/fs/btrfs/print-tree.c index a4e11cf04671..59efcf2e0de8 100644 --- a/fs/btrfs/print-tree.c +++ b/fs/btrfs/print-tree.c @@ -267,8 +267,8 @@ void btrfs_print_leaf(struct extent_buffer *l) struct btrfs_file_extent_item); if (btrfs_file_extent_type(l, fi) == BTRFS_FILE_EXTENT_INLINE) { - pr_info("\t\tinline extent data size %u\n", - btrfs_file_extent_inline_len(l, i, fi)); + pr_info("\t\tinline extent data size %llu\n", + btrfs_file_extent_ram_bytes(l, fi)); break; } pr_info("\t\textent data disk bytenr %llu nr %llu\n", diff --git a/fs/btrfs/send.c b/fs/btrfs/send.c index c47f62b19226..6ff7a1315e52 100644 --- a/fs/btrfs/send.c +++ b/fs/btrfs/send.c @@ -1500,7 +1500,7 @@ static int read_symlink(struct btrfs_root *root, BUG_ON(compression); off = btrfs_file_extent_inline_start(ei); - len = btrfs_file_extent_inline_len(path->nodes[0], path->slots[0], ei); + len = btrfs_file_extent_ram_bytes(path->nodes[0], ei); ret = fs_path_add_from_extent_buffer(dest, path->nodes[0], off, len); @@ -5160,7 +5160,7 @@ static int clone_range(struct send_ctx *sctx, ei = btrfs_item_ptr(leaf, slot, struct btrfs_file_extent_item); type = btrfs_file_extent_type(leaf, ei); if (type == BTRFS_FILE_EXTENT_INLINE) { - ext_len = btrfs_file_extent_inline_len(leaf, slot, ei); + ext_len = btrfs_file_extent_ram_bytes(leaf, ei); ext_len = PAGE_ALIGN(ext_len); } else { ext_len = btrfs_file_extent_num_bytes(leaf, ei); @@ -5236,8 +5236,7 @@ static int send_write_or_clone(struct send_ctx *sctx, struct btrfs_file_extent_item); type = btrfs_file_extent_type(path->nodes[0], ei); if (type == BTRFS_FILE_EXTENT_INLINE) { - len = btrfs_file_extent_inline_len(path->nodes[0], - path->slots[0], ei); + len = btrfs_file_extent_ram_bytes(path->nodes[0], ei); /* * it is possible the inline item won't cover the whole page, * but there may be items after this page. Make @@ -5375,7 +5374,7 @@ static int is_extent_unchanged(struct send_ctx *sctx, } if (right_type == BTRFS_FILE_EXTENT_INLINE) { - right_len = btrfs_file_extent_inline_len(eb, slot, ei); + right_len = btrfs_file_extent_ram_bytes(eb, ei); right_len = PAGE_ALIGN(right_len); } else { right_len = btrfs_file_extent_num_bytes(eb, ei); @@ -5496,8 +5495,7 @@ static int get_last_extent(struct send_ctx *sctx, u64 offset) struct btrfs_file_extent_item); type = btrfs_file_extent_type(path->nodes[0], fi); if (type == BTRFS_FILE_EXTENT_INLINE) { - u64 size = btrfs_file_extent_inline_len(path->nodes[0], - path->slots[0], fi); + u64 size = btrfs_file_extent_ram_bytes(path->nodes[0], fi); extent_end = ALIGN(key.offset + size, sctx->send_root->fs_info->sectorsize); } else { @@ -5560,7 +5558,7 @@ static int range_is_hole_in_parent(struct send_ctx *sctx, 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); + u64 size = btrfs_file_extent_ram_bytes(leaf, fi); extent_end = ALIGN(key.offset + size, root->fs_info->sectorsize); @@ -5606,8 +5604,7 @@ static int maybe_send_hole(struct send_ctx *sctx, struct btrfs_path *path, struct btrfs_file_extent_item); type = btrfs_file_extent_type(path->nodes[0], fi); if (type == BTRFS_FILE_EXTENT_INLINE) { - u64 size = btrfs_file_extent_inline_len(path->nodes[0], - path->slots[0], fi); + u64 size = btrfs_file_extent_ram_bytes(path->nodes[0], fi); extent_end = ALIGN(key->offset + size, sctx->send_root->fs_info->sectorsize); } else { diff --git a/fs/btrfs/tree-log.c b/fs/btrfs/tree-log.c index b3b1d424f2d8..6bca8f88ade0 100644 --- a/fs/btrfs/tree-log.c +++ b/fs/btrfs/tree-log.c @@ -597,7 +597,7 @@ static noinline int replay_one_extent(struct btrfs_trans_handle *trans, if (btrfs_file_extent_disk_bytenr(eb, item) == 0) nbytes = 0; } else if (found_type == BTRFS_FILE_EXTENT_INLINE) { - size = btrfs_file_extent_inline_len(eb, slot, item); + size = btrfs_file_extent_ram_bytes(eb, item); nbytes = btrfs_file_extent_ram_bytes(eb, item); extent_end = ALIGN(start + size, fs_info->sectorsize); @@ -3920,9 +3920,7 @@ static noinline int copy_items(struct btrfs_trans_handle *trans, struct btrfs_file_extent_item); if (btrfs_file_extent_type(src, extent) == BTRFS_FILE_EXTENT_INLINE) { - len = btrfs_file_extent_inline_len(src, - src_path->slots[0], - extent); + len = btrfs_file_extent_ram_bytes(src, extent); *last_extent = ALIGN(key.offset + len, fs_info->sectorsize); } else { @@ -3987,7 +3985,7 @@ fill_holes: extent = btrfs_item_ptr(src, i, struct btrfs_file_extent_item); if (btrfs_file_extent_type(src, extent) == BTRFS_FILE_EXTENT_INLINE) { - len = btrfs_file_extent_inline_len(src, i, extent); + len = btrfs_file_extent_ram_bytes(src, extent); extent_end = ALIGN(key.offset + len, fs_info->sectorsize); } else { @@ -4572,9 +4570,7 @@ static int btrfs_log_trailing_hole(struct btrfs_trans_handle *trans, if (btrfs_file_extent_type(leaf, extent) == BTRFS_FILE_EXTENT_INLINE) { - len = btrfs_file_extent_inline_len(leaf, - path->slots[0], - extent); + len = btrfs_file_extent_ram_bytes(leaf, extent); ASSERT(len == i_size || (len == fs_info->sectorsize && btrfs_file_extent_compression(leaf, extent) != -- cgit v1.2.3 From afd48513f0019a2048afed0d98904d3fec7e05dd Mon Sep 17 00:00:00 2001 From: Arnd Bergmann Date: Thu, 21 Jun 2018 18:04:05 +0200 Subject: btrfs: use monotonic time for transaction handling The transaction times were changed to ktime_get_real_seconds to avoid the y2038 overflow, but they still have a minor problem when they go backwards or jump due to settimeofday() or leap seconds. This changes the transaction handling to instead use ktime_get_seconds(), which returns a CLOCK_MONOTONIC timestamp that has neither of those problems. Signed-off-by: Arnd Bergmann Reviewed-by: Nikolay Borisov Reviewed-by: David Sterba Signed-off-by: David Sterba --- fs/btrfs/disk-io.c | 2 +- fs/btrfs/transaction.c | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) (limited to 'fs') diff --git a/fs/btrfs/disk-io.c b/fs/btrfs/disk-io.c index 6318ac2539d3..2de3da7b7bdc 100644 --- a/fs/btrfs/disk-io.c +++ b/fs/btrfs/disk-io.c @@ -1805,7 +1805,7 @@ static int transaction_kthread(void *arg) goto sleep; } - now = ktime_get_real_seconds(); + now = ktime_get_seconds(); if (cur->state < TRANS_STATE_BLOCKED && !test_bit(BTRFS_FS_NEED_ASYNC_COMMIT, &fs_info->flags) && (now < cur->start_time || diff --git a/fs/btrfs/transaction.c b/fs/btrfs/transaction.c index 56c8bab0b816..ebe50dfb8947 100644 --- a/fs/btrfs/transaction.c +++ b/fs/btrfs/transaction.c @@ -241,7 +241,7 @@ loop: refcount_set(&cur_trans->use_count, 2); atomic_set(&cur_trans->pending_ordered, 0); cur_trans->flags = 0; - cur_trans->start_time = ktime_get_real_seconds(); + cur_trans->start_time = ktime_get_seconds(); memset(&cur_trans->delayed_refs, 0, sizeof(cur_trans->delayed_refs)); -- cgit v1.2.3 From d3c6be6fdab48dd26af3d3e01c5972ffe20985b9 Mon Sep 17 00:00:00 2001 From: Arnd Bergmann Date: Thu, 21 Jun 2018 18:04:06 +0200 Subject: btrfs: use timespec64 for i_otime While the regular inode timestamps all use timespec64 now, the i_otime field is btrfs specific and still needs to be converted to correctly represent times beyond 2038. Signed-off-by: Arnd Bergmann Reviewed-by: Nikolay Borisov Reviewed-by: David Sterba Signed-off-by: David Sterba --- fs/btrfs/btrfs_inode.h | 2 +- fs/btrfs/inode.c | 4 ++-- 2 files changed, 3 insertions(+), 3 deletions(-) (limited to 'fs') diff --git a/fs/btrfs/btrfs_inode.h b/fs/btrfs/btrfs_inode.h index 7e075343daa5..1343ac57b438 100644 --- a/fs/btrfs/btrfs_inode.h +++ b/fs/btrfs/btrfs_inode.h @@ -178,7 +178,7 @@ struct btrfs_inode { struct btrfs_delayed_node *delayed_node; /* File creation time. */ - struct timespec i_otime; + struct timespec64 i_otime; /* Hook into fs_info->delayed_iputs */ struct list_head delayed_iput; diff --git a/fs/btrfs/inode.c b/fs/btrfs/inode.c index 1ade43c02b81..2858bc355920 100644 --- a/fs/btrfs/inode.c +++ b/fs/btrfs/inode.c @@ -5744,7 +5744,7 @@ static struct inode *new_simple_dir(struct super_block *s, inode->i_mtime = current_time(inode); inode->i_atime = inode->i_mtime; inode->i_ctime = inode->i_mtime; - BTRFS_I(inode)->i_otime = timespec64_to_timespec(inode->i_mtime); + BTRFS_I(inode)->i_otime = inode->i_mtime; return inode; } @@ -6348,7 +6348,7 @@ static struct inode *btrfs_new_inode(struct btrfs_trans_handle *trans, inode->i_mtime = current_time(inode); inode->i_atime = inode->i_mtime; inode->i_ctime = inode->i_mtime; - BTRFS_I(inode)->i_otime = timespec64_to_timespec(inode->i_mtime); + BTRFS_I(inode)->i_otime = inode->i_mtime; inode_item = btrfs_item_ptr(path->nodes[0], path->slots[0], struct btrfs_inode_item); -- cgit v1.2.3 From bc931c0ef8f9e21ed5732ea148aeea9d0fffd3f8 Mon Sep 17 00:00:00 2001 From: Geert Uytterhoeven Date: Fri, 22 Jun 2018 09:18:29 +0200 Subject: btrfs: Refactor count handling in btrfs_unpin_free_ino MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit With gcc 4.1.2: fs/btrfs/inode-map.c: In function ‘btrfs_unpin_free_ino’: fs/btrfs/inode-map.c:241: warning: ‘count’ may be used uninitialized in this function While this warning is a false-positive, it can easily be killed by refactoring the code. Signed-off-by: Geert Uytterhoeven Reviewed-by: David Sterba Signed-off-by: David Sterba --- fs/btrfs/inode-map.c | 11 ++++------- 1 file changed, 4 insertions(+), 7 deletions(-) (limited to 'fs') diff --git a/fs/btrfs/inode-map.c b/fs/btrfs/inode-map.c index 12fcd8897c33..a56f88ea9c73 100644 --- a/fs/btrfs/inode-map.c +++ b/fs/btrfs/inode-map.c @@ -244,8 +244,6 @@ void btrfs_unpin_free_ino(struct btrfs_root *root) return; while (1) { - bool add_to_ctl = true; - spin_lock(rbroot_lock); n = rb_first(rbroot); if (!n) { @@ -257,15 +255,14 @@ void btrfs_unpin_free_ino(struct btrfs_root *root) BUG_ON(info->bitmap); /* Logic error */ if (info->offset > root->ino_cache_progress) - add_to_ctl = false; - else if (info->offset + info->bytes > root->ino_cache_progress) - count = root->ino_cache_progress - info->offset + 1; + count = 0; else - count = info->bytes; + count = min(root->ino_cache_progress - info->offset + 1, + info->bytes); rb_erase(&info->offset_index, rbroot); spin_unlock(rbroot_lock); - if (add_to_ctl) + if (count) __btrfs_add_free_space(root->fs_info, ctl, info->offset, count); kmem_cache_free(btrfs_free_space_cachep, info); -- cgit v1.2.3 From 43794446548730ac8461be30bbe47d5d027d1d16 Mon Sep 17 00:00:00 2001 From: Qu Wenruo Date: Fri, 22 Jun 2018 12:35:00 +0800 Subject: btrfs: Don't remove block group that still has pinned down bytes [BUG] Under certain KVM load and LTP tests, it is possible to hit the following calltrace if quota is enabled: BTRFS critical (device vda2): unable to find logical 8820195328 length 4096 BTRFS critical (device vda2): unable to find logical 8820195328 length 4096 WARNING: CPU: 0 PID: 49 at ../block/blk-core.c:172 blk_status_to_errno+0x1a/0x30 CPU: 0 PID: 49 Comm: kworker/u2:1 Not tainted 4.12.14-15-default #1 SLE15 (unreleased) Hardware name: QEMU Standard PC (i440FX + PIIX, 1996), BIOS 1.0.0-prebuilt.qemu-project.org 04/01/2014 Workqueue: btrfs-endio-write btrfs_endio_write_helper [btrfs] task: ffff9f827b340bc0 task.stack: ffffb4f8c0304000 RIP: 0010:blk_status_to_errno+0x1a/0x30 Call Trace: submit_extent_page+0x191/0x270 [btrfs] ? btrfs_create_repair_bio+0x130/0x130 [btrfs] __do_readpage+0x2d2/0x810 [btrfs] ? btrfs_create_repair_bio+0x130/0x130 [btrfs] ? run_one_async_done+0xc0/0xc0 [btrfs] __extent_read_full_page+0xe7/0x100 [btrfs] ? run_one_async_done+0xc0/0xc0 [btrfs] read_extent_buffer_pages+0x1ab/0x2d0 [btrfs] ? run_one_async_done+0xc0/0xc0 [btrfs] btree_read_extent_buffer_pages+0x94/0xf0 [btrfs] read_tree_block+0x31/0x60 [btrfs] read_block_for_search.isra.35+0xf0/0x2e0 [btrfs] btrfs_search_slot+0x46b/0xa00 [btrfs] ? kmem_cache_alloc+0x1a8/0x510 ? btrfs_get_token_32+0x5b/0x120 [btrfs] find_parent_nodes+0x11d/0xeb0 [btrfs] ? leaf_space_used+0xb8/0xd0 [btrfs] ? btrfs_leaf_free_space+0x49/0x90 [btrfs] ? btrfs_find_all_roots_safe+0x93/0x100 [btrfs] btrfs_find_all_roots_safe+0x93/0x100 [btrfs] btrfs_find_all_roots+0x45/0x60 [btrfs] btrfs_qgroup_trace_extent_post+0x20/0x40 [btrfs] btrfs_add_delayed_data_ref+0x1a3/0x1d0 [btrfs] btrfs_alloc_reserved_file_extent+0x38/0x40 [btrfs] insert_reserved_file_extent.constprop.71+0x289/0x2e0 [btrfs] btrfs_finish_ordered_io+0x2f4/0x7f0 [btrfs] ? pick_next_task_fair+0x2cd/0x530 ? __switch_to+0x92/0x4b0 btrfs_worker_helper+0x81/0x300 [btrfs] process_one_work+0x1da/0x3f0 worker_thread+0x2b/0x3f0 ? process_one_work+0x3f0/0x3f0 kthread+0x11a/0x130 ? kthread_create_on_node+0x40/0x40 ret_from_fork+0x35/0x40 BTRFS critical (device vda2): unable to find logical 8820195328 length 16384 BTRFS: error (device vda2) in btrfs_finish_ordered_io:3023: errno=-5 IO failure BTRFS info (device vda2): forced readonly BTRFS error (device vda2): pending csums is 2887680 [CAUSE] It's caused by race with block group auto removal: - There is a meta block group X, which has only one tree block The tree block belongs to fs tree 257. - In current transaction, some operation modified fs tree 257 The tree block gets COWed, so the block group X is empty, and marked as unused, queued to be deleted. - Some workload (like fsync) wakes up cleaner_kthread() Which will call btrfs_delete_unused_bgs() to remove unused block groups. So block group X along its chunk map get removed. - Some delalloc work finished for fs tree 257 Quota needs to get the original reference of the extent, which will read tree blocks of commit root of 257. Then since the chunk map gets removed, the above warning gets triggered. [FIX] Just let btrfs_delete_unused_bgs() skip block group which still has pinned bytes. However there is a minor side effect: currently we only queue empty blocks at update_block_group(), and such empty block group with pinned bytes won't go through update_block_group() again, such block group won't be removed, until it gets new extent allocated and removed. Signed-off-by: Qu Wenruo Reviewed-by: Filipe Manana Signed-off-by: David Sterba --- fs/btrfs/extent-tree.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) (limited to 'fs') diff --git a/fs/btrfs/extent-tree.c b/fs/btrfs/extent-tree.c index 0ca3999356c7..37d8927015d9 100644 --- a/fs/btrfs/extent-tree.c +++ b/fs/btrfs/extent-tree.c @@ -10702,7 +10702,7 @@ void btrfs_delete_unused_bgs(struct btrfs_fs_info *fs_info) /* Don't want to race with allocators so take the groups_sem */ down_write(&space_info->groups_sem); spin_lock(&block_group->lock); - if (block_group->reserved || + if (block_group->reserved || block_group->pinned || btrfs_block_group_used(&block_group->item) || block_group->ro || list_is_singular(&block_group->list)) { -- cgit v1.2.3 From 7b4284de93c51b1d78699bf06bccee892699aa4e Mon Sep 17 00:00:00 2001 From: Nikolay Borisov Date: Wed, 20 Jun 2018 18:43:12 +0300 Subject: btrfs: Streamline memory allocation failure handling in btrfs_add_delayed_tree_ref Currently the function uses 2 goto labels to properly handle allocation failures. This could be simplified by simply re-arranging the code so that allocations are the in the beginning of the function. This allows to use simple return statements. No functional changes. Signed-off-by: Nikolay Borisov Reviewed-by: Su Yue Signed-off-by: David Sterba --- fs/btrfs/delayed-ref.c | 35 +++++++++++++++++------------------ 1 file changed, 17 insertions(+), 18 deletions(-) (limited to 'fs') diff --git a/fs/btrfs/delayed-ref.c b/fs/btrfs/delayed-ref.c index 6eb00eb65d76..62ff545ba1f7 100644 --- a/fs/btrfs/delayed-ref.c +++ b/fs/btrfs/delayed-ref.c @@ -730,27 +730,33 @@ int btrfs_add_delayed_tree_ref(struct btrfs_trans_handle *trans, if (!ref) return -ENOMEM; + head_ref = kmem_cache_alloc(btrfs_delayed_ref_head_cachep, GFP_NOFS); + if (!head_ref) { + kmem_cache_free(btrfs_delayed_tree_ref_cachep, ref); + return -ENOMEM; + } + + if (test_bit(BTRFS_FS_QUOTA_ENABLED, &fs_info->flags) && + is_fstree(ref_root)) { + record = kmalloc(sizeof(*record), GFP_NOFS); + if (!record) { + kmem_cache_free(btrfs_delayed_tree_ref_cachep, ref); + kmem_cache_free(btrfs_delayed_ref_head_cachep, head_ref); + return -ENOMEM; + } + } + if (parent) ref_type = BTRFS_SHARED_BLOCK_REF_KEY; else ref_type = BTRFS_TREE_BLOCK_REF_KEY; + init_delayed_ref_common(fs_info, &ref->node, bytenr, num_bytes, ref_root, action, ref_type); ref->root = ref_root; ref->parent = parent; ref->level = level; - head_ref = kmem_cache_alloc(btrfs_delayed_ref_head_cachep, GFP_NOFS); - if (!head_ref) - goto free_ref; - - if (test_bit(BTRFS_FS_QUOTA_ENABLED, &fs_info->flags) && - is_fstree(ref_root)) { - record = kmalloc(sizeof(*record), GFP_NOFS); - if (!record) - goto free_head_ref; - } - init_delayed_ref_head(head_ref, record, bytenr, num_bytes, ref_root, 0, action, false, is_system); head_ref->extent_op = extent_op; @@ -779,13 +785,6 @@ int btrfs_add_delayed_tree_ref(struct btrfs_trans_handle *trans, btrfs_qgroup_trace_extent_post(fs_info, record); return 0; - -free_head_ref: - kmem_cache_free(btrfs_delayed_ref_head_cachep, head_ref); -free_ref: - kmem_cache_free(btrfs_delayed_tree_ref_cachep, ref); - - return -ENOMEM; } /* -- cgit v1.2.3 From 893bf4b115c713738df05bb557f8fba14f07c077 Mon Sep 17 00:00:00 2001 From: Su Yue Date: Fri, 22 Jun 2018 09:52:15 +0800 Subject: btrfs: print more details when checking tree block finds a problem For easier debugging, print eb->start if level is invalid. Also make clear if bytenr found is not expected. Signed-off-by: Su Yue Reviewed-by: David Sterba Signed-off-by: David Sterba --- fs/btrfs/disk-io.c | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) (limited to 'fs') diff --git a/fs/btrfs/disk-io.c b/fs/btrfs/disk-io.c index 2de3da7b7bdc..c77afa9e5d91 100644 --- a/fs/btrfs/disk-io.c +++ b/fs/btrfs/disk-io.c @@ -615,8 +615,8 @@ static int btree_readpage_end_io_hook(struct btrfs_io_bio *io_bio, found_start = btrfs_header_bytenr(eb); if (found_start != eb->start) { - btrfs_err_rl(fs_info, "bad tree block start %llu %llu", - found_start, eb->start); + btrfs_err_rl(fs_info, "bad tree block start, want %llu have %llu", + eb->start, found_start); ret = -EIO; goto err; } @@ -628,8 +628,8 @@ static int btree_readpage_end_io_hook(struct btrfs_io_bio *io_bio, } found_level = btrfs_header_level(eb); if (found_level >= BTRFS_MAX_LEVEL) { - btrfs_err(fs_info, "bad tree block level %d", - (int)btrfs_header_level(eb)); + btrfs_err(fs_info, "bad tree block level %d on %llu", + (int)btrfs_header_level(eb), eb->start); ret = -EIO; goto err; } -- cgit v1.2.3 From e4af400a9c5081e7d2b703e4c479cb9831cc1117 Mon Sep 17 00:00:00 2001 From: Goldwyn Rodrigues Date: Sun, 17 Jun 2018 12:39:47 -0500 Subject: btrfs: Use iocb to derive pos instead of passing a separate parameter struct kiocb carries the ki_pos, so there is no need to pass it as a separate function parameter. generic_file_direct_write() increments ki_pos, so we now assign pos after the function. Signed-off-by: Goldwyn Rodrigues Reviewed-by: Misono Tomohiro [ rename to btrfs_buffered_write ] Signed-off-by: David Sterba --- fs/btrfs/file.c | 15 ++++++++------- 1 file changed, 8 insertions(+), 7 deletions(-) (limited to 'fs') diff --git a/fs/btrfs/file.c b/fs/btrfs/file.c index 4cd8af14f915..89c9404fee9a 100644 --- a/fs/btrfs/file.c +++ b/fs/btrfs/file.c @@ -1568,10 +1568,11 @@ static noinline int check_can_nocow(struct btrfs_inode *inode, loff_t pos, return ret; } -static noinline ssize_t __btrfs_buffered_write(struct file *file, - struct iov_iter *i, - loff_t pos) +static noinline ssize_t btrfs_buffered_write(struct kiocb *iocb, + struct iov_iter *i) { + struct file *file = iocb->ki_filp; + loff_t pos = iocb->ki_pos; struct inode *inode = file_inode(file); struct btrfs_fs_info *fs_info = btrfs_sb(inode->i_sb); struct btrfs_root *root = BTRFS_I(inode)->root; @@ -1803,7 +1804,7 @@ static ssize_t __btrfs_direct_write(struct kiocb *iocb, struct iov_iter *from) { struct file *file = iocb->ki_filp; struct inode *inode = file_inode(file); - loff_t pos = iocb->ki_pos; + loff_t pos; ssize_t written; ssize_t written_buffered; loff_t endbyte; @@ -1814,8 +1815,8 @@ static ssize_t __btrfs_direct_write(struct kiocb *iocb, struct iov_iter *from) if (written < 0 || !iov_iter_count(from)) return written; - pos += written; - written_buffered = __btrfs_buffered_write(file, from, pos); + pos = iocb->ki_pos; + written_buffered = btrfs_buffered_write(iocb, from); if (written_buffered < 0) { err = written_buffered; goto out; @@ -1952,7 +1953,7 @@ static ssize_t btrfs_file_write_iter(struct kiocb *iocb, if (iocb->ki_flags & IOCB_DIRECT) { num_written = __btrfs_direct_write(iocb, from); } else { - num_written = __btrfs_buffered_write(file, from, pos); + num_written = btrfs_buffered_write(iocb, from); if (num_written > 0) iocb->ki_pos = pos + num_written; if (clean_page) -- cgit v1.2.3 From af431dcb249ffff20b16e08adaa4b624405a046b Mon Sep 17 00:00:00 2001 From: Su Yue Date: Fri, 22 Jun 2018 16:18:01 +0800 Subject: btrfs: return EUCLEAN if extent_inline_ref type is invalid If type of extent_inline_ref found is not expected, filesystem may have been corrupted, should return EUCLEAN instead of EINVAL. Signed-off-by: Su Yue Reviewed-by: David Sterba Signed-off-by: David Sterba --- fs/btrfs/backref.c | 4 ++-- fs/btrfs/extent-tree.c | 2 +- fs/btrfs/relocation.c | 4 ++-- 3 files changed, 5 insertions(+), 5 deletions(-) (limited to 'fs') diff --git a/fs/btrfs/backref.c b/fs/btrfs/backref.c index 0a8e2e29a66b..60f4afa8ecbc 100644 --- a/fs/btrfs/backref.c +++ b/fs/btrfs/backref.c @@ -925,7 +925,7 @@ static int add_inline_refs(const struct btrfs_fs_info *fs_info, type = btrfs_get_extent_inline_ref_type(leaf, iref, BTRFS_REF_TYPE_ANY); if (type == BTRFS_REF_TYPE_INVALID) - return -EINVAL; + return -EUCLEAN; offset = btrfs_extent_inline_ref_offset(leaf, iref); @@ -1793,7 +1793,7 @@ static int get_extent_inline_ref(unsigned long *ptr, *out_type = btrfs_get_extent_inline_ref_type(eb, *out_eiref, BTRFS_REF_TYPE_ANY); if (*out_type == BTRFS_REF_TYPE_INVALID) - return -EINVAL; + return -EUCLEAN; *ptr += btrfs_extent_inline_ref_size(*out_type); WARN_ON(*ptr > end); diff --git a/fs/btrfs/extent-tree.c b/fs/btrfs/extent-tree.c index 37d8927015d9..b28fa3d20ef7 100644 --- a/fs/btrfs/extent-tree.c +++ b/fs/btrfs/extent-tree.c @@ -1719,7 +1719,7 @@ again: iref = (struct btrfs_extent_inline_ref *)ptr; type = btrfs_get_extent_inline_ref_type(leaf, iref, needed); if (type == BTRFS_REF_TYPE_INVALID) { - err = -EINVAL; + err = -EUCLEAN; goto out; } diff --git a/fs/btrfs/relocation.c b/fs/btrfs/relocation.c index 22214033a4a2..44722e939e34 100644 --- a/fs/btrfs/relocation.c +++ b/fs/btrfs/relocation.c @@ -792,7 +792,7 @@ again: type = btrfs_get_extent_inline_ref_type(eb, iref, BTRFS_REF_TYPE_BLOCK); if (type == BTRFS_REF_TYPE_INVALID) { - err = -EINVAL; + err = -EUCLEAN; goto out; } key.type = type; @@ -3801,7 +3801,7 @@ int add_data_references(struct reloc_control *rc, ret = find_data_references(rc, extent_key, eb, dref, blocks); } else { - ret = -EINVAL; + ret = -EUCLEAN; btrfs_err(rc->extent_root->fs_info, "extent %llu slot %d has an invalid inline ref type", eb->start, path->slots[0]); -- cgit v1.2.3 From ab3629ed86ec43e7d95cf087d0b5a9d403fcd822 Mon Sep 17 00:00:00 2001 From: Chengguang Xu Date: Wed, 27 Jun 2018 12:16:34 +0800 Subject: btrfs: return error instead of crash when detecting unexpected type in btrfs_get_acl The caller of btrfs_get_acl() checks error condition so there is no impact from this change. In practice there is no chance to get into default case of switch statement because VFS has already checked the type. Signed-off-by: Chengguang Xu Reviewed-by: Nikolay Borisov Reviewed-by: David Sterba Signed-off-by: David Sterba --- fs/btrfs/acl.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) (limited to 'fs') diff --git a/fs/btrfs/acl.c b/fs/btrfs/acl.c index 15e1dfef56a5..60f83a3bd77c 100644 --- a/fs/btrfs/acl.c +++ b/fs/btrfs/acl.c @@ -30,7 +30,7 @@ struct posix_acl *btrfs_get_acl(struct inode *inode, int type) name = XATTR_NAME_POSIX_ACL_DEFAULT; break; default: - BUG(); + return ERR_PTR(-EINVAL); } size = btrfs_getxattr(inode, name, "", 0); -- cgit v1.2.3 From 7e35eab958e30d15743b1f9928d15b559a6e432d Mon Sep 17 00:00:00 2001 From: Chengguang Xu Date: Wed, 27 Jun 2018 12:16:35 +0800 Subject: btrfs: replace empty string with NULL when getting attribute length in btrfs_get_acl In btrfs_get_acl() the first call of btr_getxattr() is for getting the length of attribute, the value buffer is never used in this case. So it's better to replace empty string with NULL. Signed-off-by: Chengguang Xu Reviewed-by: Nikolay Borisov Reviewed-by: David Sterba Signed-off-by: David Sterba --- fs/btrfs/acl.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) (limited to 'fs') diff --git a/fs/btrfs/acl.c b/fs/btrfs/acl.c index 60f83a3bd77c..83fdd80c51c6 100644 --- a/fs/btrfs/acl.c +++ b/fs/btrfs/acl.c @@ -33,7 +33,7 @@ struct posix_acl *btrfs_get_acl(struct inode *inode, int type) return ERR_PTR(-EINVAL); } - size = btrfs_getxattr(inode, name, "", 0); + size = btrfs_getxattr(inode, name, NULL, 0); if (size > 0) { value = kzalloc(size, GFP_KERNEL); if (!value) -- cgit v1.2.3 From 5ee552da503961e6df785b8495bcfc98eb30eb2a Mon Sep 17 00:00:00 2001 From: Chengguang Xu Date: Wed, 27 Jun 2018 12:16:36 +0800 Subject: btrfs: remove unnecessary -ERANGE check in btrfs_get_acl There is no chance to get into -ERANGE error condition because we first call btrfs_getxattr to get the length of the attribute, then we do a subsequent call with the size from the first call. Between the 2 calls the size shouldn't change. So remove the unnecessary -ERANGE error check. Signed-off-by: Chengguang Xu Reviewed-by: Nikolay Borisov Reviewed-by: David Sterba Signed-off-by: David Sterba --- fs/btrfs/acl.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) (limited to 'fs') diff --git a/fs/btrfs/acl.c b/fs/btrfs/acl.c index 83fdd80c51c6..a1d7211c8884 100644 --- a/fs/btrfs/acl.c +++ b/fs/btrfs/acl.c @@ -42,7 +42,7 @@ struct posix_acl *btrfs_get_acl(struct inode *inode, int type) } if (size > 0) { acl = posix_acl_from_xattr(&init_user_ns, value, size); - } else if (size == -ERANGE || size == -ENODATA || size == 0) { + } else if (size == -ENODATA || size == 0) { acl = NULL; } else { acl = ERR_PTR(-EIO); -- cgit v1.2.3 From dc7789ef8785ea996ecf302a89415439ccf10faa Mon Sep 17 00:00:00 2001 From: Chengguang Xu Date: Wed, 27 Jun 2018 12:16:37 +0800 Subject: btrfs: avoid error code override in btrfs_get_acl It's not good to override the error code when failing from btrfs_getxattr() in btrfs_get_acl() because it hides the real reason of the failure. Signed-off-by: Chengguang Xu Reviewed-by: Nikolay Borisov Reviewed-by: David Sterba Signed-off-by: David Sterba --- fs/btrfs/acl.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) (limited to 'fs') diff --git a/fs/btrfs/acl.c b/fs/btrfs/acl.c index a1d7211c8884..7d673ec9e54a 100644 --- a/fs/btrfs/acl.c +++ b/fs/btrfs/acl.c @@ -45,7 +45,7 @@ struct posix_acl *btrfs_get_acl(struct inode *inode, int type) } else if (size == -ENODATA || size == 0) { acl = NULL; } else { - acl = ERR_PTR(-EIO); + acl = ERR_PTR(size); } kfree(value); -- cgit v1.2.3 From 4de426cd394e4de4d3039aff7d20724d7d988dcf Mon Sep 17 00:00:00 2001 From: Chengguang Xu Date: Wed, 27 Jun 2018 12:16:38 +0800 Subject: btrfs: remove unnecessary curly braces in btrfs_get_acl It's only coding style fix not functinal change. When if/else has only one statement then the braces are not needed. Signed-off-by: Chengguang Xu Reviewed-by: Nikolay Borisov Reviewed-by: David Sterba Signed-off-by: David Sterba --- fs/btrfs/acl.c | 7 +++---- 1 file changed, 3 insertions(+), 4 deletions(-) (limited to 'fs') diff --git a/fs/btrfs/acl.c b/fs/btrfs/acl.c index 7d673ec9e54a..3b66c957ea6f 100644 --- a/fs/btrfs/acl.c +++ b/fs/btrfs/acl.c @@ -40,13 +40,12 @@ struct posix_acl *btrfs_get_acl(struct inode *inode, int type) return ERR_PTR(-ENOMEM); size = btrfs_getxattr(inode, name, value, size); } - if (size > 0) { + if (size > 0) acl = posix_acl_from_xattr(&init_user_ns, value, size); - } else if (size == -ENODATA || size == 0) { + else if (size == -ENODATA || size == 0) acl = NULL; - } else { + else acl = ERR_PTR(size); - } kfree(value); return acl; -- cgit v1.2.3 From a79865c680d81220a1355cd13098e75227dc2994 Mon Sep 17 00:00:00 2001 From: Nikolay Borisov Date: Thu, 21 Jun 2018 09:45:00 +0300 Subject: btrfs: Remove V0 extent support The v0 compat code was introduced in commit 5d4f98a28c7d ("Btrfs: Mixed back reference (FORWARD ROLLING FORMAT CHANGE)") 9 years ago, which was merged in 2.6.31. This means that the code is there to support filesystems which are _VERY_ old and if you are using btrfs on such an old kernel, you have much bigger problems. This coupled with the fact that no one is likely testing/maintining this code likely means it has bugs lurking. All things considered I think 43 kernel releases later it's high time this remnant of the past got removed. This patch removes all code wrapped in #ifdefs but leaves the BUG_ONs in case we have a v0 with no support intact as a sort of safety-net. Signed-off-by: Nikolay Borisov Reviewed-by: David Sterba Signed-off-by: David Sterba --- fs/btrfs/ctree.c | 6 +- fs/btrfs/ctree.h | 2 - fs/btrfs/extent-tree.c | 209 +------------------------------------------------ fs/btrfs/print-tree.c | 30 +------ fs/btrfs/relocation.c | 151 +---------------------------------- 5 files changed, 4 insertions(+), 394 deletions(-) (limited to 'fs') diff --git a/fs/btrfs/ctree.c b/fs/btrfs/ctree.c index 18f1ca1c5bd9..d436fb4c002e 100644 --- a/fs/btrfs/ctree.c +++ b/fs/btrfs/ctree.c @@ -888,11 +888,7 @@ int btrfs_block_can_be_shared(struct btrfs_root *root, btrfs_root_last_snapshot(&root->root_item) || btrfs_header_flag(buf, BTRFS_HEADER_FLAG_RELOC))) return 1; -#ifdef BTRFS_COMPAT_EXTENT_TREE_V0 - if (test_bit(BTRFS_ROOT_REF_COWS, &root->state) && - btrfs_header_backref_rev(buf) < BTRFS_MIXED_BACKREF_REV) - return 1; -#endif + return 0; } diff --git a/fs/btrfs/ctree.h b/fs/btrfs/ctree.h index 41ba770b9db9..9fa958ed065e 100644 --- a/fs/btrfs/ctree.h +++ b/fs/btrfs/ctree.h @@ -55,8 +55,6 @@ struct btrfs_ordered_sum; #define BTRFS_OLDEST_GENERATION 0ULL -#define BTRFS_COMPAT_EXTENT_TREE_V0 - /* * the max metadata block size. This limit is somewhat artificial, * but the memmove costs go through the roof for larger blocks. diff --git a/fs/btrfs/extent-tree.c b/fs/btrfs/extent-tree.c index b28fa3d20ef7..6a73d2698807 100644 --- a/fs/btrfs/extent-tree.c +++ b/fs/btrfs/extent-tree.c @@ -867,17 +867,7 @@ search_again: num_refs = btrfs_extent_refs(leaf, ei); extent_flags = btrfs_extent_flags(leaf, ei); } else { -#ifdef BTRFS_COMPAT_EXTENT_TREE_V0 - struct btrfs_extent_item_v0 *ei0; - BUG_ON(item_size != sizeof(*ei0)); - ei0 = btrfs_item_ptr(leaf, path->slots[0], - struct btrfs_extent_item_v0); - num_refs = btrfs_extent_refs_v0(leaf, ei0); - /* FIXME: this isn't correct for data */ - extent_flags = BTRFS_BLOCK_FLAG_FULL_BACKREF; -#else BUG(); -#endif } BUG_ON(num_refs == 0); } else { @@ -1036,89 +1026,6 @@ out_free: * tree block info structure. */ -#ifdef BTRFS_COMPAT_EXTENT_TREE_V0 -static int convert_extent_item_v0(struct btrfs_trans_handle *trans, - struct btrfs_fs_info *fs_info, - struct btrfs_path *path, - u64 owner, u32 extra_size) -{ - struct btrfs_root *root = fs_info->extent_root; - struct btrfs_extent_item *item; - struct btrfs_extent_item_v0 *ei0; - struct btrfs_extent_ref_v0 *ref0; - struct btrfs_tree_block_info *bi; - struct extent_buffer *leaf; - struct btrfs_key key; - struct btrfs_key found_key; - u32 new_size = sizeof(*item); - u64 refs; - int ret; - - leaf = path->nodes[0]; - BUG_ON(btrfs_item_size_nr(leaf, path->slots[0]) != sizeof(*ei0)); - - btrfs_item_key_to_cpu(leaf, &key, path->slots[0]); - ei0 = btrfs_item_ptr(leaf, path->slots[0], - struct btrfs_extent_item_v0); - refs = btrfs_extent_refs_v0(leaf, ei0); - - if (owner == (u64)-1) { - while (1) { - if (path->slots[0] >= btrfs_header_nritems(leaf)) { - ret = btrfs_next_leaf(root, path); - if (ret < 0) - return ret; - BUG_ON(ret > 0); /* Corruption */ - leaf = path->nodes[0]; - } - btrfs_item_key_to_cpu(leaf, &found_key, - path->slots[0]); - BUG_ON(key.objectid != found_key.objectid); - if (found_key.type != BTRFS_EXTENT_REF_V0_KEY) { - path->slots[0]++; - continue; - } - ref0 = btrfs_item_ptr(leaf, path->slots[0], - struct btrfs_extent_ref_v0); - owner = btrfs_ref_objectid_v0(leaf, ref0); - break; - } - } - btrfs_release_path(path); - - if (owner < BTRFS_FIRST_FREE_OBJECTID) - new_size += sizeof(*bi); - - new_size -= sizeof(*ei0); - ret = btrfs_search_slot(trans, root, &key, path, - new_size + extra_size, 1); - if (ret < 0) - return ret; - BUG_ON(ret); /* Corruption */ - - btrfs_extend_item(fs_info, path, new_size); - - leaf = path->nodes[0]; - item = btrfs_item_ptr(leaf, path->slots[0], struct btrfs_extent_item); - btrfs_set_extent_refs(leaf, item, refs); - /* FIXME: get real generation */ - btrfs_set_extent_generation(leaf, item, 0); - if (owner < BTRFS_FIRST_FREE_OBJECTID) { - btrfs_set_extent_flags(leaf, item, - BTRFS_EXTENT_FLAG_TREE_BLOCK | - BTRFS_BLOCK_FLAG_FULL_BACKREF); - bi = (struct btrfs_tree_block_info *)(item + 1); - /* FIXME: get first key of the block */ - memzero_extent_buffer(leaf, (unsigned long)bi, sizeof(*bi)); - btrfs_set_tree_block_level(leaf, bi, (int)owner); - } else { - btrfs_set_extent_flags(leaf, item, BTRFS_EXTENT_FLAG_DATA); - } - btrfs_mark_buffer_dirty(leaf); - return 0; -} -#endif - /* * is_data == BTRFS_REF_TYPE_BLOCK, tree block type is required, * is_data == BTRFS_REF_TYPE_DATA, data type is requried, @@ -1247,17 +1154,6 @@ again: if (parent) { if (!ret) return 0; -#ifdef BTRFS_COMPAT_EXTENT_TREE_V0 - key.type = BTRFS_EXTENT_REF_V0_KEY; - btrfs_release_path(path); - ret = btrfs_search_slot(trans, root, &key, path, -1, 1); - if (ret < 0) { - err = ret; - goto fail; - } - if (!ret) - return 0; -#endif goto fail; } @@ -1400,13 +1296,6 @@ static noinline int remove_extent_data_ref(struct btrfs_trans_handle *trans, ref2 = btrfs_item_ptr(leaf, path->slots[0], struct btrfs_shared_data_ref); num_refs = btrfs_shared_data_ref_count(leaf, ref2); -#ifdef BTRFS_COMPAT_EXTENT_TREE_V0 - } else if (key.type == BTRFS_EXTENT_REF_V0_KEY) { - struct btrfs_extent_ref_v0 *ref0; - ref0 = btrfs_item_ptr(leaf, path->slots[0], - struct btrfs_extent_ref_v0); - num_refs = btrfs_ref_count_v0(leaf, ref0); -#endif } else { BUG(); } @@ -1422,14 +1311,6 @@ static noinline int remove_extent_data_ref(struct btrfs_trans_handle *trans, btrfs_set_extent_data_ref_count(leaf, ref1, num_refs); else if (key.type == BTRFS_SHARED_DATA_REF_KEY) btrfs_set_shared_data_ref_count(leaf, ref2, num_refs); -#ifdef BTRFS_COMPAT_EXTENT_TREE_V0 - else { - struct btrfs_extent_ref_v0 *ref0; - ref0 = btrfs_item_ptr(leaf, path->slots[0], - struct btrfs_extent_ref_v0); - btrfs_set_ref_count_v0(leaf, ref0, num_refs); - } -#endif btrfs_mark_buffer_dirty(leaf); } return ret; @@ -1469,13 +1350,6 @@ static noinline u32 extent_data_ref_count(struct btrfs_path *path, ref2 = btrfs_item_ptr(leaf, path->slots[0], struct btrfs_shared_data_ref); num_refs = btrfs_shared_data_ref_count(leaf, ref2); -#ifdef BTRFS_COMPAT_EXTENT_TREE_V0 - } else if (key.type == BTRFS_EXTENT_REF_V0_KEY) { - struct btrfs_extent_ref_v0 *ref0; - ref0 = btrfs_item_ptr(leaf, path->slots[0], - struct btrfs_extent_ref_v0); - num_refs = btrfs_ref_count_v0(leaf, ref0); -#endif } else { WARN_ON(1); } @@ -1503,15 +1377,6 @@ static noinline int lookup_tree_block_ref(struct btrfs_trans_handle *trans, ret = btrfs_search_slot(trans, root, &key, path, -1, 1); if (ret > 0) ret = -ENOENT; -#ifdef BTRFS_COMPAT_EXTENT_TREE_V0 - if (ret == -ENOENT && parent) { - btrfs_release_path(path); - key.type = BTRFS_EXTENT_REF_V0_KEY; - ret = btrfs_search_slot(trans, root, &key, path, -1, 1); - if (ret > 0) - ret = -ENOENT; - } -#endif return ret; } @@ -1676,22 +1541,6 @@ again: leaf = path->nodes[0]; item_size = btrfs_item_size_nr(leaf, path->slots[0]); -#ifdef BTRFS_COMPAT_EXTENT_TREE_V0 - if (item_size < sizeof(*ei)) { - if (!insert) { - err = -ENOENT; - goto out; - } - ret = convert_extent_item_v0(trans, fs_info, path, owner, - extra_size); - if (ret < 0) { - err = ret; - goto out; - } - leaf = path->nodes[0]; - item_size = btrfs_item_size_nr(leaf, path->slots[0]); - } -#endif BUG_ON(item_size < sizeof(*ei)); ei = btrfs_item_ptr(leaf, path->slots[0], struct btrfs_extent_item); @@ -2416,17 +2265,6 @@ again: leaf = path->nodes[0]; item_size = btrfs_item_size_nr(leaf, path->slots[0]); -#ifdef BTRFS_COMPAT_EXTENT_TREE_V0 - if (item_size < sizeof(*ei)) { - ret = convert_extent_item_v0(trans, fs_info, path, (u64)-1, 0); - if (ret < 0) { - err = ret; - goto out; - } - leaf = path->nodes[0]; - item_size = btrfs_item_size_nr(leaf, path->slots[0]); - } -#endif BUG_ON(item_size < sizeof(*ei)); ei = btrfs_item_ptr(leaf, path->slots[0], struct btrfs_extent_item); __run_delayed_extent_op(extent_op, leaf, ei); @@ -3238,12 +3076,6 @@ static noinline int check_committed_ref(struct btrfs_root *root, ret = 1; item_size = btrfs_item_size_nr(leaf, path->slots[0]); -#ifdef BTRFS_COMPAT_EXTENT_TREE_V0 - if (item_size < sizeof(*ei)) { - WARN_ON(item_size != sizeof(struct btrfs_extent_item_v0)); - goto out; - } -#endif ei = btrfs_item_ptr(leaf, path->slots[0], struct btrfs_extent_item); if (item_size != sizeof(*ei) + @@ -6888,11 +6720,7 @@ static int __btrfs_free_extent(struct btrfs_trans_handle *trans, break; extent_slot--; } -#ifdef BTRFS_COMPAT_EXTENT_TREE_V0 - item_size = btrfs_item_size_nr(path->nodes[0], extent_slot); - if (found_extent && item_size < sizeof(*ei)) - found_extent = 0; -#endif + if (!found_extent) { BUG_ON(iref); ret = remove_extent_backref(trans, path, NULL, @@ -6968,41 +6796,6 @@ static int __btrfs_free_extent(struct btrfs_trans_handle *trans, leaf = path->nodes[0]; item_size = btrfs_item_size_nr(leaf, extent_slot); -#ifdef BTRFS_COMPAT_EXTENT_TREE_V0 - if (item_size < sizeof(*ei)) { - BUG_ON(found_extent || extent_slot != path->slots[0]); - ret = convert_extent_item_v0(trans, info, path, owner_objectid, - 0); - if (ret < 0) { - btrfs_abort_transaction(trans, ret); - goto out; - } - - btrfs_release_path(path); - path->leave_spinning = 1; - - key.objectid = bytenr; - key.type = BTRFS_EXTENT_ITEM_KEY; - key.offset = num_bytes; - - ret = btrfs_search_slot(trans, extent_root, &key, path, - -1, 1); - if (ret) { - btrfs_err(info, - "umm, got %d back from search, was looking for %llu", - ret, bytenr); - btrfs_print_leaf(path->nodes[0]); - } - if (ret < 0) { - btrfs_abort_transaction(trans, ret); - goto out; - } - - extent_slot = path->slots[0]; - leaf = path->nodes[0]; - item_size = btrfs_item_size_nr(leaf, extent_slot); - } -#endif BUG_ON(item_size < sizeof(*ei)); ei = btrfs_item_ptr(leaf, extent_slot, struct btrfs_extent_item); diff --git a/fs/btrfs/print-tree.c b/fs/btrfs/print-tree.c index 59efcf2e0de8..c0dac9d7ce33 100644 --- a/fs/btrfs/print-tree.c +++ b/fs/btrfs/print-tree.c @@ -52,18 +52,8 @@ static void print_extent_item(struct extent_buffer *eb, int slot, int type) u64 offset; int ref_index = 0; - if (item_size < sizeof(*ei)) { -#ifdef BTRFS_COMPAT_EXTENT_TREE_V0 - struct btrfs_extent_item_v0 *ei0; - BUG_ON(item_size != sizeof(*ei0)); - ei0 = btrfs_item_ptr(eb, slot, struct btrfs_extent_item_v0); - pr_info("\t\textent refs %u\n", - btrfs_extent_refs_v0(eb, ei0)); - return; -#else + if (item_size < sizeof(*ei)) BUG(); -#endif - } ei = btrfs_item_ptr(eb, slot, struct btrfs_extent_item); flags = btrfs_extent_flags(eb, ei); @@ -133,20 +123,6 @@ static void print_extent_item(struct extent_buffer *eb, int slot, int type) WARN_ON(ptr > end); } -#ifdef BTRFS_COMPAT_EXTENT_TREE_V0 -static void print_extent_ref_v0(struct extent_buffer *eb, int slot) -{ - struct btrfs_extent_ref_v0 *ref0; - - ref0 = btrfs_item_ptr(eb, slot, struct btrfs_extent_ref_v0); - printk("\t\textent back ref root %llu gen %llu owner %llu num_refs %lu\n", - btrfs_ref_root_v0(eb, ref0), - btrfs_ref_generation_v0(eb, ref0), - btrfs_ref_objectid_v0(eb, ref0), - (unsigned long)btrfs_ref_count_v0(eb, ref0)); -} -#endif - static void print_uuid_item(struct extent_buffer *l, unsigned long offset, u32 item_size) { @@ -280,11 +256,7 @@ void btrfs_print_leaf(struct extent_buffer *l) btrfs_file_extent_ram_bytes(l, fi)); break; case BTRFS_EXTENT_REF_V0_KEY: -#ifdef BTRFS_COMPAT_EXTENT_TREE_V0 - print_extent_ref_v0(l, i); -#else BUG(); -#endif break; case BTRFS_BLOCK_GROUP_ITEM_KEY: bi = btrfs_item_ptr(l, i, diff --git a/fs/btrfs/relocation.c b/fs/btrfs/relocation.c index 44722e939e34..6dfa92e5ceed 100644 --- a/fs/btrfs/relocation.c +++ b/fs/btrfs/relocation.c @@ -586,29 +586,6 @@ static struct btrfs_root *read_fs_root(struct btrfs_fs_info *fs_info, return btrfs_get_fs_root(fs_info, &key, false); } -#ifdef BTRFS_COMPAT_EXTENT_TREE_V0 -static noinline_for_stack -struct btrfs_root *find_tree_root(struct reloc_control *rc, - struct extent_buffer *leaf, - struct btrfs_extent_ref_v0 *ref0) -{ - struct btrfs_root *root; - u64 root_objectid = btrfs_ref_root_v0(leaf, ref0); - u64 generation = btrfs_ref_generation_v0(leaf, ref0); - - BUG_ON(root_objectid == BTRFS_TREE_RELOC_OBJECTID); - - root = read_fs_root(rc->extent_root->fs_info, root_objectid); - BUG_ON(IS_ERR(root)); - - if (test_bit(BTRFS_ROOT_REF_COWS, &root->state) && - generation != btrfs_root_generation(&root->root_item)) - return NULL; - - return root; -} -#endif - static noinline_for_stack int find_inline_backref(struct extent_buffer *leaf, int slot, unsigned long *ptr, unsigned long *end) @@ -621,12 +598,6 @@ int find_inline_backref(struct extent_buffer *leaf, int slot, btrfs_item_key_to_cpu(leaf, &key, slot); item_size = btrfs_item_size_nr(leaf, slot); -#ifdef BTRFS_COMPAT_EXTENT_TREE_V0 - if (item_size < sizeof(*ei)) { - WARN_ON(item_size != sizeof(struct btrfs_extent_item_v0)); - return 1; - } -#endif ei = btrfs_item_ptr(leaf, slot, struct btrfs_extent_item); WARN_ON(!(btrfs_extent_flags(leaf, ei) & BTRFS_EXTENT_FLAG_TREE_BLOCK)); @@ -811,29 +782,8 @@ again: goto next; } -#ifdef BTRFS_COMPAT_EXTENT_TREE_V0 - if (key.type == BTRFS_SHARED_BLOCK_REF_KEY || - key.type == BTRFS_EXTENT_REF_V0_KEY) { - if (key.type == BTRFS_EXTENT_REF_V0_KEY) { - struct btrfs_extent_ref_v0 *ref0; - ref0 = btrfs_item_ptr(eb, path1->slots[0], - struct btrfs_extent_ref_v0); - if (key.objectid == key.offset) { - root = find_tree_root(rc, eb, ref0); - if (root && !should_ignore_root(root)) - cur->root = root; - else - list_add(&cur->list, &useless); - break; - } - if (is_cowonly_root(btrfs_ref_root_v0(eb, - ref0))) - cur->cowonly = 1; - } -#else ASSERT(key.type != BTRFS_EXTENT_REF_V0_KEY); if (key.type == BTRFS_SHARED_BLOCK_REF_KEY) { -#endif if (key.objectid == key.offset) { /* * only root blocks of reloc trees use @@ -3333,48 +3283,6 @@ int relocate_data_extent(struct inode *inode, struct btrfs_key *extent_key, return 0; } -#ifdef BTRFS_COMPAT_EXTENT_TREE_V0 -static int get_ref_objectid_v0(struct reloc_control *rc, - struct btrfs_path *path, - struct btrfs_key *extent_key, - u64 *ref_objectid, int *path_change) -{ - struct btrfs_key key; - struct extent_buffer *leaf; - struct btrfs_extent_ref_v0 *ref0; - int ret; - int slot; - - leaf = path->nodes[0]; - slot = path->slots[0]; - while (1) { - if (slot >= btrfs_header_nritems(leaf)) { - ret = btrfs_next_leaf(rc->extent_root, path); - if (ret < 0) - return ret; - BUG_ON(ret > 0); - leaf = path->nodes[0]; - slot = path->slots[0]; - if (path_change) - *path_change = 1; - } - btrfs_item_key_to_cpu(leaf, &key, slot); - if (key.objectid != extent_key->objectid) - return -ENOENT; - - if (key.type != BTRFS_EXTENT_REF_V0_KEY) { - slot++; - continue; - } - ref0 = btrfs_item_ptr(leaf, slot, - struct btrfs_extent_ref_v0); - *ref_objectid = btrfs_ref_objectid_v0(leaf, ref0); - break; - } - return 0; -} -#endif - /* * helper to add a tree block to the list. * the major work is getting the generation and level of the block @@ -3408,22 +3316,7 @@ static int add_tree_block(struct reloc_control *rc, } generation = btrfs_extent_generation(eb, ei); } else { -#ifdef BTRFS_COMPAT_EXTENT_TREE_V0 - u64 ref_owner; - int ret; - - BUG_ON(item_size != sizeof(struct btrfs_extent_item_v0)); - ret = get_ref_objectid_v0(rc, path, extent_key, - &ref_owner, NULL); - if (ret < 0) - return ret; - BUG_ON(ref_owner >= BTRFS_MAX_LEVEL); - level = (int)ref_owner; - /* FIXME: get real generation */ - generation = 0; -#else BUG(); -#endif } btrfs_release_path(path); @@ -3781,12 +3674,7 @@ int add_data_references(struct reloc_control *rc, eb = path->nodes[0]; ptr = btrfs_item_ptr_offset(eb, path->slots[0]); end = ptr + btrfs_item_size_nr(eb, path->slots[0]); -#ifdef BTRFS_COMPAT_EXTENT_TREE_V0 - if (ptr + sizeof(struct btrfs_extent_item_v0) == end) - ptr = end; - else -#endif - ptr += sizeof(struct btrfs_extent_item); + ptr += sizeof(struct btrfs_extent_item); while (ptr < end) { iref = (struct btrfs_extent_inline_ref *)ptr; @@ -3832,13 +3720,8 @@ int add_data_references(struct reloc_control *rc, if (key.objectid != extent_key->objectid) break; -#ifdef BTRFS_COMPAT_EXTENT_TREE_V0 - if (key.type == BTRFS_SHARED_DATA_REF_KEY || - key.type == BTRFS_EXTENT_REF_V0_KEY) { -#else BUG_ON(key.type == BTRFS_EXTENT_REF_V0_KEY); if (key.type == BTRFS_SHARED_DATA_REF_KEY) { -#endif ret = __add_tree_block(rc, key.offset, blocksize, blocks); } else if (key.type == BTRFS_EXTENT_DATA_REF_KEY) { @@ -4086,39 +3969,7 @@ restart: BUG_ON(ret); } else { -#ifdef BTRFS_COMPAT_EXTENT_TREE_V0 - u64 ref_owner; - int path_change = 0; - - BUG_ON(item_size != - sizeof(struct btrfs_extent_item_v0)); - ret = get_ref_objectid_v0(rc, path, &key, &ref_owner, - &path_change); - if (ret < 0) { - err = ret; - break; - } - if (ref_owner < BTRFS_FIRST_FREE_OBJECTID) - flags = BTRFS_EXTENT_FLAG_TREE_BLOCK; - else - flags = BTRFS_EXTENT_FLAG_DATA; - - if (path_change) { - btrfs_release_path(path); - - path->search_commit_root = 1; - path->skip_locking = 1; - ret = btrfs_search_slot(NULL, rc->extent_root, - &key, path, 0, 0); - if (ret < 0) { - err = ret; - break; - } - BUG_ON(ret > 0); - } -#else BUG(); -#endif } if (flags & BTRFS_EXTENT_FLAG_TREE_BLOCK) { -- cgit v1.2.3 From ba3c2b196bf59ba8574808fe6f8fd88d0fed7510 Mon Sep 17 00:00:00 2001 From: Nikolay Borisov Date: Tue, 26 Jun 2018 16:57:36 +0300 Subject: btrfs: Add graceful handling of V0 extents Following the removal of the v0 handling code let's be courteous and print an error message when such extents are handled. In the cases where we have a transaction just abort it, otherwise just call btrfs_handle_fs_error. Both cases result in the FS being re-mounted RO. In case the error handling would be too intrusive, leave the BUG_ON in place, like extent_data_ref_count, other proper handling would catch that earlier. Signed-off-by: Nikolay Borisov Reviewed-by: David Sterba Signed-off-by: David Sterba --- fs/btrfs/ctree.h | 7 +++++++ fs/btrfs/extent-tree.c | 39 +++++++++++++++++++++++++++++++++++---- fs/btrfs/print-tree.c | 9 ++++++--- fs/btrfs/relocation.c | 27 ++++++++++++++++++++++++--- 4 files changed, 72 insertions(+), 10 deletions(-) (limited to 'fs') diff --git a/fs/btrfs/ctree.h b/fs/btrfs/ctree.h index 9fa958ed065e..427ca5de8542 100644 --- a/fs/btrfs/ctree.h +++ b/fs/btrfs/ctree.h @@ -3432,6 +3432,13 @@ static inline void assfail(char *expr, char *file, int line) #define ASSERT(expr) ((void)0) #endif +__cold +static inline void btrfs_print_v0_err(struct btrfs_fs_info *fs_info) +{ + btrfs_err(fs_info, +"Unsupported V0 extent filesystem detected. Aborting. Please re-create your filesystem with a newer kernel"); +} + __printf(5, 6) __cold void __btrfs_handle_fs_error(struct btrfs_fs_info *fs_info, const char *function, diff --git a/fs/btrfs/extent-tree.c b/fs/btrfs/extent-tree.c index 6a73d2698807..71283faa85e2 100644 --- a/fs/btrfs/extent-tree.c +++ b/fs/btrfs/extent-tree.c @@ -867,8 +867,16 @@ search_again: num_refs = btrfs_extent_refs(leaf, ei); extent_flags = btrfs_extent_flags(leaf, ei); } else { - BUG(); + ret = -EINVAL; + btrfs_print_v0_err(fs_info); + if (trans) + btrfs_abort_transaction(trans, ret); + else + btrfs_handle_fs_error(fs_info, ret, NULL); + + goto out_free; } + BUG_ON(num_refs == 0); } else { num_refs = 0; @@ -1296,6 +1304,10 @@ static noinline int remove_extent_data_ref(struct btrfs_trans_handle *trans, ref2 = btrfs_item_ptr(leaf, path->slots[0], struct btrfs_shared_data_ref); num_refs = btrfs_shared_data_ref_count(leaf, ref2); + } else if (key.type == BTRFS_EXTENT_REF_V0_KEY) { + btrfs_print_v0_err(trans->fs_info); + btrfs_abort_transaction(trans, -EINVAL); + return -EINVAL; } else { BUG(); } @@ -1328,6 +1340,8 @@ static noinline u32 extent_data_ref_count(struct btrfs_path *path, leaf = path->nodes[0]; btrfs_item_key_to_cpu(leaf, &key, path->slots[0]); + + BUG_ON(key.type == BTRFS_EXTENT_REF_V0_KEY); if (iref) { /* * If type is invalid, we should have bailed out earlier than @@ -1541,7 +1555,12 @@ again: leaf = path->nodes[0]; item_size = btrfs_item_size_nr(leaf, path->slots[0]); - BUG_ON(item_size < sizeof(*ei)); + if (item_size < sizeof(*ei)) { + err = -EINVAL; + btrfs_print_v0_err(fs_info); + btrfs_abort_transaction(trans, err); + goto out; + } ei = btrfs_item_ptr(leaf, path->slots[0], struct btrfs_extent_item); flags = btrfs_extent_flags(leaf, ei); @@ -2265,7 +2284,14 @@ again: leaf = path->nodes[0]; item_size = btrfs_item_size_nr(leaf, path->slots[0]); - BUG_ON(item_size < sizeof(*ei)); + + if (item_size < sizeof(*ei)) { + err = -EINVAL; + btrfs_print_v0_err(fs_info); + btrfs_abort_transaction(trans, err); + goto out; + } + ei = btrfs_item_ptr(leaf, path->slots[0], struct btrfs_extent_item); __run_delayed_extent_op(extent_op, leaf, ei); @@ -6796,7 +6822,12 @@ static int __btrfs_free_extent(struct btrfs_trans_handle *trans, leaf = path->nodes[0]; item_size = btrfs_item_size_nr(leaf, extent_slot); - BUG_ON(item_size < sizeof(*ei)); + if (item_size < sizeof(*ei)) { + ret = -EINVAL; + btrfs_print_v0_err(info); + btrfs_abort_transaction(trans, ret); + goto out; + } ei = btrfs_item_ptr(leaf, extent_slot, struct btrfs_extent_item); if (owner_objectid < BTRFS_FIRST_FREE_OBJECTID && diff --git a/fs/btrfs/print-tree.c b/fs/btrfs/print-tree.c index c0dac9d7ce33..cc945376c244 100644 --- a/fs/btrfs/print-tree.c +++ b/fs/btrfs/print-tree.c @@ -52,8 +52,10 @@ static void print_extent_item(struct extent_buffer *eb, int slot, int type) u64 offset; int ref_index = 0; - if (item_size < sizeof(*ei)) - BUG(); + if (item_size < sizeof(*ei)) { + btrfs_print_v0_err(eb->fs_info); + btrfs_handle_fs_error(eb->fs_info, -EINVAL, NULL); + } ei = btrfs_item_ptr(eb, slot, struct btrfs_extent_item); flags = btrfs_extent_flags(eb, ei); @@ -256,7 +258,8 @@ void btrfs_print_leaf(struct extent_buffer *l) btrfs_file_extent_ram_bytes(l, fi)); break; case BTRFS_EXTENT_REF_V0_KEY: - BUG(); + btrfs_print_v0_err(fs_info); + btrfs_handle_fs_error(fs_info, -EINVAL, NULL); break; case BTRFS_BLOCK_GROUP_ITEM_KEY: bi = btrfs_item_ptr(l, i, diff --git a/fs/btrfs/relocation.c b/fs/btrfs/relocation.c index 6dfa92e5ceed..eaf59c742dc8 100644 --- a/fs/btrfs/relocation.c +++ b/fs/btrfs/relocation.c @@ -598,6 +598,11 @@ int find_inline_backref(struct extent_buffer *leaf, int slot, btrfs_item_key_to_cpu(leaf, &key, slot); item_size = btrfs_item_size_nr(leaf, slot); + if (item_size < sizeof(*ei)) { + btrfs_print_v0_err(leaf->fs_info); + btrfs_handle_fs_error(leaf->fs_info, -EINVAL, NULL); + return 1; + } ei = btrfs_item_ptr(leaf, slot, struct btrfs_extent_item); WARN_ON(!(btrfs_extent_flags(leaf, ei) & BTRFS_EXTENT_FLAG_TREE_BLOCK)); @@ -782,7 +787,6 @@ again: goto next; } - ASSERT(key.type != BTRFS_EXTENT_REF_V0_KEY); if (key.type == BTRFS_SHARED_BLOCK_REF_KEY) { if (key.objectid == key.offset) { /* @@ -826,6 +830,12 @@ again: edge->node[UPPER] = upper; goto next; + } else if (key.type == BTRFS_EXTENT_REF_V0_KEY) { + err = -EINVAL; + btrfs_print_v0_err(rc->extent_root->fs_info); + btrfs_handle_fs_error(rc->extent_root->fs_info, err, + NULL); + goto out; } else if (key.type != BTRFS_TREE_BLOCK_REF_KEY) { goto next; } @@ -3315,6 +3325,10 @@ static int add_tree_block(struct reloc_control *rc, level = (int)extent_key->offset; } generation = btrfs_extent_generation(eb, ei); + } else if (item_size == sizeof(struct btrfs_extent_item_v0)) { + btrfs_print_v0_err(eb->fs_info); + btrfs_handle_fs_error(eb->fs_info, -EINVAL, NULL); + return -EINVAL; } else { BUG(); } @@ -3720,7 +3734,6 @@ int add_data_references(struct reloc_control *rc, if (key.objectid != extent_key->objectid) break; - BUG_ON(key.type == BTRFS_EXTENT_REF_V0_KEY); if (key.type == BTRFS_SHARED_DATA_REF_KEY) { ret = __add_tree_block(rc, key.offset, blocksize, blocks); @@ -3729,6 +3742,10 @@ int add_data_references(struct reloc_control *rc, struct btrfs_extent_data_ref); ret = find_data_references(rc, extent_key, eb, dref, blocks); + } else if (key.type == BTRFS_EXTENT_REF_V0_KEY) { + btrfs_print_v0_err(eb->fs_info); + btrfs_handle_fs_error(eb->fs_info, -EINVAL, NULL); + ret = -EINVAL; } else { ret = 0; } @@ -3967,7 +3984,11 @@ restart: flags = btrfs_extent_flags(path->nodes[0], ei); ret = check_extent_flags(flags); BUG_ON(ret); - + } else if (item_size == sizeof(struct btrfs_extent_item_v0)) { + err = -EINVAL; + btrfs_print_v0_err(trans->fs_info); + btrfs_abort_transaction(trans, err); + break; } else { BUG(); } -- cgit v1.2.3 From 6d8ff4e4584cd84093b751671351c8103ead551d Mon Sep 17 00:00:00 2001 From: David Sterba Date: Tue, 26 Jun 2018 16:20:59 +0200 Subject: btrfs: annotate unlikely branches after V0 extent type removal The v0 extent type checks are the right case for the unlikely annotations as we don't expect to ever see them, so let's give the compiler some hint. Reviewed-by: Nikolay Borisov Signed-off-by: David Sterba --- fs/btrfs/extent-tree.c | 8 ++++---- fs/btrfs/print-tree.c | 2 +- fs/btrfs/relocation.c | 8 ++++---- 3 files changed, 9 insertions(+), 9 deletions(-) (limited to 'fs') diff --git a/fs/btrfs/extent-tree.c b/fs/btrfs/extent-tree.c index 71283faa85e2..352b7e95f657 100644 --- a/fs/btrfs/extent-tree.c +++ b/fs/btrfs/extent-tree.c @@ -1304,7 +1304,7 @@ static noinline int remove_extent_data_ref(struct btrfs_trans_handle *trans, ref2 = btrfs_item_ptr(leaf, path->slots[0], struct btrfs_shared_data_ref); num_refs = btrfs_shared_data_ref_count(leaf, ref2); - } else if (key.type == BTRFS_EXTENT_REF_V0_KEY) { + } else if (unlikely(key.type == BTRFS_EXTENT_REF_V0_KEY)) { btrfs_print_v0_err(trans->fs_info); btrfs_abort_transaction(trans, -EINVAL); return -EINVAL; @@ -1555,7 +1555,7 @@ again: leaf = path->nodes[0]; item_size = btrfs_item_size_nr(leaf, path->slots[0]); - if (item_size < sizeof(*ei)) { + if (unlikely(item_size < sizeof(*ei))) { err = -EINVAL; btrfs_print_v0_err(fs_info); btrfs_abort_transaction(trans, err); @@ -2285,7 +2285,7 @@ again: leaf = path->nodes[0]; item_size = btrfs_item_size_nr(leaf, path->slots[0]); - if (item_size < sizeof(*ei)) { + if (unlikely(item_size < sizeof(*ei))) { err = -EINVAL; btrfs_print_v0_err(fs_info); btrfs_abort_transaction(trans, err); @@ -6822,7 +6822,7 @@ static int __btrfs_free_extent(struct btrfs_trans_handle *trans, leaf = path->nodes[0]; item_size = btrfs_item_size_nr(leaf, extent_slot); - if (item_size < sizeof(*ei)) { + if (unlikely(item_size < sizeof(*ei))) { ret = -EINVAL; btrfs_print_v0_err(info); btrfs_abort_transaction(trans, ret); diff --git a/fs/btrfs/print-tree.c b/fs/btrfs/print-tree.c index cc945376c244..df49931ffe92 100644 --- a/fs/btrfs/print-tree.c +++ b/fs/btrfs/print-tree.c @@ -52,7 +52,7 @@ static void print_extent_item(struct extent_buffer *eb, int slot, int type) u64 offset; int ref_index = 0; - if (item_size < sizeof(*ei)) { + if (unlikely(item_size < sizeof(*ei))) { btrfs_print_v0_err(eb->fs_info); btrfs_handle_fs_error(eb->fs_info, -EINVAL, NULL); } diff --git a/fs/btrfs/relocation.c b/fs/btrfs/relocation.c index eaf59c742dc8..229f721cbde9 100644 --- a/fs/btrfs/relocation.c +++ b/fs/btrfs/relocation.c @@ -830,7 +830,7 @@ again: edge->node[UPPER] = upper; goto next; - } else if (key.type == BTRFS_EXTENT_REF_V0_KEY) { + } else if (unlikely(key.type == BTRFS_EXTENT_REF_V0_KEY)) { err = -EINVAL; btrfs_print_v0_err(rc->extent_root->fs_info); btrfs_handle_fs_error(rc->extent_root->fs_info, err, @@ -3325,7 +3325,7 @@ static int add_tree_block(struct reloc_control *rc, level = (int)extent_key->offset; } generation = btrfs_extent_generation(eb, ei); - } else if (item_size == sizeof(struct btrfs_extent_item_v0)) { + } else if (unlikely(item_size == sizeof(struct btrfs_extent_item_v0))) { btrfs_print_v0_err(eb->fs_info); btrfs_handle_fs_error(eb->fs_info, -EINVAL, NULL); return -EINVAL; @@ -3742,7 +3742,7 @@ int add_data_references(struct reloc_control *rc, struct btrfs_extent_data_ref); ret = find_data_references(rc, extent_key, eb, dref, blocks); - } else if (key.type == BTRFS_EXTENT_REF_V0_KEY) { + } else if (unlikely(key.type == BTRFS_EXTENT_REF_V0_KEY)) { btrfs_print_v0_err(eb->fs_info); btrfs_handle_fs_error(eb->fs_info, -EINVAL, NULL); ret = -EINVAL; @@ -3984,7 +3984,7 @@ restart: flags = btrfs_extent_flags(path->nodes[0], ei); ret = check_extent_flags(flags); BUG_ON(ret); - } else if (item_size == sizeof(struct btrfs_extent_item_v0)) { + } else if (unlikely(item_size == sizeof(struct btrfs_extent_item_v0))) { err = -EINVAL; btrfs_print_v0_err(trans->fs_info); btrfs_abort_transaction(trans, err); -- cgit v1.2.3 From fce466eab7ac6baa9d2dcd88abcf945be3d4a089 Mon Sep 17 00:00:00 2001 From: Qu Wenruo Date: Tue, 3 Jul 2018 17:10:05 +0800 Subject: btrfs: tree-checker: Verify block_group_item A crafted image with invalid block group items could make free space cache code to cause panic. We could detect such invalid block group item by checking: 1) Item size Known fixed value. 2) Block group size (key.offset) We have an upper limit on block group item (10G) 3) Chunk objectid Known fixed value. 4) Type Only 4 valid type values, DATA, METADATA, SYSTEM and DATA|METADATA. No more than 1 bit set for profile type. 5) Used space No more than the block group size. This should allow btrfs to detect and refuse to mount the crafted image. Link: https://bugzilla.kernel.org/show_bug.cgi?id=199849 Reported-by: Xu Wen Signed-off-by: Qu Wenruo Reviewed-by: Gu Jinxiang Reviewed-by: Nikolay Borisov Tested-by: Gu Jinxiang Reviewed-by: David Sterba Signed-off-by: David Sterba --- fs/btrfs/tree-checker.c | 100 ++++++++++++++++++++++++++++++++++++++++++++++++ fs/btrfs/volumes.c | 2 +- fs/btrfs/volumes.h | 2 + 3 files changed, 103 insertions(+), 1 deletion(-) (limited to 'fs') diff --git a/fs/btrfs/tree-checker.c b/fs/btrfs/tree-checker.c index 8d40e7dd8c30..3bade2ad39e8 100644 --- a/fs/btrfs/tree-checker.c +++ b/fs/btrfs/tree-checker.c @@ -19,6 +19,7 @@ #include "tree-checker.h" #include "disk-io.h" #include "compression.h" +#include "volumes.h" /* * Error message should follow the following format: @@ -353,6 +354,102 @@ static int check_dir_item(struct btrfs_fs_info *fs_info, return 0; } +__printf(4, 5) +__cold +static void block_group_err(const struct btrfs_fs_info *fs_info, + const struct extent_buffer *eb, int slot, + const char *fmt, ...) +{ + struct btrfs_key key; + struct va_format vaf; + va_list args; + + btrfs_item_key_to_cpu(eb, &key, slot); + va_start(args, fmt); + + vaf.fmt = fmt; + vaf.va = &args; + + btrfs_crit(fs_info, + "corrupt %s: root=%llu block=%llu slot=%d bg_start=%llu bg_len=%llu, %pV", + btrfs_header_level(eb) == 0 ? "leaf" : "node", + btrfs_header_owner(eb), btrfs_header_bytenr(eb), slot, + key.objectid, key.offset, &vaf); + va_end(args); +} + +static int check_block_group_item(struct btrfs_fs_info *fs_info, + struct extent_buffer *leaf, + struct btrfs_key *key, int slot) +{ + struct btrfs_block_group_item bgi; + u32 item_size = btrfs_item_size_nr(leaf, slot); + u64 flags; + u64 type; + + /* + * Here we don't really care about alignment since extent allocator can + * handle it. We care more about the size, as if one block group is + * larger than maximum size, it's must be some obvious corruption. + */ + if (key->offset > BTRFS_MAX_DATA_CHUNK_SIZE || key->offset == 0) { + block_group_err(fs_info, leaf, slot, + "invalid block group size, have %llu expect (0, %llu]", + key->offset, BTRFS_MAX_DATA_CHUNK_SIZE); + return -EUCLEAN; + } + + if (item_size != sizeof(bgi)) { + block_group_err(fs_info, leaf, slot, + "invalid item size, have %u expect %zu", + item_size, sizeof(bgi)); + return -EUCLEAN; + } + + read_extent_buffer(leaf, &bgi, btrfs_item_ptr_offset(leaf, slot), + sizeof(bgi)); + if (btrfs_block_group_chunk_objectid(&bgi) != + BTRFS_FIRST_CHUNK_TREE_OBJECTID) { + block_group_err(fs_info, leaf, slot, + "invalid block group chunk objectid, have %llu expect %llu", + btrfs_block_group_chunk_objectid(&bgi), + BTRFS_FIRST_CHUNK_TREE_OBJECTID); + return -EUCLEAN; + } + + if (btrfs_block_group_used(&bgi) > key->offset) { + block_group_err(fs_info, leaf, slot, + "invalid block group used, have %llu expect [0, %llu)", + btrfs_block_group_used(&bgi), key->offset); + return -EUCLEAN; + } + + flags = btrfs_block_group_flags(&bgi); + if (hweight64(flags & BTRFS_BLOCK_GROUP_PROFILE_MASK) > 1) { + block_group_err(fs_info, leaf, slot, +"invalid profile flags, have 0x%llx (%lu bits set) expect no more than 1 bit set", + flags & BTRFS_BLOCK_GROUP_PROFILE_MASK, + hweight64(flags & BTRFS_BLOCK_GROUP_PROFILE_MASK)); + return -EUCLEAN; + } + + type = flags & BTRFS_BLOCK_GROUP_TYPE_MASK; + if (type != BTRFS_BLOCK_GROUP_DATA && + type != BTRFS_BLOCK_GROUP_METADATA && + type != BTRFS_BLOCK_GROUP_SYSTEM && + type != (BTRFS_BLOCK_GROUP_METADATA | + BTRFS_BLOCK_GROUP_DATA)) { + block_group_err(fs_info, leaf, slot, +"invalid type, have 0x%llx (%lu bits set) expect either 0x%llx, 0x%llx, 0x%llu or 0x%llx", + type, hweight64(type), + BTRFS_BLOCK_GROUP_DATA, BTRFS_BLOCK_GROUP_METADATA, + BTRFS_BLOCK_GROUP_SYSTEM, + BTRFS_BLOCK_GROUP_METADATA | BTRFS_BLOCK_GROUP_DATA); + return -EUCLEAN; + } + return 0; +} + /* * Common point to switch the item-specific validation. */ @@ -374,6 +471,9 @@ static int check_leaf_item(struct btrfs_fs_info *fs_info, case BTRFS_XATTR_ITEM_KEY: ret = check_dir_item(fs_info, leaf, key, slot); break; + case BTRFS_BLOCK_GROUP_ITEM_KEY: + ret = check_block_group_item(fs_info, leaf, key, slot); + break; } return ret; } diff --git a/fs/btrfs/volumes.c b/fs/btrfs/volumes.c index fe497937933f..256e57eec8ec 100644 --- a/fs/btrfs/volumes.c +++ b/fs/btrfs/volumes.c @@ -4692,7 +4692,7 @@ static int __btrfs_alloc_chunk(struct btrfs_trans_handle *trans, if (type & BTRFS_BLOCK_GROUP_DATA) { max_stripe_size = SZ_1G; - max_chunk_size = 10 * max_stripe_size; + max_chunk_size = BTRFS_MAX_DATA_CHUNK_SIZE; if (!devs_max) devs_max = BTRFS_MAX_DEVS(info); } else if (type & BTRFS_BLOCK_GROUP_METADATA) { diff --git a/fs/btrfs/volumes.h b/fs/btrfs/volumes.h index df2d8bdf8c9a..275c31c730cf 100644 --- a/fs/btrfs/volumes.h +++ b/fs/btrfs/volumes.h @@ -11,6 +11,8 @@ #include #include "async-thread.h" +#define BTRFS_MAX_DATA_CHUNK_SIZE (10ULL * SZ_1G) + extern struct mutex uuid_mutex; #define BTRFS_STRIPE_LEN SZ_64K -- cgit v1.2.3 From ba480dd4db9f1798541eb2d1c423fc95feee8d36 Mon Sep 17 00:00:00 2001 From: Qu Wenruo Date: Tue, 3 Jul 2018 17:10:06 +0800 Subject: btrfs: tree-checker: Detect invalid and empty essential trees A crafted image has empty root tree block, which will later cause NULL pointer dereference. The following trees should never be empty: 1) Tree root Must contain at least root items for extent tree, device tree and fs tree 2) Chunk tree Or we can't even bootstrap as it contains the mapping. 3) Fs tree At least inode item for top level inode (.). 4) Device tree Dev extents for chunks 5) Extent tree Must have corresponding extent for each chunk. If any of them is empty, we are sure the fs is corrupted and no need to mount it. Link: https://bugzilla.kernel.org/show_bug.cgi?id=199847 Reported-by: Xu Wen Signed-off-by: Qu Wenruo Tested-by: Gu Jinxiang Reviewed-by: David Sterba Signed-off-by: David Sterba --- fs/btrfs/tree-checker.c | 15 ++++++++++++++- 1 file changed, 14 insertions(+), 1 deletion(-) (limited to 'fs') diff --git a/fs/btrfs/tree-checker.c b/fs/btrfs/tree-checker.c index 3bade2ad39e8..db835635372f 100644 --- a/fs/btrfs/tree-checker.c +++ b/fs/btrfs/tree-checker.c @@ -496,9 +496,22 @@ static int check_leaf(struct btrfs_fs_info *fs_info, struct extent_buffer *leaf, * skip this check for relocation trees. */ if (nritems == 0 && !btrfs_header_flag(leaf, BTRFS_HEADER_FLAG_RELOC)) { + u64 owner = btrfs_header_owner(leaf); struct btrfs_root *check_root; - key.objectid = btrfs_header_owner(leaf); + /* These trees must never be empty */ + if (owner == BTRFS_ROOT_TREE_OBJECTID || + owner == BTRFS_CHUNK_TREE_OBJECTID || + owner == BTRFS_EXTENT_TREE_OBJECTID || + owner == BTRFS_DEV_TREE_OBJECTID || + owner == BTRFS_FS_TREE_OBJECTID || + owner == BTRFS_DATA_RELOC_TREE_OBJECTID) { + generic_err(fs_info, leaf, 0, + "invalid root, root %llu must never be empty", + owner); + return -EUCLEAN; + } + key.objectid = owner; key.type = BTRFS_ROOT_ITEM_KEY; key.offset = (u64)-1; -- cgit v1.2.3 From 389305b2aa68723c754f88d9dbd268a400e10664 Mon Sep 17 00:00:00 2001 From: Qu Wenruo Date: Tue, 3 Jul 2018 17:10:07 +0800 Subject: btrfs: relocation: Only remove reloc rb_trees if reloc control has been initialized Invalid reloc tree can cause kernel NULL pointer dereference when btrfs does some cleanup of the reloc roots. It turns out that fs_info::reloc_ctl can be NULL in btrfs_recover_relocation() as we allocate relocation control after all reloc roots have been verified. So when we hit: note, we haven't called set_reloc_control() thus fs_info::reloc_ctl is still NULL. Link: https://bugzilla.kernel.org/show_bug.cgi?id=199833 Reported-by: Xu Wen Signed-off-by: Qu Wenruo Tested-by: Gu Jinxiang Reviewed-by: David Sterba Signed-off-by: David Sterba --- fs/btrfs/relocation.c | 23 ++++++++++++----------- 1 file changed, 12 insertions(+), 11 deletions(-) (limited to 'fs') diff --git a/fs/btrfs/relocation.c b/fs/btrfs/relocation.c index 229f721cbde9..b98d7a594542 100644 --- a/fs/btrfs/relocation.c +++ b/fs/btrfs/relocation.c @@ -1281,18 +1281,19 @@ static void __del_reloc_root(struct btrfs_root *root) struct mapping_node *node = NULL; struct reloc_control *rc = fs_info->reloc_ctl; - spin_lock(&rc->reloc_root_tree.lock); - rb_node = tree_search(&rc->reloc_root_tree.rb_root, - root->node->start); - if (rb_node) { - node = rb_entry(rb_node, struct mapping_node, rb_node); - rb_erase(&node->rb_node, &rc->reloc_root_tree.rb_root); + if (rc) { + spin_lock(&rc->reloc_root_tree.lock); + rb_node = tree_search(&rc->reloc_root_tree.rb_root, + root->node->start); + if (rb_node) { + node = rb_entry(rb_node, struct mapping_node, rb_node); + rb_erase(&node->rb_node, &rc->reloc_root_tree.rb_root); + } + spin_unlock(&rc->reloc_root_tree.lock); + if (!node) + return; + BUG_ON((struct btrfs_root *)node->data != root); } - spin_unlock(&rc->reloc_root_tree.lock); - - if (!node) - return; - BUG_ON((struct btrfs_root *)node->data != root); spin_lock(&fs_info->trans_lock); list_del_init(&root->root_list); -- cgit v1.2.3 From 5da54bc13801d378bf2e868beb623fc13ba40a83 Mon Sep 17 00:00:00 2001 From: Anand Jain Date: Tue, 3 Jul 2018 13:14:50 +0800 Subject: btrfs: use a temporary variable for fs_devices in btrfs_init_new_device There are many instances of the %fs_info->fs_devices pointer dereferences, use a temporary variable instead. Signed-off-by: Anand Jain Signed-off-by: David Sterba --- fs/btrfs/volumes.c | 42 +++++++++++++++++++++--------------------- 1 file changed, 21 insertions(+), 21 deletions(-) (limited to 'fs') diff --git a/fs/btrfs/volumes.c b/fs/btrfs/volumes.c index 256e57eec8ec..adce1c2e9b7b 100644 --- a/fs/btrfs/volumes.c +++ b/fs/btrfs/volumes.c @@ -2410,12 +2410,13 @@ int btrfs_init_new_device(struct btrfs_fs_info *fs_info, const char *device_path struct list_head *devices; struct super_block *sb = fs_info->sb; struct rcu_string *name; + struct btrfs_fs_devices *fs_devices = fs_info->fs_devices; u64 tmp; int seeding_dev = 0; int ret = 0; bool unlocked = false; - if (sb_rdonly(sb) && !fs_info->fs_devices->seeding) + if (sb_rdonly(sb) && !fs_devices->seeding) return -EROFS; bdev = blkdev_get_by_path(device_path, FMODE_WRITE | FMODE_EXCL, @@ -2423,7 +2424,7 @@ int btrfs_init_new_device(struct btrfs_fs_info *fs_info, const char *device_path if (IS_ERR(bdev)) return PTR_ERR(bdev); - if (fs_info->fs_devices->seeding) { + if (fs_devices->seeding) { seeding_dev = 1; down_write(&sb->s_umount); mutex_lock(&uuid_mutex); @@ -2431,18 +2432,18 @@ int btrfs_init_new_device(struct btrfs_fs_info *fs_info, const char *device_path filemap_write_and_wait(bdev->bd_inode->i_mapping); - devices = &fs_info->fs_devices->devices; + devices = &fs_devices->devices; - mutex_lock(&fs_info->fs_devices->device_list_mutex); + mutex_lock(&fs_devices->device_list_mutex); list_for_each_entry(device, devices, dev_list) { if (device->bdev == bdev) { ret = -EEXIST; mutex_unlock( - &fs_info->fs_devices->device_list_mutex); + &fs_devices->device_list_mutex); goto error; } } - mutex_unlock(&fs_info->fs_devices->device_list_mutex); + mutex_unlock(&fs_devices->device_list_mutex); device = btrfs_alloc_device(fs_info, NULL, NULL); if (IS_ERR(device)) { @@ -2491,23 +2492,22 @@ int btrfs_init_new_device(struct btrfs_fs_info *fs_info, const char *device_path } } - device->fs_devices = fs_info->fs_devices; + device->fs_devices = fs_devices; - mutex_lock(&fs_info->fs_devices->device_list_mutex); + mutex_lock(&fs_devices->device_list_mutex); mutex_lock(&fs_info->chunk_mutex); - list_add_rcu(&device->dev_list, &fs_info->fs_devices->devices); - list_add(&device->dev_alloc_list, - &fs_info->fs_devices->alloc_list); - fs_info->fs_devices->num_devices++; - fs_info->fs_devices->open_devices++; - fs_info->fs_devices->rw_devices++; - fs_info->fs_devices->total_devices++; - fs_info->fs_devices->total_rw_bytes += device->total_bytes; + list_add_rcu(&device->dev_list, &fs_devices->devices); + list_add(&device->dev_alloc_list, &fs_devices->alloc_list); + fs_devices->num_devices++; + fs_devices->open_devices++; + fs_devices->rw_devices++; + fs_devices->total_devices++; + fs_devices->total_rw_bytes += device->total_bytes; atomic64_add(device->total_bytes, &fs_info->free_chunk_space); if (!blk_queue_nonrot(q)) - fs_info->fs_devices->rotating = 1; + fs_devices->rotating = 1; tmp = btrfs_super_total_bytes(fs_info->super_copy); btrfs_set_super_total_bytes(fs_info->super_copy, @@ -2517,7 +2517,7 @@ int btrfs_init_new_device(struct btrfs_fs_info *fs_info, const char *device_path btrfs_set_super_num_devices(fs_info->super_copy, tmp + 1); /* add sysfs device entry */ - btrfs_sysfs_add_device_link(fs_info->fs_devices, device); + btrfs_sysfs_add_device_link(fs_devices, device); /* * we've got more storage, clear any full flags on the space @@ -2526,7 +2526,7 @@ int btrfs_init_new_device(struct btrfs_fs_info *fs_info, const char *device_path btrfs_clear_space_info_full(fs_info); mutex_unlock(&fs_info->chunk_mutex); - mutex_unlock(&fs_info->fs_devices->device_list_mutex); + mutex_unlock(&fs_devices->device_list_mutex); if (seeding_dev) { mutex_lock(&fs_info->chunk_mutex); @@ -2558,7 +2558,7 @@ int btrfs_init_new_device(struct btrfs_fs_info *fs_info, const char *device_path */ snprintf(fsid_buf, BTRFS_UUID_UNPARSED_SIZE, "%pU", fs_info->fsid); - if (kobject_rename(&fs_info->fs_devices->fsid_kobj, fsid_buf)) + if (kobject_rename(&fs_devices->fsid_kobj, fsid_buf)) btrfs_warn(fs_info, "sysfs: failed to create fsid for sprout"); } @@ -2593,7 +2593,7 @@ int btrfs_init_new_device(struct btrfs_fs_info *fs_info, const char *device_path return ret; error_sysfs: - btrfs_sysfs_rm_device_link(fs_info->fs_devices, device); + btrfs_sysfs_rm_device_link(fs_devices, device); error_trans: if (seeding_dev) sb->s_flags |= SB_RDONLY; -- cgit v1.2.3 From 694c51fb2eb6b6d7c9552af78ba646023a843366 Mon Sep 17 00:00:00 2001 From: Anand Jain Date: Tue, 3 Jul 2018 13:14:51 +0800 Subject: btrfs: drop unnecessary variable in btrfs_init_new_device There is only usage of the declared devices variable, instead use its value directly. Signed-off-by: Anand Jain Reviewed-by: Nikolay Borisov Signed-off-by: David Sterba --- fs/btrfs/volumes.c | 5 +---- 1 file changed, 1 insertion(+), 4 deletions(-) (limited to 'fs') diff --git a/fs/btrfs/volumes.c b/fs/btrfs/volumes.c index adce1c2e9b7b..1ffc49c9c02f 100644 --- a/fs/btrfs/volumes.c +++ b/fs/btrfs/volumes.c @@ -2407,7 +2407,6 @@ int btrfs_init_new_device(struct btrfs_fs_info *fs_info, const char *device_path struct btrfs_trans_handle *trans; struct btrfs_device *device; struct block_device *bdev; - struct list_head *devices; struct super_block *sb = fs_info->sb; struct rcu_string *name; struct btrfs_fs_devices *fs_devices = fs_info->fs_devices; @@ -2432,10 +2431,8 @@ int btrfs_init_new_device(struct btrfs_fs_info *fs_info, const char *device_path filemap_write_and_wait(bdev->bd_inode->i_mapping); - devices = &fs_devices->devices; - mutex_lock(&fs_devices->device_list_mutex); - list_for_each_entry(device, devices, dev_list) { + list_for_each_entry(device, &fs_devices->devices, dev_list) { if (device->bdev == bdev) { ret = -EEXIST; mutex_unlock( -- cgit v1.2.3 From 8f6c72a9e08c2a74d2159d2fc986fa9b29ceb851 Mon Sep 17 00:00:00 2001 From: Zhihui Zhang Date: Mon, 2 Jul 2018 20:00:54 -0400 Subject: Btrfs: free space cache: make sure there is always room for generation number io_ctl_set_generation() assumes that the generation number shares the same page with inline CRCs. Let's make sure this is always true. Signed-off-by: Zhihui Zhang Reviewed-by: David Sterba Signed-off-by: David Sterba --- fs/btrfs/free-space-cache.c | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) (limited to 'fs') diff --git a/fs/btrfs/free-space-cache.c b/fs/btrfs/free-space-cache.c index d5f80cb300be..d2c0bdbd79ec 100644 --- a/fs/btrfs/free-space-cache.c +++ b/fs/btrfs/free-space-cache.c @@ -300,9 +300,9 @@ static int io_ctl_init(struct btrfs_io_ctl *io_ctl, struct inode *inode, if (btrfs_ino(BTRFS_I(inode)) != BTRFS_FREE_INO_OBJECTID) check_crcs = 1; - /* Make sure we can fit our crcs into the first page */ + /* Make sure we can fit our crcs and generation into the first page */ if (write && check_crcs && - (num_pages * sizeof(u32)) >= PAGE_SIZE) + (num_pages * sizeof(u32) + sizeof(u64)) > PAGE_SIZE) return -ENOSPC; memset(io_ctl, 0, sizeof(struct btrfs_io_ctl)); -- cgit v1.2.3 From 37508515621551538addaf826ab4b8a9aaf0a382 Mon Sep 17 00:00:00 2001 From: David Sterba Date: Fri, 29 Jun 2018 10:56:40 +0200 Subject: btrfs: simplify some assignments of inode numbers There are several places when the btrfs inode is converted to the generic inode, back to btrfs and then passed to btrfs_ino. We can remove the extra back and forth conversions. Signed-off-by: David Sterba --- fs/btrfs/inode.c | 12 ++++++------ 1 file changed, 6 insertions(+), 6 deletions(-) (limited to 'fs') diff --git a/fs/btrfs/inode.c b/fs/btrfs/inode.c index 2858bc355920..17816c455786 100644 --- a/fs/btrfs/inode.c +++ b/fs/btrfs/inode.c @@ -4242,9 +4242,9 @@ again: prev = node; entry = rb_entry(node, struct btrfs_inode, rb_node); - if (objectid < btrfs_ino(BTRFS_I(&entry->vfs_inode))) + if (objectid < btrfs_ino(entry)) node = node->rb_left; - else if (objectid > btrfs_ino(BTRFS_I(&entry->vfs_inode))) + else if (objectid > btrfs_ino(entry)) node = node->rb_right; else break; @@ -4252,7 +4252,7 @@ again: if (!node) { while (prev) { entry = rb_entry(prev, struct btrfs_inode, rb_node); - if (objectid <= btrfs_ino(BTRFS_I(&entry->vfs_inode))) { + if (objectid <= btrfs_ino(entry)) { node = prev; break; } @@ -4261,7 +4261,7 @@ again: } while (node) { entry = rb_entry(node, struct btrfs_inode, rb_node); - objectid = btrfs_ino(BTRFS_I(&entry->vfs_inode)) + 1; + objectid = btrfs_ino(entry) + 1; inode = igrab(&entry->vfs_inode); if (inode) { spin_unlock(&root->inode_lock); @@ -5614,9 +5614,9 @@ static void inode_tree_add(struct inode *inode) parent = *p; entry = rb_entry(parent, struct btrfs_inode, rb_node); - if (ino < btrfs_ino(BTRFS_I(&entry->vfs_inode))) + if (ino < btrfs_ino(entry)) p = &parent->rb_left; - else if (ino > btrfs_ino(BTRFS_I(&entry->vfs_inode))) + else if (ino > btrfs_ino(entry)) p = &parent->rb_right; else { WARN_ON(!(entry->vfs_inode.i_state & -- cgit v1.2.3 From 3ffbd68c48320730ef64ebfb5e639220f1f65483 Mon Sep 17 00:00:00 2001 From: David Sterba Date: Fri, 29 Jun 2018 10:56:42 +0200 Subject: btrfs: simplify pointer chasing of local fs_info variables Functions that get btrfs inode can simply reach the fs_info by dereferencing the root and this looks a bit more straightforward compared to the btrfs_sb(...) indirection. If the transaction handle is available and not NULL it's used instead. Signed-off-by: David Sterba --- fs/btrfs/delayed-inode.c | 4 ++-- fs/btrfs/disk-io.c | 2 +- fs/btrfs/extent-tree.c | 6 +++--- fs/btrfs/file-item.c | 2 +- fs/btrfs/file.c | 14 +++++++------- fs/btrfs/free-space-cache.c | 7 ++----- fs/btrfs/inode.c | 6 +++--- fs/btrfs/tree-log.c | 6 +++--- 8 files changed, 22 insertions(+), 25 deletions(-) (limited to 'fs') diff --git a/fs/btrfs/delayed-inode.c b/fs/btrfs/delayed-inode.c index fe6caa7e698b..596d2af0c8aa 100644 --- a/fs/btrfs/delayed-inode.c +++ b/fs/btrfs/delayed-inode.c @@ -1222,7 +1222,7 @@ int btrfs_commit_inode_delayed_items(struct btrfs_trans_handle *trans, int btrfs_commit_inode_delayed_inode(struct btrfs_inode *inode) { - struct btrfs_fs_info *fs_info = btrfs_sb(inode->vfs_inode.i_sb); + struct btrfs_fs_info *fs_info = inode->root->fs_info; struct btrfs_trans_handle *trans; struct btrfs_delayed_node *delayed_node = btrfs_get_delayed_node(inode); struct btrfs_path *path; @@ -1837,7 +1837,7 @@ release_node: int btrfs_delayed_delete_inode_ref(struct btrfs_inode *inode) { - struct btrfs_fs_info *fs_info = btrfs_sb(inode->vfs_inode.i_sb); + struct btrfs_fs_info *fs_info = inode->root->fs_info; struct btrfs_delayed_node *delayed_node; /* diff --git a/fs/btrfs/disk-io.c b/fs/btrfs/disk-io.c index c77afa9e5d91..e0baf2f3154d 100644 --- a/fs/btrfs/disk-io.c +++ b/fs/btrfs/disk-io.c @@ -212,7 +212,7 @@ struct extent_map *btree_get_extent(struct btrfs_inode *inode, struct page *page, size_t pg_offset, u64 start, u64 len, int create) { - struct btrfs_fs_info *fs_info = btrfs_sb(inode->vfs_inode.i_sb); + struct btrfs_fs_info *fs_info = inode->root->fs_info; struct extent_map_tree *em_tree = &inode->extent_tree; struct extent_map *em; int ret; diff --git a/fs/btrfs/extent-tree.c b/fs/btrfs/extent-tree.c index 352b7e95f657..6bba288133b8 100644 --- a/fs/btrfs/extent-tree.c +++ b/fs/btrfs/extent-tree.c @@ -5889,7 +5889,7 @@ static void btrfs_calculate_inode_block_rsv_size(struct btrfs_fs_info *fs_info, int btrfs_delalloc_reserve_metadata(struct btrfs_inode *inode, u64 num_bytes) { - struct btrfs_fs_info *fs_info = btrfs_sb(inode->vfs_inode.i_sb); + struct btrfs_fs_info *fs_info = inode->root->fs_info; unsigned nr_extents; enum btrfs_reserve_flush_enum flush = BTRFS_RESERVE_FLUSH_ALL; int ret = 0; @@ -5962,7 +5962,7 @@ out_fail: void btrfs_delalloc_release_metadata(struct btrfs_inode *inode, u64 num_bytes, bool qgroup_free) { - struct btrfs_fs_info *fs_info = btrfs_sb(inode->vfs_inode.i_sb); + struct btrfs_fs_info *fs_info = inode->root->fs_info; num_bytes = ALIGN(num_bytes, fs_info->sectorsize); spin_lock(&inode->lock); @@ -5991,7 +5991,7 @@ void btrfs_delalloc_release_metadata(struct btrfs_inode *inode, u64 num_bytes, void btrfs_delalloc_release_extents(struct btrfs_inode *inode, u64 num_bytes, bool qgroup_free) { - struct btrfs_fs_info *fs_info = btrfs_sb(inode->vfs_inode.i_sb); + struct btrfs_fs_info *fs_info = inode->root->fs_info; unsigned num_extents; spin_lock(&inode->lock); diff --git a/fs/btrfs/file-item.c b/fs/btrfs/file-item.c index 8c3cd7072caf..ba74827beb32 100644 --- a/fs/btrfs/file-item.c +++ b/fs/btrfs/file-item.c @@ -922,7 +922,7 @@ void btrfs_extent_item_to_extent_map(struct btrfs_inode *inode, const bool new_inline, struct extent_map *em) { - struct btrfs_fs_info *fs_info = btrfs_sb(inode->vfs_inode.i_sb); + struct btrfs_fs_info *fs_info = inode->root->fs_info; struct btrfs_root *root = inode->root; struct extent_buffer *leaf = path->nodes[0]; const int slot = path->slots[0]; diff --git a/fs/btrfs/file.c b/fs/btrfs/file.c index 89c9404fee9a..da53e45705ba 100644 --- a/fs/btrfs/file.c +++ b/fs/btrfs/file.c @@ -83,7 +83,7 @@ static int __compare_inode_defrag(struct inode_defrag *defrag1, static int __btrfs_add_inode_defrag(struct btrfs_inode *inode, struct inode_defrag *defrag) { - struct btrfs_fs_info *fs_info = btrfs_sb(inode->vfs_inode.i_sb); + struct btrfs_fs_info *fs_info = inode->root->fs_info; struct inode_defrag *entry; struct rb_node **p; struct rb_node *parent = NULL; @@ -135,8 +135,8 @@ static inline int __need_auto_defrag(struct btrfs_fs_info *fs_info) int btrfs_add_inode_defrag(struct btrfs_trans_handle *trans, struct btrfs_inode *inode) { - struct btrfs_fs_info *fs_info = btrfs_sb(inode->vfs_inode.i_sb); struct btrfs_root *root = inode->root; + struct btrfs_fs_info *fs_info = root->fs_info; struct inode_defrag *defrag; u64 transid; int ret; @@ -185,7 +185,7 @@ int btrfs_add_inode_defrag(struct btrfs_trans_handle *trans, static void btrfs_requeue_inode_defrag(struct btrfs_inode *inode, struct inode_defrag *defrag) { - struct btrfs_fs_info *fs_info = btrfs_sb(inode->vfs_inode.i_sb); + struct btrfs_fs_info *fs_info = inode->root->fs_info; int ret; if (!__need_auto_defrag(fs_info)) @@ -1132,7 +1132,7 @@ static int extent_mergeable(struct extent_buffer *leaf, int slot, int btrfs_mark_extent_written(struct btrfs_trans_handle *trans, struct btrfs_inode *inode, u64 start, u64 end) { - struct btrfs_fs_info *fs_info = btrfs_sb(inode->vfs_inode.i_sb); + struct btrfs_fs_info *fs_info = trans->fs_info; struct btrfs_root *root = inode->root; struct extent_buffer *leaf; struct btrfs_path *path; @@ -1469,7 +1469,7 @@ lock_and_cleanup_extent_if_need(struct btrfs_inode *inode, struct page **pages, u64 *lockstart, u64 *lockend, struct extent_state **cached_state) { - struct btrfs_fs_info *fs_info = btrfs_sb(inode->vfs_inode.i_sb); + struct btrfs_fs_info *fs_info = inode->root->fs_info; u64 start_pos; u64 last_pos; int i; @@ -1525,7 +1525,7 @@ lock_and_cleanup_extent_if_need(struct btrfs_inode *inode, struct page **pages, static noinline int check_can_nocow(struct btrfs_inode *inode, loff_t pos, size_t *write_bytes) { - struct btrfs_fs_info *fs_info = btrfs_sb(inode->vfs_inode.i_sb); + struct btrfs_fs_info *fs_info = inode->root->fs_info; struct btrfs_root *root = inode->root; struct btrfs_ordered_extent *ordered; u64 lockstart, lockend; @@ -2227,7 +2227,7 @@ static int fill_holes(struct btrfs_trans_handle *trans, struct btrfs_inode *inode, struct btrfs_path *path, u64 offset, u64 end) { - struct btrfs_fs_info *fs_info = btrfs_sb(inode->vfs_inode.i_sb); + struct btrfs_fs_info *fs_info = trans->fs_info; struct btrfs_root *root = inode->root; struct extent_buffer *leaf; struct btrfs_file_extent_item *fi; diff --git a/fs/btrfs/free-space-cache.c b/fs/btrfs/free-space-cache.c index d2c0bdbd79ec..354d55f22d99 100644 --- a/fs/btrfs/free-space-cache.c +++ b/fs/btrfs/free-space-cache.c @@ -655,7 +655,7 @@ static int __load_free_space_cache(struct btrfs_root *root, struct inode *inode, struct btrfs_free_space_ctl *ctl, struct btrfs_path *path, u64 offset) { - struct btrfs_fs_info *fs_info = btrfs_sb(inode->i_sb); + struct btrfs_fs_info *fs_info = root->fs_info; struct btrfs_free_space_header *header; struct extent_buffer *leaf; struct btrfs_io_ctl io_ctl; @@ -1123,13 +1123,10 @@ static int __btrfs_wait_cache_io(struct btrfs_root *root, { int ret; struct inode *inode = io_ctl->inode; - struct btrfs_fs_info *fs_info; if (!inode) return 0; - fs_info = btrfs_sb(inode->i_sb); - /* Flush the dirty pages in the cache file. */ ret = flush_dirty_cache(inode); if (ret) @@ -1145,7 +1142,7 @@ out: BTRFS_I(inode)->generation = 0; if (block_group) { #ifdef DEBUG - btrfs_err(fs_info, + btrfs_err(root->fs_info, "failed to write free space cache for block group %llu", block_group->key.objectid); #endif diff --git a/fs/btrfs/inode.c b/fs/btrfs/inode.c index 17816c455786..32613dca13c1 100644 --- a/fs/btrfs/inode.c +++ b/fs/btrfs/inode.c @@ -1751,7 +1751,7 @@ static void btrfs_add_delalloc_inodes(struct btrfs_root *root, void __btrfs_del_delalloc_inode(struct btrfs_root *root, struct btrfs_inode *inode) { - struct btrfs_fs_info *fs_info = btrfs_sb(inode->vfs_inode.i_sb); + struct btrfs_fs_info *fs_info = root->fs_info; if (!list_empty(&inode->delalloc_inodes)) { list_del_init(&inode->delalloc_inodes); @@ -6418,7 +6418,7 @@ int btrfs_add_link(struct btrfs_trans_handle *trans, struct btrfs_inode *parent_inode, struct btrfs_inode *inode, const char *name, int name_len, int add_backref, u64 index) { - struct btrfs_fs_info *fs_info = btrfs_sb(inode->vfs_inode.i_sb); + struct btrfs_fs_info *fs_info = trans->fs_info; int ret = 0; struct btrfs_key key; struct btrfs_root *root = parent_inode->root; @@ -6846,7 +6846,7 @@ struct extent_map *btrfs_get_extent(struct btrfs_inode *inode, size_t pg_offset, u64 start, u64 len, int create) { - struct btrfs_fs_info *fs_info = btrfs_sb(inode->vfs_inode.i_sb); + struct btrfs_fs_info *fs_info = inode->root->fs_info; int ret; int err = 0; u64 extent_start = 0; diff --git a/fs/btrfs/tree-log.c b/fs/btrfs/tree-log.c index 6bca8f88ade0..7b7498f1f641 100644 --- a/fs/btrfs/tree-log.c +++ b/fs/btrfs/tree-log.c @@ -3739,7 +3739,7 @@ static noinline int copy_items(struct btrfs_trans_handle *trans, int start_slot, int nr, int inode_only, u64 logged_isize) { - struct btrfs_fs_info *fs_info = btrfs_sb(inode->vfs_inode.i_sb); + struct btrfs_fs_info *fs_info = trans->fs_info; unsigned long src_offset; unsigned long dst_offset; struct btrfs_root *log = inode->root->log_root; @@ -5436,7 +5436,7 @@ static int btrfs_log_all_parents(struct btrfs_trans_handle *trans, struct btrfs_inode *inode, struct btrfs_log_ctx *ctx) { - struct btrfs_fs_info *fs_info = btrfs_sb(inode->vfs_inode.i_sb); + struct btrfs_fs_info *fs_info = trans->fs_info; int ret; struct btrfs_path *path; struct btrfs_key key; @@ -5971,7 +5971,7 @@ int btrfs_log_new_name(struct btrfs_trans_handle *trans, struct btrfs_inode *inode, struct btrfs_inode *old_dir, struct dentry *parent) { - struct btrfs_fs_info *fs_info = btrfs_sb(inode->vfs_inode.i_sb); + struct btrfs_fs_info *fs_info = trans->fs_info; /* * this will force the logging code to walk the dentry chain -- cgit v1.2.3 From 69d2480456d1baf027a86e530989d7bedd698d5f Mon Sep 17 00:00:00 2001 From: David Sterba Date: Fri, 29 Jun 2018 10:56:44 +0200 Subject: btrfs: use copy_page for copying pages instead of memcpy Use the helper that's possibly optimized for full page copies. Signed-off-by: David Sterba --- fs/btrfs/free-space-cache.c | 4 ++-- fs/btrfs/raid56.c | 12 +++++------- 2 files changed, 7 insertions(+), 9 deletions(-) (limited to 'fs') diff --git a/fs/btrfs/free-space-cache.c b/fs/btrfs/free-space-cache.c index 354d55f22d99..57e7ab7f5e03 100644 --- a/fs/btrfs/free-space-cache.c +++ b/fs/btrfs/free-space-cache.c @@ -547,7 +547,7 @@ static int io_ctl_add_bitmap(struct btrfs_io_ctl *io_ctl, void *bitmap) io_ctl_map_page(io_ctl, 0); } - memcpy(io_ctl->cur, bitmap, PAGE_SIZE); + copy_page(io_ctl->cur, bitmap); io_ctl_set_crc(io_ctl, io_ctl->index - 1); if (io_ctl->index < io_ctl->num_pages) io_ctl_map_page(io_ctl, 0); @@ -607,7 +607,7 @@ static int io_ctl_read_bitmap(struct btrfs_io_ctl *io_ctl, if (ret) return ret; - memcpy(entry->bitmap, io_ctl->cur, PAGE_SIZE); + copy_page(entry->bitmap, io_ctl->cur); io_ctl_unmap_page(io_ctl); return 0; diff --git a/fs/btrfs/raid56.c b/fs/btrfs/raid56.c index 5e4ad134b9ad..27ed47a23f26 100644 --- a/fs/btrfs/raid56.c +++ b/fs/btrfs/raid56.c @@ -260,7 +260,7 @@ static void cache_rbio_pages(struct btrfs_raid_bio *rbio) s = kmap(rbio->bio_pages[i]); d = kmap(rbio->stripe_pages[i]); - memcpy(d, s, PAGE_SIZE); + copy_page(d, s); kunmap(rbio->bio_pages[i]); kunmap(rbio->stripe_pages[i]); @@ -1275,7 +1275,7 @@ static noinline void finish_rmw(struct btrfs_raid_bio *rbio) pointers); } else { /* raid5 */ - memcpy(pointers[nr_data], pointers[0], PAGE_SIZE); + copy_page(pointers[nr_data], pointers[0]); run_xor(pointers + 1, nr_data - 1, PAGE_SIZE); } @@ -1941,9 +1941,7 @@ static void __raid_recover_end_io(struct btrfs_raid_bio *rbio) BUG_ON(failb != -1); pstripe: /* Copy parity block into failed block to start with */ - memcpy(pointers[faila], - pointers[rbio->nr_data], - PAGE_SIZE); + copy_page(pointers[faila], pointers[rbio->nr_data]); /* rearrange the pointer array */ p = pointers[faila]; @@ -2448,7 +2446,7 @@ static noinline void finish_parity_scrub(struct btrfs_raid_bio *rbio, pointers); } else { /* raid5 */ - memcpy(pointers[nr_data], pointers[0], PAGE_SIZE); + copy_page(pointers[nr_data], pointers[0]); run_xor(pointers + 1, nr_data - 1, PAGE_SIZE); } @@ -2456,7 +2454,7 @@ static noinline void finish_parity_scrub(struct btrfs_raid_bio *rbio, p = rbio_stripe_page(rbio, rbio->scrubp, pagenr); parity = kmap(p); if (memcmp(parity, pointers[rbio->scrubp], PAGE_SIZE)) - memcpy(parity, pointers[rbio->scrubp], PAGE_SIZE); + copy_page(parity, pointers[rbio->scrubp]); else /* Parity is right, needn't writeback */ bitmap_clear(rbio->dbitmap, pagenr, 1); -- cgit v1.2.3 From d7f663fa3ff906247a979c1115bc92cbabfb19ba Mon Sep 17 00:00:00 2001 From: David Sterba Date: Fri, 29 Jun 2018 10:56:47 +0200 Subject: btrfs: prune unused includes Remove includes if none of the interfaces and exports is used in the given source file. Signed-off-by: David Sterba --- fs/btrfs/compression.c | 4 ---- fs/btrfs/dev-replace.c | 5 ----- fs/btrfs/disk-io.c | 2 -- fs/btrfs/file.c | 3 --- fs/btrfs/inode-map.c | 1 - fs/btrfs/inode.c | 4 ---- fs/btrfs/ioctl.c | 5 ----- fs/btrfs/ordered-data.c | 1 - fs/btrfs/raid56.c | 13 ------------- fs/btrfs/reada.c | 1 - fs/btrfs/struct-funcs.c | 1 - fs/btrfs/super.c | 3 --- fs/btrfs/sysfs.c | 2 -- fs/btrfs/volumes.c | 3 --- 14 files changed, 48 deletions(-) (limited to 'fs') diff --git a/fs/btrfs/compression.c b/fs/btrfs/compression.c index d3e447b45bf7..f48794a36068 100644 --- a/fs/btrfs/compression.c +++ b/fs/btrfs/compression.c @@ -5,7 +5,6 @@ #include #include -#include #include #include #include @@ -14,10 +13,7 @@ #include #include #include -#include -#include #include -#include #include #include #include diff --git a/fs/btrfs/dev-replace.c b/fs/btrfs/dev-replace.c index 1b30c38d05c9..059ca3d5ddd3 100644 --- a/fs/btrfs/dev-replace.c +++ b/fs/btrfs/dev-replace.c @@ -6,14 +6,9 @@ #include #include #include -#include #include -#include -#include -#include #include #include -#include #include "ctree.h" #include "extent_map.h" #include "disk-io.h" diff --git a/fs/btrfs/disk-io.c b/fs/btrfs/disk-io.c index e0baf2f3154d..6023eed3e805 100644 --- a/fs/btrfs/disk-io.c +++ b/fs/btrfs/disk-io.c @@ -5,8 +5,6 @@ #include #include -#include -#include #include #include #include diff --git a/fs/btrfs/file.c b/fs/btrfs/file.c index da53e45705ba..2be00e873e92 100644 --- a/fs/btrfs/file.c +++ b/fs/btrfs/file.c @@ -5,14 +5,11 @@ #include #include -#include #include #include #include #include -#include #include -#include #include #include #include diff --git a/fs/btrfs/inode-map.c b/fs/btrfs/inode-map.c index a56f88ea9c73..ffca2abf13d0 100644 --- a/fs/btrfs/inode-map.c +++ b/fs/btrfs/inode-map.c @@ -3,7 +3,6 @@ * Copyright (C) 2007 Oracle. All rights reserved. */ -#include #include #include diff --git a/fs/btrfs/inode.c b/fs/btrfs/inode.c index 32613dca13c1..ada8a698af10 100644 --- a/fs/btrfs/inode.c +++ b/fs/btrfs/inode.c @@ -14,17 +14,13 @@ #include #include #include -#include -#include #include #include -#include #include #include #include #include #include -#include #include #include #include diff --git a/fs/btrfs/ioctl.c b/fs/btrfs/ioctl.c index 08b8c0b346b3..802918507cc0 100644 --- a/fs/btrfs/ioctl.c +++ b/fs/btrfs/ioctl.c @@ -5,23 +5,18 @@ #include #include -#include #include #include #include #include #include #include -#include #include #include #include -#include #include -#include #include #include -#include #include #include #include diff --git a/fs/btrfs/ordered-data.c b/fs/btrfs/ordered-data.c index e173b252d795..0c4ef208b8b9 100644 --- a/fs/btrfs/ordered-data.c +++ b/fs/btrfs/ordered-data.c @@ -6,7 +6,6 @@ #include #include #include -#include #include "ctree.h" #include "transaction.h" #include "btrfs_inode.h" diff --git a/fs/btrfs/raid56.c b/fs/btrfs/raid56.c index 27ed47a23f26..42631079c492 100644 --- a/fs/btrfs/raid56.c +++ b/fs/btrfs/raid56.c @@ -5,32 +5,19 @@ */ #include -#include #include #include -#include #include -#include -#include -#include -#include -#include #include #include #include #include #include -#include #include "ctree.h" -#include "extent_map.h" #include "disk-io.h" -#include "transaction.h" -#include "print-tree.h" #include "volumes.h" #include "raid56.h" #include "async-thread.h" -#include "check-integrity.h" -#include "rcu-string.h" /* set when additional merges to this rbio are not allowed */ #define RBIO_RMW_LOCKED_BIT 1 diff --git a/fs/btrfs/reada.c b/fs/btrfs/reada.c index 4be425f70c2d..dec14b739b10 100644 --- a/fs/btrfs/reada.c +++ b/fs/btrfs/reada.c @@ -7,7 +7,6 @@ #include #include #include -#include #include #include #include "ctree.h" diff --git a/fs/btrfs/struct-funcs.c b/fs/btrfs/struct-funcs.c index b7b4acb12833..4c13b737f568 100644 --- a/fs/btrfs/struct-funcs.c +++ b/fs/btrfs/struct-funcs.c @@ -3,7 +3,6 @@ * Copyright (C) 2007 Oracle. All rights reserved. */ -#include #include #include "ctree.h" diff --git a/fs/btrfs/super.c b/fs/btrfs/super.c index 3c5f221b5303..e04bcf0b0ed4 100644 --- a/fs/btrfs/super.c +++ b/fs/btrfs/super.c @@ -5,7 +5,6 @@ #include #include -#include #include #include #include @@ -15,8 +14,6 @@ #include #include #include -#include -#include #include #include #include diff --git a/fs/btrfs/sysfs.c b/fs/btrfs/sysfs.c index 4a4e960c7c66..3717c864ba23 100644 --- a/fs/btrfs/sysfs.c +++ b/fs/btrfs/sysfs.c @@ -7,10 +7,8 @@ #include #include #include -#include #include #include -#include #include #include "ctree.h" diff --git a/fs/btrfs/volumes.c b/fs/btrfs/volumes.c index 1ffc49c9c02f..211fb2161487 100644 --- a/fs/btrfs/volumes.c +++ b/fs/btrfs/volumes.c @@ -8,15 +8,12 @@ #include #include #include -#include -#include #include #include #include #include #include #include -#include #include "ctree.h" #include "extent_map.h" #include "disk-io.h" -- cgit v1.2.3 From 65ad010488a5cc0f123a9924f7ad26a1b3f6a4f6 Mon Sep 17 00:00:00 2001 From: David Sterba Date: Fri, 29 Jun 2018 10:56:49 +0200 Subject: btrfs: pass only eb to num_extent_pages Almost all callers pass the start and len as 2 arguments but this is not necessary, all the information is provided by the eb. By reordering the calls to num_extent_pages, we don't need the local variables with start/len. Reviewed-by: Nikolay Borisov Signed-off-by: David Sterba --- fs/btrfs/extent_io.c | 30 +++++++++++++++--------------- fs/btrfs/extent_io.h | 6 +++--- 2 files changed, 18 insertions(+), 18 deletions(-) (limited to 'fs') diff --git a/fs/btrfs/extent_io.c b/fs/btrfs/extent_io.c index b3e45714d28f..fd34c749209e 100644 --- a/fs/btrfs/extent_io.c +++ b/fs/btrfs/extent_io.c @@ -2059,7 +2059,7 @@ int repair_eb_io_failure(struct btrfs_fs_info *fs_info, struct extent_buffer *eb, int mirror_num) { u64 start = eb->start; - unsigned long i, num_pages = num_extent_pages(eb->start, eb->len); + unsigned long i, num_pages = num_extent_pages(eb); int ret = 0; if (sb_rdonly(fs_info->sb)) @@ -3588,7 +3588,7 @@ lock_extent_buffer_for_io(struct extent_buffer *eb, if (!ret) return ret; - num_pages = num_extent_pages(eb->start, eb->len); + num_pages = num_extent_pages(eb); for (i = 0; i < num_pages; i++) { struct page *p = eb->pages[i]; @@ -3718,7 +3718,7 @@ static noinline_for_stack int write_one_eb(struct extent_buffer *eb, int ret = 0; clear_bit(EXTENT_BUFFER_WRITE_ERR, &eb->bflags); - num_pages = num_extent_pages(eb->start, eb->len); + num_pages = num_extent_pages(eb); atomic_set(&eb->io_pages, num_pages); /* set btree blocks beyond nritems with 0 to avoid stale content. */ @@ -4653,7 +4653,7 @@ static void btrfs_release_extent_buffer_page(struct extent_buffer *eb) BUG_ON(extent_buffer_under_io(eb)); - index = num_extent_pages(eb->start, eb->len); + index = num_extent_pages(eb); if (index == 0) return; @@ -4746,7 +4746,7 @@ struct extent_buffer *btrfs_clone_extent_buffer(struct extent_buffer *src) unsigned long i; struct page *p; struct extent_buffer *new; - unsigned long num_pages = num_extent_pages(src->start, src->len); + unsigned long num_pages = num_extent_pages(src); new = __alloc_extent_buffer(src->fs_info, src->start, src->len); if (new == NULL) @@ -4778,12 +4778,11 @@ struct extent_buffer *__alloc_dummy_extent_buffer(struct btrfs_fs_info *fs_info, unsigned long num_pages; unsigned long i; - num_pages = num_extent_pages(start, len); - eb = __alloc_extent_buffer(fs_info, start, len); if (!eb) return NULL; + num_pages = num_extent_pages(eb); for (i = 0; i < num_pages; i++) { eb->pages[i] = alloc_page(GFP_NOFS); if (!eb->pages[i]) @@ -4847,7 +4846,7 @@ static void mark_extent_buffer_accessed(struct extent_buffer *eb, check_buffer_tree_ref(eb); - num_pages = num_extent_pages(eb->start, eb->len); + num_pages = num_extent_pages(eb); for (i = 0; i < num_pages; i++) { struct page *p = eb->pages[i]; @@ -4944,7 +4943,7 @@ struct extent_buffer *alloc_extent_buffer(struct btrfs_fs_info *fs_info, u64 start) { unsigned long len = fs_info->nodesize; - unsigned long num_pages = num_extent_pages(start, len); + unsigned long num_pages; unsigned long i; unsigned long index = start >> PAGE_SHIFT; struct extent_buffer *eb; @@ -4967,6 +4966,7 @@ struct extent_buffer *alloc_extent_buffer(struct btrfs_fs_info *fs_info, if (!eb) return ERR_PTR(-ENOMEM); + num_pages = num_extent_pages(eb); for (i = 0; i < num_pages; i++, index++) { p = find_or_create_page(mapping, index, GFP_NOFS|__GFP_NOFAIL); if (!p) { @@ -5163,7 +5163,7 @@ void clear_extent_buffer_dirty(struct extent_buffer *eb) unsigned long num_pages; struct page *page; - num_pages = num_extent_pages(eb->start, eb->len); + num_pages = num_extent_pages(eb); for (i = 0; i < num_pages; i++) { page = eb->pages[i]; @@ -5197,7 +5197,7 @@ int set_extent_buffer_dirty(struct extent_buffer *eb) was_dirty = test_and_set_bit(EXTENT_BUFFER_DIRTY, &eb->bflags); - num_pages = num_extent_pages(eb->start, eb->len); + num_pages = num_extent_pages(eb); WARN_ON(atomic_read(&eb->refs) == 0); WARN_ON(!test_bit(EXTENT_BUFFER_TREE_REF, &eb->bflags)); @@ -5213,7 +5213,7 @@ void clear_extent_buffer_uptodate(struct extent_buffer *eb) unsigned long num_pages; clear_bit(EXTENT_BUFFER_UPTODATE, &eb->bflags); - num_pages = num_extent_pages(eb->start, eb->len); + num_pages = num_extent_pages(eb); for (i = 0; i < num_pages; i++) { page = eb->pages[i]; if (page) @@ -5228,7 +5228,7 @@ void set_extent_buffer_uptodate(struct extent_buffer *eb) unsigned long num_pages; set_bit(EXTENT_BUFFER_UPTODATE, &eb->bflags); - num_pages = num_extent_pages(eb->start, eb->len); + num_pages = num_extent_pages(eb); for (i = 0; i < num_pages; i++) { page = eb->pages[i]; SetPageUptodate(page); @@ -5252,7 +5252,7 @@ int read_extent_buffer_pages(struct extent_io_tree *tree, if (test_bit(EXTENT_BUFFER_UPTODATE, &eb->bflags)) return 0; - num_pages = num_extent_pages(eb->start, eb->len); + num_pages = num_extent_pages(eb); for (i = 0; i < num_pages; i++) { page = eb->pages[i]; if (wait == WAIT_NONE) { @@ -5580,7 +5580,7 @@ void copy_extent_buffer_full(struct extent_buffer *dst, ASSERT(dst->len == src->len); - num_pages = num_extent_pages(dst->start, dst->len); + num_pages = num_extent_pages(dst); for (i = 0; i < num_pages; i++) copy_page(page_address(dst->pages[i]), page_address(src->pages[i])); diff --git a/fs/btrfs/extent_io.h b/fs/btrfs/extent_io.h index 0bfd4aeb822d..d8382a4a7f46 100644 --- a/fs/btrfs/extent_io.h +++ b/fs/btrfs/extent_io.h @@ -440,10 +440,10 @@ int read_extent_buffer_pages(struct extent_io_tree *tree, int mirror_num); void wait_on_extent_buffer_writeback(struct extent_buffer *eb); -static inline unsigned long num_extent_pages(u64 start, u64 len) +static inline unsigned long num_extent_pages(const struct extent_buffer *eb) { - return ((start + len + PAGE_SIZE - 1) >> PAGE_SHIFT) - - (start >> PAGE_SHIFT); + return ((eb->start + eb->len + PAGE_SIZE - 1) >> PAGE_SHIFT) - + (eb->start >> PAGE_SHIFT); } static inline void extent_buffer_get(struct extent_buffer *eb) -- cgit v1.2.3 From 8791d43207966f40d8ffba18c663514aca5a6f3e Mon Sep 17 00:00:00 2001 From: David Sterba Date: Wed, 4 Jul 2018 17:49:31 +0200 Subject: btrfs: use round_up wrapper in num_extent_pages Reviewed-by: Nikolay Borisov Signed-off-by: David Sterba --- fs/btrfs/extent_io.h | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) (limited to 'fs') diff --git a/fs/btrfs/extent_io.h b/fs/btrfs/extent_io.h index d8382a4a7f46..7a3c15b55f2b 100644 --- a/fs/btrfs/extent_io.h +++ b/fs/btrfs/extent_io.h @@ -442,8 +442,8 @@ void wait_on_extent_buffer_writeback(struct extent_buffer *eb); static inline unsigned long num_extent_pages(const struct extent_buffer *eb) { - return ((eb->start + eb->len + PAGE_SIZE - 1) >> PAGE_SHIFT) - - (eb->start >> PAGE_SHIFT); + return (round_up(eb->start + eb->len, PAGE_SIZE) >> PAGE_SHIFT) - + (eb->start >> PAGE_SHIFT); } static inline void extent_buffer_get(struct extent_buffer *eb) -- cgit v1.2.3 From cc5e31a4775d0d6b98139fdee51868a270bda42f Mon Sep 17 00:00:00 2001 From: David Sterba Date: Thu, 1 Mar 2018 18:20:27 +0100 Subject: btrfs: switch types to int when counting eb pages The loops iterating eb pages use unsigned long, that's an overkill as we know that there are at most 16 pages (64k / 4k), and 4 by default (with nodesize 16k). Reviewed-by: Nikolay Borisov Signed-off-by: David Sterba --- fs/btrfs/extent_io.c | 44 ++++++++++++++++++++++---------------------- fs/btrfs/extent_io.h | 2 +- 2 files changed, 23 insertions(+), 23 deletions(-) (limited to 'fs') diff --git a/fs/btrfs/extent_io.c b/fs/btrfs/extent_io.c index fd34c749209e..4fc37e284a79 100644 --- a/fs/btrfs/extent_io.c +++ b/fs/btrfs/extent_io.c @@ -2059,7 +2059,7 @@ int repair_eb_io_failure(struct btrfs_fs_info *fs_info, struct extent_buffer *eb, int mirror_num) { u64 start = eb->start; - unsigned long i, num_pages = num_extent_pages(eb); + int i, num_pages = num_extent_pages(eb); int ret = 0; if (sb_rdonly(fs_info->sb)) @@ -3538,7 +3538,7 @@ lock_extent_buffer_for_io(struct extent_buffer *eb, struct btrfs_fs_info *fs_info, struct extent_page_data *epd) { - unsigned long i, num_pages; + int i, num_pages; int flush = 0; int ret = 0; @@ -3712,7 +3712,7 @@ static noinline_for_stack int write_one_eb(struct extent_buffer *eb, struct extent_io_tree *tree = &BTRFS_I(fs_info->btree_inode)->io_tree; u64 offset = eb->start; u32 nritems; - unsigned long i, num_pages; + int i, num_pages; unsigned long start, end; unsigned int write_flags = wbc_to_write_flags(wbc) | REQ_META; int ret = 0; @@ -4647,7 +4647,7 @@ int extent_buffer_under_io(struct extent_buffer *eb) */ static void btrfs_release_extent_buffer_page(struct extent_buffer *eb) { - unsigned long index; + int index; struct page *page; int mapped = !test_bit(EXTENT_BUFFER_DUMMY, &eb->bflags); @@ -4743,10 +4743,10 @@ __alloc_extent_buffer(struct btrfs_fs_info *fs_info, u64 start, struct extent_buffer *btrfs_clone_extent_buffer(struct extent_buffer *src) { - unsigned long i; + int i; struct page *p; struct extent_buffer *new; - unsigned long num_pages = num_extent_pages(src); + int num_pages = num_extent_pages(src); new = __alloc_extent_buffer(src->fs_info, src->start, src->len); if (new == NULL) @@ -4775,8 +4775,8 @@ struct extent_buffer *__alloc_dummy_extent_buffer(struct btrfs_fs_info *fs_info, u64 start, unsigned long len) { struct extent_buffer *eb; - unsigned long num_pages; - unsigned long i; + int num_pages; + int i; eb = __alloc_extent_buffer(fs_info, start, len); if (!eb) @@ -4842,7 +4842,7 @@ static void check_buffer_tree_ref(struct extent_buffer *eb) static void mark_extent_buffer_accessed(struct extent_buffer *eb, struct page *accessed) { - unsigned long num_pages, i; + int num_pages, i; check_buffer_tree_ref(eb); @@ -4943,8 +4943,8 @@ struct extent_buffer *alloc_extent_buffer(struct btrfs_fs_info *fs_info, u64 start) { unsigned long len = fs_info->nodesize; - unsigned long num_pages; - unsigned long i; + int num_pages; + int i; unsigned long index = start >> PAGE_SHIFT; struct extent_buffer *eb; struct extent_buffer *exists = NULL; @@ -5159,8 +5159,8 @@ void free_extent_buffer_stale(struct extent_buffer *eb) void clear_extent_buffer_dirty(struct extent_buffer *eb) { - unsigned long i; - unsigned long num_pages; + int i; + int num_pages; struct page *page; num_pages = num_extent_pages(eb); @@ -5189,8 +5189,8 @@ void clear_extent_buffer_dirty(struct extent_buffer *eb) int set_extent_buffer_dirty(struct extent_buffer *eb) { - unsigned long i; - unsigned long num_pages; + int i; + int num_pages; int was_dirty = 0; check_buffer_tree_ref(eb); @@ -5208,9 +5208,9 @@ int set_extent_buffer_dirty(struct extent_buffer *eb) void clear_extent_buffer_uptodate(struct extent_buffer *eb) { - unsigned long i; + int i; struct page *page; - unsigned long num_pages; + int num_pages; clear_bit(EXTENT_BUFFER_UPTODATE, &eb->bflags); num_pages = num_extent_pages(eb); @@ -5223,9 +5223,9 @@ void clear_extent_buffer_uptodate(struct extent_buffer *eb) void set_extent_buffer_uptodate(struct extent_buffer *eb) { - unsigned long i; + int i; struct page *page; - unsigned long num_pages; + int num_pages; set_bit(EXTENT_BUFFER_UPTODATE, &eb->bflags); num_pages = num_extent_pages(eb); @@ -5238,13 +5238,13 @@ void set_extent_buffer_uptodate(struct extent_buffer *eb) int read_extent_buffer_pages(struct extent_io_tree *tree, struct extent_buffer *eb, int wait, int mirror_num) { - unsigned long i; + int i; struct page *page; int err; int ret = 0; int locked_pages = 0; int all_uptodate = 1; - unsigned long num_pages; + int num_pages; unsigned long num_reads = 0; struct bio *bio = NULL; unsigned long bio_flags = 0; @@ -5576,7 +5576,7 @@ void copy_extent_buffer_full(struct extent_buffer *dst, struct extent_buffer *src) { int i; - unsigned num_pages; + int num_pages; ASSERT(dst->len == src->len); diff --git a/fs/btrfs/extent_io.h b/fs/btrfs/extent_io.h index 7a3c15b55f2b..48f1ee9ad379 100644 --- a/fs/btrfs/extent_io.h +++ b/fs/btrfs/extent_io.h @@ -440,7 +440,7 @@ int read_extent_buffer_pages(struct extent_io_tree *tree, int mirror_num); void wait_on_extent_buffer_writeback(struct extent_buffer *eb); -static inline unsigned long num_extent_pages(const struct extent_buffer *eb) +static inline int num_extent_pages(const struct extent_buffer *eb) { return (round_up(eb->start + eb->len, PAGE_SIZE) >> PAGE_SHIFT) - (eb->start >> PAGE_SHIFT); -- cgit v1.2.3 From ebcc326316f3d798e9715e5ca1451c3e457b95dd Mon Sep 17 00:00:00 2001 From: David Sterba Date: Fri, 29 Jun 2018 10:56:53 +0200 Subject: btrfs: open-code bio_set_op_attrs The helper is trivial and marked as deprecated. Signed-off-by: David Sterba --- fs/btrfs/check-integrity.c | 2 +- fs/btrfs/compression.c | 4 ++-- fs/btrfs/extent_io.c | 2 +- fs/btrfs/inode.c | 2 +- fs/btrfs/raid56.c | 10 +++++----- fs/btrfs/scrub.c | 6 +++--- 6 files changed, 13 insertions(+), 13 deletions(-) (limited to 'fs') diff --git a/fs/btrfs/check-integrity.c b/fs/btrfs/check-integrity.c index daf45472bef9..833cf3c35b4d 100644 --- a/fs/btrfs/check-integrity.c +++ b/fs/btrfs/check-integrity.c @@ -1629,7 +1629,7 @@ static int btrfsic_read_block(struct btrfsic_state *state, bio = btrfs_io_bio_alloc(num_pages - i); bio_set_dev(bio, block_ctx->dev->bdev); bio->bi_iter.bi_sector = dev_bytenr >> 9; - bio_set_op_attrs(bio, REQ_OP_READ, 0); + bio->bi_opf = REQ_OP_READ; for (j = i; j < num_pages; j++) { ret = bio_add_page(bio, block_ctx->pagev[j], diff --git a/fs/btrfs/compression.c b/fs/btrfs/compression.c index f48794a36068..70dace47258b 100644 --- a/fs/btrfs/compression.c +++ b/fs/btrfs/compression.c @@ -609,7 +609,7 @@ blk_status_t btrfs_submit_compressed_read(struct inode *inode, struct bio *bio, cb->len = bio->bi_iter.bi_size; comp_bio = btrfs_bio_alloc(bdev, cur_disk_byte); - bio_set_op_attrs (comp_bio, REQ_OP_READ, 0); + comp_bio->bi_opf = REQ_OP_READ; comp_bio->bi_private = cb; comp_bio->bi_end_io = end_compressed_bio_read; refcount_set(&cb->pending_bios, 1); @@ -656,7 +656,7 @@ blk_status_t btrfs_submit_compressed_read(struct inode *inode, struct bio *bio, } comp_bio = btrfs_bio_alloc(bdev, cur_disk_byte); - bio_set_op_attrs(comp_bio, REQ_OP_READ, 0); + comp_bio->bi_opf = REQ_OP_READ; comp_bio->bi_private = cb; comp_bio->bi_end_io = end_compressed_bio_read; diff --git a/fs/btrfs/extent_io.c b/fs/btrfs/extent_io.c index 4fc37e284a79..fea015be4ce1 100644 --- a/fs/btrfs/extent_io.c +++ b/fs/btrfs/extent_io.c @@ -2398,7 +2398,7 @@ static int bio_readpage_error(struct bio *failed_bio, u64 phy_offset, start - page_offset(page), (int)phy_offset, failed_bio->bi_end_io, NULL); - bio_set_op_attrs(bio, REQ_OP_READ, read_mode); + bio->bi_opf = REQ_OP_READ | read_mode; btrfs_debug(btrfs_sb(inode->i_sb), "Repair Read Error: submitting new read[%#x] to this_mirror=%d, in_validation=%d", diff --git a/fs/btrfs/inode.c b/fs/btrfs/inode.c index ada8a698af10..564ec00c765b 100644 --- a/fs/btrfs/inode.c +++ b/fs/btrfs/inode.c @@ -7861,7 +7861,7 @@ static blk_status_t dio_read_error(struct inode *inode, struct bio *failed_bio, isector >>= inode->i_sb->s_blocksize_bits; bio = btrfs_create_repair_bio(inode, failed_bio, failrec, page, pgoff, isector, repair_endio, repair_arg); - bio_set_op_attrs(bio, REQ_OP_READ, read_mode); + bio->bi_opf = REQ_OP_READ | read_mode; btrfs_debug(BTRFS_I(inode)->root->fs_info, "repair DIO read error: submitting new dio read[%#x] to this_mirror=%d, in_validation=%d", diff --git a/fs/btrfs/raid56.c b/fs/btrfs/raid56.c index 42631079c492..1a1b7d6c44cb 100644 --- a/fs/btrfs/raid56.c +++ b/fs/btrfs/raid56.c @@ -1330,7 +1330,7 @@ write_data: bio->bi_private = rbio; bio->bi_end_io = raid_write_end_io; - bio_set_op_attrs(bio, REQ_OP_WRITE, 0); + bio->bi_opf = REQ_OP_WRITE; submit_bio(bio); } @@ -1586,7 +1586,7 @@ static int raid56_rmw_stripe(struct btrfs_raid_bio *rbio) bio->bi_private = rbio; bio->bi_end_io = raid_rmw_end_io; - bio_set_op_attrs(bio, REQ_OP_READ, 0); + bio->bi_opf = REQ_OP_READ; btrfs_bio_wq_end_io(rbio->fs_info, bio, BTRFS_WQ_ENDIO_RAID56); @@ -2130,7 +2130,7 @@ static int __raid56_parity_recover(struct btrfs_raid_bio *rbio) bio->bi_private = rbio; bio->bi_end_io = raid_recover_end_io; - bio_set_op_attrs(bio, REQ_OP_READ, 0); + bio->bi_opf = REQ_OP_READ; btrfs_bio_wq_end_io(rbio->fs_info, bio, BTRFS_WQ_ENDIO_RAID56); @@ -2502,7 +2502,7 @@ submit_write: bio->bi_private = rbio; bio->bi_end_io = raid_write_end_io; - bio_set_op_attrs(bio, REQ_OP_WRITE, 0); + bio->bi_opf = REQ_OP_WRITE; submit_bio(bio); } @@ -2684,7 +2684,7 @@ static void raid56_parity_scrub_stripe(struct btrfs_raid_bio *rbio) bio->bi_private = rbio; bio->bi_end_io = raid56_parity_scrub_end_io; - bio_set_op_attrs(bio, REQ_OP_READ, 0); + bio->bi_opf = REQ_OP_READ; btrfs_bio_wq_end_io(rbio->fs_info, bio, BTRFS_WQ_ENDIO_RAID56); diff --git a/fs/btrfs/scrub.c b/fs/btrfs/scrub.c index 67bb003323e7..bf4f262f9a52 100644 --- a/fs/btrfs/scrub.c +++ b/fs/btrfs/scrub.c @@ -1842,7 +1842,7 @@ static int scrub_repair_page_from_good_copy(struct scrub_block *sblock_bad, bio = btrfs_io_bio_alloc(1); bio_set_dev(bio, page_bad->dev->bdev); bio->bi_iter.bi_sector = page_bad->physical >> 9; - bio_set_op_attrs(bio, REQ_OP_WRITE, 0); + bio->bi_opf = REQ_OP_WRITE; ret = bio_add_page(bio, page_good->page, PAGE_SIZE, 0); if (PAGE_SIZE != ret) { @@ -1937,7 +1937,7 @@ again: bio->bi_end_io = scrub_wr_bio_end_io; bio_set_dev(bio, sbio->dev->bdev); bio->bi_iter.bi_sector = sbio->physical >> 9; - bio_set_op_attrs(bio, REQ_OP_WRITE, 0); + bio->bi_opf = REQ_OP_WRITE; sbio->status = 0; } else if (sbio->physical + sbio->page_count * PAGE_SIZE != spage->physical_for_dev_replace || @@ -2337,7 +2337,7 @@ again: bio->bi_end_io = scrub_bio_end_io; bio_set_dev(bio, sbio->dev->bdev); bio->bi_iter.bi_sector = sbio->physical >> 9; - bio_set_op_attrs(bio, REQ_OP_READ, 0); + bio->bi_opf = REQ_OP_READ; sbio->status = 0; } else if (sbio->physical + sbio->page_count * PAGE_SIZE != spage->physical || -- cgit v1.2.3 From ac63885907ee25bf277fa39ba66a0d85dec20786 Mon Sep 17 00:00:00 2001 From: David Sterba Date: Fri, 29 Jun 2018 10:56:56 +0200 Subject: btrfs: raid56: add new helper for starting async work Add helper that schedules a given function to run on the rmw workqueue. This will replace several standalone helpers. Signed-off-by: David Sterba --- fs/btrfs/raid56.c | 6 ++++++ 1 file changed, 6 insertions(+) (limited to 'fs') diff --git a/fs/btrfs/raid56.c b/fs/btrfs/raid56.c index 1a1b7d6c44cb..f30d847baf07 100644 --- a/fs/btrfs/raid56.c +++ b/fs/btrfs/raid56.c @@ -174,6 +174,12 @@ static noinline void finish_parity_scrub(struct btrfs_raid_bio *rbio, int need_check); static void async_scrub_parity(struct btrfs_raid_bio *rbio); +static void start_async_work(struct btrfs_raid_bio *rbio, btrfs_func_t work_func) +{ + btrfs_init_work(&rbio->work, btrfs_rmw_helper, work_func, NULL, NULL); + btrfs_queue_work(rbio->fs_info->rmw_workers, &rbio->work); +} + /* * the stripe hash table is used for locking, and to collect * bios in hopes of making a full stripe -- cgit v1.2.3 From cf6a4a7587dc997b29359e29cf14079e1931715b Mon Sep 17 00:00:00 2001 From: David Sterba Date: Fri, 29 Jun 2018 10:56:58 +0200 Subject: btrfs: raid56: use new helper for async_rmw_stripe Signed-off-by: David Sterba --- fs/btrfs/raid56.c | 11 ++--------- 1 file changed, 2 insertions(+), 9 deletions(-) (limited to 'fs') diff --git a/fs/btrfs/raid56.c b/fs/btrfs/raid56.c index f30d847baf07..96a7d3445623 100644 --- a/fs/btrfs/raid56.c +++ b/fs/btrfs/raid56.c @@ -162,7 +162,6 @@ static int __raid56_parity_recover(struct btrfs_raid_bio *rbio); static noinline void finish_rmw(struct btrfs_raid_bio *rbio); static void rmw_work(struct btrfs_work *work); static void read_rebuild_work(struct btrfs_work *work); -static void async_rmw_stripe(struct btrfs_raid_bio *rbio); static void async_read_rebuild(struct btrfs_raid_bio *rbio); static int fail_bio_stripe(struct btrfs_raid_bio *rbio, struct bio *bio); static int fail_rbio_index(struct btrfs_raid_bio *rbio, int failed); @@ -811,7 +810,7 @@ static noinline void unlock_stripe(struct btrfs_raid_bio *rbio) async_read_rebuild(next); } else if (next->operation == BTRFS_RBIO_WRITE) { steal_rbio(rbio, next); - async_rmw_stripe(next); + start_async_work(next, rmw_work); } else if (next->operation == BTRFS_RBIO_PARITY_SCRUB) { steal_rbio(rbio, next); async_scrub_parity(next); @@ -1501,12 +1500,6 @@ cleanup: rbio_orig_end_io(rbio, BLK_STS_IOERR); } -static void async_rmw_stripe(struct btrfs_raid_bio *rbio) -{ - btrfs_init_work(&rbio->work, btrfs_rmw_helper, rmw_work, NULL, NULL); - btrfs_queue_work(rbio->fs_info->rmw_workers, &rbio->work); -} - static void async_read_rebuild(struct btrfs_raid_bio *rbio) { btrfs_init_work(&rbio->work, btrfs_rmw_helper, @@ -1645,7 +1638,7 @@ static int partial_stripe_write(struct btrfs_raid_bio *rbio) ret = lock_stripe_add(rbio); if (ret == 0) - async_rmw_stripe(rbio); + start_async_work(rbio, rmw_work); return 0; } -- cgit v1.2.3 From e66d8d5a41c1e3c560fc7aba4edcb53caf4f26c8 Mon Sep 17 00:00:00 2001 From: David Sterba Date: Fri, 29 Jun 2018 10:57:00 +0200 Subject: btrfs: raid56: use new helper for async_read_rebuild Signed-off-by: David Sterba --- fs/btrfs/raid56.c | 15 +++------------ 1 file changed, 3 insertions(+), 12 deletions(-) (limited to 'fs') diff --git a/fs/btrfs/raid56.c b/fs/btrfs/raid56.c index 96a7d3445623..f9b349171d61 100644 --- a/fs/btrfs/raid56.c +++ b/fs/btrfs/raid56.c @@ -162,7 +162,6 @@ static int __raid56_parity_recover(struct btrfs_raid_bio *rbio); static noinline void finish_rmw(struct btrfs_raid_bio *rbio); static void rmw_work(struct btrfs_work *work); static void read_rebuild_work(struct btrfs_work *work); -static void async_read_rebuild(struct btrfs_raid_bio *rbio); static int fail_bio_stripe(struct btrfs_raid_bio *rbio, struct bio *bio); static int fail_rbio_index(struct btrfs_raid_bio *rbio, int failed); static void __free_raid_bio(struct btrfs_raid_bio *rbio); @@ -804,10 +803,10 @@ static noinline void unlock_stripe(struct btrfs_raid_bio *rbio) spin_unlock_irqrestore(&h->lock, flags); if (next->operation == BTRFS_RBIO_READ_REBUILD) - async_read_rebuild(next); + start_async_work(next, read_rebuild_work); else if (next->operation == BTRFS_RBIO_REBUILD_MISSING) { steal_rbio(rbio, next); - async_read_rebuild(next); + start_async_work(next, read_rebuild_work); } else if (next->operation == BTRFS_RBIO_WRITE) { steal_rbio(rbio, next); start_async_work(next, rmw_work); @@ -1500,14 +1499,6 @@ cleanup: rbio_orig_end_io(rbio, BLK_STS_IOERR); } -static void async_read_rebuild(struct btrfs_raid_bio *rbio) -{ - btrfs_init_work(&rbio->work, btrfs_rmw_helper, - read_rebuild_work, NULL, NULL); - - btrfs_queue_work(rbio->fs_info->rmw_workers, &rbio->work); -} - /* * the stripe must be locked by the caller. It will * unlock after all the writes are done @@ -2765,5 +2756,5 @@ raid56_alloc_missing_rbio(struct btrfs_fs_info *fs_info, struct bio *bio, void raid56_submit_missing_rbio(struct btrfs_raid_bio *rbio) { if (!lock_stripe_add(rbio)) - async_read_rebuild(rbio); + start_async_work(rbio, read_rebuild_work); } -- cgit v1.2.3 From a81b747d0f6efc01506fbd5335e91607dc013b8d Mon Sep 17 00:00:00 2001 From: David Sterba Date: Fri, 29 Jun 2018 10:57:03 +0200 Subject: btrfs: raid56: use new helper for async_scrub_parity Signed-off-by: David Sterba --- fs/btrfs/raid56.c | 14 +++----------- 1 file changed, 3 insertions(+), 11 deletions(-) (limited to 'fs') diff --git a/fs/btrfs/raid56.c b/fs/btrfs/raid56.c index f9b349171d61..339cce0878d1 100644 --- a/fs/btrfs/raid56.c +++ b/fs/btrfs/raid56.c @@ -170,7 +170,7 @@ static int alloc_rbio_pages(struct btrfs_raid_bio *rbio); static noinline void finish_parity_scrub(struct btrfs_raid_bio *rbio, int need_check); -static void async_scrub_parity(struct btrfs_raid_bio *rbio); +static void scrub_parity_work(struct btrfs_work *work); static void start_async_work(struct btrfs_raid_bio *rbio, btrfs_func_t work_func) { @@ -812,7 +812,7 @@ static noinline void unlock_stripe(struct btrfs_raid_bio *rbio) start_async_work(next, rmw_work); } else if (next->operation == BTRFS_RBIO_PARITY_SCRUB) { steal_rbio(rbio, next); - async_scrub_parity(next); + start_async_work(next, scrub_parity_work); } goto done_nolock; @@ -2703,18 +2703,10 @@ static void scrub_parity_work(struct btrfs_work *work) raid56_parity_scrub_stripe(rbio); } -static void async_scrub_parity(struct btrfs_raid_bio *rbio) -{ - btrfs_init_work(&rbio->work, btrfs_rmw_helper, - scrub_parity_work, NULL, NULL); - - btrfs_queue_work(rbio->fs_info->rmw_workers, &rbio->work); -} - void raid56_parity_submit_scrub_rbio(struct btrfs_raid_bio *rbio) { if (!lock_stripe_add(rbio)) - async_scrub_parity(rbio); + start_async_work(rbio, scrub_parity_work); } /* The following code is used for dev replace of a missing RAID 5/6 device. */ -- cgit v1.2.3 From 176571a1f64f7670c87c3f8d3b50c11cc836110e Mon Sep 17 00:00:00 2001 From: David Sterba Date: Fri, 29 Jun 2018 10:57:05 +0200 Subject: btrfs: raid56: merge rbio_is_full helpers There's only one call site of the unlocked helper so it can be folded into the caller. Signed-off-by: David Sterba --- fs/btrfs/raid56.c | 23 ++++++----------------- 1 file changed, 6 insertions(+), 17 deletions(-) (limited to 'fs') diff --git a/fs/btrfs/raid56.c b/fs/btrfs/raid56.c index 339cce0878d1..272acd9b1192 100644 --- a/fs/btrfs/raid56.c +++ b/fs/btrfs/raid56.c @@ -507,32 +507,21 @@ static void run_xor(void **pages, int src_cnt, ssize_t len) } /* - * returns true if the bio list inside this rbio - * covers an entire stripe (no rmw required). - * Must be called with the bio list lock held, or - * at a time when you know it is impossible to add - * new bios into the list + * Returns true if the bio list inside this rbio covers an entire stripe (no + * rmw required). */ -static int __rbio_is_full(struct btrfs_raid_bio *rbio) +static int rbio_is_full(struct btrfs_raid_bio *rbio) { + unsigned long flags; unsigned long size = rbio->bio_list_bytes; int ret = 1; + spin_lock_irqsave(&rbio->bio_list_lock, flags); if (size != rbio->nr_data * rbio->stripe_len) ret = 0; - BUG_ON(size > rbio->nr_data * rbio->stripe_len); - return ret; -} - -static int rbio_is_full(struct btrfs_raid_bio *rbio) -{ - unsigned long flags; - int ret; - - spin_lock_irqsave(&rbio->bio_list_lock, flags); - ret = __rbio_is_full(rbio); spin_unlock_irqrestore(&rbio->bio_list_lock, flags); + return ret; } -- cgit v1.2.3 From c7b562c5480322ffaf591f45a4ff7ee089340ab4 Mon Sep 17 00:00:00 2001 From: David Sterba Date: Fri, 29 Jun 2018 10:57:10 +0200 Subject: btrfs: raid56: catch errors from full_stripe_write Add fall-back code to catch failure of full_stripe_write. Proper error handling from inside run_plug would need more code restructuring as it's called at arbitrary points by io scheduler. Signed-off-by: David Sterba --- fs/btrfs/raid56.c | 5 ++++- 1 file changed, 4 insertions(+), 1 deletion(-) (limited to 'fs') diff --git a/fs/btrfs/raid56.c b/fs/btrfs/raid56.c index 272acd9b1192..df41d7049936 100644 --- a/fs/btrfs/raid56.c +++ b/fs/btrfs/raid56.c @@ -1686,8 +1686,11 @@ static void run_plug(struct btrfs_plug_cb *plug) list_del_init(&cur->plug_list); if (rbio_is_full(cur)) { + int ret; + /* we have a full stripe, send it down */ - full_stripe_write(cur); + ret = full_stripe_write(cur); + BUG_ON(ret); continue; } if (last) { -- cgit v1.2.3 From 340f1aa27f367e0c3d2662d44f356b05087fea05 Mon Sep 17 00:00:00 2001 From: Nikolay Borisov Date: Thu, 5 Jul 2018 14:50:48 +0300 Subject: btrfs: qgroups: Move transaction management inside btrfs_quota_enable/disable Commit 5d23515be669 ("btrfs: Move qgroup rescan on quota enable to btrfs_quota_enable") not only resulted in an easier to follow code but it also introduced a subtle bug. It changed the timing when the initial transaction rescan was happening: - before the commit: it would happen after transaction commit had occured - after the commit: it might happen before the transaction was committed This results in failure to correctly rescan the quota since there could be data which is still not committed on disk. This patch aims to fix this by moving the transaction creation/commit inside btrfs_quota_enable, which allows to schedule the quota commit after the transaction has been committed. Fixes: 5d23515be669 ("btrfs: Move qgroup rescan on quota enable to btrfs_quota_enable") Reported-by: Misono Tomohiro Link: https://marc.info/?l=linux-btrfs&m=152999289017582 Signed-off-by: Nikolay Borisov Signed-off-by: David Sterba --- fs/btrfs/ioctl.c | 15 ++-------- fs/btrfs/qgroup.c | 86 ++++++++++++++++++++++++++++++++++++++++++++++--------- fs/btrfs/qgroup.h | 6 ++-- 3 files changed, 76 insertions(+), 31 deletions(-) (limited to 'fs') diff --git a/fs/btrfs/ioctl.c b/fs/btrfs/ioctl.c index 802918507cc0..9dcd16dec754 100644 --- a/fs/btrfs/ioctl.c +++ b/fs/btrfs/ioctl.c @@ -5105,9 +5105,7 @@ static long btrfs_ioctl_quota_ctl(struct file *file, void __user *arg) struct inode *inode = file_inode(file); struct btrfs_fs_info *fs_info = btrfs_sb(inode->i_sb); struct btrfs_ioctl_quota_ctl_args *sa; - struct btrfs_trans_handle *trans = NULL; int ret; - int err; if (!capable(CAP_SYS_ADMIN)) return -EPERM; @@ -5123,28 +5121,19 @@ static long btrfs_ioctl_quota_ctl(struct file *file, void __user *arg) } down_write(&fs_info->subvol_sem); - trans = btrfs_start_transaction(fs_info->tree_root, 2); - if (IS_ERR(trans)) { - ret = PTR_ERR(trans); - goto out; - } switch (sa->cmd) { case BTRFS_QUOTA_CTL_ENABLE: - ret = btrfs_quota_enable(trans, fs_info); + ret = btrfs_quota_enable(fs_info); break; case BTRFS_QUOTA_CTL_DISABLE: - ret = btrfs_quota_disable(trans, fs_info); + ret = btrfs_quota_disable(fs_info); break; default: ret = -EINVAL; break; } - err = btrfs_commit_transaction(trans); - if (err && !ret) - ret = err; -out: kfree(sa); up_write(&fs_info->subvol_sem); drop_write: diff --git a/fs/btrfs/qgroup.c b/fs/btrfs/qgroup.c index c25dc47210a3..97a59a444500 100644 --- a/fs/btrfs/qgroup.c +++ b/fs/btrfs/qgroup.c @@ -875,8 +875,7 @@ out: return ret; } -int btrfs_quota_enable(struct btrfs_trans_handle *trans, - struct btrfs_fs_info *fs_info) +int btrfs_quota_enable(struct btrfs_fs_info *fs_info) { struct btrfs_root *quota_root; struct btrfs_root *tree_root = fs_info->tree_root; @@ -886,6 +885,7 @@ int btrfs_quota_enable(struct btrfs_trans_handle *trans, struct btrfs_key key; struct btrfs_key found_key; struct btrfs_qgroup *qgroup = NULL; + struct btrfs_trans_handle *trans = NULL; int ret = 0; int slot; @@ -893,9 +893,25 @@ int btrfs_quota_enable(struct btrfs_trans_handle *trans, if (fs_info->quota_root) goto out; + /* + * 1 for quota root item + * 1 for BTRFS_QGROUP_STATUS item + * + * Yet we also need 2*n items for a QGROUP_INFO/QGROUP_LIMIT items + * per subvolume. However those are not currently reserved since it + * would be a lot of overkill. + */ + trans = btrfs_start_transaction(tree_root, 2); + if (IS_ERR(trans)) { + ret = PTR_ERR(trans); + trans = NULL; + goto out; + } + fs_info->qgroup_ulist = ulist_alloc(GFP_KERNEL); if (!fs_info->qgroup_ulist) { ret = -ENOMEM; + btrfs_abort_transaction(trans, ret); goto out; } @@ -906,12 +922,14 @@ int btrfs_quota_enable(struct btrfs_trans_handle *trans, BTRFS_QUOTA_TREE_OBJECTID); if (IS_ERR(quota_root)) { ret = PTR_ERR(quota_root); + btrfs_abort_transaction(trans, ret); goto out; } path = btrfs_alloc_path(); if (!path) { ret = -ENOMEM; + btrfs_abort_transaction(trans, ret); goto out_free_root; } @@ -921,8 +939,10 @@ int btrfs_quota_enable(struct btrfs_trans_handle *trans, ret = btrfs_insert_empty_item(trans, quota_root, path, &key, sizeof(*ptr)); - if (ret) + if (ret) { + btrfs_abort_transaction(trans, ret); goto out_free_path; + } leaf = path->nodes[0]; ptr = btrfs_item_ptr(leaf, path->slots[0], @@ -944,9 +964,10 @@ int btrfs_quota_enable(struct btrfs_trans_handle *trans, ret = btrfs_search_slot_for_read(tree_root, &key, path, 1, 0); if (ret > 0) goto out_add_root; - if (ret < 0) + if (ret < 0) { + btrfs_abort_transaction(trans, ret); goto out_free_path; - + } while (1) { slot = path->slots[0]; @@ -956,18 +977,23 @@ int btrfs_quota_enable(struct btrfs_trans_handle *trans, if (found_key.type == BTRFS_ROOT_REF_KEY) { ret = add_qgroup_item(trans, quota_root, found_key.offset); - if (ret) + if (ret) { + btrfs_abort_transaction(trans, ret); goto out_free_path; + } qgroup = add_qgroup_rb(fs_info, found_key.offset); if (IS_ERR(qgroup)) { ret = PTR_ERR(qgroup); + btrfs_abort_transaction(trans, ret); goto out_free_path; } } ret = btrfs_next_item(tree_root, path); - if (ret < 0) + if (ret < 0) { + btrfs_abort_transaction(trans, ret); goto out_free_path; + } if (ret) break; } @@ -975,18 +1001,28 @@ int btrfs_quota_enable(struct btrfs_trans_handle *trans, out_add_root: btrfs_release_path(path); ret = add_qgroup_item(trans, quota_root, BTRFS_FS_TREE_OBJECTID); - if (ret) + if (ret) { + btrfs_abort_transaction(trans, ret); goto out_free_path; + } qgroup = add_qgroup_rb(fs_info, BTRFS_FS_TREE_OBJECTID); if (IS_ERR(qgroup)) { ret = PTR_ERR(qgroup); + btrfs_abort_transaction(trans, ret); goto out_free_path; } spin_lock(&fs_info->qgroup_lock); fs_info->quota_root = quota_root; set_bit(BTRFS_FS_QUOTA_ENABLED, &fs_info->flags); spin_unlock(&fs_info->qgroup_lock); + + ret = btrfs_commit_transaction(trans); + if (ret) { + trans = NULL; + goto out_free_path; + } + ret = qgroup_rescan_init(fs_info, 0, 1); if (!ret) { qgroup_rescan_zero_tracking(fs_info); @@ -1006,20 +1042,35 @@ out: if (ret) { ulist_free(fs_info->qgroup_ulist); fs_info->qgroup_ulist = NULL; + if (trans) + btrfs_end_transaction(trans); } mutex_unlock(&fs_info->qgroup_ioctl_lock); return ret; } -int btrfs_quota_disable(struct btrfs_trans_handle *trans, - struct btrfs_fs_info *fs_info) +int btrfs_quota_disable(struct btrfs_fs_info *fs_info) { struct btrfs_root *quota_root; + struct btrfs_trans_handle *trans = NULL; int ret = 0; mutex_lock(&fs_info->qgroup_ioctl_lock); if (!fs_info->quota_root) goto out; + + /* + * 1 For the root item + * + * We should also reserve enough items for the quota tree deletion in + * btrfs_clean_quota_tree but this is not done. + */ + trans = btrfs_start_transaction(fs_info->tree_root, 1); + if (IS_ERR(trans)) { + ret = PTR_ERR(trans); + goto out; + } + clear_bit(BTRFS_FS_QUOTA_ENABLED, &fs_info->flags); btrfs_qgroup_wait_for_completion(fs_info, false); spin_lock(&fs_info->qgroup_lock); @@ -1031,12 +1082,16 @@ int btrfs_quota_disable(struct btrfs_trans_handle *trans, btrfs_free_qgroup_config(fs_info); ret = btrfs_clean_quota_tree(trans, quota_root); - if (ret) - goto out; + if (ret) { + btrfs_abort_transaction(trans, ret); + goto end_trans; + } ret = btrfs_del_root(trans, fs_info, "a_root->root_key); - if (ret) - goto out; + if (ret) { + btrfs_abort_transaction(trans, ret); + goto end_trans; + } list_del("a_root->dirty_list); @@ -1048,6 +1103,9 @@ int btrfs_quota_disable(struct btrfs_trans_handle *trans, free_extent_buffer(quota_root->node); free_extent_buffer(quota_root->commit_root); kfree(quota_root); + +end_trans: + ret = btrfs_end_transaction(trans); out: mutex_unlock(&fs_info->qgroup_ioctl_lock); return ret; diff --git a/fs/btrfs/qgroup.h b/fs/btrfs/qgroup.h index d60dd06445ce..bec7c9b17a8e 100644 --- a/fs/btrfs/qgroup.h +++ b/fs/btrfs/qgroup.h @@ -141,10 +141,8 @@ struct btrfs_qgroup { #define QGROUP_RELEASE (1<<1) #define QGROUP_FREE (1<<2) -int btrfs_quota_enable(struct btrfs_trans_handle *trans, - struct btrfs_fs_info *fs_info); -int btrfs_quota_disable(struct btrfs_trans_handle *trans, - struct btrfs_fs_info *fs_info); +int btrfs_quota_enable(struct btrfs_fs_info *fs_info); +int btrfs_quota_disable(struct btrfs_fs_info *fs_info); int btrfs_qgroup_rescan(struct btrfs_fs_info *fs_info); void btrfs_qgroup_rescan_resume(struct btrfs_fs_info *fs_info); int btrfs_qgroup_wait_for_completion(struct btrfs_fs_info *fs_info, -- cgit v1.2.3 From b4993e64f78a9605b45252fa9ba385c88a1f4ce9 Mon Sep 17 00:00:00 2001 From: Anand Jain Date: Tue, 3 Jul 2018 17:07:23 +0800 Subject: btrfs: fix in-memory value of total_devices after seed device deletion In case of deleting the seed device the %cur_devices (seed) and the %fs_devices (parent) are different. Now, as the parent fs_devices::total_devices also maintains the total number of devices including the seed device, so decrement its in-memory value for the successful seed delete. We are already updating its corresponding on-disk btrfs_super_block::number_devices value. Signed-off-by: Anand Jain Signed-off-by: David Sterba --- fs/btrfs/volumes.c | 3 +++ 1 file changed, 3 insertions(+) (limited to 'fs') diff --git a/fs/btrfs/volumes.c b/fs/btrfs/volumes.c index 211fb2161487..f532e855b507 100644 --- a/fs/btrfs/volumes.c +++ b/fs/btrfs/volumes.c @@ -2026,6 +2026,9 @@ int btrfs_rm_device(struct btrfs_fs_info *fs_info, const char *device_path, cur_devices->num_devices--; cur_devices->total_devices--; + /* Update total_devices of the parent fs_devices if it's seed */ + if (cur_devices != fs_devices) + fs_devices->total_devices--; if (test_bit(BTRFS_DEV_STATE_MISSING, &device->dev_state)) cur_devices->missing_devices--; -- cgit v1.2.3 From 93b9bcdf9fbcb683d4e8c44ee8cec0989053d4de Mon Sep 17 00:00:00 2001 From: Gu Jinxiang Date: Mon, 9 Jul 2018 14:39:15 +0800 Subject: btrfs: remove unused parameter from btrfs_parse_subvol_options Since parameter flags is no more used since commit d7407606564c ("btrfs: split parse_early_options() in two"), remove it. Signed-off-by: Gu Jinxiang Reviewed-by: David Sterba Signed-off-by: David Sterba --- fs/btrfs/super.c | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) (limited to 'fs') diff --git a/fs/btrfs/super.c b/fs/btrfs/super.c index e04bcf0b0ed4..39d8e39b2fe1 100644 --- a/fs/btrfs/super.c +++ b/fs/btrfs/super.c @@ -933,8 +933,8 @@ out: * * The value is later passed to mount_subvol() */ -static int btrfs_parse_subvol_options(const char *options, fmode_t flags, - char **subvol_name, u64 *subvol_objectid) +static int btrfs_parse_subvol_options(const char *options, char **subvol_name, + u64 *subvol_objectid) { substring_t args[MAX_OPT_ARGS]; char *opts, *orig, *p; @@ -1648,8 +1648,8 @@ static struct dentry *btrfs_mount(struct file_system_type *fs_type, int flags, if (!(flags & SB_RDONLY)) mode |= FMODE_WRITE; - error = btrfs_parse_subvol_options(data, mode, - &subvol_name, &subvol_objectid); + error = btrfs_parse_subvol_options(data, &subvol_name, + &subvol_objectid); if (error) { kfree(subvol_name); return ERR_PTR(error); -- cgit v1.2.3 From 621567a28ce081424bdcaaef7763a34b204d5be0 Mon Sep 17 00:00:00 2001 From: Qu Wenruo Date: Mon, 9 Jul 2018 14:52:54 +0800 Subject: btrfs: Remove unused function btrfs_account_dev_extents_size This function is not used since the alloc_start parameter has been obsoleted in commit 0d0c71b317207082856 ("btrfs: obsolete and remove mount option alloc_start"). Signed-off-by: Qu Wenruo Reviewed-by: Nikolay Borisov Reviewed-by: David Sterba Signed-off-by: David Sterba --- fs/btrfs/volumes.c | 85 ------------------------------------------------------ fs/btrfs/volumes.h | 2 -- 2 files changed, 87 deletions(-) (limited to 'fs') diff --git a/fs/btrfs/volumes.c b/fs/btrfs/volumes.c index f532e855b507..f7191fdfb44c 100644 --- a/fs/btrfs/volumes.c +++ b/fs/btrfs/volumes.c @@ -1258,91 +1258,6 @@ error_bdev_put: return ret; } -/* helper to account the used device space in the range */ -int btrfs_account_dev_extents_size(struct btrfs_device *device, u64 start, - u64 end, u64 *length) -{ - struct btrfs_key key; - struct btrfs_root *root = device->fs_info->dev_root; - struct btrfs_dev_extent *dev_extent; - struct btrfs_path *path; - u64 extent_end; - int ret; - int slot; - struct extent_buffer *l; - - *length = 0; - - if (start >= device->total_bytes || - test_bit(BTRFS_DEV_STATE_REPLACE_TGT, &device->dev_state)) - return 0; - - path = btrfs_alloc_path(); - if (!path) - return -ENOMEM; - path->reada = READA_FORWARD; - - key.objectid = device->devid; - key.offset = start; - key.type = BTRFS_DEV_EXTENT_KEY; - - ret = btrfs_search_slot(NULL, root, &key, path, 0, 0); - if (ret < 0) - goto out; - if (ret > 0) { - ret = btrfs_previous_item(root, path, key.objectid, key.type); - if (ret < 0) - goto out; - } - - while (1) { - l = path->nodes[0]; - slot = path->slots[0]; - if (slot >= btrfs_header_nritems(l)) { - ret = btrfs_next_leaf(root, path); - if (ret == 0) - continue; - if (ret < 0) - goto out; - - break; - } - btrfs_item_key_to_cpu(l, &key, slot); - - if (key.objectid < device->devid) - goto next; - - if (key.objectid > device->devid) - break; - - if (key.type != BTRFS_DEV_EXTENT_KEY) - goto next; - - dev_extent = btrfs_item_ptr(l, slot, struct btrfs_dev_extent); - extent_end = key.offset + btrfs_dev_extent_length(l, - dev_extent); - if (key.offset <= start && extent_end > end) { - *length = end - start + 1; - break; - } else if (key.offset <= start && extent_end > start) - *length += extent_end - start; - else if (key.offset > start && extent_end <= end) - *length += extent_end - key.offset; - else if (key.offset > start && key.offset <= end) { - *length += end - key.offset + 1; - break; - } else if (key.offset > end) - break; - -next: - path->slots[0]++; - } - ret = 0; -out: - btrfs_free_path(path); - return ret; -} - static int contains_pending_extent(struct btrfs_transaction *transaction, struct btrfs_device *device, u64 *start, u64 len) diff --git a/fs/btrfs/volumes.h b/fs/btrfs/volumes.h index 275c31c730cf..9665b84b1026 100644 --- a/fs/btrfs/volumes.h +++ b/fs/btrfs/volumes.h @@ -384,8 +384,6 @@ static inline enum btrfs_map_op btrfs_op(struct bio *bio) } } -int btrfs_account_dev_extents_size(struct btrfs_device *device, u64 start, - u64 end, u64 *length); void btrfs_get_bbio(struct btrfs_bio *bbio); void btrfs_put_bbio(struct btrfs_bio *bbio); int btrfs_map_block(struct btrfs_fs_info *fs_info, enum btrfs_map_op op, -- cgit v1.2.3 From 959b1c04675735aa51b9a7b3e28963c4141bf3e7 Mon Sep 17 00:00:00 2001 From: Nikolay Borisov Date: Fri, 29 Jun 2018 08:26:05 +0300 Subject: btrfs: close devices without offloading to a temporary list Since commit 88c14590cdd6 ("btrfs: use RCU in btrfs_show_devname for device list traversal") btrfs_show_devname no longer takes device_list_mutex. As such the deadlock that 0ccd05285e7f ("btrfs: fix a possible umount deadlock") aimed to fix no longer exists, we can free the devices immediatelly and remove the code that does the pending work. Signed-off-by: Nikolay Borisov Reviewed-by: Anand Jain [ update changelog ] Reviewed-by: David Sterba Signed-off-by: David Sterba --- fs/btrfs/volumes.c | 26 ++++++-------------------- 1 file changed, 6 insertions(+), 20 deletions(-) (limited to 'fs') diff --git a/fs/btrfs/volumes.c b/fs/btrfs/volumes.c index f7191fdfb44c..3c3359d7e91d 100644 --- a/fs/btrfs/volumes.c +++ b/fs/btrfs/volumes.c @@ -1001,7 +1001,7 @@ static void btrfs_close_bdev(struct btrfs_device *device) blkdev_put(device->bdev, device->mode); } -static void btrfs_prepare_close_one_device(struct btrfs_device *device) +static void btrfs_close_one_device(struct btrfs_device *device) { struct btrfs_fs_devices *fs_devices = device->fs_devices; struct btrfs_device *new_device; @@ -1019,6 +1019,8 @@ static void btrfs_prepare_close_one_device(struct btrfs_device *device) if (test_bit(BTRFS_DEV_STATE_MISSING, &device->dev_state)) fs_devices->missing_devices--; + btrfs_close_bdev(device); + new_device = btrfs_alloc_device(NULL, &device->devid, device->uuid); BUG_ON(IS_ERR(new_device)); /* -ENOMEM */ @@ -1032,39 +1034,23 @@ static void btrfs_prepare_close_one_device(struct btrfs_device *device) list_replace_rcu(&device->dev_list, &new_device->dev_list); new_device->fs_devices = device->fs_devices; + + call_rcu(&device->rcu, free_device_rcu); } static int close_fs_devices(struct btrfs_fs_devices *fs_devices) { struct btrfs_device *device, *tmp; - struct list_head pending_put; - - INIT_LIST_HEAD(&pending_put); if (--fs_devices->opened > 0) return 0; mutex_lock(&fs_devices->device_list_mutex); list_for_each_entry_safe(device, tmp, &fs_devices->devices, dev_list) { - btrfs_prepare_close_one_device(device); - list_add(&device->dev_list, &pending_put); + btrfs_close_one_device(device); } mutex_unlock(&fs_devices->device_list_mutex); - /* - * btrfs_show_devname() is using the device_list_mutex, - * sometimes call to blkdev_put() leads vfs calling - * into this func. So do put outside of device_list_mutex, - * as of now. - */ - while (!list_empty(&pending_put)) { - device = list_first_entry(&pending_put, - struct btrfs_device, dev_list); - list_del(&device->dev_list); - btrfs_close_bdev(device); - call_rcu(&device->rcu, free_device_rcu); - } - WARN_ON(fs_devices->open_devices); WARN_ON(fs_devices->rw_devices); fs_devices->opened = 0; -- cgit v1.2.3 From 4306a97449f9a0f9e5229af7889d4401315355aa Mon Sep 17 00:00:00 2001 From: Anand Jain Date: Tue, 29 May 2018 12:28:37 +0800 Subject: btrfs: do btrfs_free_stale_devices outside of device_list_add btrfs_free_stale_devices() looks for device path reused for another filesystem, and deletes the older fs_devices::device entry. In preparation to handle locking in device_list_add, move btrfs_free_stale_devices outside as these two functions serve a different purpose. Signed-off-by: Anand Jain Reviewed-by: David Sterba Signed-off-by: David Sterba --- fs/btrfs/volumes.c | 15 ++++++++++----- 1 file changed, 10 insertions(+), 5 deletions(-) (limited to 'fs') diff --git a/fs/btrfs/volumes.c b/fs/btrfs/volumes.c index 3c3359d7e91d..c84a9e22daf1 100644 --- a/fs/btrfs/volumes.c +++ b/fs/btrfs/volumes.c @@ -747,7 +747,8 @@ error_brelse: * error pointer when failed */ static noinline struct btrfs_device *device_list_add(const char *path, - struct btrfs_super_block *disk_super) + struct btrfs_super_block *disk_super, + bool *new_device_added) { struct btrfs_device *device; struct btrfs_fs_devices *fs_devices; @@ -793,7 +794,7 @@ static noinline struct btrfs_device *device_list_add(const char *path, mutex_unlock(&fs_devices->device_list_mutex); device->fs_devices = fs_devices; - btrfs_free_stale_devices(path, device); + *new_device_added = true; if (disk_super->label[0]) pr_info("BTRFS: device label %s devid %llu transid %llu %s\n", @@ -1204,6 +1205,7 @@ int btrfs_scan_one_device(const char *path, fmode_t flags, void *holder, struct btrfs_fs_devices **fs_devices_ret) { struct btrfs_super_block *disk_super; + bool new_device_added = false; struct btrfs_device *device; struct block_device *bdev; struct page *page; @@ -1229,11 +1231,14 @@ int btrfs_scan_one_device(const char *path, fmode_t flags, void *holder, } mutex_lock(&uuid_mutex); - device = device_list_add(path, disk_super); - if (IS_ERR(device)) + device = device_list_add(path, disk_super, &new_device_added); + if (IS_ERR(device)) { ret = PTR_ERR(device); - else + } else { *fs_devices_ret = device->fs_devices; + if (new_device_added) + btrfs_free_stale_devices(path, device); + } mutex_unlock(&uuid_mutex); btrfs_release_disk_super(page); -- cgit v1.2.3 From 9c6d173ea6e4c8c939ae6c257c7fc18f7b320316 Mon Sep 17 00:00:00 2001 From: Anand Jain Date: Tue, 29 May 2018 14:10:20 +0800 Subject: btrfs: extend locked section when adding a new device in device_list_add Make sure the device_list_lock is held the whole time: * when the device is being looked up * new device is initialized and put to the list * the list counters are updated (fs_devices::opened, fs_devices::total_devices) Signed-off-by: Anand Jain [ update changelog ] Reviewed-by: David Sterba Signed-off-by: David Sterba --- fs/btrfs/volumes.c | 16 ++++++++++++---- 1 file changed, 12 insertions(+), 4 deletions(-) (limited to 'fs') diff --git a/fs/btrfs/volumes.c b/fs/btrfs/volumes.c index c84a9e22daf1..870732ef356c 100644 --- a/fs/btrfs/volumes.c +++ b/fs/btrfs/volumes.c @@ -762,21 +762,26 @@ static noinline struct btrfs_device *device_list_add(const char *path, if (IS_ERR(fs_devices)) return ERR_CAST(fs_devices); + mutex_lock(&fs_devices->device_list_mutex); list_add(&fs_devices->fs_list, &fs_uuids); device = NULL; } else { + mutex_lock(&fs_devices->device_list_mutex); device = find_device(fs_devices, devid, disk_super->dev_item.uuid); } if (!device) { - if (fs_devices->opened) + if (fs_devices->opened) { + mutex_unlock(&fs_devices->device_list_mutex); return ERR_PTR(-EBUSY); + } device = btrfs_alloc_device(NULL, &devid, disk_super->dev_item.uuid); if (IS_ERR(device)) { + mutex_unlock(&fs_devices->device_list_mutex); /* we can safely leave the fs_devices entry around */ return device; } @@ -784,14 +789,13 @@ static noinline struct btrfs_device *device_list_add(const char *path, name = rcu_string_strdup(path, GFP_NOFS); if (!name) { btrfs_free_device(device); + mutex_unlock(&fs_devices->device_list_mutex); return ERR_PTR(-ENOMEM); } rcu_assign_pointer(device->name, name); - mutex_lock(&fs_devices->device_list_mutex); list_add_rcu(&device->dev_list, &fs_devices->devices); fs_devices->num_devices++; - mutex_unlock(&fs_devices->device_list_mutex); device->fs_devices = fs_devices; *new_device_added = true; @@ -838,12 +842,15 @@ static noinline struct btrfs_device *device_list_add(const char *path, * with larger generation number or the last-in if * generation are equal. */ + mutex_unlock(&fs_devices->device_list_mutex); return ERR_PTR(-EEXIST); } name = rcu_string_strdup(path, GFP_NOFS); - if (!name) + if (!name) { + mutex_unlock(&fs_devices->device_list_mutex); return ERR_PTR(-ENOMEM); + } rcu_string_free(device->name); rcu_assign_pointer(device->name, name); if (test_bit(BTRFS_DEV_STATE_MISSING, &device->dev_state)) { @@ -863,6 +870,7 @@ static noinline struct btrfs_device *device_list_add(const char *path, fs_devices->total_devices = btrfs_super_num_devices(disk_super); + mutex_unlock(&fs_devices->device_list_mutex); return device; } -- cgit v1.2.3 From fa6d2ae540a200a17bb7ee769f9df22d411c9404 Mon Sep 17 00:00:00 2001 From: Anand Jain Date: Tue, 29 May 2018 15:33:08 +0800 Subject: btrfs: rename local devices for fs_devices in btrfs_free_stale_devices( Over the years we named %fs_devices and %devices to represent the struct btrfs_fs_devices and the struct btrfs_device. So follow the same scheme here too. No functional changes. Signed-off-by: Anand Jain Signed-off-by: David Sterba --- fs/btrfs/volumes.c | 35 +++++++++++++++++------------------ 1 file changed, 17 insertions(+), 18 deletions(-) (limited to 'fs') diff --git a/fs/btrfs/volumes.c b/fs/btrfs/volumes.c index 870732ef356c..f4ce081bbe46 100644 --- a/fs/btrfs/volumes.c +++ b/fs/btrfs/volumes.c @@ -631,43 +631,42 @@ static void pending_bios_fn(struct btrfs_work *work) * devices. */ static void btrfs_free_stale_devices(const char *path, - struct btrfs_device *skip_dev) + struct btrfs_device *skip_device) { - struct btrfs_fs_devices *fs_devs, *tmp_fs_devs; - struct btrfs_device *dev, *tmp_dev; + struct btrfs_fs_devices *fs_devices, *tmp_fs_devices; + struct btrfs_device *device, *tmp_device; - list_for_each_entry_safe(fs_devs, tmp_fs_devs, &fs_uuids, fs_list) { - - if (fs_devs->opened) + list_for_each_entry_safe(fs_devices, tmp_fs_devices, &fs_uuids, fs_list) { + if (fs_devices->opened) continue; - list_for_each_entry_safe(dev, tmp_dev, - &fs_devs->devices, dev_list) { + list_for_each_entry_safe(device, tmp_device, + &fs_devices->devices, dev_list) { int not_found = 0; - if (skip_dev && skip_dev == dev) + if (skip_device && skip_device == device) continue; - if (path && !dev->name) + if (path && !device->name) continue; rcu_read_lock(); if (path) - not_found = strcmp(rcu_str_deref(dev->name), + not_found = strcmp(rcu_str_deref(device->name), path); rcu_read_unlock(); if (not_found) continue; /* delete the stale device */ - if (fs_devs->num_devices == 1) { - btrfs_sysfs_remove_fsid(fs_devs); - list_del(&fs_devs->fs_list); - free_fs_devices(fs_devs); + if (fs_devices->num_devices == 1) { + btrfs_sysfs_remove_fsid(fs_devices); + list_del(&fs_devices->fs_list); + free_fs_devices(fs_devices); break; } else { - fs_devs->num_devices--; - list_del(&dev->dev_list); - btrfs_free_device(dev); + fs_devices->num_devices--; + list_del(&device->dev_list); + btrfs_free_device(device); } } } -- cgit v1.2.3 From 7bcb8164ad9435068d9bc3b83b8a002c64d63ff6 Mon Sep 17 00:00:00 2001 From: Anand Jain Date: Tue, 29 May 2018 17:23:20 +0800 Subject: btrfs: use device_list_mutex when removing stale devices btrfs_free_stale_devices() finds a stale (not opened) device matching path in the fs_uuid list. We are already under uuid_mutex so when we check for each fs_devices, hold the device_list_mutex too. Signed-off-by: Anand Jain Reviewed-by: David Sterba Signed-off-by: David Sterba --- fs/btrfs/volumes.c | 25 +++++++++++++++---------- 1 file changed, 15 insertions(+), 10 deletions(-) (limited to 'fs') diff --git a/fs/btrfs/volumes.c b/fs/btrfs/volumes.c index f4ce081bbe46..6a8f1e2c116f 100644 --- a/fs/btrfs/volumes.c +++ b/fs/btrfs/volumes.c @@ -637,8 +637,11 @@ static void btrfs_free_stale_devices(const char *path, struct btrfs_device *device, *tmp_device; list_for_each_entry_safe(fs_devices, tmp_fs_devices, &fs_uuids, fs_list) { - if (fs_devices->opened) + mutex_lock(&fs_devices->device_list_mutex); + if (fs_devices->opened) { + mutex_unlock(&fs_devices->device_list_mutex); continue; + } list_for_each_entry_safe(device, tmp_device, &fs_devices->devices, dev_list) { @@ -658,16 +661,18 @@ static void btrfs_free_stale_devices(const char *path, continue; /* delete the stale device */ - if (fs_devices->num_devices == 1) { - btrfs_sysfs_remove_fsid(fs_devices); - list_del(&fs_devices->fs_list); - free_fs_devices(fs_devices); + fs_devices->num_devices--; + list_del(&device->dev_list); + btrfs_free_device(device); + + if (fs_devices->num_devices == 0) break; - } else { - fs_devices->num_devices--; - list_del(&device->dev_list); - btrfs_free_device(device); - } + } + mutex_unlock(&fs_devices->device_list_mutex); + if (fs_devices->num_devices == 0) { + btrfs_sysfs_remove_fsid(fs_devices); + list_del(&fs_devices->fs_list); + free_fs_devices(fs_devices); } } } -- cgit v1.2.3 From 899f9307c33ce4758c30a076b10ed54d5c91c6e7 Mon Sep 17 00:00:00 2001 From: David Sterba Date: Tue, 19 Jun 2018 16:37:36 +0200 Subject: btrfs: lift uuid_mutex to callers of btrfs_scan_one_device Prepartory work to fix race between mount and device scan. The callers will have to manage the critical section, eg. mount wants to scan and then call btrfs_open_devices without the ioctl scan walking in and modifying the fs devices in the meantime. Reviewed-by: Anand Jain Signed-off-by: David Sterba --- fs/btrfs/super.c | 12 +++++++++++- fs/btrfs/volumes.c | 4 ++-- 2 files changed, 13 insertions(+), 3 deletions(-) (limited to 'fs') diff --git a/fs/btrfs/super.c b/fs/btrfs/super.c index 39d8e39b2fe1..0b6567f0c63d 100644 --- a/fs/btrfs/super.c +++ b/fs/btrfs/super.c @@ -915,8 +915,10 @@ static int btrfs_parse_early_options(const char *options, fmode_t flags, error = -ENOMEM; goto out; } + mutex_lock(&uuid_mutex); error = btrfs_scan_one_device(device_name, flags, holder, fs_devices); + mutex_unlock(&uuid_mutex); kfree(device_name); if (error) goto out; @@ -1537,7 +1539,9 @@ static struct dentry *btrfs_mount_root(struct file_system_type *fs_type, return ERR_PTR(error); } + mutex_lock(&uuid_mutex); error = btrfs_scan_one_device(device_name, mode, fs_type, &fs_devices); + mutex_unlock(&uuid_mutex); if (error) goto error_sec_opts; @@ -2232,15 +2236,21 @@ static long btrfs_control_ioctl(struct file *file, unsigned int cmd, switch (cmd) { case BTRFS_IOC_SCAN_DEV: + mutex_lock(&uuid_mutex); ret = btrfs_scan_one_device(vol->name, FMODE_READ, &btrfs_root_fs_type, &fs_devices); + mutex_unlock(&uuid_mutex); break; case BTRFS_IOC_DEVICES_READY: + mutex_lock(&uuid_mutex); ret = btrfs_scan_one_device(vol->name, FMODE_READ, &btrfs_root_fs_type, &fs_devices); - if (ret) + if (ret) { + mutex_unlock(&uuid_mutex); break; + } ret = !(fs_devices->num_devices == fs_devices->total_devices); + mutex_unlock(&uuid_mutex); break; case BTRFS_IOC_GET_SUPPORTED_FEATURES: ret = btrfs_ioctl_get_supported_features((void __user*)arg); diff --git a/fs/btrfs/volumes.c b/fs/btrfs/volumes.c index 6a8f1e2c116f..df5dd6f67887 100644 --- a/fs/btrfs/volumes.c +++ b/fs/btrfs/volumes.c @@ -1224,6 +1224,8 @@ int btrfs_scan_one_device(const char *path, fmode_t flags, void *holder, int ret = 0; u64 bytenr; + lockdep_assert_held(&uuid_mutex); + /* * we would like to check all the supers, but that would make * a btrfs mount succeed after a mkfs from a different FS. @@ -1242,7 +1244,6 @@ int btrfs_scan_one_device(const char *path, fmode_t flags, void *holder, goto error_bdev_put; } - mutex_lock(&uuid_mutex); device = device_list_add(path, disk_super, &new_device_added); if (IS_ERR(device)) { ret = PTR_ERR(device); @@ -1251,7 +1252,6 @@ int btrfs_scan_one_device(const char *path, fmode_t flags, void *holder, if (new_device_added) btrfs_free_stale_devices(path, device); } - mutex_unlock(&uuid_mutex); btrfs_release_disk_super(page); -- cgit v1.2.3 From f5194e34cabaddd348a90f950e0a8188dd26cdc0 Mon Sep 17 00:00:00 2001 From: David Sterba Date: Tue, 19 Jun 2018 17:09:47 +0200 Subject: btrfs: lift uuid_mutex to callers of btrfs_open_devices Prepartory work to fix race between mount and device scan. The callers will have to manage the critical section, eg. mount wants to scan and then call btrfs_open_devices without the ioctl scan walking in and modifying the fs devices in the meantime. Reviewed-by: Anand Jain Signed-off-by: David Sterba --- fs/btrfs/super.c | 2 ++ fs/btrfs/volumes.c | 4 ++-- 2 files changed, 4 insertions(+), 2 deletions(-) (limited to 'fs') diff --git a/fs/btrfs/super.c b/fs/btrfs/super.c index 0b6567f0c63d..d470eb6b9226 100644 --- a/fs/btrfs/super.c +++ b/fs/btrfs/super.c @@ -1567,7 +1567,9 @@ static struct dentry *btrfs_mount_root(struct file_system_type *fs_type, goto error_fs_info; } + mutex_lock(&uuid_mutex); error = btrfs_open_devices(fs_devices, mode, fs_type); + mutex_unlock(&uuid_mutex); if (error) goto error_fs_info; diff --git a/fs/btrfs/volumes.c b/fs/btrfs/volumes.c index df5dd6f67887..459cc2a2a31c 100644 --- a/fs/btrfs/volumes.c +++ b/fs/btrfs/volumes.c @@ -1142,7 +1142,8 @@ int btrfs_open_devices(struct btrfs_fs_devices *fs_devices, { int ret; - mutex_lock(&uuid_mutex); + lockdep_assert_held(&uuid_mutex); + mutex_lock(&fs_devices->device_list_mutex); if (fs_devices->opened) { fs_devices->opened++; @@ -1152,7 +1153,6 @@ int btrfs_open_devices(struct btrfs_fs_devices *fs_devices, ret = open_fs_devices(fs_devices, flags, holder); } mutex_unlock(&fs_devices->device_list_mutex); - mutex_unlock(&uuid_mutex); return ret; } -- cgit v1.2.3 From 5139cff598d42b1e531f40c84691a7e945f04553 Mon Sep 17 00:00:00 2001 From: David Sterba Date: Tue, 19 Jun 2018 17:50:25 +0200 Subject: btrfs: lift uuid_mutex to callers of btrfs_parse_early_options Prepartory work to fix race between mount and device scan. btrfs_parse_early_options calls the device scan from mount and we'll need to let mount completely manage the critical section. Reviewed-by: Anand Jain Signed-off-by: David Sterba --- fs/btrfs/super.c | 6 ++++-- 1 file changed, 4 insertions(+), 2 deletions(-) (limited to 'fs') diff --git a/fs/btrfs/super.c b/fs/btrfs/super.c index d470eb6b9226..de87b7b0367d 100644 --- a/fs/btrfs/super.c +++ b/fs/btrfs/super.c @@ -890,6 +890,8 @@ static int btrfs_parse_early_options(const char *options, fmode_t flags, char *device_name, *opts, *orig, *p; int error = 0; + lockdep_assert_held(&uuid_mutex); + if (!options) return 0; @@ -915,10 +917,8 @@ static int btrfs_parse_early_options(const char *options, fmode_t flags, error = -ENOMEM; goto out; } - mutex_lock(&uuid_mutex); error = btrfs_scan_one_device(device_name, flags, holder, fs_devices); - mutex_unlock(&uuid_mutex); kfree(device_name); if (error) goto out; @@ -1526,8 +1526,10 @@ static struct dentry *btrfs_mount_root(struct file_system_type *fs_type, if (!(flags & SB_RDONLY)) mode |= FMODE_WRITE; + mutex_lock(&uuid_mutex); error = btrfs_parse_early_options(data, mode, fs_type, &fs_devices); + mutex_unlock(&uuid_mutex); if (error) { return ERR_PTR(error); } -- cgit v1.2.3 From 399f7f4c42e8a58c8456264d5112287aefe44cf4 Mon Sep 17 00:00:00 2001 From: David Sterba Date: Tue, 19 Jun 2018 18:01:24 +0200 Subject: btrfs: reorder initialization before the mount locks uuid_mutex In preparation to take a big lock, move resource initialization before the critical section. It's not obvious from the diff, the desired order is: - initialize mount security options - allocate temporary fs_info - allocate superblock buffers Reviewed-by: Anand Jain Signed-off-by: David Sterba --- fs/btrfs/super.c | 30 ++++++++++++++---------------- 1 file changed, 14 insertions(+), 16 deletions(-) (limited to 'fs') diff --git a/fs/btrfs/super.c b/fs/btrfs/super.c index de87b7b0367d..d33fc1fc4285 100644 --- a/fs/btrfs/super.c +++ b/fs/btrfs/super.c @@ -1526,14 +1526,6 @@ static struct dentry *btrfs_mount_root(struct file_system_type *fs_type, if (!(flags & SB_RDONLY)) mode |= FMODE_WRITE; - mutex_lock(&uuid_mutex); - error = btrfs_parse_early_options(data, mode, fs_type, - &fs_devices); - mutex_unlock(&uuid_mutex); - if (error) { - return ERR_PTR(error); - } - security_init_mnt_opts(&new_sec_opts); if (data) { error = parse_security_options(data, &new_sec_opts); @@ -1541,12 +1533,6 @@ static struct dentry *btrfs_mount_root(struct file_system_type *fs_type, return ERR_PTR(error); } - mutex_lock(&uuid_mutex); - error = btrfs_scan_one_device(device_name, mode, fs_type, &fs_devices); - mutex_unlock(&uuid_mutex); - if (error) - goto error_sec_opts; - /* * Setup a dummy root and fs_info for test/set super. This is because * we don't actually fill this stuff out until open_ctree, but we need @@ -1559,8 +1545,6 @@ static struct dentry *btrfs_mount_root(struct file_system_type *fs_type, goto error_sec_opts; } - fs_info->fs_devices = fs_devices; - fs_info->super_copy = kzalloc(BTRFS_SUPER_INFO_SIZE, GFP_KERNEL); fs_info->super_for_commit = kzalloc(BTRFS_SUPER_INFO_SIZE, GFP_KERNEL); security_init_mnt_opts(&fs_info->security_opts); @@ -1569,6 +1553,20 @@ static struct dentry *btrfs_mount_root(struct file_system_type *fs_type, goto error_fs_info; } + mutex_lock(&uuid_mutex); + error = btrfs_parse_early_options(data, mode, fs_type, &fs_devices); + mutex_unlock(&uuid_mutex); + if (error) + goto error_fs_info; + + mutex_lock(&uuid_mutex); + error = btrfs_scan_one_device(device_name, mode, fs_type, &fs_devices); + mutex_unlock(&uuid_mutex); + if (error) + goto error_fs_info; + + fs_info->fs_devices = fs_devices; + mutex_lock(&uuid_mutex); error = btrfs_open_devices(fs_devices, mode, fs_type); mutex_unlock(&uuid_mutex); -- cgit v1.2.3 From 81ffd56b5745355b70d54ca4e1bdd0d64a66ff9f Mon Sep 17 00:00:00 2001 From: David Sterba Date: Tue, 19 Jun 2018 18:04:07 +0200 Subject: btrfs: fix mount and ioctl device scan ioctl race Technically this extends the critical section covered by uuid_mutex to: - parse early mount options -- here we can call device scan on paths that can be passed as 'device=/dev/...' - scan the device passed to mount - open the devices related to the fs_devices -- this increases fs_devices::opened The race can happen when mount calls one of the scans and there's another one called eg. by mkfs or 'btrfs dev scan': Mount Scan ----- ---- scan_one_device (dev1, fsid1) scan_one_device (dev2, fsid1) add the device free stale devices fsid1 fs_devices::opened == 0 find fsid1:dev1 free fsid1:dev1 if it's the last one, free fs_devices of fsid1 too open_devices (dev1, fsid1) dev1 not found When fixed, the uuid mutex will make sure that mount will increase fs_devices::opened and this will not be touched by the racing scan ioctl. Reported-and-tested-by: syzbot+909a5177749d7990ffa4@syzkaller.appspotmail.com Reported-and-tested-by: syzbot+ceb2606025ec1cc3479c@syzkaller.appspotmail.com Reviewed-by: Anand Jain Signed-off-by: David Sterba --- fs/btrfs/super.c | 12 ++++++------ 1 file changed, 6 insertions(+), 6 deletions(-) (limited to 'fs') diff --git a/fs/btrfs/super.c b/fs/btrfs/super.c index d33fc1fc4285..28ab75ebb983 100644 --- a/fs/btrfs/super.c +++ b/fs/btrfs/super.c @@ -1555,19 +1555,19 @@ static struct dentry *btrfs_mount_root(struct file_system_type *fs_type, mutex_lock(&uuid_mutex); error = btrfs_parse_early_options(data, mode, fs_type, &fs_devices); - mutex_unlock(&uuid_mutex); - if (error) + if (error) { + mutex_unlock(&uuid_mutex); goto error_fs_info; + } - mutex_lock(&uuid_mutex); error = btrfs_scan_one_device(device_name, mode, fs_type, &fs_devices); - mutex_unlock(&uuid_mutex); - if (error) + if (error) { + mutex_unlock(&uuid_mutex); goto error_fs_info; + } fs_info->fs_devices = fs_devices; - mutex_lock(&uuid_mutex); error = btrfs_open_devices(fs_devices, mode, fs_type); mutex_unlock(&uuid_mutex); if (error) -- cgit v1.2.3 From d64dcbd183abab251beb0fa0acd81a772a09887e Mon Sep 17 00:00:00 2001 From: Gu Jinxiang Date: Thu, 12 Jul 2018 14:23:15 +0800 Subject: btrfs: make fs_devices a local variable in btrfs_parse_early_options fs_devices is always passed to btrfs_scan_one_device which overrides it. In the call stack below fs_devices is passed to btrfs_scan_one_device from btrfs_mount_root. In btrfs_mount_root the output fs_devices of this call stack is not used. btrfs_mount_root btrfs_parse_early_options btrfs_scan_one_device So, it is not necessary to pass fs_devices from btrfs_mount_root, using a local variable in btrfs_parse_early_options is enough. Signed-off-by: Gu Jinxiang Reviewed-by: Anand Jain Reviewed-by: Nikolay Borisov Reviewed-by: David Sterba Signed-off-by: David Sterba --- fs/btrfs/super.c | 7 ++++--- 1 file changed, 4 insertions(+), 3 deletions(-) (limited to 'fs') diff --git a/fs/btrfs/super.c b/fs/btrfs/super.c index 28ab75ebb983..909ea2564e84 100644 --- a/fs/btrfs/super.c +++ b/fs/btrfs/super.c @@ -884,10 +884,11 @@ out: * only when we need to allocate a new super block. */ static int btrfs_parse_early_options(const char *options, fmode_t flags, - void *holder, struct btrfs_fs_devices **fs_devices) + void *holder) { substring_t args[MAX_OPT_ARGS]; char *device_name, *opts, *orig, *p; + struct btrfs_fs_devices *fs_devices = NULL; int error = 0; lockdep_assert_held(&uuid_mutex); @@ -918,7 +919,7 @@ static int btrfs_parse_early_options(const char *options, fmode_t flags, goto out; } error = btrfs_scan_one_device(device_name, - flags, holder, fs_devices); + flags, holder, &fs_devices); kfree(device_name); if (error) goto out; @@ -1554,7 +1555,7 @@ static struct dentry *btrfs_mount_root(struct file_system_type *fs_type, } mutex_lock(&uuid_mutex); - error = btrfs_parse_early_options(data, mode, fs_type, &fs_devices); + error = btrfs_parse_early_options(data, mode, fs_type); if (error) { mutex_unlock(&uuid_mutex); goto error_fs_info; -- cgit v1.2.3 From 36350e95a2b1feed6382fe38cc80f79ec35a1323 Mon Sep 17 00:00:00 2001 From: Gu Jinxiang Date: Thu, 12 Jul 2018 14:23:16 +0800 Subject: btrfs: return device pointer from btrfs_scan_one_device Return device pointer (with the IS_ERR semantics) from btrfs_scan_one_device so we don't have to return in through pointer. And since btrfs_fs_devices can be obtained from btrfs_device, return that. Signed-off-by: Gu Jinxiang Reviewed-by: Nikolay Borisov Reviewed-by: David Sterba [ fixed conflics after recent changes to btrfs_scan_one_device ] Signed-off-by: David Sterba --- fs/btrfs/super.c | 34 +++++++++++++++++++++------------- fs/btrfs/volumes.c | 18 +++++++----------- fs/btrfs/volumes.h | 4 ++-- 3 files changed, 30 insertions(+), 26 deletions(-) (limited to 'fs') diff --git a/fs/btrfs/super.c b/fs/btrfs/super.c index 909ea2564e84..5384afae3364 100644 --- a/fs/btrfs/super.c +++ b/fs/btrfs/super.c @@ -888,7 +888,7 @@ static int btrfs_parse_early_options(const char *options, fmode_t flags, { substring_t args[MAX_OPT_ARGS]; char *device_name, *opts, *orig, *p; - struct btrfs_fs_devices *fs_devices = NULL; + struct btrfs_device *device = NULL; int error = 0; lockdep_assert_held(&uuid_mutex); @@ -918,11 +918,13 @@ static int btrfs_parse_early_options(const char *options, fmode_t flags, error = -ENOMEM; goto out; } - error = btrfs_scan_one_device(device_name, - flags, holder, &fs_devices); + device = btrfs_scan_one_device(device_name, flags, + holder); kfree(device_name); - if (error) + if (IS_ERR(device)) { + error = PTR_ERR(device); goto out; + } } } @@ -1518,6 +1520,7 @@ static struct dentry *btrfs_mount_root(struct file_system_type *fs_type, { struct block_device *bdev = NULL; struct super_block *s; + struct btrfs_device *device = NULL; struct btrfs_fs_devices *fs_devices = NULL; struct btrfs_fs_info *fs_info = NULL; struct security_mnt_opts new_sec_opts; @@ -1561,12 +1564,14 @@ static struct dentry *btrfs_mount_root(struct file_system_type *fs_type, goto error_fs_info; } - error = btrfs_scan_one_device(device_name, mode, fs_type, &fs_devices); - if (error) { + device = btrfs_scan_one_device(device_name, mode, fs_type); + if (IS_ERR(device)) { mutex_unlock(&uuid_mutex); + error = PTR_ERR(device); goto error_fs_info; } + fs_devices = device->fs_devices; fs_info->fs_devices = fs_devices; error = btrfs_open_devices(fs_devices, mode, fs_type); @@ -2227,7 +2232,7 @@ static long btrfs_control_ioctl(struct file *file, unsigned int cmd, unsigned long arg) { struct btrfs_ioctl_vol_args *vol; - struct btrfs_fs_devices *fs_devices; + struct btrfs_device *device = NULL; int ret = -ENOTTY; if (!capable(CAP_SYS_ADMIN)) @@ -2240,19 +2245,22 @@ static long btrfs_control_ioctl(struct file *file, unsigned int cmd, switch (cmd) { case BTRFS_IOC_SCAN_DEV: mutex_lock(&uuid_mutex); - ret = btrfs_scan_one_device(vol->name, FMODE_READ, - &btrfs_root_fs_type, &fs_devices); + device = btrfs_scan_one_device(vol->name, FMODE_READ, + &btrfs_root_fs_type); + ret = PTR_ERR_OR_ZERO(device); mutex_unlock(&uuid_mutex); break; case BTRFS_IOC_DEVICES_READY: mutex_lock(&uuid_mutex); - ret = btrfs_scan_one_device(vol->name, FMODE_READ, - &btrfs_root_fs_type, &fs_devices); - if (ret) { + device = btrfs_scan_one_device(vol->name, FMODE_READ, + &btrfs_root_fs_type); + if (IS_ERR(device)) { mutex_unlock(&uuid_mutex); + ret = PTR_ERR(device); break; } - ret = !(fs_devices->num_devices == fs_devices->total_devices); + ret = !(device->fs_devices->num_devices == + device->fs_devices->total_devices); mutex_unlock(&uuid_mutex); break; case BTRFS_IOC_GET_SUPPORTED_FEATURES: diff --git a/fs/btrfs/volumes.c b/fs/btrfs/volumes.c index 459cc2a2a31c..fd9d4e056b37 100644 --- a/fs/btrfs/volumes.c +++ b/fs/btrfs/volumes.c @@ -1213,15 +1213,14 @@ static int btrfs_read_disk_super(struct block_device *bdev, u64 bytenr, * and we are not allowed to call set_blocksize during the scan. The superblock * is read via pagecache */ -int btrfs_scan_one_device(const char *path, fmode_t flags, void *holder, - struct btrfs_fs_devices **fs_devices_ret) +struct btrfs_device *btrfs_scan_one_device(const char *path, fmode_t flags, + void *holder) { struct btrfs_super_block *disk_super; bool new_device_added = false; - struct btrfs_device *device; + struct btrfs_device *device = NULL; struct block_device *bdev; struct page *page; - int ret = 0; u64 bytenr; lockdep_assert_held(&uuid_mutex); @@ -1237,18 +1236,15 @@ int btrfs_scan_one_device(const char *path, fmode_t flags, void *holder, bdev = blkdev_get_by_path(path, flags, holder); if (IS_ERR(bdev)) - return PTR_ERR(bdev); + return ERR_CAST(bdev); if (btrfs_read_disk_super(bdev, bytenr, &page, &disk_super)) { - ret = -EINVAL; + device = ERR_PTR(-EINVAL); goto error_bdev_put; } device = device_list_add(path, disk_super, &new_device_added); - if (IS_ERR(device)) { - ret = PTR_ERR(device); - } else { - *fs_devices_ret = device->fs_devices; + if (!IS_ERR(device)) { if (new_device_added) btrfs_free_stale_devices(path, device); } @@ -1258,7 +1254,7 @@ int btrfs_scan_one_device(const char *path, fmode_t flags, void *holder, error_bdev_put: blkdev_put(bdev, flags); - return ret; + return device; } static int contains_pending_extent(struct btrfs_transaction *transaction, diff --git a/fs/btrfs/volumes.h b/fs/btrfs/volumes.h index 9665b84b1026..06d8bb7dd557 100644 --- a/fs/btrfs/volumes.h +++ b/fs/btrfs/volumes.h @@ -403,8 +403,8 @@ blk_status_t btrfs_map_bio(struct btrfs_fs_info *fs_info, struct bio *bio, int mirror_num, int async_submit); int btrfs_open_devices(struct btrfs_fs_devices *fs_devices, fmode_t flags, void *holder); -int btrfs_scan_one_device(const char *path, fmode_t flags, void *holder, - struct btrfs_fs_devices **fs_devices_ret); +struct btrfs_device *btrfs_scan_one_device(const char *path, + fmode_t flags, void *holder); int btrfs_close_devices(struct btrfs_fs_devices *fs_devices); void btrfs_free_extra_devids(struct btrfs_fs_devices *fs_devices, int step); void btrfs_assign_next_active_device(struct btrfs_fs_info *fs_info, -- cgit v1.2.3 From d814a49198eafa6163698bdd93961302f3a877a4 Mon Sep 17 00:00:00 2001 From: Ethan Lien Date: Mon, 2 Jul 2018 15:44:58 +0800 Subject: btrfs: use correct compare function of dirty_metadata_bytes We use customized, nodesize batch value to update dirty_metadata_bytes. We should also use batch version of compare function or we will easily goto fast path and get false result from percpu_counter_compare(). Fixes: e2d845211eda ("Btrfs: use percpu counter for dirty metadata count") CC: stable@vger.kernel.org # 4.4+ Signed-off-by: Ethan Lien Reviewed-by: Nikolay Borisov Signed-off-by: David Sterba --- fs/btrfs/disk-io.c | 10 ++++++---- 1 file changed, 6 insertions(+), 4 deletions(-) (limited to 'fs') diff --git a/fs/btrfs/disk-io.c b/fs/btrfs/disk-io.c index 6023eed3e805..e3858b2fe014 100644 --- a/fs/btrfs/disk-io.c +++ b/fs/btrfs/disk-io.c @@ -959,8 +959,9 @@ static int btree_writepages(struct address_space *mapping, fs_info = BTRFS_I(mapping->host)->root->fs_info; /* this is a bit racy, but that's ok */ - ret = percpu_counter_compare(&fs_info->dirty_metadata_bytes, - BTRFS_DIRTY_METADATA_THRESH); + ret = __percpu_counter_compare(&fs_info->dirty_metadata_bytes, + BTRFS_DIRTY_METADATA_THRESH, + fs_info->dirty_metadata_batch); if (ret < 0) return 0; } @@ -4134,8 +4135,9 @@ static void __btrfs_btree_balance_dirty(struct btrfs_fs_info *fs_info, if (flush_delayed) btrfs_balance_delayed_items(fs_info); - ret = percpu_counter_compare(&fs_info->dirty_metadata_bytes, - BTRFS_DIRTY_METADATA_THRESH); + ret = __percpu_counter_compare(&fs_info->dirty_metadata_bytes, + BTRFS_DIRTY_METADATA_THRESH, + fs_info->dirty_metadata_batch); if (ret > 0) { balance_dirty_pages_ratelimited(fs_info->btree_inode->i_mapping); } -- cgit v1.2.3 From dec59fa3a760952fc71f2e122e66a7291109670a Mon Sep 17 00:00:00 2001 From: Ethan Lien Date: Fri, 13 Jul 2018 16:50:42 +0800 Subject: btrfs: use customized batch size for total_bytes_pinned In commit b150a4f10d878 ("Btrfs: use a percpu to keep track of possibly pinned bytes") we use total_bytes_pinned to track how many bytes we are going to free in this transaction. When we are close to ENOSPC, we check it and know if we can make the allocation by commit the current transaction. For every data/metadata extent we are going to free, we add total_bytes_pinned in btrfs_free_extent() and btrfs_free_tree_block(), and release it in unpin_extent_range() when we finish the transaction. So this is a variable we frequently update but rarely read - just the suitable use of percpu_counter. But in previous commit we update total_bytes_pinned by default 32 batch size, making every update essentially a spin lock protected update. Since every spin lock/unlock operation involves syncing a globally used variable and some kind of barrier in a SMP system, this is more expensive than using total_bytes_pinned as a simple atomic64_t. So fix this by using a customized batch size. Since we only read total_bytes_pinned when we are close to ENOSPC and fail to allocate new chunk, we can use a really large batch size and have nearly no penalty in most cases. [Test] We tested the patch on a 4-cores x86 machine: 1. fallocate a 16GiB size test file 2. take snapshot (so all following writes will be COW) 3. run a 180 sec, 4 jobs, 4K random write fio on test file We also added a temporary lockdep class on percpu_counter's spin lock used by total_bytes_pinned to track it by lock_stat. [Results] unpatched: lock_stat version 0.4 ----------------------------------------------------------------------- class name con-bounces contentions waittime-min waittime-max waittime-total waittime-avg acq-bounces acquisitions holdtime-min holdtime-max holdtime-total holdtime-avg total_bytes_pinned_percpu: 82 82 0.21 0.61 29.46 0.36 298340 635973 0.09 11.01 173476.25 0.27 patched: lock_stat version 0.4 ----------------------------------------------------------------------- class name con-bounces contentions waittime-min waittime-max waittime-total waittime-avg acq-bounces acquisitions holdtime-min holdtime-max holdtime-total holdtime-avg total_bytes_pinned_percpu: 1 1 0.62 0.62 0.62 0.62 13601 31542 0.14 9.61 11016.90 0.35 [Analysis] Since the spin lock only protects a single in-memory variable, the contentions (number of lock acquisitions that had to wait) in both unpatched and patched version are low. But when we see acquisitions and acq-bounces, we get much lower counts in patched version. Here the most important metric is acq-bounces. It means how many times the lock gets transferred between different cpus, so the patch can really reduce cacheline bouncing of spin lock (also the global counter of percpu_counter) in a SMP system. Fixes: b150a4f10d878 ("Btrfs: use a percpu to keep track of possibly pinned bytes") Signed-off-by: Ethan Lien Reviewed-by: Nikolay Borisov Reviewed-by: David Sterba Signed-off-by: David Sterba --- fs/btrfs/ctree.h | 8 ++++++++ fs/btrfs/extent-tree.c | 39 ++++++++++++++++++++++++--------------- 2 files changed, 32 insertions(+), 15 deletions(-) (limited to 'fs') diff --git a/fs/btrfs/ctree.h b/fs/btrfs/ctree.h index 427ca5de8542..bf1451bf3ed7 100644 --- a/fs/btrfs/ctree.h +++ b/fs/btrfs/ctree.h @@ -84,6 +84,14 @@ static const int btrfs_csum_sizes[] = { 4 }; #define BTRFS_DIRTY_METADATA_THRESH SZ_32M +/* + * Use large batch size to reduce overhead of metadata updates. On the reader + * side, we only read it when we are close to ENOSPC and the read overhead is + * mostly related to the number of CPUs, so it is OK to use arbitrary large + * value here. + */ +#define BTRFS_TOTAL_BYTES_PINNED_BATCH SZ_128M + #define BTRFS_MAX_EXTENT_SIZE SZ_128M diff --git a/fs/btrfs/extent-tree.c b/fs/btrfs/extent-tree.c index 6bba288133b8..2d1f893902f1 100644 --- a/fs/btrfs/extent-tree.c +++ b/fs/btrfs/extent-tree.c @@ -755,7 +755,8 @@ static void add_pinned_bytes(struct btrfs_fs_info *fs_info, s64 num_bytes, space_info = __find_space_info(fs_info, flags); ASSERT(space_info); - percpu_counter_add(&space_info->total_bytes_pinned, num_bytes); + percpu_counter_add_batch(&space_info->total_bytes_pinned, num_bytes, + BTRFS_TOTAL_BYTES_PINNED_BATCH); } /* @@ -2473,8 +2474,9 @@ static int cleanup_ref_head(struct btrfs_trans_handle *trans, flags = BTRFS_BLOCK_GROUP_METADATA; space_info = __find_space_info(fs_info, flags); ASSERT(space_info); - percpu_counter_add(&space_info->total_bytes_pinned, - -head->num_bytes); + percpu_counter_add_batch(&space_info->total_bytes_pinned, + -head->num_bytes, + BTRFS_TOTAL_BYTES_PINNED_BATCH); if (head->is_data) { spin_lock(&delayed_refs->lock); @@ -4178,9 +4180,10 @@ again: * allocation, and no removed chunk in current transaction, * don't bother committing the transaction. */ - have_pinned_space = percpu_counter_compare( + have_pinned_space = __percpu_counter_compare( &data_sinfo->total_bytes_pinned, - used + bytes - data_sinfo->total_bytes); + used + bytes - data_sinfo->total_bytes, + BTRFS_TOTAL_BYTES_PINNED_BATCH); spin_unlock(&data_sinfo->lock); /* commit the current transaction and try again */ @@ -4782,8 +4785,9 @@ static int may_commit_transaction(struct btrfs_fs_info *fs_info, return 0; /* See if there is enough pinned space to make this reservation */ - if (percpu_counter_compare(&space_info->total_bytes_pinned, - bytes) >= 0) + if (__percpu_counter_compare(&space_info->total_bytes_pinned, + bytes, + BTRFS_TOTAL_BYTES_PINNED_BATCH) >= 0) goto commit; /* @@ -4800,8 +4804,9 @@ static int may_commit_transaction(struct btrfs_fs_info *fs_info, bytes -= delayed_rsv->size; spin_unlock(&delayed_rsv->lock); - if (percpu_counter_compare(&space_info->total_bytes_pinned, - bytes) < 0) { + if (__percpu_counter_compare(&space_info->total_bytes_pinned, + bytes, + BTRFS_TOTAL_BYTES_PINNED_BATCH) < 0) { return -ENOSPC; } @@ -6138,8 +6143,9 @@ static int update_block_group(struct btrfs_trans_handle *trans, trace_btrfs_space_reservation(info, "pinned", cache->space_info->flags, num_bytes, 1); - percpu_counter_add(&cache->space_info->total_bytes_pinned, - num_bytes); + percpu_counter_add_batch(&cache->space_info->total_bytes_pinned, + num_bytes, + BTRFS_TOTAL_BYTES_PINNED_BATCH); set_extent_dirty(info->pinned_extents, bytenr, bytenr + num_bytes - 1, GFP_NOFS | __GFP_NOFAIL); @@ -6217,7 +6223,8 @@ static int pin_down_extent(struct btrfs_fs_info *fs_info, trace_btrfs_space_reservation(fs_info, "pinned", cache->space_info->flags, num_bytes, 1); - percpu_counter_add(&cache->space_info->total_bytes_pinned, num_bytes); + percpu_counter_add_batch(&cache->space_info->total_bytes_pinned, + num_bytes, BTRFS_TOTAL_BYTES_PINNED_BATCH); set_extent_dirty(fs_info->pinned_extents, bytenr, bytenr + num_bytes - 1, GFP_NOFS | __GFP_NOFAIL); return 0; @@ -6581,7 +6588,8 @@ static int unpin_extent_range(struct btrfs_fs_info *fs_info, trace_btrfs_space_reservation(fs_info, "pinned", space_info->flags, len, 0); space_info->max_extent_size = 0; - percpu_counter_add(&space_info->total_bytes_pinned, -len); + percpu_counter_add_batch(&space_info->total_bytes_pinned, + -len, BTRFS_TOTAL_BYTES_PINNED_BATCH); if (cache->ro) { space_info->bytes_readonly += len; readonly = true; @@ -10603,8 +10611,9 @@ void btrfs_delete_unused_bgs(struct btrfs_fs_info *fs_info) space_info->bytes_pinned -= block_group->pinned; space_info->bytes_readonly += block_group->pinned; - percpu_counter_add(&space_info->total_bytes_pinned, - -block_group->pinned); + percpu_counter_add_batch(&space_info->total_bytes_pinned, + -block_group->pinned, + BTRFS_TOTAL_BYTES_PINNED_BATCH); block_group->pinned = 0; spin_unlock(&block_group->lock); -- cgit v1.2.3 From 2556fbb0bead7929ddf67f8b4184f434cee4e7d7 Mon Sep 17 00:00:00 2001 From: Nikolay Borisov Date: Wed, 18 Apr 2018 10:27:57 +0300 Subject: btrfs: Rewrite retry logic in do_chunk_alloc do_chunk_alloc implements logic to detect whether there is currently pending chunk allocation (by means of space_info->chunk_alloc being set) and if so it loops around to the 'again' label. Additionally, based on the state of the space_info (e.g. whether it's full or not) and the return value of should_alloc_chunk() it decides whether this is a "hard" error (ENOSPC) or we can just return 0. This patch refactors all of this: 1. Put order to the scattered ifs handling the various cases in an easy-to-read if {} else if{} branches. This makes clear the various cases we are interested in handling. 2. Call should_alloc_chunk only once and use the result in the if/else if constructs. All of this is done under space_info->lock, so even before multiple calls of should_alloc_chunk were unnecessary. 3. Rewrite the "do {} while()" loop currently implemented via label into an explicit loop construct. 4. Move the mutex locking for the case where the caller is the one doing the allocation. For the case where the caller needs to wait a concurrent allocation, introduce a pair of mutex_lock/mutex_unlock to act as a barrier and reword the comment. 5. Switch local vars to bool type where pertinent. All in all this shouldn't introduce any functional changes. Signed-off-by: Nikolay Borisov Reviewed-by: David Sterba Signed-off-by: David Sterba --- fs/btrfs/extent-tree.c | 74 +++++++++++++++++++++++++------------------------- 1 file changed, 37 insertions(+), 37 deletions(-) (limited to 'fs') diff --git a/fs/btrfs/extent-tree.c b/fs/btrfs/extent-tree.c index 2d1f893902f1..bbd756223b23 100644 --- a/fs/btrfs/extent-tree.c +++ b/fs/btrfs/extent-tree.c @@ -4450,7 +4450,8 @@ static int do_chunk_alloc(struct btrfs_trans_handle *trans, u64 flags, { struct btrfs_fs_info *fs_info = trans->fs_info; struct btrfs_space_info *space_info; - int wait_for_alloc = 0; + bool wait_for_alloc = false; + bool should_alloc = false; int ret = 0; /* Don't re-enter if we're already allocating a chunk */ @@ -4460,45 +4461,44 @@ static int do_chunk_alloc(struct btrfs_trans_handle *trans, u64 flags, space_info = __find_space_info(fs_info, flags); ASSERT(space_info); -again: - spin_lock(&space_info->lock); - if (force < space_info->force_alloc) - force = space_info->force_alloc; - if (space_info->full) { - if (should_alloc_chunk(fs_info, space_info, force)) - ret = -ENOSPC; - else - ret = 0; - spin_unlock(&space_info->lock); - return ret; - } - - if (!should_alloc_chunk(fs_info, space_info, force)) { - spin_unlock(&space_info->lock); - return 0; - } else if (space_info->chunk_alloc) { - wait_for_alloc = 1; - } else { - space_info->chunk_alloc = 1; - } - - spin_unlock(&space_info->lock); - - mutex_lock(&fs_info->chunk_mutex); + do { + spin_lock(&space_info->lock); + if (force < space_info->force_alloc) + force = space_info->force_alloc; + should_alloc = should_alloc_chunk(fs_info, space_info, force); + if (space_info->full) { + /* No more free physical space */ + if (should_alloc) + ret = -ENOSPC; + else + ret = 0; + spin_unlock(&space_info->lock); + return ret; + } else if (!should_alloc) { + spin_unlock(&space_info->lock); + return 0; + } else if (space_info->chunk_alloc) { + /* + * Someone is already allocating, so we need to block + * until this someone is finished and then loop to + * recheck if we should continue with our allocation + * attempt. + */ + wait_for_alloc = true; + spin_unlock(&space_info->lock); + mutex_lock(&fs_info->chunk_mutex); + mutex_unlock(&fs_info->chunk_mutex); + } else { + /* Proceed with allocation */ + space_info->chunk_alloc = 1; + wait_for_alloc = false; + spin_unlock(&space_info->lock); + } - /* - * The chunk_mutex is held throughout the entirety of a chunk - * allocation, so once we've acquired the chunk_mutex we know that the - * other guy is done and we need to recheck and see if we should - * allocate. - */ - if (wait_for_alloc) { - mutex_unlock(&fs_info->chunk_mutex); - wait_for_alloc = 0; cond_resched(); - goto again; - } + } while (wait_for_alloc); + mutex_lock(&fs_info->chunk_mutex); trans->allocating_chunk = true; /* -- cgit v1.2.3 From 031f24da2c8a7b611331c368d7bfabccafda09fa Mon Sep 17 00:00:00 2001 From: Qu Wenruo Date: Tue, 22 May 2018 16:43:47 +0800 Subject: btrfs: Use btrfs_mark_bg_unused to replace open code Introduce a small helper, btrfs_mark_bg_unused(), to acquire locks and add a block group to unused_bgs list. No functional modification, and only 3 callers are involved. Signed-off-by: Qu Wenruo Reviewed-by: Nikolay Borisov Signed-off-by: David Sterba --- fs/btrfs/ctree.h | 1 + fs/btrfs/extent-tree.c | 36 +++++++++++++++++------------------- fs/btrfs/scrub.c | 9 +-------- 3 files changed, 19 insertions(+), 27 deletions(-) (limited to 'fs') diff --git a/fs/btrfs/ctree.h b/fs/btrfs/ctree.h index bf1451bf3ed7..ee1e152cb94b 100644 --- a/fs/btrfs/ctree.h +++ b/fs/btrfs/ctree.h @@ -2801,6 +2801,7 @@ void btrfs_wait_for_snapshot_creation(struct btrfs_root *root); void check_system_chunk(struct btrfs_trans_handle *trans, const u64 type); u64 add_new_free_space(struct btrfs_block_group_cache *block_group, u64 start, u64 end); +void btrfs_mark_bg_unused(struct btrfs_block_group_cache *bg); /* ctree.c */ int btrfs_bin_search(struct extent_buffer *eb, const struct btrfs_key *key, diff --git a/fs/btrfs/extent-tree.c b/fs/btrfs/extent-tree.c index bbd756223b23..ced26ba8d392 100644 --- a/fs/btrfs/extent-tree.c +++ b/fs/btrfs/extent-tree.c @@ -6166,16 +6166,8 @@ static int update_block_group(struct btrfs_trans_handle *trans, * dirty list to avoid races between cleaner kthread and space * cache writeout. */ - if (!alloc && old_val == 0) { - spin_lock(&info->unused_bgs_lock); - if (list_empty(&cache->bg_list)) { - btrfs_get_block_group(cache); - trace_btrfs_add_unused_block_group(cache); - list_add_tail(&cache->bg_list, - &info->unused_bgs); - } - spin_unlock(&info->unused_bgs_lock); - } + if (!alloc && old_val == 0) + btrfs_mark_bg_unused(cache); btrfs_put_block_group(cache); total -= num_bytes; @@ -9987,15 +9979,8 @@ int btrfs_read_block_groups(struct btrfs_fs_info *info) if (btrfs_chunk_readonly(info, cache->key.objectid)) { inc_block_group_ro(cache, 1); } else if (btrfs_block_group_used(&cache->item) == 0) { - spin_lock(&info->unused_bgs_lock); - /* Should always be true but just in case. */ - if (list_empty(&cache->bg_list)) { - btrfs_get_block_group(cache); - trace_btrfs_add_unused_block_group(cache); - list_add_tail(&cache->bg_list, - &info->unused_bgs); - } - spin_unlock(&info->unused_bgs_lock); + ASSERT(list_empty(&cache->bg_list)); + btrfs_mark_bg_unused(cache); } } @@ -10914,3 +10899,16 @@ void btrfs_wait_for_snapshot_creation(struct btrfs_root *root) !atomic_read(&root->will_be_snapshotted)); } } + +void btrfs_mark_bg_unused(struct btrfs_block_group_cache *bg) +{ + struct btrfs_fs_info *fs_info = bg->fs_info; + + spin_lock(&fs_info->unused_bgs_lock); + if (list_empty(&bg->bg_list)) { + btrfs_get_block_group(bg); + trace_btrfs_add_unused_block_group(bg); + list_add_tail(&bg->bg_list, &fs_info->unused_bgs); + } + spin_unlock(&fs_info->unused_bgs_lock); +} diff --git a/fs/btrfs/scrub.c b/fs/btrfs/scrub.c index bf4f262f9a52..1235ad8dd9d7 100644 --- a/fs/btrfs/scrub.c +++ b/fs/btrfs/scrub.c @@ -3951,14 +3951,7 @@ int scrub_enumerate_chunks(struct scrub_ctx *sctx, if (!cache->removed && !cache->ro && cache->reserved == 0 && btrfs_block_group_used(&cache->item) == 0) { spin_unlock(&cache->lock); - spin_lock(&fs_info->unused_bgs_lock); - if (list_empty(&cache->bg_list)) { - btrfs_get_block_group(cache); - trace_btrfs_add_unused_block_group(cache); - list_add_tail(&cache->bg_list, - &fs_info->unused_bgs); - } - spin_unlock(&fs_info->unused_bgs_lock); + btrfs_mark_bg_unused(cache); } else { spin_unlock(&cache->lock); } -- cgit v1.2.3 From c8389d4c0d6eb7c0b7f8b8a98620874f9123cd20 Mon Sep 17 00:00:00 2001 From: Lu Fengqi Date: Tue, 17 Jul 2018 16:58:22 +0800 Subject: btrfs: qgroup: cleanup the unused srcroot from btrfs_qgroup_inherit Since commit 0b246afa62b0 ("btrfs: root->fs_info cleanup, add fs_info convenience variables"), the srcroot is no longer used to get fs_info::nodesize. In fact, it can be dropped after commit 707e8a071528 ("btrfs: use nodesize everywhere, kill leafsize"). Signed-off-by: Lu Fengqi Reviewed-by: David Sterba Signed-off-by: David Sterba --- fs/btrfs/qgroup.c | 17 +---------------- 1 file changed, 1 insertion(+), 16 deletions(-) (limited to 'fs') diff --git a/fs/btrfs/qgroup.c b/fs/btrfs/qgroup.c index 97a59a444500..e0bd48c5a98b 100644 --- a/fs/btrfs/qgroup.c +++ b/fs/btrfs/qgroup.c @@ -2287,22 +2287,6 @@ int btrfs_qgroup_inherit(struct btrfs_trans_handle *trans, if (ret) goto out; - if (srcid) { - struct btrfs_root *srcroot; - struct btrfs_key srckey; - - srckey.objectid = srcid; - srckey.type = BTRFS_ROOT_ITEM_KEY; - srckey.offset = (u64)-1; - srcroot = btrfs_read_fs_root_no_name(fs_info, &srckey); - if (IS_ERR(srcroot)) { - ret = PTR_ERR(srcroot); - goto out; - } - - level_size = fs_info->nodesize; - } - /* * add qgroup to all inherited groups */ @@ -2359,6 +2343,7 @@ int btrfs_qgroup_inherit(struct btrfs_trans_handle *trans, * our counts don't go crazy, so at this point the only * difference between the two roots should be the root node. */ + level_size = fs_info->nodesize; dstgroup->rfer = srcgroup->rfer; dstgroup->rfer_cmpr = srcgroup->rfer_cmpr; dstgroup->excl = level_size; -- cgit v1.2.3 From fa59f27c8c35bbe00af8eff23de446a7f4b048b0 Mon Sep 17 00:00:00 2001 From: Anand Jain Date: Mon, 16 Jul 2018 22:18:07 +0800 Subject: btrfs: rename btrfs_parse_early_options Rename btrfs_parse_early_options() to btrfs_parse_device_options(). As btrfs_parse_early_options() parses the -o device options and scan the device provided. So this rename specifies its action. Also the function name is in line with btrfs_parse_subvol_options(). No functional changes. Signed-off-by: Anand Jain Signed-off-by: David Sterba --- fs/btrfs/super.c | 13 ++++++------- 1 file changed, 6 insertions(+), 7 deletions(-) (limited to 'fs') diff --git a/fs/btrfs/super.c b/fs/btrfs/super.c index 5384afae3364..d7a54c648c5f 100644 --- a/fs/btrfs/super.c +++ b/fs/btrfs/super.c @@ -465,9 +465,8 @@ int btrfs_parse_options(struct btrfs_fs_info *info, char *options, case Opt_subvolrootid: case Opt_device: /* - * These are parsed by btrfs_parse_subvol_options - * and btrfs_parse_early_options - * and can be happily ignored here. + * These are parsed by btrfs_parse_subvol_options or + * btrfs_parse_device_options and can be ignored here. */ break; case Opt_nodatasum: @@ -883,8 +882,8 @@ out: * All other options will be parsed on much later in the mount process and * only when we need to allocate a new super block. */ -static int btrfs_parse_early_options(const char *options, fmode_t flags, - void *holder) +static int btrfs_parse_device_options(const char *options, fmode_t flags, + void *holder) { substring_t args[MAX_OPT_ARGS]; char *device_name, *opts, *orig, *p; @@ -951,7 +950,7 @@ static int btrfs_parse_subvol_options(const char *options, char **subvol_name, /* * strsep changes the string, duplicate it because - * btrfs_parse_early_options gets called later + * btrfs_parse_device_options gets called later */ opts = kstrdup(options, GFP_KERNEL); if (!opts) @@ -1558,7 +1557,7 @@ static struct dentry *btrfs_mount_root(struct file_system_type *fs_type, } mutex_lock(&uuid_mutex); - error = btrfs_parse_early_options(data, mode, fs_type); + error = btrfs_parse_device_options(data, mode, fs_type); if (error) { mutex_unlock(&uuid_mutex); goto error_fs_info; -- cgit v1.2.3 From 711169c40f908df6df91ba2672d05b44243833e4 Mon Sep 17 00:00:00 2001 From: Lu Fengqi Date: Wed, 18 Jul 2018 14:45:24 +0800 Subject: btrfs: qgroup: Drop quota_root parameter from add_qgroup_relation_item It can be fetched from the transaction handle. Signed-off-by: Lu Fengqi Signed-off-by: David Sterba --- fs/btrfs/qgroup.c | 18 +++++++++--------- 1 file changed, 9 insertions(+), 9 deletions(-) (limited to 'fs') diff --git a/fs/btrfs/qgroup.c b/fs/btrfs/qgroup.c index e0bd48c5a98b..4f523b7a3e91 100644 --- a/fs/btrfs/qgroup.c +++ b/fs/btrfs/qgroup.c @@ -530,11 +530,11 @@ void btrfs_free_qgroup_config(struct btrfs_fs_info *fs_info) fs_info->qgroup_ulist = NULL; } -static int add_qgroup_relation_item(struct btrfs_trans_handle *trans, - struct btrfs_root *quota_root, - u64 src, u64 dst) +static int add_qgroup_relation_item(struct btrfs_trans_handle *trans, u64 src, + u64 dst) { int ret; + struct btrfs_root *quota_root = trans->fs_info->quota_root; struct btrfs_path *path; struct btrfs_key key; @@ -1274,11 +1274,11 @@ int btrfs_add_qgroup_relation(struct btrfs_trans_handle *trans, } } - ret = add_qgroup_relation_item(trans, quota_root, src, dst); + ret = add_qgroup_relation_item(trans, src, dst); if (ret) goto out; - ret = add_qgroup_relation_item(trans, quota_root, dst, src); + ret = add_qgroup_relation_item(trans, dst, src); if (ret) { del_qgroup_relation_item(trans, quota_root, src, dst); goto out; @@ -2295,12 +2295,12 @@ int btrfs_qgroup_inherit(struct btrfs_trans_handle *trans, for (i = 0; i < inherit->num_qgroups; ++i, ++i_qgroups) { if (*i_qgroups == 0) continue; - ret = add_qgroup_relation_item(trans, quota_root, - objectid, *i_qgroups); + ret = add_qgroup_relation_item(trans, objectid, + *i_qgroups); if (ret && ret != -EEXIST) goto out; - ret = add_qgroup_relation_item(trans, quota_root, - *i_qgroups, objectid); + ret = add_qgroup_relation_item(trans, *i_qgroups, + objectid); if (ret && ret != -EEXIST) goto out; } -- cgit v1.2.3 From 99d7f09ac01cbea28767a84d4d34dd5b1922a245 Mon Sep 17 00:00:00 2001 From: Lu Fengqi Date: Wed, 18 Jul 2018 14:45:25 +0800 Subject: btrfs: qgroup: Drop quota_root parameter from del_qgroup_relation_item It can be fetched from the transaction handle. Signed-off-by: Lu Fengqi Signed-off-by: David Sterba --- fs/btrfs/qgroup.c | 12 ++++++------ 1 file changed, 6 insertions(+), 6 deletions(-) (limited to 'fs') diff --git a/fs/btrfs/qgroup.c b/fs/btrfs/qgroup.c index 4f523b7a3e91..c22f1e655a60 100644 --- a/fs/btrfs/qgroup.c +++ b/fs/btrfs/qgroup.c @@ -554,11 +554,11 @@ static int add_qgroup_relation_item(struct btrfs_trans_handle *trans, u64 src, return ret; } -static int del_qgroup_relation_item(struct btrfs_trans_handle *trans, - struct btrfs_root *quota_root, - u64 src, u64 dst) +static int del_qgroup_relation_item(struct btrfs_trans_handle *trans, u64 src, + u64 dst) { int ret; + struct btrfs_root *quota_root = trans->fs_info->quota_root; struct btrfs_path *path; struct btrfs_key key; @@ -1280,7 +1280,7 @@ int btrfs_add_qgroup_relation(struct btrfs_trans_handle *trans, ret = add_qgroup_relation_item(trans, dst, src); if (ret) { - del_qgroup_relation_item(trans, quota_root, src, dst); + del_qgroup_relation_item(trans, src, dst); goto out; } @@ -1334,8 +1334,8 @@ static int __del_qgroup_relation(struct btrfs_trans_handle *trans, ret = -ENOENT; goto out; exist: - ret = del_qgroup_relation_item(trans, quota_root, src, dst); - err = del_qgroup_relation_item(trans, quota_root, dst, src); + ret = del_qgroup_relation_item(trans, src, dst); + err = del_qgroup_relation_item(trans, dst, src); if (err && !ret) ret = err; -- cgit v1.2.3 From 69104618f4b9dd445109e8dd755406427bd75b76 Mon Sep 17 00:00:00 2001 From: Lu Fengqi Date: Wed, 18 Jul 2018 14:45:26 +0800 Subject: btrfs: qgroup: Drop quota_root parameter from del_qgroup_item It can be fetched from the transaction handle. Signed-off-by: Lu Fengqi Signed-off-by: David Sterba --- fs/btrfs/qgroup.c | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) (limited to 'fs') diff --git a/fs/btrfs/qgroup.c b/fs/btrfs/qgroup.c index c22f1e655a60..67e0f4f38c31 100644 --- a/fs/btrfs/qgroup.c +++ b/fs/btrfs/qgroup.c @@ -653,10 +653,10 @@ out: return ret; } -static int del_qgroup_item(struct btrfs_trans_handle *trans, - struct btrfs_root *quota_root, u64 qgroupid) +static int del_qgroup_item(struct btrfs_trans_handle *trans, u64 qgroupid) { int ret; + struct btrfs_root *quota_root = trans->fs_info->quota_root; struct btrfs_path *path; struct btrfs_key key; @@ -1420,7 +1420,7 @@ int btrfs_remove_qgroup(struct btrfs_trans_handle *trans, goto out; } } - ret = del_qgroup_item(trans, quota_root, qgroupid); + ret = del_qgroup_item(trans, qgroupid); if (ret && ret != -ENOENT) goto out; -- cgit v1.2.3 From ac8a866af17edc692b50cbdd2aec612de4205c8f Mon Sep 17 00:00:00 2001 From: Lu Fengqi Date: Wed, 18 Jul 2018 14:45:27 +0800 Subject: btrfs: qgroup: Drop root parameter from update_qgroup_limit_item It can be fetched from the transaction handle. Signed-off-by: Lu Fengqi Signed-off-by: David Sterba --- fs/btrfs/qgroup.c | 10 +++++----- 1 file changed, 5 insertions(+), 5 deletions(-) (limited to 'fs') diff --git a/fs/btrfs/qgroup.c b/fs/btrfs/qgroup.c index 67e0f4f38c31..44e1462e0f76 100644 --- a/fs/btrfs/qgroup.c +++ b/fs/btrfs/qgroup.c @@ -700,9 +700,9 @@ out: } static int update_qgroup_limit_item(struct btrfs_trans_handle *trans, - struct btrfs_root *root, struct btrfs_qgroup *qgroup) { + struct btrfs_root *quota_root = trans->fs_info->quota_root; struct btrfs_path *path; struct btrfs_key key; struct extent_buffer *l; @@ -718,7 +718,7 @@ static int update_qgroup_limit_item(struct btrfs_trans_handle *trans, if (!path) return -ENOMEM; - ret = btrfs_search_slot(trans, root, &key, path, 0, 1); + ret = btrfs_search_slot(trans, quota_root, &key, path, 0, 1); if (ret > 0) ret = -ENOENT; @@ -1509,7 +1509,7 @@ int btrfs_limit_qgroup(struct btrfs_trans_handle *trans, spin_unlock(&fs_info->qgroup_lock); - ret = update_qgroup_limit_item(trans, quota_root, qgroup); + ret = update_qgroup_limit_item(trans, qgroup); if (ret) { fs_info->qgroup_flags |= BTRFS_QGROUP_STATUS_FLAG_INCONSISTENT; btrfs_info(fs_info, "unable to update quota limit for %llu", @@ -2214,7 +2214,7 @@ int btrfs_run_qgroups(struct btrfs_trans_handle *trans, if (ret) fs_info->qgroup_flags |= BTRFS_QGROUP_STATUS_FLAG_INCONSISTENT; - ret = update_qgroup_limit_item(trans, quota_root, qgroup); + ret = update_qgroup_limit_item(trans, qgroup); if (ret) fs_info->qgroup_flags |= BTRFS_QGROUP_STATUS_FLAG_INCONSISTENT; @@ -2323,7 +2323,7 @@ int btrfs_qgroup_inherit(struct btrfs_trans_handle *trans, dstgroup->rsv_rfer = inherit->lim.rsv_rfer; dstgroup->rsv_excl = inherit->lim.rsv_excl; - ret = update_qgroup_limit_item(trans, quota_root, dstgroup); + ret = update_qgroup_limit_item(trans, dstgroup); if (ret) { fs_info->qgroup_flags |= BTRFS_QGROUP_STATUS_FLAG_INCONSISTENT; btrfs_info(fs_info, -- cgit v1.2.3 From 3e07e9a09f27868dbc63d07db8677fcd256e3bbc Mon Sep 17 00:00:00 2001 From: Lu Fengqi Date: Wed, 18 Jul 2018 14:45:28 +0800 Subject: btrfs: qgroup: Drop root parameter from update_qgroup_info_item It can be fetched from the transaction handle. Signed-off-by: Lu Fengqi Signed-off-by: David Sterba --- fs/btrfs/qgroup.c | 9 +++++---- 1 file changed, 5 insertions(+), 4 deletions(-) (limited to 'fs') diff --git a/fs/btrfs/qgroup.c b/fs/btrfs/qgroup.c index 44e1462e0f76..f4b25e0a32f8 100644 --- a/fs/btrfs/qgroup.c +++ b/fs/btrfs/qgroup.c @@ -742,9 +742,10 @@ out: } static int update_qgroup_info_item(struct btrfs_trans_handle *trans, - struct btrfs_root *root, struct btrfs_qgroup *qgroup) { + struct btrfs_fs_info *fs_info = trans->fs_info; + struct btrfs_root *quota_root = fs_info->quota_root; struct btrfs_path *path; struct btrfs_key key; struct extent_buffer *l; @@ -752,7 +753,7 @@ static int update_qgroup_info_item(struct btrfs_trans_handle *trans, int ret; int slot; - if (btrfs_is_testing(root->fs_info)) + if (btrfs_is_testing(fs_info)) return 0; key.objectid = 0; @@ -763,7 +764,7 @@ static int update_qgroup_info_item(struct btrfs_trans_handle *trans, if (!path) return -ENOMEM; - ret = btrfs_search_slot(trans, root, &key, path, 0, 1); + ret = btrfs_search_slot(trans, quota_root, &key, path, 0, 1); if (ret > 0) ret = -ENOENT; @@ -2210,7 +2211,7 @@ int btrfs_run_qgroups(struct btrfs_trans_handle *trans, struct btrfs_qgroup, dirty); list_del_init(&qgroup->dirty); spin_unlock(&fs_info->qgroup_lock); - ret = update_qgroup_info_item(trans, quota_root, qgroup); + ret = update_qgroup_info_item(trans, qgroup); if (ret) fs_info->qgroup_flags |= BTRFS_QGROUP_STATUS_FLAG_INCONSISTENT; -- cgit v1.2.3 From 2e980acdd829742966c6a7e565ef3382c0717295 Mon Sep 17 00:00:00 2001 From: Lu Fengqi Date: Wed, 18 Jul 2018 14:45:29 +0800 Subject: btrfs: qgroup: Drop quota_root and fs_info parameters from update_qgroup_status_item They can be fetched from the transaction handle. Signed-off-by: Lu Fengqi Signed-off-by: David Sterba --- fs/btrfs/qgroup.c | 12 ++++++------ 1 file changed, 6 insertions(+), 6 deletions(-) (limited to 'fs') diff --git a/fs/btrfs/qgroup.c b/fs/btrfs/qgroup.c index f4b25e0a32f8..a7890183f20f 100644 --- a/fs/btrfs/qgroup.c +++ b/fs/btrfs/qgroup.c @@ -787,10 +787,10 @@ out: return ret; } -static int update_qgroup_status_item(struct btrfs_trans_handle *trans, - struct btrfs_fs_info *fs_info, - struct btrfs_root *root) +static int update_qgroup_status_item(struct btrfs_trans_handle *trans) { + struct btrfs_fs_info *fs_info = trans->fs_info; + struct btrfs_root *quota_root = fs_info->quota_root; struct btrfs_path *path; struct btrfs_key key; struct extent_buffer *l; @@ -806,7 +806,7 @@ static int update_qgroup_status_item(struct btrfs_trans_handle *trans, if (!path) return -ENOMEM; - ret = btrfs_search_slot(trans, root, &key, path, 0, 1); + ret = btrfs_search_slot(trans, quota_root, &key, path, 0, 1); if (ret > 0) ret = -ENOENT; @@ -2227,7 +2227,7 @@ int btrfs_run_qgroups(struct btrfs_trans_handle *trans, fs_info->qgroup_flags &= ~BTRFS_QGROUP_STATUS_FLAG_ON; spin_unlock(&fs_info->qgroup_lock); - ret = update_qgroup_status_item(trans, fs_info, quota_root); + ret = update_qgroup_status_item(trans); if (ret) fs_info->qgroup_flags |= BTRFS_QGROUP_STATUS_FLAG_INCONSISTENT; @@ -2795,7 +2795,7 @@ out: err); goto done; } - ret = update_qgroup_status_item(trans, fs_info, fs_info->quota_root); + ret = update_qgroup_status_item(trans); if (ret < 0) { err = ret; btrfs_err(fs_info, "fail to update qgroup status: %d", err); -- cgit v1.2.3 From 9f8a6ce6ba8ebeb86de59b1adfdc64087049f76f Mon Sep 17 00:00:00 2001 From: Lu Fengqi Date: Wed, 18 Jul 2018 14:45:30 +0800 Subject: btrfs: qgroup: Drop fs_info parameter from btrfs_add_qgroup_relation It can be fetched from the transaction handle. Signed-off-by: Lu Fengqi Signed-off-by: David Sterba --- fs/btrfs/ioctl.c | 3 +-- fs/btrfs/qgroup.c | 5 +++-- fs/btrfs/qgroup.h | 4 ++-- 3 files changed, 6 insertions(+), 6 deletions(-) (limited to 'fs') diff --git a/fs/btrfs/ioctl.c b/fs/btrfs/ioctl.c index 9dcd16dec754..70b6f943fd70 100644 --- a/fs/btrfs/ioctl.c +++ b/fs/btrfs/ioctl.c @@ -5171,8 +5171,7 @@ static long btrfs_ioctl_qgroup_assign(struct file *file, void __user *arg) } if (sa->assign) { - ret = btrfs_add_qgroup_relation(trans, fs_info, - sa->src, sa->dst); + ret = btrfs_add_qgroup_relation(trans, sa->src, sa->dst); } else { ret = btrfs_del_qgroup_relation(trans, fs_info, sa->src, sa->dst); diff --git a/fs/btrfs/qgroup.c b/fs/btrfs/qgroup.c index a7890183f20f..8b71aec85d84 100644 --- a/fs/btrfs/qgroup.c +++ b/fs/btrfs/qgroup.c @@ -1236,9 +1236,10 @@ out: return ret; } -int btrfs_add_qgroup_relation(struct btrfs_trans_handle *trans, - struct btrfs_fs_info *fs_info, u64 src, u64 dst) +int btrfs_add_qgroup_relation(struct btrfs_trans_handle *trans, u64 src, + u64 dst) { + struct btrfs_fs_info *fs_info = trans->fs_info; struct btrfs_root *quota_root; struct btrfs_qgroup *parent; struct btrfs_qgroup *member; diff --git a/fs/btrfs/qgroup.h b/fs/btrfs/qgroup.h index bec7c9b17a8e..cb4d0e58f486 100644 --- a/fs/btrfs/qgroup.h +++ b/fs/btrfs/qgroup.h @@ -147,8 +147,8 @@ int btrfs_qgroup_rescan(struct btrfs_fs_info *fs_info); void btrfs_qgroup_rescan_resume(struct btrfs_fs_info *fs_info); int btrfs_qgroup_wait_for_completion(struct btrfs_fs_info *fs_info, bool interruptible); -int btrfs_add_qgroup_relation(struct btrfs_trans_handle *trans, - struct btrfs_fs_info *fs_info, u64 src, u64 dst); +int btrfs_add_qgroup_relation(struct btrfs_trans_handle *trans, u64 src, + u64 dst); int btrfs_del_qgroup_relation(struct btrfs_trans_handle *trans, struct btrfs_fs_info *fs_info, u64 src, u64 dst); int btrfs_create_qgroup(struct btrfs_trans_handle *trans, -- cgit v1.2.3 From 6b36f1aa5cda39acac50f6f80c81776a31fccd24 Mon Sep 17 00:00:00 2001 From: Lu Fengqi Date: Wed, 18 Jul 2018 14:45:31 +0800 Subject: btrfs: qgroup: Drop fs_info parameter from __del_qgroup_relation It can be fetched from the transaction handle. Signed-off-by: Lu Fengqi Signed-off-by: David Sterba --- fs/btrfs/qgroup.c | 12 ++++++------ 1 file changed, 6 insertions(+), 6 deletions(-) (limited to 'fs') diff --git a/fs/btrfs/qgroup.c b/fs/btrfs/qgroup.c index 8b71aec85d84..953b0d54e5d6 100644 --- a/fs/btrfs/qgroup.c +++ b/fs/btrfs/qgroup.c @@ -1300,9 +1300,10 @@ out: return ret; } -static int __del_qgroup_relation(struct btrfs_trans_handle *trans, - struct btrfs_fs_info *fs_info, u64 src, u64 dst) +static int __del_qgroup_relation(struct btrfs_trans_handle *trans, u64 src, + u64 dst) { + struct btrfs_fs_info *fs_info = trans->fs_info; struct btrfs_root *quota_root; struct btrfs_qgroup *parent; struct btrfs_qgroup *member; @@ -1356,7 +1357,7 @@ int btrfs_del_qgroup_relation(struct btrfs_trans_handle *trans, int ret = 0; mutex_lock(&fs_info->qgroup_ioctl_lock); - ret = __del_qgroup_relation(trans, fs_info, src, dst); + ret = __del_qgroup_relation(trans, src, dst); mutex_unlock(&fs_info->qgroup_ioctl_lock); return ret; @@ -1429,9 +1430,8 @@ int btrfs_remove_qgroup(struct btrfs_trans_handle *trans, while (!list_empty(&qgroup->groups)) { list = list_first_entry(&qgroup->groups, struct btrfs_qgroup_list, next_group); - ret = __del_qgroup_relation(trans, fs_info, - qgroupid, - list->group->qgroupid); + ret = __del_qgroup_relation(trans, qgroupid, + list->group->qgroupid); if (ret) goto out; } -- cgit v1.2.3 From 39616c2735ad04ecf4874519b64556decb73d968 Mon Sep 17 00:00:00 2001 From: Lu Fengqi Date: Wed, 18 Jul 2018 14:45:32 +0800 Subject: btrfs: qgroup: Drop fs_info parameter from btrfs_del_qgroup_relation It can be fetched from the transaction handle. Signed-off-by: Lu Fengqi Signed-off-by: David Sterba --- fs/btrfs/ioctl.c | 3 +-- fs/btrfs/qgroup.c | 5 +++-- fs/btrfs/qgroup.h | 4 ++-- 3 files changed, 6 insertions(+), 6 deletions(-) (limited to 'fs') diff --git a/fs/btrfs/ioctl.c b/fs/btrfs/ioctl.c index 70b6f943fd70..09943e396c77 100644 --- a/fs/btrfs/ioctl.c +++ b/fs/btrfs/ioctl.c @@ -5173,8 +5173,7 @@ static long btrfs_ioctl_qgroup_assign(struct file *file, void __user *arg) if (sa->assign) { ret = btrfs_add_qgroup_relation(trans, sa->src, sa->dst); } else { - ret = btrfs_del_qgroup_relation(trans, fs_info, - sa->src, sa->dst); + ret = btrfs_del_qgroup_relation(trans, sa->src, sa->dst); } /* update qgroup status and info */ diff --git a/fs/btrfs/qgroup.c b/fs/btrfs/qgroup.c index 953b0d54e5d6..8c6f594a7ee8 100644 --- a/fs/btrfs/qgroup.c +++ b/fs/btrfs/qgroup.c @@ -1351,9 +1351,10 @@ out: return ret; } -int btrfs_del_qgroup_relation(struct btrfs_trans_handle *trans, - struct btrfs_fs_info *fs_info, u64 src, u64 dst) +int btrfs_del_qgroup_relation(struct btrfs_trans_handle *trans, u64 src, + u64 dst) { + struct btrfs_fs_info *fs_info = trans->fs_info; int ret = 0; mutex_lock(&fs_info->qgroup_ioctl_lock); diff --git a/fs/btrfs/qgroup.h b/fs/btrfs/qgroup.h index cb4d0e58f486..539d4c449f26 100644 --- a/fs/btrfs/qgroup.h +++ b/fs/btrfs/qgroup.h @@ -149,8 +149,8 @@ int btrfs_qgroup_wait_for_completion(struct btrfs_fs_info *fs_info, bool interruptible); int btrfs_add_qgroup_relation(struct btrfs_trans_handle *trans, u64 src, u64 dst); -int btrfs_del_qgroup_relation(struct btrfs_trans_handle *trans, - struct btrfs_fs_info *fs_info, u64 src, u64 dst); +int btrfs_del_qgroup_relation(struct btrfs_trans_handle *trans, u64 src, + u64 dst); int btrfs_create_qgroup(struct btrfs_trans_handle *trans, struct btrfs_fs_info *fs_info, u64 qgroupid); int btrfs_remove_qgroup(struct btrfs_trans_handle *trans, -- cgit v1.2.3 From 49a05ecde3f130ae9d69ab619e3ea125cf1f32c9 Mon Sep 17 00:00:00 2001 From: Lu Fengqi Date: Wed, 18 Jul 2018 14:45:33 +0800 Subject: btrfs: qgroup: Drop fs_info parameter from btrfs_create_qgroup It can be fetched from the transaction handle. Signed-off-by: Lu Fengqi Signed-off-by: David Sterba --- fs/btrfs/ioctl.c | 2 +- fs/btrfs/qgroup.c | 4 ++-- fs/btrfs/qgroup.h | 3 +-- fs/btrfs/tests/qgroup-tests.c | 4 ++-- 4 files changed, 6 insertions(+), 7 deletions(-) (limited to 'fs') diff --git a/fs/btrfs/ioctl.c b/fs/btrfs/ioctl.c index 09943e396c77..2fdc34a67139 100644 --- a/fs/btrfs/ioctl.c +++ b/fs/btrfs/ioctl.c @@ -5227,7 +5227,7 @@ static long btrfs_ioctl_qgroup_create(struct file *file, void __user *arg) } if (sa->create) { - ret = btrfs_create_qgroup(trans, fs_info, sa->qgroupid); + ret = btrfs_create_qgroup(trans, sa->qgroupid); } else { ret = btrfs_remove_qgroup(trans, fs_info, sa->qgroupid); } diff --git a/fs/btrfs/qgroup.c b/fs/btrfs/qgroup.c index 8c6f594a7ee8..9c97be3fbf35 100644 --- a/fs/btrfs/qgroup.c +++ b/fs/btrfs/qgroup.c @@ -1364,9 +1364,9 @@ int btrfs_del_qgroup_relation(struct btrfs_trans_handle *trans, u64 src, return ret; } -int btrfs_create_qgroup(struct btrfs_trans_handle *trans, - struct btrfs_fs_info *fs_info, u64 qgroupid) +int btrfs_create_qgroup(struct btrfs_trans_handle *trans, u64 qgroupid) { + struct btrfs_fs_info *fs_info = trans->fs_info; struct btrfs_root *quota_root; struct btrfs_qgroup *qgroup; int ret = 0; diff --git a/fs/btrfs/qgroup.h b/fs/btrfs/qgroup.h index 539d4c449f26..03adfedd9d01 100644 --- a/fs/btrfs/qgroup.h +++ b/fs/btrfs/qgroup.h @@ -151,8 +151,7 @@ int btrfs_add_qgroup_relation(struct btrfs_trans_handle *trans, u64 src, u64 dst); int btrfs_del_qgroup_relation(struct btrfs_trans_handle *trans, u64 src, u64 dst); -int btrfs_create_qgroup(struct btrfs_trans_handle *trans, - struct btrfs_fs_info *fs_info, u64 qgroupid); +int btrfs_create_qgroup(struct btrfs_trans_handle *trans, u64 qgroupid); int btrfs_remove_qgroup(struct btrfs_trans_handle *trans, struct btrfs_fs_info *fs_info, u64 qgroupid); int btrfs_limit_qgroup(struct btrfs_trans_handle *trans, diff --git a/fs/btrfs/tests/qgroup-tests.c b/fs/btrfs/tests/qgroup-tests.c index ace94db09d29..b5e332d45d37 100644 --- a/fs/btrfs/tests/qgroup-tests.c +++ b/fs/btrfs/tests/qgroup-tests.c @@ -216,7 +216,7 @@ static int test_no_shared_qgroup(struct btrfs_root *root, btrfs_init_dummy_trans(&trans, fs_info); test_msg("qgroup basic add"); - ret = btrfs_create_qgroup(NULL, fs_info, BTRFS_FS_TREE_OBJECTID); + ret = btrfs_create_qgroup(&trans, BTRFS_FS_TREE_OBJECTID); if (ret) { test_err("couldn't create a qgroup %d", ret); return ret; @@ -322,7 +322,7 @@ static int test_multiple_refs(struct btrfs_root *root, * We have BTRFS_FS_TREE_OBJECTID created already from the * previous test. */ - ret = btrfs_create_qgroup(NULL, fs_info, BTRFS_FIRST_FREE_OBJECTID); + ret = btrfs_create_qgroup(&trans, BTRFS_FIRST_FREE_OBJECTID); if (ret) { test_err("couldn't create a qgroup %d", ret); return ret; -- cgit v1.2.3 From 3efbee1d006a97eaec5f070430c75010ef8746f1 Mon Sep 17 00:00:00 2001 From: Lu Fengqi Date: Wed, 18 Jul 2018 14:45:34 +0800 Subject: btrfs: qgroup: Drop fs_info parameter from btrfs_remove_qgroup It can be fetched from the transaction handle. Signed-off-by: Lu Fengqi Signed-off-by: David Sterba --- fs/btrfs/ioctl.c | 3 +-- fs/btrfs/qgroup.c | 4 ++-- fs/btrfs/qgroup.h | 3 +-- 3 files changed, 4 insertions(+), 6 deletions(-) (limited to 'fs') diff --git a/fs/btrfs/ioctl.c b/fs/btrfs/ioctl.c index 2fdc34a67139..cb2b74db24ea 100644 --- a/fs/btrfs/ioctl.c +++ b/fs/btrfs/ioctl.c @@ -5195,7 +5195,6 @@ drop_write: static long btrfs_ioctl_qgroup_create(struct file *file, void __user *arg) { struct inode *inode = file_inode(file); - struct btrfs_fs_info *fs_info = btrfs_sb(inode->i_sb); struct btrfs_root *root = BTRFS_I(inode)->root; struct btrfs_ioctl_qgroup_create_args *sa; struct btrfs_trans_handle *trans; @@ -5229,7 +5228,7 @@ static long btrfs_ioctl_qgroup_create(struct file *file, void __user *arg) if (sa->create) { ret = btrfs_create_qgroup(trans, sa->qgroupid); } else { - ret = btrfs_remove_qgroup(trans, fs_info, sa->qgroupid); + ret = btrfs_remove_qgroup(trans, sa->qgroupid); } err = btrfs_end_transaction(trans); diff --git a/fs/btrfs/qgroup.c b/fs/btrfs/qgroup.c index 9c97be3fbf35..d3d205d0e176 100644 --- a/fs/btrfs/qgroup.c +++ b/fs/btrfs/qgroup.c @@ -1398,9 +1398,9 @@ out: return ret; } -int btrfs_remove_qgroup(struct btrfs_trans_handle *trans, - struct btrfs_fs_info *fs_info, u64 qgroupid) +int btrfs_remove_qgroup(struct btrfs_trans_handle *trans, u64 qgroupid) { + struct btrfs_fs_info *fs_info = trans->fs_info; struct btrfs_root *quota_root; struct btrfs_qgroup *qgroup; struct btrfs_qgroup_list *list; diff --git a/fs/btrfs/qgroup.h b/fs/btrfs/qgroup.h index 03adfedd9d01..41516dddf123 100644 --- a/fs/btrfs/qgroup.h +++ b/fs/btrfs/qgroup.h @@ -152,8 +152,7 @@ int btrfs_add_qgroup_relation(struct btrfs_trans_handle *trans, u64 src, int btrfs_del_qgroup_relation(struct btrfs_trans_handle *trans, u64 src, u64 dst); int btrfs_create_qgroup(struct btrfs_trans_handle *trans, u64 qgroupid); -int btrfs_remove_qgroup(struct btrfs_trans_handle *trans, - struct btrfs_fs_info *fs_info, u64 qgroupid); +int btrfs_remove_qgroup(struct btrfs_trans_handle *trans, u64 qgroupid); int btrfs_limit_qgroup(struct btrfs_trans_handle *trans, struct btrfs_fs_info *fs_info, u64 qgroupid, struct btrfs_qgroup_limit *limit); -- cgit v1.2.3 From f0042d5e92b66969a12166d1deb5a979250d6c25 Mon Sep 17 00:00:00 2001 From: Lu Fengqi Date: Wed, 18 Jul 2018 14:45:35 +0800 Subject: btrfs: qgroup: Drop fs_info parameter from btrfs_limit_qgroup It can be fetched from the transaction handle. Signed-off-by: Lu Fengqi Signed-off-by: David Sterba --- fs/btrfs/ioctl.c | 3 +-- fs/btrfs/qgroup.c | 4 ++-- fs/btrfs/qgroup.h | 3 +-- 3 files changed, 4 insertions(+), 6 deletions(-) (limited to 'fs') diff --git a/fs/btrfs/ioctl.c b/fs/btrfs/ioctl.c index cb2b74db24ea..01aab038120e 100644 --- a/fs/btrfs/ioctl.c +++ b/fs/btrfs/ioctl.c @@ -5245,7 +5245,6 @@ drop_write: static long btrfs_ioctl_qgroup_limit(struct file *file, void __user *arg) { struct inode *inode = file_inode(file); - struct btrfs_fs_info *fs_info = btrfs_sb(inode->i_sb); struct btrfs_root *root = BTRFS_I(inode)->root; struct btrfs_ioctl_qgroup_limit_args *sa; struct btrfs_trans_handle *trans; @@ -5278,7 +5277,7 @@ static long btrfs_ioctl_qgroup_limit(struct file *file, void __user *arg) qgroupid = root->root_key.objectid; } - ret = btrfs_limit_qgroup(trans, fs_info, qgroupid, &sa->lim); + ret = btrfs_limit_qgroup(trans, qgroupid, &sa->lim); err = btrfs_end_transaction(trans); if (err && !ret) diff --git a/fs/btrfs/qgroup.c b/fs/btrfs/qgroup.c index d3d205d0e176..8953d0264887 100644 --- a/fs/btrfs/qgroup.c +++ b/fs/btrfs/qgroup.c @@ -1445,10 +1445,10 @@ out: return ret; } -int btrfs_limit_qgroup(struct btrfs_trans_handle *trans, - struct btrfs_fs_info *fs_info, u64 qgroupid, +int btrfs_limit_qgroup(struct btrfs_trans_handle *trans, u64 qgroupid, struct btrfs_qgroup_limit *limit) { + struct btrfs_fs_info *fs_info = trans->fs_info; struct btrfs_root *quota_root; struct btrfs_qgroup *qgroup; int ret = 0; diff --git a/fs/btrfs/qgroup.h b/fs/btrfs/qgroup.h index 41516dddf123..385367989ed6 100644 --- a/fs/btrfs/qgroup.h +++ b/fs/btrfs/qgroup.h @@ -153,8 +153,7 @@ int btrfs_del_qgroup_relation(struct btrfs_trans_handle *trans, u64 src, u64 dst); int btrfs_create_qgroup(struct btrfs_trans_handle *trans, u64 qgroupid); int btrfs_remove_qgroup(struct btrfs_trans_handle *trans, u64 qgroupid); -int btrfs_limit_qgroup(struct btrfs_trans_handle *trans, - struct btrfs_fs_info *fs_info, u64 qgroupid, +int btrfs_limit_qgroup(struct btrfs_trans_handle *trans, u64 qgroupid, struct btrfs_qgroup_limit *limit); int btrfs_read_qgroup_config(struct btrfs_fs_info *fs_info); void btrfs_free_qgroup_config(struct btrfs_fs_info *fs_info); -- cgit v1.2.3 From a95f3aafd6a2d0e8de834c95e91066825e3e7787 Mon Sep 17 00:00:00 2001 From: Lu Fengqi Date: Wed, 18 Jul 2018 16:28:03 +0800 Subject: btrfs: qgroup: Drop fs_info parameter from btrfs_qgroup_trace_extent It can be fetched from the transaction handle. In addition, remove the WARN_ON(trans == NULL) because it's not possible to hit this condition. Signed-off-by: Lu Fengqi Reviewed-by: David Sterba Signed-off-by: David Sterba --- fs/btrfs/qgroup.c | 15 ++++++--------- fs/btrfs/qgroup.h | 5 ++--- fs/btrfs/tree-log.c | 2 +- 3 files changed, 9 insertions(+), 13 deletions(-) (limited to 'fs') diff --git a/fs/btrfs/qgroup.c b/fs/btrfs/qgroup.c index 8953d0264887..d1e8b4851912 100644 --- a/fs/btrfs/qgroup.c +++ b/fs/btrfs/qgroup.c @@ -1580,10 +1580,10 @@ int btrfs_qgroup_trace_extent_post(struct btrfs_fs_info *fs_info, return 0; } -int btrfs_qgroup_trace_extent(struct btrfs_trans_handle *trans, - struct btrfs_fs_info *fs_info, u64 bytenr, u64 num_bytes, - gfp_t gfp_flag) +int btrfs_qgroup_trace_extent(struct btrfs_trans_handle *trans, u64 bytenr, + u64 num_bytes, gfp_t gfp_flag) { + struct btrfs_fs_info *fs_info = trans->fs_info; struct btrfs_qgroup_extent_record *record; struct btrfs_delayed_ref_root *delayed_refs; int ret; @@ -1591,8 +1591,6 @@ int btrfs_qgroup_trace_extent(struct btrfs_trans_handle *trans, if (!test_bit(BTRFS_FS_QUOTA_ENABLED, &fs_info->flags) || bytenr == 0 || num_bytes == 0) return 0; - if (WARN_ON(trans == NULL)) - return -EINVAL; record = kmalloc(sizeof(*record), gfp_flag); if (!record) return -ENOMEM; @@ -1645,8 +1643,8 @@ int btrfs_qgroup_trace_leaf_items(struct btrfs_trans_handle *trans, num_bytes = btrfs_file_extent_disk_num_bytes(eb, fi); - ret = btrfs_qgroup_trace_extent(trans, fs_info, bytenr, - num_bytes, GFP_NOFS); + ret = btrfs_qgroup_trace_extent(trans, bytenr, num_bytes, + GFP_NOFS); if (ret) return ret; } @@ -1797,8 +1795,7 @@ walk_down: btrfs_set_lock_blocking_rw(eb, BTRFS_READ_LOCK); path->locks[level] = BTRFS_READ_LOCK_BLOCKING; - ret = btrfs_qgroup_trace_extent(trans, fs_info, - child_bytenr, + ret = btrfs_qgroup_trace_extent(trans, child_bytenr, fs_info->nodesize, GFP_NOFS); if (ret) diff --git a/fs/btrfs/qgroup.h b/fs/btrfs/qgroup.h index 385367989ed6..0215dc0b1710 100644 --- a/fs/btrfs/qgroup.h +++ b/fs/btrfs/qgroup.h @@ -212,9 +212,8 @@ int btrfs_qgroup_trace_extent_post(struct btrfs_fs_info *fs_info, * Return <0 for error, like memory allocation failure or invalid parameter * (NULL trans) */ -int btrfs_qgroup_trace_extent(struct btrfs_trans_handle *trans, - struct btrfs_fs_info *fs_info, u64 bytenr, u64 num_bytes, - gfp_t gfp_flag); +int btrfs_qgroup_trace_extent(struct btrfs_trans_handle *trans, u64 bytenr, + u64 num_bytes, gfp_t gfp_flag); /* * Inform qgroup to trace all leaf items of data diff --git a/fs/btrfs/tree-log.c b/fs/btrfs/tree-log.c index 7b7498f1f641..10f6a4223897 100644 --- a/fs/btrfs/tree-log.c +++ b/fs/btrfs/tree-log.c @@ -685,7 +685,7 @@ static noinline int replay_one_extent(struct btrfs_trans_handle *trans, * as the owner of the file extent changed from log tree * (doesn't affect qgroup) to fs/file tree(affects qgroup) */ - ret = btrfs_qgroup_trace_extent(trans, fs_info, + ret = btrfs_qgroup_trace_extent(trans, btrfs_file_extent_disk_bytenr(eb, item), btrfs_file_extent_disk_num_bytes(eb, item), GFP_NOFS); -- cgit v1.2.3 From 8d38d7eb7bb60a7a441cec3ba92784d9f1e20d5f Mon Sep 17 00:00:00 2001 From: Lu Fengqi Date: Wed, 18 Jul 2018 14:45:37 +0800 Subject: btrfs: qgroup: Drop fs_info parameter from btrfs_qgroup_trace_leaf_items It can be fetched from the transaction handle. Signed-off-by: Lu Fengqi Signed-off-by: David Sterba --- fs/btrfs/extent-tree.c | 2 +- fs/btrfs/qgroup.c | 8 ++++---- fs/btrfs/qgroup.h | 1 - 3 files changed, 5 insertions(+), 6 deletions(-) (limited to 'fs') diff --git a/fs/btrfs/extent-tree.c b/fs/btrfs/extent-tree.c index ced26ba8d392..51da902a0ad7 100644 --- a/fs/btrfs/extent-tree.c +++ b/fs/btrfs/extent-tree.c @@ -8760,7 +8760,7 @@ static noinline int walk_up_proc(struct btrfs_trans_handle *trans, else ret = btrfs_dec_ref(trans, root, eb, 0); BUG_ON(ret); /* -ENOMEM */ - ret = btrfs_qgroup_trace_leaf_items(trans, fs_info, eb); + ret = btrfs_qgroup_trace_leaf_items(trans, eb); if (ret) { btrfs_err_rl(fs_info, "error %d accounting leaf items. Quota is out of sync, rescan required.", diff --git a/fs/btrfs/qgroup.c b/fs/btrfs/qgroup.c index d1e8b4851912..11a23b17a432 100644 --- a/fs/btrfs/qgroup.c +++ b/fs/btrfs/qgroup.c @@ -1611,9 +1611,9 @@ int btrfs_qgroup_trace_extent(struct btrfs_trans_handle *trans, u64 bytenr, } int btrfs_qgroup_trace_leaf_items(struct btrfs_trans_handle *trans, - struct btrfs_fs_info *fs_info, struct extent_buffer *eb) { + struct btrfs_fs_info *fs_info = trans->fs_info; int nr = btrfs_header_nritems(eb); int i, extent_type, ret; struct btrfs_key key; @@ -1737,7 +1737,7 @@ int btrfs_qgroup_trace_subtree(struct btrfs_trans_handle *trans, } if (root_level == 0) { - ret = btrfs_qgroup_trace_leaf_items(trans, fs_info, root_eb); + ret = btrfs_qgroup_trace_leaf_items(trans, root_eb); goto out; } @@ -1803,8 +1803,8 @@ walk_down: } if (level == 0) { - ret = btrfs_qgroup_trace_leaf_items(trans,fs_info, - path->nodes[level]); + ret = btrfs_qgroup_trace_leaf_items(trans, + path->nodes[level]); if (ret) goto out; diff --git a/fs/btrfs/qgroup.h b/fs/btrfs/qgroup.h index 0215dc0b1710..9d434a01d467 100644 --- a/fs/btrfs/qgroup.h +++ b/fs/btrfs/qgroup.h @@ -222,7 +222,6 @@ int btrfs_qgroup_trace_extent(struct btrfs_trans_handle *trans, u64 bytenr, * Return <0 for error(ENOMEM) */ int btrfs_qgroup_trace_leaf_items(struct btrfs_trans_handle *trans, - struct btrfs_fs_info *fs_info, struct extent_buffer *eb); /* * Inform qgroup to trace a whole subtree, including all its child tree -- cgit v1.2.3 From deb406274339f386836313af7eeb8001cca6c33f Mon Sep 17 00:00:00 2001 From: Lu Fengqi Date: Wed, 18 Jul 2018 14:45:38 +0800 Subject: btrfs: qgroup: Drop root parameter from btrfs_qgroup_trace_subtree The fs_info can be fetched from the transaction handle directly. Signed-off-by: Lu Fengqi Signed-off-by: David Sterba --- fs/btrfs/extent-tree.c | 2 +- fs/btrfs/qgroup.c | 3 +-- fs/btrfs/qgroup.h | 1 - fs/btrfs/relocation.c | 5 ++--- 4 files changed, 4 insertions(+), 7 deletions(-) (limited to 'fs') diff --git a/fs/btrfs/extent-tree.c b/fs/btrfs/extent-tree.c index 51da902a0ad7..4f19bdca3214 100644 --- a/fs/btrfs/extent-tree.c +++ b/fs/btrfs/extent-tree.c @@ -8660,7 +8660,7 @@ skip: } if (need_account) { - ret = btrfs_qgroup_trace_subtree(trans, root, next, + ret = btrfs_qgroup_trace_subtree(trans, next, generation, level - 1); if (ret) { btrfs_err_rl(fs_info, diff --git a/fs/btrfs/qgroup.c b/fs/btrfs/qgroup.c index 11a23b17a432..0b43e9e2a71e 100644 --- a/fs/btrfs/qgroup.c +++ b/fs/btrfs/qgroup.c @@ -1714,11 +1714,10 @@ static int adjust_slots_upwards(struct btrfs_path *path, int root_level) } int btrfs_qgroup_trace_subtree(struct btrfs_trans_handle *trans, - struct btrfs_root *root, struct extent_buffer *root_eb, u64 root_gen, int root_level) { - struct btrfs_fs_info *fs_info = root->fs_info; + struct btrfs_fs_info *fs_info = trans->fs_info; int ret = 0; int level; struct extent_buffer *eb = root_eb; diff --git a/fs/btrfs/qgroup.h b/fs/btrfs/qgroup.h index 9d434a01d467..b8f15ce6c83d 100644 --- a/fs/btrfs/qgroup.h +++ b/fs/btrfs/qgroup.h @@ -234,7 +234,6 @@ int btrfs_qgroup_trace_leaf_items(struct btrfs_trans_handle *trans, * Return <0 for error(ENOMEM or tree search error) */ int btrfs_qgroup_trace_subtree(struct btrfs_trans_handle *trans, - struct btrfs_root *root, struct extent_buffer *root_eb, u64 root_gen, int root_level); int diff --git a/fs/btrfs/relocation.c b/fs/btrfs/relocation.c index b98d7a594542..d6bcf558789e 100644 --- a/fs/btrfs/relocation.c +++ b/fs/btrfs/relocation.c @@ -1879,13 +1879,12 @@ again: * and tree block numbers, if current trans doesn't free * data reloc tree inode. */ - ret = btrfs_qgroup_trace_subtree(trans, src, parent, + ret = btrfs_qgroup_trace_subtree(trans, parent, btrfs_header_generation(parent), btrfs_header_level(parent)); if (ret < 0) break; - ret = btrfs_qgroup_trace_subtree(trans, dest, - path->nodes[level], + ret = btrfs_qgroup_trace_subtree(trans, path->nodes[level], btrfs_header_generation(path->nodes[level]), btrfs_header_level(path->nodes[level])); if (ret < 0) -- cgit v1.2.3 From 8696d76045579c9611fe1cfc064e48ada32bb796 Mon Sep 17 00:00:00 2001 From: Lu Fengqi Date: Wed, 18 Jul 2018 14:45:39 +0800 Subject: btrfs: qgroup: Drop fs_info parameter from btrfs_qgroup_account_extent It can be fetched from the transaction handle. Signed-off-by: Lu Fengqi Signed-off-by: David Sterba --- fs/btrfs/qgroup.c | 20 ++++++++++---------- fs/btrfs/qgroup.h | 8 +++----- fs/btrfs/tests/qgroup-tests.c | 20 ++++++++++---------- 3 files changed, 23 insertions(+), 25 deletions(-) (limited to 'fs') diff --git a/fs/btrfs/qgroup.c b/fs/btrfs/qgroup.c index 0b43e9e2a71e..5ac57fc3fa4b 100644 --- a/fs/btrfs/qgroup.c +++ b/fs/btrfs/qgroup.c @@ -2038,12 +2038,11 @@ static int maybe_fs_roots(struct ulist *roots) return is_fstree(unode->val); } -int -btrfs_qgroup_account_extent(struct btrfs_trans_handle *trans, - struct btrfs_fs_info *fs_info, - u64 bytenr, u64 num_bytes, - struct ulist *old_roots, struct ulist *new_roots) +int btrfs_qgroup_account_extent(struct btrfs_trans_handle *trans, u64 bytenr, + u64 num_bytes, struct ulist *old_roots, + struct ulist *new_roots) { + struct btrfs_fs_info *fs_info = trans->fs_info; struct ulist *qgroups = NULL; struct ulist *tmp = NULL; u64 seq; @@ -2173,9 +2172,10 @@ int btrfs_qgroup_account_extents(struct btrfs_trans_handle *trans) ulist_del(record->old_roots, qgroup_to_skip, 0); } - ret = btrfs_qgroup_account_extent(trans, fs_info, - record->bytenr, record->num_bytes, - record->old_roots, new_roots); + ret = btrfs_qgroup_account_extent(trans, record->bytenr, + record->num_bytes, + record->old_roots, + new_roots); record->old_roots = NULL; new_roots = NULL; } @@ -2711,8 +2711,8 @@ qgroup_rescan_leaf(struct btrfs_fs_info *fs_info, struct btrfs_path *path, if (ret < 0) goto out; /* For rescan, just pass old_roots as NULL */ - ret = btrfs_qgroup_account_extent(trans, fs_info, - found.objectid, num_bytes, NULL, roots); + ret = btrfs_qgroup_account_extent(trans, found.objectid, + num_bytes, NULL, roots); if (ret < 0) goto out; } diff --git a/fs/btrfs/qgroup.h b/fs/btrfs/qgroup.h index b8f15ce6c83d..61b723b1e4d8 100644 --- a/fs/btrfs/qgroup.h +++ b/fs/btrfs/qgroup.h @@ -236,11 +236,9 @@ int btrfs_qgroup_trace_leaf_items(struct btrfs_trans_handle *trans, int btrfs_qgroup_trace_subtree(struct btrfs_trans_handle *trans, struct extent_buffer *root_eb, u64 root_gen, int root_level); -int -btrfs_qgroup_account_extent(struct btrfs_trans_handle *trans, - struct btrfs_fs_info *fs_info, - u64 bytenr, u64 num_bytes, - struct ulist *old_roots, struct ulist *new_roots); +int btrfs_qgroup_account_extent(struct btrfs_trans_handle *trans, u64 bytenr, + u64 num_bytes, struct ulist *old_roots, + struct ulist *new_roots); int btrfs_qgroup_account_extents(struct btrfs_trans_handle *trans); int btrfs_run_qgroups(struct btrfs_trans_handle *trans, struct btrfs_fs_info *fs_info); diff --git a/fs/btrfs/tests/qgroup-tests.c b/fs/btrfs/tests/qgroup-tests.c index b5e332d45d37..412b910b04cc 100644 --- a/fs/btrfs/tests/qgroup-tests.c +++ b/fs/btrfs/tests/qgroup-tests.c @@ -249,8 +249,8 @@ static int test_no_shared_qgroup(struct btrfs_root *root, return ret; } - ret = btrfs_qgroup_account_extent(&trans, fs_info, nodesize, - nodesize, old_roots, new_roots); + ret = btrfs_qgroup_account_extent(&trans, nodesize, nodesize, old_roots, + new_roots); if (ret) { test_err("couldn't account space for a qgroup %d", ret); return ret; @@ -285,8 +285,8 @@ static int test_no_shared_qgroup(struct btrfs_root *root, return ret; } - ret = btrfs_qgroup_account_extent(&trans, fs_info, nodesize, - nodesize, old_roots, new_roots); + ret = btrfs_qgroup_account_extent(&trans, nodesize, nodesize, old_roots, + new_roots); if (ret) { test_err("couldn't account space for a qgroup %d", ret); return -EINVAL; @@ -350,8 +350,8 @@ static int test_multiple_refs(struct btrfs_root *root, return ret; } - ret = btrfs_qgroup_account_extent(&trans, fs_info, nodesize, - nodesize, old_roots, new_roots); + ret = btrfs_qgroup_account_extent(&trans, nodesize, nodesize, old_roots, + new_roots); if (ret) { test_err("couldn't account space for a qgroup %d", ret); return ret; @@ -385,8 +385,8 @@ static int test_multiple_refs(struct btrfs_root *root, return ret; } - ret = btrfs_qgroup_account_extent(&trans, fs_info, nodesize, - nodesize, old_roots, new_roots); + ret = btrfs_qgroup_account_extent(&trans, nodesize, nodesize, old_roots, + new_roots); if (ret) { test_err("couldn't account space for a qgroup %d", ret); return ret; @@ -426,8 +426,8 @@ static int test_multiple_refs(struct btrfs_root *root, return ret; } - ret = btrfs_qgroup_account_extent(&trans, fs_info, nodesize, - nodesize, old_roots, new_roots); + ret = btrfs_qgroup_account_extent(&trans, nodesize, nodesize, old_roots, + new_roots); if (ret) { test_err("couldn't account space for a qgroup %d", ret); return ret; -- cgit v1.2.3 From 280f8bd2cbe0b4b578c217b8fa504294c30abde1 Mon Sep 17 00:00:00 2001 From: Lu Fengqi Date: Wed, 18 Jul 2018 14:45:40 +0800 Subject: btrfs: qgroup: Drop fs_info parameter from btrfs_run_qgroups It can be fetched from the transaction handle. Signed-off-by: Lu Fengqi Signed-off-by: David Sterba --- fs/btrfs/ioctl.c | 2 +- fs/btrfs/qgroup.c | 4 ++-- fs/btrfs/qgroup.h | 3 +-- fs/btrfs/transaction.c | 2 +- 4 files changed, 5 insertions(+), 6 deletions(-) (limited to 'fs') diff --git a/fs/btrfs/ioctl.c b/fs/btrfs/ioctl.c index 01aab038120e..d0096383ac3d 100644 --- a/fs/btrfs/ioctl.c +++ b/fs/btrfs/ioctl.c @@ -5177,7 +5177,7 @@ static long btrfs_ioctl_qgroup_assign(struct file *file, void __user *arg) } /* update qgroup status and info */ - err = btrfs_run_qgroups(trans, fs_info); + err = btrfs_run_qgroups(trans); if (err < 0) btrfs_handle_fs_error(fs_info, err, "failed to update qgroup status and info"); diff --git a/fs/btrfs/qgroup.c b/fs/btrfs/qgroup.c index 5ac57fc3fa4b..819cdaea51ab 100644 --- a/fs/btrfs/qgroup.c +++ b/fs/btrfs/qgroup.c @@ -2193,9 +2193,9 @@ cleanup: /* * called from commit_transaction. Writes all changed qgroups to disk. */ -int btrfs_run_qgroups(struct btrfs_trans_handle *trans, - struct btrfs_fs_info *fs_info) +int btrfs_run_qgroups(struct btrfs_trans_handle *trans) { + struct btrfs_fs_info *fs_info = trans->fs_info; struct btrfs_root *quota_root = fs_info->quota_root; int ret = 0; diff --git a/fs/btrfs/qgroup.h b/fs/btrfs/qgroup.h index 61b723b1e4d8..2c8960f9028c 100644 --- a/fs/btrfs/qgroup.h +++ b/fs/btrfs/qgroup.h @@ -240,8 +240,7 @@ int btrfs_qgroup_account_extent(struct btrfs_trans_handle *trans, u64 bytenr, u64 num_bytes, struct ulist *old_roots, struct ulist *new_roots); int btrfs_qgroup_account_extents(struct btrfs_trans_handle *trans); -int btrfs_run_qgroups(struct btrfs_trans_handle *trans, - struct btrfs_fs_info *fs_info); +int btrfs_run_qgroups(struct btrfs_trans_handle *trans); int btrfs_qgroup_inherit(struct btrfs_trans_handle *trans, struct btrfs_fs_info *fs_info, u64 srcid, u64 objectid, struct btrfs_qgroup_inherit *inherit); diff --git a/fs/btrfs/transaction.c b/fs/btrfs/transaction.c index ebe50dfb8947..0cbd55c498a1 100644 --- a/fs/btrfs/transaction.c +++ b/fs/btrfs/transaction.c @@ -1152,7 +1152,7 @@ static noinline int commit_cowonly_roots(struct btrfs_trans_handle *trans) ret = btrfs_run_dev_replace(trans, fs_info); if (ret) return ret; - ret = btrfs_run_qgroups(trans, fs_info); + ret = btrfs_run_qgroups(trans); if (ret) return ret; -- cgit v1.2.3 From a937742250199a37358a4da0a990744b92c8623c Mon Sep 17 00:00:00 2001 From: Lu Fengqi Date: Wed, 18 Jul 2018 14:45:41 +0800 Subject: btrfs: qgroup: Drop fs_info parameter from btrfs_qgroup_inherit It can be fetched from the transaction handle. Signed-off-by: Lu Fengqi Signed-off-by: David Sterba --- fs/btrfs/ioctl.c | 2 +- fs/btrfs/qgroup.c | 6 +++--- fs/btrfs/qgroup.h | 5 ++--- fs/btrfs/transaction.c | 3 +-- 4 files changed, 7 insertions(+), 9 deletions(-) (limited to 'fs') diff --git a/fs/btrfs/ioctl.c b/fs/btrfs/ioctl.c index d0096383ac3d..4482cf35522e 100644 --- a/fs/btrfs/ioctl.c +++ b/fs/btrfs/ioctl.c @@ -601,7 +601,7 @@ static noinline int create_subvol(struct inode *dir, trans->block_rsv = &block_rsv; trans->bytes_reserved = block_rsv.size; - ret = btrfs_qgroup_inherit(trans, fs_info, 0, objectid, inherit); + ret = btrfs_qgroup_inherit(trans, 0, objectid, inherit); if (ret) goto fail; diff --git a/fs/btrfs/qgroup.c b/fs/btrfs/qgroup.c index 819cdaea51ab..96640c56c910 100644 --- a/fs/btrfs/qgroup.c +++ b/fs/btrfs/qgroup.c @@ -2238,13 +2238,13 @@ int btrfs_run_qgroups(struct btrfs_trans_handle *trans) * cause a transaction abort so we take extra care here to only error * when a readonly fs is a reasonable outcome. */ -int btrfs_qgroup_inherit(struct btrfs_trans_handle *trans, - struct btrfs_fs_info *fs_info, u64 srcid, u64 objectid, - struct btrfs_qgroup_inherit *inherit) +int btrfs_qgroup_inherit(struct btrfs_trans_handle *trans, u64 srcid, + u64 objectid, struct btrfs_qgroup_inherit *inherit) { int ret = 0; int i; u64 *i_qgroups; + struct btrfs_fs_info *fs_info = trans->fs_info; struct btrfs_root *quota_root = fs_info->quota_root; struct btrfs_qgroup *srcgroup; struct btrfs_qgroup *dstgroup; diff --git a/fs/btrfs/qgroup.h b/fs/btrfs/qgroup.h index 2c8960f9028c..54b8bb282c0e 100644 --- a/fs/btrfs/qgroup.h +++ b/fs/btrfs/qgroup.h @@ -241,9 +241,8 @@ int btrfs_qgroup_account_extent(struct btrfs_trans_handle *trans, u64 bytenr, struct ulist *new_roots); int btrfs_qgroup_account_extents(struct btrfs_trans_handle *trans); int btrfs_run_qgroups(struct btrfs_trans_handle *trans); -int btrfs_qgroup_inherit(struct btrfs_trans_handle *trans, - struct btrfs_fs_info *fs_info, u64 srcid, u64 objectid, - struct btrfs_qgroup_inherit *inherit); +int btrfs_qgroup_inherit(struct btrfs_trans_handle *trans, u64 srcid, + u64 objectid, struct btrfs_qgroup_inherit *inherit); void btrfs_qgroup_free_refroot(struct btrfs_fs_info *fs_info, u64 ref_root, u64 num_bytes, enum btrfs_qgroup_rsv_type type); diff --git a/fs/btrfs/transaction.c b/fs/btrfs/transaction.c index 0cbd55c498a1..aec208cbff00 100644 --- a/fs/btrfs/transaction.c +++ b/fs/btrfs/transaction.c @@ -1355,8 +1355,7 @@ static int qgroup_account_snapshot(struct btrfs_trans_handle *trans, goto out; /* Now qgroup are all updated, we can inherit it to new qgroups */ - ret = btrfs_qgroup_inherit(trans, fs_info, - src->root_key.objectid, dst_objectid, + ret = btrfs_qgroup_inherit(trans, src->root_key.objectid, dst_objectid, inherit); if (ret < 0) goto out; -- cgit v1.2.3 From 62088ca7427d23ec1a5def9143098ca9c41c5302 Mon Sep 17 00:00:00 2001 From: Lu Fengqi Date: Wed, 18 Jul 2018 14:45:42 +0800 Subject: btrfs: qgroup: Drop fs_info parameter from qgroup_rescan_leaf It can be fetched from the transaction handle. Signed-off-by: Lu Fengqi Signed-off-by: David Sterba --- fs/btrfs/qgroup.c | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) (limited to 'fs') diff --git a/fs/btrfs/qgroup.c b/fs/btrfs/qgroup.c index 96640c56c910..e11ed7b3f32a 100644 --- a/fs/btrfs/qgroup.c +++ b/fs/btrfs/qgroup.c @@ -2640,10 +2640,10 @@ static bool is_last_leaf(struct btrfs_path *path) * returns < 0 on error, 0 when more leafs are to be scanned. * returns 1 when done. */ -static int -qgroup_rescan_leaf(struct btrfs_fs_info *fs_info, struct btrfs_path *path, - struct btrfs_trans_handle *trans) +static int qgroup_rescan_leaf(struct btrfs_trans_handle *trans, + struct btrfs_path *path) { + struct btrfs_fs_info *fs_info = trans->fs_info; struct btrfs_key found; struct extent_buffer *scratch_leaf = NULL; struct ulist *roots = NULL; @@ -2758,7 +2758,7 @@ static void btrfs_qgroup_rescan_worker(struct btrfs_work *work) if (!test_bit(BTRFS_FS_QUOTA_ENABLED, &fs_info->flags)) { err = -EINTR; } else { - err = qgroup_rescan_leaf(fs_info, path, trans); + err = qgroup_rescan_leaf(trans, path); } if (err > 0) btrfs_commit_transaction(trans); -- cgit v1.2.3 From 321a4bf72b251319aa456ea542161729442b6f61 Mon Sep 17 00:00:00 2001 From: Anand Jain Date: Mon, 16 Jul 2018 22:58:09 +0800 Subject: btrfs: use the assigned fs_devices instead of the dereference We have assigned the %fs_info->fs_devices in %fs_devices as its not modified just use it for the mutex_lock(). Signed-off-by: Anand Jain Signed-off-by: David Sterba --- fs/btrfs/volumes.c | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) (limited to 'fs') diff --git a/fs/btrfs/volumes.c b/fs/btrfs/volumes.c index fd9d4e056b37..0b9023f52b2a 100644 --- a/fs/btrfs/volumes.c +++ b/fs/btrfs/volumes.c @@ -2211,7 +2211,7 @@ static int btrfs_prepare_sprout(struct btrfs_fs_info *fs_info) INIT_LIST_HEAD(&seed_devices->alloc_list); mutex_init(&seed_devices->device_list_mutex); - mutex_lock(&fs_info->fs_devices->device_list_mutex); + mutex_lock(&fs_devices->device_list_mutex); list_splice_init_rcu(&fs_devices->devices, &seed_devices->devices, synchronize_rcu); list_for_each_entry(device, &seed_devices->devices, dev_list) @@ -2231,7 +2231,7 @@ static int btrfs_prepare_sprout(struct btrfs_fs_info *fs_info) generate_random_uuid(fs_devices->fsid); memcpy(fs_info->fsid, fs_devices->fsid, BTRFS_FSID_SIZE); memcpy(disk_super->fsid, fs_devices->fsid, BTRFS_FSID_SIZE); - mutex_unlock(&fs_info->fs_devices->device_list_mutex); + mutex_unlock(&fs_devices->device_list_mutex); super_flags = btrfs_super_flags(disk_super) & ~BTRFS_SUPER_FLAG_SEEDING; -- cgit v1.2.3 From 46df06b85e28eaf430aa5c8f8aa26120fa746b72 Mon Sep 17 00:00:00 2001 From: David Sterba Date: Fri, 13 Jul 2018 20:46:30 +0200 Subject: btrfs: refactor block group replication factor calculation to a helper There are many places that open code the duplicity factor of the block group profiles, create a common helper. This can be easily extended for more copies. Signed-off-by: David Sterba --- fs/btrfs/extent-tree.c | 36 ++++++++---------------------------- fs/btrfs/super.c | 11 +++-------- fs/btrfs/volumes.c | 11 +++++++++++ fs/btrfs/volumes.h | 2 ++ 4 files changed, 24 insertions(+), 36 deletions(-) (limited to 'fs') diff --git a/fs/btrfs/extent-tree.c b/fs/btrfs/extent-tree.c index 4f19bdca3214..fd109bfd528d 100644 --- a/fs/btrfs/extent-tree.c +++ b/fs/btrfs/extent-tree.c @@ -3931,11 +3931,7 @@ static void update_space_info(struct btrfs_fs_info *info, u64 flags, struct btrfs_space_info *found; int factor; - if (flags & (BTRFS_BLOCK_GROUP_DUP | BTRFS_BLOCK_GROUP_RAID1 | - BTRFS_BLOCK_GROUP_RAID10)) - factor = 2; - else - factor = 1; + factor = btrfs_bg_type_to_factor(flags); found = __find_space_info(info, flags); ASSERT(found); @@ -4576,6 +4572,7 @@ static int can_overcommit(struct btrfs_fs_info *fs_info, u64 space_size; u64 avail; u64 used; + int factor; /* Don't overcommit when in mixed mode. */ if (space_info->flags & BTRFS_BLOCK_GROUP_DATA) @@ -4610,10 +4607,8 @@ static int can_overcommit(struct btrfs_fs_info *fs_info, * doesn't include the parity drive, so we don't have to * change the math */ - if (profile & (BTRFS_BLOCK_GROUP_DUP | - BTRFS_BLOCK_GROUP_RAID1 | - BTRFS_BLOCK_GROUP_RAID10)) - avail >>= 1; + factor = btrfs_bg_type_to_factor(profile); + avail = div_u64(avail, factor); /* * If we aren't flushing all things, let us overcommit up to @@ -6094,12 +6089,8 @@ static int update_block_group(struct btrfs_trans_handle *trans, cache = btrfs_lookup_block_group(info, bytenr); if (!cache) return -ENOENT; - if (cache->flags & (BTRFS_BLOCK_GROUP_DUP | - BTRFS_BLOCK_GROUP_RAID1 | - BTRFS_BLOCK_GROUP_RAID10)) - factor = 2; - else - factor = 1; + factor = btrfs_bg_type_to_factor(cache->flags); + /* * If this block group has free space cache written out, we * need to make sure to load it if we are removing space. This @@ -9359,13 +9350,7 @@ u64 btrfs_account_ro_block_groups_free_space(struct btrfs_space_info *sinfo) continue; } - if (block_group->flags & (BTRFS_BLOCK_GROUP_RAID1 | - BTRFS_BLOCK_GROUP_RAID10 | - BTRFS_BLOCK_GROUP_DUP)) - factor = 2; - else - factor = 1; - + factor = btrfs_bg_type_to_factor(block_group->flags); free_bytes += (block_group->key.offset - btrfs_block_group_used(&block_group->item)) * factor; @@ -10175,12 +10160,7 @@ int btrfs_remove_block_group(struct btrfs_trans_handle *trans, memcpy(&key, &block_group->key, sizeof(key)); index = btrfs_bg_flags_to_raid_index(block_group->flags); - if (block_group->flags & (BTRFS_BLOCK_GROUP_DUP | - BTRFS_BLOCK_GROUP_RAID1 | - BTRFS_BLOCK_GROUP_RAID10)) - factor = 2; - else - factor = 1; + factor = btrfs_bg_type_to_factor(block_group->flags); /* make sure this block group isn't part of an allocation cluster */ cluster = &fs_info->data_alloc_cluster; diff --git a/fs/btrfs/super.c b/fs/btrfs/super.c index d7a54c648c5f..efe8b03ce380 100644 --- a/fs/btrfs/super.c +++ b/fs/btrfs/super.c @@ -2107,14 +2107,9 @@ static int btrfs_statfs(struct dentry *dentry, struct kstatfs *buf) btrfs_account_ro_block_groups_free_space(found); for (i = 0; i < BTRFS_NR_RAID_TYPES; i++) { - if (!list_empty(&found->block_groups[i])) { - switch (i) { - case BTRFS_RAID_DUP: - case BTRFS_RAID_RAID1: - case BTRFS_RAID_RAID10: - factor = 2; - } - } + if (!list_empty(&found->block_groups[i])) + factor = btrfs_bg_type_to_factor( + btrfs_raid_array[i].bg_flag); } } diff --git a/fs/btrfs/volumes.c b/fs/btrfs/volumes.c index 0b9023f52b2a..eca67529e536 100644 --- a/fs/btrfs/volumes.c +++ b/fs/btrfs/volumes.c @@ -7292,3 +7292,14 @@ void btrfs_reset_fs_info_ptr(struct btrfs_fs_info *fs_info) fs_devices = fs_devices->seed; } } + +/* + * Multiplicity factor for simple profiles: DUP, RAID1-like and RAID10. + */ +int btrfs_bg_type_to_factor(u64 flags) +{ + if (flags & (BTRFS_BLOCK_GROUP_DUP | BTRFS_BLOCK_GROUP_RAID1 | + BTRFS_BLOCK_GROUP_RAID10)) + return 2; + return 1; +} diff --git a/fs/btrfs/volumes.h b/fs/btrfs/volumes.h index 06d8bb7dd557..6943aab9bdd7 100644 --- a/fs/btrfs/volumes.h +++ b/fs/btrfs/volumes.h @@ -559,4 +559,6 @@ void btrfs_reset_fs_info_ptr(struct btrfs_fs_info *fs_info); bool btrfs_check_rw_degradable(struct btrfs_fs_info *fs_info, struct btrfs_device *failing_dev); +int btrfs_bg_type_to_factor(u64 flags); + #endif -- cgit v1.2.3 From 8b9b6f255485a4354da5474b16e79c447222e9ed Mon Sep 17 00:00:00 2001 From: Qu Wenruo Date: Wed, 11 Jul 2018 13:41:22 +0800 Subject: btrfs: scrub: cleanup the remaining nodatasum fixup code Remove the remaining code that misused the page cache pages during device replace and could cause data corruption for compressed nodatasum extents. Such files do not normally exist but there's a bug that allows this combination and the corruption was exposed by device replace fixup code. Signed-off-by: Qu Wenruo Signed-off-by: David Sterba --- fs/btrfs/scrub.c | 289 ------------------------------------------------------- 1 file changed, 289 deletions(-) (limited to 'fs') diff --git a/fs/btrfs/scrub.c b/fs/btrfs/scrub.c index 1235ad8dd9d7..c4eb9eca13b8 100644 --- a/fs/btrfs/scrub.c +++ b/fs/btrfs/scrub.c @@ -188,15 +188,6 @@ struct scrub_ctx { refcount_t refs; }; -struct scrub_fixup_nodatasum { - struct scrub_ctx *sctx; - struct btrfs_device *dev; - u64 logical; - struct btrfs_root *root; - struct btrfs_work work; - int mirror_num; -}; - struct scrub_warning { struct btrfs_path *path; u64 extent_item_size; @@ -215,8 +206,6 @@ struct full_stripe_lock { static void scrub_pending_bio_inc(struct scrub_ctx *sctx); static void scrub_pending_bio_dec(struct scrub_ctx *sctx); -static void scrub_pending_trans_workers_inc(struct scrub_ctx *sctx); -static void scrub_pending_trans_workers_dec(struct scrub_ctx *sctx); static int scrub_handle_errored_block(struct scrub_block *sblock_to_check); static int scrub_setup_recheck_block(struct scrub_block *original_sblock, struct scrub_block *sblocks_for_recheck); @@ -531,60 +520,6 @@ out: return ret; } -/* - * used for workers that require transaction commits (i.e., for the - * NOCOW case) - */ -static void scrub_pending_trans_workers_inc(struct scrub_ctx *sctx) -{ - struct btrfs_fs_info *fs_info = sctx->fs_info; - - refcount_inc(&sctx->refs); - /* - * increment scrubs_running to prevent cancel requests from - * completing as long as a worker is running. we must also - * increment scrubs_paused to prevent deadlocking on pause - * requests used for transactions commits (as the worker uses a - * transaction context). it is safe to regard the worker - * as paused for all matters practical. effectively, we only - * avoid cancellation requests from completing. - */ - mutex_lock(&fs_info->scrub_lock); - atomic_inc(&fs_info->scrubs_running); - atomic_inc(&fs_info->scrubs_paused); - mutex_unlock(&fs_info->scrub_lock); - - /* - * check if @scrubs_running=@scrubs_paused condition - * inside wait_event() is not an atomic operation. - * which means we may inc/dec @scrub_running/paused - * at any time. Let's wake up @scrub_pause_wait as - * much as we can to let commit transaction blocked less. - */ - wake_up(&fs_info->scrub_pause_wait); - - atomic_inc(&sctx->workers_pending); -} - -/* used for workers that require transaction commits */ -static void scrub_pending_trans_workers_dec(struct scrub_ctx *sctx) -{ - struct btrfs_fs_info *fs_info = sctx->fs_info; - - /* - * see scrub_pending_trans_workers_inc() why we're pretending - * to be paused in the scrub counters - */ - mutex_lock(&fs_info->scrub_lock); - atomic_dec(&fs_info->scrubs_running); - atomic_dec(&fs_info->scrubs_paused); - mutex_unlock(&fs_info->scrub_lock); - atomic_dec(&sctx->workers_pending); - wake_up(&fs_info->scrub_pause_wait); - wake_up(&sctx->list_wait); - scrub_put_ctx(sctx); -} - static void scrub_free_csums(struct scrub_ctx *sctx) { while (!list_empty(&sctx->csum_list)) { @@ -858,194 +793,6 @@ out: btrfs_free_path(path); } -static int scrub_fixup_readpage(u64 inum, u64 offset, u64 root, void *fixup_ctx) -{ - struct page *page = NULL; - unsigned long index; - struct scrub_fixup_nodatasum *fixup = fixup_ctx; - int ret; - int corrected = 0; - struct btrfs_key key; - struct inode *inode = NULL; - struct btrfs_fs_info *fs_info; - u64 end = offset + PAGE_SIZE - 1; - struct btrfs_root *local_root; - int srcu_index; - - key.objectid = root; - key.type = BTRFS_ROOT_ITEM_KEY; - key.offset = (u64)-1; - - fs_info = fixup->root->fs_info; - srcu_index = srcu_read_lock(&fs_info->subvol_srcu); - - local_root = btrfs_read_fs_root_no_name(fs_info, &key); - if (IS_ERR(local_root)) { - srcu_read_unlock(&fs_info->subvol_srcu, srcu_index); - return PTR_ERR(local_root); - } - - key.type = BTRFS_INODE_ITEM_KEY; - key.objectid = inum; - key.offset = 0; - inode = btrfs_iget(fs_info->sb, &key, local_root, NULL); - srcu_read_unlock(&fs_info->subvol_srcu, srcu_index); - if (IS_ERR(inode)) - return PTR_ERR(inode); - - index = offset >> PAGE_SHIFT; - - page = find_or_create_page(inode->i_mapping, index, GFP_NOFS); - if (!page) { - ret = -ENOMEM; - goto out; - } - - if (PageUptodate(page)) { - if (PageDirty(page)) { - /* - * we need to write the data to the defect sector. the - * data that was in that sector is not in memory, - * because the page was modified. we must not write the - * modified page to that sector. - * - * TODO: what could be done here: wait for the delalloc - * runner to write out that page (might involve - * COW) and see whether the sector is still - * referenced afterwards. - * - * For the meantime, we'll treat this error - * incorrectable, although there is a chance that a - * later scrub will find the bad sector again and that - * there's no dirty page in memory, then. - */ - ret = -EIO; - goto out; - } - ret = repair_io_failure(fs_info, inum, offset, PAGE_SIZE, - fixup->logical, page, - offset - page_offset(page), - fixup->mirror_num); - unlock_page(page); - corrected = !ret; - } else { - /* - * we need to get good data first. the general readpage path - * will call repair_io_failure for us, we just have to make - * sure we read the bad mirror. - */ - ret = set_extent_bits(&BTRFS_I(inode)->io_tree, offset, end, - EXTENT_DAMAGED); - if (ret) { - /* set_extent_bits should give proper error */ - WARN_ON(ret > 0); - if (ret > 0) - ret = -EFAULT; - goto out; - } - - ret = extent_read_full_page(&BTRFS_I(inode)->io_tree, page, - btrfs_get_extent, - fixup->mirror_num); - wait_on_page_locked(page); - - corrected = !test_range_bit(&BTRFS_I(inode)->io_tree, offset, - end, EXTENT_DAMAGED, 0, NULL); - if (!corrected) - clear_extent_bits(&BTRFS_I(inode)->io_tree, offset, end, - EXTENT_DAMAGED); - } - -out: - if (page) - put_page(page); - - iput(inode); - - if (ret < 0) - return ret; - - if (ret == 0 && corrected) { - /* - * we only need to call readpage for one of the inodes belonging - * to this extent. so make iterate_extent_inodes stop - */ - return 1; - } - - return -EIO; -} - -static void scrub_fixup_nodatasum(struct btrfs_work *work) -{ - struct btrfs_fs_info *fs_info; - int ret; - struct scrub_fixup_nodatasum *fixup; - struct scrub_ctx *sctx; - struct btrfs_trans_handle *trans = NULL; - struct btrfs_path *path; - int uncorrectable = 0; - - fixup = container_of(work, struct scrub_fixup_nodatasum, work); - sctx = fixup->sctx; - fs_info = fixup->root->fs_info; - - path = btrfs_alloc_path(); - if (!path) { - spin_lock(&sctx->stat_lock); - ++sctx->stat.malloc_errors; - spin_unlock(&sctx->stat_lock); - uncorrectable = 1; - goto out; - } - - trans = btrfs_join_transaction(fixup->root); - if (IS_ERR(trans)) { - uncorrectable = 1; - goto out; - } - - /* - * the idea is to trigger a regular read through the standard path. we - * read a page from the (failed) logical address by specifying the - * corresponding copynum of the failed sector. thus, that readpage is - * expected to fail. - * that is the point where on-the-fly error correction will kick in - * (once it's finished) and rewrite the failed sector if a good copy - * can be found. - */ - ret = iterate_inodes_from_logical(fixup->logical, fs_info, path, - scrub_fixup_readpage, fixup, false); - if (ret < 0) { - uncorrectable = 1; - goto out; - } - WARN_ON(ret != 1); - - spin_lock(&sctx->stat_lock); - ++sctx->stat.corrected_errors; - spin_unlock(&sctx->stat_lock); - -out: - if (trans && !IS_ERR(trans)) - btrfs_end_transaction(trans); - if (uncorrectable) { - spin_lock(&sctx->stat_lock); - ++sctx->stat.uncorrectable_errors; - spin_unlock(&sctx->stat_lock); - btrfs_dev_replace_stats_inc( - &fs_info->dev_replace.num_uncorrectable_read_errors); - btrfs_err_rl_in_rcu(fs_info, - "unable to fixup (nodatasum) error at logical %llu on dev %s", - fixup->logical, rcu_str_deref(fixup->dev->name)); - } - - btrfs_free_path(path); - kfree(fixup); - - scrub_pending_trans_workers_dec(sctx); -} - static inline void scrub_get_recover(struct scrub_recover *recover) { refcount_inc(&recover->refs); @@ -1239,42 +986,6 @@ static int scrub_handle_errored_block(struct scrub_block *sblock_to_check) goto out; } - /* - * NOTE: Even for nodatasum case, it's still possible that it's a - * compressed data extent, thus scrub_fixup_nodatasum(), which write - * inode page cache onto disk, could cause serious data corruption. - * - * So here we could only read from disk, and hope our recovery could - * reach disk before the newer write. - */ - if (0 && !is_metadata && !have_csum) { - struct scrub_fixup_nodatasum *fixup_nodatasum; - - WARN_ON(sctx->is_dev_replace); - - /* - * !is_metadata and !have_csum, this means that the data - * might not be COWed, that it might be modified - * concurrently. The general strategy to work on the - * commit root does not help in the case when COW is not - * used. - */ - fixup_nodatasum = kzalloc(sizeof(*fixup_nodatasum), GFP_NOFS); - if (!fixup_nodatasum) - goto did_not_correct_error; - fixup_nodatasum->sctx = sctx; - fixup_nodatasum->dev = dev; - fixup_nodatasum->logical = logical; - fixup_nodatasum->root = fs_info->extent_root; - fixup_nodatasum->mirror_num = failed_mirror_index + 1; - scrub_pending_trans_workers_inc(sctx); - btrfs_init_work(&fixup_nodatasum->work, btrfs_scrub_helper, - scrub_fixup_nodatasum, NULL, NULL); - btrfs_queue_work(fs_info->scrub_workers, - &fixup_nodatasum->work); - goto out; - } - /* * now build and submit the bios for the other mirrors, check * checksums. -- cgit v1.2.3 From 28187ae569e8a6c34eb7ac8871f479d94be31e16 Mon Sep 17 00:00:00 2001 From: Nikolay Borisov Date: Wed, 4 Jul 2018 10:24:51 +0300 Subject: btrfs: Simplify page unlocking in alloc_extent_buffer Current version of the page unlocking code was added in 727011e07cbd ("Btrfs: allow metadata blocks larger than the page size") but even in this commit that particular flag was never used per-se. In fact, btrfs only uses PageChecked for data pages to identify pages which have been dirtied but don't have ORDERED bit set. For more information see 247e743cbe6e ("Btrfs: Use async helpers to deal with pages that have been improperly dirtied"). However, this doesn't apply to extent buffer pages. The important bit here is that the pages are unlocked AFTER the extent buffer has been properly recorded in the radix tree to avoid races with btree_releasepage. Let's exploit this fact and simplify the page unlocking sequence by unlocking the pages in-order and removing the redundant PageChecked flag setting/clearing. Signed-off-by: Nikolay Borisov Reviewed-by: David Sterba Signed-off-by: David Sterba --- fs/btrfs/extent_io.c | 9 ++------- 1 file changed, 2 insertions(+), 7 deletions(-) (limited to 'fs') diff --git a/fs/btrfs/extent_io.c b/fs/btrfs/extent_io.c index fea015be4ce1..e9c74ce9623f 100644 --- a/fs/btrfs/extent_io.c +++ b/fs/btrfs/extent_io.c @@ -5047,13 +5047,8 @@ again: * after the extent buffer is in the radix tree so * it doesn't get lost */ - SetPageChecked(eb->pages[0]); - for (i = 1; i < num_pages; i++) { - p = eb->pages[i]; - ClearPageChecked(p); - unlock_page(p); - } - unlock_page(eb->pages[0]); + for (i = 0; i < num_pages; i++) + unlock_page(eb->pages[i]); return eb; free_eb: -- cgit v1.2.3 From b16d011e79fb353abff70b2ef35b22ed90dc8db5 Mon Sep 17 00:00:00 2001 From: Nikolay Borisov Date: Wed, 4 Jul 2018 10:24:52 +0300 Subject: btrfs: Reword dodgy comments in alloc_extent_buffer Commit eb14ab8ed24a ("Btrfs: fix page->private races") fixed a genuine race between extent buffer initialisation and btree_releasepage. Unfortunately as the code has evolved the comments weren't changed which made them slightly wrong and they weren't very clear in the fist place. Fix this by (hopefully) rewording them in a more approachable manner. Signed-off-by: Nikolay Borisov Reviewed-by: David Sterba Signed-off-by: David Sterba --- fs/btrfs/extent_io.c | 17 ++++++++--------- 1 file changed, 8 insertions(+), 9 deletions(-) (limited to 'fs') diff --git a/fs/btrfs/extent_io.c b/fs/btrfs/extent_io.c index e9c74ce9623f..96039dd56c72 100644 --- a/fs/btrfs/extent_io.c +++ b/fs/btrfs/extent_io.c @@ -5009,8 +5009,11 @@ struct extent_buffer *alloc_extent_buffer(struct btrfs_fs_info *fs_info, uptodate = 0; /* - * see below about how we avoid a nasty race with release page - * and why we unlock later + * We can't unlock the pages just yet since the extent buffer + * hasn't been properly inserted in the radix tree, this + * opens a race with btree_releasepage which can free a page + * while we are still filling in all pages for the buffer and + * we could crash. */ } if (uptodate) @@ -5039,13 +5042,9 @@ again: set_bit(EXTENT_BUFFER_IN_TREE, &eb->bflags); /* - * there is a race where release page may have - * tried to find this extent buffer in the radix - * but failed. It will tell the VM it is safe to - * reclaim the, and it will clear the page private bit. - * We must make sure to set the page private bit properly - * after the extent buffer is in the radix tree so - * it doesn't get lost + * Now it's safe to unlock the pages because any calls to + * btree_releasepage will correctly detect that a page belongs to a + * live buffer and won't free them prematurely. */ for (i = 0; i < num_pages; i++) unlock_page(eb->pages[i]); -- cgit v1.2.3 From d64766fdf9cd172f8416d898cc9d5219ed933b96 Mon Sep 17 00:00:00 2001 From: Nikolay Borisov Date: Wed, 27 Jun 2018 16:38:22 +0300 Subject: btrfs: Refactor loop in btrfs_release_extent_buffer_page The purpose of the function is to free all the pages comprising an extent buffer. This can be achieved with a simple for loop rather than the slightly more involved 'do {} while' construct. So rewrite the loop using a 'for' construct. Additionally we can never have an extent_buffer that has 0 pages so remove the check for index == 0. No functional changes. The reversed order used to have a meaning in the past where the first page served as a blocking point for several callers. See eg 4f2de97acee6532b36dd6e99 ("Btrfs: set page->private to the eb"). Signed-off-by: Nikolay Borisov Reviewed-by: David Sterba Signed-off-by: David Sterba --- fs/btrfs/extent_io.c | 15 ++++++--------- 1 file changed, 6 insertions(+), 9 deletions(-) (limited to 'fs') diff --git a/fs/btrfs/extent_io.c b/fs/btrfs/extent_io.c index 96039dd56c72..66b5272bbaab 100644 --- a/fs/btrfs/extent_io.c +++ b/fs/btrfs/extent_io.c @@ -4647,19 +4647,16 @@ int extent_buffer_under_io(struct extent_buffer *eb) */ static void btrfs_release_extent_buffer_page(struct extent_buffer *eb) { - int index; - struct page *page; + int i; + int num_pages; int mapped = !test_bit(EXTENT_BUFFER_DUMMY, &eb->bflags); BUG_ON(extent_buffer_under_io(eb)); - index = num_extent_pages(eb); - if (index == 0) - return; + num_pages = num_extent_pages(eb); + for (i = 0; i < num_pages; i++) { + struct page *page = eb->pages[i]; - do { - index--; - page = eb->pages[index]; if (!page) continue; if (mapped) @@ -4691,7 +4688,7 @@ static void btrfs_release_extent_buffer_page(struct extent_buffer *eb) /* One for when we allocated the page */ put_page(page); - } while (index != 0); + } } /* -- cgit v1.2.3 From 55ac01396ae8cfc0616e85bb4b49a130144633c2 Mon Sep 17 00:00:00 2001 From: David Sterba Date: Thu, 19 Jul 2018 17:24:32 +0200 Subject: btrfs: rename btrfs_release_extent_buffer_page The function used to release one page (and always the first one), but not anymore since a50924e3a4d7fccb0ecfbd4 ("btrfs: drop constant param from btrfs_release_extent_buffer_page"). Update the name and comment. Signed-off-by: David Sterba --- fs/btrfs/extent_io.c | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) (limited to 'fs') diff --git a/fs/btrfs/extent_io.c b/fs/btrfs/extent_io.c index 66b5272bbaab..6a4013ddcf73 100644 --- a/fs/btrfs/extent_io.c +++ b/fs/btrfs/extent_io.c @@ -4643,9 +4643,9 @@ int extent_buffer_under_io(struct extent_buffer *eb) } /* - * Helper for releasing extent buffer page. + * Release all pages attached to the extent buffer. */ -static void btrfs_release_extent_buffer_page(struct extent_buffer *eb) +static void btrfs_release_extent_buffer_pages(struct extent_buffer *eb) { int i; int num_pages; @@ -4696,7 +4696,7 @@ static void btrfs_release_extent_buffer_page(struct extent_buffer *eb) */ static inline void btrfs_release_extent_buffer(struct extent_buffer *eb) { - btrfs_release_extent_buffer_page(eb); + btrfs_release_extent_buffer_pages(eb); __free_extent_buffer(eb); } @@ -5085,7 +5085,7 @@ static int release_extent_buffer(struct extent_buffer *eb) } /* Should be safe to release our pages at this point */ - btrfs_release_extent_buffer_page(eb); + btrfs_release_extent_buffer_pages(eb); #ifdef CONFIG_BTRFS_FS_RUN_SANITY_TESTS if (unlikely(test_bit(EXTENT_BUFFER_DUMMY, &eb->bflags))) { __free_extent_buffer(eb); -- cgit v1.2.3 From 07e21c4dad42be8d2a6b8cd0b98cf8e6931e12fd Mon Sep 17 00:00:00 2001 From: Nikolay Borisov Date: Wed, 27 Jun 2018 16:38:23 +0300 Subject: btrfs: Document locking requirement via lockdep_assert_held Remove stale comment since there is no longer an eb->eb_lock and document the locking expectation with a lockdep_assert_held statement. No functional changes. Signed-off-by: Nikolay Borisov Reviewed-by: David Sterba Signed-off-by: David Sterba --- fs/btrfs/extent_io.c | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) (limited to 'fs') diff --git a/fs/btrfs/extent_io.c b/fs/btrfs/extent_io.c index 6a4013ddcf73..5ab401f79683 100644 --- a/fs/btrfs/extent_io.c +++ b/fs/btrfs/extent_io.c @@ -5066,9 +5066,10 @@ static inline void btrfs_release_extent_buffer_rcu(struct rcu_head *head) __free_extent_buffer(eb); } -/* Expects to have eb->eb_lock already held */ static int release_extent_buffer(struct extent_buffer *eb) { + lockdep_assert_held(&eb->refs_lock); + WARN_ON(atomic_read(&eb->refs) == 0); if (atomic_dec_and_test(&eb->refs)) { if (test_and_clear_bit(EXTENT_BUFFER_IN_TREE, &eb->bflags)) { -- cgit v1.2.3 From b0132a3be5daf84116833542717ff5692f51640e Mon Sep 17 00:00:00 2001 From: Nikolay Borisov Date: Wed, 27 Jun 2018 16:38:24 +0300 Subject: btrfs: Rename EXTENT_BUFFER_DUMMY to EXTENT_BUFFER_UNMAPPED EXTENT_BUFFER_DUMMY is an awful name for this flag. Buffers which have this flag set are not in any way dummy. Rather, they are private in the sense that are not mapped and linked to the global buffer tree. This flag has subtle implications to the way free_extent_buffer works for example, as well as controls whether page->mapping->private_lock is held during extent_buffer release. Pages for an unmapped buffer cannot be under io, nor can they be written by a 3rd party so taking the lock is unnecessary. Signed-off-by: Nikolay Borisov Reviewed-by: David Sterba [ EXTENT_BUFFER_UNMAPPED, update changelog ] Signed-off-by: David Sterba --- fs/btrfs/disk-io.c | 4 ++-- fs/btrfs/extent_io.c | 10 +++++----- fs/btrfs/extent_io.h | 2 +- 3 files changed, 8 insertions(+), 8 deletions(-) (limited to 'fs') diff --git a/fs/btrfs/disk-io.c b/fs/btrfs/disk-io.c index e3858b2fe014..a4b713d03a33 100644 --- a/fs/btrfs/disk-io.c +++ b/fs/btrfs/disk-io.c @@ -4089,10 +4089,10 @@ void btrfs_mark_buffer_dirty(struct extent_buffer *buf) #ifdef CONFIG_BTRFS_FS_RUN_SANITY_TESTS /* * This is a fast path so only do this check if we have sanity tests - * enabled. Normal people shouldn't be marking dummy buffers as dirty + * enabled. Normal people shouldn't be using umapped buffers as dirty * outside of the sanity tests. */ - if (unlikely(test_bit(EXTENT_BUFFER_DUMMY, &buf->bflags))) + if (unlikely(test_bit(EXTENT_BUFFER_UNMAPPED, &buf->bflags))) return; #endif root = BTRFS_I(buf->pages[0]->mapping->host)->root; diff --git a/fs/btrfs/extent_io.c b/fs/btrfs/extent_io.c index 5ab401f79683..3440053f3599 100644 --- a/fs/btrfs/extent_io.c +++ b/fs/btrfs/extent_io.c @@ -4649,7 +4649,7 @@ static void btrfs_release_extent_buffer_pages(struct extent_buffer *eb) { int i; int num_pages; - int mapped = !test_bit(EXTENT_BUFFER_DUMMY, &eb->bflags); + int mapped = !test_bit(EXTENT_BUFFER_UNMAPPED, &eb->bflags); BUG_ON(extent_buffer_under_io(eb)); @@ -4763,7 +4763,7 @@ struct extent_buffer *btrfs_clone_extent_buffer(struct extent_buffer *src) } set_bit(EXTENT_BUFFER_UPTODATE, &new->bflags); - set_bit(EXTENT_BUFFER_DUMMY, &new->bflags); + set_bit(EXTENT_BUFFER_UNMAPPED, &new->bflags); return new; } @@ -4787,7 +4787,7 @@ struct extent_buffer *__alloc_dummy_extent_buffer(struct btrfs_fs_info *fs_info, } set_extent_buffer_uptodate(eb); btrfs_set_header_nritems(eb, 0); - set_bit(EXTENT_BUFFER_DUMMY, &eb->bflags); + set_bit(EXTENT_BUFFER_UNMAPPED, &eb->bflags); return eb; err: @@ -5088,7 +5088,7 @@ static int release_extent_buffer(struct extent_buffer *eb) /* Should be safe to release our pages at this point */ btrfs_release_extent_buffer_pages(eb); #ifdef CONFIG_BTRFS_FS_RUN_SANITY_TESTS - if (unlikely(test_bit(EXTENT_BUFFER_DUMMY, &eb->bflags))) { + if (unlikely(test_bit(EXTENT_BUFFER_UNMAPPED, &eb->bflags))) { __free_extent_buffer(eb); return 1; } @@ -5119,7 +5119,7 @@ void free_extent_buffer(struct extent_buffer *eb) spin_lock(&eb->refs_lock); if (atomic_read(&eb->refs) == 2 && - test_bit(EXTENT_BUFFER_DUMMY, &eb->bflags)) + test_bit(EXTENT_BUFFER_UNMAPPED, &eb->bflags)) atomic_dec(&eb->refs); if (atomic_read(&eb->refs) == 2 && diff --git a/fs/btrfs/extent_io.h b/fs/btrfs/extent_io.h index 48f1ee9ad379..0ecc13b7d6f7 100644 --- a/fs/btrfs/extent_io.h +++ b/fs/btrfs/extent_io.h @@ -46,7 +46,7 @@ #define EXTENT_BUFFER_STALE 6 #define EXTENT_BUFFER_WRITEBACK 7 #define EXTENT_BUFFER_READ_ERR 8 /* read IO error */ -#define EXTENT_BUFFER_DUMMY 9 +#define EXTENT_BUFFER_UNMAPPED 9 #define EXTENT_BUFFER_IN_TREE 10 #define EXTENT_BUFFER_WRITE_ERR 11 /* write IO error */ -- cgit v1.2.3 From 315409b0098fb2651d86553f0436b70502b29bb2 Mon Sep 17 00:00:00 2001 From: Gu Jinxiang Date: Wed, 4 Jul 2018 18:16:39 +0800 Subject: btrfs: validate type when reading a chunk Reported in https://bugzilla.kernel.org/show_bug.cgi?id=199839, with an image that has an invalid chunk type but does not return an error. Add chunk type check in btrfs_check_chunk_valid, to detect the wrong type combinations. Link: https://bugzilla.kernel.org/show_bug.cgi?id=199839 Reported-by: Xu Wen Reviewed-by: Qu Wenruo Signed-off-by: Gu Jinxiang Signed-off-by: David Sterba --- fs/btrfs/volumes.c | 28 ++++++++++++++++++++++++++++ 1 file changed, 28 insertions(+) (limited to 'fs') diff --git a/fs/btrfs/volumes.c b/fs/btrfs/volumes.c index eca67529e536..f237ef9e70a7 100644 --- a/fs/btrfs/volumes.c +++ b/fs/btrfs/volumes.c @@ -6313,6 +6313,8 @@ static int btrfs_check_chunk_valid(struct btrfs_fs_info *fs_info, u16 num_stripes; u16 sub_stripes; u64 type; + u64 features; + bool mixed = false; length = btrfs_chunk_length(leaf, chunk); stripe_len = btrfs_chunk_stripe_len(leaf, chunk); @@ -6351,6 +6353,32 @@ static int btrfs_check_chunk_valid(struct btrfs_fs_info *fs_info, btrfs_chunk_type(leaf, chunk)); return -EIO; } + + if ((type & BTRFS_BLOCK_GROUP_TYPE_MASK) == 0) { + btrfs_err(fs_info, "missing chunk type flag: 0x%llx", type); + return -EIO; + } + + if ((type & BTRFS_BLOCK_GROUP_SYSTEM) && + (type & (BTRFS_BLOCK_GROUP_METADATA | BTRFS_BLOCK_GROUP_DATA))) { + btrfs_err(fs_info, + "system chunk with data or metadata type: 0x%llx", type); + return -EIO; + } + + features = btrfs_super_incompat_flags(fs_info->super_copy); + if (features & BTRFS_FEATURE_INCOMPAT_MIXED_GROUPS) + mixed = true; + + if (!mixed) { + if ((type & BTRFS_BLOCK_GROUP_METADATA) && + (type & BTRFS_BLOCK_GROUP_DATA)) { + btrfs_err(fs_info, + "mixed chunk type in non-mixed mode: 0x%llx", type); + return -EIO; + } + } + if ((type & BTRFS_BLOCK_GROUP_RAID10 && sub_stripes != 2) || (type & BTRFS_BLOCK_GROUP_RAID1 && num_stripes < 1) || (type & BTRFS_BLOCK_GROUP_RAID5 && num_stripes < 2) || -- cgit v1.2.3 From d7e8555b1dd493c809e56e359974eecabe7d3fde Mon Sep 17 00:00:00 2001 From: David Sterba Date: Wed, 18 Jul 2018 17:31:19 +0200 Subject: btrfs: remove unused member async_submit_bio::fs_info Introduced by c6100a4b4e3d1 ("Btrfs: replace tree->mapping with tree->private_data") to be used in run_one_async_done where it got unused after 736cd52e0c720103 ("Btrfs: remove nr_async_submits and async_submit_draining"). Reviewed-by: Nikolay Borisov Signed-off-by: David Sterba --- fs/btrfs/disk-io.c | 2 -- 1 file changed, 2 deletions(-) (limited to 'fs') diff --git a/fs/btrfs/disk-io.c b/fs/btrfs/disk-io.c index a4b713d03a33..8033289d2189 100644 --- a/fs/btrfs/disk-io.c +++ b/fs/btrfs/disk-io.c @@ -106,7 +106,6 @@ void __cold btrfs_end_io_wq_exit(void) */ struct async_submit_bio { void *private_data; - struct btrfs_fs_info *fs_info; struct bio *bio; extent_submit_bio_start_t *submit_bio_start; extent_submit_bio_done_t *submit_bio_done; @@ -801,7 +800,6 @@ blk_status_t btrfs_wq_submit_bio(struct btrfs_fs_info *fs_info, struct bio *bio, return BLK_STS_RESOURCE; async->private_data = private_data; - async->fs_info = fs_info; async->bio = bio; async->mirror_num = mirror_num; async->submit_bio_start = submit_bio_start; -- cgit v1.2.3 From d7cbfafc4bc37ed21351cdedbc6f9d979545dbf3 Mon Sep 17 00:00:00 2001 From: David Sterba Date: Wed, 18 Jul 2018 17:31:10 +0200 Subject: btrfs: remove unused member async_submit_bio::bio_flags After splitting the start and end hooks in a758781d4b76c3 ("btrfs: separate types for submit_bio_start and submit_bio_done"), some of the function arguments were dropped but not removed from the structure. Reviewed-by: Nikolay Borisov Signed-off-by: David Sterba --- fs/btrfs/disk-io.c | 2 -- 1 file changed, 2 deletions(-) (limited to 'fs') diff --git a/fs/btrfs/disk-io.c b/fs/btrfs/disk-io.c index 8033289d2189..d82df15af89c 100644 --- a/fs/btrfs/disk-io.c +++ b/fs/btrfs/disk-io.c @@ -110,7 +110,6 @@ struct async_submit_bio { extent_submit_bio_start_t *submit_bio_start; extent_submit_bio_done_t *submit_bio_done; int mirror_num; - unsigned long bio_flags; /* * bio_offset is optional, can be used if the pages in the bio * can't tell us where in the file the bio should go @@ -808,7 +807,6 @@ blk_status_t btrfs_wq_submit_bio(struct btrfs_fs_info *fs_info, struct bio *bio, btrfs_init_work(&async->work, btrfs_worker_helper, run_one_async_start, run_one_async_done, run_one_async_free); - async->bio_flags = bio_flags; async->bio_offset = bio_offset; async->status = 0; -- cgit v1.2.3 From e288c080dddd1fdc3b7e0165cebd7af51a52d016 Mon Sep 17 00:00:00 2001 From: David Sterba Date: Wed, 18 Jul 2018 17:36:24 +0200 Subject: btrfs: unify end_io callbacks of async_submit_bio The end_io callbacks passed to btrfs_wq_submit_bio (btrfs_submit_bio_done and btree_submit_bio_done) are effectively the same code, there's no point to do the indirection. Export btrfs_submit_bio_done and call it directly. Reviewed-by: Nikolay Borisov Signed-off-by: David Sterba --- fs/btrfs/disk-io.c | 28 +++------------------------- fs/btrfs/disk-io.h | 5 +++-- fs/btrfs/extent_io.h | 3 --- fs/btrfs/inode.c | 8 +++----- 4 files changed, 9 insertions(+), 35 deletions(-) (limited to 'fs') diff --git a/fs/btrfs/disk-io.c b/fs/btrfs/disk-io.c index d82df15af89c..03a7ed448f38 100644 --- a/fs/btrfs/disk-io.c +++ b/fs/btrfs/disk-io.c @@ -108,7 +108,6 @@ struct async_submit_bio { void *private_data; struct bio *bio; extent_submit_bio_start_t *submit_bio_start; - extent_submit_bio_done_t *submit_bio_done; int mirror_num; /* * bio_offset is optional, can be used if the pages in the bio @@ -775,7 +774,7 @@ static void run_one_async_done(struct btrfs_work *work) return; } - async->submit_bio_done(async->private_data, async->bio, async->mirror_num); + btrfs_submit_bio_done(async->private_data, async->bio, async->mirror_num); } static void run_one_async_free(struct btrfs_work *work) @@ -789,8 +788,7 @@ static void run_one_async_free(struct btrfs_work *work) blk_status_t btrfs_wq_submit_bio(struct btrfs_fs_info *fs_info, struct bio *bio, int mirror_num, unsigned long bio_flags, u64 bio_offset, void *private_data, - extent_submit_bio_start_t *submit_bio_start, - extent_submit_bio_done_t *submit_bio_done) + extent_submit_bio_start_t *submit_bio_start) { struct async_submit_bio *async; @@ -802,7 +800,6 @@ blk_status_t btrfs_wq_submit_bio(struct btrfs_fs_info *fs_info, struct bio *bio, async->bio = bio; async->mirror_num = mirror_num; async->submit_bio_start = submit_bio_start; - async->submit_bio_done = submit_bio_done; btrfs_init_work(&async->work, btrfs_worker_helper, run_one_async_start, run_one_async_done, run_one_async_free); @@ -845,24 +842,6 @@ static blk_status_t btree_submit_bio_start(void *private_data, struct bio *bio, return btree_csum_one_bio(bio); } -static blk_status_t btree_submit_bio_done(void *private_data, struct bio *bio, - int mirror_num) -{ - struct inode *inode = private_data; - blk_status_t ret; - - /* - * when we're called for a write, we're already in the async - * submission context. Just jump into btrfs_map_bio - */ - ret = btrfs_map_bio(btrfs_sb(inode->i_sb), bio, mirror_num, 1); - if (ret) { - bio->bi_status = ret; - bio_endio(bio); - } - return ret; -} - static int check_async_write(struct btrfs_inode *bi) { if (atomic_read(&bi->sync_writers)) @@ -905,8 +884,7 @@ static blk_status_t btree_submit_bio_hook(void *private_data, struct bio *bio, */ ret = btrfs_wq_submit_bio(fs_info, bio, mirror_num, 0, bio_offset, private_data, - btree_submit_bio_start, - btree_submit_bio_done); + btree_submit_bio_start); } if (ret) diff --git a/fs/btrfs/disk-io.h b/fs/btrfs/disk-io.h index 1a3d277b027b..4cccba22640f 100644 --- a/fs/btrfs/disk-io.h +++ b/fs/btrfs/disk-io.h @@ -120,8 +120,9 @@ blk_status_t btrfs_bio_wq_end_io(struct btrfs_fs_info *info, struct bio *bio, blk_status_t btrfs_wq_submit_bio(struct btrfs_fs_info *fs_info, struct bio *bio, int mirror_num, unsigned long bio_flags, u64 bio_offset, void *private_data, - extent_submit_bio_start_t *submit_bio_start, - extent_submit_bio_done_t *submit_bio_done); + extent_submit_bio_start_t *submit_bio_start); +blk_status_t btrfs_submit_bio_done(void *private_data, struct bio *bio, + int mirror_num); int btrfs_write_tree_block(struct extent_buffer *buf); void btrfs_wait_tree_block_writeback(struct extent_buffer *buf); int btrfs_init_log_root_tree(struct btrfs_trans_handle *trans, diff --git a/fs/btrfs/extent_io.h b/fs/btrfs/extent_io.h index 0ecc13b7d6f7..4e6d34dd7caf 100644 --- a/fs/btrfs/extent_io.h +++ b/fs/btrfs/extent_io.h @@ -92,9 +92,6 @@ typedef blk_status_t (extent_submit_bio_hook_t)(void *private_data, struct bio * typedef blk_status_t (extent_submit_bio_start_t)(void *private_data, struct bio *bio, u64 bio_offset); -typedef blk_status_t (extent_submit_bio_done_t)(void *private_data, - struct bio *bio, int mirror_num); - struct extent_io_ops { /* * The following callbacks must be allways defined, the function diff --git a/fs/btrfs/inode.c b/fs/btrfs/inode.c index 564ec00c765b..6cb42e33fdc3 100644 --- a/fs/btrfs/inode.c +++ b/fs/btrfs/inode.c @@ -1957,7 +1957,7 @@ static blk_status_t btrfs_submit_bio_start(void *private_data, struct bio *bio, * At IO completion time the cums attached on the ordered extent record * are inserted into the btree */ -static blk_status_t btrfs_submit_bio_done(void *private_data, struct bio *bio, +blk_status_t btrfs_submit_bio_done(void *private_data, struct bio *bio, int mirror_num) { struct inode *inode = private_data; @@ -2030,8 +2030,7 @@ static blk_status_t btrfs_submit_bio_hook(void *private_data, struct bio *bio, /* we're doing a write, do the async checksumming */ ret = btrfs_wq_submit_bio(fs_info, bio, mirror_num, bio_flags, bio_offset, inode, - btrfs_submit_bio_start, - btrfs_submit_bio_done); + btrfs_submit_bio_start); goto out; } else if (!skip_sum) { ret = btrfs_csum_one_bio(inode, bio, 0, 0); @@ -8295,8 +8294,7 @@ static inline blk_status_t btrfs_submit_dio_bio(struct bio *bio, if (write && async_submit) { ret = btrfs_wq_submit_bio(fs_info, bio, 0, 0, file_offset, inode, - btrfs_submit_bio_start_direct_io, - btrfs_submit_bio_done); + btrfs_submit_bio_start_direct_io); goto err; } else if (write) { /* -- cgit v1.2.3 From 05912a3c04ebca217507b4323b679c60eda4ac11 Mon Sep 17 00:00:00 2001 From: David Sterba Date: Wed, 18 Jul 2018 19:23:45 +0200 Subject: btrfs: drop extent_io_ops::tree_fs_info callback All implementations of the callback are trivial and do the same and there's only one user. Merge everything together. Reviewed-by: Nikolay Borisov Signed-off-by: David Sterba --- fs/btrfs/disk-io.c | 7 ------- fs/btrfs/extent_io.c | 14 ++++---------- fs/btrfs/extent_io.h | 1 - fs/btrfs/inode.c | 7 ------- 4 files changed, 4 insertions(+), 25 deletions(-) (limited to 'fs') diff --git a/fs/btrfs/disk-io.c b/fs/btrfs/disk-io.c index 03a7ed448f38..126460214512 100644 --- a/fs/btrfs/disk-io.c +++ b/fs/btrfs/disk-io.c @@ -4523,12 +4523,6 @@ static int btrfs_cleanup_transaction(struct btrfs_fs_info *fs_info) return 0; } -static struct btrfs_fs_info *btree_fs_info(void *private_data) -{ - struct inode *inode = private_data; - return btrfs_sb(inode->i_sb); -} - static const struct extent_io_ops btree_extent_io_ops = { /* mandatory callbacks */ .submit_bio_hook = btree_submit_bio_hook, @@ -4537,7 +4531,6 @@ static const struct extent_io_ops btree_extent_io_ops = { .merge_bio_hook = btrfs_merge_bio_hook, .readpage_io_failed_hook = btree_io_failed_hook, .set_range_writeback = btrfs_set_range_writeback, - .tree_fs_info = btree_fs_info, /* optional callbacks */ }; diff --git a/fs/btrfs/extent_io.c b/fs/btrfs/extent_io.c index 3440053f3599..7a19437c6eda 100644 --- a/fs/btrfs/extent_io.c +++ b/fs/btrfs/extent_io.c @@ -140,14 +140,6 @@ static int add_extent_changeset(struct extent_state *state, unsigned bits, static void flush_write_bio(struct extent_page_data *epd); -static inline struct btrfs_fs_info * -tree_fs_info(struct extent_io_tree *tree) -{ - if (tree->ops) - return tree->ops->tree_fs_info(tree->private_data); - return NULL; -} - int __init extent_io_init(void) { extent_state_cache = kmem_cache_create("btrfs_extent_state", @@ -564,8 +556,10 @@ alloc_extent_state_atomic(struct extent_state *prealloc) static void extent_io_tree_panic(struct extent_io_tree *tree, int err) { - btrfs_panic(tree_fs_info(tree), err, - "Locking error: Extent tree was modified by another thread while locked."); + struct inode *inode = tree->private_data; + + btrfs_panic(btrfs_sb(inode->i_sb), err, + "locking error: extent tree was modified by another thread while locked"); } /* diff --git a/fs/btrfs/extent_io.h b/fs/btrfs/extent_io.h index 4e6d34dd7caf..004517f3eb35 100644 --- a/fs/btrfs/extent_io.h +++ b/fs/btrfs/extent_io.h @@ -105,7 +105,6 @@ struct extent_io_ops { size_t size, struct bio *bio, unsigned long bio_flags); int (*readpage_io_failed_hook)(struct page *page, int failed_mirror); - struct btrfs_fs_info *(*tree_fs_info)(void *private_data); void (*set_range_writeback)(void *private_data, u64 start, u64 end); /* diff --git a/fs/btrfs/inode.c b/fs/btrfs/inode.c index 6cb42e33fdc3..f279e380f36e 100644 --- a/fs/btrfs/inode.c +++ b/fs/btrfs/inode.c @@ -10473,12 +10473,6 @@ static int btrfs_readpage_io_failed_hook(struct page *page, int failed_mirror) return -EAGAIN; } -static struct btrfs_fs_info *iotree_fs_info(void *private_data) -{ - struct inode *inode = private_data; - return btrfs_sb(inode->i_sb); -} - static void btrfs_check_extent_io_range(void *private_data, const char *caller, u64 start, u64 end) { @@ -10553,7 +10547,6 @@ static const struct extent_io_ops btrfs_extent_io_ops = { .readpage_end_io_hook = btrfs_readpage_end_io_hook, .merge_bio_hook = btrfs_merge_bio_hook, .readpage_io_failed_hook = btrfs_readpage_io_failed_hook, - .tree_fs_info = iotree_fs_info, .set_range_writeback = btrfs_set_range_writeback, /* optional callbacks */ -- cgit v1.2.3 From 00032d38eaa89c76de7d9c1ae6de8c48c14edd74 Mon Sep 17 00:00:00 2001 From: David Sterba Date: Wed, 18 Jul 2018 19:28:09 +0200 Subject: btrfs: drop extent_io_ops::merge_bio_hook callback The data and metadata callback implementation both use the same function. We can remove the call indirection completely. Reviewed-by: Nikolay Borisov Signed-off-by: David Sterba --- fs/btrfs/compression.c | 10 +++------- fs/btrfs/disk-io.c | 2 -- fs/btrfs/extent_io.c | 4 ++-- fs/btrfs/extent_io.h | 3 --- fs/btrfs/inode.c | 5 ++--- 5 files changed, 7 insertions(+), 17 deletions(-) (limited to 'fs') diff --git a/fs/btrfs/compression.c b/fs/btrfs/compression.c index 70dace47258b..9bfa66592aa7 100644 --- a/fs/btrfs/compression.c +++ b/fs/btrfs/compression.c @@ -299,7 +299,6 @@ blk_status_t btrfs_submit_compressed_write(struct inode *inode, u64 start, struct bio *bio = NULL; struct compressed_bio *cb; unsigned long bytes_left; - struct extent_io_tree *io_tree = &BTRFS_I(inode)->io_tree; int pg_index = 0; struct page *page; u64 first_byte = disk_start; @@ -338,9 +337,7 @@ blk_status_t btrfs_submit_compressed_write(struct inode *inode, u64 start, page = compressed_pages[pg_index]; page->mapping = inode->i_mapping; if (bio->bi_iter.bi_size) - submit = io_tree->ops->merge_bio_hook(page, 0, - PAGE_SIZE, - bio, 0); + submit = btrfs_merge_bio_hook(page, 0, PAGE_SIZE, bio, 0); page->mapping = NULL; if (submit || bio_add_page(bio, page, PAGE_SIZE, 0) < @@ -622,9 +619,8 @@ blk_status_t btrfs_submit_compressed_read(struct inode *inode, struct bio *bio, page->index = em_start >> PAGE_SHIFT; if (comp_bio->bi_iter.bi_size) - submit = tree->ops->merge_bio_hook(page, 0, - PAGE_SIZE, - comp_bio, 0); + submit = btrfs_merge_bio_hook(page, 0, PAGE_SIZE, + comp_bio, 0); page->mapping = NULL; if (submit || bio_add_page(comp_bio, page, PAGE_SIZE, 0) < diff --git a/fs/btrfs/disk-io.c b/fs/btrfs/disk-io.c index 126460214512..0c9c029ade72 100644 --- a/fs/btrfs/disk-io.c +++ b/fs/btrfs/disk-io.c @@ -4527,8 +4527,6 @@ static const struct extent_io_ops btree_extent_io_ops = { /* mandatory callbacks */ .submit_bio_hook = btree_submit_bio_hook, .readpage_end_io_hook = btree_readpage_end_io_hook, - /* note we're sharing with inode.c for the merge bio hook */ - .merge_bio_hook = btrfs_merge_bio_hook, .readpage_io_failed_hook = btree_io_failed_hook, .set_range_writeback = btrfs_set_range_writeback, diff --git a/fs/btrfs/extent_io.c b/fs/btrfs/extent_io.c index 7a19437c6eda..20af0efd7c17 100644 --- a/fs/btrfs/extent_io.c +++ b/fs/btrfs/extent_io.c @@ -2784,8 +2784,8 @@ static int submit_extent_page(unsigned int opf, struct extent_io_tree *tree, else contig = bio_end_sector(bio) == sector; - if (tree->ops && tree->ops->merge_bio_hook(page, offset, - page_size, bio, bio_flags)) + if (tree->ops && btrfs_merge_bio_hook(page, offset, page_size, + bio, bio_flags)) can_merge = false; if (prev_bio_flags != bio_flags || !contig || !can_merge || diff --git a/fs/btrfs/extent_io.h b/fs/btrfs/extent_io.h index 004517f3eb35..5c07f87c2ec9 100644 --- a/fs/btrfs/extent_io.h +++ b/fs/btrfs/extent_io.h @@ -101,9 +101,6 @@ struct extent_io_ops { int (*readpage_end_io_hook)(struct btrfs_io_bio *io_bio, u64 phy_offset, struct page *page, u64 start, u64 end, int mirror); - int (*merge_bio_hook)(struct page *page, unsigned long offset, - size_t size, struct bio *bio, - unsigned long bio_flags); int (*readpage_io_failed_hook)(struct page *page, int failed_mirror); void (*set_range_writeback)(void *private_data, u64 start, u64 end); diff --git a/fs/btrfs/inode.c b/fs/btrfs/inode.c index f279e380f36e..a72784d5666f 100644 --- a/fs/btrfs/inode.c +++ b/fs/btrfs/inode.c @@ -1898,8 +1898,8 @@ static void btrfs_clear_bit_hook(void *private_data, } /* - * extent_io.c merge_bio_hook, this must check the chunk tree to make sure - * we don't create bios that span stripes or chunks + * Merge bio hook, this must check the chunk tree to make sure we don't create + * bios that span stripes or chunks * * return 1 if page cannot be merged to bio * return 0 if page can be merged to bio @@ -10545,7 +10545,6 @@ static const struct extent_io_ops btrfs_extent_io_ops = { /* mandatory callbacks */ .submit_bio_hook = btrfs_submit_bio_hook, .readpage_end_io_hook = btrfs_readpage_end_io_hook, - .merge_bio_hook = btrfs_merge_bio_hook, .readpage_io_failed_hook = btrfs_readpage_io_failed_hook, .set_range_writeback = btrfs_set_range_writeback, -- cgit v1.2.3 From 5cdc84bfde22dc17b11ee7cb18cebd48f4a09f70 Mon Sep 17 00:00:00 2001 From: David Sterba Date: Wed, 18 Jul 2018 20:32:52 +0200 Subject: btrfs: drop extent_io_ops::set_range_writeback callback The data and metadata callback implementation both use the same function. We can remove the call indirection and intermediate helper completely. Reviewed-by: Nikolay Borisov Signed-off-by: David Sterba --- fs/btrfs/ctree.h | 2 +- fs/btrfs/disk-io.c | 1 - fs/btrfs/extent_io.c | 10 +--------- fs/btrfs/extent_io.h | 1 - fs/btrfs/inode.c | 5 ++--- 5 files changed, 4 insertions(+), 15 deletions(-) (limited to 'fs') diff --git a/fs/btrfs/ctree.h b/fs/btrfs/ctree.h index ee1e152cb94b..9c638931b75e 100644 --- a/fs/btrfs/ctree.h +++ b/fs/btrfs/ctree.h @@ -3172,7 +3172,7 @@ int btrfs_create_subvol_root(struct btrfs_trans_handle *trans, int btrfs_merge_bio_hook(struct page *page, unsigned long offset, size_t size, struct bio *bio, unsigned long bio_flags); -void btrfs_set_range_writeback(void *private_data, u64 start, u64 end); +void btrfs_set_range_writeback(struct extent_io_tree *tree, u64 start, u64 end); vm_fault_t btrfs_page_mkwrite(struct vm_fault *vmf); int btrfs_readpage(struct file *file, struct page *page); void btrfs_evict_inode(struct inode *inode); diff --git a/fs/btrfs/disk-io.c b/fs/btrfs/disk-io.c index 0c9c029ade72..9b208ccf24fe 100644 --- a/fs/btrfs/disk-io.c +++ b/fs/btrfs/disk-io.c @@ -4528,7 +4528,6 @@ static const struct extent_io_ops btree_extent_io_ops = { .submit_bio_hook = btree_submit_bio_hook, .readpage_end_io_hook = btree_readpage_end_io_hook, .readpage_io_failed_hook = btree_io_failed_hook, - .set_range_writeback = btrfs_set_range_writeback, /* optional callbacks */ }; diff --git a/fs/btrfs/extent_io.c b/fs/btrfs/extent_io.c index 20af0efd7c17..628f1aef34b0 100644 --- a/fs/btrfs/extent_io.c +++ b/fs/btrfs/extent_io.c @@ -1380,14 +1380,6 @@ void extent_range_redirty_for_io(struct inode *inode, u64 start, u64 end) } } -/* - * helper function to set both pages and extents in the tree writeback - */ -static void set_range_writeback(struct extent_io_tree *tree, u64 start, u64 end) -{ - tree->ops->set_range_writeback(tree->private_data, start, end); -} - /* find the first state struct with 'bits' set after 'start', and * return it. tree->lock must be held. NULL will returned if * nothing was found after 'start' @@ -3416,7 +3408,7 @@ static noinline_for_stack int __extent_writepage_io(struct inode *inode, continue; } - set_range_writeback(tree, cur, cur + iosize - 1); + btrfs_set_range_writeback(tree, cur, cur + iosize - 1); if (!PageWriteback(page)) { btrfs_err(BTRFS_I(inode)->root->fs_info, "page %lu not writeback, cur %llu end %llu", diff --git a/fs/btrfs/extent_io.h b/fs/btrfs/extent_io.h index 5c07f87c2ec9..b4d03e677e1d 100644 --- a/fs/btrfs/extent_io.h +++ b/fs/btrfs/extent_io.h @@ -102,7 +102,6 @@ struct extent_io_ops { struct page *page, u64 start, u64 end, int mirror); int (*readpage_io_failed_hook)(struct page *page, int failed_mirror); - void (*set_range_writeback)(void *private_data, u64 start, u64 end); /* * Optional hooks, called if the pointer is not NULL diff --git a/fs/btrfs/inode.c b/fs/btrfs/inode.c index a72784d5666f..4955e04da4c8 100644 --- a/fs/btrfs/inode.c +++ b/fs/btrfs/inode.c @@ -10487,9 +10487,9 @@ static void btrfs_check_extent_io_range(void *private_data, const char *caller, } } -void btrfs_set_range_writeback(void *private_data, u64 start, u64 end) +void btrfs_set_range_writeback(struct extent_io_tree *tree, u64 start, u64 end) { - struct inode *inode = private_data; + struct inode *inode = tree->private_data; unsigned long index = start >> PAGE_SHIFT; unsigned long end_index = end >> PAGE_SHIFT; struct page *page; @@ -10546,7 +10546,6 @@ static const struct extent_io_ops btrfs_extent_io_ops = { .submit_bio_hook = btrfs_submit_bio_hook, .readpage_end_io_hook = btrfs_readpage_end_io_hook, .readpage_io_failed_hook = btrfs_readpage_io_failed_hook, - .set_range_writeback = btrfs_set_range_writeback, /* optional callbacks */ .fill_delalloc = run_delalloc_range, -- cgit v1.2.3 From ca5d2ba1ae2dfd651b798218d56c3277784fa499 Mon Sep 17 00:00:00 2001 From: Filipe Manana Date: Mon, 23 Jul 2018 09:10:09 +0100 Subject: Btrfs: remove unused key assignment when doing a full send At send.c:full_send_tree() we were setting the 'key' variable in the loop while never using it later. We were also using two btrfs_key variables to store the initial key for search and the key found in every iteration of the loop. So remove this useless key assignment and use the same btrfs_key variable to store the initial search key and the key found in each iteration. This was introduced in the initial send commit but was never used (commit 31db9f7c23fb ("Btrfs: introduce BTRFS_IOC_SEND for btrfs send/receive"). Signed-off-by: Filipe Manana Reviewed-by: David Sterba Signed-off-by: David Sterba --- fs/btrfs/send.c | 9 ++------- 1 file changed, 2 insertions(+), 7 deletions(-) (limited to 'fs') diff --git a/fs/btrfs/send.c b/fs/btrfs/send.c index 6ff7a1315e52..42e04cd3cd95 100644 --- a/fs/btrfs/send.c +++ b/fs/btrfs/send.c @@ -6325,7 +6325,6 @@ static int full_send_tree(struct send_ctx *sctx) int ret; struct btrfs_root *send_root = sctx->send_root; struct btrfs_key key; - struct btrfs_key found_key; struct btrfs_path *path; struct extent_buffer *eb; int slot; @@ -6347,17 +6346,13 @@ static int full_send_tree(struct send_ctx *sctx) while (1) { eb = path->nodes[0]; slot = path->slots[0]; - btrfs_item_key_to_cpu(eb, &found_key, slot); + btrfs_item_key_to_cpu(eb, &key, slot); - ret = changed_cb(path, NULL, &found_key, + ret = changed_cb(path, NULL, &key, BTRFS_COMPARE_TREE_NEW, sctx); if (ret < 0) goto out; - key.objectid = found_key.objectid; - key.type = found_key.type; - key.offset = found_key.offset + 1; - ret = btrfs_next_item(send_root, path); if (ret < 0) goto out; -- cgit v1.2.3 From 5e23a6fea6189d1f9d6e6ca5cb3290b4a0fe2d48 Mon Sep 17 00:00:00 2001 From: Qu Wenruo Date: Mon, 23 Jul 2018 14:47:29 +0800 Subject: btrfs: extent-tree: Remove dead alignment check In find_free_extent() under checks: label, we have the following code: search_start = ALIGN(offset, fs_info->stripesize); /* move on to the next group */ if (search_start + num_bytes > block_group->key.objectid + block_group->key.offset) { btrfs_add_free_space(block_group, offset, num_bytes); goto loop; } if (offset < search_start) btrfs_add_free_space(block_group, offset, search_start - offset); BUG_ON(offset > search_start); However ALIGN() is rounding up, thus @search_start >= @offset and that BUG_ON() will never be triggered. Signed-off-by: Qu Wenruo Reviewed-by: David Sterba Signed-off-by: David Sterba --- fs/btrfs/extent-tree.c | 3 +-- 1 file changed, 1 insertion(+), 2 deletions(-) (limited to 'fs') diff --git a/fs/btrfs/extent-tree.c b/fs/btrfs/extent-tree.c index fd109bfd528d..c71aa118679d 100644 --- a/fs/btrfs/extent-tree.c +++ b/fs/btrfs/extent-tree.c @@ -7564,7 +7564,7 @@ unclustered_alloc: goto loop; } checks: - search_start = ALIGN(offset, fs_info->stripesize); + search_start = round_up(offset, fs_info->stripesize); /* move on to the next group */ if (search_start + num_bytes > @@ -7576,7 +7576,6 @@ checks: if (offset < search_start) btrfs_add_free_space(block_group, offset, search_start - offset); - BUG_ON(offset > search_start); ret = btrfs_add_reserved_bytes(block_group, ram_bytes, num_bytes, delalloc); -- cgit v1.2.3 From 8e87e8562744e23e10afea98d610cc6b7f4ba9bb Mon Sep 17 00:00:00 2001 From: Nikolay Borisov Date: Fri, 20 Jul 2018 19:37:47 +0300 Subject: btrfs: Remove fs_info argument from btrfs_add_dev_item It can be referenced form the passed transaction handle. Signed-off-by: Nikolay Borisov Reviewed-by: Lu Fengqi Signed-off-by: David Sterba --- fs/btrfs/volumes.c | 10 ++++------ 1 file changed, 4 insertions(+), 6 deletions(-) (limited to 'fs') diff --git a/fs/btrfs/volumes.c b/fs/btrfs/volumes.c index f237ef9e70a7..1c88c4c947bb 100644 --- a/fs/btrfs/volumes.c +++ b/fs/btrfs/volumes.c @@ -1666,10 +1666,8 @@ error: * the btrfs_device struct should be fully filled in */ static int btrfs_add_dev_item(struct btrfs_trans_handle *trans, - struct btrfs_fs_info *fs_info, struct btrfs_device *device) { - struct btrfs_root *root = fs_info->chunk_root; int ret; struct btrfs_path *path; struct btrfs_dev_item *dev_item; @@ -1685,8 +1683,8 @@ static int btrfs_add_dev_item(struct btrfs_trans_handle *trans, key.type = BTRFS_DEV_ITEM_KEY; key.offset = device->devid; - ret = btrfs_insert_empty_item(trans, root, path, &key, - sizeof(*dev_item)); + ret = btrfs_insert_empty_item(trans, trans->fs_info->chunk_root, path, + &key, sizeof(*dev_item)); if (ret) goto out; @@ -1711,7 +1709,7 @@ static int btrfs_add_dev_item(struct btrfs_trans_handle *trans, ptr = btrfs_device_uuid(dev_item); write_extent_buffer(leaf, device->uuid, ptr, BTRFS_UUID_SIZE); ptr = btrfs_device_fsid(dev_item); - write_extent_buffer(leaf, fs_info->fsid, ptr, BTRFS_FSID_SIZE); + write_extent_buffer(leaf, trans->fs_info->fsid, ptr, BTRFS_FSID_SIZE); btrfs_mark_buffer_dirty(leaf); ret = 0; @@ -2449,7 +2447,7 @@ int btrfs_init_new_device(struct btrfs_fs_info *fs_info, const char *device_path } } - ret = btrfs_add_dev_item(trans, fs_info, device); + ret = btrfs_add_dev_item(trans, device); if (ret) { btrfs_abort_transaction(trans, ret); goto error_sysfs; -- cgit v1.2.3 From 68a9db5f2395cdef98b387bbb816604f6f298056 Mon Sep 17 00:00:00 2001 From: Nikolay Borisov Date: Fri, 20 Jul 2018 19:37:48 +0300 Subject: btrfs: Remove fs_info from btrfs_rm_dev_replace_remove_srcdev It can be referenced from the passed srcdev argument. Signed-off-by: Nikolay Borisov Reviewed-by: Lu Fengqi Signed-off-by: David Sterba --- fs/btrfs/dev-replace.c | 2 +- fs/btrfs/volumes.c | 5 ++--- fs/btrfs/volumes.h | 3 +-- 3 files changed, 4 insertions(+), 6 deletions(-) (limited to 'fs') diff --git a/fs/btrfs/dev-replace.c b/fs/btrfs/dev-replace.c index 059ca3d5ddd3..df375e1a0c9f 100644 --- a/fs/btrfs/dev-replace.c +++ b/fs/btrfs/dev-replace.c @@ -667,7 +667,7 @@ static int btrfs_dev_replace_finishing(struct btrfs_fs_info *fs_info, btrfs_rm_dev_replace_blocked(fs_info); - btrfs_rm_dev_replace_remove_srcdev(fs_info, src_device); + btrfs_rm_dev_replace_remove_srcdev(src_device); btrfs_rm_dev_replace_unblocked(fs_info); diff --git a/fs/btrfs/volumes.c b/fs/btrfs/volumes.c index 1c88c4c947bb..d82658b01773 100644 --- a/fs/btrfs/volumes.c +++ b/fs/btrfs/volumes.c @@ -1996,12 +1996,11 @@ error_undo: goto out; } -void btrfs_rm_dev_replace_remove_srcdev(struct btrfs_fs_info *fs_info, - struct btrfs_device *srcdev) +void btrfs_rm_dev_replace_remove_srcdev(struct btrfs_device *srcdev) { struct btrfs_fs_devices *fs_devices; - lockdep_assert_held(&fs_info->fs_devices->device_list_mutex); + lockdep_assert_held(&srcdev->fs_info->fs_devices->device_list_mutex); /* * in case of fs with no seed, srcdev->fs_devices will point diff --git a/fs/btrfs/volumes.h b/fs/btrfs/volumes.h index 6943aab9bdd7..0ae45ff1961b 100644 --- a/fs/btrfs/volumes.h +++ b/fs/btrfs/volumes.h @@ -452,8 +452,7 @@ void btrfs_init_devices_late(struct btrfs_fs_info *fs_info); int btrfs_init_dev_stats(struct btrfs_fs_info *fs_info); int btrfs_run_dev_stats(struct btrfs_trans_handle *trans, struct btrfs_fs_info *fs_info); -void btrfs_rm_dev_replace_remove_srcdev(struct btrfs_fs_info *fs_info, - struct btrfs_device *srcdev); +void btrfs_rm_dev_replace_remove_srcdev(struct btrfs_device *srcdev); void btrfs_rm_dev_replace_free_srcdev(struct btrfs_fs_info *fs_info, struct btrfs_device *srcdev); void btrfs_destroy_dev_replace_tgtdev(struct btrfs_fs_info *fs_info, -- cgit v1.2.3 From 5495f195fc5b246d8b0b8a2e0fbbc9c94b3ebf24 Mon Sep 17 00:00:00 2001 From: Nikolay Borisov Date: Fri, 20 Jul 2018 19:37:49 +0300 Subject: btrfs: remove fs_info argument from update_dev_stat_item It can be referenced from the passed transaction handle. Signed-off-by: Nikolay Borisov Reviewed-by: Lu Fengqi Signed-off-by: David Sterba --- fs/btrfs/volumes.c | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) (limited to 'fs') diff --git a/fs/btrfs/volumes.c b/fs/btrfs/volumes.c index d82658b01773..fc9d70a16d82 100644 --- a/fs/btrfs/volumes.c +++ b/fs/btrfs/volumes.c @@ -7043,9 +7043,9 @@ out: } static int update_dev_stat_item(struct btrfs_trans_handle *trans, - struct btrfs_fs_info *fs_info, struct btrfs_device *device) { + struct btrfs_fs_info *fs_info = trans->fs_info; struct btrfs_root *dev_root = fs_info->dev_root; struct btrfs_path *path; struct btrfs_key key; @@ -7138,7 +7138,7 @@ int btrfs_run_dev_stats(struct btrfs_trans_handle *trans, */ smp_rmb(); - ret = update_dev_stat_item(trans, fs_info, device); + ret = update_dev_stat_item(trans, device); if (!ret) atomic_sub(stats_cnt, &device->dev_stats_ccnt); } -- cgit v1.2.3 From d6507cf1e2dfa4f6888cd90e4c9a307f7ac9b383 Mon Sep 17 00:00:00 2001 From: Nikolay Borisov Date: Fri, 20 Jul 2018 19:37:50 +0300 Subject: btrfs: Remove fs_info from btrfs_assign_next_active_device It can be referenced from the passed 'device' argument which is always a well-formed device. Signed-off-by: Nikolay Borisov Reviewed-by: Lu Fengqi Reviewed-by: David Sterba Signed-off-by: David Sterba --- fs/btrfs/dev-replace.c | 2 +- fs/btrfs/volumes.c | 9 +++++---- fs/btrfs/volumes.h | 4 ++-- 3 files changed, 8 insertions(+), 7 deletions(-) (limited to 'fs') diff --git a/fs/btrfs/dev-replace.c b/fs/btrfs/dev-replace.c index df375e1a0c9f..dd17a4d7bea2 100644 --- a/fs/btrfs/dev-replace.c +++ b/fs/btrfs/dev-replace.c @@ -658,7 +658,7 @@ static int btrfs_dev_replace_finishing(struct btrfs_fs_info *fs_info, tgt_device->commit_total_bytes = src_device->commit_total_bytes; tgt_device->commit_bytes_used = src_device->bytes_used; - btrfs_assign_next_active_device(fs_info, src_device, tgt_device); + btrfs_assign_next_active_device(src_device, tgt_device); list_add(&tgt_device->dev_alloc_list, &fs_info->fs_devices->alloc_list); fs_info->fs_devices->rw_devices++; diff --git a/fs/btrfs/volumes.c b/fs/btrfs/volumes.c index fc9d70a16d82..9cd15964ab6f 100644 --- a/fs/btrfs/volumes.c +++ b/fs/btrfs/volumes.c @@ -1833,9 +1833,10 @@ static struct btrfs_device * btrfs_find_next_active_device( * where this function called, there should be always be another device (or * this_dev) which is active. */ -void btrfs_assign_next_active_device(struct btrfs_fs_info *fs_info, - struct btrfs_device *device, struct btrfs_device *this_dev) +void btrfs_assign_next_active_device(struct btrfs_device *device, + struct btrfs_device *this_dev) { + struct btrfs_fs_info *fs_info = device->fs_info; struct btrfs_device *next_device; if (this_dev) @@ -1945,7 +1946,7 @@ int btrfs_rm_device(struct btrfs_fs_info *fs_info, const char *device_path, if (test_bit(BTRFS_DEV_STATE_MISSING, &device->dev_state)) cur_devices->missing_devices--; - btrfs_assign_next_active_device(fs_info, device, NULL); + btrfs_assign_next_active_device(device, NULL); if (device->bdev) { cur_devices->open_devices--; @@ -2077,7 +2078,7 @@ void btrfs_destroy_dev_replace_tgtdev(struct btrfs_fs_info *fs_info, fs_devices->num_devices--; - btrfs_assign_next_active_device(fs_info, tgtdev, NULL); + btrfs_assign_next_active_device(tgtdev, NULL); list_del_rcu(&tgtdev->dev_list); diff --git a/fs/btrfs/volumes.h b/fs/btrfs/volumes.h index 0ae45ff1961b..1bcf0f34e8dc 100644 --- a/fs/btrfs/volumes.h +++ b/fs/btrfs/volumes.h @@ -407,8 +407,8 @@ struct btrfs_device *btrfs_scan_one_device(const char *path, fmode_t flags, void *holder); int btrfs_close_devices(struct btrfs_fs_devices *fs_devices); void btrfs_free_extra_devids(struct btrfs_fs_devices *fs_devices, int step); -void btrfs_assign_next_active_device(struct btrfs_fs_info *fs_info, - struct btrfs_device *device, struct btrfs_device *this_dev); +void btrfs_assign_next_active_device(struct btrfs_device *device, + struct btrfs_device *this_dev); int btrfs_find_device_missing_or_by_path(struct btrfs_fs_info *fs_info, const char *device_path, struct btrfs_device **device); -- cgit v1.2.3 From 4f5ad7bd6315528ed50a11d53c66854a5d16425b Mon Sep 17 00:00:00 2001 From: Nikolay Borisov Date: Fri, 20 Jul 2018 19:37:51 +0300 Subject: btrfs: Remove fs_info from btrfs_destroy_dev_replace_tgtdev This function is always passed a well-formed tgtdevice so the fs_info can be referenced from there. Signed-off-by: Nikolay Borisov Reviewed-by: Lu Fengqi Signed-off-by: David Sterba --- fs/btrfs/dev-replace.c | 6 +++--- fs/btrfs/volumes.c | 5 ++--- fs/btrfs/volumes.h | 3 +-- 3 files changed, 6 insertions(+), 8 deletions(-) (limited to 'fs') diff --git a/fs/btrfs/dev-replace.c b/fs/btrfs/dev-replace.c index dd17a4d7bea2..5a72f9933e58 100644 --- a/fs/btrfs/dev-replace.c +++ b/fs/btrfs/dev-replace.c @@ -506,7 +506,7 @@ leave: dev_replace->srcdev = NULL; dev_replace->tgtdev = NULL; btrfs_dev_replace_write_unlock(dev_replace); - btrfs_destroy_dev_replace_tgtdev(fs_info, tgt_device); + btrfs_destroy_dev_replace_tgtdev(tgt_device); return ret; } @@ -632,7 +632,7 @@ static int btrfs_dev_replace_finishing(struct btrfs_fs_info *fs_info, mutex_unlock(&fs_info->fs_devices->device_list_mutex); btrfs_rm_dev_replace_blocked(fs_info); if (tgt_device) - btrfs_destroy_dev_replace_tgtdev(fs_info, tgt_device); + btrfs_destroy_dev_replace_tgtdev(tgt_device); btrfs_rm_dev_replace_unblocked(fs_info); mutex_unlock(&dev_replace->lock_finishing_cancel_unmount); @@ -821,7 +821,7 @@ int btrfs_dev_replace_cancel(struct btrfs_fs_info *fs_info) btrfs_dev_name(tgt_device)); if (tgt_device) - btrfs_destroy_dev_replace_tgtdev(fs_info, tgt_device); + btrfs_destroy_dev_replace_tgtdev(tgt_device); leave: mutex_unlock(&dev_replace->lock_finishing_cancel_unmount); diff --git a/fs/btrfs/volumes.c b/fs/btrfs/volumes.c index 9cd15964ab6f..45d7c37050ce 100644 --- a/fs/btrfs/volumes.c +++ b/fs/btrfs/volumes.c @@ -2063,10 +2063,9 @@ void btrfs_rm_dev_replace_free_srcdev(struct btrfs_fs_info *fs_info, } } -void btrfs_destroy_dev_replace_tgtdev(struct btrfs_fs_info *fs_info, - struct btrfs_device *tgtdev) +void btrfs_destroy_dev_replace_tgtdev(struct btrfs_device *tgtdev) { - struct btrfs_fs_devices *fs_devices = fs_info->fs_devices; + struct btrfs_fs_devices *fs_devices = tgtdev->fs_info->fs_devices; WARN_ON(!tgtdev); mutex_lock(&fs_devices->device_list_mutex); diff --git a/fs/btrfs/volumes.h b/fs/btrfs/volumes.h index 1bcf0f34e8dc..69a028058c43 100644 --- a/fs/btrfs/volumes.h +++ b/fs/btrfs/volumes.h @@ -455,8 +455,7 @@ int btrfs_run_dev_stats(struct btrfs_trans_handle *trans, void btrfs_rm_dev_replace_remove_srcdev(struct btrfs_device *srcdev); void btrfs_rm_dev_replace_free_srcdev(struct btrfs_fs_info *fs_info, struct btrfs_device *srcdev); -void btrfs_destroy_dev_replace_tgtdev(struct btrfs_fs_info *fs_info, - struct btrfs_device *tgtdev); +void btrfs_destroy_dev_replace_tgtdev(struct btrfs_device *tgtdev); void btrfs_scratch_superblocks(struct block_device *bdev, const char *device_path); int btrfs_is_parity_mirror(struct btrfs_fs_info *fs_info, u64 logical, u64 len); -- cgit v1.2.3 From f4208794d02e74f16e5744fe2fe294d7f71fa0f9 Mon Sep 17 00:00:00 2001 From: Nikolay Borisov Date: Fri, 20 Jul 2018 19:37:52 +0300 Subject: btrfs: Remove fs_info form btrfs_free_chunk It can be referenced from the passed transaction handle. Signed-off-by: Nikolay Borisov Reviewed-by: Lu Fengqi Signed-off-by: David Sterba --- fs/btrfs/volumes.c | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) (limited to 'fs') diff --git a/fs/btrfs/volumes.c b/fs/btrfs/volumes.c index 45d7c37050ce..991022f5219f 100644 --- a/fs/btrfs/volumes.c +++ b/fs/btrfs/volumes.c @@ -2605,9 +2605,9 @@ int btrfs_grow_device(struct btrfs_trans_handle *trans, return btrfs_update_device(trans, device); } -static int btrfs_free_chunk(struct btrfs_trans_handle *trans, - struct btrfs_fs_info *fs_info, u64 chunk_offset) +static int btrfs_free_chunk(struct btrfs_trans_handle *trans, u64 chunk_offset) { + struct btrfs_fs_info *fs_info = trans->fs_info; struct btrfs_root *root = fs_info->chunk_root; int ret; struct btrfs_path *path; @@ -2777,7 +2777,7 @@ int btrfs_remove_chunk(struct btrfs_trans_handle *trans, } mutex_unlock(&fs_devices->device_list_mutex); - ret = btrfs_free_chunk(trans, fs_info, chunk_offset); + ret = btrfs_free_chunk(trans, chunk_offset); if (ret) { btrfs_abort_transaction(trans, ret); goto out; -- cgit v1.2.3 From 97aff912a2fa75555641303d42bd4c723a98df5d Mon Sep 17 00:00:00 2001 From: Nikolay Borisov Date: Fri, 20 Jul 2018 19:37:53 +0300 Subject: btrfs: Remove fs_info from btrfs_finish_chunk_alloc It can be referenced from the passed transaction handle. Signed-off-by: Nikolay Borisov Reviewed-by: Lu Fengqi Signed-off-by: David Sterba --- fs/btrfs/extent-tree.c | 6 ++---- fs/btrfs/volumes.c | 10 +++++----- fs/btrfs/volumes.h | 6 ++---- 3 files changed, 9 insertions(+), 13 deletions(-) (limited to 'fs') diff --git a/fs/btrfs/extent-tree.c b/fs/btrfs/extent-tree.c index c71aa118679d..16b916a33e56 100644 --- a/fs/btrfs/extent-tree.c +++ b/fs/btrfs/extent-tree.c @@ -10022,8 +10022,7 @@ void btrfs_create_pending_block_groups(struct btrfs_trans_handle *trans) sizeof(item)); if (ret) btrfs_abort_transaction(trans, ret); - ret = btrfs_finish_chunk_alloc(trans, fs_info, key.objectid, - key.offset); + ret = btrfs_finish_chunk_alloc(trans, key.objectid, key.offset); if (ret) btrfs_abort_transaction(trans, ret); add_block_group_free_space(trans, block_group); @@ -10594,8 +10593,7 @@ void btrfs_delete_unused_bgs(struct btrfs_fs_info *fs_info) * Btrfs_remove_chunk will abort the transaction if things go * horribly wrong. */ - ret = btrfs_remove_chunk(trans, fs_info, - block_group->key.objectid); + ret = btrfs_remove_chunk(trans, block_group->key.objectid); if (ret) { if (trimming) diff --git a/fs/btrfs/volumes.c b/fs/btrfs/volumes.c index 991022f5219f..d86346f83a08 100644 --- a/fs/btrfs/volumes.c +++ b/fs/btrfs/volumes.c @@ -2716,9 +2716,9 @@ static struct extent_map *get_chunk_map(struct btrfs_fs_info *fs_info, return em; } -int btrfs_remove_chunk(struct btrfs_trans_handle *trans, - struct btrfs_fs_info *fs_info, u64 chunk_offset) +int btrfs_remove_chunk(struct btrfs_trans_handle *trans, u64 chunk_offset) { + struct btrfs_fs_info *fs_info = trans->fs_info; struct extent_map *em; struct map_lookup *map; u64 dev_extent_len = 0; @@ -2858,7 +2858,7 @@ static int btrfs_relocate_chunk(struct btrfs_fs_info *fs_info, u64 chunk_offset) * step two, delete the device extents and the * chunk tree entries */ - ret = btrfs_remove_chunk(trans, fs_info, chunk_offset); + ret = btrfs_remove_chunk(trans, chunk_offset); btrfs_end_transaction(trans); return ret; } @@ -4842,9 +4842,9 @@ error: } int btrfs_finish_chunk_alloc(struct btrfs_trans_handle *trans, - struct btrfs_fs_info *fs_info, - u64 chunk_offset, u64 chunk_size) + u64 chunk_offset, u64 chunk_size) { + struct btrfs_fs_info *fs_info = trans->fs_info; struct btrfs_root *extent_root = fs_info->extent_root; struct btrfs_root *chunk_root = fs_info->chunk_root; struct btrfs_key key; diff --git a/fs/btrfs/volumes.h b/fs/btrfs/volumes.h index 69a028058c43..049619176831 100644 --- a/fs/btrfs/volumes.h +++ b/fs/btrfs/volumes.h @@ -462,10 +462,8 @@ int btrfs_is_parity_mirror(struct btrfs_fs_info *fs_info, unsigned long btrfs_full_stripe_len(struct btrfs_fs_info *fs_info, u64 logical); int btrfs_finish_chunk_alloc(struct btrfs_trans_handle *trans, - struct btrfs_fs_info *fs_info, - u64 chunk_offset, u64 chunk_size); -int btrfs_remove_chunk(struct btrfs_trans_handle *trans, - struct btrfs_fs_info *fs_info, u64 chunk_offset); + u64 chunk_offset, u64 chunk_size); +int btrfs_remove_chunk(struct btrfs_trans_handle *trans, u64 chunk_offset); static inline void btrfs_dev_stat_inc(struct btrfs_device *dev, int index) -- cgit v1.2.3 From 3c4276936f6fbe52884b4ea4e6cc120b890a0f9f Mon Sep 17 00:00:00 2001 From: Josef Bacik Date: Fri, 20 Jul 2018 11:46:10 -0700 Subject: Btrfs: fix btrfs_write_inode vs delayed iput deadlock We recently ran into the following deadlock involving btrfs_write_inode(): [ +0.005066] __schedule+0x38e/0x8c0 [ +0.007144] schedule+0x36/0x80 [ +0.006447] bit_wait+0x11/0x60 [ +0.006446] __wait_on_bit+0xbe/0x110 [ +0.007487] ? bit_wait_io+0x60/0x60 [ +0.007319] __inode_wait_for_writeback+0x96/0xc0 [ +0.009568] ? autoremove_wake_function+0x40/0x40 [ +0.009565] inode_wait_for_writeback+0x21/0x30 [ +0.009224] evict+0xb0/0x190 [ +0.006099] iput+0x1a8/0x210 [ +0.006103] btrfs_run_delayed_iputs+0x73/0xc0 [ +0.009047] btrfs_commit_transaction+0x799/0x8c0 [ +0.009567] btrfs_write_inode+0x81/0xb0 [ +0.008008] __writeback_single_inode+0x267/0x320 [ +0.009569] writeback_sb_inodes+0x25b/0x4e0 [ +0.008702] wb_writeback+0x102/0x2d0 [ +0.007487] wb_workfn+0xa4/0x310 [ +0.006794] ? wb_workfn+0xa4/0x310 [ +0.007143] process_one_work+0x150/0x410 [ +0.008179] worker_thread+0x6d/0x520 [ +0.007490] kthread+0x12c/0x160 [ +0.006620] ? put_pwq_unlocked+0x80/0x80 [ +0.008185] ? kthread_park+0xa0/0xa0 [ +0.007484] ? do_syscall_64+0x53/0x150 [ +0.007837] ret_from_fork+0x29/0x40 Writeback calls: btrfs_write_inode btrfs_commit_transaction btrfs_run_delayed_iputs If iput() is called on that same inode, evict() will wait for writeback forever. btrfs_write_inode() was originally added way back in 4730a4bc5bf3 ("btrfs_dirty_inode") to support O_SYNC writes. However, ->write_inode() hasn't been used for O_SYNC since 148f948ba877 ("vfs: Introduce new helpers for syncing after writing to O_SYNC file or IS_SYNC inode"), so btrfs_write_inode() is actually unnecessary (and leads to a bunch of unnecessary commits). Get rid of it, which also gets rid of the deadlock. CC: stable@vger.kernel.org # 3.2+ Signed-off-by: Josef Bacik [Omar: new commit message] Signed-off-by: Omar Sandoval Signed-off-by: David Sterba --- fs/btrfs/inode.c | 26 -------------------------- fs/btrfs/super.c | 1 - 2 files changed, 27 deletions(-) (limited to 'fs') diff --git a/fs/btrfs/inode.c b/fs/btrfs/inode.c index 4955e04da4c8..472457795486 100644 --- a/fs/btrfs/inode.c +++ b/fs/btrfs/inode.c @@ -6021,32 +6021,6 @@ err: return ret; } -int btrfs_write_inode(struct inode *inode, struct writeback_control *wbc) -{ - struct btrfs_root *root = BTRFS_I(inode)->root; - struct btrfs_trans_handle *trans; - int ret = 0; - bool nolock = false; - - if (test_bit(BTRFS_INODE_DUMMY, &BTRFS_I(inode)->runtime_flags)) - return 0; - - if (btrfs_fs_closing(root->fs_info) && - btrfs_is_free_space_inode(BTRFS_I(inode))) - nolock = true; - - if (wbc->sync_mode == WB_SYNC_ALL) { - if (nolock) - trans = btrfs_join_transaction_nolock(root); - else - trans = btrfs_join_transaction(root); - if (IS_ERR(trans)) - return PTR_ERR(trans); - ret = btrfs_commit_transaction(trans); - } - return ret; -} - /* * This is somewhat expensive, updating the tree every time the * inode changes. But, it is most likely to find the inode in cache. diff --git a/fs/btrfs/super.c b/fs/btrfs/super.c index efe8b03ce380..67de3c0fc85b 100644 --- a/fs/btrfs/super.c +++ b/fs/btrfs/super.c @@ -2344,7 +2344,6 @@ static const struct super_operations btrfs_super_ops = { .sync_fs = btrfs_sync_fs, .show_options = btrfs_show_options, .show_devname = btrfs_show_devname, - .write_inode = btrfs_write_inode, .alloc_inode = btrfs_alloc_inode, .destroy_inode = btrfs_destroy_inode, .statfs = btrfs_statfs, -- cgit v1.2.3 From 616d374efa23cb699074ea02b301254ad64d224a Mon Sep 17 00:00:00 2001 From: Adam Borowski Date: Wed, 18 Jul 2018 00:08:59 +0200 Subject: btrfs: allow defrag on a file opened read-only that has rw permissions Requiring a read-write descriptor conflicts both ways with exec, returning ETXTBSY whenever you try to defrag a program that's currently being run, or causing intermittent exec failures on a live system being defragged. As defrag doesn't change the file's contents in any way, there's no reason to consider it a rw operation. Thus, let's check only whether the file could have been opened rw. Such access control is still needed as currently defrag can use extra disk space, and might trigger bugs. We return EINVAL when the request is invalid; here it's ok but merely the user has insufficient privileges. Thus, the EPERM return value reflects the error better -- as discussed in the identical case for dedupe. According to codesearch.debian.net, no userspace program distinguishes these values beyond strerror(). Signed-off-by: Adam Borowski Reviewed-by: David Sterba [ fold the EPERM patch from Adam ] Signed-off-by: David Sterba --- fs/btrfs/ioctl.c | 10 ++++++++-- 1 file changed, 8 insertions(+), 2 deletions(-) (limited to 'fs') diff --git a/fs/btrfs/ioctl.c b/fs/btrfs/ioctl.c index 4482cf35522e..80fe3c654612 100644 --- a/fs/btrfs/ioctl.c +++ b/fs/btrfs/ioctl.c @@ -2928,8 +2928,14 @@ static int btrfs_ioctl_defrag(struct file *file, void __user *argp) ret = btrfs_defrag_root(root); break; case S_IFREG: - if (!(file->f_mode & FMODE_WRITE)) { - ret = -EINVAL; + /* + * Note that this does not check the file descriptor for write + * access. This prevents defragmenting executables that are + * running and allows defrag on files open in read-only mode. + */ + if (!capable(CAP_SYS_ADMIN) && + inode_permission(inode, MAY_WRITE)) { + ret = -EPERM; goto out; } -- cgit v1.2.3 From e17385ca2960177da402d6f4d80bdc5b53c29bc4 Mon Sep 17 00:00:00 2001 From: David Sterba Date: Fri, 20 Jul 2018 16:30:18 +0200 Subject: btrfs: remove unused member btrfs_root::name Added in 58176a9604c ("Btrfs: Add per-root block accounting and sysfs entries") in 2007, the roots had names exported in sysfs. The code was commented out in 4df27c4d5cc1dda54ed ("Btrfs: change how subvolumes are organized") and cleaned by 182608c8294b5fe9 ("btrfs: remove old unused commented out code"). Signed-off-by: David Sterba --- fs/btrfs/ctree.h | 1 - fs/btrfs/disk-io.c | 2 -- 2 files changed, 3 deletions(-) (limited to 'fs') diff --git a/fs/btrfs/ctree.h b/fs/btrfs/ctree.h index 9c638931b75e..4ca6c4e141ea 100644 --- a/fs/btrfs/ctree.h +++ b/fs/btrfs/ctree.h @@ -1219,7 +1219,6 @@ struct btrfs_root { u64 defrag_trans_start; struct btrfs_key defrag_progress; struct btrfs_key defrag_max; - char *name; /* the dirty list is only used by non-reference counted roots */ struct list_head dirty_list; diff --git a/fs/btrfs/disk-io.c b/fs/btrfs/disk-io.c index 9b208ccf24fe..3830867e0225 100644 --- a/fs/btrfs/disk-io.c +++ b/fs/btrfs/disk-io.c @@ -1154,7 +1154,6 @@ static void __setup_root(struct btrfs_root *root, struct btrfs_fs_info *fs_info, root->highest_objectid = 0; root->nr_delalloc_inodes = 0; root->nr_ordered_extents = 0; - root->name = NULL; root->inode_tree = RB_ROOT; INIT_RADIX_TREE(&root->delayed_nodes_tree, GFP_ATOMIC); root->block_rsv = NULL; @@ -3849,7 +3848,6 @@ static void free_fs_root(struct btrfs_root *root) free_extent_buffer(root->commit_root); kfree(root->free_ino_ctl); kfree(root->free_ino_pinned); - kfree(root->name); btrfs_put_fs_root(root); } -- cgit v1.2.3 From e9539cff04728e31e150b41000b828745fc0c2b3 Mon Sep 17 00:00:00 2001 From: David Sterba Date: Fri, 20 Jul 2018 16:30:20 +0200 Subject: btrfs: dev-replace: remove unused members of btrfs_dev_replace Lock owner and nesting level have been unused since day 1, probably copy&pasted from the extent_buffer locking scheme without much thinking. The locking of device replace is simpler and does not need any lock nesting. Signed-off-by: David Sterba --- fs/btrfs/ctree.h | 2 -- fs/btrfs/disk-io.c | 2 -- 2 files changed, 4 deletions(-) (limited to 'fs') diff --git a/fs/btrfs/ctree.h b/fs/btrfs/ctree.h index 4ca6c4e141ea..5f6ec80d374f 100644 --- a/fs/btrfs/ctree.h +++ b/fs/btrfs/ctree.h @@ -365,8 +365,6 @@ struct btrfs_dev_replace { struct btrfs_device *srcdev; struct btrfs_device *tgtdev; - pid_t lock_owner; - atomic_t nesting_level; struct mutex lock_finishing_cancel_unmount; rwlock_t lock; atomic_t read_locks; diff --git a/fs/btrfs/disk-io.c b/fs/btrfs/disk-io.c index 3830867e0225..c1d287a766c1 100644 --- a/fs/btrfs/disk-io.c +++ b/fs/btrfs/disk-io.c @@ -2154,8 +2154,6 @@ static void btrfs_init_btree_inode(struct btrfs_fs_info *fs_info) static void btrfs_init_dev_replace_locks(struct btrfs_fs_info *fs_info) { - fs_info->dev_replace.lock_owner = 0; - atomic_set(&fs_info->dev_replace.nesting_level, 0); mutex_init(&fs_info->dev_replace.lock_finishing_cancel_unmount); rwlock_init(&fs_info->dev_replace.lock); atomic_set(&fs_info->dev_replace.read_locks, 0); -- cgit v1.2.3 From 2ffad70ed3b6fbc946bc102f9d11c0e7c1cd380f Mon Sep 17 00:00:00 2001 From: David Sterba Date: Fri, 20 Jul 2018 16:30:23 +0200 Subject: btrfs: constify strings passed to assertion helper Signed-off-by: David Sterba --- fs/btrfs/ctree.h | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) (limited to 'fs') diff --git a/fs/btrfs/ctree.h b/fs/btrfs/ctree.h index 5f6ec80d374f..2e32584c635f 100644 --- a/fs/btrfs/ctree.h +++ b/fs/btrfs/ctree.h @@ -3425,7 +3425,7 @@ do { \ #ifdef CONFIG_BTRFS_ASSERT __cold -static inline void assfail(char *expr, char *file, int line) +static inline void assfail(const char *expr, const char *file, int line) { pr_err("assertion failed: %s, file: %s, line: %d\n", expr, file, line); -- cgit v1.2.3 From 84db5ccf4262894852e0d178d250678945d9b0b8 Mon Sep 17 00:00:00 2001 From: David Sterba Date: Fri, 20 Jul 2018 16:30:25 +0200 Subject: btrfs: merge free_fs_root helpers The exported helper just calls the static one. There's no obvious reason to have them separate eg. for performance reasons where the static one could be better optimized in the same unit. There's a slight decrease in code size and stack consumption. Signed-off-by: David Sterba --- fs/btrfs/disk-io.c | 16 +++++----------- 1 file changed, 5 insertions(+), 11 deletions(-) (limited to 'fs') diff --git a/fs/btrfs/disk-io.c b/fs/btrfs/disk-io.c index c1d287a766c1..6a5a3cd12886 100644 --- a/fs/btrfs/disk-io.c +++ b/fs/btrfs/disk-io.c @@ -52,7 +52,6 @@ static const struct extent_io_ops btree_extent_io_ops; static void end_workqueue_fn(struct btrfs_work *work); -static void free_fs_root(struct btrfs_root *root); static void btrfs_destroy_ordered_extents(struct btrfs_root *root); static int btrfs_destroy_delayed_refs(struct btrfs_transaction *trans, struct btrfs_fs_info *fs_info); @@ -1504,7 +1503,7 @@ int btrfs_init_fs_root(struct btrfs_root *root) return 0; fail: - /* the caller is responsible to call free_fs_root */ + /* The caller is responsible to call btrfs_free_fs_root */ return ret; } @@ -1609,14 +1608,14 @@ again: ret = btrfs_insert_fs_root(fs_info, root); if (ret) { if (ret == -EEXIST) { - free_fs_root(root); + btrfs_free_fs_root(root); goto again; } goto fail; } return root; fail: - free_fs_root(root); + btrfs_free_fs_root(root); return ERR_PTR(ret); } @@ -3831,10 +3830,10 @@ void btrfs_drop_and_free_fs_root(struct btrfs_fs_info *fs_info, __btrfs_remove_free_space_cache(root->free_ino_pinned); if (root->free_ino_ctl) __btrfs_remove_free_space_cache(root->free_ino_ctl); - free_fs_root(root); + btrfs_free_fs_root(root); } -static void free_fs_root(struct btrfs_root *root) +void btrfs_free_fs_root(struct btrfs_root *root) { iput(root->ino_cache_inode); WARN_ON(!RB_EMPTY_ROOT(&root->inode_tree)); @@ -3849,11 +3848,6 @@ static void free_fs_root(struct btrfs_root *root) btrfs_put_fs_root(root); } -void btrfs_free_fs_root(struct btrfs_root *root) -{ - free_fs_root(root); -} - int btrfs_cleanup_fs_roots(struct btrfs_fs_info *fs_info) { u64 root_objectid = 0; -- cgit v1.2.3 From 4559b0a71749c442d34f7cfb9e72c9e58db83948 Mon Sep 17 00:00:00 2001 From: Josef Bacik Date: Thu, 19 Jul 2018 10:49:51 -0400 Subject: btrfs: don't leak ret from do_chunk_alloc If we're trying to make a data reservation and we have to allocate a data chunk we could leak ret == 1, as do_chunk_alloc() will return 1 if it allocated a chunk. Since the end of the function is the success path just return 0. CC: stable@vger.kernel.org # 4.4+ Signed-off-by: Josef Bacik Reviewed-by: Nikolay Borisov Signed-off-by: David Sterba --- fs/btrfs/extent-tree.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) (limited to 'fs') diff --git a/fs/btrfs/extent-tree.c b/fs/btrfs/extent-tree.c index 16b916a33e56..2eb2d7ac0ba4 100644 --- a/fs/btrfs/extent-tree.c +++ b/fs/btrfs/extent-tree.c @@ -4226,7 +4226,7 @@ commit_trans: data_sinfo->flags, bytes, 1); spin_unlock(&data_sinfo->lock); - return ret; + return 0; } int btrfs_check_data_free_space(struct inode *inode, -- cgit v1.2.3 From 0d836392cadd5535f4184d46d901a82eb276ed62 Mon Sep 17 00:00:00 2001 From: Filipe Manana Date: Fri, 20 Jul 2018 10:59:06 +0100 Subject: Btrfs: fix mount failure after fsync due to hard link recreation If we end up with logging an inode reference item which has the same name but different index from the one we have persisted, we end up failing when replaying the log with an errno value of -EEXIST. The error comes from btrfs_add_link(), which is called from add_inode_ref(), when we are replaying an inode reference item. Example scenario where this happens: $ mkfs.btrfs -f /dev/sdb $ mount /dev/sdb /mnt $ touch /mnt/foo $ ln /mnt/foo /mnt/bar $ sync # Rename the first hard link (foo) to a new name and rename the second # hard link (bar) to the old name of the first hard link (foo). $ mv /mnt/foo /mnt/qwerty $ mv /mnt/bar /mnt/foo # Create a new file, in the same parent directory, with the old name of # the second hard link (bar) and fsync this new file. # We do this instead of calling fsync on foo/qwerty because if we did # that the fsync resulted in a full transaction commit, not triggering # the problem. $ touch /mnt/bar $ xfs_io -c "fsync" /mnt/bar $ mount /dev/sdb /mnt mount: mount /dev/sdb on /mnt failed: File exists So fix this by checking if a conflicting inode reference exists (same name, same parent but different index), removing it (and the associated dir index entries from the parent inode) if it exists, before attempting to add the new reference. A test case for fstests follows soon. CC: stable@vger.kernel.org # 4.4+ Signed-off-by: Filipe Manana Signed-off-by: David Sterba --- fs/btrfs/tree-log.c | 66 +++++++++++++++++++++++++++++++++++++++++++++++++++++ 1 file changed, 66 insertions(+) (limited to 'fs') diff --git a/fs/btrfs/tree-log.c b/fs/btrfs/tree-log.c index 10f6a4223897..033aeebbe9de 100644 --- a/fs/btrfs/tree-log.c +++ b/fs/btrfs/tree-log.c @@ -1290,6 +1290,46 @@ again: return ret; } +static int btrfs_inode_ref_exists(struct inode *inode, struct inode *dir, + const u8 ref_type, const char *name, + const int namelen) +{ + struct btrfs_key key; + struct btrfs_path *path; + const u64 parent_id = btrfs_ino(BTRFS_I(dir)); + int ret; + + path = btrfs_alloc_path(); + if (!path) + return -ENOMEM; + + key.objectid = btrfs_ino(BTRFS_I(inode)); + key.type = ref_type; + if (key.type == BTRFS_INODE_REF_KEY) + key.offset = parent_id; + else + key.offset = btrfs_extref_hash(parent_id, name, namelen); + + ret = btrfs_search_slot(NULL, BTRFS_I(inode)->root, &key, path, 0, 0); + if (ret < 0) + goto out; + if (ret > 0) { + ret = 0; + goto out; + } + if (key.type == BTRFS_INODE_EXTREF_KEY) + ret = btrfs_find_name_in_ext_backref(path->nodes[0], + path->slots[0], parent_id, + name, namelen, NULL); + else + ret = btrfs_find_name_in_backref(path->nodes[0], path->slots[0], + name, namelen, NULL); + +out: + btrfs_free_path(path); + return ret; +} + /* * replay one inode back reference item found in the log tree. * eb, slot and key refer to the buffer and key found in the log tree. @@ -1399,6 +1439,32 @@ static noinline int add_inode_ref(struct btrfs_trans_handle *trans, } } + /* + * If a reference item already exists for this inode + * with the same parent and name, but different index, + * drop it and the corresponding directory index entries + * from the parent before adding the new reference item + * and dir index entries, otherwise we would fail with + * -EEXIST returned from btrfs_add_link() below. + */ + ret = btrfs_inode_ref_exists(inode, dir, key->type, + name, namelen); + if (ret > 0) { + ret = btrfs_unlink_inode(trans, root, + BTRFS_I(dir), + BTRFS_I(inode), + name, namelen); + /* + * If we dropped the link count to 0, bump it so + * that later the iput() on the inode will not + * free it. We will fixup the link count later. + */ + if (!ret && inode->i_nlink == 0) + inc_nlink(inode); + } + if (ret < 0) + goto out; + /* insert our name */ ret = btrfs_add_link(trans, BTRFS_I(dir), BTRFS_I(inode), -- cgit v1.2.3 From 46b2f4590aab71d31088a265c86026b1e96c9de4 Mon Sep 17 00:00:00 2001 From: Filipe Manana Date: Tue, 24 Jul 2018 11:54:04 +0100 Subject: Btrfs: fix send failure when root has deleted files still open The more common use case of send involves creating a RO snapshot and then use it for a send operation. In this case it's not possible to have inodes in the snapshot that have a link count of zero (inode with an orphan item) since during snapshot creation we do the orphan cleanup. However, other less common use cases for send can end up seeing inodes with a link count of zero and in this case the send operation fails with a ENOENT error because any attempt to generate a path for the inode, with the purpose of creating it or updating it at the receiver, fails since there are no inode reference items. One use case it to use a regular subvolume for a send operation after turning it to RO mode or turning a RW snapshot into RO mode and then using it for a send operation. In both cases, if a file gets all its hard links deleted while there is an open file descriptor before turning the subvolume/snapshot into RO mode, the send operation will encounter an inode with a link count of zero and then fail with errno ENOENT. Example using a full send with a subvolume: $ mkfs.btrfs -f /dev/sdb $ mount /dev/sdb /mnt $ btrfs subvolume create /mnt/sv1 $ touch /mnt/sv1/foo $ touch /mnt/sv1/bar # keep an open file descriptor on file bar $ exec 73> /mnt/sv1/bar $ btrfs subvolume snapshot -r /mnt/sv1 /mnt/snap2 # Turn the second snapshot to RW mode and delete file foo while # holding an open file descriptor on it. $ btrfs property set /mnt/snap2 ro false $ exec 73 Signed-off-by: Filipe Manana Reviewed-by: David Sterba Signed-off-by: David Sterba --- fs/btrfs/send.c | 137 ++++++++++++++++++++++++++++++++++++++++++++++++++++---- 1 file changed, 129 insertions(+), 8 deletions(-) (limited to 'fs') diff --git a/fs/btrfs/send.c b/fs/btrfs/send.c index 42e04cd3cd95..551294a6c9e2 100644 --- a/fs/btrfs/send.c +++ b/fs/btrfs/send.c @@ -100,6 +100,7 @@ struct send_ctx { u64 cur_inode_rdev; u64 cur_inode_last_extent; u64 cur_inode_next_write_offset; + bool ignore_cur_inode; u64 send_progress; @@ -5796,6 +5797,9 @@ static int finish_inode_if_needed(struct send_ctx *sctx, int at_end) int pending_move = 0; int refs_processed = 0; + if (sctx->ignore_cur_inode) + return 0; + ret = process_recorded_refs_if_needed(sctx, at_end, &pending_move, &refs_processed); if (ret < 0) @@ -5914,6 +5918,93 @@ out: return ret; } +struct parent_paths_ctx { + struct list_head *refs; + struct send_ctx *sctx; +}; + +static int record_parent_ref(int num, u64 dir, int index, struct fs_path *name, + void *ctx) +{ + struct parent_paths_ctx *ppctx = ctx; + + return record_ref(ppctx->sctx->parent_root, dir, name, ppctx->sctx, + ppctx->refs); +} + +/* + * Issue unlink operations for all paths of the current inode found in the + * parent snapshot. + */ +static int btrfs_unlink_all_paths(struct send_ctx *sctx) +{ + LIST_HEAD(deleted_refs); + struct btrfs_path *path; + struct btrfs_key key; + struct parent_paths_ctx ctx; + int ret; + + path = alloc_path_for_send(); + if (!path) + return -ENOMEM; + + key.objectid = sctx->cur_ino; + key.type = BTRFS_INODE_REF_KEY; + key.offset = 0; + ret = btrfs_search_slot(NULL, sctx->parent_root, &key, path, 0, 0); + if (ret < 0) + goto out; + + ctx.refs = &deleted_refs; + ctx.sctx = sctx; + + while (true) { + struct extent_buffer *eb = path->nodes[0]; + int slot = path->slots[0]; + + if (slot >= btrfs_header_nritems(eb)) { + ret = btrfs_next_leaf(sctx->parent_root, path); + if (ret < 0) + goto out; + else if (ret > 0) + break; + continue; + } + + btrfs_item_key_to_cpu(eb, &key, slot); + if (key.objectid != sctx->cur_ino) + break; + if (key.type != BTRFS_INODE_REF_KEY && + key.type != BTRFS_INODE_EXTREF_KEY) + break; + + ret = iterate_inode_ref(sctx->parent_root, path, &key, 1, + record_parent_ref, &ctx); + if (ret < 0) + goto out; + + path->slots[0]++; + } + + while (!list_empty(&deleted_refs)) { + struct recorded_ref *ref; + + ref = list_first_entry(&deleted_refs, struct recorded_ref, list); + ret = send_unlink(sctx, ref->full_path); + if (ret < 0) + goto out; + fs_path_free(ref->full_path); + list_del(&ref->list); + kfree(ref); + } + ret = 0; +out: + btrfs_free_path(path); + if (ret) + __free_recorded_refs(&deleted_refs); + return ret; +} + static int changed_inode(struct send_ctx *sctx, enum btrfs_compare_tree_result result) { @@ -5928,6 +6019,7 @@ static int changed_inode(struct send_ctx *sctx, sctx->cur_inode_new_gen = 0; sctx->cur_inode_last_extent = (u64)-1; sctx->cur_inode_next_write_offset = 0; + sctx->ignore_cur_inode = false; /* * Set send_progress to current inode. This will tell all get_cur_xxx @@ -5968,6 +6060,33 @@ static int changed_inode(struct send_ctx *sctx, sctx->cur_inode_new_gen = 1; } + /* + * Normally we do not find inodes with a link count of zero (orphans) + * because the most common case is to create a snapshot and use it + * for a send operation. However other less common use cases involve + * using a subvolume and send it after turning it to RO mode just + * after deleting all hard links of a file while holding an open + * file descriptor against it or turning a RO snapshot into RW mode, + * keep an open file descriptor against a file, delete it and then + * turn the snapshot back to RO mode before using it for a send + * operation. So if we find such cases, ignore the inode and all its + * items completely if it's a new inode, or if it's a changed inode + * make sure all its previous paths (from the parent snapshot) are all + * unlinked and all other the inode items are ignored. + */ + if (result == BTRFS_COMPARE_TREE_NEW || + result == BTRFS_COMPARE_TREE_CHANGED) { + u32 nlinks; + + nlinks = btrfs_inode_nlink(sctx->left_path->nodes[0], left_ii); + if (nlinks == 0) { + sctx->ignore_cur_inode = true; + if (result == BTRFS_COMPARE_TREE_CHANGED) + ret = btrfs_unlink_all_paths(sctx); + goto out; + } + } + if (result == BTRFS_COMPARE_TREE_NEW) { sctx->cur_inode_gen = left_gen; sctx->cur_inode_new = 1; @@ -6306,15 +6425,17 @@ static int changed_cb(struct btrfs_path *left_path, key->objectid == BTRFS_FREE_SPACE_OBJECTID) goto out; - if (key->type == BTRFS_INODE_ITEM_KEY) + if (key->type == BTRFS_INODE_ITEM_KEY) { ret = changed_inode(sctx, result); - else if (key->type == BTRFS_INODE_REF_KEY || - key->type == BTRFS_INODE_EXTREF_KEY) - ret = changed_ref(sctx, result); - else if (key->type == BTRFS_XATTR_ITEM_KEY) - ret = changed_xattr(sctx, result); - else if (key->type == BTRFS_EXTENT_DATA_KEY) - ret = changed_extent(sctx, result); + } else if (!sctx->ignore_cur_inode) { + if (key->type == BTRFS_INODE_REF_KEY || + key->type == BTRFS_INODE_EXTREF_KEY) + ret = changed_ref(sctx, result); + else if (key->type == BTRFS_XATTR_ITEM_KEY) + ret = changed_xattr(sctx, result); + else if (key->type == BTRFS_EXTENT_DATA_KEY) + ret = changed_extent(sctx, result); + } out: return ret; -- cgit v1.2.3 From b5851021f1ea0e099543fa125744368de7e9b865 Mon Sep 17 00:00:00 2001 From: David Sterba Date: Tue, 24 Jul 2018 17:19:48 +0200 Subject: btrfs: extent-tree: remove unused member walk_control::for_reloc Leftover after fix e339a6b097c5 ("Btrfs: __btrfs_mod_ref should always use no_quota"), that removed it from the function calls but not the structure. Signed-off-by: David Sterba --- fs/btrfs/extent-tree.c | 3 --- 1 file changed, 3 deletions(-) (limited to 'fs') diff --git a/fs/btrfs/extent-tree.c b/fs/btrfs/extent-tree.c index 2eb2d7ac0ba4..fcaf598f4222 100644 --- a/fs/btrfs/extent-tree.c +++ b/fs/btrfs/extent-tree.c @@ -8330,7 +8330,6 @@ struct walk_control { int keep_locks; int reada_slot; int reada_count; - int for_reloc; }; #define DROP_REFERENCE 1 @@ -8967,7 +8966,6 @@ int btrfs_drop_snapshot(struct btrfs_root *root, wc->stage = DROP_REFERENCE; wc->update_ref = update_ref; wc->keep_locks = 0; - wc->for_reloc = for_reloc; wc->reada_count = BTRFS_NODEPTRS_PER_BLOCK(fs_info); while (1) { @@ -9133,7 +9131,6 @@ int btrfs_drop_subtree(struct btrfs_trans_handle *trans, wc->stage = DROP_REFERENCE; wc->update_ref = 0; wc->keep_locks = 1; - wc->for_reloc = 1; wc->reada_count = BTRFS_NODEPTRS_PER_BLOCK(fs_info); while (1) { -- cgit v1.2.3 From 4465c8b4229de50f17b6780677ce068b3582a55d Mon Sep 17 00:00:00 2001 From: Lu Fengqi Date: Wed, 1 Aug 2018 11:32:25 +0800 Subject: btrfs: Remove fs_info from btrfs_insert_delayed_dir_index It can be referenced from the passed transaction handle. Signed-off-by: Lu Fengqi Signed-off-by: David Sterba --- fs/btrfs/delayed-inode.c | 4 +--- fs/btrfs/delayed-inode.h | 1 - fs/btrfs/dir-item.c | 4 ++-- 3 files changed, 3 insertions(+), 6 deletions(-) (limited to 'fs') diff --git a/fs/btrfs/delayed-inode.c b/fs/btrfs/delayed-inode.c index 596d2af0c8aa..5d103eda1874 100644 --- a/fs/btrfs/delayed-inode.c +++ b/fs/btrfs/delayed-inode.c @@ -1418,7 +1418,6 @@ void btrfs_balance_delayed_items(struct btrfs_fs_info *fs_info) /* Will return 0 or -ENOMEM */ int btrfs_insert_delayed_dir_index(struct btrfs_trans_handle *trans, - struct btrfs_fs_info *fs_info, const char *name, int name_len, struct btrfs_inode *dir, struct btrfs_disk_key *disk_key, u8 type, @@ -1458,11 +1457,10 @@ int btrfs_insert_delayed_dir_index(struct btrfs_trans_handle *trans, */ BUG_ON(ret); - mutex_lock(&delayed_node->mutex); ret = __btrfs_add_delayed_insertion_item(delayed_node, delayed_item); if (unlikely(ret)) { - btrfs_err(fs_info, + btrfs_err(trans->fs_info, "err add delayed dir index item(name: %.*s) into the insertion tree of the delayed node(root id: %llu, inode id: %llu, errno: %d)", name_len, name, delayed_node->root->objectid, delayed_node->inode_id, ret); diff --git a/fs/btrfs/delayed-inode.h b/fs/btrfs/delayed-inode.h index ca7a97f3ab6b..44558ededcf5 100644 --- a/fs/btrfs/delayed-inode.h +++ b/fs/btrfs/delayed-inode.h @@ -86,7 +86,6 @@ static inline void btrfs_init_delayed_root( } int btrfs_insert_delayed_dir_index(struct btrfs_trans_handle *trans, - struct btrfs_fs_info *fs_info, const char *name, int name_len, struct btrfs_inode *dir, struct btrfs_disk_key *disk_key, u8 type, diff --git a/fs/btrfs/dir-item.c b/fs/btrfs/dir-item.c index 39e9766d1cbd..a678b07fcf01 100644 --- a/fs/btrfs/dir-item.c +++ b/fs/btrfs/dir-item.c @@ -160,8 +160,8 @@ second_insert: } btrfs_release_path(path); - ret2 = btrfs_insert_delayed_dir_index(trans, root->fs_info, name, - name_len, dir, &disk_key, type, index); + ret2 = btrfs_insert_delayed_dir_index(trans, name, name_len, dir, + &disk_key, type, index); out_free: btrfs_free_path(path); if (ret) -- cgit v1.2.3 From 9add29457ac124e846cde4b875c632edaa722c08 Mon Sep 17 00:00:00 2001 From: Lu Fengqi Date: Wed, 1 Aug 2018 11:32:26 +0800 Subject: btrfs: Remove fs_info from btrfs_delete_delayed_dir_index It can be referenced from the passed transaction handle. Signed-off-by: Lu Fengqi Signed-off-by: David Sterba --- fs/btrfs/delayed-inode.c | 6 +++--- fs/btrfs/delayed-inode.h | 1 - fs/btrfs/inode.c | 4 ++-- 3 files changed, 5 insertions(+), 6 deletions(-) (limited to 'fs') diff --git a/fs/btrfs/delayed-inode.c b/fs/btrfs/delayed-inode.c index 5d103eda1874..f51b509f2d9b 100644 --- a/fs/btrfs/delayed-inode.c +++ b/fs/btrfs/delayed-inode.c @@ -1493,7 +1493,6 @@ static int btrfs_delete_delayed_insertion_item(struct btrfs_fs_info *fs_info, } int btrfs_delete_delayed_dir_index(struct btrfs_trans_handle *trans, - struct btrfs_fs_info *fs_info, struct btrfs_inode *dir, u64 index) { struct btrfs_delayed_node *node; @@ -1509,7 +1508,8 @@ int btrfs_delete_delayed_dir_index(struct btrfs_trans_handle *trans, item_key.type = BTRFS_DIR_INDEX_KEY; item_key.offset = index; - ret = btrfs_delete_delayed_insertion_item(fs_info, node, &item_key); + ret = btrfs_delete_delayed_insertion_item(trans->fs_info, node, + &item_key); if (!ret) goto end; @@ -1531,7 +1531,7 @@ int btrfs_delete_delayed_dir_index(struct btrfs_trans_handle *trans, mutex_lock(&node->mutex); ret = __btrfs_add_delayed_deletion_item(node, item); if (unlikely(ret)) { - btrfs_err(fs_info, + btrfs_err(trans->fs_info, "err add delayed dir index item(index: %llu) into the deletion tree of the delayed node(root id: %llu, inode id: %llu, errno: %d)", index, node->root->objectid, node->inode_id, ret); BUG(); diff --git a/fs/btrfs/delayed-inode.h b/fs/btrfs/delayed-inode.h index 44558ededcf5..33536cd681d4 100644 --- a/fs/btrfs/delayed-inode.h +++ b/fs/btrfs/delayed-inode.h @@ -92,7 +92,6 @@ int btrfs_insert_delayed_dir_index(struct btrfs_trans_handle *trans, u64 index); int btrfs_delete_delayed_dir_index(struct btrfs_trans_handle *trans, - struct btrfs_fs_info *fs_info, struct btrfs_inode *dir, u64 index); int btrfs_inode_delayed_dir_index_count(struct btrfs_inode *inode); diff --git a/fs/btrfs/inode.c b/fs/btrfs/inode.c index 472457795486..59b3ea32b6de 100644 --- a/fs/btrfs/inode.c +++ b/fs/btrfs/inode.c @@ -3978,7 +3978,7 @@ static int __btrfs_unlink_inode(struct btrfs_trans_handle *trans, goto err; } skip_backref: - ret = btrfs_delete_delayed_dir_index(trans, fs_info, dir, index); + ret = btrfs_delete_delayed_dir_index(trans, dir, index); if (ret) { btrfs_abort_transaction(trans, ret); goto err; @@ -4144,7 +4144,7 @@ static int btrfs_unlink_subvol(struct btrfs_trans_handle *trans, } btrfs_release_path(path); - ret = btrfs_delete_delayed_dir_index(trans, fs_info, BTRFS_I(dir), index); + ret = btrfs_delete_delayed_dir_index(trans, BTRFS_I(dir), index); if (ret) { btrfs_abort_transaction(trans, ret); goto out; -- cgit v1.2.3 From ab9ce7d42bf66f0750a4ca4a228a2db238376afb Mon Sep 17 00:00:00 2001 From: Lu Fengqi Date: Wed, 1 Aug 2018 11:32:27 +0800 Subject: btrfs: Remove fs_info from btrfs_del_root It can be referenced from the passed transaction handle. Signed-off-by: Lu Fengqi Signed-off-by: David Sterba --- fs/btrfs/ctree.h | 2 +- fs/btrfs/extent-tree.c | 2 +- fs/btrfs/free-space-tree.c | 2 +- fs/btrfs/qgroup.c | 2 +- fs/btrfs/root-tree.c | 4 ++-- 5 files changed, 6 insertions(+), 6 deletions(-) (limited to 'fs') diff --git a/fs/btrfs/ctree.h b/fs/btrfs/ctree.h index 2e32584c635f..9ef47a171e2f 100644 --- a/fs/btrfs/ctree.h +++ b/fs/btrfs/ctree.h @@ -2993,7 +2993,7 @@ int btrfs_del_root_ref(struct btrfs_trans_handle *trans, u64 root_id, u64 ref_id, u64 dirid, u64 *sequence, const char *name, int name_len); int btrfs_del_root(struct btrfs_trans_handle *trans, - struct btrfs_fs_info *fs_info, const struct btrfs_key *key); + const struct btrfs_key *key); int btrfs_insert_root(struct btrfs_trans_handle *trans, struct btrfs_root *root, const struct btrfs_key *key, struct btrfs_root_item *item); diff --git a/fs/btrfs/extent-tree.c b/fs/btrfs/extent-tree.c index fcaf598f4222..042dd4186fb8 100644 --- a/fs/btrfs/extent-tree.c +++ b/fs/btrfs/extent-tree.c @@ -9028,7 +9028,7 @@ int btrfs_drop_snapshot(struct btrfs_root *root, if (err) goto out_end_trans; - ret = btrfs_del_root(trans, fs_info, &root->root_key); + ret = btrfs_del_root(trans, &root->root_key); if (ret) { btrfs_abort_transaction(trans, ret); err = ret; diff --git a/fs/btrfs/free-space-tree.c b/fs/btrfs/free-space-tree.c index b5950aacd697..d6736595ec57 100644 --- a/fs/btrfs/free-space-tree.c +++ b/fs/btrfs/free-space-tree.c @@ -1236,7 +1236,7 @@ int btrfs_clear_free_space_tree(struct btrfs_fs_info *fs_info) if (ret) goto abort; - ret = btrfs_del_root(trans, fs_info, &free_space_root->root_key); + ret = btrfs_del_root(trans, &free_space_root->root_key); if (ret) goto abort; diff --git a/fs/btrfs/qgroup.c b/fs/btrfs/qgroup.c index e11ed7b3f32a..4353bb69bb86 100644 --- a/fs/btrfs/qgroup.c +++ b/fs/btrfs/qgroup.c @@ -1088,7 +1088,7 @@ int btrfs_quota_disable(struct btrfs_fs_info *fs_info) goto end_trans; } - ret = btrfs_del_root(trans, fs_info, "a_root->root_key); + ret = btrfs_del_root(trans, "a_root->root_key); if (ret) { btrfs_abort_transaction(trans, ret); goto end_trans; diff --git a/fs/btrfs/root-tree.c b/fs/btrfs/root-tree.c index c451285976ac..f7c14c454f91 100644 --- a/fs/btrfs/root-tree.c +++ b/fs/btrfs/root-tree.c @@ -320,9 +320,9 @@ int btrfs_find_orphan_roots(struct btrfs_fs_info *fs_info) /* drop the root item for 'key' from the tree root */ int btrfs_del_root(struct btrfs_trans_handle *trans, - struct btrfs_fs_info *fs_info, const struct btrfs_key *key) + const struct btrfs_key *key) { - struct btrfs_root *root = fs_info->tree_root; + struct btrfs_root *root = trans->fs_info->tree_root; struct btrfs_path *path; int ret; -- cgit v1.2.3 From 3ee1c5530e649182e602eb2f81193289c4d2e655 Mon Sep 17 00:00:00 2001 From: Lu Fengqi Date: Wed, 1 Aug 2018 11:32:28 +0800 Subject: btrfs: Remove fs_info from btrfs_del_root_ref It can be referenced from the passed transaction handle. Signed-off-by: Lu Fengqi Signed-off-by: David Sterba --- fs/btrfs/ctree.h | 7 +++---- fs/btrfs/inode.c | 8 +++----- fs/btrfs/root-tree.c | 9 ++++----- 3 files changed, 10 insertions(+), 14 deletions(-) (limited to 'fs') diff --git a/fs/btrfs/ctree.h b/fs/btrfs/ctree.h index 9ef47a171e2f..3677082ddf4c 100644 --- a/fs/btrfs/ctree.h +++ b/fs/btrfs/ctree.h @@ -2988,10 +2988,9 @@ int btrfs_add_root_ref(struct btrfs_trans_handle *trans, struct btrfs_fs_info *fs_info, u64 root_id, u64 ref_id, u64 dirid, u64 sequence, const char *name, int name_len); -int btrfs_del_root_ref(struct btrfs_trans_handle *trans, - struct btrfs_fs_info *fs_info, - u64 root_id, u64 ref_id, u64 dirid, u64 *sequence, - const char *name, int name_len); +int btrfs_del_root_ref(struct btrfs_trans_handle *trans, u64 root_id, + u64 ref_id, u64 dirid, u64 *sequence, const char *name, + int name_len); int btrfs_del_root(struct btrfs_trans_handle *trans, const struct btrfs_key *key); int btrfs_insert_root(struct btrfs_trans_handle *trans, struct btrfs_root *root, diff --git a/fs/btrfs/inode.c b/fs/btrfs/inode.c index 59b3ea32b6de..7bf4a8d07e1e 100644 --- a/fs/btrfs/inode.c +++ b/fs/btrfs/inode.c @@ -4085,7 +4085,6 @@ static int btrfs_unlink_subvol(struct btrfs_trans_handle *trans, struct inode *dir, u64 objectid, const char *name, int name_len) { - struct btrfs_fs_info *fs_info = root->fs_info; struct btrfs_path *path; struct extent_buffer *leaf; struct btrfs_dir_item *di; @@ -4118,9 +4117,8 @@ static int btrfs_unlink_subvol(struct btrfs_trans_handle *trans, } btrfs_release_path(path); - ret = btrfs_del_root_ref(trans, fs_info, objectid, - root->root_key.objectid, dir_ino, - &index, name, name_len); + ret = btrfs_del_root_ref(trans, objectid, root->root_key.objectid, + dir_ino, &index, name, name_len); if (ret < 0) { if (ret != -ENOENT) { btrfs_abort_transaction(trans, ret); @@ -6439,7 +6437,7 @@ fail_dir_item: if (unlikely(ino == BTRFS_FIRST_FREE_OBJECTID)) { u64 local_index; int err; - err = btrfs_del_root_ref(trans, fs_info, key.objectid, + err = btrfs_del_root_ref(trans, key.objectid, root->root_key.objectid, parent_ino, &local_index, name, name_len); diff --git a/fs/btrfs/root-tree.c b/fs/btrfs/root-tree.c index f7c14c454f91..52fa133ab53c 100644 --- a/fs/btrfs/root-tree.c +++ b/fs/btrfs/root-tree.c @@ -341,13 +341,12 @@ out: return ret; } -int btrfs_del_root_ref(struct btrfs_trans_handle *trans, - struct btrfs_fs_info *fs_info, - u64 root_id, u64 ref_id, u64 dirid, u64 *sequence, - const char *name, int name_len) +int btrfs_del_root_ref(struct btrfs_trans_handle *trans, u64 root_id, + u64 ref_id, u64 dirid, u64 *sequence, const char *name, + int name_len) { - struct btrfs_root *tree_root = fs_info->tree_root; + struct btrfs_root *tree_root = trans->fs_info->tree_root; struct btrfs_path *path; struct btrfs_root_ref *ref; struct extent_buffer *leaf; -- cgit v1.2.3 From 6025c19fb208e93b99eafc304e7f16160e49fc88 Mon Sep 17 00:00:00 2001 From: Lu Fengqi Date: Wed, 1 Aug 2018 11:32:29 +0800 Subject: btrfs: Remove fs_info from btrfs_add_root_ref It can be referenced from the passed transaction handle. Signed-off-by: Lu Fengqi Signed-off-by: David Sterba --- fs/btrfs/ctree.h | 7 +++---- fs/btrfs/inode.c | 3 +-- fs/btrfs/ioctl.c | 3 +-- fs/btrfs/root-tree.c | 9 ++++----- fs/btrfs/transaction.c | 2 +- 5 files changed, 10 insertions(+), 14 deletions(-) (limited to 'fs') diff --git a/fs/btrfs/ctree.h b/fs/btrfs/ctree.h index 3677082ddf4c..c275ea258f9a 100644 --- a/fs/btrfs/ctree.h +++ b/fs/btrfs/ctree.h @@ -2984,10 +2984,9 @@ void btrfs_put_tree_mod_seq(struct btrfs_fs_info *fs_info, int btrfs_old_root_level(struct btrfs_root *root, u64 time_seq); /* root-item.c */ -int btrfs_add_root_ref(struct btrfs_trans_handle *trans, - struct btrfs_fs_info *fs_info, - u64 root_id, u64 ref_id, u64 dirid, u64 sequence, - const char *name, int name_len); +int btrfs_add_root_ref(struct btrfs_trans_handle *trans, u64 root_id, + u64 ref_id, u64 dirid, u64 sequence, const char *name, + int name_len); int btrfs_del_root_ref(struct btrfs_trans_handle *trans, u64 root_id, u64 ref_id, u64 dirid, u64 *sequence, const char *name, int name_len); diff --git a/fs/btrfs/inode.c b/fs/btrfs/inode.c index 7bf4a8d07e1e..407d068d4208 100644 --- a/fs/btrfs/inode.c +++ b/fs/btrfs/inode.c @@ -6385,7 +6385,6 @@ int btrfs_add_link(struct btrfs_trans_handle *trans, struct btrfs_inode *parent_inode, struct btrfs_inode *inode, const char *name, int name_len, int add_backref, u64 index) { - struct btrfs_fs_info *fs_info = trans->fs_info; int ret = 0; struct btrfs_key key; struct btrfs_root *root = parent_inode->root; @@ -6401,7 +6400,7 @@ int btrfs_add_link(struct btrfs_trans_handle *trans, } if (unlikely(ino == BTRFS_FIRST_FREE_OBJECTID)) { - ret = btrfs_add_root_ref(trans, fs_info, key.objectid, + ret = btrfs_add_root_ref(trans, key.objectid, root->root_key.objectid, parent_ino, index, name, name_len); } else if (add_backref) { diff --git a/fs/btrfs/ioctl.c b/fs/btrfs/ioctl.c index 80fe3c654612..6eaadddaca9f 100644 --- a/fs/btrfs/ioctl.c +++ b/fs/btrfs/ioctl.c @@ -698,8 +698,7 @@ static noinline int create_subvol(struct inode *dir, ret = btrfs_update_inode(trans, root, dir); BUG_ON(ret); - ret = btrfs_add_root_ref(trans, fs_info, - objectid, root->root_key.objectid, + ret = btrfs_add_root_ref(trans, objectid, root->root_key.objectid, btrfs_ino(BTRFS_I(dir)), index, name, namelen); BUG_ON(ret); diff --git a/fs/btrfs/root-tree.c b/fs/btrfs/root-tree.c index 52fa133ab53c..65bda0682928 100644 --- a/fs/btrfs/root-tree.c +++ b/fs/btrfs/root-tree.c @@ -412,12 +412,11 @@ out: * * Will return 0, -ENOMEM, or anything from the CoW path */ -int btrfs_add_root_ref(struct btrfs_trans_handle *trans, - struct btrfs_fs_info *fs_info, - u64 root_id, u64 ref_id, u64 dirid, u64 sequence, - const char *name, int name_len) +int btrfs_add_root_ref(struct btrfs_trans_handle *trans, u64 root_id, + u64 ref_id, u64 dirid, u64 sequence, const char *name, + int name_len) { - struct btrfs_root *tree_root = fs_info->tree_root; + struct btrfs_root *tree_root = trans->fs_info->tree_root; struct btrfs_key key; int ret; struct btrfs_path *path; diff --git a/fs/btrfs/transaction.c b/fs/btrfs/transaction.c index aec208cbff00..001ed1bc2aa8 100644 --- a/fs/btrfs/transaction.c +++ b/fs/btrfs/transaction.c @@ -1573,7 +1573,7 @@ static noinline int create_pending_snapshot(struct btrfs_trans_handle *trans, /* * insert root back/forward references */ - ret = btrfs_add_root_ref(trans, fs_info, objectid, + ret = btrfs_add_root_ref(trans, objectid, parent_root->root_key.objectid, btrfs_ino(BTRFS_I(parent_inode)), index, dentry->d_name.name, dentry->d_name.len); -- cgit v1.2.3 From 401b3b19d592391b718b7a17295ae34eace973dd Mon Sep 17 00:00:00 2001 From: Lu Fengqi Date: Wed, 1 Aug 2018 11:32:30 +0800 Subject: btrfs: Remove root parameter from btrfs_unlink_subvol All callers pass the root tree of dir, we can push that down to the function itself. Signed-off-by: Lu Fengqi Reviewed-by: David Sterba Signed-off-by: David Sterba --- fs/btrfs/inode.c | 25 ++++++++++--------------- 1 file changed, 10 insertions(+), 15 deletions(-) (limited to 'fs') diff --git a/fs/btrfs/inode.c b/fs/btrfs/inode.c index 407d068d4208..b8c131b82978 100644 --- a/fs/btrfs/inode.c +++ b/fs/btrfs/inode.c @@ -4081,10 +4081,10 @@ out: } static int btrfs_unlink_subvol(struct btrfs_trans_handle *trans, - struct btrfs_root *root, - struct inode *dir, u64 objectid, - const char *name, int name_len) + struct inode *dir, u64 objectid, + const char *name, int name_len) { + struct btrfs_root *root = BTRFS_I(dir)->root; struct btrfs_path *path; struct extent_buffer *leaf; struct btrfs_dir_item *di; @@ -4335,10 +4335,8 @@ int btrfs_delete_subvolume(struct inode *dir, struct dentry *dentry) btrfs_record_snapshot_destroy(trans, BTRFS_I(dir)); - ret = btrfs_unlink_subvol(trans, root, dir, - dest->root_key.objectid, - dentry->d_name.name, - dentry->d_name.len); + ret = btrfs_unlink_subvol(trans, dir, dest->root_key.objectid, + dentry->d_name.name, dentry->d_name.len); if (ret) { err = ret; btrfs_abort_transaction(trans, ret); @@ -4433,7 +4431,7 @@ static int btrfs_rmdir(struct inode *dir, struct dentry *dentry) return PTR_ERR(trans); if (unlikely(btrfs_ino(BTRFS_I(inode)) == BTRFS_EMPTY_SUBVOL_DIR_OBJECTID)) { - err = btrfs_unlink_subvol(trans, root, dir, + err = btrfs_unlink_subvol(trans, dir, BTRFS_I(inode)->location.objectid, dentry->d_name.name, dentry->d_name.len); @@ -9505,8 +9503,7 @@ static int btrfs_rename_exchange(struct inode *old_dir, /* src is a subvolume */ if (old_ino == BTRFS_FIRST_FREE_OBJECTID) { root_objectid = BTRFS_I(old_inode)->root->root_key.objectid; - ret = btrfs_unlink_subvol(trans, root, old_dir, - root_objectid, + ret = btrfs_unlink_subvol(trans, old_dir, root_objectid, old_dentry->d_name.name, old_dentry->d_name.len); } else { /* src is an inode */ @@ -9525,8 +9522,7 @@ static int btrfs_rename_exchange(struct inode *old_dir, /* dest is a subvolume */ if (new_ino == BTRFS_FIRST_FREE_OBJECTID) { root_objectid = BTRFS_I(new_inode)->root->root_key.objectid; - ret = btrfs_unlink_subvol(trans, dest, new_dir, - root_objectid, + ret = btrfs_unlink_subvol(trans, new_dir, root_objectid, new_dentry->d_name.name, new_dentry->d_name.len); } else { /* dest is an inode */ @@ -9786,7 +9782,7 @@ static int btrfs_rename(struct inode *old_dir, struct dentry *old_dentry, if (unlikely(old_ino == BTRFS_FIRST_FREE_OBJECTID)) { root_objectid = BTRFS_I(old_inode)->root->root_key.objectid; - ret = btrfs_unlink_subvol(trans, root, old_dir, root_objectid, + ret = btrfs_unlink_subvol(trans, old_dir, root_objectid, old_dentry->d_name.name, old_dentry->d_name.len); } else { @@ -9808,8 +9804,7 @@ static int btrfs_rename(struct inode *old_dir, struct dentry *old_dentry, if (unlikely(btrfs_ino(BTRFS_I(new_inode)) == BTRFS_EMPTY_SUBVOL_DIR_OBJECTID)) { root_objectid = BTRFS_I(new_inode)->location.objectid; - ret = btrfs_unlink_subvol(trans, dest, new_dir, - root_objectid, + ret = btrfs_unlink_subvol(trans, new_dir, root_objectid, new_dentry->d_name.name, new_dentry->d_name.len); BUG_ON(new_inode->i_nlink == 0); -- cgit v1.2.3 From 5b7d687ad5913a56b6a8788435d7a53990b4176d Mon Sep 17 00:00:00 2001 From: Lu Fengqi Date: Wed, 1 Aug 2018 11:32:31 +0800 Subject: btrfs: Remove redundant btrfs_release_path from btrfs_unlink_subvol Although it is safe to call this on already released paths with no locks held or extent buffers, removing the redundant btrfs_release_path is reasonable. Signed-off-by: Lu Fengqi Reviewed-by: David Sterba Signed-off-by: David Sterba --- fs/btrfs/inode.c | 1 - 1 file changed, 1 deletion(-) (limited to 'fs') diff --git a/fs/btrfs/inode.c b/fs/btrfs/inode.c index b8c131b82978..7e56a203c109 100644 --- a/fs/btrfs/inode.c +++ b/fs/btrfs/inode.c @@ -4137,7 +4137,6 @@ static int btrfs_unlink_subvol(struct btrfs_trans_handle *trans, leaf = path->nodes[0]; btrfs_item_key_to_cpu(leaf, &key, path->slots[0]); - btrfs_release_path(path); index = key.offset; } btrfs_release_path(path); -- cgit v1.2.3 From afc6961ffd96ee7e2a86e70e9691a008eadf2926 Mon Sep 17 00:00:00 2001 From: Misono Tomohiro Date: Thu, 26 Jul 2018 10:22:58 +0900 Subject: btrfs: backref: Use ERR_CAST to return error code Use ERR_CAST() instead of void * to make meaning clear. Signed-off-by: Misono Tomohiro Reviewed-by: Nikolay Borisov Reviewed-by: David Sterba Signed-off-by: David Sterba --- fs/btrfs/backref.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) (limited to 'fs') diff --git a/fs/btrfs/backref.c b/fs/btrfs/backref.c index 60f4afa8ecbc..ae750b1574a2 100644 --- a/fs/btrfs/backref.c +++ b/fs/btrfs/backref.c @@ -2225,7 +2225,7 @@ struct inode_fs_paths *init_ipath(s32 total_bytes, struct btrfs_root *fs_root, fspath = init_data_container(total_bytes); if (IS_ERR(fspath)) - return (void *)fspath; + return ERR_CAST(fspath); ifp = kmalloc(sizeof(*ifp), GFP_KERNEL); if (!ifp) { -- cgit v1.2.3 From 85c39548199b966062578fb99d4d4ecdeae2afae Mon Sep 17 00:00:00 2001 From: Misono Tomohiro Date: Thu, 26 Jul 2018 11:40:54 +0900 Subject: btrfs: extent-tree: Remove unused __btrfs_free_block_rsv There is no user of this function anymore. This was forgotten to be removed in commit a575ceeb1338 ("Btrfs: get rid of unused orphan infrastructure"). Signed-off-by: Misono Tomohiro Reviewed-by: Nikolay Borisov Reviewed-by: David Sterba Signed-off-by: David Sterba --- fs/btrfs/ctree.h | 1 - fs/btrfs/extent-tree.c | 5 ----- 2 files changed, 6 deletions(-) (limited to 'fs') diff --git a/fs/btrfs/ctree.h b/fs/btrfs/ctree.h index c275ea258f9a..318be7864072 100644 --- a/fs/btrfs/ctree.h +++ b/fs/btrfs/ctree.h @@ -2761,7 +2761,6 @@ void btrfs_init_metadata_block_rsv(struct btrfs_fs_info *fs_info, unsigned short type); void btrfs_free_block_rsv(struct btrfs_fs_info *fs_info, struct btrfs_block_rsv *rsv); -void __btrfs_free_block_rsv(struct btrfs_block_rsv *rsv); int btrfs_block_rsv_add(struct btrfs_root *root, struct btrfs_block_rsv *block_rsv, u64 num_bytes, enum btrfs_reserve_flush_enum flush); diff --git a/fs/btrfs/extent-tree.c b/fs/btrfs/extent-tree.c index 042dd4186fb8..9e7b237b9547 100644 --- a/fs/btrfs/extent-tree.c +++ b/fs/btrfs/extent-tree.c @@ -5529,11 +5529,6 @@ void btrfs_free_block_rsv(struct btrfs_fs_info *fs_info, kfree(rsv); } -void __btrfs_free_block_rsv(struct btrfs_block_rsv *rsv) -{ - kfree(rsv); -} - int btrfs_block_rsv_add(struct btrfs_root *root, struct btrfs_block_rsv *block_rsv, u64 num_bytes, enum btrfs_reserve_flush_enum flush) -- cgit v1.2.3 From 1e7e1f9e3aba00c9b9c323bfeeddafe69ff21ff6 Mon Sep 17 00:00:00 2001 From: Misono Tomohiro Date: Tue, 31 Jul 2018 16:20:21 +0900 Subject: btrfs: replace: Reset on-disk dev stats value after replace on-disk devs stats value is updated in btrfs_run_dev_stats(), which is called during commit transaction, if device->dev_stats_ccnt is not zero. Since current replace operation does not touch dev_stats_ccnt, on-disk dev stats value is not updated. Therefore "btrfs device stats" may return old device's value after umount/mount (Example: See "btrfs ins dump-t -t DEV $DEV" after btrfs/100 finish). Fix this by just incrementing dev_stats_ccnt in btrfs_dev_replace_finishing() when replace is succeeded and this will update the values. Signed-off-by: Misono Tomohiro Reviewed-by: David Sterba Signed-off-by: David Sterba --- fs/btrfs/dev-replace.c | 6 ++++++ 1 file changed, 6 insertions(+) (limited to 'fs') diff --git a/fs/btrfs/dev-replace.c b/fs/btrfs/dev-replace.c index 5a72f9933e58..dec01970d8c5 100644 --- a/fs/btrfs/dev-replace.c +++ b/fs/btrfs/dev-replace.c @@ -671,6 +671,12 @@ static int btrfs_dev_replace_finishing(struct btrfs_fs_info *fs_info, btrfs_rm_dev_replace_unblocked(fs_info); + /* + * Increment dev_stats_ccnt so that btrfs_run_dev_stats() will + * update on-disk dev stats value during commit transaction + */ + atomic_inc(&tgt_device->dev_stats_ccnt); + /* * this is again a consistent state where no dev_replace procedure * is running, the target device is part of the filesystem, the -- cgit v1.2.3 From 2e19f1f9d31b3515356710b8bdfb655f47a98448 Mon Sep 17 00:00:00 2001 From: Al Viro Date: Sun, 29 Jul 2018 23:04:45 +0100 Subject: btrfs: btrfs_iget never returns an is_bad_inode inode Just get rid of pointless checks. Signed-off-by: Al Viro Reviewed-by: Nikolay Borisov Reviewed-by: David Sterba Signed-off-by: David Sterba --- fs/btrfs/free-space-cache.c | 4 ---- fs/btrfs/relocation.c | 7 ++----- fs/btrfs/tree-log.c | 6 +----- 3 files changed, 3 insertions(+), 14 deletions(-) (limited to 'fs') diff --git a/fs/btrfs/free-space-cache.c b/fs/btrfs/free-space-cache.c index 57e7ab7f5e03..0adf38b00fa0 100644 --- a/fs/btrfs/free-space-cache.c +++ b/fs/btrfs/free-space-cache.c @@ -71,10 +71,6 @@ static struct inode *__lookup_free_space_inode(struct btrfs_root *root, inode = btrfs_iget(fs_info->sb, &location, root, NULL); if (IS_ERR(inode)) return inode; - if (is_bad_inode(inode)) { - iput(inode); - return ERR_PTR(-ENOENT); - } mapping_set_gfp_mask(inode->i_mapping, mapping_gfp_constraint(inode->i_mapping, diff --git a/fs/btrfs/relocation.c b/fs/btrfs/relocation.c index d6bcf558789e..8783a1776540 100644 --- a/fs/btrfs/relocation.c +++ b/fs/btrfs/relocation.c @@ -3470,11 +3470,8 @@ static int delete_block_group_cache(struct btrfs_fs_info *fs_info, key.offset = 0; inode = btrfs_iget(fs_info->sb, &key, root, NULL); - if (IS_ERR(inode) || is_bad_inode(inode)) { - if (!IS_ERR(inode)) - iput(inode); + if (IS_ERR(inode)) return -ENOENT; - } truncate: ret = btrfs_check_trunc_cache_free_space(fs_info, @@ -4155,7 +4152,7 @@ struct inode *create_reloc_inode(struct btrfs_fs_info *fs_info, key.type = BTRFS_INODE_ITEM_KEY; key.offset = 0; inode = btrfs_iget(fs_info->sb, &key, root, NULL); - BUG_ON(IS_ERR(inode) || is_bad_inode(inode)); + BUG_ON(IS_ERR(inode)); BTRFS_I(inode)->index_cnt = group->key.objectid; err = btrfs_orphan_add(trans, BTRFS_I(inode)); diff --git a/fs/btrfs/tree-log.c b/fs/btrfs/tree-log.c index 033aeebbe9de..730b97dee955 100644 --- a/fs/btrfs/tree-log.c +++ b/fs/btrfs/tree-log.c @@ -545,12 +545,8 @@ static noinline struct inode *read_one_inode(struct btrfs_root *root, key.type = BTRFS_INODE_ITEM_KEY; key.offset = 0; inode = btrfs_iget(root->fs_info->sb, &key, root, NULL); - if (IS_ERR(inode)) { + if (IS_ERR(inode)) inode = NULL; - } else if (is_bad_inode(inode)) { - iput(inode); - inode = NULL; - } return inode; } -- cgit v1.2.3 From 8d9e220ca0844bf75b98cb5b8e2c25d203c0d0f6 Mon Sep 17 00:00:00 2001 From: Al Viro Date: Sun, 29 Jul 2018 23:04:46 +0100 Subject: btrfs: simplify IS_ERR/PTR_ERR checks IS_ERR(p) && PTR_ERR(p) == n is a weird way to spell p == ERR_PTR(n). Signed-off-by: Al Viro Reviewed-by: David Sterba Reviewed-by: Nikolay Borisov [ update changelog ] Signed-off-by: David Sterba --- fs/btrfs/transaction.c | 2 +- fs/btrfs/tree-log.c | 5 ++--- 2 files changed, 3 insertions(+), 4 deletions(-) (limited to 'fs') diff --git a/fs/btrfs/transaction.c b/fs/btrfs/transaction.c index 001ed1bc2aa8..3b84f5015029 100644 --- a/fs/btrfs/transaction.c +++ b/fs/btrfs/transaction.c @@ -680,7 +680,7 @@ btrfs_attach_transaction_barrier(struct btrfs_root *root) trans = start_transaction(root, 0, TRANS_ATTACH, BTRFS_RESERVE_NO_FLUSH, true); - if (IS_ERR(trans) && PTR_ERR(trans) == -ENOENT) + if (trans == ERR_PTR(-ENOENT)) btrfs_wait_for_commit(root->fs_info, 0); return trans; diff --git a/fs/btrfs/tree-log.c b/fs/btrfs/tree-log.c index 730b97dee955..1650dc44a5e3 100644 --- a/fs/btrfs/tree-log.c +++ b/fs/btrfs/tree-log.c @@ -2181,7 +2181,7 @@ again: dir_key->offset, name, name_len, 0); } - if (!log_di || (IS_ERR(log_di) && PTR_ERR(log_di) == -ENOENT)) { + if (!log_di || log_di == ERR_PTR(-ENOENT)) { btrfs_dir_item_key_to_cpu(eb, di, &location); btrfs_release_path(path); btrfs_release_path(log_path); @@ -5011,8 +5011,7 @@ again: * we don't need to do more work nor fallback to * a transaction commit. */ - if (IS_ERR(other_inode) && - PTR_ERR(other_inode) == -ENOENT) { + if (other_inode == ERR_PTR(-ENOENT)) { goto next_key; } else if (IS_ERR(other_inode)) { err = PTR_ERR(other_inode); -- cgit v1.2.3 From 9bc2ceff660580454f971ed3f891a2c82085433a Mon Sep 17 00:00:00 2001 From: Al Viro Date: Sun, 29 Jul 2018 23:04:50 +0100 Subject: btrfs: lift make_bad_inode into btrfs_iget We don't need to check is_bad_inode() after the call of btrfs_read_locked_inode() - it's exactly the same as checking return value for being non-zero. Signed-off-by: Al Viro Reviewed-by: David Sterba Reviewed-by: Nikolay Borisov Signed-off-by: David Sterba --- fs/btrfs/inode.c | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) (limited to 'fs') diff --git a/fs/btrfs/inode.c b/fs/btrfs/inode.c index 7e56a203c109..cd99ce8583a8 100644 --- a/fs/btrfs/inode.c +++ b/fs/btrfs/inode.c @@ -3771,7 +3771,6 @@ cache_acl: make_bad: btrfs_free_path(path); - make_bad_inode(inode); return ret; } @@ -5697,12 +5696,13 @@ struct inode *btrfs_iget(struct super_block *s, struct btrfs_key *location, int ret; ret = btrfs_read_locked_inode(inode); - if (!is_bad_inode(inode)) { + if (!ret) { inode_tree_add(inode); unlock_new_inode(inode); if (new) *new = 1; } else { + make_bad_inode(inode); unlock_new_inode(inode); iput(inode); ASSERT(ret < 0); -- cgit v1.2.3 From f5b3a4173ff624b766c56936bb315e1517603891 Mon Sep 17 00:00:00 2001 From: Al Viro Date: Sun, 29 Jul 2018 23:04:51 +0100 Subject: btrfs: simplify btrfs_iget Don't open-code iget_failed(), don't bother with btrfs_free_path(NULL), move handling of positive return values of btrfs_lookup_inode() from btrfs_read_locked_inode() to btrfs_iget() and kill now obviously pointless ASSERT() in there. Signed-off-by: Al Viro Reviewed-by: Nikolay Borisov Reviewed-by: David Sterba Signed-off-by: David Sterba --- fs/btrfs/inode.c | 29 +++++++++++++---------------- 1 file changed, 13 insertions(+), 16 deletions(-) (limited to 'fs') diff --git a/fs/btrfs/inode.c b/fs/btrfs/inode.c index cd99ce8583a8..3f51ddc18f98 100644 --- a/fs/btrfs/inode.c +++ b/fs/btrfs/inode.c @@ -3604,18 +3604,15 @@ static int btrfs_read_locked_inode(struct inode *inode) filled = true; path = btrfs_alloc_path(); - if (!path) { - ret = -ENOMEM; - goto make_bad; - } + if (!path) + return -ENOMEM; memcpy(&location, &BTRFS_I(inode)->location, sizeof(location)); ret = btrfs_lookup_inode(NULL, root, path, &location, 0); if (ret) { - if (ret > 0) - ret = -ENOENT; - goto make_bad; + btrfs_free_path(path); + return ret; } leaf = path->nodes[0]; @@ -3768,10 +3765,6 @@ cache_acl: btrfs_sync_inode_flags_to_i_flags(inode); return 0; - -make_bad: - btrfs_free_path(path); - return ret; } /* @@ -5702,11 +5695,15 @@ struct inode *btrfs_iget(struct super_block *s, struct btrfs_key *location, if (new) *new = 1; } else { - make_bad_inode(inode); - unlock_new_inode(inode); - iput(inode); - ASSERT(ret < 0); - inode = ERR_PTR(ret < 0 ? ret : -ESTALE); + iget_failed(inode); + /* + * ret > 0 can come from btrfs_search_slot called by + * btrfs_read_locked_inode, this means the inode item + * was not found. + */ + if (ret > 0) + ret = -ENOENT; + inode = ERR_PTR(ret); } } -- cgit v1.2.3 From 672d599041c862dd61a1576c32e946ef0d77aa34 Mon Sep 17 00:00:00 2001 From: Misono Tomohiro Date: Thu, 2 Aug 2018 16:19:07 +0900 Subject: btrfs: Use wrapper macro for rcu string to remove duplicate code Cleanup patch and no functional changes. Signed-off-by: Misono Tomohiro Reviewed-by: Qu Wenruo Reviewed-by: David Sterba Signed-off-by: David Sterba --- fs/btrfs/ioctl.c | 6 ++---- fs/btrfs/scrub.c | 8 ++------ fs/btrfs/super.c | 9 +++------ fs/btrfs/volumes.c | 20 +++++--------------- 4 files changed, 12 insertions(+), 31 deletions(-) (limited to 'fs') diff --git a/fs/btrfs/ioctl.c b/fs/btrfs/ioctl.c index 6eaadddaca9f..d3a5d2a41e5f 100644 --- a/fs/btrfs/ioctl.c +++ b/fs/btrfs/ioctl.c @@ -3157,10 +3157,8 @@ static long btrfs_ioctl_dev_info(struct btrfs_fs_info *fs_info, di_args->total_bytes = btrfs_device_get_total_bytes(dev); memcpy(di_args->uuid, dev->uuid, sizeof(di_args->uuid)); if (dev->name) { - struct rcu_string *name; - - name = rcu_dereference(dev->name); - strncpy(di_args->path, name->str, sizeof(di_args->path) - 1); + strncpy(di_args->path, rcu_str_deref(dev->name), + sizeof(di_args->path) - 1); di_args->path[sizeof(di_args->path) - 1] = 0; } else { di_args->path[0] = '\0'; diff --git a/fs/btrfs/scrub.c b/fs/btrfs/scrub.c index c4eb9eca13b8..3be1456b5116 100644 --- a/fs/btrfs/scrub.c +++ b/fs/btrfs/scrub.c @@ -3779,7 +3779,6 @@ int btrfs_scrub_dev(struct btrfs_fs_info *fs_info, u64 devid, u64 start, struct scrub_ctx *sctx; int ret; struct btrfs_device *dev; - struct rcu_string *name; if (btrfs_fs_closing(fs_info)) return -EINVAL; @@ -3833,11 +3832,8 @@ int btrfs_scrub_dev(struct btrfs_fs_info *fs_info, u64 devid, u64 start, if (!is_dev_replace && !readonly && !test_bit(BTRFS_DEV_STATE_WRITEABLE, &dev->dev_state)) { mutex_unlock(&fs_info->fs_devices->device_list_mutex); - rcu_read_lock(); - name = rcu_dereference(dev->name); - btrfs_err(fs_info, "scrub: device %s is not writable", - name->str); - rcu_read_unlock(); + btrfs_err_in_rcu(fs_info, "scrub: device %s is not writable", + rcu_str_deref(dev->name)); return -EROFS; } diff --git a/fs/btrfs/super.c b/fs/btrfs/super.c index 67de3c0fc85b..6601c9aa5e35 100644 --- a/fs/btrfs/super.c +++ b/fs/btrfs/super.c @@ -2303,7 +2303,6 @@ static int btrfs_show_devname(struct seq_file *m, struct dentry *root) struct btrfs_fs_devices *cur_devices; struct btrfs_device *dev, *first_dev = NULL; struct list_head *head; - struct rcu_string *name; /* * Lightweight locking of the devices. We should not need @@ -2327,12 +2326,10 @@ static int btrfs_show_devname(struct seq_file *m, struct dentry *root) cur_devices = cur_devices->seed; } - if (first_dev) { - name = rcu_dereference(first_dev->name); - seq_escape(m, name->str, " \t\n\\"); - } else { + if (first_dev) + seq_escape(m, rcu_str_deref(first_dev->name), " \t\n\\"); + else WARN_ON(1); - } rcu_read_unlock(); return 0; } diff --git a/fs/btrfs/volumes.c b/fs/btrfs/volumes.c index d86346f83a08..74977203fc85 100644 --- a/fs/btrfs/volumes.c +++ b/fs/btrfs/volumes.c @@ -6094,21 +6094,11 @@ static void submit_stripe_bio(struct btrfs_bio *bbio, struct bio *bio, btrfs_io_bio(bio)->stripe_index = dev_nr; bio->bi_end_io = btrfs_end_bio; bio->bi_iter.bi_sector = physical >> 9; -#ifdef DEBUG - { - struct rcu_string *name; - - rcu_read_lock(); - name = rcu_dereference(dev->name); - btrfs_debug(fs_info, - "btrfs_map_bio: rw %d 0x%x, sector=%llu, dev=%lu (%s id %llu), size=%u", - bio_op(bio), bio->bi_opf, - (u64)bio->bi_iter.bi_sector, - (u_long)dev->bdev->bd_dev, name->str, dev->devid, - bio->bi_iter.bi_size); - rcu_read_unlock(); - } -#endif + btrfs_debug_in_rcu(fs_info, + "btrfs_map_bio: rw %d 0x%x, sector=%llu, dev=%lu (%s id %llu), size=%u", + bio_op(bio), bio->bi_opf, (u64)bio->bi_iter.bi_sector, + (u_long)dev->bdev->bd_dev, rcu_str_deref(dev->name), dev->devid, + bio->bi_iter.bi_size); bio_set_dev(bio, dev->bdev); btrfs_bio_counter_inc_noblocked(fs_info); -- cgit v1.2.3 From 22d3151c2c4cb517a309154d1e828a28106508c7 Mon Sep 17 00:00:00 2001 From: Filipe Manana Date: Mon, 30 Jul 2018 12:39:58 +0100 Subject: Btrfs: send, fix incorrect file layout after hole punching beyond eof When doing an incremental send, if we have a file in the parent snapshot that has prealloc extents beyond EOF and in the send snapshot it got a hole punch that partially covers the prealloc extents, the send stream, when replayed by a receiver, can result in a file that has a size bigger than it should and filled with zeroes past the correct EOF. For example: $ mkfs.btrfs -f /dev/sdb $ mount /dev/sdb /mnt $ xfs_io -f -c "falloc -k 0 4M" /mnt/foobar $ xfs_io -c "pwrite -S 0xea 0 1M" /mnt/foobar $ btrfs subvolume snapshot -r /mnt /mnt/snap1 $ btrfs send -f /tmp/1.send /mnt/snap1 $ xfs_io -c "fpunch 1M 2M" /mnt/foobar $ btrfs subvolume snapshot -r /mnt /mnt/snap2 $ btrfs send -f /tmp/2.send -p /mnt/snap1 /mnt/snap2 $ stat --format %s /mnt/snap2/foobar 1048576 $ md5sum /mnt/snap2/foobar d31659e82e87798acd4669a1e0a19d4f /mnt/snap2/foobar $ umount /mnt $ mkfs.btrfs -f /dev/sdc $ mount /dev/sdc /mnt $ btrfs receive -f /mnt/1.snap /mnt $ btrfs receive -f /mnt/2.snap /mnt $ stat --format %s /mnt/snap2/foobar 3145728 # --> should be 1Mb and not 3Mb (which was the end offset of hole # punch operation) $ md5sum /mnt/snap2/foobar 117baf295297c2a995f92da725b0b651 /mnt/snap2/foobar # --> should be d31659e82e87798acd4669a1e0a19d4f as in the original fs This issue actually happens only since commit ffa7c4296e93 ("Btrfs: send, do not issue unnecessary truncate operations"), but before that commit we were issuing a write operation full of zeroes (to "punch" a hole) which was extending the file size beyond the correct value and then immediately issue a truncate operation to the correct size and undoing the previous write operation. Since the send protocol does not support fallocate, for extent preallocation and hole punching, fix this by not even attempting to send a "hole" (regular write full of zeroes) if it starts at an offset greater then or equals to the file's size. This approach, besides being much more simple then making send issue the truncate operation, adds the benefit of avoiding the useless pair of write of zeroes and truncate operations, saving time and IO at the receiver and reducing the size of the send stream. A test case for fstests follows soon. Fixes: ffa7c4296e93 ("Btrfs: send, do not issue unnecessary truncate operations") CC: stable@vger.kernel.org # 4.17+ Signed-off-by: Filipe Manana Signed-off-by: David Sterba --- fs/btrfs/send.c | 9 +++++++++ 1 file changed, 9 insertions(+) (limited to 'fs') diff --git a/fs/btrfs/send.c b/fs/btrfs/send.c index 551294a6c9e2..ba8950bfd9c7 100644 --- a/fs/btrfs/send.c +++ b/fs/btrfs/send.c @@ -5007,6 +5007,15 @@ static int send_hole(struct send_ctx *sctx, u64 end) u64 len; int ret = 0; + /* + * A hole that starts at EOF or beyond it. Since we do not yet support + * fallocate (for extent preallocation and hole punching), sending a + * write of zeroes starting at EOF or beyond would later require issuing + * a truncate operation which would undo the write and achieve nothing. + */ + if (offset >= sctx->cur_inode_size) + return 0; + if (sctx->flags & BTRFS_SEND_FLAG_NO_FILE_DATA) return send_update_extent(sctx, offset, end - offset); -- cgit v1.2.3 From 514c7dca85a0bf40be984dab0b477403a6db901f Mon Sep 17 00:00:00 2001 From: Qu Wenruo Date: Wed, 1 Aug 2018 10:37:16 +0800 Subject: btrfs: Check that each block group has corresponding chunk at mount time A crafted btrfs image with incorrect chunk<->block group mapping will trigger a lot of unexpected things as the mapping is essential. Although the problem can be caught by block group item checker added in "btrfs: tree-checker: Verify block_group_item", it's still not sufficient. A sufficiently valid block group item can pass the check added by the mentioned patch but could fail to match the existing chunk. This patch will add extra block group -> chunk mapping check, to ensure we have a completely matching (start, len, flags) chunk for each block group at mount time. Here we reuse the original helper find_first_block_group(), which is already doing the basic bg -> chunk checks, adding further checks of the start/len and type flags. Link: https://bugzilla.kernel.org/show_bug.cgi?id=199837 Reported-by: Xu Wen Signed-off-by: Qu Wenruo Reviewed-by: Su Yue Reviewed-by: David Sterba Signed-off-by: David Sterba --- fs/btrfs/extent-tree.c | 28 +++++++++++++++++++++++++++- 1 file changed, 27 insertions(+), 1 deletion(-) (limited to 'fs') diff --git a/fs/btrfs/extent-tree.c b/fs/btrfs/extent-tree.c index 9e7b237b9547..54a0cfef5c5c 100644 --- a/fs/btrfs/extent-tree.c +++ b/fs/btrfs/extent-tree.c @@ -9532,6 +9532,8 @@ static int find_first_block_group(struct btrfs_fs_info *fs_info, int ret = 0; struct btrfs_key found_key; struct extent_buffer *leaf; + struct btrfs_block_group_item bg; + u64 flags; int slot; ret = btrfs_search_slot(NULL, root, key, path, 0, 0); @@ -9566,8 +9568,32 @@ static int find_first_block_group(struct btrfs_fs_info *fs_info, "logical %llu len %llu found bg but no related chunk", found_key.objectid, found_key.offset); ret = -ENOENT; + } else if (em->start != found_key.objectid || + em->len != found_key.offset) { + btrfs_err(fs_info, + "block group %llu len %llu mismatch with chunk %llu len %llu", + found_key.objectid, found_key.offset, + em->start, em->len); + ret = -EUCLEAN; } else { - ret = 0; + read_extent_buffer(leaf, &bg, + btrfs_item_ptr_offset(leaf, slot), + sizeof(bg)); + flags = btrfs_block_group_flags(&bg) & + BTRFS_BLOCK_GROUP_TYPE_MASK; + + if (flags != (em->map_lookup->type & + BTRFS_BLOCK_GROUP_TYPE_MASK)) { + btrfs_err(fs_info, +"block group %llu len %llu type flags 0x%llx mismatch with chunk type flags 0x%llx", + found_key.objectid, + found_key.offset, flags, + (BTRFS_BLOCK_GROUP_TYPE_MASK & + em->map_lookup->type)); + ret = -EUCLEAN; + } else { + ret = 0; + } } free_extent_map(em); goto out; -- cgit v1.2.3 From 7ef49515fa6727cb4b6f2f5b0ffbc5fc20a9f8c6 Mon Sep 17 00:00:00 2001 From: Qu Wenruo Date: Wed, 1 Aug 2018 10:37:17 +0800 Subject: btrfs: Verify that every chunk has corresponding block group at mount time If a crafted image has missing block group items, it could cause unexpected behavior and breaks the assumption of 1:1 chunk<->block group mapping. Although we have the block group -> chunk mapping check, we still need chunk -> block group mapping check. This patch will do extra check to ensure each chunk has its corresponding block group. Link: https://bugzilla.kernel.org/show_bug.cgi?id=199847 Reported-by: Xu Wen Signed-off-by: Qu Wenruo Reviewed-by: Gu Jinxiang Reviewed-by: David Sterba Signed-off-by: David Sterba --- fs/btrfs/extent-tree.c | 58 +++++++++++++++++++++++++++++++++++++++++++++++++- 1 file changed, 57 insertions(+), 1 deletion(-) (limited to 'fs') diff --git a/fs/btrfs/extent-tree.c b/fs/btrfs/extent-tree.c index 54a0cfef5c5c..de6f75f5547b 100644 --- a/fs/btrfs/extent-tree.c +++ b/fs/btrfs/extent-tree.c @@ -9844,6 +9844,62 @@ btrfs_create_block_group_cache(struct btrfs_fs_info *fs_info, return cache; } + +/* + * Iterate all chunks and verify that each of them has the corresponding block + * group + */ +static int check_chunk_block_group_mappings(struct btrfs_fs_info *fs_info) +{ + struct btrfs_mapping_tree *map_tree = &fs_info->mapping_tree; + struct extent_map *em; + struct btrfs_block_group_cache *bg; + u64 start = 0; + int ret = 0; + + while (1) { + read_lock(&map_tree->map_tree.lock); + /* + * lookup_extent_mapping will return the first extent map + * intersecting the range, so setting @len to 1 is enough to + * get the first chunk. + */ + em = lookup_extent_mapping(&map_tree->map_tree, start, 1); + read_unlock(&map_tree->map_tree.lock); + if (!em) + break; + + bg = btrfs_lookup_block_group(fs_info, em->start); + if (!bg) { + btrfs_err(fs_info, + "chunk start=%llu len=%llu doesn't have corresponding block group", + em->start, em->len); + ret = -EUCLEAN; + free_extent_map(em); + break; + } + if (bg->key.objectid != em->start || + bg->key.offset != em->len || + (bg->flags & BTRFS_BLOCK_GROUP_TYPE_MASK) != + (em->map_lookup->type & BTRFS_BLOCK_GROUP_TYPE_MASK)) { + btrfs_err(fs_info, +"chunk start=%llu len=%llu flags=0x%llx doesn't match block group start=%llu len=%llu flags=0x%llx", + em->start, em->len, + em->map_lookup->type & BTRFS_BLOCK_GROUP_TYPE_MASK, + bg->key.objectid, bg->key.offset, + bg->flags & BTRFS_BLOCK_GROUP_TYPE_MASK); + ret = -EUCLEAN; + free_extent_map(em); + btrfs_put_block_group(bg); + break; + } + start = em->start + em->len; + free_extent_map(em); + btrfs_put_block_group(bg); + } + return ret; +} + int btrfs_read_block_groups(struct btrfs_fs_info *info) { struct btrfs_path *path; @@ -10010,7 +10066,7 @@ int btrfs_read_block_groups(struct btrfs_fs_info *info) btrfs_add_raid_kobjects(info); init_global_block_rsv(info); - ret = 0; + ret = check_chunk_block_group_mappings(info); error: btrfs_free_path(path); return ret; -- cgit v1.2.3 From cf90d884b347c50a1e8c1effc4093e497dd68b4b Mon Sep 17 00:00:00 2001 From: Qu Wenruo Date: Wed, 1 Aug 2018 10:37:19 +0800 Subject: btrfs: Introduce mount time chunk <-> dev extent mapping check This patch will introduce chunk <-> dev extent mapping check, to protect us against invalid dev extents or chunks. Since chunk mapping is the fundamental infrastructure of btrfs, extra check at mount time could prevent a lot of unexpected behavior (BUG_ON). Reported-by: Xu Wen Link: https://bugzilla.kernel.org/show_bug.cgi?id=200403 Link: https://bugzilla.kernel.org/show_bug.cgi?id=200407 Signed-off-by: Qu Wenruo Reviewed-by: Su Yue Reviewed-by: David Sterba Signed-off-by: David Sterba --- fs/btrfs/disk-io.c | 7 ++ fs/btrfs/volumes.c | 184 +++++++++++++++++++++++++++++++++++++++++++++++++++++ fs/btrfs/volumes.h | 2 + 3 files changed, 193 insertions(+) (limited to 'fs') diff --git a/fs/btrfs/disk-io.c b/fs/btrfs/disk-io.c index 6a5a3cd12886..5124c15705ce 100644 --- a/fs/btrfs/disk-io.c +++ b/fs/btrfs/disk-io.c @@ -3030,6 +3030,13 @@ retry_root_backup: fs_info->generation = generation; fs_info->last_trans_committed = generation; + ret = btrfs_verify_dev_extents(fs_info); + if (ret) { + btrfs_err(fs_info, + "failed to verify dev extents against chunks: %d", + ret); + goto fail_block_groups; + } ret = btrfs_recover_balance(fs_info); if (ret) { btrfs_err(fs_info, "failed to recover balance: %d", ret); diff --git a/fs/btrfs/volumes.c b/fs/btrfs/volumes.c index 74977203fc85..96be1e50b027 100644 --- a/fs/btrfs/volumes.c +++ b/fs/btrfs/volumes.c @@ -6452,6 +6452,7 @@ static int read_one_chunk(struct btrfs_fs_info *fs_info, struct btrfs_key *key, map->stripe_len = btrfs_chunk_stripe_len(leaf, chunk); map->type = btrfs_chunk_type(leaf, chunk); map->sub_stripes = btrfs_chunk_sub_stripes(leaf, chunk); + map->verified_stripes = 0; for (i = 0; i < num_stripes; i++) { map->stripes[i].physical = btrfs_stripe_offset_nr(leaf, chunk, i); @@ -7318,3 +7319,186 @@ int btrfs_bg_type_to_factor(u64 flags) return 2; return 1; } + + +static u64 calc_stripe_length(u64 type, u64 chunk_len, int num_stripes) +{ + int index = btrfs_bg_flags_to_raid_index(type); + int ncopies = btrfs_raid_array[index].ncopies; + int data_stripes; + + switch (type & BTRFS_BLOCK_GROUP_PROFILE_MASK) { + case BTRFS_BLOCK_GROUP_RAID5: + data_stripes = num_stripes - 1; + break; + case BTRFS_BLOCK_GROUP_RAID6: + data_stripes = num_stripes - 2; + break; + default: + data_stripes = num_stripes / ncopies; + break; + } + return div_u64(chunk_len, data_stripes); +} + +static int verify_one_dev_extent(struct btrfs_fs_info *fs_info, + u64 chunk_offset, u64 devid, + u64 physical_offset, u64 physical_len) +{ + struct extent_map_tree *em_tree = &fs_info->mapping_tree.map_tree; + struct extent_map *em; + struct map_lookup *map; + u64 stripe_len; + bool found = false; + int ret = 0; + int i; + + read_lock(&em_tree->lock); + em = lookup_extent_mapping(em_tree, chunk_offset, 1); + read_unlock(&em_tree->lock); + + if (!em) { + btrfs_err(fs_info, +"dev extent physical offset %llu on devid %llu doesn't have corresponding chunk", + physical_offset, devid); + ret = -EUCLEAN; + goto out; + } + + map = em->map_lookup; + stripe_len = calc_stripe_length(map->type, em->len, map->num_stripes); + if (physical_len != stripe_len) { + btrfs_err(fs_info, +"dev extent physical offset %llu on devid %llu length doesn't match chunk %llu, have %llu expect %llu", + physical_offset, devid, em->start, physical_len, + stripe_len); + ret = -EUCLEAN; + goto out; + } + + for (i = 0; i < map->num_stripes; i++) { + if (map->stripes[i].dev->devid == devid && + map->stripes[i].physical == physical_offset) { + found = true; + if (map->verified_stripes >= map->num_stripes) { + btrfs_err(fs_info, + "too many dev extents for chunk %llu found", + em->start); + ret = -EUCLEAN; + goto out; + } + map->verified_stripes++; + break; + } + } + if (!found) { + btrfs_err(fs_info, + "dev extent physical offset %llu devid %llu has no corresponding chunk", + physical_offset, devid); + ret = -EUCLEAN; + } +out: + free_extent_map(em); + return ret; +} + +static int verify_chunk_dev_extent_mapping(struct btrfs_fs_info *fs_info) +{ + struct extent_map_tree *em_tree = &fs_info->mapping_tree.map_tree; + struct extent_map *em; + struct rb_node *node; + int ret = 0; + + read_lock(&em_tree->lock); + for (node = rb_first(&em_tree->map); node; node = rb_next(node)) { + em = rb_entry(node, struct extent_map, rb_node); + if (em->map_lookup->num_stripes != + em->map_lookup->verified_stripes) { + btrfs_err(fs_info, + "chunk %llu has missing dev extent, have %d expect %d", + em->start, em->map_lookup->verified_stripes, + em->map_lookup->num_stripes); + ret = -EUCLEAN; + goto out; + } + } +out: + read_unlock(&em_tree->lock); + return ret; +} + +/* + * Ensure that all dev extents are mapped to correct chunk, otherwise + * later chunk allocation/free would cause unexpected behavior. + * + * NOTE: This will iterate through the whole device tree, which should be of + * the same size level as the chunk tree. This slightly increases mount time. + */ +int btrfs_verify_dev_extents(struct btrfs_fs_info *fs_info) +{ + struct btrfs_path *path; + struct btrfs_root *root = fs_info->dev_root; + struct btrfs_key key; + int ret = 0; + + key.objectid = 1; + key.type = BTRFS_DEV_EXTENT_KEY; + key.offset = 0; + + path = btrfs_alloc_path(); + if (!path) + return -ENOMEM; + + path->reada = READA_FORWARD; + ret = btrfs_search_slot(NULL, root, &key, path, 0, 0); + if (ret < 0) + goto out; + + if (path->slots[0] >= btrfs_header_nritems(path->nodes[0])) { + ret = btrfs_next_item(root, path); + if (ret < 0) + goto out; + /* No dev extents at all? Not good */ + if (ret > 0) { + ret = -EUCLEAN; + goto out; + } + } + while (1) { + struct extent_buffer *leaf = path->nodes[0]; + struct btrfs_dev_extent *dext; + int slot = path->slots[0]; + u64 chunk_offset; + u64 physical_offset; + u64 physical_len; + u64 devid; + + btrfs_item_key_to_cpu(leaf, &key, slot); + if (key.type != BTRFS_DEV_EXTENT_KEY) + break; + devid = key.objectid; + physical_offset = key.offset; + + dext = btrfs_item_ptr(leaf, slot, struct btrfs_dev_extent); + chunk_offset = btrfs_dev_extent_chunk_offset(leaf, dext); + physical_len = btrfs_dev_extent_length(leaf, dext); + + ret = verify_one_dev_extent(fs_info, chunk_offset, devid, + physical_offset, physical_len); + if (ret < 0) + goto out; + ret = btrfs_next_item(root, path); + if (ret < 0) + goto out; + if (ret > 0) { + ret = 0; + break; + } + } + + /* Ensure all chunks have corresponding dev extents */ + ret = verify_chunk_dev_extent_mapping(fs_info); +out: + btrfs_free_path(path); + return ret; +} diff --git a/fs/btrfs/volumes.h b/fs/btrfs/volumes.h index 049619176831..23e9285d88de 100644 --- a/fs/btrfs/volumes.h +++ b/fs/btrfs/volumes.h @@ -345,6 +345,7 @@ struct map_lookup { u64 stripe_len; int num_stripes; int sub_stripes; + int verified_stripes; /* For mount time dev extent verification */ struct btrfs_bio_stripe stripes[]; }; @@ -556,5 +557,6 @@ bool btrfs_check_rw_degradable(struct btrfs_fs_info *fs_info, struct btrfs_device *failing_dev); int btrfs_bg_type_to_factor(u64 flags); +int btrfs_verify_dev_extents(struct btrfs_fs_info *fs_info); #endif -- cgit v1.2.3 From 64f64f43c89aca1782aa672e0586f6903c5d8979 Mon Sep 17 00:00:00 2001 From: Qu Wenruo Date: Wed, 1 Aug 2018 10:37:20 +0800 Subject: btrfs: Exit gracefully when chunk map cannot be inserted to the tree It's entirely possible that a crafted btrfs image contains overlapping chunks. Although we can't detect such problem by tree-checker, it's not a catastrophic problem, current extent map can already detect such problem and return -EEXIST. We just only need to exit gracefully and fail the mount. Reported-by: Xu Wen Link: https://bugzilla.kernel.org/show_bug.cgi?id=200409 Signed-off-by: Qu Wenruo Reviewed-by: David Sterba Signed-off-by: David Sterba --- fs/btrfs/volumes.c | 8 ++++++-- 1 file changed, 6 insertions(+), 2 deletions(-) (limited to 'fs') diff --git a/fs/btrfs/volumes.c b/fs/btrfs/volumes.c index 96be1e50b027..7218a79a0e57 100644 --- a/fs/btrfs/volumes.c +++ b/fs/btrfs/volumes.c @@ -6489,10 +6489,14 @@ static int read_one_chunk(struct btrfs_fs_info *fs_info, struct btrfs_key *key, write_lock(&map_tree->map_tree.lock); ret = add_extent_mapping(&map_tree->map_tree, em, 0); write_unlock(&map_tree->map_tree.lock); - BUG_ON(ret); /* Tree corruption */ + if (ret < 0) { + btrfs_err(fs_info, + "failed to add chunk map, start=%llu len=%llu: %d", + em->start, em->len, ret); + } free_extent_map(em); - return 0; + return ret; } static void fill_device_from_item(struct extent_buffer *leaf, -- cgit v1.2.3 From 39379faaad79e3cf403a6904a08676b7850043ae Mon Sep 17 00:00:00 2001 From: Naohiro Aota Date: Fri, 27 Jul 2018 09:04:55 +0900 Subject: btrfs: revert fs_devices state on error of btrfs_init_new_device When btrfs hits error after modifying fs_devices in btrfs_init_new_device() (such as btrfs_add_dev_item() returns error), it leaves everything as is, but frees allocated btrfs_device. As a result, fs_devices->devices and fs_devices->alloc_list contain already freed btrfs_device, leading to later use-after-free bug. Error path also messes the things like ->num_devices. While they go back to the original value by unscanning btrfs devices, it is safe to revert them here. Fixes: 79787eaab461 ("btrfs: replace many BUG_ONs with proper error handling") Signed-off-by: Naohiro Aota Reviewed-by: Filipe Manana Signed-off-by: David Sterba --- fs/btrfs/volumes.c | 29 ++++++++++++++++++++++++----- 1 file changed, 24 insertions(+), 5 deletions(-) (limited to 'fs') diff --git a/fs/btrfs/volumes.c b/fs/btrfs/volumes.c index 7218a79a0e57..da86706123ff 100644 --- a/fs/btrfs/volumes.c +++ b/fs/btrfs/volumes.c @@ -2321,7 +2321,8 @@ int btrfs_init_new_device(struct btrfs_fs_info *fs_info, const char *device_path struct super_block *sb = fs_info->sb; struct rcu_string *name; struct btrfs_fs_devices *fs_devices = fs_info->fs_devices; - u64 tmp; + u64 orig_super_total_bytes; + u64 orig_super_num_devices; int seeding_dev = 0; int ret = 0; bool unlocked = false; @@ -2417,12 +2418,14 @@ int btrfs_init_new_device(struct btrfs_fs_info *fs_info, const char *device_path if (!blk_queue_nonrot(q)) fs_devices->rotating = 1; - tmp = btrfs_super_total_bytes(fs_info->super_copy); + orig_super_total_bytes = btrfs_super_total_bytes(fs_info->super_copy); btrfs_set_super_total_bytes(fs_info->super_copy, - round_down(tmp + device->total_bytes, fs_info->sectorsize)); + round_down(orig_super_total_bytes + device->total_bytes, + fs_info->sectorsize)); - tmp = btrfs_super_num_devices(fs_info->super_copy); - btrfs_set_super_num_devices(fs_info->super_copy, tmp + 1); + orig_super_num_devices = btrfs_super_num_devices(fs_info->super_copy); + btrfs_set_super_num_devices(fs_info->super_copy, + orig_super_num_devices + 1); /* add sysfs device entry */ btrfs_sysfs_add_device_link(fs_devices, device); @@ -2502,6 +2505,22 @@ int btrfs_init_new_device(struct btrfs_fs_info *fs_info, const char *device_path error_sysfs: btrfs_sysfs_rm_device_link(fs_devices, device); + mutex_lock(&fs_info->fs_devices->device_list_mutex); + mutex_lock(&fs_info->chunk_mutex); + list_del_rcu(&device->dev_list); + list_del(&device->dev_alloc_list); + fs_info->fs_devices->num_devices--; + fs_info->fs_devices->open_devices--; + fs_info->fs_devices->rw_devices--; + fs_info->fs_devices->total_devices--; + fs_info->fs_devices->total_rw_bytes -= device->total_bytes; + atomic64_sub(device->total_bytes, &fs_info->free_chunk_space); + btrfs_set_super_total_bytes(fs_info->super_copy, + orig_super_total_bytes); + btrfs_set_super_num_devices(fs_info->super_copy, + orig_super_num_devices); + mutex_unlock(&fs_info->chunk_mutex); + mutex_unlock(&fs_info->fs_devices->device_list_mutex); error_trans: if (seeding_dev) sb->s_flags |= SB_RDONLY; -- cgit v1.2.3