Merge tag 'md-6.19-20251111' of gitolite.kernel.org:pub/scm/linux/kernel/git/mdraid/linux into for-6.19/block

Pull MD changes from Yu:

"- Change maintainer's email address (Yu Kuai)
 - Data can be lost if array is created with different lbs devices, fix
   this problem and record lbs of the array in metadata (Li Nan)
 - Fix rcu protection for md_thread (Yun Zhou)
 - Fix mddev kobject lifetime regression (Xiao Ni)
 - Enable atomic writes for md-linear (John Garry)
 - Some cleanups (Chen Ni, Huiwen He, Wu Guanghao)"

* tag 'md-6.19-20251111' of gitolite.kernel.org:pub/scm/linux/kernel/git/mdraid/linux:
  md: allow configuring logical block size
  md: add check_new_feature module parameter
  md/raid0: Move queue limit setup before r0conf initialization
  md: init bioset in mddev_init
  md: delete md_redundancy_group when array is becoming inactive
  md: prevent adding disks with larger logical_block_size to active arrays
  md/raid5: remove redundant __GFP_NOWARN
  md: avoid repeated calls to del_gendisk
  md/md-llbitmap: Remove unneeded semicolon
  md/md-linear: Enable atomic writes
  Factor out code into md_should_do_recovery()
  md: fix rcu protection in md_wakeup_thread
  md: delete mddev kobj before deleting gendisk kobj
  MAINTAINERS: Update Yu Kuai's E-mail address
This commit is contained in:
Jens Axboe 2025-11-11 06:58:11 -07:00
commit 3d076988aa
12 changed files with 225 additions and 75 deletions

View File

@ -238,6 +238,16 @@ All md devices contain:
the number of devices in a raid4/5/6, or to support external
metadata formats which mandate such clipping.
logical_block_size
Configure the array's logical block size in bytes. This attribute
is only supported for 1.x meta. Write the value before starting
array. The final array LBS uses the maximum between this
configuration and LBS of all combined devices. Note that
LBS cannot exceed PAGE_SIZE before RAID supports folio.
WARNING: Arrays created on new kernel cannot be assembled at old
kernel due to padding check, Set module parameter 'check_new_feature'
to false to bypass, but data loss may occur.
reshape_position
This is either ``none`` or a sector number within the devices of
the array where ``reshape`` is up to. If this is set, the three

View File

@ -4300,7 +4300,7 @@ F: Documentation/filesystems/befs.rst
F: fs/befs/
BFQ I/O SCHEDULER
M: Yu Kuai <yukuai3@huawei.com>
M: Yu Kuai <yukuai@fnnas.com>
L: linux-block@vger.kernel.org
S: Odd Fixes
F: Documentation/block/bfq-iosched.rst
@ -23842,7 +23842,7 @@ F: include/linux/property.h
SOFTWARE RAID (Multiple Disks) SUPPORT
M: Song Liu <song@kernel.org>
M: Yu Kuai <yukuai3@huawei.com>
M: Yu Kuai <yukuai@fnnas.com>
L: linux-raid@vger.kernel.org
S: Supported
Q: https://patchwork.kernel.org/project/linux-raid/list/

View File

@ -72,9 +72,11 @@ static int linear_set_limits(struct mddev *mddev)
md_init_stacking_limits(&lim);
lim.max_hw_sectors = mddev->chunk_sectors;
lim.logical_block_size = mddev->logical_block_size;
lim.max_write_zeroes_sectors = mddev->chunk_sectors;
lim.max_hw_wzeroes_unmap_sectors = mddev->chunk_sectors;
lim.io_min = mddev->chunk_sectors << 9;
lim.features |= BLK_FEAT_ATOMIC_WRITES;
err = mddev_stack_rdev_limits(mddev, &lim, MDDEV_STACK_INTEGRITY);
if (err)
return err;

View File

@ -378,7 +378,7 @@ static void llbitmap_infect_dirty_bits(struct llbitmap *llbitmap,
case BitClean:
pctl->state[pos] = BitDirty;
break;
};
}
}
}

View File

@ -99,7 +99,7 @@ static int remove_and_add_spares(struct mddev *mddev,
struct md_rdev *this);
static void mddev_detach(struct mddev *mddev);
static void export_rdev(struct md_rdev *rdev, struct mddev *mddev);
static void md_wakeup_thread_directly(struct md_thread __rcu *thread);
static void md_wakeup_thread_directly(struct md_thread __rcu **thread);
/*
* Default number of read corrections we'll attempt on an rdev
@ -339,6 +339,7 @@ static int start_readonly;
*/
static bool create_on_open = true;
static bool legacy_async_del_gendisk = true;
static bool check_new_feature = true;
/*
* We have a system wide 'event count' that is incremented
@ -730,6 +731,8 @@ static void mddev_clear_bitmap_ops(struct mddev *mddev)
int mddev_init(struct mddev *mddev)
{
int err = 0;
if (!IS_ENABLED(CONFIG_MD_BITMAP))
mddev->bitmap_id = ID_BITMAP_NONE;
else
@ -741,10 +744,23 @@ int mddev_init(struct mddev *mddev)
if (percpu_ref_init(&mddev->writes_pending, no_op,
PERCPU_REF_ALLOW_REINIT, GFP_KERNEL)) {
percpu_ref_exit(&mddev->active_io);
return -ENOMEM;
err = -ENOMEM;
goto exit_acitve_io;
}
err = bioset_init(&mddev->bio_set, BIO_POOL_SIZE, 0, BIOSET_NEED_BVECS);
if (err)
goto exit_writes_pending;
err = bioset_init(&mddev->sync_set, BIO_POOL_SIZE, 0, BIOSET_NEED_BVECS);
if (err)
goto exit_bio_set;
err = bioset_init(&mddev->io_clone_set, BIO_POOL_SIZE,
offsetof(struct md_io_clone, bio_clone), 0);
if (err)
goto exit_sync_set;
/* We want to start with the refcount at zero */
percpu_ref_put(&mddev->writes_pending);
@ -773,11 +789,24 @@ int mddev_init(struct mddev *mddev)
INIT_WORK(&mddev->del_work, mddev_delayed_delete);
return 0;
exit_sync_set:
bioset_exit(&mddev->sync_set);
exit_bio_set:
bioset_exit(&mddev->bio_set);
exit_writes_pending:
percpu_ref_exit(&mddev->writes_pending);
exit_acitve_io:
percpu_ref_exit(&mddev->active_io);
return err;
}
EXPORT_SYMBOL_GPL(mddev_init);
void mddev_destroy(struct mddev *mddev)
{
bioset_exit(&mddev->bio_set);
bioset_exit(&mddev->sync_set);
bioset_exit(&mddev->io_clone_set);
percpu_ref_exit(&mddev->active_io);
percpu_ref_exit(&mddev->writes_pending);
}
@ -941,8 +970,11 @@ void mddev_unlock(struct mddev *mddev)
* do_md_stop. dm raid only uses md_stop to stop. So dm raid
* doesn't need to check MD_DELETED when getting reconfig lock
*/
if (test_bit(MD_DELETED, &mddev->flags))
if (test_bit(MD_DELETED, &mddev->flags) &&
!test_and_set_bit(MD_DO_DELETE, &mddev->flags)) {
kobject_del(&mddev->kobj);
del_gendisk(mddev->gendisk);
}
}
}
EXPORT_SYMBOL_GPL(mddev_unlock);
@ -1820,9 +1852,13 @@ static int super_1_load(struct md_rdev *rdev, struct md_rdev *refdev, int minor_
}
if (sb->pad0 ||
sb->pad3[0] ||
memcmp(sb->pad3, sb->pad3+1, sizeof(sb->pad3) - sizeof(sb->pad3[1])))
/* Some padding is non-zero, might be a new feature */
return -EINVAL;
memcmp(sb->pad3, sb->pad3+1, sizeof(sb->pad3) - sizeof(sb->pad3[1]))) {
pr_warn("Some padding is non-zero on %pg, might be a new feature\n",
rdev->bdev);
if (check_new_feature)
return -EINVAL;
pr_warn("check_new_feature is disabled, data corruption possible\n");
}
rdev->preferred_minor = 0xffff;
rdev->data_offset = le64_to_cpu(sb->data_offset);
@ -1963,6 +1999,7 @@ static int super_1_validate(struct mddev *mddev, struct md_rdev *freshest, struc
mddev->layout = le32_to_cpu(sb->layout);
mddev->raid_disks = le32_to_cpu(sb->raid_disks);
mddev->dev_sectors = le64_to_cpu(sb->size);
mddev->logical_block_size = le32_to_cpu(sb->logical_block_size);
mddev->events = ev1;
mddev->bitmap_info.offset = 0;
mddev->bitmap_info.space = 0;
@ -2172,6 +2209,7 @@ static void super_1_sync(struct mddev *mddev, struct md_rdev *rdev)
sb->chunksize = cpu_to_le32(mddev->chunk_sectors);
sb->level = cpu_to_le32(mddev->level);
sb->layout = cpu_to_le32(mddev->layout);
sb->logical_block_size = cpu_to_le32(mddev->logical_block_size);
if (test_bit(FailFast, &rdev->flags))
sb->devflags |= FailFast1;
else
@ -5134,7 +5172,7 @@ static void stop_sync_thread(struct mddev *mddev, bool locked)
* Thread might be blocked waiting for metadata update which will now
* never happen
*/
md_wakeup_thread_directly(mddev->sync_thread);
md_wakeup_thread_directly(&mddev->sync_thread);
if (work_pending(&mddev->sync_work))
flush_work(&mddev->sync_work);
@ -5900,6 +5938,68 @@ static struct md_sysfs_entry md_serialize_policy =
__ATTR(serialize_policy, S_IRUGO | S_IWUSR, serialize_policy_show,
serialize_policy_store);
static int mddev_set_logical_block_size(struct mddev *mddev,
unsigned int lbs)
{
int err = 0;
struct queue_limits lim;
if (queue_logical_block_size(mddev->gendisk->queue) >= lbs) {
pr_err("%s: Cannot set LBS smaller than mddev LBS %u\n",
mdname(mddev), lbs);
return -EINVAL;
}
lim = queue_limits_start_update(mddev->gendisk->queue);
lim.logical_block_size = lbs;
pr_info("%s: logical_block_size is changed, data may be lost\n",
mdname(mddev));
err = queue_limits_commit_update(mddev->gendisk->queue, &lim);
if (err)
return err;
mddev->logical_block_size = lbs;
/* New lbs will be written to superblock after array is running */
set_bit(MD_SB_CHANGE_DEVS, &mddev->sb_flags);
return 0;
}
static ssize_t
lbs_show(struct mddev *mddev, char *page)
{
return sprintf(page, "%u\n", mddev->logical_block_size);
}
static ssize_t
lbs_store(struct mddev *mddev, const char *buf, size_t len)
{
unsigned int lbs;
int err = -EBUSY;
/* Only 1.x meta supports configurable LBS */
if (mddev->major_version == 0)
return -EINVAL;
if (mddev->pers)
return -EBUSY;
err = kstrtouint(buf, 10, &lbs);
if (err < 0)
return -EINVAL;
err = mddev_lock(mddev);
if (err)
goto unlock;
err = mddev_set_logical_block_size(mddev, lbs);
unlock:
mddev_unlock(mddev);
return err ?: len;
}
static struct md_sysfs_entry md_logical_block_size =
__ATTR(logical_block_size, 0644, lbs_show, lbs_store);
static struct attribute *md_default_attrs[] = {
&md_level.attr,
@ -5922,6 +6022,7 @@ static struct attribute *md_default_attrs[] = {
&md_consistency_policy.attr,
&md_fail_last_dev.attr,
&md_serialize_policy.attr,
&md_logical_block_size.attr,
NULL,
};
@ -6052,6 +6153,17 @@ int mddev_stack_rdev_limits(struct mddev *mddev, struct queue_limits *lim,
return -EINVAL;
}
/*
* Before RAID adding folio support, the logical_block_size
* should be smaller than the page size.
*/
if (lim->logical_block_size > PAGE_SIZE) {
pr_err("%s: logical_block_size must not larger than PAGE_SIZE\n",
mdname(mddev));
return -EINVAL;
}
mddev->logical_block_size = lim->logical_block_size;
return 0;
}
EXPORT_SYMBOL_GPL(mddev_stack_rdev_limits);
@ -6064,6 +6176,13 @@ int mddev_stack_new_rdev(struct mddev *mddev, struct md_rdev *rdev)
if (mddev_is_dm(mddev))
return 0;
if (queue_logical_block_size(rdev->bdev->bd_disk->queue) >
queue_logical_block_size(mddev->gendisk->queue)) {
pr_err("%s: incompatible logical_block_size, can not add\n",
mdname(mddev));
return -EINVAL;
}
lim = queue_limits_start_update(mddev->gendisk->queue);
queue_limits_stack_bdev(&lim, rdev->bdev, rdev->data_offset,
mddev->gendisk->disk_name);
@ -6384,29 +6503,9 @@ int md_run(struct mddev *mddev)
nowait = nowait && bdev_nowait(rdev->bdev);
}
if (!bioset_initialized(&mddev->bio_set)) {
err = bioset_init(&mddev->bio_set, BIO_POOL_SIZE, 0, BIOSET_NEED_BVECS);
if (err)
return err;
}
if (!bioset_initialized(&mddev->sync_set)) {
err = bioset_init(&mddev->sync_set, BIO_POOL_SIZE, 0, BIOSET_NEED_BVECS);
if (err)
goto exit_bio_set;
}
if (!bioset_initialized(&mddev->io_clone_set)) {
err = bioset_init(&mddev->io_clone_set, BIO_POOL_SIZE,
offsetof(struct md_io_clone, bio_clone), 0);
if (err)
goto exit_sync_set;
}
pers = get_pers(mddev->level, mddev->clevel);
if (!pers) {
err = -EINVAL;
goto abort;
}
if (!pers)
return -EINVAL;
if (mddev->level != pers->head.id) {
mddev->level = pers->head.id;
mddev->new_level = pers->head.id;
@ -6417,8 +6516,7 @@ int md_run(struct mddev *mddev)
pers->start_reshape == NULL) {
/* This personality cannot handle reshaping... */
put_pers(pers);
err = -EINVAL;
goto abort;
return -EINVAL;
}
if (pers->sync_request) {
@ -6545,12 +6643,6 @@ bitmap_abort:
mddev->private = NULL;
put_pers(pers);
md_bitmap_destroy(mddev);
abort:
bioset_exit(&mddev->io_clone_set);
exit_sync_set:
bioset_exit(&mddev->sync_set);
exit_bio_set:
bioset_exit(&mddev->bio_set);
return err;
}
EXPORT_SYMBOL_GPL(md_run);
@ -6683,6 +6775,7 @@ static void md_clean(struct mddev *mddev)
mddev->chunk_sectors = 0;
mddev->ctime = mddev->utime = 0;
mddev->layout = 0;
mddev->logical_block_size = 0;
mddev->max_disks = 0;
mddev->events = 0;
mddev->can_decrease_events = 0;
@ -6775,10 +6868,6 @@ static void __md_stop(struct mddev *mddev)
mddev->private = NULL;
put_pers(pers);
clear_bit(MD_RECOVERY_FROZEN, &mddev->recovery);
bioset_exit(&mddev->bio_set);
bioset_exit(&mddev->sync_set);
bioset_exit(&mddev->io_clone_set);
}
void md_stop(struct mddev *mddev)
@ -6869,6 +6958,10 @@ static int do_md_stop(struct mddev *mddev, int mode)
if (!md_is_rdwr(mddev))
set_disk_ro(disk, 0);
if (mode == 2 && mddev->pers->sync_request &&
mddev->to_remove == NULL)
mddev->to_remove = &md_redundancy_group;
__md_stop_writes(mddev);
__md_stop(mddev);
@ -8373,22 +8466,21 @@ static int md_thread(void *arg)
return 0;
}
static void md_wakeup_thread_directly(struct md_thread __rcu *thread)
static void md_wakeup_thread_directly(struct md_thread __rcu **thread)
{
struct md_thread *t;
rcu_read_lock();
t = rcu_dereference(thread);
t = rcu_dereference(*thread);
if (t)
wake_up_process(t->tsk);
rcu_read_unlock();
}
void md_wakeup_thread(struct md_thread __rcu *thread)
void __md_wakeup_thread(struct md_thread __rcu *thread)
{
struct md_thread *t;
rcu_read_lock();
t = rcu_dereference(thread);
if (t) {
pr_debug("md: waking up MD thread %s.\n", t->tsk->comm);
@ -8396,9 +8488,8 @@ void md_wakeup_thread(struct md_thread __rcu *thread)
if (wq_has_sleeper(&t->wqueue))
wake_up(&t->wqueue);
}
rcu_read_unlock();
}
EXPORT_SYMBOL(md_wakeup_thread);
EXPORT_SYMBOL(__md_wakeup_thread);
struct md_thread *md_register_thread(void (*run) (struct md_thread *),
struct mddev *mddev, const char *name)
@ -9978,6 +10069,52 @@ static void unregister_sync_thread(struct mddev *mddev)
md_reap_sync_thread(mddev);
}
static bool md_should_do_recovery(struct mddev *mddev)
{
/*
* As long as one of the following flags is set,
* recovery needs to do or cleanup.
*/
if (test_bit(MD_RECOVERY_NEEDED, &mddev->recovery) ||
test_bit(MD_RECOVERY_DONE, &mddev->recovery))
return true;
/*
* If no flags are set and it is in read-only status,
* there is nothing to do.
*/
if (!md_is_rdwr(mddev))
return false;
/*
* MD_SB_CHANGE_PENDING indicates that the array is switching from clean to
* active, and no action is needed for now.
* All other MD_SB_* flags require to update the superblock.
*/
if (mddev->sb_flags & ~ (1<<MD_SB_CHANGE_PENDING))
return true;
/*
* If the array is not using external metadata and there has been no data
* written for some time, then the array's status needs to be set to
* in_sync.
*/
if (mddev->external == 0 && mddev->safemode == 1)
return true;
/*
* When the system is about to restart or the process receives an signal,
* the array needs to be synchronized as soon as possible.
* Once the data synchronization is completed, need to change the array
* status to in_sync.
*/
if (mddev->safemode == 2 && !mddev->in_sync &&
mddev->resync_offset == MaxSector)
return true;
return false;
}
/*
* This routine is regularly called by all per-raid-array threads to
* deal with generic issues like resync and super-block update.
@ -10014,18 +10151,7 @@ void md_check_recovery(struct mddev *mddev)
flush_signals(current);
}
if (!md_is_rdwr(mddev) &&
!test_bit(MD_RECOVERY_NEEDED, &mddev->recovery) &&
!test_bit(MD_RECOVERY_DONE, &mddev->recovery))
return;
if ( ! (
(mddev->sb_flags & ~ (1<<MD_SB_CHANGE_PENDING)) ||
test_bit(MD_RECOVERY_NEEDED, &mddev->recovery) ||
test_bit(MD_RECOVERY_DONE, &mddev->recovery) ||
(mddev->external == 0 && mddev->safemode == 1) ||
(mddev->safemode == 2
&& !mddev->in_sync && mddev->resync_offset == MaxSector)
))
if (!md_should_do_recovery(mddev))
return;
if (mddev_trylock(mddev)) {
@ -10697,6 +10823,7 @@ module_param(start_dirty_degraded, int, S_IRUGO|S_IWUSR);
module_param_call(new_array, add_named_array, NULL, NULL, S_IWUSR);
module_param(create_on_open, bool, S_IRUSR|S_IWUSR);
module_param(legacy_async_del_gendisk, bool, 0600);
module_param(check_new_feature, bool, 0600);
MODULE_LICENSE("GPL");
MODULE_DESCRIPTION("MD RAID framework");

View File

@ -354,6 +354,7 @@ enum mddev_flags {
MD_HAS_MULTIPLE_PPLS,
MD_NOT_READY,
MD_BROKEN,
MD_DO_DELETE,
MD_DELETED,
};
@ -432,6 +433,7 @@ struct mddev {
sector_t array_sectors; /* exported array size */
int external_size; /* size managed
* externally */
unsigned int logical_block_size;
__u64 events;
/* If the last 'event' was simply a clean->dirty transition, and
* we didn't write it to the spares, then it is safe and simple
@ -882,6 +884,12 @@ struct md_io_clone {
#define THREAD_WAKEUP 0
#define md_wakeup_thread(thread) do { \
rcu_read_lock(); \
__md_wakeup_thread(thread); \
rcu_read_unlock(); \
} while (0)
static inline void safe_put_page(struct page *p)
{
if (p) put_page(p);
@ -895,7 +903,7 @@ extern struct md_thread *md_register_thread(
struct mddev *mddev,
const char *name);
extern void md_unregister_thread(struct mddev *mddev, struct md_thread __rcu **threadp);
extern void md_wakeup_thread(struct md_thread __rcu *thread);
extern void __md_wakeup_thread(struct md_thread __rcu *thread);
extern void md_check_recovery(struct mddev *mddev);
extern void md_reap_sync_thread(struct mddev *mddev);
extern enum sync_action md_sync_action(struct mddev *mddev);

View File

@ -68,7 +68,7 @@ static int create_strip_zones(struct mddev *mddev, struct r0conf **private_conf)
struct strip_zone *zone;
int cnt;
struct r0conf *conf = kzalloc(sizeof(*conf), GFP_KERNEL);
unsigned blksize = 512;
unsigned int blksize = queue_logical_block_size(mddev->gendisk->queue);
*private_conf = ERR_PTR(-ENOMEM);
if (!conf)
@ -84,9 +84,6 @@ static int create_strip_zones(struct mddev *mddev, struct r0conf **private_conf)
sector_div(sectors, mddev->chunk_sectors);
rdev1->sectors = sectors * mddev->chunk_sectors;
blksize = max(blksize, queue_logical_block_size(
rdev1->bdev->bd_disk->queue));
rdev_for_each(rdev2, mddev) {
pr_debug("md/raid0:%s: comparing %pg(%llu)"
" with %pg(%llu)\n",
@ -383,6 +380,7 @@ static int raid0_set_limits(struct mddev *mddev)
lim.max_hw_sectors = mddev->chunk_sectors;
lim.max_write_zeroes_sectors = mddev->chunk_sectors;
lim.max_hw_wzeroes_unmap_sectors = mddev->chunk_sectors;
lim.logical_block_size = mddev->logical_block_size;
lim.io_min = mddev->chunk_sectors << 9;
lim.io_opt = lim.io_min * mddev->raid_disks;
lim.chunk_sectors = mddev->chunk_sectors;
@ -405,6 +403,12 @@ static int raid0_run(struct mddev *mddev)
if (md_check_no_bitmap(mddev))
return -EINVAL;
if (!mddev_is_dm(mddev)) {
ret = raid0_set_limits(mddev);
if (ret)
return ret;
}
/* if private is not null, we are here after takeover */
if (mddev->private == NULL) {
ret = create_strip_zones(mddev, &conf);
@ -413,11 +417,6 @@ static int raid0_run(struct mddev *mddev)
mddev->private = conf;
}
conf = mddev->private;
if (!mddev_is_dm(mddev)) {
ret = raid0_set_limits(mddev);
if (ret)
return ret;
}
/* calculate array device size */
md_set_array_sectors(mddev, raid0_size(mddev, 0, 0));

View File

@ -3213,6 +3213,7 @@ static int raid1_set_limits(struct mddev *mddev)
md_init_stacking_limits(&lim);
lim.max_write_zeroes_sectors = 0;
lim.max_hw_wzeroes_unmap_sectors = 0;
lim.logical_block_size = mddev->logical_block_size;
lim.features |= BLK_FEAT_ATOMIC_WRITES;
err = mddev_stack_rdev_limits(mddev, &lim, MDDEV_STACK_INTEGRITY);
if (err)

View File

@ -4000,6 +4000,7 @@ static int raid10_set_queue_limits(struct mddev *mddev)
md_init_stacking_limits(&lim);
lim.max_write_zeroes_sectors = 0;
lim.max_hw_wzeroes_unmap_sectors = 0;
lim.logical_block_size = mddev->logical_block_size;
lim.io_min = mddev->chunk_sectors << 9;
lim.chunk_sectors = mddev->chunk_sectors;
lim.io_opt = lim.io_min * raid10_nr_stripes(conf);

View File

@ -3104,7 +3104,7 @@ int r5l_init_log(struct r5conf *conf, struct md_rdev *rdev)
goto out_mempool;
spin_lock_init(&log->tree_lock);
INIT_RADIX_TREE(&log->big_stripe_tree, GFP_NOWAIT | __GFP_NOWARN);
INIT_RADIX_TREE(&log->big_stripe_tree, GFP_NOWAIT);
thread = md_register_thread(r5l_reclaim_thread, log->rdev->mddev,
"reclaim");

View File

@ -7745,6 +7745,7 @@ static int raid5_set_limits(struct mddev *mddev)
stripe = roundup_pow_of_two(data_disks * (mddev->chunk_sectors << 9));
md_init_stacking_limits(&lim);
lim.logical_block_size = mddev->logical_block_size;
lim.io_min = mddev->chunk_sectors << 9;
lim.io_opt = lim.io_min * (conf->raid_disks - conf->max_degraded);
lim.features |= BLK_FEAT_RAID_PARTIAL_STRIPES_EXPENSIVE;

View File

@ -291,7 +291,8 @@ struct mdp_superblock_1 {
__le64 resync_offset; /* data before this offset (from data_offset) known to be in sync */
__le32 sb_csum; /* checksum up to devs[max_dev] */
__le32 max_dev; /* size of devs[] array to consider */
__u8 pad3[64-32]; /* set to 0 when writing */
__le32 logical_block_size; /* same as q->limits->logical_block_size */
__u8 pad3[64-36]; /* set to 0 when writing */
/* device state information. Indexed by dev_number.
* 2 bytes per device