mirror of
https://github.com/torvalds/linux.git
synced 2026-11-07 06:17:02 +01:00
Merge tag 'md-7.4-20261013' of https://git.kernel.org/pub/scm/linux/kernel/git/mdraid/linux into block-7.4
Pull MD changes from Yu Kuai: "Bug Fixes: - Wake RAID10 barrier waiters when a pending-count rollback satisfies an active array freeze. (Zizhi Wo) - Reject v0.90 superblocks whose device count cannot fit the metadata format, preventing out-of-bounds access. (Jérémy Jean) - Track RAID5 disk-array allocation size and avoid removing an unregistered CPU hotplug instance on setup or resize failure. (Cao Guanghui) - Validate the RAID0 device count before allocating its device list. (Chandradhar Kumar) - Validate RAID5 journal payload header, size, and checksum bounds before accessing them. (Martin Wilck) - Reject inconsistent RAID5 reshape metadata instead of triggering a kernel BUG. (Yogesh Gaur) - Reject invalid RAID4/5 disk counts before setup and invalid reshape disk counts in raid5_run. (Chen Cheng) - Fix a NULL-pointer dereference in RAID5 setup error handling. (Zhihao Cheng) - Reject RAID5 per-device sizes smaller than one chunk. (Zizhi Wo) - Fix mddev_unlock() on an unacquired mutex in lbs_store(). (Jack Wang) - Give RAID5 io_unit slab caches per-array names to avoid duplicate cache names. (Yogesh Gaur) - Validate v1.x bad-block log size when loading superblocks. (Yuchao Zhang) - Take reconfig_mutex while enabling PPL on an inactive array to prevent a NULL PPL configuration. (Nguyen Ngoc Thang) - Drain released RAID5 stripes before destroying the stripe cache on takeover setup failure. (Li Youhong) - Protect RAID5 big_stripe_tree lookup with RCU. (Sang-Hoon Choi) - Prevent a NULL mddev->private dereference when stopping an array while I/O is being submitted. (Zhihao Cheng) - Don't publish an md array before md_alloc() finishes initializing mddev->kobj. (Yogesh Gaur) Cleanups: - Annotate intentional lockless RAID10 freeze-state accesses. (Zizhi Wo) - Add shared RAID write-error and bad-block-sector helpers, and share flush_bio_list between RAID1 and RAID10. (Li Youhong) - Extract RAID5 min_raid_disks() helper. (Chen Cheng) - Use assign_bit() where applicable in MD/RAID. (Peng Fan)" * tag 'md-7.4-20261013' of https://git.kernel.org/pub/scm/linux/kernel/git/mdraid/linux: (25 commits) md: don't hand out the array before md_alloc() has added mddev->kobj md: Fix the null-ptr-deref of 'mddev->private' while submitting IO md/raid5: protect big_stripe_tree lookup with RCU md/raid5: drain released_stripes before destroying the cache md: take reconfig_mutex when enabling PPL on an inactive array md: validate bblog_size when loading v1.x badblocks metadata md/raid: use assign_bit() where applicable md/raid5: reject invalid reshape disks in raid5_run() md/raid5: extract min_raid_disks() md/raid5: give the io_unit slab caches per-array names md: fix mddev_unlock() called without holding lock in lbs_store() md/raid1-10: share flush_bio_list between raid1 and raid10 md/raid1-10: add rdev_bb_block_sectors() helper md: add rdev_record_write_error() helper md/raid5: reject a per-device size smaller than one chunk md/raid5: setup_conf: Fix null-ptr-def in error handling path md/raid5: reject raid4/5 arrays with too few disks md/raid5: don't BUG() on an inconsistent reshape state from the superblock md/raid5: validate payload size before calculating payload_len md/raid0: validate device count before allocating devlist ...
This commit is contained in:
commit
f89fa411b8
|
|
@ -414,6 +414,20 @@ bool md_handle_request(struct mddev *mddev, struct bio *bio)
|
|||
if (!percpu_ref_tryget_live(&mddev->active_io))
|
||||
goto check_suspended;
|
||||
}
|
||||
if (!mddev->pers) {
|
||||
/*
|
||||
* The __md_stop() sets 'mddev->private' to NULL during
|
||||
* the IO submitting, check 'mddev->pers' before the IO
|
||||
* being processed by specific driver to avoid the
|
||||
* null-ptr-deref of 'mddev-><member>'. The check is
|
||||
* safe because the IO has got the 'mddev->active_io'
|
||||
* reference, and all __md_stop() callers will wait for
|
||||
* the reference to be zero.
|
||||
*/
|
||||
bio_io_error(bio);
|
||||
percpu_ref_put(&mddev->active_io);
|
||||
return true;
|
||||
}
|
||||
if (!mddev->pers->make_request(mddev, bio)) {
|
||||
percpu_ref_put(&mddev->active_io);
|
||||
if (mddev_is_dm(mddev) && mddev->pers->prepare_suspend)
|
||||
|
|
@ -1393,7 +1407,7 @@ static int super_90_load(struct md_rdev *rdev, struct md_rdev *refdev, int minor
|
|||
goto abort;
|
||||
}
|
||||
|
||||
if (sb->raid_disks <= 0)
|
||||
if (sb->raid_disks <= 0 || sb->raid_disks > MD_SB_DISKS)
|
||||
goto abort;
|
||||
|
||||
if (md_csum_fold(calc_sb_csum(sb)) != md_csum_fold(sb->sb_csum)) {
|
||||
|
|
@ -1934,8 +1948,11 @@ static int super_1_load(struct md_rdev *rdev, struct md_rdev *refdev, int minor_
|
|||
if (!badblocks_set(&rdev->badblocks, sector, count, 1))
|
||||
return -EINVAL;
|
||||
}
|
||||
} else if (sb->bblog_offset != 0)
|
||||
} else if (sb->bblog_offset != 0) {
|
||||
if (le16_to_cpu(sb->bblog_size) > (PAGE_SIZE / 512))
|
||||
return -EINVAL;
|
||||
rdev->badblocks.shift = 0;
|
||||
}
|
||||
|
||||
if ((le32_to_cpu(sb->feature_map) &
|
||||
(MD_FEATURE_PPL | MD_FEATURE_MULTIPLE_PPLS))) {
|
||||
|
|
@ -3586,10 +3603,7 @@ static ssize_t recovery_start_store(struct md_rdev *rdev, const char *buf, size_
|
|||
return -EBUSY;
|
||||
|
||||
rdev->recovery_offset = recovery_start;
|
||||
if (recovery_start == MaxSector)
|
||||
set_bit(In_sync, &rdev->flags);
|
||||
else
|
||||
clear_bit(In_sync, &rdev->flags);
|
||||
assign_bit(In_sync, &rdev->flags, recovery_start == MaxSector);
|
||||
return len;
|
||||
}
|
||||
|
||||
|
|
@ -4670,7 +4684,8 @@ array_state_store(struct mddev *mddev, const char *buf, size_t len)
|
|||
case readonly:
|
||||
case inactive:
|
||||
case read_auto:
|
||||
if (!mddev->pers || !md_is_rdwr(mddev))
|
||||
if (!mddev->pers ||
|
||||
(st != clear && st != inactive && !md_is_rdwr(mddev)))
|
||||
break;
|
||||
/* write sysfs will not open mddev and opener should be 0 */
|
||||
err = mddev_set_closing_and_sync_blockdev(mddev, 0);
|
||||
|
|
@ -5884,7 +5899,15 @@ consistency_policy_store(struct mddev *mddev, const char *buf, size_t len)
|
|||
else
|
||||
err = -EBUSY;
|
||||
} else if (mddev->external && strncmp(buf, "ppl", 3) == 0) {
|
||||
set_bit(MD_HAS_PPL, &mddev->flags);
|
||||
/* md_run() holds the lock until ->pers is set */
|
||||
err = mddev_lock(mddev);
|
||||
if (err)
|
||||
return err;
|
||||
if (mddev->pers)
|
||||
err = -EBUSY;
|
||||
else
|
||||
set_bit(MD_HAS_PPL, &mddev->flags);
|
||||
mddev_unlock(mddev);
|
||||
} else {
|
||||
err = -EINVAL;
|
||||
}
|
||||
|
|
@ -5915,10 +5938,7 @@ fail_last_dev_store(struct mddev *mddev, const char *buf, size_t len)
|
|||
if (ret)
|
||||
return ret;
|
||||
|
||||
if (value)
|
||||
set_bit(MD_FAILLAST_DEV, &mddev->flags);
|
||||
else
|
||||
clear_bit(MD_FAILLAST_DEV, &mddev->flags);
|
||||
assign_bit(MD_FAILLAST_DEV, &mddev->flags, value);
|
||||
|
||||
return len;
|
||||
}
|
||||
|
|
@ -6048,11 +6068,10 @@ lbs_store(struct mddev *mddev, const char *buf, size_t len)
|
|||
|
||||
err = mddev_lock(mddev);
|
||||
if (err)
|
||||
goto unlock;
|
||||
return err;
|
||||
|
||||
err = mddev_set_logical_block_size(mddev, lbs);
|
||||
|
||||
unlock:
|
||||
mddev_unlock(mddev);
|
||||
return err ?: len;
|
||||
}
|
||||
|
|
@ -6385,12 +6404,22 @@ struct mddev *md_alloc(dev_t dev, char *name)
|
|||
|
||||
disk->events |= DISK_EVENT_MEDIA_CHANGE;
|
||||
mddev->gendisk = disk;
|
||||
|
||||
/*
|
||||
* add_disk() makes the array openable before mddev->kobj exists.
|
||||
* Hold reconfig_mutex until kobject_add() is done so that ioctls
|
||||
* issued in between wait instead of using an uninitialised kobj.
|
||||
*/
|
||||
mddev_lock_nointr(mddev);
|
||||
error = add_disk(disk);
|
||||
if (error)
|
||||
if (error) {
|
||||
mddev_unlock(mddev);
|
||||
goto out_put_disk;
|
||||
}
|
||||
|
||||
kobject_init(&mddev->kobj, &md_ktype);
|
||||
error = kobject_add(&mddev->kobj, &disk_to_dev(disk)->kobj, "%s", "md");
|
||||
mddev_unlock(mddev);
|
||||
if (error) {
|
||||
/*
|
||||
* The disk is already live at this point. Clear the hold flag
|
||||
|
|
@ -7574,14 +7603,10 @@ int md_add_new_disk(struct mddev *mddev, struct mdu_disk_info_s *info)
|
|||
}
|
||||
|
||||
clear_bit(In_sync, &rdev->flags); /* just to be sure */
|
||||
if (info->state & (1<<MD_DISK_WRITEMOSTLY))
|
||||
set_bit(WriteMostly, &rdev->flags);
|
||||
else
|
||||
clear_bit(WriteMostly, &rdev->flags);
|
||||
if (info->state & (1<<MD_DISK_FAILFAST))
|
||||
set_bit(FailFast, &rdev->flags);
|
||||
else
|
||||
clear_bit(FailFast, &rdev->flags);
|
||||
assign_bit(WriteMostly, &rdev->flags,
|
||||
info->state & (1 << MD_DISK_WRITEMOSTLY));
|
||||
assign_bit(FailFast, &rdev->flags,
|
||||
info->state & (1 << MD_DISK_FAILFAST));
|
||||
|
||||
if (info->state & (1<<MD_DISK_JOURNAL)) {
|
||||
struct md_rdev *rdev2;
|
||||
|
|
@ -8299,6 +8324,7 @@ static bool md_ioctl_need_suspend(unsigned int cmd)
|
|||
case HOT_REMOVE_DISK:
|
||||
case SET_BITMAP_FILE:
|
||||
case SET_ARRAY_INFO:
|
||||
case STOP_ARRAY:
|
||||
return true;
|
||||
default:
|
||||
return false;
|
||||
|
|
|
|||
|
|
@ -989,6 +989,13 @@ static inline void rdev_dec_pending(struct md_rdev *rdev, struct mddev *mddev)
|
|||
}
|
||||
}
|
||||
|
||||
static inline void rdev_record_write_error(struct md_rdev *rdev)
|
||||
{
|
||||
set_bit(WriteErrorSeen, &rdev->flags);
|
||||
if (!test_and_set_bit(WantReplacement, &rdev->flags))
|
||||
set_bit(MD_RECOVERY_NEEDED, &rdev->mddev->recovery);
|
||||
}
|
||||
|
||||
static inline int mddev_is_clustered(struct mddev *mddev)
|
||||
{
|
||||
return mddev->cluster_info && mddev->bitmap_info.nodes > 1;
|
||||
|
|
|
|||
|
|
@ -79,7 +79,10 @@ static int create_strip_zones(struct mddev *mddev, struct r0conf **private_conf)
|
|||
*private_conf = ERR_PTR(-ENOMEM);
|
||||
if (!conf)
|
||||
return -ENOMEM;
|
||||
|
||||
cnt = 0;
|
||||
rdev_for_each(rdev1, mddev) {
|
||||
cnt++;
|
||||
pr_debug("md/raid0:%s: looking at %pg\n",
|
||||
mdname(mddev),
|
||||
rdev1->bdev);
|
||||
|
|
@ -144,6 +147,14 @@ static int create_strip_zones(struct mddev *mddev, struct r0conf **private_conf)
|
|||
}
|
||||
|
||||
err = -ENOMEM;
|
||||
|
||||
if (cnt != mddev->raid_disks) {
|
||||
pr_warn("md/raid0:%s: too few disks (%d of %d) - aborting!\n",
|
||||
mdname(mddev), cnt, mddev->raid_disks);
|
||||
err = -EINVAL;
|
||||
goto abort;
|
||||
}
|
||||
|
||||
conf->strip_zone = kvzalloc_objs(struct strip_zone, conf->nr_strip_zones);
|
||||
if (!conf->strip_zone)
|
||||
goto abort;
|
||||
|
|
@ -200,11 +211,6 @@ static int create_strip_zones(struct mddev *mddev, struct r0conf **private_conf)
|
|||
smallest = rdev1;
|
||||
cnt++;
|
||||
}
|
||||
if (cnt != mddev->raid_disks) {
|
||||
pr_warn("md/raid0:%s: too few disks (%d of %d) - aborting!\n",
|
||||
mdname(mddev), cnt, mddev->raid_disks);
|
||||
goto abort;
|
||||
}
|
||||
zone->nb_dev = cnt;
|
||||
zone->zone_end = smallest->sectors * cnt;
|
||||
|
||||
|
|
|
|||
|
|
@ -155,6 +155,16 @@ static inline bool raid1_add_bio_to_plug(struct mddev *mddev, struct bio *bio,
|
|||
return true;
|
||||
}
|
||||
|
||||
/* Block size used when narrowing a write error down to badblocks granularity. */
|
||||
static inline int rdev_bb_block_sectors(struct md_rdev *rdev)
|
||||
{
|
||||
int lbs = bdev_logical_block_size(rdev->bdev) >> 9;
|
||||
|
||||
if (rdev->badblocks.shift < 0)
|
||||
return lbs;
|
||||
return roundup(1 << rdev->badblocks.shift, lbs);
|
||||
}
|
||||
|
||||
/*
|
||||
* current->bio_list will be set under submit_bio() context, in this case bitmap
|
||||
* io will be added to the list and wait for current io submission to finish,
|
||||
|
|
@ -166,6 +176,23 @@ static inline void raid1_prepare_flush_writes(struct mddev *mddev)
|
|||
mddev->bitmap_ops->unplug(mddev, current->bio_list == NULL);
|
||||
}
|
||||
|
||||
static inline void flush_bio_list(struct mddev *mddev, struct bio *bio,
|
||||
wait_queue_head_t *wait)
|
||||
{
|
||||
/* flush any pending bitmap writes to disk before proceeding w/ I/O */
|
||||
raid1_prepare_flush_writes(mddev);
|
||||
if (wq_has_sleeper(wait))
|
||||
wake_up(wait);
|
||||
|
||||
while (bio) { /* submit pending writes */
|
||||
struct bio *next = bio->bi_next;
|
||||
|
||||
raid1_submit_write(bio);
|
||||
bio = next;
|
||||
cond_resched();
|
||||
}
|
||||
}
|
||||
|
||||
/*
|
||||
* Used by fix_read_error() to decay the per rdev read_errors.
|
||||
* We halve the read error count for every hour that has elapsed
|
||||
|
|
|
|||
|
|
@ -483,10 +483,7 @@ static void raid1_end_write_request(struct bio *bio)
|
|||
* 'one mirror IO has finished' event handler:
|
||||
*/
|
||||
if (bio->bi_status && !ignore_error) {
|
||||
set_bit(WriteErrorSeen, &rdev->flags);
|
||||
if (!test_and_set_bit(WantReplacement, &rdev->flags))
|
||||
set_bit(MD_RECOVERY_NEEDED, &
|
||||
conf->mddev->recovery);
|
||||
rdev_record_write_error(rdev);
|
||||
|
||||
if (test_bit(FailFast, &rdev->flags) &&
|
||||
(bio->bi_opf & MD_FAILFAST) &&
|
||||
|
|
@ -922,21 +919,6 @@ static void wake_up_barrier(struct r1conf *conf)
|
|||
wake_up(&conf->wait_barrier);
|
||||
}
|
||||
|
||||
static void flush_bio_list(struct r1conf *conf, struct bio *bio)
|
||||
{
|
||||
/* flush any pending bitmap writes to disk before proceeding w/ I/O */
|
||||
raid1_prepare_flush_writes(conf->mddev);
|
||||
wake_up_barrier(conf);
|
||||
|
||||
while (bio) { /* submit pending writes */
|
||||
struct bio *next = bio->bi_next;
|
||||
|
||||
raid1_submit_write(bio);
|
||||
bio = next;
|
||||
cond_resched();
|
||||
}
|
||||
}
|
||||
|
||||
static void flush_pending_writes(struct r1conf *conf)
|
||||
{
|
||||
/* Any writes that have been queued but are awaiting
|
||||
|
|
@ -962,7 +944,7 @@ static void flush_pending_writes(struct r1conf *conf)
|
|||
*/
|
||||
__set_current_state(TASK_RUNNING);
|
||||
blk_start_plug(&plug);
|
||||
flush_bio_list(conf, bio);
|
||||
flush_bio_list(conf->mddev, bio, &conf->wait_barrier);
|
||||
blk_finish_plug(&plug);
|
||||
} else
|
||||
spin_unlock_irq(&conf->device_lock);
|
||||
|
|
@ -1292,7 +1274,7 @@ static void raid1_unplug(struct blk_plug_cb *cb, bool from_schedule)
|
|||
|
||||
/* we aren't scheduling, so we can do the write-out directly. */
|
||||
bio = bio_list_get(&plug->pending);
|
||||
flush_bio_list(conf, bio);
|
||||
flush_bio_list(conf->mddev, bio, &conf->wait_barrier);
|
||||
kfree(plug);
|
||||
}
|
||||
|
||||
|
|
@ -2067,10 +2049,7 @@ static void end_sync_write(struct bio *bio)
|
|||
|
||||
if (bio->bi_status) {
|
||||
abort_sync_write(mddev, r1_bio);
|
||||
set_bit(WriteErrorSeen, &rdev->flags);
|
||||
if (!test_and_set_bit(WantReplacement, &rdev->flags))
|
||||
set_bit(MD_RECOVERY_NEEDED, &
|
||||
mddev->recovery);
|
||||
rdev_record_write_error(rdev);
|
||||
set_bit(R1BIO_WriteError, &r1_bio->state);
|
||||
} else if (rdev_has_badblock(rdev, r1_bio->sector, r1_bio->sectors) &&
|
||||
!rdev_has_badblock(conf->mirrors[r1_bio->read_disk].rdev,
|
||||
|
|
@ -2088,11 +2067,7 @@ static int r1_sync_page_io(struct md_rdev *rdev, sector_t sector,
|
|||
/* success */
|
||||
return 1;
|
||||
if (rw == REQ_OP_WRITE) {
|
||||
set_bit(WriteErrorSeen, &rdev->flags);
|
||||
if (!test_and_set_bit(WantReplacement,
|
||||
&rdev->flags))
|
||||
set_bit(MD_RECOVERY_NEEDED, &
|
||||
rdev->mddev->recovery);
|
||||
rdev_record_write_error(rdev);
|
||||
}
|
||||
/* need to record an error - either for the block or the device */
|
||||
rdev_set_badblocks(rdev, sector, sectors, 0);
|
||||
|
|
@ -2475,16 +2450,11 @@ static void narrow_write_error(struct r1bio *r1_bio, int i)
|
|||
* We currently own a reference on the rdev.
|
||||
*/
|
||||
|
||||
int block_sectors, lbs = bdev_logical_block_size(rdev->bdev) >> 9;
|
||||
int block_sectors = rdev_bb_block_sectors(rdev);
|
||||
sector_t sector;
|
||||
int sectors;
|
||||
int sect_to_write = r1_bio->sectors;
|
||||
|
||||
if (rdev->badblocks.shift < 0)
|
||||
block_sectors = lbs;
|
||||
else
|
||||
block_sectors = roundup(1 << rdev->badblocks.shift, lbs);
|
||||
|
||||
sector = r1_bio->sector;
|
||||
sectors = ((sector + block_sectors)
|
||||
& ~(sector_t)(block_sectors - 1))
|
||||
|
|
|
|||
|
|
@ -496,10 +496,7 @@ static void raid10_end_write_request(struct bio *bio)
|
|||
*/
|
||||
md_error(rdev->mddev, rdev);
|
||||
else {
|
||||
set_bit(WriteErrorSeen, &rdev->flags);
|
||||
if (!test_and_set_bit(WantReplacement, &rdev->flags))
|
||||
set_bit(MD_RECOVERY_NEEDED,
|
||||
&rdev->mddev->recovery);
|
||||
rdev_record_write_error(rdev);
|
||||
|
||||
dec_rdev = 0;
|
||||
if (test_bit(FailFast, &rdev->flags) &&
|
||||
|
|
@ -898,16 +895,7 @@ static void flush_pending_writes(struct r10conf *conf)
|
|||
__set_current_state(TASK_RUNNING);
|
||||
|
||||
blk_start_plug(&plug);
|
||||
raid1_prepare_flush_writes(conf->mddev);
|
||||
wake_up(&conf->wait_barrier);
|
||||
|
||||
while (bio) { /* submit pending writes */
|
||||
struct bio *next = bio->bi_next;
|
||||
|
||||
raid1_submit_write(bio);
|
||||
bio = next;
|
||||
cond_resched();
|
||||
}
|
||||
flush_bio_list(conf->mddev, bio, &conf->wait_barrier);
|
||||
blk_finish_plug(&plug);
|
||||
} else
|
||||
spin_unlock_irq(&conf->device_lock);
|
||||
|
|
@ -1010,7 +998,8 @@ static bool wait_barrier_nolock(struct r10conf *conf)
|
|||
if (!read_seqretry(&conf->resync_lock, seq))
|
||||
return true;
|
||||
|
||||
if (atomic_dec_and_test(&conf->nr_pending))
|
||||
if (atomic_dec_and_test(&conf->nr_pending) ||
|
||||
READ_ONCE(conf->array_freeze_pending))
|
||||
wake_up_barrier(conf);
|
||||
|
||||
return false;
|
||||
|
|
@ -1037,7 +1026,7 @@ static void wait_barrier(struct r10conf *conf)
|
|||
static void allow_barrier(struct r10conf *conf)
|
||||
{
|
||||
if ((atomic_dec_and_test(&conf->nr_pending)) ||
|
||||
(conf->array_freeze_pending))
|
||||
READ_ONCE(conf->array_freeze_pending))
|
||||
wake_up_barrier(conf);
|
||||
}
|
||||
|
||||
|
|
@ -1056,12 +1045,12 @@ static void freeze_array(struct r10conf *conf, int extra)
|
|||
* we continue.
|
||||
*/
|
||||
write_seqlock_irq(&conf->resync_lock);
|
||||
conf->array_freeze_pending++;
|
||||
WRITE_ONCE(conf->array_freeze_pending, conf->array_freeze_pending + 1);
|
||||
WRITE_ONCE(conf->barrier, conf->barrier + 1);
|
||||
conf->nr_waiting++;
|
||||
wait_event_barrier_cmd(conf, atomic_read(&conf->nr_pending) ==
|
||||
conf->nr_queued + extra, flush_pending_writes(conf));
|
||||
conf->array_freeze_pending--;
|
||||
WRITE_ONCE(conf->array_freeze_pending, conf->array_freeze_pending - 1);
|
||||
write_sequnlock_irq(&conf->resync_lock);
|
||||
}
|
||||
|
||||
|
|
@ -1104,16 +1093,7 @@ static void raid10_unplug(struct blk_plug_cb *cb, bool from_schedule)
|
|||
|
||||
/* we aren't scheduling, so we can do the write-out directly. */
|
||||
bio = bio_list_get(&plug->pending);
|
||||
raid1_prepare_flush_writes(mddev);
|
||||
wake_up_barrier(conf);
|
||||
|
||||
while (bio) { /* submit pending writes */
|
||||
struct bio *next = bio->bi_next;
|
||||
|
||||
raid1_submit_write(bio);
|
||||
bio = next;
|
||||
cond_resched();
|
||||
}
|
||||
flush_bio_list(mddev, bio, &conf->wait_barrier);
|
||||
kfree(plug);
|
||||
}
|
||||
|
||||
|
|
@ -2299,10 +2279,7 @@ static void end_sync_write(struct bio *bio)
|
|||
if (repl)
|
||||
md_error(mddev, rdev);
|
||||
else {
|
||||
set_bit(WriteErrorSeen, &rdev->flags);
|
||||
if (!test_and_set_bit(WantReplacement, &rdev->flags))
|
||||
set_bit(MD_RECOVERY_NEEDED,
|
||||
&rdev->mddev->recovery);
|
||||
rdev_record_write_error(rdev);
|
||||
set_bit(R10BIO_WriteError, &r10_bio->state);
|
||||
}
|
||||
} else if (rdev_has_badblock(rdev, r10_bio->devs[slot].addr,
|
||||
|
|
@ -2500,11 +2477,7 @@ static void fix_recovery_read_error(struct r10bio *r10_bio)
|
|||
pages[idx],
|
||||
REQ_OP_WRITE, false);
|
||||
if (!ok) {
|
||||
set_bit(WriteErrorSeen, &rdev->flags);
|
||||
if (!test_and_set_bit(WantReplacement,
|
||||
&rdev->flags))
|
||||
set_bit(MD_RECOVERY_NEEDED,
|
||||
&rdev->mddev->recovery);
|
||||
rdev_record_write_error(rdev);
|
||||
}
|
||||
}
|
||||
if (!ok) {
|
||||
|
|
@ -2585,10 +2558,7 @@ static int r10_sync_page_io(struct md_rdev *rdev, sector_t sector,
|
|||
/* success */
|
||||
return 1;
|
||||
if (op == REQ_OP_WRITE) {
|
||||
set_bit(WriteErrorSeen, &rdev->flags);
|
||||
if (!test_and_set_bit(WantReplacement, &rdev->flags))
|
||||
set_bit(MD_RECOVERY_NEEDED,
|
||||
&rdev->mddev->recovery);
|
||||
rdev_record_write_error(rdev);
|
||||
}
|
||||
/* need to record an error - either for the block or the device */
|
||||
rdev_set_badblocks(rdev, sector, sectors, 0);
|
||||
|
|
@ -2775,16 +2745,11 @@ static void narrow_write_error(struct r10bio *r10_bio, int i)
|
|||
* We currently own a reference to the rdev.
|
||||
*/
|
||||
|
||||
int block_sectors, lbs = bdev_logical_block_size(rdev->bdev) >> 9;
|
||||
int block_sectors = rdev_bb_block_sectors(rdev);
|
||||
sector_t sector;
|
||||
int sectors;
|
||||
int sect_to_write = r10_bio->sectors;
|
||||
|
||||
if (rdev->badblocks.shift < 0)
|
||||
block_sectors = lbs;
|
||||
else
|
||||
block_sectors = roundup(1 << rdev->badblocks.shift, lbs);
|
||||
|
||||
sector = r10_bio->sector;
|
||||
sectors = ((r10_bio->sector + block_sectors)
|
||||
& ~(sector_t)(block_sectors - 1))
|
||||
|
|
|
|||
|
|
@ -432,10 +432,8 @@ static inline void r5c_update_log_state(struct r5l_log *log)
|
|||
wake_reclaim = true;
|
||||
clear_bit(R5C_LOG_CRITICAL, &conf->cache_state);
|
||||
}
|
||||
if (free_space < 3 * reclaim_space)
|
||||
set_bit(R5C_LOG_TIGHT, &conf->cache_state);
|
||||
else
|
||||
clear_bit(R5C_LOG_TIGHT, &conf->cache_state);
|
||||
assign_bit(R5C_LOG_TIGHT, &conf->cache_state,
|
||||
free_space < 3 * reclaim_space);
|
||||
|
||||
if (wake_reclaim)
|
||||
r5l_wake_reclaim(log, 0);
|
||||
|
|
@ -2001,27 +1999,36 @@ r5l_recovery_verify_data_checksum_for_mb(struct r5l_log *log,
|
|||
if (!page)
|
||||
return -ENOMEM;
|
||||
|
||||
while (mb_offset < le32_to_cpu(mb->meta_size)) {
|
||||
while (mb_offset + sizeof(struct r5l_payload_header) <= le32_to_cpu(mb->meta_size)) {
|
||||
u32 payload_size;
|
||||
sector_t payload_len;
|
||||
|
||||
payload = (void *)mb + mb_offset;
|
||||
payload_flush = (void *)mb + mb_offset;
|
||||
|
||||
if (le16_to_cpu(payload->header.type) == R5LOG_PAYLOAD_DATA) {
|
||||
if (mb_offset + sizeof(struct r5l_payload_data_parity)
|
||||
> le32_to_cpu(mb->meta_size))
|
||||
goto mismatch;
|
||||
payload_size = le32_to_cpu(payload->size) >> (PAGE_SHIFT - 9);
|
||||
payload_len = sizeof(struct r5l_payload_data_parity) +
|
||||
(sector_t)sizeof(__le32) *
|
||||
(le32_to_cpu(payload->size) >> (PAGE_SHIFT - 9));
|
||||
if (mb_offset + payload_len > le32_to_cpu(mb->meta_size))
|
||||
(sector_t)sizeof(__le32) * payload_size;
|
||||
if (mb_offset + payload_len > le32_to_cpu(mb->meta_size) ||
|
||||
payload_size < 1)
|
||||
goto mismatch;
|
||||
if (r5l_recovery_verify_data_checksum(
|
||||
log, ctx, page, log_offset,
|
||||
payload->checksum[0]) < 0)
|
||||
goto mismatch;
|
||||
} else if (le16_to_cpu(payload->header.type) == R5LOG_PAYLOAD_PARITY) {
|
||||
if (mb_offset + sizeof(struct r5l_payload_data_parity)
|
||||
> le32_to_cpu(mb->meta_size))
|
||||
goto mismatch;
|
||||
payload_size = le32_to_cpu(payload->size) >> (PAGE_SHIFT - 9);
|
||||
payload_len = sizeof(struct r5l_payload_data_parity) +
|
||||
(sector_t)sizeof(__le32) *
|
||||
(le32_to_cpu(payload->size) >> (PAGE_SHIFT - 9));
|
||||
if (mb_offset + payload_len > le32_to_cpu(mb->meta_size))
|
||||
(sector_t)sizeof(__le32) * payload_size;
|
||||
if (mb_offset + payload_len > le32_to_cpu(mb->meta_size) ||
|
||||
payload_size < conf->max_degraded)
|
||||
goto mismatch;
|
||||
if (r5l_recovery_verify_data_checksum(
|
||||
log, ctx, page, log_offset,
|
||||
|
|
@ -2035,6 +2042,9 @@ r5l_recovery_verify_data_checksum_for_mb(struct r5l_log *log,
|
|||
payload->checksum[1]) < 0)
|
||||
goto mismatch;
|
||||
} else if (le16_to_cpu(payload->header.type) == R5LOG_PAYLOAD_FLUSH) {
|
||||
if (mb_offset + sizeof(struct r5l_payload_flush)
|
||||
> le32_to_cpu(mb->meta_size))
|
||||
goto mismatch;
|
||||
payload_len = sizeof(struct r5l_payload_flush) +
|
||||
(sector_t)le32_to_cpu(payload_flush->size);
|
||||
if (mb_offset + payload_len > le32_to_cpu(mb->meta_size))
|
||||
|
|
@ -2096,7 +2106,7 @@ r5c_recovery_analyze_meta_block(struct r5l_log *log,
|
|||
mb_offset = sizeof(struct r5l_meta_block);
|
||||
log_offset = r5l_ring_add(log, ctx->pos, BLOCK_SECTORS);
|
||||
|
||||
while (mb_offset < le32_to_cpu(mb->meta_size)) {
|
||||
while (mb_offset + sizeof(struct r5l_payload_header) < le32_to_cpu(mb->meta_size)) {
|
||||
sector_t payload_len;
|
||||
int dd;
|
||||
|
||||
|
|
@ -2106,6 +2116,9 @@ r5c_recovery_analyze_meta_block(struct r5l_log *log,
|
|||
if (le16_to_cpu(payload->header.type) == R5LOG_PAYLOAD_FLUSH) {
|
||||
int i, count;
|
||||
|
||||
if (mb_offset + sizeof(struct r5l_payload_flush) >
|
||||
le32_to_cpu(mb->meta_size))
|
||||
return -EINVAL;
|
||||
payload_len = sizeof(struct r5l_payload_flush) +
|
||||
(sector_t)le32_to_cpu(payload_flush->size);
|
||||
if (mb_offset + payload_len >
|
||||
|
|
@ -2130,6 +2143,9 @@ r5c_recovery_analyze_meta_block(struct r5l_log *log,
|
|||
}
|
||||
|
||||
/* DATA or PARITY payload */
|
||||
if (mb_offset + sizeof(struct r5l_payload_data_parity) >
|
||||
le32_to_cpu(mb->meta_size))
|
||||
return -EINVAL;
|
||||
payload_len = sizeof(struct r5l_payload_data_parity) +
|
||||
(sector_t)sizeof(__le32) *
|
||||
(le32_to_cpu(payload->size) >> (PAGE_SHIFT - 9));
|
||||
|
|
@ -2952,7 +2968,9 @@ bool r5c_big_stripe_cached(struct r5conf *conf, sector_t sect)
|
|||
return false;
|
||||
|
||||
tree_index = r5c_tree_index(conf, sect);
|
||||
rcu_read_lock();
|
||||
slot = radix_tree_lookup(&log->big_stripe_tree, tree_index);
|
||||
rcu_read_unlock();
|
||||
return slot != NULL;
|
||||
}
|
||||
|
||||
|
|
@ -3066,6 +3084,7 @@ int r5l_init_log(struct r5conf *conf, struct md_rdev *rdev)
|
|||
{
|
||||
struct r5l_log *log;
|
||||
struct md_thread *thread;
|
||||
char cache_name[48];
|
||||
int ret;
|
||||
|
||||
pr_debug("md/raid:%s: using device %pg as journal\n",
|
||||
|
|
@ -3105,7 +3124,16 @@ int r5l_init_log(struct r5conf *conf, struct md_rdev *rdev)
|
|||
INIT_LIST_HEAD(&log->flushing_ios);
|
||||
INIT_LIST_HEAD(&log->finished_ios);
|
||||
|
||||
log->io_kc = KMEM_CACHE(r5l_io_unit, 0);
|
||||
if (mddev_is_dm(conf->mddev))
|
||||
snprintf(cache_name, sizeof(cache_name), "r5l_io_unit-%p",
|
||||
conf->mddev);
|
||||
else
|
||||
snprintf(cache_name, sizeof(cache_name), "r5l_io_unit-%s",
|
||||
mdname(conf->mddev));
|
||||
|
||||
log->io_kc = kmem_cache_create(cache_name, sizeof(struct r5l_io_unit),
|
||||
__alignof__(struct r5l_io_unit),
|
||||
0, NULL);
|
||||
if (!log->io_kc)
|
||||
goto io_kc;
|
||||
|
||||
|
|
|
|||
|
|
@ -1318,6 +1318,7 @@ int ppl_init_log(struct r5conf *conf)
|
|||
{
|
||||
struct ppl_conf *ppl_conf;
|
||||
struct mddev *mddev = conf->mddev;
|
||||
char cache_name[48];
|
||||
int ret = 0;
|
||||
int max_disks;
|
||||
int i;
|
||||
|
|
@ -1360,7 +1361,16 @@ int ppl_init_log(struct r5conf *conf)
|
|||
|
||||
ppl_conf->mddev = mddev;
|
||||
|
||||
ppl_conf->io_kc = KMEM_CACHE(ppl_io_unit, 0);
|
||||
if (mddev_is_dm(mddev))
|
||||
snprintf(cache_name, sizeof(cache_name), "ppl_io_unit-%p", mddev);
|
||||
else
|
||||
snprintf(cache_name, sizeof(cache_name), "ppl_io_unit-%s",
|
||||
mdname(mddev));
|
||||
|
||||
ppl_conf->io_kc = kmem_cache_create(cache_name,
|
||||
sizeof(struct ppl_io_unit),
|
||||
__alignof__(struct ppl_io_unit),
|
||||
0, NULL);
|
||||
if (!ppl_conf->io_kc) {
|
||||
ret = -ENOMEM;
|
||||
goto err;
|
||||
|
|
|
|||
|
|
@ -2642,6 +2642,7 @@ static int resize_stripes(struct r5conf *conf, int newsize)
|
|||
} else {
|
||||
kfree(conf->disks);
|
||||
conf->disks = ndisks;
|
||||
conf->disks_cnt = newsize;
|
||||
}
|
||||
} else
|
||||
err = -ENOMEM;
|
||||
|
|
@ -2712,6 +2713,37 @@ static int drop_one_stripe(struct r5conf *conf)
|
|||
|
||||
static void shrink_stripes(struct r5conf *conf)
|
||||
{
|
||||
struct list_head temp[NR_STRIPE_HASH_LOCKS];
|
||||
int i;
|
||||
|
||||
/*
|
||||
* grow_one_stripe() parks new stripes on released_stripes when
|
||||
* mddev->thread is already set. Takeover leaves the previous
|
||||
* personality's thread there, so raid5d never moves them to
|
||||
* inactive_list. Drain them before the cache is destroyed.
|
||||
* slab_cache is assigned only after device_lock and the hash
|
||||
* lists exist; earlier abort paths have nothing to drain.
|
||||
*/
|
||||
if (conf->slab_cache) {
|
||||
for (i = 0; i < NR_STRIPE_HASH_LOCKS; i++)
|
||||
INIT_LIST_HEAD(&temp[i]);
|
||||
|
||||
spin_lock_irq(&conf->device_lock);
|
||||
release_stripe_list(conf, temp);
|
||||
spin_unlock_irq(&conf->device_lock);
|
||||
|
||||
for (i = 0; i < NR_STRIPE_HASH_LOCKS; i++) {
|
||||
if (list_empty(&temp[i]))
|
||||
continue;
|
||||
spin_lock_irq(conf->hash_locks + i);
|
||||
if (list_empty(conf->inactive_list + i))
|
||||
atomic_dec(&conf->empty_inactive_list_nr);
|
||||
list_splice_tail_init(&temp[i],
|
||||
conf->inactive_list + i);
|
||||
spin_unlock_irq(conf->hash_locks + i);
|
||||
}
|
||||
}
|
||||
|
||||
while (conf->max_nr_stripes &&
|
||||
drop_one_stripe(conf))
|
||||
;
|
||||
|
|
@ -2888,11 +2920,8 @@ static void raid5_end_write_request(struct bio *bi)
|
|||
set_bit(R5_MadeGoodRepl, &sh->dev[i].flags);
|
||||
} else {
|
||||
if (bi->bi_status) {
|
||||
set_bit(WriteErrorSeen, &rdev->flags);
|
||||
rdev_record_write_error(rdev);
|
||||
set_bit(R5_WriteError, &sh->dev[i].flags);
|
||||
if (!test_and_set_bit(WantReplacement, &rdev->flags))
|
||||
set_bit(MD_RECOVERY_NEEDED,
|
||||
&rdev->mddev->recovery);
|
||||
} else if (rdev_has_badblock(rdev, sh->sector,
|
||||
RAID5_STRIPE_SECTORS(conf))) {
|
||||
set_bit(R5_MadeGood, &sh->dev[i].flags);
|
||||
|
|
@ -4748,10 +4777,8 @@ static void analyse_stripe(struct stripe_head *sh, struct stripe_head_state *s)
|
|||
RAID5_STRIPE_SECTORS(conf)))
|
||||
set_bit(R5_ReadRepl, &dev->flags);
|
||||
else {
|
||||
if (rdev && !test_bit(Faulty, &rdev->flags))
|
||||
set_bit(R5_NeedReplace, &dev->flags);
|
||||
else
|
||||
clear_bit(R5_NeedReplace, &dev->flags);
|
||||
assign_bit(R5_NeedReplace, &dev->flags,
|
||||
rdev && !test_bit(Faulty, &rdev->flags));
|
||||
rdev = conf->disks[i].rdev;
|
||||
clear_bit(R5_ReadRepl, &dev->flags);
|
||||
}
|
||||
|
|
@ -7538,7 +7565,8 @@ static void raid5_free_percpu(struct r5conf *conf)
|
|||
if (!conf->percpu)
|
||||
return;
|
||||
|
||||
cpuhp_state_remove_instance(CPUHP_MD_RAID5_PREPARE, &conf->node);
|
||||
if (!hlist_unhashed_lockless(&conf->node))
|
||||
cpuhp_state_remove_instance(CPUHP_MD_RAID5_PREPARE, &conf->node);
|
||||
free_percpu(conf->percpu);
|
||||
}
|
||||
|
||||
|
|
@ -7552,7 +7580,7 @@ static void free_conf(struct r5conf *conf)
|
|||
free_thread_groups(conf);
|
||||
shrink_stripes(conf);
|
||||
raid5_free_percpu(conf);
|
||||
for (i = 0; i < conf->pool_size; i++)
|
||||
for (i = 0; i < conf->disks_cnt; i++)
|
||||
if (conf->disks[i].extra_page)
|
||||
put_page(conf->disks[i].extra_page);
|
||||
kfree(conf->disks);
|
||||
|
|
@ -7630,10 +7658,15 @@ static unsigned long raid5_cache_count(struct shrinker *shrink,
|
|||
return max_stripes - min_stripes;
|
||||
}
|
||||
|
||||
static int min_raid_disks(int level)
|
||||
{
|
||||
return level == 6 ? 4 : 2;
|
||||
}
|
||||
|
||||
static struct r5conf *setup_conf(struct mddev *mddev)
|
||||
{
|
||||
struct r5conf *conf;
|
||||
int raid_disk, memory, max_disks;
|
||||
int raid_disk, memory, max_disks, min_disks;
|
||||
struct md_rdev *rdev;
|
||||
struct disk_info *disk;
|
||||
char pers_name[6];
|
||||
|
|
@ -7657,9 +7690,11 @@ static struct r5conf *setup_conf(struct mddev *mddev)
|
|||
mdname(mddev), mddev->new_layout);
|
||||
return ERR_PTR(-EIO);
|
||||
}
|
||||
if (mddev->new_level == 6 && mddev->raid_disks < 4) {
|
||||
pr_warn("md/raid:%s: not enough configured devices (%d, minimum 4)\n",
|
||||
mdname(mddev), mddev->raid_disks);
|
||||
min_disks = min_raid_disks(mddev->new_level);
|
||||
if (mddev->raid_disks < min_disks) {
|
||||
pr_warn("md/raid:%s: not enough configured devices (%d, minimum %d)\n",
|
||||
mdname(mddev), mddev->raid_disks,
|
||||
min_disks);
|
||||
return ERR_PTR(-EINVAL);
|
||||
}
|
||||
|
||||
|
|
@ -7675,6 +7710,7 @@ static struct r5conf *setup_conf(struct mddev *mddev)
|
|||
if (conf == NULL)
|
||||
goto abort;
|
||||
|
||||
conf->mddev = mddev;
|
||||
#if PAGE_SIZE != DEFAULT_STRIPE_SIZE
|
||||
conf->stripe_size = DEFAULT_STRIPE_SIZE;
|
||||
conf->stripe_shift = ilog2(DEFAULT_STRIPE_SIZE) - 9;
|
||||
|
|
@ -7733,7 +7769,7 @@ static struct r5conf *setup_conf(struct mddev *mddev)
|
|||
|
||||
if (!conf->disks)
|
||||
goto abort;
|
||||
|
||||
conf->disks_cnt = max_disks;
|
||||
for (i = 0; i < max_disks; i++) {
|
||||
conf->disks[i].extra_page = alloc_page(GFP_KERNEL);
|
||||
if (!conf->disks[i].extra_page)
|
||||
|
|
@ -7743,7 +7779,6 @@ static struct r5conf *setup_conf(struct mddev *mddev)
|
|||
ret = bioset_init(&conf->bio_split, BIO_POOL_SIZE, 0, 0);
|
||||
if (ret)
|
||||
goto abort;
|
||||
conf->mddev = mddev;
|
||||
|
||||
ret = -ENOMEM;
|
||||
conf->stripe_hashtbl = kzalloc(PAGE_SIZE, GFP_KERNEL);
|
||||
|
|
@ -8046,6 +8081,7 @@ static int raid5_run(struct mddev *mddev)
|
|||
sector_t here_new, here_old;
|
||||
int old_disks;
|
||||
int max_degraded = (mddev->level == 6 ? 2 : 1);
|
||||
int min_disks = min_raid_disks(mddev->level);
|
||||
int chunk_sectors;
|
||||
int new_data_disks;
|
||||
|
||||
|
|
@ -8061,6 +8097,12 @@ static int raid5_run(struct mddev *mddev)
|
|||
return -EINVAL;
|
||||
}
|
||||
old_disks = mddev->raid_disks - mddev->delta_disks;
|
||||
if (mddev->raid_disks < min_disks || old_disks < min_disks) {
|
||||
pr_warn("md/raid:%s: invalid reshape disks (%d -> %d, min %d)\n",
|
||||
mdname(mddev), old_disks, mddev->raid_disks,
|
||||
min_disks);
|
||||
return -EINVAL;
|
||||
}
|
||||
/* reshape_position must be on a new-stripe boundary, and one
|
||||
* further up in new geometry must map after here in old
|
||||
* geometry.
|
||||
|
|
@ -8110,11 +8152,17 @@ static int raid5_run(struct mddev *mddev)
|
|||
}
|
||||
pr_debug("md/raid:%s: reshape will continue\n", mdname(mddev));
|
||||
/* OK, we should be able to continue; */
|
||||
} else {
|
||||
BUG_ON(mddev->level != mddev->new_level);
|
||||
BUG_ON(mddev->layout != mddev->new_layout);
|
||||
BUG_ON(mddev->chunk_sectors != mddev->new_chunk_sectors);
|
||||
BUG_ON(mddev->delta_disks != 0);
|
||||
} else if (mddev->level != mddev->new_level ||
|
||||
mddev->layout != mddev->new_layout ||
|
||||
mddev->chunk_sectors != mddev->new_chunk_sectors ||
|
||||
mddev->delta_disks != 0) {
|
||||
/* No reshape is in progress, but the array describes one.
|
||||
* The superblock validators do not cross-check these against
|
||||
* reshape_position, so this is reachable from disk.
|
||||
*/
|
||||
pr_warn("md/raid:%s: inconsistent reshape state - aborting.\n",
|
||||
mdname(mddev));
|
||||
return -EINVAL;
|
||||
}
|
||||
|
||||
if (test_bit(MD_HAS_JOURNAL, &mddev->flags) &&
|
||||
|
|
@ -8203,6 +8251,12 @@ static int raid5_run(struct mddev *mddev)
|
|||
|
||||
/* device size must be a multiple of chunk size */
|
||||
mddev->dev_sectors &= ~((sector_t)mddev->chunk_sectors - 1);
|
||||
if (!mddev->dev_sectors) {
|
||||
pr_warn("md/raid:%s: device size is smaller than one chunk\n",
|
||||
mdname(mddev));
|
||||
ret = -EINVAL;
|
||||
goto abort;
|
||||
}
|
||||
mddev->resync_max_sectors = mddev->dev_sectors;
|
||||
|
||||
if (mddev->degraded > dirty_parity_disks &&
|
||||
|
|
@ -8536,6 +8590,8 @@ static int raid5_resize(struct mddev *mddev, sector_t sectors)
|
|||
if (raid5_has_log(conf) || raid5_has_ppl(conf))
|
||||
return -EINVAL;
|
||||
sectors &= ~((sector_t)conf->chunk_sectors - 1);
|
||||
if (!sectors)
|
||||
return -EINVAL;
|
||||
newsize = raid5_size(mddev, sectors, mddev->raid_disks);
|
||||
if (mddev->external_size &&
|
||||
mddev->array_sectors > newsize)
|
||||
|
|
@ -8600,13 +8656,9 @@ static int check_reshape(struct mddev *mddev)
|
|||
if (mddev->delta_disks < 0 && mddev->reshape_position == MaxSector) {
|
||||
/* We might be able to shrink, but the devices must
|
||||
* be made bigger first.
|
||||
* For raid6, 4 is the minimum size.
|
||||
* Otherwise 2 is the minimum
|
||||
*/
|
||||
int min = 2;
|
||||
if (mddev->level == 6)
|
||||
min = 4;
|
||||
if (mddev->raid_disks + mddev->delta_disks < min)
|
||||
if (mddev->raid_disks + mddev->delta_disks <
|
||||
min_raid_disks(mddev->level))
|
||||
return -EINVAL;
|
||||
}
|
||||
|
||||
|
|
|
|||
|
|
@ -667,6 +667,7 @@ struct r5conf {
|
|||
unsigned long cache_state;
|
||||
struct shrinker *shrinker;
|
||||
int pool_size; /* number of disks in stripeheads in pool */
|
||||
int disks_cnt; /* number of entries in disks[] array */
|
||||
spinlock_t device_lock;
|
||||
struct disk_info *disks;
|
||||
struct bio_set bio_split;
|
||||
|
|
|
|||
Loading…
Reference in New Issue
Block a user