Skip to content

Commit 6b49264

Browse files
committed
Merge tag 'for-6.12-rc5-tag' of git://git.kernel.org/pub/scm/linux/kernel/git/kdave/linux
Pull btrfs fixes from David Sterba: "A few more stability fixes. There's one patch adding export of MIPS cmpxchg helper, used in the error propagation fix. - fix error propagation from split bios to the original btrfs bio - fix merging of adjacent extents (normal operation, defragmentation) - fix potential use after free after freeing btrfs device structures" * tag 'for-6.12-rc5-tag' of git://git.kernel.org/pub/scm/linux/kernel/git/kdave/linux: btrfs: fix defrag not merging contiguous extents due to merged extent maps btrfs: fix extent map merging not happening for adjacent extents btrfs: fix use-after-free of block device file in __btrfs_free_extra_devids() btrfs: fix error propagation of split bios MIPS: export __cmpxchg_small()
2 parents 7b83601 + 77b0d11 commit 6b49264

File tree

6 files changed

+29
-30
lines changed

6 files changed

+29
-30
lines changed

arch/mips/kernel/cmpxchg.c

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -102,3 +102,4 @@ unsigned long __cmpxchg_small(volatile void *ptr, unsigned long old,
102102
return old;
103103
}
104104
}
105+
EXPORT_SYMBOL(__cmpxchg_small);

fs/btrfs/bio.c

Lines changed: 13 additions & 24 deletions
Original file line numberDiff line numberDiff line change
@@ -49,6 +49,7 @@ void btrfs_bio_init(struct btrfs_bio *bbio, struct btrfs_fs_info *fs_info,
4949
bbio->end_io = end_io;
5050
bbio->private = private;
5151
atomic_set(&bbio->pending_ios, 1);
52+
WRITE_ONCE(bbio->status, BLK_STS_OK);
5253
}
5354

5455
/*
@@ -113,41 +114,29 @@ static void __btrfs_bio_end_io(struct btrfs_bio *bbio)
113114
}
114115
}
115116

116-
static void btrfs_orig_write_end_io(struct bio *bio);
117-
118-
static void btrfs_bbio_propagate_error(struct btrfs_bio *bbio,
119-
struct btrfs_bio *orig_bbio)
120-
{
121-
/*
122-
* For writes we tolerate nr_mirrors - 1 write failures, so we can't
123-
* just blindly propagate a write failure here. Instead increment the
124-
* error count in the original I/O context so that it is guaranteed to
125-
* be larger than the error tolerance.
126-
*/
127-
if (bbio->bio.bi_end_io == &btrfs_orig_write_end_io) {
128-
struct btrfs_io_stripe *orig_stripe = orig_bbio->bio.bi_private;
129-
struct btrfs_io_context *orig_bioc = orig_stripe->bioc;
130-
131-
atomic_add(orig_bioc->max_errors, &orig_bioc->error);
132-
} else {
133-
orig_bbio->bio.bi_status = bbio->bio.bi_status;
134-
}
135-
}
136-
137117
void btrfs_bio_end_io(struct btrfs_bio *bbio, blk_status_t status)
138118
{
139119
bbio->bio.bi_status = status;
140120
if (bbio->bio.bi_pool == &btrfs_clone_bioset) {
141121
struct btrfs_bio *orig_bbio = bbio->private;
142122

143-
if (bbio->bio.bi_status)
144-
btrfs_bbio_propagate_error(bbio, orig_bbio);
145123
btrfs_cleanup_bio(bbio);
146124
bbio = orig_bbio;
147125
}
148126

149-
if (atomic_dec_and_test(&bbio->pending_ios))
127+
/*
128+
* At this point, bbio always points to the original btrfs_bio. Save
129+
* the first error in it.
130+
*/
131+
if (status != BLK_STS_OK)
132+
cmpxchg(&bbio->status, BLK_STS_OK, status);
133+
134+
if (atomic_dec_and_test(&bbio->pending_ios)) {
135+
/* Load split bio's error which might be set above. */
136+
if (status == BLK_STS_OK)
137+
bbio->bio.bi_status = READ_ONCE(bbio->status);
150138
__btrfs_bio_end_io(bbio);
139+
}
151140
}
152141

153142
static int next_repair_mirror(struct btrfs_failed_bio *fbio, int cur_mirror)

fs/btrfs/bio.h

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -79,6 +79,9 @@ struct btrfs_bio {
7979
/* File system that this I/O operates on. */
8080
struct btrfs_fs_info *fs_info;
8181

82+
/* Save the first error status of split bio. */
83+
blk_status_t status;
84+
8285
/*
8386
* This member must come last, bio_alloc_bioset will allocate enough
8487
* bytes for entire btrfs_bio but relies on bio being last.

fs/btrfs/defrag.c

Lines changed: 5 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -763,12 +763,12 @@ static struct extent_map *defrag_lookup_extent(struct inode *inode, u64 start,
763763
* We can get a merged extent, in that case, we need to re-search
764764
* tree to get the original em for defrag.
765765
*
766-
* If @newer_than is 0 or em::generation < newer_than, we can trust
767-
* this em, as either we don't care about the generation, or the
768-
* merged extent map will be rejected anyway.
766+
* This is because even if we have adjacent extents that are contiguous
767+
* and compatible (same type and flags), we still want to defrag them
768+
* so that we use less metadata (extent items in the extent tree and
769+
* file extent items in the inode's subvolume tree).
769770
*/
770-
if (em && (em->flags & EXTENT_FLAG_MERGED) &&
771-
newer_than && em->generation >= newer_than) {
771+
if (em && (em->flags & EXTENT_FLAG_MERGED)) {
772772
free_extent_map(em);
773773
em = NULL;
774774
}

fs/btrfs/extent_map.c

Lines changed: 6 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -230,7 +230,12 @@ static bool mergeable_maps(const struct extent_map *prev, const struct extent_ma
230230
if (extent_map_end(prev) != next->start)
231231
return false;
232232

233-
if (prev->flags != next->flags)
233+
/*
234+
* The merged flag is not an on-disk flag, it just indicates we had the
235+
* extent maps of 2 (or more) adjacent extents merged, so factor it out.
236+
*/
237+
if ((prev->flags & ~EXTENT_FLAG_MERGED) !=
238+
(next->flags & ~EXTENT_FLAG_MERGED))
234239
return false;
235240

236241
if (next->disk_bytenr < EXTENT_MAP_LAST_BYTE - 1)

fs/btrfs/volumes.c

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1105,6 +1105,7 @@ static void btrfs_close_one_device(struct btrfs_device *device)
11051105
if (device->bdev) {
11061106
fs_devices->open_devices--;
11071107
device->bdev = NULL;
1108+
device->bdev_file = NULL;
11081109
}
11091110
clear_bit(BTRFS_DEV_STATE_WRITEABLE, &device->dev_state);
11101111
btrfs_destroy_dev_zone_info(device);

0 commit comments

Comments
 (0)