diff --git a/drivers/md/md.c b/drivers/md/md.c index 680b34a63cb3..03e35386a802 100644 --- a/drivers/md/md.c +++ b/drivers/md/md.c @@ -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->'. 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<flags); - else - clear_bit(WriteMostly, &rdev->flags); - if (info->state & (1<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<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; diff --git a/drivers/md/raid0.c b/drivers/md/raid0.c index 35e103f0c2c3..453e8abda22b 100644 --- a/drivers/md/raid0.c +++ b/drivers/md/raid0.c @@ -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; diff --git a/drivers/md/raid1-10.c b/drivers/md/raid1-10.c index 3b0e230692ba..341a9785e3f2 100644 --- a/drivers/md/raid1-10.c +++ b/drivers/md/raid1-10.c @@ -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 diff --git a/drivers/md/raid1.c b/drivers/md/raid1.c index f0646fb24371..894efb50c6d5 100644 --- a/drivers/md/raid1.c +++ b/drivers/md/raid1.c @@ -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)) diff --git a/drivers/md/raid10.c b/drivers/md/raid10.c index 1093c798d9dd..066c43154497 100644 --- a/drivers/md/raid10.c +++ b/drivers/md/raid10.c @@ -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)) diff --git a/drivers/md/raid5-cache.c b/drivers/md/raid5-cache.c index 7b7546bfa21f..785ddcb17e9e 100644 --- a/drivers/md/raid5-cache.c +++ b/drivers/md/raid5-cache.c @@ -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; diff --git a/drivers/md/raid5-ppl.c b/drivers/md/raid5-ppl.c index 7f8a9d3fd578..0530632f9d2a 100644 --- a/drivers/md/raid5-ppl.c +++ b/drivers/md/raid5-ppl.c @@ -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; diff --git a/drivers/md/raid5.c b/drivers/md/raid5.c index b91545ce090d..d52adf81065a 100644 --- a/drivers/md/raid5.c +++ b/drivers/md/raid5.c @@ -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; } diff --git a/drivers/md/raid5.h b/drivers/md/raid5.h index cb5feae04db2..94b3e2c947ba 100644 --- a/drivers/md/raid5.h +++ b/drivers/md/raid5.h @@ -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;