mirror of
https://git.kernel.org/pub/scm/linux/kernel/git/stable/linux.git
synced 2024-12-29 09:16:33 +00:00
for-6.12-rc5-tag
-----BEGIN PGP SIGNATURE----- iQIzBAABCgAdFiEE8rQSAMVO+zA4DBdWxWXV+ddtWDsFAmck8eQACgkQxWXV+ddt WDu05g/6AwrnvPkivC4iVOv4Wkzrpk4gm76smx91Y9B8tSDLI1pHaS27CvJz9iWl vBKXPN3PQVQHwo6SPn+NjsFOSMkXlbBOVKpPU+MlZwH9Tuw66qcC+EnUCK2wEuAy 3TN7cUGIA4r/j+SkhgIz+Irlr5pjdb1KkPIMBEVGcVFqDIuvDaTEGBqTn2i/V5aa dMn+gK+9rfngTOJ68t/pEFaX7SEWCvgMIcBpBB4/vs1gHm3ve2bcc1sBAdMxb1Se SrxgZfq+Rc5tkMn540JaWGwkb0rLzwXlurK6ygTKDKCpH0IMX+pBvDkexh9Zj0ux jejlRxiuDzTx3z2a7FjHDyp2sdZWMpq3sPsowpJ1Dsgi5EtSxTy4irmQuSAZY1Uj /uo6YwV9aTGeiNDwZeKqKc/wOuAttaMZLr14s37pro9KxndFJ/XZBxeyB+euUCOw B8AvAQVVIJAYQLyWINWruNKppqlgiO2RaN15RvvT2pX01d0TOx1KX1XFQku7YFxb M/8ZNXzJ96XtkeyHL3euo3zj7N5jWtnCvPINugUG1ADQa+bc8aX336gld1neD6fs QqIFIgzZG0l4N95viJilACrI6tW9zFnBqMyNFRhucKiX9aP9glOvhSfxfjcpDuQ/ i/LIyxVLwp8M3hPNvv8tC345+1C2ug9AD0OyhWjjIYPuiOxtTWs= =alpB -----END PGP SIGNATURE----- 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()
This commit is contained in:
commit
6b4926494e
@ -102,3 +102,4 @@ unsigned long __cmpxchg_small(volatile void *ptr, unsigned long old,
|
|||||||
return old;
|
return old;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
EXPORT_SYMBOL(__cmpxchg_small);
|
||||||
|
@ -49,6 +49,7 @@ void btrfs_bio_init(struct btrfs_bio *bbio, struct btrfs_fs_info *fs_info,
|
|||||||
bbio->end_io = end_io;
|
bbio->end_io = end_io;
|
||||||
bbio->private = private;
|
bbio->private = private;
|
||||||
atomic_set(&bbio->pending_ios, 1);
|
atomic_set(&bbio->pending_ios, 1);
|
||||||
|
WRITE_ONCE(bbio->status, BLK_STS_OK);
|
||||||
}
|
}
|
||||||
|
|
||||||
/*
|
/*
|
||||||
@ -113,41 +114,29 @@ static void __btrfs_bio_end_io(struct btrfs_bio *bbio)
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
static void btrfs_orig_write_end_io(struct bio *bio);
|
|
||||||
|
|
||||||
static void btrfs_bbio_propagate_error(struct btrfs_bio *bbio,
|
|
||||||
struct btrfs_bio *orig_bbio)
|
|
||||||
{
|
|
||||||
/*
|
|
||||||
* For writes we tolerate nr_mirrors - 1 write failures, so we can't
|
|
||||||
* just blindly propagate a write failure here. Instead increment the
|
|
||||||
* error count in the original I/O context so that it is guaranteed to
|
|
||||||
* be larger than the error tolerance.
|
|
||||||
*/
|
|
||||||
if (bbio->bio.bi_end_io == &btrfs_orig_write_end_io) {
|
|
||||||
struct btrfs_io_stripe *orig_stripe = orig_bbio->bio.bi_private;
|
|
||||||
struct btrfs_io_context *orig_bioc = orig_stripe->bioc;
|
|
||||||
|
|
||||||
atomic_add(orig_bioc->max_errors, &orig_bioc->error);
|
|
||||||
} else {
|
|
||||||
orig_bbio->bio.bi_status = bbio->bio.bi_status;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
void btrfs_bio_end_io(struct btrfs_bio *bbio, blk_status_t status)
|
void btrfs_bio_end_io(struct btrfs_bio *bbio, blk_status_t status)
|
||||||
{
|
{
|
||||||
bbio->bio.bi_status = status;
|
bbio->bio.bi_status = status;
|
||||||
if (bbio->bio.bi_pool == &btrfs_clone_bioset) {
|
if (bbio->bio.bi_pool == &btrfs_clone_bioset) {
|
||||||
struct btrfs_bio *orig_bbio = bbio->private;
|
struct btrfs_bio *orig_bbio = bbio->private;
|
||||||
|
|
||||||
if (bbio->bio.bi_status)
|
|
||||||
btrfs_bbio_propagate_error(bbio, orig_bbio);
|
|
||||||
btrfs_cleanup_bio(bbio);
|
btrfs_cleanup_bio(bbio);
|
||||||
bbio = orig_bbio;
|
bbio = orig_bbio;
|
||||||
}
|
}
|
||||||
|
|
||||||
if (atomic_dec_and_test(&bbio->pending_ios))
|
/*
|
||||||
|
* At this point, bbio always points to the original btrfs_bio. Save
|
||||||
|
* the first error in it.
|
||||||
|
*/
|
||||||
|
if (status != BLK_STS_OK)
|
||||||
|
cmpxchg(&bbio->status, BLK_STS_OK, status);
|
||||||
|
|
||||||
|
if (atomic_dec_and_test(&bbio->pending_ios)) {
|
||||||
|
/* Load split bio's error which might be set above. */
|
||||||
|
if (status == BLK_STS_OK)
|
||||||
|
bbio->bio.bi_status = READ_ONCE(bbio->status);
|
||||||
__btrfs_bio_end_io(bbio);
|
__btrfs_bio_end_io(bbio);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
static int next_repair_mirror(struct btrfs_failed_bio *fbio, int cur_mirror)
|
static int next_repair_mirror(struct btrfs_failed_bio *fbio, int cur_mirror)
|
||||||
|
@ -79,6 +79,9 @@ struct btrfs_bio {
|
|||||||
/* File system that this I/O operates on. */
|
/* File system that this I/O operates on. */
|
||||||
struct btrfs_fs_info *fs_info;
|
struct btrfs_fs_info *fs_info;
|
||||||
|
|
||||||
|
/* Save the first error status of split bio. */
|
||||||
|
blk_status_t status;
|
||||||
|
|
||||||
/*
|
/*
|
||||||
* This member must come last, bio_alloc_bioset will allocate enough
|
* This member must come last, bio_alloc_bioset will allocate enough
|
||||||
* bytes for entire btrfs_bio but relies on bio being last.
|
* bytes for entire btrfs_bio but relies on bio being last.
|
||||||
|
@ -763,12 +763,12 @@ static struct extent_map *defrag_lookup_extent(struct inode *inode, u64 start,
|
|||||||
* We can get a merged extent, in that case, we need to re-search
|
* We can get a merged extent, in that case, we need to re-search
|
||||||
* tree to get the original em for defrag.
|
* tree to get the original em for defrag.
|
||||||
*
|
*
|
||||||
* If @newer_than is 0 or em::generation < newer_than, we can trust
|
* This is because even if we have adjacent extents that are contiguous
|
||||||
* this em, as either we don't care about the generation, or the
|
* and compatible (same type and flags), we still want to defrag them
|
||||||
* merged extent map will be rejected anyway.
|
* so that we use less metadata (extent items in the extent tree and
|
||||||
|
* file extent items in the inode's subvolume tree).
|
||||||
*/
|
*/
|
||||||
if (em && (em->flags & EXTENT_FLAG_MERGED) &&
|
if (em && (em->flags & EXTENT_FLAG_MERGED)) {
|
||||||
newer_than && em->generation >= newer_than) {
|
|
||||||
free_extent_map(em);
|
free_extent_map(em);
|
||||||
em = NULL;
|
em = NULL;
|
||||||
}
|
}
|
||||||
|
@ -230,7 +230,12 @@ static bool mergeable_maps(const struct extent_map *prev, const struct extent_ma
|
|||||||
if (extent_map_end(prev) != next->start)
|
if (extent_map_end(prev) != next->start)
|
||||||
return false;
|
return false;
|
||||||
|
|
||||||
if (prev->flags != next->flags)
|
/*
|
||||||
|
* The merged flag is not an on-disk flag, it just indicates we had the
|
||||||
|
* extent maps of 2 (or more) adjacent extents merged, so factor it out.
|
||||||
|
*/
|
||||||
|
if ((prev->flags & ~EXTENT_FLAG_MERGED) !=
|
||||||
|
(next->flags & ~EXTENT_FLAG_MERGED))
|
||||||
return false;
|
return false;
|
||||||
|
|
||||||
if (next->disk_bytenr < EXTENT_MAP_LAST_BYTE - 1)
|
if (next->disk_bytenr < EXTENT_MAP_LAST_BYTE - 1)
|
||||||
|
@ -1105,6 +1105,7 @@ static void btrfs_close_one_device(struct btrfs_device *device)
|
|||||||
if (device->bdev) {
|
if (device->bdev) {
|
||||||
fs_devices->open_devices--;
|
fs_devices->open_devices--;
|
||||||
device->bdev = NULL;
|
device->bdev = NULL;
|
||||||
|
device->bdev_file = NULL;
|
||||||
}
|
}
|
||||||
clear_bit(BTRFS_DEV_STATE_WRITEABLE, &device->dev_state);
|
clear_bit(BTRFS_DEV_STATE_WRITEABLE, &device->dev_state);
|
||||||
btrfs_destroy_dev_zone_info(device);
|
btrfs_destroy_dev_zone_info(device);
|
||||||
|
Loading…
Reference in New Issue
Block a user