FAILED: patch "[PATCH] btrfs: zoned: clone zoned device info when cloning a device" failed to apply to 5.15-stable tree
Subsystems (2)
[email protected]
maintainerThe patch below does not apply to the 5.15-stable tree.
If someone wants it applied there, or to any other stable or longterm tree, then please email the backport, including the original git commit id to <[email protected]>.
Possible dependencies:
21e61ec6d0bb ("btrfs: zoned: clone zoned device info when cloning a device")
thanks,
greg k-h
------------------ original commit in Linus's tree ------------------
From 21e61ec6d0bb786818490e926aa9aeb4de95ad0d Mon Sep 17 00:00:00 2001
From: Johannes Thumshirn <[email protected]>
Date: Fri, 4 Nov 2022 07:12:33 -0700
Subject: [PATCH] btrfs: zoned: clone zoned device info when cloning a device
When cloning a btrfs_device, we're not cloning the associated btrfs_zoned_device_info structure of the device in case of a zoned filesystem.
Later on this leads to a NULL pointer dereference when accessing the device's zone_info for instance when setting a zone as active.
This was uncovered by fstests' testcase btrfs/161.
fs/btrfs/volumes.c +12 -0
@@ -1011,6 +1011,18 @@ static struct btrfs_fs_devices *clone_fs_devices(struct btrfs_fs_devices *orig)rcu_assign_pointer (device->name, name); } +if (orig_dev->zone_info) { +struct btrfs_zoned_device_info *zone_info; + + zone_info =btrfs_clone_dev_zone_info (orig_dev); +if (!zone_info) { +btrfs_free_device (device); + ret = -ENOMEM ; + goto error; + } + device->zone_info = zone_info; + } +list_add (&device->dev_list, &fs_devices->devices); device->fs_devices = fs_devices; fs_devices->num_devices++;
fs/btrfs/zoned.c +40 -0
@@ -639,6 +639,46 @@ void btrfs_destroy_dev_zone_info(struct btrfs_device *device) device->zone_info =NULL ; } +struct btrfs_zoned_device_info *btrfs_clone_dev_zone_info (struct btrfs_device *orig_dev) +{ +struct btrfs_zoned_device_info *zone_info; + + zone_info =kmemdup (orig_dev->zone_info,sizeof (*zone_info),GFP_KERNEL ); +if (!zone_info) +return NULL ; + + zone_info->seq_zones =bitmap_zalloc (zone_info->nr_zones,GFP_KERNEL ); +if (!zone_info->seq_zones) + goto out; + +bitmap_copy (zone_info->seq_zones, orig_dev->zone_info->seq_zones, + zone_info->nr_zones); + + zone_info->empty_zones =bitmap_zalloc (zone_info->nr_zones,GFP_KERNEL ); +if (!zone_info->empty_zones) + goto out; + +bitmap_copy (zone_info->empty_zones, orig_dev->zone_info->empty_zones, + zone_info->nr_zones); + + zone_info->active_zones =bitmap_zalloc (zone_info->nr_zones,GFP_KERNEL ); +if (!zone_info->active_zones) + goto out; + +bitmap_copy (zone_info->active_zones, orig_dev->zone_info->active_zones, + zone_info->nr_zones); + zone_info->zone_cache =NULL ; + +return zone_info; + +out: +bitmap_free (zone_info->seq_zones); +bitmap_free (zone_info->empty_zones); +bitmap_free (zone_info->active_zones); +kfree (zone_info); +return NULL ; +} +int btrfs_get_dev_zone (struct btrfs_device *device,u64 pos,struct blk_zone *zone) {
fs/btrfs/zoned.h +11 -0
@@ -36,6 +36,7 @@ int btrfs_get_dev_zone(struct btrfs_device *device, u64 pos,int btrfs_get_dev_zone_info_all_devices (struct btrfs_fs_info *fs_info);int btrfs_get_dev_zone_info (struct btrfs_device *device,bool populate_cache);void btrfs_destroy_dev_zone_info (struct btrfs_device *device); +struct btrfs_zoned_device_info *btrfs_clone_dev_zone_info (struct btrfs_device *orig_dev);int btrfs_check_zoned_mode (struct btrfs_fs_info *fs_info);int btrfs_check_mountopts_zoned (struct btrfs_fs_info *info); int btrfs_sb_log_location_bdev(struct block_device *bdev, int mirror, int rw,
@@ -103,6 +104,16 @@ static inline int btrfs_get_dev_zone_info(struct btrfs_device *device,static inline void btrfs_destroy_dev_zone_info (struct btrfs_device *device) { } +/* +* In case the kernel is compiled without CONFIG_BLK_DEV_ZONED we'll never call +* into btrfs_clone_dev_zone_info() so it's safe to return NULL here. +*/ +static inline struct btrfs_zoned_device_info *btrfs_clone_dev_zone_info ( +struct btrfs_device *orig_dev) +{ +return NULL ; +} +static inline int btrfs_check_zoned_mode (const struct btrfs_fs_info *fs_info) {if (!btrfs_is_zoned (fs_info))