Skip to content

Commit

Permalink
Merge branch 'md-next' of git://git.kernel.org/pub/scm/linux/kernel/g…
Browse files Browse the repository at this point in the history
…it/song/md into for-5.4/block

Pull MD fixes from Song.

* 'md-next' of git://git.kernel.org/pub/scm/linux/kernel/git/song/md:
  raid5: use bio_end_sector in r5_next_bio
  raid5: remove STRIPE_OPS_REQ_PENDING
  md: add feature flag MD_FEATURE_RAID0_LAYOUT
  md/raid0: avoid RAID0 data corruption due to layout confusion.
  raid5: don't set STRIPE_HANDLE to stripe which is in batch list
  raid5: don't increment read_errors on EILSEQ return
  • Loading branch information
axboe committed Sep 13, 2019
2 parents 21fa100 + 067df25 commit 99e5381
Show file tree
Hide file tree
Showing 6 changed files with 68 additions and 8 deletions.
13 changes: 13 additions & 0 deletions drivers/md/md.c
Original file line number Diff line number Diff line change
Expand Up @@ -1237,6 +1237,8 @@ static int super_90_validate(struct mddev *mddev, struct md_rdev *rdev)
mddev->new_layout = mddev->layout;
mddev->new_chunk_sectors = mddev->chunk_sectors;
}
if (mddev->level == 0)
mddev->layout = -1;

if (sb->state & (1<<MD_SB_CLEAN))
mddev->recovery_cp = MaxSector;
Expand Down Expand Up @@ -1652,6 +1654,10 @@ static int super_1_load(struct md_rdev *rdev, struct md_rdev *refdev, int minor_
rdev->ppl.sector = rdev->sb_start + rdev->ppl.offset;
}

if ((le32_to_cpu(sb->feature_map) & MD_FEATURE_RAID0_LAYOUT) &&
sb->level != 0)
return -EINVAL;

if (!refdev) {
ret = 1;
} else {
Expand Down Expand Up @@ -1762,6 +1768,10 @@ static int super_1_validate(struct mddev *mddev, struct md_rdev *rdev)
mddev->new_chunk_sectors = mddev->chunk_sectors;
}

if (mddev->level == 0 &&
!(le32_to_cpu(sb->feature_map) & MD_FEATURE_RAID0_LAYOUT))
mddev->layout = -1;

if (le32_to_cpu(sb->feature_map) & MD_FEATURE_JOURNAL)
set_bit(MD_HAS_JOURNAL, &mddev->flags);

Expand Down Expand Up @@ -6898,6 +6908,9 @@ static int set_array_info(struct mddev *mddev, mdu_array_info_t *info)
mddev->external = 0;

mddev->layout = info->layout;
if (mddev->level == 0)
/* Cannot trust RAID0 layout info here */
mddev->layout = -1;
mddev->chunk_sectors = info->chunk_size >> 9;

if (mddev->persistent) {
Expand Down
35 changes: 34 additions & 1 deletion drivers/md/raid0.c
Original file line number Diff line number Diff line change
Expand Up @@ -19,6 +19,9 @@
#include "raid0.h"
#include "raid5.h"

static int default_layout = 0;
module_param(default_layout, int, 0644);

#define UNSUPPORTED_MDDEV_FLAGS \
((1L << MD_HAS_JOURNAL) | \
(1L << MD_JOURNAL_CLEAN) | \
Expand Down Expand Up @@ -139,6 +142,22 @@ static int create_strip_zones(struct mddev *mddev, struct r0conf **private_conf)
}
pr_debug("md/raid0:%s: FINAL %d zones\n",
mdname(mddev), conf->nr_strip_zones);

if (conf->nr_strip_zones == 1) {
conf->layout = RAID0_ORIG_LAYOUT;
} else if (mddev->layout == RAID0_ORIG_LAYOUT ||
mddev->layout == RAID0_ALT_MULTIZONE_LAYOUT) {
conf->layout = mddev->layout;
} else if (default_layout == RAID0_ORIG_LAYOUT ||
default_layout == RAID0_ALT_MULTIZONE_LAYOUT) {
conf->layout = default_layout;
} else {
pr_err("md/raid0:%s: cannot assemble multi-zone RAID0 with default_layout setting\n",
mdname(mddev));
pr_err("md/raid0: please set raid.default_layout to 1 or 2\n");
err = -ENOTSUPP;
goto abort;
}
/*
* now since we have the hard sector sizes, we can make sure
* chunk size is a multiple of that sector size
Expand Down Expand Up @@ -547,10 +566,12 @@ static void raid0_handle_discard(struct mddev *mddev, struct bio *bio)

static bool raid0_make_request(struct mddev *mddev, struct bio *bio)
{
struct r0conf *conf = mddev->private;
struct strip_zone *zone;
struct md_rdev *tmp_dev;
sector_t bio_sector;
sector_t sector;
sector_t orig_sector;
unsigned chunk_sects;
unsigned sectors;

Expand Down Expand Up @@ -584,8 +605,20 @@ static bool raid0_make_request(struct mddev *mddev, struct bio *bio)
bio = split;
}

orig_sector = sector;
zone = find_zone(mddev->private, &sector);
tmp_dev = map_sector(mddev, zone, sector, &sector);
switch (conf->layout) {
case RAID0_ORIG_LAYOUT:
tmp_dev = map_sector(mddev, zone, orig_sector, &sector);
break;
case RAID0_ALT_MULTIZONE_LAYOUT:
tmp_dev = map_sector(mddev, zone, sector, &sector);
break;
default:
WARN("md/raid0:%s: Invalid layout\n", mdname(mddev));
bio_io_error(bio);
return true;
}

if (unlikely(is_mddev_broken(tmp_dev, "raid0"))) {
bio_io_error(bio);
Expand Down
14 changes: 14 additions & 0 deletions drivers/md/raid0.h
Original file line number Diff line number Diff line change
Expand Up @@ -8,11 +8,25 @@ struct strip_zone {
int nb_dev; /* # of devices attached to the zone */
};

/* Linux 3.14 (20d0189b101) made an unintended change to
* the RAID0 layout for multi-zone arrays (where devices aren't all
* the same size.
* RAID0_ORIG_LAYOUT restores the original layout
* RAID0_ALT_MULTIZONE_LAYOUT uses the altered layout
* The layouts are identical when there is only one zone (all
* devices the same size).
*/

enum r0layout {
RAID0_ORIG_LAYOUT = 1,
RAID0_ALT_MULTIZONE_LAYOUT = 2,
};
struct r0conf {
struct strip_zone *strip_zone;
struct md_rdev **devlist; /* lists of rdevs, pointed to
* by strip_zone->dev */
int nr_strip_zones;
enum r0layout layout;
};

#endif
7 changes: 4 additions & 3 deletions drivers/md/raid5.c
Original file line number Diff line number Diff line change
Expand Up @@ -2526,7 +2526,8 @@ static void raid5_end_read_request(struct bio * bi)
int set_bad = 0;

clear_bit(R5_UPTODATE, &sh->dev[i].flags);
atomic_inc(&rdev->read_errors);
if (!(bi->bi_status == BLK_STS_PROTECTION))
atomic_inc(&rdev->read_errors);
if (test_bit(R5_ReadRepl, &sh->dev[i].flags))
pr_warn_ratelimited(
"md/raid:%s: read error on replacement device (sector %llu on %s).\n",
Expand Down Expand Up @@ -4620,7 +4621,6 @@ static void break_stripe_batch_list(struct stripe_head *head_sh,
(1 << STRIPE_FULL_WRITE) |
(1 << STRIPE_BIOFILL_RUN) |
(1 << STRIPE_COMPUTE_RUN) |
(1 << STRIPE_OPS_REQ_PENDING) |
(1 << STRIPE_DISCARD) |
(1 << STRIPE_BATCH_READY) |
(1 << STRIPE_BATCH_ERR) |
Expand Down Expand Up @@ -5726,7 +5726,8 @@ static bool raid5_make_request(struct mddev *mddev, struct bio * bi)
do_flush = false;
}

set_bit(STRIPE_HANDLE, &sh->state);
if (!sh->batch_head)
set_bit(STRIPE_HANDLE, &sh->state);
clear_bit(STRIPE_DELAYED, &sh->state);
if ((!sh->batch_head || sh == sh->batch_head) &&
(bi->bi_opf & REQ_SYNC) &&
Expand Down
5 changes: 1 addition & 4 deletions drivers/md/raid5.h
Original file line number Diff line number Diff line change
Expand Up @@ -357,7 +357,6 @@ enum {
STRIPE_FULL_WRITE, /* all blocks are set to be overwritten */
STRIPE_BIOFILL_RUN,
STRIPE_COMPUTE_RUN,
STRIPE_OPS_REQ_PENDING,
STRIPE_ON_UNPLUG_LIST,
STRIPE_DISCARD,
STRIPE_ON_RELEASE_LIST,
Expand Down Expand Up @@ -493,9 +492,7 @@ struct disk_info {
*/
static inline struct bio *r5_next_bio(struct bio *bio, sector_t sector)
{
int sectors = bio_sectors(bio);

if (bio->bi_iter.bi_sector + sectors < sector + STRIPE_SECTORS)
if (bio_end_sector(bio) < sector + STRIPE_SECTORS)
return bio->bi_next;
else
return NULL;
Expand Down
2 changes: 2 additions & 0 deletions include/uapi/linux/raid/md_p.h
Original file line number Diff line number Diff line change
Expand Up @@ -329,6 +329,7 @@ struct mdp_superblock_1 {
#define MD_FEATURE_JOURNAL 512 /* support write cache */
#define MD_FEATURE_PPL 1024 /* support PPL */
#define MD_FEATURE_MULTIPLE_PPLS 2048 /* support for multiple PPLs */
#define MD_FEATURE_RAID0_LAYOUT 4096 /* layout is meaningful for RAID0 */
#define MD_FEATURE_ALL (MD_FEATURE_BITMAP_OFFSET \
|MD_FEATURE_RECOVERY_OFFSET \
|MD_FEATURE_RESHAPE_ACTIVE \
Expand All @@ -341,6 +342,7 @@ struct mdp_superblock_1 {
|MD_FEATURE_JOURNAL \
|MD_FEATURE_PPL \
|MD_FEATURE_MULTIPLE_PPLS \
|MD_FEATURE_RAID0_LAYOUT \
)

struct r5l_payload_header {
Expand Down

0 comments on commit 99e5381

Please sign in to comment.