md: align bio to io_opt for better performance
v4 cover md: align bio to io_opt for better performance
This patchset optimizes MD RAID performance by aligning bios to the optimal I/O size before splitting. When I/O is aligned to io_opt, raid5 can perform full stripe writes without needing to read extra data for parity calculation, significantly improving bandwidth.
Patches 1-3: Cleanup - merge boolean fields into mddev_flags Patches 4-5: Preparation - use mempool for stripe_request_ctx and
ensure max_sectors >= io_opt
Patches 6-7: Core - add bio alignment infrastructure Patches 8-10: Enable bio alignment for raid5, raid10, and raid0 Patch 11: Fix abnormal io_opt from member disks
Performance improvement on 32-disk raid5 with 64kb chunk:
dd if=/dev/zero of=/dev/md0 bs=100M oflag=direct
Before: 782 MB/s
After: 1.1 GB/s
Changes in v4:
- Patch 11: Simplify by checking rdev_is_mddev() first, remove MD_STACK_IO_OPT flag
Changes in v3:
- Patch 4: Remove unnecessary NULL check before mempool_destroy()
- Patch 6: Use sector_div() instead of roundup()/rounddown() to fix 64-bit division issue on 32-bit platforms
Changes in v2:
- Fix mempool in patch 4
- Add prep cleanup patches, 1-3
- Add patch 11 to fix abnormal io_opt
- Add Link tags to patches
Yu Kuai (11):
md: merge mddev has_superblock into mddev_flags
md: merge mddev faillast_dev into mddev_flags
md: merge mddev serialize_policy into mddev_flags md/raid5: use mempool to allocate stripe_request_ctx md/raid5: make sure max_sectors is not less than io_opt
md: support to align bio to limits
md: add a helper md_config_align_limits() md/raid5: align bio to io_opt
md/raid10: align bio to io_opt
md/raid0: align bio to io_opt
md: fix abnormal io_opt from member disks
drivers/md/md-bitmap.c | 4 +- drivers/md/md.c | 118 +++++++++++++++++++++++++++++++++++------ drivers/md/md.h | 30 +++++++++-- drivers/md/raid0.c | 6 ++- drivers/md/raid1-10.c | 5 -- drivers/md/raid1.c | 13 ++--- drivers/md/raid10.c | 10 ++-- drivers/md/raid5.c | 92 ++++++++++++++++++++++---------- drivers/md/raid5.h | 3 ++ 9 files changed, 215 insertions(+), 66 deletions(-)
Signature · 1 line
2.51.0
PATCH v4 1/11 md: merge mddev has_superblock into mddev_flags
There is not need to use a separate field in struct mddev, there are no functional changes.
--- drivers/md/md.c | 6 +++--- drivers/md/md.h | 3 ++- 2 files changed, 5 insertions(+), 4 deletions(-)
drivers/md/md.c +3 -3
@@ -6463,7 +6463,7 @@ int md_run(struct mddev *mddev)* the only valid external interface is through the md * device. */ - mddev->has_superblocks = false; +clear_bit (MD_HAS_SUPERBLOCK , &mddev->flags);rdev_for_each (rdev, mddev) {if (test_bit (Faulty, &rdev->flags))continue ;
@@ -6476,7 +6476,7 @@ int md_run(struct mddev *mddev) }if (rdev->sb_page) - mddev->has_superblocks = true; +set_bit (MD_HAS_SUPERBLOCK , &mddev->flags);/* perform some consistency tests on the device. * We don't want the data to overlap the metadata,
@@ -9086,7 +9086,7 @@ void md_write_start(struct mddev *mddev, struct bio *bi)rcu_read_unlock ();if (did_change)sysfs_notify_dirent_safe (mddev->sysfs_state); -if (!mddev->has_superblocks) +if (!test_bit (MD_HAS_SUPERBLOCK , &mddev->flags))return ;wait_event (mddev->sb_wait, !test_bit (MD_SB_CHANGE_PENDING , &mddev->sb_flags));
drivers/md/md.h +2 -1
@@ -340,6 +340,7 @@ struct md_cluster_operations;* array is ready yet. * @MD_BROKEN: This is used to stop writes and mark array as failed. * @MD_DELETED: This device is being deleted +* @MD_HAS_SUPERBLOCK: There is persistence sb in member disks. * * change UNSUPPORTED_MDDEV_FLAGS for each array type if new flag is added */
@@ -356,6 +357,7 @@ enum mddev_flags {MD_BROKEN ,MD_DO_DELETE ,MD_DELETED , + MD_HAS_SUPERBLOCK, }; enum mddev_sb_flags {
@@ -623,7 +625,6 @@ struct mddev {/* The sequence number for sync thread */ atomic_t sync_seq; - bool has_superblocks:1; bool fail_last_dev:1; bool serialize_policy:1; };
Signature · 1 line
2.51.0
PATCH v4 2/11 md: merge mddev faillast_dev into mddev_flags
In reply to Yu KuaiThere is not need to use a separate field in struct mddev, there are no functional changes.
--- drivers/md/md.c | 10 ++++++---- drivers/md/md.h | 3 ++- drivers/md/raid0.c | 3 ++- drivers/md/raid1.c | 4 ++-- drivers/md/raid10.c | 4 ++-- drivers/md/raid5.c | 5 ++++- 6 files changed, 18 insertions(+), 11 deletions(-)
drivers/md/md.c +6 -4
@@ -5865,11 +5865,11 @@ __ATTR(consistency_policy, S_IRUGO | S_IWUSR, consistency_policy_show,static ssize_t fail_last_dev_show (struct mddev *mddev,char *page) { -return sprintf (page,"%d\n" , mddev->fail_last_dev); +return sprintf (page,"%d\n" ,test_bit (MD_FAILLAST_DEV , &mddev->flags)); }/* -* Setting fail_last_dev to true to allow last device to be forcibly removed +* Setting MD_FAILLAST_DEV to allow last device to be forcibly removed * from RAID1/RAID10. */ static ssize_t
@@ -5882,8 +5882,10 @@ fail_last_dev_store(struct mddev *mddev, const char *buf, size_t len)if (ret)return ret; -if (value != mddev->fail_last_dev) - mddev->fail_last_dev = value; +if (value) +set_bit (MD_FAILLAST_DEV , &mddev->flags); +else +clear_bit (MD_FAILLAST_DEV , &mddev->flags);return len; }
drivers/md/md.h +2 -1
@@ -341,6 +341,7 @@ struct md_cluster_operations;* @MD_BROKEN: This is used to stop writes and mark array as failed. * @MD_DELETED: This device is being deleted * @MD_HAS_SUPERBLOCK: There is persistence sb in member disks. +* @MD_FAILLAST_DEV: Allow last rdev to be removed. * * change UNSUPPORTED_MDDEV_FLAGS for each array type if new flag is added */
@@ -358,6 +359,7 @@ enum mddev_flags {MD_DO_DELETE ,MD_DELETED ,MD_HAS_SUPERBLOCK , + MD_FAILLAST_DEV, }; enum mddev_sb_flags {
@@ -625,7 +627,6 @@ struct mddev {/* The sequence number for sync thread */ atomic_t sync_seq; - bool fail_last_dev:1; bool serialize_policy:1; };
drivers/md/raid0.c +2 -1
@@ -27,7 +27,8 @@ module_param(default_layout, int, 0644); (1L <<MD_JOURNAL_CLEAN ) | \ (1L <<MD_FAILFAST_SUPPORTED ) |\ (1L <<MD_HAS_PPL ) | \ - (1L << MD_HAS_MULTIPLE_PPLS)) + (1L <<MD_HAS_MULTIPLE_PPLS ) | \ + (1L << MD_FAILLAST_DEV))/* * inform the user of the raid configuration
drivers/md/raid1.c +2 -2
@@ -1746,7 +1746,7 @@ static void raid1_status(struct seq_file *seq, struct mddev *mddev)* - &mddev->degraded is bumped. * * @rdev is marked as &Faulty excluding case when array is failed and -* &mddev->fail_last_dev is off. +* MD_FAILLAST_DEV is not set. */ static void raid1_error (struct mddev *mddev,struct md_rdev *rdev) {
@@ -1759,7 +1759,7 @@ static void raid1_error(struct mddev *mddev, struct md_rdev *rdev) (conf->raid_disks - mddev->degraded) == 1) {set_bit (MD_BROKEN , &mddev->flags); -if (!mddev->fail_last_dev) { +if (!test_bit (MD_FAILLAST_DEV , &mddev->flags)) { conf->recovery_disabled = mddev->recovery_disabled;spin_unlock_irqrestore (&conf->device_lock, flags);return ;
drivers/md/raid10.c +2 -2
@@ -1990,7 +1990,7 @@ static int enough(struct r10conf *conf, int ignore)* - &mddev->degraded is bumped. * * @rdev is marked as &Faulty excluding case when array is failed and -* &mddev->fail_last_dev is off. +* MD_FAILLAST_DEV is not set. */ static void raid10_error (struct mddev *mddev,struct md_rdev *rdev) {
@@ -2002,7 +2002,7 @@ static void raid10_error(struct mddev *mddev, struct md_rdev *rdev)if (test_bit (In_sync, &rdev->flags) && !enough (conf, rdev->raid_disk)) {set_bit (MD_BROKEN , &mddev->flags); -if (!mddev->fail_last_dev) { +if (!test_bit (MD_FAILLAST_DEV , &mddev->flags)) {spin_unlock_irqrestore (&conf->device_lock, flags);return ; }
drivers/md/raid5.c +4 -1
@@ -56,7 +56,10 @@#include "md-bitmap.h" #include "raid5-log.h" -#define UNSUPPORTED_MDDEV_FLAGS (1L << MD_FAILFAST_SUPPORTED) +#define UNSUPPORTED_MDDEV_FLAGS \ + ((1L << MD_FAILFAST_SUPPORTED) | \ + (1L << MD_FAILLAST_DEV)) +#define cpu_to_group (cpu) cpu_to_node(cpu)#define ANY_GROUP NUMA_NO_NODE
Signature · 1 line
2.51.0
PATCH v4 3/11 md: merge mddev serialize_policy into mddev_flags
In reply to Yu KuaiThere is not need to use a separate field in struct mddev, there are no functional changes.
--- drivers/md/md-bitmap.c | 4 ++-- drivers/md/md.c | 20 ++++++++++++-------- drivers/md/md.h | 4 ++-- drivers/md/raid0.c | 3 ++- drivers/md/raid1.c | 4 ++-- drivers/md/raid5.c | 3 ++- 6 files changed, 22 insertions(+), 16 deletions(-)
drivers/md/md-bitmap.c +2 -2
@@ -2085,7 +2085,7 @@ static void bitmap_destroy(struct mddev *mddev)return ;bitmap_wait_behind_writes (mddev); -if (!mddev->serialize_policy) +if (!test_bit (MD_SERIALIZE_POLICY , &mddev->flags))mddev_destroy_serial_pool (mddev,NULL );mutex_lock (&mddev->bitmap_info.mutex);
@@ -2809,7 +2809,7 @@ backlog_store(struct mddev *mddev, const char *buf, size_t len) mddev->bitmap_info.max_write_behind = backlog;if (!backlog && mddev->serial_info_pool) {/* serial_info_pool is not needed if backlog is zero */ -if (!mddev->serialize_policy) +if (!test_bit (MD_SERIALIZE_POLICY , &mddev->flags))mddev_destroy_serial_pool (mddev,NULL ); }else if (backlog && !mddev->serial_info_pool) {/* serial_info_pool is needed since backlog is not zero */
drivers/md/md.c +12 -8
@@ -279,7 +279,8 @@ void mddev_destroy_serial_pool(struct mddev *mddev, struct md_rdev *rdev)rdev_for_each (temp, mddev) {if (!rdev) { -if (!mddev->serialize_policy || +if (!test_bit (MD_SERIALIZE_POLICY , + &mddev->flags) || !rdev_need_serial (temp))rdev_uninit_serial (temp);else
@@ -5898,11 +5899,12 @@ static ssize_t serialize_policy_show(struct mddev *mddev, char *page)if (mddev->pers ==NULL || (mddev->pers->head.id !=ID_RAID1 ))return sprintf (page,"n/a\n" );else -return sprintf (page,"%d\n" , mddev->serialize_policy); +return sprintf (page,"%d\n" , +test_bit (MD_SERIALIZE_POLICY , &mddev->flags)); }/* -* Setting serialize_policy to true to enforce write IO is not reordered +* Setting MD_SERIALIZE_POLICY enforce write IO is not reordered * for raid1. */ static ssize_t
@@ -5915,7 +5917,7 @@ serialize_policy_store(struct mddev *mddev, const char *buf, size_t len)if (err)return err; -if (value == mddev->serialize_policy) +if (value ==test_bit (MD_SERIALIZE_POLICY , &mddev->flags))return len; err =mddev_suspend_and_lock (mddev);
@@ -5927,11 +5929,13 @@ serialize_policy_store(struct mddev *mddev, const char *buf, size_t len) goto unlock; } -if (value) +if (value) {mddev_create_serial_pool (mddev,NULL ); -else +set_bit (MD_SERIALIZE_POLICY , &mddev->flags); + }else {mddev_destroy_serial_pool (mddev,NULL ); - mddev->serialize_policy = value; +clear_bit (MD_SERIALIZE_POLICY , &mddev->flags); + } unlock:mddev_unlock_and_resume (mddev);return err ?: len;
@@ -6828,7 +6832,7 @@ static void __md_stop_writes(struct mddev *mddev)md_update_sb (mddev,1 ); }/* disable policy to guarantee rdevs free resources for serialization */ - mddev->serialize_policy =0 ; +clear_bit (MD_SERIALIZE_POLICY , &mddev->flags);mddev_destroy_serial_pool (mddev,NULL ); }
drivers/md/md.h +2 -2
@@ -342,6 +342,7 @@ struct md_cluster_operations;* @MD_DELETED: This device is being deleted * @MD_HAS_SUPERBLOCK: There is persistence sb in member disks. * @MD_FAILLAST_DEV: Allow last rdev to be removed. +* @MD_SERIALIZE_POLICY: Enforce write IO is not reordered, just used by raid1. * * change UNSUPPORTED_MDDEV_FLAGS for each array type if new flag is added */
@@ -360,6 +361,7 @@ enum mddev_flags {MD_DELETED ,MD_HAS_SUPERBLOCK ,MD_FAILLAST_DEV , + MD_SERIALIZE_POLICY, }; enum mddev_sb_flags {
@@ -626,8 +628,6 @@ struct mddev {/* The sequence number for sync thread */ atomic_t sync_seq; - - bool serialize_policy:1; };enum recovery_flags {
drivers/md/raid0.c +2 -1
@@ -28,7 +28,8 @@ module_param(default_layout, int, 0644); (1L <<MD_FAILFAST_SUPPORTED ) |\ (1L <<MD_HAS_PPL ) | \ (1L <<MD_HAS_MULTIPLE_PPLS ) | \ - (1L << MD_FAILLAST_DEV)) + (1L <<MD_FAILLAST_DEV ) | \ + (1L << MD_SERIALIZE_POLICY))/* * inform the user of the raid configuration
drivers/md/raid1.c +2 -2
@@ -542,7 +542,7 @@ static void raid1_end_write_request(struct bio *bio)call_bio_endio (r1_bio); } } - }else if (rdev->mddev->serialize_policy) + }else if (test_bit (MD_SERIALIZE_POLICY , &rdev->mddev->flags))remove_serial (rdev, lo, hi);if (r1_bio->bios[mirror] ==NULL )rdev_dec_pending (rdev, conf->mddev);
@@ -1644,7 +1644,7 @@ static void raid1_write_request(struct mddev *mddev, struct bio *bio, mbio =bio_alloc_clone (rdev->bdev, bio,GFP_NOIO , &mddev->bio_set); -if (mddev->serialize_policy) +if (test_bit (MD_SERIALIZE_POLICY , &mddev->flags))wait_for_serialization (rdev, r1_bio); }
drivers/md/raid5.c +2 -1
@@ -58,7 +58,8 @@#define UNSUPPORTED_MDDEV_FLAGS \ ((1L << MD_FAILFAST_SUPPORTED) | \ - (1L << MD_FAILLAST_DEV)) + (1L << MD_FAILLAST_DEV) | \ + (1L << MD_SERIALIZE_POLICY))#define cpu_to_group (cpu) cpu_to_node(cpu)
Signature · 1 line
2.51.0
PATCH v4 4/11 md/raid5: use mempool to allocate stripe_request_ctx
In reply to Yu KuaiOn the one hand, stripe_request_ctx is 72 bytes, and it's a bit huge for a stack variable.
On the other hand, the bitmap sectors_to_do is a fixed size, result in max_hw_sector_kb of raid5 array is at most 256 * 4k = 1Mb, and this will make full stripe IO impossible for the array that chunk_size * data_disks is bigger. Allocate ctx during runtime will make it possible to get rid of this limit.
--- drivers/md/md.h | 4 +++ drivers/md/raid1-10.c | 5 ---- drivers/md/raid5.c | 61 +++++++++++++++++++++++++++---------------- drivers/md/raid5.h | 2 ++ 4 files changed, 45 insertions(+), 27 deletions(-)
drivers/md/md.h +4 -0
@@ -22,6 +22,10 @@#include <trace/events/block.h> #define MaxSector (~(sector_t)0) +/* +* Number of guaranteed raid bios in case of extreme VM load: +*/ +#define NR_RAID_BIOS 256enum md_submodule_type {MD_PERSONALITY =0 ,
drivers/md/raid1-10.c +0 -5
@@ -3,11 +3,6 @@#define RESYNC_BLOCK_SIZE (64*1024)#define RESYNC_PAGES ((RESYNC_BLOCK_SIZE + PAGE_SIZE-1) / PAGE_SIZE) -/* -* Number of guaranteed raid bios in case of extreme VM load: -*/ -#define NR_RAID_BIOS 256 -/* when we get a read error on a read-only array, we redirect to another * device without failing the first device, or trying to over-write to * correct the read error. To keep track of bad blocks on a per-bio
drivers/md/raid5.c +39 -22
137 lines not on this page · raw message
drivers/md/raid5.h +2 -0
@@ -690,6 +690,8 @@ struct r5conf {struct list_head pending_list;int pending_data_cnt;struct r5pending_data *next_pending_data; + +mempool_t *ctx_pool; };#if PAGE_SIZE ==DEFAULT_STRIPE_SIZE
Signature · 1 line
2.51.0
PATCH v4 5/11 md/raid5: make sure max_sectors is not less than io_opt
In reply to Yu KuaiOtherwise, even if user issue IO by io_opt, such IO will be split by max_sectors before they are submitted to raid5. For consequence, full stripe IO is impossible.
BTW, dm-raid5 is not affected and still have such problem.
--- drivers/md/raid5.c | 38 ++++++++++++++++++++++++++++---------- drivers/md/raid5.h | 1 + 2 files changed, 29 insertions(+), 10 deletions(-)
drivers/md/raid5.c +28 -10
@@ -777,14 +777,14 @@ struct stripe_request_ctx {/* last sector in the request */ sector_t last_sector; +/* the request had REQ_PREFLUSH, cleared after the first stripe_head */ +bool do_flush; +/* * bitmap to track stripe sectors that have been added to stripes * add one to account for unaligned requests */ -DECLARE_BITMAP (sectors_to_do,RAID5_MAX_REQ_STRIPES +1 ); - -/* the request had REQ_PREFLUSH, cleared after the first stripe_head */ -bool do_flush; +unsigned long sectors_to_do[]; };/*
@@ -6127,7 +6127,7 @@ static bool raid5_make_request(struct mddev *mddev, struct bio * bi) bi->bi_next =NULL ; ctx =mempool_alloc (conf->ctx_pool,GFP_NOIO ); -memset (ctx,0 ,sizeof (*ctx)); +memset (ctx,0 , conf->ctx_size); ctx->first_sector = logical_sector; ctx->last_sector =bio_end_sector (bi);/*
@@ -7741,6 +7741,25 @@ static int only_parity(int raid_disk, int algo, int raid_disks, int max_degradedreturn 0 ; } +static int raid5_create_ctx_pool (struct r5conf *conf) +{ +struct stripe_request_ctx *ctx; +int size; + +if (mddev_is_dm (conf->mddev)) + size =BITS_TO_LONGS (RAID5_MAX_REQ_STRIPES ); +else + size =BITS_TO_LONGS ( +queue_max_hw_sectors (conf->mddev->gendisk->queue) >> +RAID5_STRIPE_SHIFT (conf)); + + conf->ctx_size =struct_size (ctx, sectors_to_do, size); + conf->ctx_pool =mempool_create_kmalloc_pool (NR_RAID_BIOS , + conf->ctx_size); + +return conf->ctx_pool ?0 : -ENOMEM ; +} +static int raid5_set_limits (struct mddev *mddev) {struct r5conf *conf = mddev->private;
@@ -7797,6 +7816,8 @@ static int raid5_set_limits(struct mddev *mddev)* Limit the max sectors based on this. */ lim.max_hw_sectors =RAID5_MAX_REQ_STRIPES <<RAID5_STRIPE_SHIFT (conf); +if ((lim.max_hw_sectors <<9 ) < lim.io_opt) + lim.max_hw_sectors = lim.io_opt >>9 ;/* No restrictions on the number of segments in the request */ lim.max_segments =USHRT_MAX ;
@@ -8069,12 +8090,9 @@ static int raid5_run(struct mddev *mddev) goto abort; } - conf->ctx_pool =mempool_create_kmalloc_pool (NR_RAID_BIOS , -sizeof (struct stripe_request_ctx )); -if (!conf->ctx_pool) { - ret = -ENOMEM ; + ret =raid5_create_ctx_pool (conf); +if (ret) goto abort; - }if (log_init (conf, journal_dev,raid5_has_ppl (conf))) goto abort;
drivers/md/raid5.h +1 -0
@@ -692,6 +692,7 @@ struct r5conf {struct r5pending_data *next_pending_data;mempool_t *ctx_pool; +int ctx_size; };#if PAGE_SIZE ==DEFAULT_STRIPE_SIZE
Signature · 1 line
2.51.0
Dan Carpenter
build botRe: [PATCH v4 05/11] md/raid5: make sure max_sectors is not less than io_opt
BCC: [email protected] CC: [email protected] In-Reply-To: <[email protected]> References: <[email protected]> TO: Yu Kuai <[email protected]>…
BCC: [email protected]
CC: [email protected]
In-Reply-To: <[email protected]>
References: <[email protected]>
TO: Yu Kuai <[email protected]>
TO: [email protected]
TO: [email protected]
CC: [email protected]
Hi Yu,
kernel test robot noticed the following build warnings:
[auto build test WARNING on linus/master]
[also build test WARNING on v6.19-rc5 next-20260109]
[cannot apply to song-md/md-next]
[If your patch is applied to the wrong git tree, kindly drop us a note. And when submitting patch, we suggest to use '--base' as documented in
https://git-scm.com/docs/git-format-patch#_base_tree_information]
url: https://github.com/intel-lab-lkp/linux/commits/Yu-Kuai/md-merge-mddev-has_superblock-into-mddev_flags/20260112-123233 base: linus/master patch link: https://lore.kernel.org/r/20260112042857.2334264-6-yukuai%40fnnas.com patch subject: [PATCH v4 05/11] md/raid5: make sure max_sectors is not less than io_opt
:::::: branch date: 18 hours ago
:::::: commit date: 18 hours ago
config: i386-randconfig-141-20260113 (https://download.01.org/0day-ci/archive/20260113/[email protected]/config)
compiler: gcc-14 (Debian 14.2.0-19) 14.2.0
smatch version: v0.5.0-8985-g2614ff1a
If you fix the issue in a separate patch/commit (i.e. not just a new version of the same patch/commit), kindly add following tags
| Reported-by: kernel test robot <[email protected]> | Reported-by: Dan Carpenter <[email protected]> | Closes: https://lore.kernel.org/r/[email protected]/
New smatch warnings:drivers/md/raid5.c:8100 raid5_run() warn: missing error code 'ret'
Old smatch warnings:drivers/md/raid5.c:2880 raid5_end_write_request() error: uninitialized symbol 'rdev'. drivers/md/raid5.c:2885 raid5_end_write_request() error: uninitialized symbol 'rdev'. drivers/md/raid5.c:8580 raid5_start_reshape() warn: mixing irq and irqsave
vim +/ret +8100 drivers/md/raid5.c
16ef510139315a Christoph Hellwig 2020-09-24 7829
849674e4fb175e Shaohua Li 2016-01-20 7830 static int raid5_run(struct mddev *mddev)
91adb56473febe NeilBrown 2009-03-31 7831 {
d1688a6d5515f1 NeilBrown 2011-10-11 7832 struct r5conf *conf;
c148ffdcda00b6 NeilBrown 2009-11-13 7833 int dirty_parity_disks = 0;
3cb03002000f13 NeilBrown 2011-10-11 7834 struct md_rdev *rdev;
713cf5a63954bd Shaohua Li 2015-08-13 7835 struct md_rdev *journal_dev = NULL;
c148ffdcda00b6 NeilBrown 2009-11-13 7836 sector_t reshape_offset = 0;
c567c86b90d471 Yu Kuai 2023-06-22 7837 int i;
b5254dd5fdd9ab NeilBrown 2012-05-21 7838 long long min_offset_diff = 0;
b5254dd5fdd9ab NeilBrown 2012-05-21 7839 int first = 1;
f63f17350e5373 Christoph Hellwig 2024-03-03 7840 int ret = -EIO;
91adb56473febe NeilBrown 2009-03-31 7841
907a99c314a5a6 Li Nan 2025-07-22 7842 if (mddev->resync_offset != MaxSector)
cc6167b4f3b3ca NeilBrown 2016-11-02 7843 pr_notice("md/raid:%s: not clean -- starting background reconstruction\n",
8c6ac868b107ed Andre Noll 2009-06-18 7844 mdname(mddev));
b5254dd5fdd9ab NeilBrown 2012-05-21 7845
b5254dd5fdd9ab NeilBrown 2012-05-21 7846 rdev_for_each(rdev, mddev) {
b5254dd5fdd9ab NeilBrown 2012-05-21 7847 long long diff;
713cf5a63954bd Shaohua Li 2015-08-13 7848
f2076e7d0643d1 Shaohua Li 2015-10-08 7849 if (test_bit(Journal, &rdev->flags)) {
713cf5a63954bd Shaohua Li 2015-08-13 7850 journal_dev = rdev;
f2076e7d0643d1 Shaohua Li 2015-10-08 7851 continue;
f2076e7d0643d1 Shaohua Li 2015-10-08 7852 }
b5254dd5fdd9ab NeilBrown 2012-05-21 7853 if (rdev->raid_disk < 0)
b5254dd5fdd9ab NeilBrown 2012-05-21 7854 continue;
b5254dd5fdd9ab NeilBrown 2012-05-21 7855 diff = (rdev->new_data_offset - rdev->data_offset);
b5254dd5fdd9ab NeilBrown 2012-05-21 7856 if (first) {
b5254dd5fdd9ab NeilBrown 2012-05-21 7857 min_offset_diff = diff;
b5254dd5fdd9ab NeilBrown 2012-05-21 7858 first = 0;
b5254dd5fdd9ab NeilBrown 2012-05-21 7859 } else if (mddev->reshape_backwards &&
b5254dd5fdd9ab NeilBrown 2012-05-21 7860 diff < min_offset_diff)
b5254dd5fdd9ab NeilBrown 2012-05-21 7861 min_offset_diff = diff;
b5254dd5fdd9ab NeilBrown 2012-05-21 7862 else if (!mddev->reshape_backwards &&
b5254dd5fdd9ab NeilBrown 2012-05-21 7863 diff > min_offset_diff)
b5254dd5fdd9ab NeilBrown 2012-05-21 7864 min_offset_diff = diff;
b5254dd5fdd9ab NeilBrown 2012-05-21 7865 }
b5254dd5fdd9ab NeilBrown 2012-05-21 7866
230b55fa8d6400 NeilBrown 2017-10-17 7867 if ((test_bit(MD_HAS_JOURNAL, &mddev->flags) || journal_dev) &&
230b55fa8d6400 NeilBrown 2017-10-17 7868 (mddev->bitmap_info.offset || mddev->bitmap_info.file)) {
230b55fa8d6400 NeilBrown 2017-10-17 7869 pr_notice("md/raid:%s: array cannot have both journal and bitmap\n",
230b55fa8d6400 NeilBrown 2017-10-17 7870 mdname(mddev));
c567c86b90d471 Yu Kuai 2023-06-22 7871 return -EINVAL;
230b55fa8d6400 NeilBrown 2017-10-17 7872 }
230b55fa8d6400 NeilBrown 2017-10-17 7873
91adb56473febe NeilBrown 2009-03-31 7874 if (mddev->reshape_position != MaxSector) {
91adb56473febe NeilBrown 2009-03-31 7875 /* Check that we can continue the reshape.
b5254dd5fdd9ab NeilBrown 2012-05-21 7876 * Difficulties arise if the stripe we would write to
b5254dd5fdd9ab NeilBrown 2012-05-21 7877 * next is at or after the stripe we would read from next.
b5254dd5fdd9ab NeilBrown 2012-05-21 7878 * For a reshape that changes the number of devices, this
b5254dd5fdd9ab NeilBrown 2012-05-21 7879 * is only possible for a very short time, and mdadm makes
b5254dd5fdd9ab NeilBrown 2012-05-21 7880 * sure that time appears to have past before assembling
b5254dd5fdd9ab NeilBrown 2012-05-21 7881 * the array. So we fail if that time hasn't passed.
b5254dd5fdd9ab NeilBrown 2012-05-21 7882 * For a reshape that keeps the number of devices the same
b5254dd5fdd9ab NeilBrown 2012-05-21 7883 * mdadm must be monitoring the reshape can keeping the
b5254dd5fdd9ab NeilBrown 2012-05-21 7884 * critical areas read-only and backed up. It will start
b5254dd5fdd9ab NeilBrown 2012-05-21 7885 * the array in read-only mode, so we check for that.
91adb56473febe NeilBrown 2009-03-31 7886 */
91adb56473febe NeilBrown 2009-03-31 7887 sector_t here_new, here_old;
91adb56473febe NeilBrown 2009-03-31 7888 int old_disks;
18b0033491f584 Andre Noll 2009-03-31 7889 int max_degraded = (mddev->level == 6 ? 2 : 1);
05256d9884d327 NeilBrown 2015-07-15 7890 int chunk_sectors;
05256d9884d327 NeilBrown 2015-07-15 7891 int new_data_disks;
91adb56473febe NeilBrown 2009-03-31 7892
713cf5a63954bd Shaohua Li 2015-08-13 7893 if (journal_dev) {
cc6167b4f3b3ca NeilBrown 2016-11-02 7894 pr_warn("md/raid:%s: don't support reshape with journal - aborting.\n",
713cf5a63954bd Shaohua Li 2015-08-13 7895 mdname(mddev));
c567c86b90d471 Yu Kuai 2023-06-22 7896 return -EINVAL;
713cf5a63954bd Shaohua Li 2015-08-13 7897 }
713cf5a63954bd Shaohua Li 2015-08-13 7898
88ce4930e2b803 NeilBrown 2009-03-31 7899 if (mddev->new_level != mddev->level) {
cc6167b4f3b3ca NeilBrown 2016-11-02 7900 pr_warn("md/raid:%s: unsupported reshape required - aborting.\n",
91adb56473febe NeilBrown 2009-03-31 7901 mdname(mddev));
c567c86b90d471 Yu Kuai 2023-06-22 7902 return -EINVAL;
91adb56473febe NeilBrown 2009-03-31 7903 }
91adb56473febe NeilBrown 2009-03-31 7904 old_disks = mddev->raid_disks - mddev->delta_disks;
91adb56473febe NeilBrown 2009-03-31 7905 /* reshape_position must be on a new-stripe boundary, and one
91adb56473febe NeilBrown 2009-03-31 7906 * further up in new geometry must map after here in old
91adb56473febe NeilBrown 2009-03-31 7907 * geometry.
05256d9884d327 NeilBrown 2015-07-15 7908 * If the chunk sizes are different, then as we perform reshape
05256d9884d327 NeilBrown 2015-07-15 7909 * in units of the largest of the two, reshape_position needs
05256d9884d327 NeilBrown 2015-07-15 7910 * be a multiple of the largest chunk size times new data disks.
91adb56473febe NeilBrown 2009-03-31 7911 */
91adb56473febe NeilBrown 2009-03-31 7912 here_new = mddev->reshape_position;
05256d9884d327 NeilBrown 2015-07-15 7913 chunk_sectors = max(mddev->chunk_sectors, mddev->new_chunk_sectors);
05256d9884d327 NeilBrown 2015-07-15 7914 new_data_disks = mddev->raid_disks - max_degraded;
05256d9884d327 NeilBrown 2015-07-15 7915 if (sector_div(here_new, chunk_sectors * new_data_disks)) {
cc6167b4f3b3ca NeilBrown 2016-11-02 7916 pr_warn("md/raid:%s: reshape_position not on a stripe boundary\n",
cc6167b4f3b3ca NeilBrown 2016-11-02 7917 mdname(mddev));
c567c86b90d471 Yu Kuai 2023-06-22 7918 return -EINVAL;
91adb56473febe NeilBrown 2009-03-31 7919 }
05256d9884d327 NeilBrown 2015-07-15 7920 reshape_offset = here_new * chunk_sectors;
91adb56473febe NeilBrown 2009-03-31 7921 /* here_new is the stripe we will write to */
91adb56473febe NeilBrown 2009-03-31 7922 here_old = mddev->reshape_position;
05256d9884d327 NeilBrown 2015-07-15 7923 sector_div(here_old, chunk_sectors * (old_disks-max_degraded));
91adb56473febe NeilBrown 2009-03-31 7924 /* here_old is the first stripe that we might need to read
91adb56473febe NeilBrown 2009-03-31 7925 * from */
67ac6011db5d2b NeilBrown 2009-08-13 7926 if (mddev->delta_disks == 0) {
67ac6011db5d2b NeilBrown 2009-08-13 7927 /* We cannot be sure it is safe to start an in-place
b5254dd5fdd9ab NeilBrown 2012-05-21 7928 * reshape. It is only safe if user-space is monitoring
67ac6011db5d2b NeilBrown 2009-08-13 7929 * and taking constant backups.
67ac6011db5d2b NeilBrown 2009-08-13 7930 * mdadm always starts a situation like this in
67ac6011db5d2b NeilBrown 2009-08-13 7931 * readonly mode so it can take control before
67ac6011db5d2b NeilBrown 2009-08-13 7932 * allowing any writes. So just check for that.
67ac6011db5d2b NeilBrown 2009-08-13 7933 */
b5254dd5fdd9ab NeilBrown 2012-05-21 7934 if (abs(min_offset_diff) >= mddev->chunk_sectors &&
b5254dd5fdd9ab NeilBrown 2012-05-21 7935 abs(min_offset_diff) >= mddev->new_chunk_sectors)
b5254dd5fdd9ab NeilBrown 2012-05-21 7936 /* not really in-place - so OK */;
b5254dd5fdd9ab NeilBrown 2012-05-21 7937 else if (mddev->ro == 0) {
cc6167b4f3b3ca NeilBrown 2016-11-02 7938 pr_warn("md/raid:%s: in-place reshape must be started in read-only mode - aborting\n",
0c55e02259115c NeilBrown 2010-05-03 7939 mdname(mddev));
c567c86b90d471 Yu Kuai 2023-06-22 7940 return -EINVAL;
67ac6011db5d2b NeilBrown 2009-08-13 7941 }
2c810cddc44d6f NeilBrown 2012-05-21 7942 } else if (mddev->reshape_backwards
05256d9884d327 NeilBrown 2015-07-15 7943 ? (here_new * chunk_sectors + min_offset_diff <=
05256d9884d327 NeilBrown 2015-07-15 7944 here_old * chunk_sectors)
05256d9884d327 NeilBrown 2015-07-15 7945 : (here_new * chunk_sectors >=
05256d9884d327 NeilBrown 2015-07-15 7946 here_old * chunk_sectors + (-min_offset_diff))) {
91adb56473febe NeilBrown 2009-03-31 7947 /* Reading from the same stripe as writing to - bad */
cc6167b4f3b3ca NeilBrown 2016-11-02 7948 pr_warn("md/raid:%s: reshape_position too early for auto-recovery - aborting.\n",
0c55e02259115c NeilBrown 2010-05-03 7949 mdname(mddev));
c567c86b90d471 Yu Kuai 2023-06-22 7950 return -EINVAL;
91adb56473febe NeilBrown 2009-03-31 7951 }
cc6167b4f3b3ca NeilBrown 2016-11-02 7952 pr_debug("md/raid:%s: reshape will continue\n", mdname(mddev));
91adb56473febe NeilBrown 2009-03-31 7953 /* OK, we should be able to continue; */
91adb56473febe NeilBrown 2009-03-31 7954 } else {
91adb56473febe NeilBrown 2009-03-31 7955 BUG_ON(mddev->level != mddev->new_level);
91adb56473febe NeilBrown 2009-03-31 7956 BUG_ON(mddev->layout != mddev->new_layout);
664e7c413f1e90 Andre Noll 2009-06-18 7957 BUG_ON(mddev->chunk_sectors != mddev->new_chunk_sectors);
91adb56473febe NeilBrown 2009-03-31 7958 BUG_ON(mddev->delta_disks != 0);
91adb56473febe NeilBrown 2009-03-31 7959 }
245f46c2c221ef NeilBrown 2009-03-31 7960
3418d036c81dcb Artur Paszkiewicz 2017-03-09 7961 if (test_bit(MD_HAS_JOURNAL, &mddev->flags) &&
3418d036c81dcb Artur Paszkiewicz 2017-03-09 7962 test_bit(MD_HAS_PPL, &mddev->flags)) {
3418d036c81dcb Artur Paszkiewicz 2017-03-09 7963 pr_warn("md/raid:%s: using journal device and PPL not allowed - disabling PPL\n",
3418d036c81dcb Artur Paszkiewicz 2017-03-09 7964 mdname(mddev));
3418d036c81dcb Artur Paszkiewicz 2017-03-09 7965 clear_bit(MD_HAS_PPL, &mddev->flags);
ddc088238cd698 Pawel Baldysiak 2017-08-16 7966 clear_bit(MD_HAS_MULTIPLE_PPLS, &mddev->flags);
3418d036c81dcb Artur Paszkiewicz 2017-03-09 7967 }
3418d036c81dcb Artur Paszkiewicz 2017-03-09 7968
245f46c2c221ef NeilBrown 2009-03-31 7969 if (mddev->private == NULL)
91adb56473febe NeilBrown 2009-03-31 7970 conf = setup_conf(mddev);
245f46c2c221ef NeilBrown 2009-03-31 7971 else
245f46c2c221ef NeilBrown 2009-03-31 7972 conf = mddev->private;
91adb56473febe NeilBrown 2009-03-31 7973
c567c86b90d471 Yu Kuai 2023-06-22 7974 if (IS_ERR(conf))
c567c86b90d471 Yu Kuai 2023-06-22 7975 return PTR_ERR(conf);
91adb56473febe NeilBrown 2009-03-31 7976
486b0f7bcd64be Song Liu 2016-08-19 7977 if (test_bit(MD_HAS_JOURNAL, &mddev->flags)) {
486b0f7bcd64be Song Liu 2016-08-19 7978 if (!journal_dev) {
cc6167b4f3b3ca NeilBrown 2016-11-02 7979 pr_warn("md/raid:%s: journal disk is missing, force array readonly\n",
7dde2ad3c5b4af Shaohua Li 2015-10-08 7980 mdname(mddev));
7dde2ad3c5b4af Shaohua Li 2015-10-08 7981 mddev->ro = 1;
7dde2ad3c5b4af Shaohua Li 2015-10-08 7982 set_disk_ro(mddev->gendisk, 1);
907a99c314a5a6 Li Nan 2025-07-22 7983 } else if (mddev->resync_offset == MaxSector)
486b0f7bcd64be Song Liu 2016-08-19 7984 set_bit(MD_JOURNAL_CLEAN, &mddev->flags);
7dde2ad3c5b4af Shaohua Li 2015-10-08 7985 }
7dde2ad3c5b4af Shaohua Li 2015-10-08 7986
b5254dd5fdd9ab NeilBrown 2012-05-21 7987 conf->min_offset_diff = min_offset_diff;
44693154398272 Yu Kuai 2023-05-23 7988 rcu_assign_pointer(mddev->thread, conf->thread);
44693154398272 Yu Kuai 2023-05-23 7989 rcu_assign_pointer(conf->thread, NULL);
91adb56473febe NeilBrown 2009-03-31 7990 mddev->private = conf;
91adb56473febe NeilBrown 2009-03-31 7991
17045f52ac76d9 NeilBrown 2011-12-23 7992 for (i = 0; i < conf->raid_disks && conf->previous_raid_disks;
17045f52ac76d9 NeilBrown 2011-12-23 7993 i++) {
ad8606702f2689 Yu Kuai 2023-11-25 7994 rdev = conf->disks[i].rdev;
17045f52ac76d9 NeilBrown 2011-12-23 7995 if (!rdev)
c148ffdcda00b6 NeilBrown 2009-11-13 7996 continue;
ad8606702f2689 Yu Kuai 2023-11-25 7997 if (conf->disks[i].replacement &&
17045f52ac76d9 NeilBrown 2011-12-23 7998 conf->reshape_progress != MaxSector) {
17045f52ac76d9 NeilBrown 2011-12-23 7999 /* replacements and reshape simply do not mix. */
cc6167b4f3b3ca NeilBrown 2016-11-02 8000 pr_warn("md: cannot handle concurrent replacement and reshape.\n");
17045f52ac76d9 NeilBrown 2011-12-23 8001 goto abort;
17045f52ac76d9 NeilBrown 2011-12-23 8002 }
7bc436121e557b Tom Rix 2023-03-27 8003 if (test_bit(In_sync, &rdev->flags))
2f115882499f3e NeilBrown 2010-06-17 8004 continue;
c148ffdcda00b6 NeilBrown 2009-11-13 8005 /* This disc is not fully in-sync. However if it
c148ffdcda00b6 NeilBrown 2009-11-13 8006 * just stored parity (beyond the recovery_offset),
c148ffdcda00b6 NeilBrown 2009-11-13 8007 * when we don't need to be concerned about the
c148ffdcda00b6 NeilBrown 2009-11-13 8008 * array being dirty.
c148ffdcda00b6 NeilBrown 2009-11-13 8009 * When reshape goes 'backwards', we never have
c148ffdcda00b6 NeilBrown 2009-11-13 8010 * partially completed devices, so we only need
c148ffdcda00b6 NeilBrown 2009-11-13 8011 * to worry about reshape going forwards.
c148ffdcda00b6 NeilBrown 2009-11-13 8012 */
c148ffdcda00b6 NeilBrown 2009-11-13 8013 /* Hack because v0.91 doesn't store recovery_offset properly. */
c148ffdcda00b6 NeilBrown 2009-11-13 8014 if (mddev->major_version == 0 &&
c148ffdcda00b6 NeilBrown 2009-11-13 8015 mddev->minor_version > 90)
c148ffdcda00b6 NeilBrown 2009-11-13 8016 rdev->recovery_offset = reshape_offset;
c148ffdcda00b6 NeilBrown 2009-11-13 8017
c148ffdcda00b6 NeilBrown 2009-11-13 8018 if (rdev->recovery_offset < reshape_offset) {
c148ffdcda00b6 NeilBrown 2009-11-13 8019 /* We need to check old and new layout */
c148ffdcda00b6 NeilBrown 2009-11-13 8020 if (!only_parity(rdev->raid_disk,
c148ffdcda00b6 NeilBrown 2009-11-13 8021 conf->algorithm,
c148ffdcda00b6 NeilBrown 2009-11-13 8022 conf->raid_disks,
c148ffdcda00b6 NeilBrown 2009-11-13 8023 conf->max_degraded))
c148ffdcda00b6 NeilBrown 2009-11-13 8024 continue;
c148ffdcda00b6 NeilBrown 2009-11-13 8025 }
c148ffdcda00b6 NeilBrown 2009-11-13 8026 if (!only_parity(rdev->raid_disk,
c148ffdcda00b6 NeilBrown 2009-11-13 8027 conf->prev_algo,
c148ffdcda00b6 NeilBrown 2009-11-13 8028 conf->previous_raid_disks,
c148ffdcda00b6 NeilBrown 2009-11-13 8029 conf->max_degraded))
c148ffdcda00b6 NeilBrown 2009-11-13 8030 continue;
c148ffdcda00b6 NeilBrown 2009-11-13 8031 dirty_parity_disks++;
c148ffdcda00b6 NeilBrown 2009-11-13 8032 }
91adb56473febe NeilBrown 2009-03-31 8033
17045f52ac76d9 NeilBrown 2011-12-23 8034 /*
17045f52ac76d9 NeilBrown 2011-12-23 8035 * 0 for a fully functional array, 1 or 2 for a degraded array.
17045f52ac76d9 NeilBrown 2011-12-23 8036 */
2e38a37f23c98d Song Liu 2017-01-24 8037 mddev->degraded = raid5_calc_degraded(conf);
91adb56473febe NeilBrown 2009-03-31 8038
674806d62fb02a NeilBrown 2010-06-16 8039 if (has_failed(conf)) {
cc6167b4f3b3ca NeilBrown 2016-11-02 8040 pr_crit("md/raid:%s: not enough operational devices (%d/%d failed)\n",
02c2de8cc83588 NeilBrown 2006-10-03 8041 mdname(mddev), mddev->degraded, conf->raid_disks);
^1da177e4c3f41 Linus Torvalds 2005-04-16 8042 goto abort;
^1da177e4c3f41 Linus Torvalds 2005-04-16 8043 }
^1da177e4c3f41 Linus Torvalds 2005-04-16 8044
91adb56473febe NeilBrown 2009-03-31 8045 /* device size must be a multiple of chunk size */
c5eec74f252dfb Guoqing Jiang 2020-12-16 8046 mddev->dev_sectors &= ~((sector_t)mddev->chunk_sectors - 1);
91adb56473febe NeilBrown 2009-03-31 8047 mddev->resync_max_sectors = mddev->dev_sectors;
91adb56473febe NeilBrown 2009-03-31 8048
c148ffdcda00b6 NeilBrown 2009-11-13 8049 if (mddev->degraded > dirty_parity_disks &&
907a99c314a5a6 Li Nan 2025-07-22 8050 mddev->resync_offset != MaxSector) {
4536bf9ba2d034 Artur Paszkiewicz 2017-03-09 8051 if (test_bit(MD_HAS_PPL, &mddev->flags))
4536bf9ba2d034 Artur Paszkiewicz 2017-03-09 8052 pr_crit("md/raid:%s: starting dirty degraded array with PPL.\n",
4536bf9ba2d034 Artur Paszkiewicz 2017-03-09 8053 mdname(mddev));
4536bf9ba2d034 Artur Paszkiewicz 2017-03-09 8054 else if (mddev->ok_start_degraded)
cc6167b4f3b3ca NeilBrown 2016-11-02 8055 pr_crit("md/raid:%s: starting dirty degraded array - data corruption possible.\n",
6ff8d8ec06690f NeilBrown 2006-01-06 8056 mdname(mddev));
6ff8d8ec06690f NeilBrown 2006-01-06 8057 else {
cc6167b4f3b3ca NeilBrown 2016-11-02 8058 pr_crit("md/raid:%s: cannot start dirty degraded array.\n",
^1da177e4c3f41 Linus Torvalds 2005-04-16 8059 mdname(mddev));
^1da177e4c3f41 Linus Torvalds 2005-04-16 8060 goto abort;
^1da177e4c3f41 Linus Torvalds 2005-04-16 8061 }
6ff8d8ec06690f NeilBrown 2006-01-06 8062 }
^1da177e4c3f41 Linus Torvalds 2005-04-16 8063
cc6167b4f3b3ca NeilBrown 2016-11-02 8064 pr_info("md/raid:%s: raid level %d active with %d out of %d devices, algorithm %d\n",
cc6167b4f3b3ca NeilBrown 2016-11-02 8065 mdname(mddev), conf->level,
^1da177e4c3f41 Linus Torvalds 2005-04-16 8066 mddev->raid_disks-mddev->degraded, mddev->raid_disks,
e183eaedd53807 NeilBrown 2009-03-31 8067 mddev->new_layout);
^1da177e4c3f41 Linus Torvalds 2005-04-16 8068
^1da177e4c3f41 Linus Torvalds 2005-04-16 8069 print_raid5_conf(conf);
^1da177e4c3f41 Linus Torvalds 2005-04-16 8070
fef9c61fdfabf9 NeilBrown 2009-03-31 8071 if (conf->reshape_progress != MaxSector) {
fef9c61fdfabf9 NeilBrown 2009-03-31 8072 conf->reshape_safe = conf->reshape_progress;
f67055780caac6 NeilBrown 2006-03-27 8073 atomic_set(&conf->reshape_stripes, 0);
f67055780caac6 NeilBrown 2006-03-27 8074 clear_bit(MD_RECOVERY_SYNC, &mddev->recovery);
f67055780caac6 NeilBrown 2006-03-27 8075 clear_bit(MD_RECOVERY_CHECK, &mddev->recovery);
f67055780caac6 NeilBrown 2006-03-27 8076 set_bit(MD_RECOVERY_RESHAPE, &mddev->recovery);
ad39c08186f8a0 Yu Kuai 2024-02-01 8077 set_bit(MD_RECOVERY_NEEDED, &mddev->recovery);
f67055780caac6 NeilBrown 2006-03-27 8078 }
f67055780caac6 NeilBrown 2006-03-27 8079
^1da177e4c3f41 Linus Torvalds 2005-04-16 8080 /* Ok, everything is just fine now */
a64c876fd35790 NeilBrown 2010-04-14 8081 if (mddev->to_remove == &raid5_attrs_group)
a64c876fd35790 NeilBrown 2010-04-14 8082 mddev->to_remove = NULL;
00bcb4ac7ee7e5 NeilBrown 2010-06-01 8083 else if (mddev->kobj.sd &&
00bcb4ac7ee7e5 NeilBrown 2010-06-01 8084 sysfs_create_group(&mddev->kobj, &raid5_attrs_group))
cc6167b4f3b3ca NeilBrown 2016-11-02 8085 pr_warn("raid5: failed to create sysfs attributes for %s\n",
5e55e2f5fc95b3 NeilBrown 2007-03-26 8086 mdname(mddev));
4a5add49951e69 NeilBrown 2010-06-01 8087 md_set_array_sectors(mddev, raid5_size(mddev, 0, 0));
7a5febe9ffeecd NeilBrown 2005-05-16 8088
176df894d79741 Christoph Hellwig 2024-03-03 8089 if (!mddev_is_dm(mddev)) {
f63f17350e5373 Christoph Hellwig 2024-03-03 8090 ret = raid5_set_limits(mddev);
f63f17350e5373 Christoph Hellwig 2024-03-03 8091 if (ret)
f63f17350e5373 Christoph Hellwig 2024-03-03 8092 goto abort;
9f7c2220017771 NeilBrown 2010-07-26 8093 }
23032a0eb97c8e Raz Ben-Jehuda(caro 2006-12-10 8094)
585d578974395f Yu Kuai 2026-01-12 8095 ret = raid5_create_ctx_pool(conf);
585d578974395f Yu Kuai 2026-01-12 8096 if (ret)
01fce9e38c0e92 Yu Kuai 2026-01-12 8097 goto abort;
01fce9e38c0e92 Yu Kuai 2026-01-12 8098
845b9e229fe071 Artur Paszkiewicz 2017-04-04 8099 if (log_init(conf, journal_dev, raid5_has_ppl(conf)))
5aabf7c49d9ebe Song Liu 2016-11-17 @8100 goto abort;
5c7e81c3de9eb3 Shaohua Li 2015-08-13 8101
^1da177e4c3f41 Linus Torvalds 2005-04-16 8102 return 0;
^1da177e4c3f41 Linus Torvalds 2005-04-16 8103 abort:
7eb8ff02c1df27 Li Lingfeng 2023-08-03 8104 md_unregister_thread(mddev, &mddev->thread);
^1da177e4c3f41 Linus Torvalds 2005-04-16 8105 print_raid5_conf(conf);
95fc17aac45300 Dan Williams 2009-07-31 8106 free_conf(conf);
^1da177e4c3f41 Linus Torvalds 2005-04-16 8107 mddev->private = NULL;
cc6167b4f3b3ca NeilBrown 2016-11-02 8108 pr_warn("md/raid:%s: failed to run raid set.\n", mdname(mddev));
f63f17350e5373 Christoph Hellwig 2024-03-03 8109 return ret;
^1da177e4c3f41 Linus Torvalds 2005-04-16 8110 }
^1da177e4c3f41 Linus Torvalds 2005-04-16 8111 Signature · 2 lines
0-DAY CI Kernel Test Service https://github.com/intel/lkp-tests/wiki
Re: [PATCH v4 05/11] md/raid5: make sure max_sectors is not less than io_opt
Hi,
Quoted 63 lines · Dan Carpenter
Hi Yu,
kernel test robot noticed the following build warnings:
https://git-scm.com/docs/git-format-patch#_base_tree_information]
url: https://github.com/intel-lab-lkp/linux/commits/Yu-Kuai/md-merge-mddev-has_superblock-into-mddev_flags/20260112-123233 base: linus/master patch link: https://lore.kernel.org/r/20260112042857.2334264-6-yukuai%40fnnas.com patch subject: [PATCH v4 05/11] md/raid5: make sure max_sectors is not less than io_opt config: i386-randconfig-141-20260113 (https://download.01.org/0day-ci/archive/20260113/[email protected]/config) compiler: gcc-14 (Debian 14.2.0-19) 14.2.0 smatch version: v0.5.0-8985-g2614ff1aIf you fix the issue in a separate patch/commit (i.e. not just a new version of the same patch/commit), kindly add following tags
| Reported-by: kernel test robot <[email protected]> | Reported-by: Dan Carpenter <[email protected]> | Closes: https://lore.kernel.org/r/[email protected]/New smatch warnings:
drivers/md/raid5.c:8100raid5_run()warn: missing error code 'ret'vim +/ret +8100
drivers/md/raid5.ccc6167b4f3b3ca NeilBrown 2016-11-02 8064 pr_info("md/raid:%s: raid level %d active with %d out of %d devices, algorithm %d\n", cc6167b4f3b3ca NeilBrown 2016-11-02 8065 mdname(mddev), conf->level, ^1da177e4c3f41 Linus Torvalds 2005-04-16 8066 mddev->raid_disks-mddev->degraded, mddev->raid_disks, e183eaedd53807 NeilBrown 2009-03-31 8067 mddev->new_layout); ^1da177e4c3f41 Linus Torvalds 2005-04-16 8068 ^1da177e4c3f41 Linus Torvalds 2005-04-16 8069 print_raid5_conf(conf); ^1da177e4c3f41 Linus Torvalds 2005-04-16 8070 fef9c61fdfabf9 NeilBrown 2009-03-31 8071 if (conf->reshape_progress != MaxSector) { fef9c61fdfabf9 NeilBrown 2009-03-31 8072 conf->reshape_safe = conf->reshape_progress; f67055780caac6 NeilBrown 2006-03-27 8073 atomic_set(&conf->reshape_stripes, 0); f67055780caac6 NeilBrown 2006-03-27 8074 clear_bit(MD_RECOVERY_SYNC, &mddev->recovery); f67055780caac6 NeilBrown 2006-03-27 8075 clear_bit(MD_RECOVERY_CHECK, &mddev->recovery); f67055780caac6 NeilBrown 2006-03-27 8076 set_bit(MD_RECOVERY_RESHAPE, &mddev->recovery); ad39c08186f8a0 Yu Kuai 2024-02-01 8077 set_bit(MD_RECOVERY_NEEDED, &mddev->recovery); f67055780caac6 NeilBrown 2006-03-27 8078 } f67055780caac6 NeilBrown 2006-03-27 8079 ^1da177e4c3f41 Linus Torvalds 2005-04-16 8080 /* Ok, everything is just fine now */ a64c876fd35790 NeilBrown 2010-04-14 8081 if (mddev->to_remove == &raid5_attrs_group) a64c876fd35790 NeilBrown 2010-04-14 8082 mddev->to_remove = NULL; 00bcb4ac7ee7e5 NeilBrown 2010-06-01 8083 else if (mddev->kobj.sd && 00bcb4ac7ee7e5 NeilBrown 2010-06-01 8084 sysfs_create_group(&mddev->kobj, &raid5_attrs_group)) cc6167b4f3b3ca NeilBrown 2016-11-02 8085 pr_warn("raid5: failed to create sysfs attributes for %s\n", 5e55e2f5fc95b3 NeilBrown 2007-03-26 8086 mdname(mddev)); 4a5add49951e69 NeilBrown 2010-06-01 8087 md_set_array_sectors(mddev, raid5_size(mddev, 0, 0)); 7a5febe9ffeecd NeilBrown 2005-05-16 8088 176df894d79741 Christoph Hellwig 2024-03-03 8089 if (!mddev_is_dm(mddev)) { f63f17350e5373 Christoph Hellwig 2024-03-03 8090 ret = raid5_set_limits(mddev); f63f17350e5373 Christoph Hellwig 2024-03-03 8091 if (ret) f63f17350e5373 Christoph Hellwig 2024-03-03 8092 goto abort; 9f7c2220017771 NeilBrown 2010-07-26 8093 } 23032a0eb97c8e Raz Ben-Jehuda(caro 2006-12-10 8094) 585d578974395f Yu Kuai 2026-01-12 8095 ret = raid5_create_ctx_pool(conf); 585d578974395f Yu Kuai 2026-01-12 8096 if (ret) 01fce9e38c0e92 Yu Kuai 2026-01-12 8097 goto abort; 01fce9e38c0e92 Yu Kuai 2026-01-12 8098 845b9e229fe071 Artur Paszkiewicz 2017-04-04 8099 if (log_init(conf, journal_dev, raid5_has_ppl(conf))) 5aabf7c49d9ebe Song Liu 2016-11-17 @8100 goto abort;
Quoted 1 line
Presumably we should propagate the error code from
log_init()?
Yes we should, but this problem looks already exist before this patch.
Quoted 12 lines
5c7e81c3de9eb3 Shaohua Li 2015-08-13 8101
^1da177e4c3f41 Linus Torvalds 2005-04-16 8102 return 0;
^1da177e4c3f41 Linus Torvalds 2005-04-16 8103 abort:
7eb8ff02c1df27 Li Lingfeng 2023-08-03 8104 md_unregister_thread(mddev, &mddev->thread);
^1da177e4c3f41 Linus Torvalds 2005-04-16 8105 print_raid5_conf(conf);
95fc17aac45300 Dan Williams 2009-07-31 8106 free_conf(conf);
^1da177e4c3f41 Linus Torvalds 2005-04-16 8107 mddev->private = NULL;
cc6167b4f3b3ca NeilBrown 2016-11-02 8108 pr_warn("md/raid:%s: failed to run raid set.\n", mdname(mddev));
f63f17350e5373 Christoph Hellwig 2024-03-03 8109 return ret;
^1da177e4c3f41 Linus Torvalds 2005-04-16 8110 }Signature · 2 lines
Thansk, Kuai
PATCH v4 6/11 md: support to align bio to limits
In reply to Yu KuaiFor personalities that report optimal IO size, it indicates that users can get the best IO bandwidth if they issue IO with this size. However there is also an implicit condition that IO should also be aligned to the optimal IO size.
Currently, bio will only be split by limits, if bio offset is not aligned to limits, then all split bio will not be aligned. This patch add a new feature to align bio to limits first, and following patches will support this for each personality if necessary.
--- drivers/md/md.c | 54 +++++++++++++++++++++++++++++++++++++++++++++++++ drivers/md/md.h | 2 ++ 2 files changed, 56 insertions(+)
drivers/md/md.c +54 -0
@@ -428,6 +428,56 @@ bool md_handle_request(struct mddev *mddev, struct bio *bio) }EXPORT_SYMBOL (md_handle_request); +static struct bio *__md_bio_align_to_limits (struct mddev *mddev, +struct bio *bio) +{ +unsigned int max_sectors = mddev->gendisk->queue->limits.max_sectors; +sector_t start = bio->bi_iter.bi_sector; +sector_t end = start +bio_sectors (bio); +sector_t align_start; +sector_t align_end; +u32 rem; + +/* calculate align_start = roundup(start, max_sectors) */ + align_start = start; + rem =sector_div (align_start, max_sectors); +/* already aligned */ +if (!rem) +return bio; + + align_start = start + max_sectors - rem; + +/* calculate align_end = rounddown(end, max_sectors) */ + align_end = end; + rem =sector_div (align_end, max_sectors); + align_end = end - rem; + +/* bio is too small to split */ +if (align_end <= align_start) +return bio; + +return bio_submit_split_bioset (bio, align_start - start, + &mddev->gendisk->bio_split); +} + +static struct bio *md_bio_align_to_limits (struct mddev *mddev,struct bio *bio) +{ +if (!test_bit (MD_BIO_ALIGN , &mddev->flags)) +return bio; + +/* atomic write can't split */ +if (bio->bi_opf &REQ_ATOMIC ) +return bio; + +switch (bio_op (bio)) { +case REQ_OP_READ : +case REQ_OP_WRITE : +return __md_bio_align_to_limits (mddev, bio); +default : +return bio; + } +} +static void md_submit_bio (struct bio *bio) {const int rw =bio_data_dir (bio);
@@ -443,6 +493,10 @@ static void md_submit_bio(struct bio *bio)return ; } + bio =md_bio_align_to_limits (mddev, bio); +if (!bio) +return ; + bio =bio_split_to_limits (bio);if (!bio)return ;
drivers/md/md.h +2 -0
@@ -347,6 +347,7 @@ struct md_cluster_operations;* @MD_HAS_SUPERBLOCK: There is persistence sb in member disks. * @MD_FAILLAST_DEV: Allow last rdev to be removed. * @MD_SERIALIZE_POLICY: Enforce write IO is not reordered, just used by raid1. +* @MD_BIO_ALIGN: Bio issued to the array will align to io_opt before split. * * change UNSUPPORTED_MDDEV_FLAGS for each array type if new flag is added */
@@ -366,6 +367,7 @@ enum mddev_flags {MD_HAS_SUPERBLOCK ,MD_FAILLAST_DEV ,MD_SERIALIZE_POLICY , + MD_BIO_ALIGN, }; enum mddev_sb_flags {
Signature · 1 line
2.51.0
Re: [PATCH v4 06/11] md: support to align bio to limits
Quoted 27 lines · Yu Kuai
For personalities that report optimal IO size, it indicates that users can get the best IO bandwidth if they issue IO with this size. However there is also an implicit condition that IO should also be aligned to the optimal IO size.
Currently, bio will only be split by limits, if bio offset is not aligned to limits, then all split bio will not be aligned. This patch add a new feature to align bio to limits first, and following patches will support this for each personality if necessary.
Signed-off-by Yu Kuai <[email protected]>Reviewed-by Li Nan <[email protected]>--- drivers/md/md.c | 54 +++++++++++++++++++++++++++++++++++++++++++++++++ drivers/md/md.h | 2 ++ 2 files changed, 56 insertions(+)drivers/md/md.c +1
-0@@ -428,6 +428,56 @@ bool md_handle_request(struct mddev *mddev, struct bio *bio) }EXPORT_SYMBOL (md_handle_request); +static struct bio *__md_bio_align_to_limits(struct mddev *mddev,
drivers/md/md.c bool md_handle_request(struct mddev *mddev, struct bio *bio) · line 441
Quoted 10 lines
drivers/md/md.c +10
-0+ struct bio *bio) +{ +unsigned int max_sectors = mddev->gendisk->queue->limits.max_sectors; +sector_t start = bio->bi_iter.bi_sector; +sector_t end = start +bio_sectors (bio); +sector_t align_start; +sector_t align_end; +u32 rem; + +/* calculate align_start = roundup(start, max_sectors) */
Can we use roundup_u64() here?
drivers/md/md.c bool md_handle_request(struct mddev *mddev, struct bio *bio) · line 450
Quoted 9 lines
drivers/md/md.c +9
-0+ align_start = start; + rem =sector_div (align_start, max_sectors); +/* already aligned */ +if (!rem) +return bio; + + align_start = start + max_sectors - rem; + +/* calculate align_end = rounddown(end, max_sectors) */
Use div64_u64_rem() here seems better.
Quoted 12 lines
drivers/md/md.c +12
-0+ align_end = end; + rem =sector_div (align_end, max_sectors); + align_end = end - rem; + +/* bio is too small to split */ +if (align_end <= align_start) +return bio; + +return bio_submit_split_bioset (bio, align_start - start, + &mddev->gendisk->bio_split); +} +
Signature · 2 lines
Thanks, Nan
Re: [PATCH v4 06/11] md: support to align bio to limits
Quoted 43 lines · Li Nan
Quoted 27 lines · Yu Kuai
For personalities that report optimal IO size, it indicates that users can get the best IO bandwidth if they issue IO with this size. However there is also an implicit condition that IO should also be aligned to the optimal IO size.
Currently, bio will only be split by limits, if bio offset is not aligned to limits, then all split bio will not be aligned. This patch add a new feature to align bio to limits first, and following patches will support this for each personality if necessary.
Signed-off-by Yu Kuai <[email protected]>Reviewed-by Li Nan <[email protected]>---
drivers/md/md.c| 54 +++++++++++++++++++++++++++++++++++++++++++++++++drivers/md/md.h| 2 ++2 files changed, 56 insertions(+)drivers/md/md.c +1
-0@@ -428,6 +428,56 @@ bool md_handle_request(struct mddev *mddev, struct bio *bio) } EXPORT_SYMBOL(md_handle_request); +static struct bio *__md_bio_align_to_limits(struct mddev *mddev,drivers/md/md.c bool md_handle_request(struct mddev *mddev, struct · line 441
Quoted 10 lines
drivers/md/md.c +10
-0+ struct bio *bio) +{ + unsigned int max_sectors = mddev->gendisk->queue->limits.max_sectors; + sector_t start = bio->bi_iter.bi_sector; + sector_t end = start + bio_sectors(bio); + sector_t align_start; + sector_t align_end; + u32 rem; + + /* calculate align_start = roundup(start, max_sectors) */Can we use
roundup_u64()here?
Quoted 11 lines
drivers/md/md.c bool md_handle_request(struct mddev *mddev, struct bio *bio) · line 450
Quoted 9 lines
drivers/md/md.c +9
-0+ align_start = start; + rem = sector_div(align_start, max_sectors); + /* already aligned */ + if (!rem) + return bio; + + align_start = start + max_sectors - rem; + + /* calculate align_end = rounddown(end, max_sectors) */Use
div64_u64_rem()here seems better.
div64_u64_rem is same as sector_div. Please ignore it.
Quoted 13 lines
Quoted 13 lines
drivers/md/md.c +12
-0+ align_end = end; + rem = sector_div(align_end, max_sectors); + align_end = end - rem; + + /* bio is too small to split */ + if (align_end <= align_start) + return bio; + + return bio_submit_split_bioset(bio, align_start - start, + &mddev->gendisk->bio_split); +} +
Signature · 2 lines
Thanks, Nan
PATCH v4 7/11 md: add a helper md_config_align_limits()
In reply to Yu KuaiThis helper will be used by personalities that want to align bio to io_opt to get best IO bandwidth.
Also add the new flag to UNSUPPORTED_MDDEV_FLAGS for now, following patches will enable this for personalities.
--- drivers/md/md.h | 11 +++++++++++ drivers/md/raid0.c | 3 ++- drivers/md/raid1.c | 3 ++- drivers/md/raid5.c | 3 ++- 4 files changed, 17 insertions(+), 3 deletions(-)
drivers/md/md.h +11 -0
@@ -1091,6 +1091,17 @@ static inline bool rdev_blocked(struct md_rdev *rdev)return false; } +static inline void md_config_align_limits (struct mddev *mddev, +struct queue_limits *lim) +{ +if ((lim->max_hw_sectors <<9 ) < lim->io_opt) + lim->max_hw_sectors = lim->io_opt >>9 ; +else + lim->max_hw_sectors =rounddown (lim->max_hw_sectors, + lim->io_opt >>9 ); +set_bit (MD_BIO_ALIGN , &mddev->flags); +} + #define mddev_add_trace_msg(mddev, fmt, args...) \ do { \ if (!mddev_is_dm(mddev)) \
drivers/md/raid0.c +2 -1
@@ -29,7 +29,8 @@ module_param(default_layout, int, 0644); (1L <<MD_HAS_PPL ) | \ (1L <<MD_HAS_MULTIPLE_PPLS ) | \ (1L <<MD_FAILLAST_DEV ) | \ - (1L << MD_SERIALIZE_POLICY)) + (1L <<MD_SERIALIZE_POLICY ) | \ + (1L << MD_BIO_ALIGN))/* * inform the user of the raid configuration
drivers/md/raid1.c +2 -1
@@ -42,7 +42,8 @@ ((1L <<MD_HAS_JOURNAL ) | \ (1L <<MD_JOURNAL_CLEAN ) | \ (1L <<MD_HAS_PPL ) | \ - (1L << MD_HAS_MULTIPLE_PPLS)) + (1L <<MD_HAS_MULTIPLE_PPLS ) | \ + (1L << MD_BIO_ALIGN))static void allow_barrier (struct r1conf *conf,sector_t sector_nr);static void lower_barrier (struct r1conf *conf,sector_t sector_nr);
drivers/md/raid5.c +2 -1
@@ -59,7 +59,8 @@#define UNSUPPORTED_MDDEV_FLAGS \ ((1L << MD_FAILFAST_SUPPORTED) | \ (1L << MD_FAILLAST_DEV) | \ - (1L << MD_SERIALIZE_POLICY)) + (1L << MD_SERIALIZE_POLICY) | \ + (1L << MD_BIO_ALIGN))#define cpu_to_group (cpu) cpu_to_node(cpu)
Signature · 1 line
2.51.0
PATCH v4 8/11 md/raid5: align bio to io_opt
In reply to Yu Kuairaid5 internal implementaion indicates that if write bio is aligned to io_opt, then full stripe write will be used, which will be best for bandwidth because there is no need to read extra data to build new xor data.
Simple test in my VM, 32 disks raid5 with 64kb chunksize:
dd if=/dev/zero of=/dev/md0 bs=100M oflag=direct
Before this patch: 782 MB/s With this patch: 1.1 GB/s
BTW, there are still other bottleneck related to stripe handler, and require further optimization.
--- drivers/md/raid5.c | 6 ++---- 1 file changed, 2 insertions(+), 4 deletions(-)
drivers/md/raid5.c +2 -4
@@ -59,8 +59,7 @@#define UNSUPPORTED_MDDEV_FLAGS \ ((1L << MD_FAILFAST_SUPPORTED) | \ (1L << MD_FAILLAST_DEV) | \ - (1L << MD_SERIALIZE_POLICY) | \ - (1L << MD_BIO_ALIGN)) + (1L << MD_SERIALIZE_POLICY))#define cpu_to_group (cpu) cpu_to_node(cpu)
@@ -7817,8 +7816,7 @@ static int raid5_set_limits(struct mddev *mddev)* Limit the max sectors based on this. */ lim.max_hw_sectors =RAID5_MAX_REQ_STRIPES <<RAID5_STRIPE_SHIFT (conf); -if ((lim.max_hw_sectors <<9 ) < lim.io_opt) - lim.max_hw_sectors = lim.io_opt >>9 ; +md_config_align_limits (mddev, &lim);/* No restrictions on the number of segments in the request */ lim.max_segments =USHRT_MAX ;
Signature · 1 line
2.51.0
PATCH v4 9/11 md/raid10: align bio to io_opt
In reply to Yu KuaiThe impact is not so significant for raid10 compared to raid5, however it's still more appropriate to issue IOs evenly to underlying disks.
--- drivers/md/raid10.c | 2 ++ 1 file changed, 2 insertions(+)
drivers/md/raid10.c +2 -0
@@ -4008,6 +4008,8 @@ static int raid10_set_queue_limits(struct mddev *mddev) err =mddev_stack_rdev_limits (mddev, &lim,MDDEV_STACK_INTEGRITY );if (err)return err; + +md_config_align_limits (mddev, &lim);return queue_limits_set (mddev->gendisk->queue, &lim); }
Signature · 1 line
2.51.0
PATCH v4 10/11 md/raid0: align bio to io_opt
In reply to Yu KuaiThe impact is not so significant for raid0 compared to raid5, however it's still more appropriate to issue IOs evenly to underlying disks.
--- drivers/md/raid0.c | 5 +++-- 1 file changed, 3 insertions(+), 2 deletions(-)
drivers/md/raid0.c +3 -2
@@ -29,8 +29,7 @@ module_param(default_layout, int, 0644); (1L <<MD_HAS_PPL ) | \ (1L <<MD_HAS_MULTIPLE_PPLS ) | \ (1L <<MD_FAILLAST_DEV ) | \ - (1L <<MD_SERIALIZE_POLICY ) | \ - (1L << MD_BIO_ALIGN)) + (1L << MD_SERIALIZE_POLICY))/* * inform the user of the raid configuration
@@ -398,6 +397,8 @@ static int raid0_set_limits(struct mddev *mddev) err =mddev_stack_rdev_limits (mddev, &lim,MDDEV_STACK_INTEGRITY );if (err)return err; + +md_config_align_limits (mddev, &lim);return queue_limits_set (mddev->gendisk->queue, &lim); }
Signature · 1 line
2.51.0
PATCH v4 11/11 md: fix abnormal io_opt from member disks
In reply to Yu KuaiIt's reported that mtp3sas can report abnormal io_opt, for consequence, md array will end up with abnormal io_opt as well, due to the lcm_not_zero() from blk_stack_limits().
Some personalities will configure optimal IO size, and it's indicate that users can get the best IO bandwidth if they issue IO with this size, and we don't want io_opt to be covered by member disks with abnormal io_opt.
Fix this problem by adding a new mddev flags MD_STACK_IO_OPT to indicate that io_opt configured by personalities is preferred over member disks or not.
--- drivers/md/md.c | 28 +++++++++++++++++++++++++++- drivers/md/md.h | 3 ++- drivers/md/raid1.c | 2 +- drivers/md/raid10.c | 4 ++-- 4 files changed, 32 insertions(+), 5 deletions(-)
drivers/md/md.c +27 -1
@@ -6200,18 +6200,33 @@ static const struct kobj_type md_ktype = {int mdp_major =0 ; +static bool rdev_is_mddev (struct md_rdev *rdev) +{ +return rdev->bdev->bd_disk->fops == &md_fops; +} +/* stack the limit for all rdevs into lim */ int mddev_stack_rdev_limits (struct mddev *mddev,struct queue_limits *lim,unsigned int flags) {struct md_rdev *rdev; +bool io_opt_configured = lim->io_opt;rdev_for_each (rdev, mddev) { +unsigned int io_opt = lim->io_opt; +queue_limits_stack_bdev (lim, rdev->bdev, rdev->data_offset, mddev->gendisk->disk_name);if ((flags &MDDEV_STACK_INTEGRITY ) && !queue_limits_stack_integrity_bdev (lim, rdev->bdev))return -EINVAL ; + +/* +* If member disk is not mdraid array, keep the io_opt +* from personality and ignore io_opt from member disk. +*/ +if (!rdev_is_mddev (rdev) && io_opt_configured) + lim->io_opt = io_opt; }/*
@@ -6230,9 +6245,11 @@ int mddev_stack_rdev_limits(struct mddev *mddev, struct queue_limits *lim,EXPORT_SYMBOL_GPL (mddev_stack_rdev_limits);/* apply the extra stacking limits from a new rdev into mddev */ -int mddev_stack_new_rdev (struct mddev *mddev,struct md_rdev *rdev) +int mddev_stack_new_rdev (struct mddev *mddev,struct md_rdev *rdev, +bool io_opt_configured) {struct queue_limits lim; +unsigned int io_opt;if (mddev_is_dm (mddev))return 0 ;
@@ -6245,6 +6262,8 @@ int mddev_stack_new_rdev(struct mddev *mddev, struct md_rdev *rdev) } lim =queue_limits_start_update (mddev->gendisk->queue); + io_opt = lim.io_opt; +queue_limits_stack_bdev (&lim, rdev->bdev, rdev->data_offset, mddev->gendisk->disk_name);
@@ -6255,6 +6274,13 @@ int mddev_stack_new_rdev(struct mddev *mddev, struct md_rdev *rdev)return -ENXIO ; } +/* +* If member disk is not mdraid array, keep the io_opt from +* personality and ignore io_opt from member disk. +*/ +if (!rdev_is_mddev (rdev) && io_opt_configured) + lim.io_opt = io_opt; +return queue_limits_commit_update (mddev->gendisk->queue, &lim); }EXPORT_SYMBOL_GPL (mddev_stack_new_rdev);
drivers/md/md.h +2 -1
@@ -1041,7 +1041,8 @@ int do_md_run(struct mddev *mddev);#define MDDEV_STACK_INTEGRITY (1u << 0)int mddev_stack_rdev_limits (struct mddev *mddev,struct queue_limits *lim,unsigned int flags); -int mddev_stack_new_rdev (struct mddev *mddev,struct md_rdev *rdev); +int mddev_stack_new_rdev (struct mddev *mddev,struct md_rdev *rdev, +bool io_opt_configured);void mddev_update_io_opt (struct mddev *mddev,unsigned int nr_stripes);extern const struct block_device_operations md_fops;
drivers/md/raid1.c +1 -1
@@ -1944,7 +1944,7 @@ static int raid1_add_disk(struct mddev *mddev, struct md_rdev *rdev)for (mirror = first; mirror <= last; mirror++) { p = conf->mirrors + mirror;if (!p->rdev) { - err =mddev_stack_new_rdev (mddev, rdev); + err =mddev_stack_new_rdev (mddev, rdev, false);if (err)return err;
drivers/md/raid10.c +2 -2
@@ -2139,7 +2139,7 @@ static int raid10_add_disk(struct mddev *mddev, struct md_rdev *rdev)continue ; } - err =mddev_stack_new_rdev (mddev, rdev); + err =mddev_stack_new_rdev (mddev, rdev, true);if (err)return err; p->head_position =0 ;
@@ -2157,7 +2157,7 @@ static int raid10_add_disk(struct mddev *mddev, struct md_rdev *rdev)clear_bit (In_sync, &rdev->flags);set_bit (Replacement, &rdev->flags); rdev->raid_disk = repl_slot; - err =mddev_stack_new_rdev (mddev, rdev); + err =mddev_stack_new_rdev (mddev, rdev, true);if (err)return err; conf->fullsync =1 ;
Signature · 1 line
2.51.0
Re: [PATCH v4 11/11] md: fix abnormal io_opt from member disks
Quoted 139 lines · Yu Kuai
It's reported that mtp3sas can report abnormal
io_opt, for consequence, md array will end up with abnormalio_optas well, due to thelcm_not_zero()fromblk_stack_limits().Some personalities will configure optimal IO size, and it's indicate that users can get the best IO bandwidth if they issue IO with this size, and we don't want
io_optto be covered by member disks with abnormalio_opt.Fix this problem by adding a new mddev flags
MD_STACK_IO_OPTto indicate thatio_optconfigured by personalities is preferred over member disks or not.Reported-by Filippo Giunchedi <[email protected]>Reported-by Coly Li <[email protected]>Signed-off-by Yu Kuai <[email protected]>--- drivers/md/md.c | 28 +++++++++++++++++++++++++++- drivers/md/md.h | 3 ++- drivers/md/raid1.c | 2 +- drivers/md/raid10.c | 4 ++-- 4 files changed, 32 insertions(+), 5 deletions(-)drivers/md/md.c +27
-1@@ -6200,18 +6200,33 @@ static const struct kobj_type md_ktype = {int mdp_major =0 ; +static bool rdev_is_mddev (struct md_rdev *rdev) +{ +return rdev->bdev->bd_disk->fops == &md_fops; +} +/* stack the limit for all rdevs into lim */ int mddev_stack_rdev_limits (struct mddev *mddev,struct queue_limits *lim,unsigned int flags) {struct md_rdev *rdev; +bool io_opt_configured = lim->io_opt;rdev_for_each (rdev, mddev) { +unsigned int io_opt = lim->io_opt; +queue_limits_stack_bdev (lim, rdev->bdev, rdev->data_offset, mddev->gendisk->disk_name);if ((flags &MDDEV_STACK_INTEGRITY ) && !queue_limits_stack_integrity_bdev (lim, rdev->bdev))return -EINVAL ; + +/* +* If member disk is not mdraid array, keep the io_opt +* from personality and ignore io_opt from member disk. +*/ +if (!rdev_is_mddev (rdev) && io_opt_configured) + lim->io_opt = io_opt; }/* @@ -6230,9 +6245,11 @@ int mddev_stack_rdev_limits(struct mddev *mddev, struct queue_limits *lim,EXPORT_SYMBOL_GPL (mddev_stack_rdev_limits);/* apply the extra stacking limits from a new rdev into mddev */ -int mddev_stack_new_rdev (struct mddev *mddev,struct md_rdev *rdev) +int mddev_stack_new_rdev (struct mddev *mddev,struct md_rdev *rdev, +bool io_opt_configured) {struct queue_limits lim; +unsigned int io_opt;if (mddev_is_dm (mddev))return 0 ;@@ -6245,6 +6262,8 @@ int mddev_stack_new_rdev(struct mddev *mddev, struct md_rdev *rdev) } lim =queue_limits_start_update (mddev->gendisk->queue); + io_opt = lim.io_opt; +queue_limits_stack_bdev (&lim, rdev->bdev, rdev->data_offset, mddev->gendisk->disk_name);@@ -6255,6 +6274,13 @@ int mddev_stack_new_rdev(struct mddev *mddev, struct md_rdev *rdev)return -ENXIO ; } +/* +* If member disk is not mdraid array, keep the io_opt from +* personality and ignore io_opt from member disk. +*/ +if (!rdev_is_mddev (rdev) && io_opt_configured) + lim.io_opt = io_opt; +return queue_limits_commit_update (mddev->gendisk->queue, &lim); }EXPORT_SYMBOL_GPL (mddev_stack_new_rdev);drivers/md/md.h +2
-1@@ -1041,7 +1041,8 @@ int do_md_run(struct mddev *mddev);#define MDDEV_STACK_INTEGRITY (1u << 0)int mddev_stack_rdev_limits (struct mddev *mddev,struct queue_limits *lim,unsigned int flags); -int mddev_stack_new_rdev (struct mddev *mddev,struct md_rdev *rdev); +int mddev_stack_new_rdev (struct mddev *mddev,struct md_rdev *rdev, +bool io_opt_configured);void mddev_update_io_opt (struct mddev *mddev,unsigned int nr_stripes);extern const struct block_device_operations md_fops;drivers/md/raid1.c +1
-1@@ -1944,7 +1944,7 @@ static int raid1_add_disk(struct mddev *mddev, struct md_rdev *rdev)for (mirror = first; mirror <= last; mirror++) { p = conf->mirrors + mirror;if (!p->rdev) { - err =mddev_stack_new_rdev (mddev, rdev); + err =mddev_stack_new_rdev (mddev, rdev, false);if (err)return err;drivers/md/raid10.c +1
-1@@ -2139,7 +2139,7 @@ static int raid10_add_disk(struct mddev *mddev, struct md_rdev *rdev)continue ; } - err =mddev_stack_new_rdev (mddev, rdev); + err =mddev_stack_new_rdev (mddev, rdev, true);if (err)return err; p->head_position =0 ;
drivers/md/raid10.c static int raid10_add_disk(struct mddev *mddev, struct md_rdev *rdev) · line 2163
Quoted 8 lines
drivers/md/raid10.c +1
-1@@ -2157,7 +2157,7 @@ static int raid10_add_disk(struct mddev *mddev, struct md_rdev *rdev)clear_bit (In_sync, &rdev->flags);set_bit (Replacement, &rdev->flags); rdev->raid_disk = repl_slot; - err =mddev_stack_new_rdev (mddev, rdev); + err =mddev_stack_new_rdev (mddev, rdev, true);if (err)return err; conf->fullsync =1 ;
LGTM
Signature · 2 lines
Thanks, Nan
Re: [PATCH v4 11/11] md: fix abnormal io_opt from member disks
In reply to Yu KuaiQuoted 5 lines · Yu Kuai
It's reported that mtp3sas can report abnormal
io_opt, for consequence, md array will end up with abnormalio_optas well, due to thelcm_not_zero()fromblk_stack_limits().
Quoted 7 lines
Some personalities will configure optimal IO size, and it's indicate that users can get the best IO bandwidth if they issue IO with this size, and we don't want
io_optto be covered by member disks with abnormalio_opt.Fix this problem by adding a new mddev flags
MD_STACK_IO_OPTto indicate thatio_optconfigured by personalities is preferred over member disks or not.
Hi Kuai
In v4, it doesn't use MD_STACK_IO_OPT anymore. So the comment needs to be modified.
The patch looks good to me.
Quoted 140 lines
Reported-by Filippo Giunchedi <[email protected]>Reported-by Coly Li <[email protected]>Signed-off-by Yu Kuai <[email protected]>--- drivers/md/md.c | 28 +++++++++++++++++++++++++++- drivers/md/md.h | 3 ++- drivers/md/raid1.c | 2 +- drivers/md/raid10.c | 4 ++-- 4 files changed, 32 insertions(+), 5 deletions(-)drivers/md/md.c +27
-1@@ -6200,18 +6200,33 @@ static const struct kobj_type md_ktype = {int mdp_major =0 ; +static bool rdev_is_mddev (struct md_rdev *rdev) +{ +return rdev->bdev->bd_disk->fops == &md_fops; +} +/* stack the limit for all rdevs into lim */ int mddev_stack_rdev_limits (struct mddev *mddev,struct queue_limits *lim,unsigned int flags) {struct md_rdev *rdev; +bool io_opt_configured = lim->io_opt;rdev_for_each (rdev, mddev) { +unsigned int io_opt = lim->io_opt; +queue_limits_stack_bdev (lim, rdev->bdev, rdev->data_offset, mddev->gendisk->disk_name);if ((flags &MDDEV_STACK_INTEGRITY ) && !queue_limits_stack_integrity_bdev (lim, rdev->bdev))return -EINVAL ; + +/* +* If member disk is not mdraid array, keep the io_opt +* from personality and ignore io_opt from member disk. +*/ +if (!rdev_is_mddev (rdev) && io_opt_configured) + lim->io_opt = io_opt; }/* @@ -6230,9 +6245,11 @@ int mddev_stack_rdev_limits(struct mddev *mddev, struct queue_limits *lim,EXPORT_SYMBOL_GPL (mddev_stack_rdev_limits);/* apply the extra stacking limits from a new rdev into mddev */ -int mddev_stack_new_rdev (struct mddev *mddev,struct md_rdev *rdev) +int mddev_stack_new_rdev (struct mddev *mddev,struct md_rdev *rdev, +bool io_opt_configured) {struct queue_limits lim; +unsigned int io_opt;if (mddev_is_dm (mddev))return 0 ;@@ -6245,6 +6262,8 @@ int mddev_stack_new_rdev(struct mddev *mddev, struct md_rdev *rdev) } lim =queue_limits_start_update (mddev->gendisk->queue); + io_opt = lim.io_opt; +queue_limits_stack_bdev (&lim, rdev->bdev, rdev->data_offset, mddev->gendisk->disk_name);@@ -6255,6 +6274,13 @@ int mddev_stack_new_rdev(struct mddev *mddev, struct md_rdev *rdev)return -ENXIO ; } +/* +* If member disk is not mdraid array, keep the io_opt from +* personality and ignore io_opt from member disk. +*/ +if (!rdev_is_mddev (rdev) && io_opt_configured) + lim.io_opt = io_opt; +return queue_limits_commit_update (mddev->gendisk->queue, &lim); }EXPORT_SYMBOL_GPL (mddev_stack_new_rdev);drivers/md/md.h +2
-1@@ -1041,7 +1041,8 @@ int do_md_run(struct mddev *mddev);#define MDDEV_STACK_INTEGRITY (1u << 0)int mddev_stack_rdev_limits (struct mddev *mddev,struct queue_limits *lim,unsigned int flags); -int mddev_stack_new_rdev (struct mddev *mddev,struct md_rdev *rdev); +int mddev_stack_new_rdev (struct mddev *mddev,struct md_rdev *rdev, +bool io_opt_configured);void mddev_update_io_opt (struct mddev *mddev,unsigned int nr_stripes);extern const struct block_device_operations md_fops;drivers/md/raid1.c +1
-1@@ -1944,7 +1944,7 @@ static int raid1_add_disk(struct mddev *mddev, struct md_rdev *rdev)for (mirror = first; mirror <= last; mirror++) { p = conf->mirrors + mirror;if (!p->rdev) { - err =mddev_stack_new_rdev (mddev, rdev); + err =mddev_stack_new_rdev (mddev, rdev, false);if (err)return err;drivers/md/raid10.c +2
-3@@ -2139,7 +2139,7 @@ static int raid10_add_disk(struct mddev *mddev, struct md_rdev *rdev)continue ; } - err =mddev_stack_new_rdev (mddev, rdev); + err =mddev_stack_new_rdev (mddev, rdev, true);if (err)return err; p->head_position =0 ;@@ -2157,7 +2157,7 @@ static int raid10_add_disk(struct mddev *mddev, struct md_rdev *rdev)clear_bit (In_sync, &rdev->flags);set_bit (Replacement, &rdev->flags); rdev->raid_disk = repl_slot; - err =mddev_stack_new_rdev (mddev, rdev); + err =mddev_stack_new_rdev (mddev, rdev, true);if (err)return err; conf->fullsync =1 ; --2.51.0