Skip to content

Commit dcdfd9c

Browse files
committed
Merge tag 'for-5.9-rc3-tag' of git://git.kernel.org/pub/scm/linux/kernel/git/kdave/linux
Pull btrfs fixes from David Sterba: "Two small fixes and a bunch of lockdep fixes for warnings that show up with an upcoming tree locking update but are valid with current locks as well" * tag 'for-5.9-rc3-tag' of git://git.kernel.org/pub/scm/linux/kernel/git/kdave/linux: btrfs: tree-checker: fix the error message for transid error btrfs: set the lockdep class for log tree extent buffers btrfs: set the correct lockdep class for new nodes btrfs: allocate scrub workqueues outside of locks btrfs: fix potential deadlock in the search ioctl btrfs: drop path before adding new uuid tree entry btrfs: block-group: fix free-space bitmap threshold
2 parents b765a32 + f96d696 commit dcdfd9c

10 files changed

Lines changed: 113 additions & 71 deletions

File tree

fs/btrfs/block-group.c

Lines changed: 3 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1798,7 +1798,6 @@ static struct btrfs_block_group *btrfs_create_block_group_cache(
17981798

17991799
cache->fs_info = fs_info;
18001800
cache->full_stripe_len = btrfs_full_stripe_len(fs_info, start);
1801-
set_free_space_tree_thresholds(cache);
18021801

18031802
cache->discard_index = BTRFS_DISCARD_INDEX_UNUSED;
18041803

@@ -1912,6 +1911,8 @@ static int read_one_block_group(struct btrfs_fs_info *info,
19121911
if (ret < 0)
19131912
goto error;
19141913

1914+
set_free_space_tree_thresholds(cache);
1915+
19151916
if (need_clear) {
19161917
/*
19171918
* When we mount with old space cache, we need to
@@ -2132,6 +2133,7 @@ int btrfs_make_block_group(struct btrfs_trans_handle *trans, u64 bytes_used,
21322133
return -ENOMEM;
21332134

21342135
cache->length = size;
2136+
set_free_space_tree_thresholds(cache);
21352137
cache->used = bytes_used;
21362138
cache->flags = type;
21372139
cache->last_byte_to_unpin = (u64)-1;

fs/btrfs/ctree.c

Lines changed: 5 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1297,6 +1297,8 @@ tree_mod_log_rewind(struct btrfs_fs_info *fs_info, struct btrfs_path *path,
12971297
btrfs_tree_read_unlock_blocking(eb);
12981298
free_extent_buffer(eb);
12991299

1300+
btrfs_set_buffer_lockdep_class(btrfs_header_owner(eb_rewin),
1301+
eb_rewin, btrfs_header_level(eb_rewin));
13001302
btrfs_tree_read_lock(eb_rewin);
13011303
__tree_mod_log_rewind(fs_info, eb_rewin, time_seq, tm);
13021304
WARN_ON(btrfs_header_nritems(eb_rewin) >
@@ -1370,14 +1372,16 @@ get_old_root(struct btrfs_root *root, u64 time_seq)
13701372

13711373
if (!eb)
13721374
return NULL;
1373-
btrfs_tree_read_lock(eb);
13741375
if (old_root) {
13751376
btrfs_set_header_bytenr(eb, eb->start);
13761377
btrfs_set_header_backref_rev(eb, BTRFS_MIXED_BACKREF_REV);
13771378
btrfs_set_header_owner(eb, eb_root_owner);
13781379
btrfs_set_header_level(eb, old_root->level);
13791380
btrfs_set_header_generation(eb, old_generation);
13801381
}
1382+
btrfs_set_buffer_lockdep_class(btrfs_header_owner(eb), eb,
1383+
btrfs_header_level(eb));
1384+
btrfs_tree_read_lock(eb);
13811385
if (tm)
13821386
__tree_mod_log_rewind(fs_info, eb, time_seq, tm);
13831387
else

fs/btrfs/extent-tree.c

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -4527,7 +4527,7 @@ btrfs_init_new_buffer(struct btrfs_trans_handle *trans, struct btrfs_root *root,
45274527
return ERR_PTR(-EUCLEAN);
45284528
}
45294529

4530-
btrfs_set_buffer_lockdep_class(root->root_key.objectid, buf, level);
4530+
btrfs_set_buffer_lockdep_class(owner, buf, level);
45314531
btrfs_tree_lock(buf);
45324532
btrfs_clean_tree_block(buf);
45334533
clear_bit(EXTENT_BUFFER_STALE, &buf->bflags);

fs/btrfs/extent_io.c

Lines changed: 4 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -5655,9 +5655,9 @@ void read_extent_buffer(const struct extent_buffer *eb, void *dstv,
56555655
}
56565656
}
56575657

5658-
int read_extent_buffer_to_user(const struct extent_buffer *eb,
5659-
void __user *dstv,
5660-
unsigned long start, unsigned long len)
5658+
int read_extent_buffer_to_user_nofault(const struct extent_buffer *eb,
5659+
void __user *dstv,
5660+
unsigned long start, unsigned long len)
56615661
{
56625662
size_t cur;
56635663
size_t offset;
@@ -5677,7 +5677,7 @@ int read_extent_buffer_to_user(const struct extent_buffer *eb,
56775677

56785678
cur = min(len, (PAGE_SIZE - offset));
56795679
kaddr = page_address(page);
5680-
if (copy_to_user(dst, kaddr + offset, cur)) {
5680+
if (copy_to_user_nofault(dst, kaddr + offset, cur)) {
56815681
ret = -EFAULT;
56825682
break;
56835683
}

fs/btrfs/extent_io.h

Lines changed: 3 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -241,9 +241,9 @@ int memcmp_extent_buffer(const struct extent_buffer *eb, const void *ptrv,
241241
void read_extent_buffer(const struct extent_buffer *eb, void *dst,
242242
unsigned long start,
243243
unsigned long len);
244-
int read_extent_buffer_to_user(const struct extent_buffer *eb,
245-
void __user *dst, unsigned long start,
246-
unsigned long len);
244+
int read_extent_buffer_to_user_nofault(const struct extent_buffer *eb,
245+
void __user *dst, unsigned long start,
246+
unsigned long len);
247247
void write_extent_buffer_fsid(const struct extent_buffer *eb, const void *src);
248248
void write_extent_buffer_chunk_tree_uuid(const struct extent_buffer *eb,
249249
const void *src);

fs/btrfs/free-space-tree.c

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -22,6 +22,10 @@ void set_free_space_tree_thresholds(struct btrfs_block_group *cache)
2222
size_t bitmap_size;
2323
u64 num_bitmaps, total_bitmap_size;
2424

25+
if (WARN_ON(cache->length == 0))
26+
btrfs_warn(cache->fs_info, "block group %llu length is zero",
27+
cache->start);
28+
2529
/*
2630
* We convert to bitmaps when the disk space required for using extents
2731
* exceeds that required for using bitmaps.

fs/btrfs/ioctl.c

Lines changed: 20 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -2086,20 +2086,29 @@ static noinline int copy_to_sk(struct btrfs_path *path,
20862086
sh.len = item_len;
20872087
sh.transid = found_transid;
20882088

2089-
/* copy search result header */
2090-
if (copy_to_user(ubuf + *sk_offset, &sh, sizeof(sh))) {
2091-
ret = -EFAULT;
2089+
/*
2090+
* Copy search result header. If we fault then loop again so we
2091+
* can fault in the pages and -EFAULT there if there's a
2092+
* problem. Otherwise we'll fault and then copy the buffer in
2093+
* properly this next time through
2094+
*/
2095+
if (copy_to_user_nofault(ubuf + *sk_offset, &sh, sizeof(sh))) {
2096+
ret = 0;
20922097
goto out;
20932098
}
20942099

20952100
*sk_offset += sizeof(sh);
20962101

20972102
if (item_len) {
20982103
char __user *up = ubuf + *sk_offset;
2099-
/* copy the item */
2100-
if (read_extent_buffer_to_user(leaf, up,
2101-
item_off, item_len)) {
2102-
ret = -EFAULT;
2104+
/*
2105+
* Copy the item, same behavior as above, but reset the
2106+
* * sk_offset so we copy the full thing again.
2107+
*/
2108+
if (read_extent_buffer_to_user_nofault(leaf, up,
2109+
item_off, item_len)) {
2110+
ret = 0;
2111+
*sk_offset -= sizeof(sh);
21032112
goto out;
21042113
}
21052114

@@ -2184,6 +2193,10 @@ static noinline int search_ioctl(struct inode *inode,
21842193
key.offset = sk->min_offset;
21852194

21862195
while (1) {
2196+
ret = fault_in_pages_writeable(ubuf, *buf_size - sk_offset);
2197+
if (ret)
2198+
break;
2199+
21872200
ret = btrfs_search_forward(root, &key, path, sk->min_transid);
21882201
if (ret != 0) {
21892202
if (ret > 0)

fs/btrfs/scrub.c

Lines changed: 70 additions & 52 deletions
Original file line numberDiff line numberDiff line change
@@ -3716,50 +3716,84 @@ static noinline_for_stack int scrub_supers(struct scrub_ctx *sctx,
37163716
return 0;
37173717
}
37183718

3719+
static void scrub_workers_put(struct btrfs_fs_info *fs_info)
3720+
{
3721+
if (refcount_dec_and_mutex_lock(&fs_info->scrub_workers_refcnt,
3722+
&fs_info->scrub_lock)) {
3723+
struct btrfs_workqueue *scrub_workers = NULL;
3724+
struct btrfs_workqueue *scrub_wr_comp = NULL;
3725+
struct btrfs_workqueue *scrub_parity = NULL;
3726+
3727+
scrub_workers = fs_info->scrub_workers;
3728+
scrub_wr_comp = fs_info->scrub_wr_completion_workers;
3729+
scrub_parity = fs_info->scrub_parity_workers;
3730+
3731+
fs_info->scrub_workers = NULL;
3732+
fs_info->scrub_wr_completion_workers = NULL;
3733+
fs_info->scrub_parity_workers = NULL;
3734+
mutex_unlock(&fs_info->scrub_lock);
3735+
3736+
btrfs_destroy_workqueue(scrub_workers);
3737+
btrfs_destroy_workqueue(scrub_wr_comp);
3738+
btrfs_destroy_workqueue(scrub_parity);
3739+
}
3740+
}
3741+
37193742
/*
37203743
* get a reference count on fs_info->scrub_workers. start worker if necessary
37213744
*/
37223745
static noinline_for_stack int scrub_workers_get(struct btrfs_fs_info *fs_info,
37233746
int is_dev_replace)
37243747
{
3748+
struct btrfs_workqueue *scrub_workers = NULL;
3749+
struct btrfs_workqueue *scrub_wr_comp = NULL;
3750+
struct btrfs_workqueue *scrub_parity = NULL;
37253751
unsigned int flags = WQ_FREEZABLE | WQ_UNBOUND;
37263752
int max_active = fs_info->thread_pool_size;
3753+
int ret = -ENOMEM;
37273754

3728-
lockdep_assert_held(&fs_info->scrub_lock);
3755+
if (refcount_inc_not_zero(&fs_info->scrub_workers_refcnt))
3756+
return 0;
37293757

3730-
if (refcount_read(&fs_info->scrub_workers_refcnt) == 0) {
3731-
ASSERT(fs_info->scrub_workers == NULL);
3732-
fs_info->scrub_workers = btrfs_alloc_workqueue(fs_info, "scrub",
3733-
flags, is_dev_replace ? 1 : max_active, 4);
3734-
if (!fs_info->scrub_workers)
3735-
goto fail_scrub_workers;
3736-
3737-
ASSERT(fs_info->scrub_wr_completion_workers == NULL);
3738-
fs_info->scrub_wr_completion_workers =
3739-
btrfs_alloc_workqueue(fs_info, "scrubwrc", flags,
3740-
max_active, 2);
3741-
if (!fs_info->scrub_wr_completion_workers)
3742-
goto fail_scrub_wr_completion_workers;
3758+
scrub_workers = btrfs_alloc_workqueue(fs_info, "scrub", flags,
3759+
is_dev_replace ? 1 : max_active, 4);
3760+
if (!scrub_workers)
3761+
goto fail_scrub_workers;
37433762

3744-
ASSERT(fs_info->scrub_parity_workers == NULL);
3745-
fs_info->scrub_parity_workers =
3746-
btrfs_alloc_workqueue(fs_info, "scrubparity", flags,
3763+
scrub_wr_comp = btrfs_alloc_workqueue(fs_info, "scrubwrc", flags,
37473764
max_active, 2);
3748-
if (!fs_info->scrub_parity_workers)
3749-
goto fail_scrub_parity_workers;
3765+
if (!scrub_wr_comp)
3766+
goto fail_scrub_wr_completion_workers;
37503767

3768+
scrub_parity = btrfs_alloc_workqueue(fs_info, "scrubparity", flags,
3769+
max_active, 2);
3770+
if (!scrub_parity)
3771+
goto fail_scrub_parity_workers;
3772+
3773+
mutex_lock(&fs_info->scrub_lock);
3774+
if (refcount_read(&fs_info->scrub_workers_refcnt) == 0) {
3775+
ASSERT(fs_info->scrub_workers == NULL &&
3776+
fs_info->scrub_wr_completion_workers == NULL &&
3777+
fs_info->scrub_parity_workers == NULL);
3778+
fs_info->scrub_workers = scrub_workers;
3779+
fs_info->scrub_wr_completion_workers = scrub_wr_comp;
3780+
fs_info->scrub_parity_workers = scrub_parity;
37513781
refcount_set(&fs_info->scrub_workers_refcnt, 1);
3752-
} else {
3753-
refcount_inc(&fs_info->scrub_workers_refcnt);
3782+
mutex_unlock(&fs_info->scrub_lock);
3783+
return 0;
37543784
}
3755-
return 0;
3785+
/* Other thread raced in and created the workers for us */
3786+
refcount_inc(&fs_info->scrub_workers_refcnt);
3787+
mutex_unlock(&fs_info->scrub_lock);
37563788

3789+
ret = 0;
3790+
btrfs_destroy_workqueue(scrub_parity);
37573791
fail_scrub_parity_workers:
3758-
btrfs_destroy_workqueue(fs_info->scrub_wr_completion_workers);
3792+
btrfs_destroy_workqueue(scrub_wr_comp);
37593793
fail_scrub_wr_completion_workers:
3760-
btrfs_destroy_workqueue(fs_info->scrub_workers);
3794+
btrfs_destroy_workqueue(scrub_workers);
37613795
fail_scrub_workers:
3762-
return -ENOMEM;
3796+
return ret;
37633797
}
37643798

37653799
int btrfs_scrub_dev(struct btrfs_fs_info *fs_info, u64 devid, u64 start,
@@ -3770,9 +3804,6 @@ int btrfs_scrub_dev(struct btrfs_fs_info *fs_info, u64 devid, u64 start,
37703804
int ret;
37713805
struct btrfs_device *dev;
37723806
unsigned int nofs_flag;
3773-
struct btrfs_workqueue *scrub_workers = NULL;
3774-
struct btrfs_workqueue *scrub_wr_comp = NULL;
3775-
struct btrfs_workqueue *scrub_parity = NULL;
37763807

37773808
if (btrfs_fs_closing(fs_info))
37783809
return -EAGAIN;
@@ -3819,13 +3850,17 @@ int btrfs_scrub_dev(struct btrfs_fs_info *fs_info, u64 devid, u64 start,
38193850
if (IS_ERR(sctx))
38203851
return PTR_ERR(sctx);
38213852

3853+
ret = scrub_workers_get(fs_info, is_dev_replace);
3854+
if (ret)
3855+
goto out_free_ctx;
3856+
38223857
mutex_lock(&fs_info->fs_devices->device_list_mutex);
38233858
dev = btrfs_find_device(fs_info->fs_devices, devid, NULL, NULL, true);
38243859
if (!dev || (test_bit(BTRFS_DEV_STATE_MISSING, &dev->dev_state) &&
38253860
!is_dev_replace)) {
38263861
mutex_unlock(&fs_info->fs_devices->device_list_mutex);
38273862
ret = -ENODEV;
3828-
goto out_free_ctx;
3863+
goto out;
38293864
}
38303865

38313866
if (!is_dev_replace && !readonly &&
@@ -3834,7 +3869,7 @@ int btrfs_scrub_dev(struct btrfs_fs_info *fs_info, u64 devid, u64 start,
38343869
btrfs_err_in_rcu(fs_info, "scrub: device %s is not writable",
38353870
rcu_str_deref(dev->name));
38363871
ret = -EROFS;
3837-
goto out_free_ctx;
3872+
goto out;
38383873
}
38393874

38403875
mutex_lock(&fs_info->scrub_lock);
@@ -3843,7 +3878,7 @@ int btrfs_scrub_dev(struct btrfs_fs_info *fs_info, u64 devid, u64 start,
38433878
mutex_unlock(&fs_info->scrub_lock);
38443879
mutex_unlock(&fs_info->fs_devices->device_list_mutex);
38453880
ret = -EIO;
3846-
goto out_free_ctx;
3881+
goto out;
38473882
}
38483883

38493884
down_read(&fs_info->dev_replace.rwsem);
@@ -3854,17 +3889,10 @@ int btrfs_scrub_dev(struct btrfs_fs_info *fs_info, u64 devid, u64 start,
38543889
mutex_unlock(&fs_info->scrub_lock);
38553890
mutex_unlock(&fs_info->fs_devices->device_list_mutex);
38563891
ret = -EINPROGRESS;
3857-
goto out_free_ctx;
3892+
goto out;
38583893
}
38593894
up_read(&fs_info->dev_replace.rwsem);
38603895

3861-
ret = scrub_workers_get(fs_info, is_dev_replace);
3862-
if (ret) {
3863-
mutex_unlock(&fs_info->scrub_lock);
3864-
mutex_unlock(&fs_info->fs_devices->device_list_mutex);
3865-
goto out_free_ctx;
3866-
}
3867-
38683896
sctx->readonly = readonly;
38693897
dev->scrub_ctx = sctx;
38703898
mutex_unlock(&fs_info->fs_devices->device_list_mutex);
@@ -3917,24 +3945,14 @@ int btrfs_scrub_dev(struct btrfs_fs_info *fs_info, u64 devid, u64 start,
39173945

39183946
mutex_lock(&fs_info->scrub_lock);
39193947
dev->scrub_ctx = NULL;
3920-
if (refcount_dec_and_test(&fs_info->scrub_workers_refcnt)) {
3921-
scrub_workers = fs_info->scrub_workers;
3922-
scrub_wr_comp = fs_info->scrub_wr_completion_workers;
3923-
scrub_parity = fs_info->scrub_parity_workers;
3924-
3925-
fs_info->scrub_workers = NULL;
3926-
fs_info->scrub_wr_completion_workers = NULL;
3927-
fs_info->scrub_parity_workers = NULL;
3928-
}
39293948
mutex_unlock(&fs_info->scrub_lock);
39303949

3931-
btrfs_destroy_workqueue(scrub_workers);
3932-
btrfs_destroy_workqueue(scrub_wr_comp);
3933-
btrfs_destroy_workqueue(scrub_parity);
3950+
scrub_workers_put(fs_info);
39343951
scrub_put_ctx(sctx);
39353952

39363953
return ret;
3937-
3954+
out:
3955+
scrub_workers_put(fs_info);
39383956
out_free_ctx:
39393957
scrub_free_ctx(sctx);
39403958

fs/btrfs/tree-checker.c

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -984,7 +984,7 @@ static int check_inode_item(struct extent_buffer *leaf,
984984
/* Note for ROOT_TREE_DIR_ITEM, mkfs could set its transid 0 */
985985
if (btrfs_inode_transid(leaf, iitem) > super_gen + 1) {
986986
inode_item_err(leaf, slot,
987-
"invalid inode generation: has %llu expect [0, %llu]",
987+
"invalid inode transid: has %llu expect [0, %llu]",
988988
btrfs_inode_transid(leaf, iitem), super_gen + 1);
989989
return -EUCLEAN;
990990
}

fs/btrfs/volumes.c

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -4462,6 +4462,7 @@ int btrfs_uuid_scan_kthread(void *data)
44624462
goto skip;
44634463
}
44644464
update_tree:
4465+
btrfs_release_path(path);
44654466
if (!btrfs_is_empty_uuid(root_item.uuid)) {
44664467
ret = btrfs_uuid_tree_add(trans, root_item.uuid,
44674468
BTRFS_UUID_KEY_SUBVOL,
@@ -4486,14 +4487,14 @@ int btrfs_uuid_scan_kthread(void *data)
44864487
}
44874488

44884489
skip:
4490+
btrfs_release_path(path);
44894491
if (trans) {
44904492
ret = btrfs_end_transaction(trans);
44914493
trans = NULL;
44924494
if (ret)
44934495
break;
44944496
}
44954497

4496-
btrfs_release_path(path);
44974498
if (key.offset < (u64)-1) {
44984499
key.offset++;
44994500
} else if (key.type < BTRFS_ROOT_ITEM_KEY) {

0 commit comments

Comments
 (0)