Skip to content
This repository was archived by the owner on Nov 8, 2023. It is now read-only.

Commit 400dd45

Browse files
committed
Merge tag 'for-6.9-rc1-tag' of git://git.kernel.org/pub/scm/linux/kernel/git/kdave/linux
Pull btrfs fixes from David Sterba: - fix race when reading extent buffer and 'uptodate' status is missed by one thread (introduced in 6.5) - do additional validation of devices using major:minor numbers - zoned mode fixes: - use zone-aware super block access during scrub - fix use-after-free during device replace (found by KASAN) - also delete zones that are 100% unusable to reclaim space - extent unpinning fixes: - fix extent map leak after error handling - print correct range in error message - error code and message updates * tag 'for-6.9-rc1-tag' of git://git.kernel.org/pub/scm/linux/kernel/git/kdave/linux: btrfs: fix race in read_extent_buffer_pages() btrfs: return accurate error code on open failure in open_fs_devices() btrfs: zoned: don't skip block groups with 100% zone unusable btrfs: use btrfs_warn() to log message at btrfs_add_extent_mapping() btrfs: fix message not properly printing interval when adding extent map btrfs: fix warning messages not printing interval at unpin_extent_range() btrfs: fix extent map leak in unexpected scenario at unpin_extent_cache() btrfs: validate device maj:min during open btrfs: zoned: fix use-after-free in do_zone_finish() btrfs: zoned: use zone aware sb location for scrub
2 parents dc189b8 + ef1e682 commit 400dd45

File tree

6 files changed

+63
-22
lines changed

6 files changed

+63
-22
lines changed

fs/btrfs/block-group.c

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1559,7 +1559,8 @@ void btrfs_delete_unused_bgs(struct btrfs_fs_info *fs_info)
15591559
* needing to allocate extents from the block group.
15601560
*/
15611561
used = btrfs_space_info_used(space_info, true);
1562-
if (space_info->total_bytes - block_group->length < used) {
1562+
if (space_info->total_bytes - block_group->length < used &&
1563+
block_group->zone_unusable < block_group->length) {
15631564
/*
15641565
* Add a reference for the list, compensate for the ref
15651566
* drop under the "next" label for the

fs/btrfs/extent_io.c

Lines changed: 13 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -4333,6 +4333,19 @@ int read_extent_buffer_pages(struct extent_buffer *eb, int wait, int mirror_num,
43334333
if (test_and_set_bit(EXTENT_BUFFER_READING, &eb->bflags))
43344334
goto done;
43354335

4336+
/*
4337+
* Between the initial test_bit(EXTENT_BUFFER_UPTODATE) and the above
4338+
* test_and_set_bit(EXTENT_BUFFER_READING), someone else could have
4339+
* started and finished reading the same eb. In this case, UPTODATE
4340+
* will now be set, and we shouldn't read it in again.
4341+
*/
4342+
if (unlikely(test_bit(EXTENT_BUFFER_UPTODATE, &eb->bflags))) {
4343+
clear_bit(EXTENT_BUFFER_READING, &eb->bflags);
4344+
smp_mb__after_atomic();
4345+
wake_up_bit(&eb->bflags, EXTENT_BUFFER_READING);
4346+
return 0;
4347+
}
4348+
43364349
clear_bit(EXTENT_BUFFER_READ_ERR, &eb->bflags);
43374350
eb->read_mirror = 0;
43384351
check_buffer_tree_ref(eb);

fs/btrfs/extent_map.c

Lines changed: 8 additions & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -309,7 +309,7 @@ int unpin_extent_cache(struct btrfs_inode *inode, u64 start, u64 len, u64 gen)
309309
btrfs_warn(fs_info,
310310
"no extent map found for inode %llu (root %lld) when unpinning extent range [%llu, %llu), generation %llu",
311311
btrfs_ino(inode), btrfs_root_id(inode->root),
312-
start, len, gen);
312+
start, start + len, gen);
313313
ret = -ENOENT;
314314
goto out;
315315
}
@@ -318,7 +318,7 @@ int unpin_extent_cache(struct btrfs_inode *inode, u64 start, u64 len, u64 gen)
318318
btrfs_warn(fs_info,
319319
"found extent map for inode %llu (root %lld) with unexpected start offset %llu when unpinning extent range [%llu, %llu), generation %llu",
320320
btrfs_ino(inode), btrfs_root_id(inode->root),
321-
em->start, start, len, gen);
321+
em->start, start, start + len, gen);
322322
ret = -EUCLEAN;
323323
goto out;
324324
}
@@ -340,9 +340,9 @@ int unpin_extent_cache(struct btrfs_inode *inode, u64 start, u64 len, u64 gen)
340340
em->mod_len = em->len;
341341
}
342342

343-
free_extent_map(em);
344343
out:
345344
write_unlock(&tree->lock);
345+
free_extent_map(em);
346346
return ret;
347347

348348
}
@@ -629,13 +629,13 @@ int btrfs_add_extent_mapping(struct btrfs_fs_info *fs_info,
629629
*/
630630
ret = merge_extent_mapping(em_tree, existing,
631631
em, start);
632-
if (ret) {
632+
if (WARN_ON(ret)) {
633633
free_extent_map(em);
634634
*em_in = NULL;
635-
WARN_ONCE(ret,
636-
"extent map merge error existing [%llu, %llu) with em [%llu, %llu) start %llu\n",
637-
existing->start, existing->len,
638-
orig_start, orig_len, start);
635+
btrfs_warn(fs_info,
636+
"extent map merge error existing [%llu, %llu) with em [%llu, %llu) start %llu",
637+
existing->start, extent_map_end(existing),
638+
orig_start, orig_start + orig_len, start);
639639
}
640640
free_extent_map(existing);
641641
}

fs/btrfs/scrub.c

Lines changed: 11 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -2812,7 +2812,17 @@ static noinline_for_stack int scrub_supers(struct scrub_ctx *sctx,
28122812
gen = btrfs_get_last_trans_committed(fs_info);
28132813

28142814
for (i = 0; i < BTRFS_SUPER_MIRROR_MAX; i++) {
2815-
bytenr = btrfs_sb_offset(i);
2815+
ret = btrfs_sb_log_location(scrub_dev, i, 0, &bytenr);
2816+
if (ret == -ENOENT)
2817+
break;
2818+
2819+
if (ret) {
2820+
spin_lock(&sctx->stat_lock);
2821+
sctx->stat.super_errors++;
2822+
spin_unlock(&sctx->stat_lock);
2823+
continue;
2824+
}
2825+
28162826
if (bytenr + BTRFS_SUPER_INFO_SIZE >
28172827
scrub_dev->commit_total_bytes)
28182828
break;

fs/btrfs/volumes.c

Lines changed: 22 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -692,6 +692,16 @@ static int btrfs_open_one_device(struct btrfs_fs_devices *fs_devices,
692692
device->bdev = file_bdev(bdev_file);
693693
clear_bit(BTRFS_DEV_STATE_IN_FS_METADATA, &device->dev_state);
694694

695+
if (device->devt != device->bdev->bd_dev) {
696+
btrfs_warn(NULL,
697+
"device %s maj:min changed from %d:%d to %d:%d",
698+
device->name->str, MAJOR(device->devt),
699+
MINOR(device->devt), MAJOR(device->bdev->bd_dev),
700+
MINOR(device->bdev->bd_dev));
701+
702+
device->devt = device->bdev->bd_dev;
703+
}
704+
695705
fs_devices->open_devices++;
696706
if (test_bit(BTRFS_DEV_STATE_WRITEABLE, &device->dev_state) &&
697707
device->devid != BTRFS_DEV_REPLACE_DEVID) {
@@ -1174,23 +1184,30 @@ static int open_fs_devices(struct btrfs_fs_devices *fs_devices,
11741184
struct btrfs_device *device;
11751185
struct btrfs_device *latest_dev = NULL;
11761186
struct btrfs_device *tmp_device;
1187+
int ret = 0;
11771188

11781189
list_for_each_entry_safe(device, tmp_device, &fs_devices->devices,
11791190
dev_list) {
1180-
int ret;
1191+
int ret2;
11811192

1182-
ret = btrfs_open_one_device(fs_devices, device, flags, holder);
1183-
if (ret == 0 &&
1193+
ret2 = btrfs_open_one_device(fs_devices, device, flags, holder);
1194+
if (ret2 == 0 &&
11841195
(!latest_dev || device->generation > latest_dev->generation)) {
11851196
latest_dev = device;
1186-
} else if (ret == -ENODATA) {
1197+
} else if (ret2 == -ENODATA) {
11871198
fs_devices->num_devices--;
11881199
list_del(&device->dev_list);
11891200
btrfs_free_device(device);
11901201
}
1202+
if (ret == 0 && ret2 != 0)
1203+
ret = ret2;
11911204
}
1192-
if (fs_devices->open_devices == 0)
1205+
1206+
if (fs_devices->open_devices == 0) {
1207+
if (ret)
1208+
return ret;
11931209
return -EINVAL;
1210+
}
11941211

11951212
fs_devices->opened = 1;
11961213
fs_devices->latest_dev = latest_dev;

fs/btrfs/zoned.c

Lines changed: 7 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -1574,11 +1574,7 @@ int btrfs_load_block_group_zone_info(struct btrfs_block_group *cache, bool new)
15741574
if (!map)
15751575
return -EINVAL;
15761576

1577-
cache->physical_map = btrfs_clone_chunk_map(map, GFP_NOFS);
1578-
if (!cache->physical_map) {
1579-
ret = -ENOMEM;
1580-
goto out;
1581-
}
1577+
cache->physical_map = map;
15821578

15831579
zone_info = kcalloc(map->num_stripes, sizeof(*zone_info), GFP_NOFS);
15841580
if (!zone_info) {
@@ -1690,7 +1686,6 @@ int btrfs_load_block_group_zone_info(struct btrfs_block_group *cache, bool new)
16901686
}
16911687
bitmap_free(active);
16921688
kfree(zone_info);
1693-
btrfs_free_chunk_map(map);
16941689

16951690
return ret;
16961691
}
@@ -2175,6 +2170,7 @@ static int do_zone_finish(struct btrfs_block_group *block_group, bool fully_writ
21752170
struct btrfs_chunk_map *map;
21762171
const bool is_metadata = (block_group->flags &
21772172
(BTRFS_BLOCK_GROUP_METADATA | BTRFS_BLOCK_GROUP_SYSTEM));
2173+
struct btrfs_dev_replace *dev_replace = &fs_info->dev_replace;
21782174
int ret = 0;
21792175
int i;
21802176

@@ -2250,6 +2246,7 @@ static int do_zone_finish(struct btrfs_block_group *block_group, bool fully_writ
22502246
btrfs_clear_data_reloc_bg(block_group);
22512247
spin_unlock(&block_group->lock);
22522248

2249+
down_read(&dev_replace->rwsem);
22532250
map = block_group->physical_map;
22542251
for (i = 0; i < map->num_stripes; i++) {
22552252
struct btrfs_device *device = map->stripes[i].dev;
@@ -2266,13 +2263,16 @@ static int do_zone_finish(struct btrfs_block_group *block_group, bool fully_writ
22662263
zinfo->zone_size >> SECTOR_SHIFT);
22672264
memalloc_nofs_restore(nofs_flags);
22682265

2269-
if (ret)
2266+
if (ret) {
2267+
up_read(&dev_replace->rwsem);
22702268
return ret;
2269+
}
22712270

22722271
if (!(block_group->flags & BTRFS_BLOCK_GROUP_DATA))
22732272
zinfo->reserved_active_zones++;
22742273
btrfs_dev_clear_active_zone(device, physical);
22752274
}
2275+
up_read(&dev_replace->rwsem);
22762276

22772277
if (!fully_written)
22782278
btrfs_dec_block_group_ro(block_group);

0 commit comments

Comments
 (0)