]> git.proxmox.com Git - mirror_ubuntu-bionic-kernel.git/blobdiff - drivers/md/raid0.c
block: fix an integer overflow in logical block size
[mirror_ubuntu-bionic-kernel.git] / drivers / md / raid0.c
index 5ecba9eef441fb3ddf0d6929a91a894553e2363a..ad75284f27a99a54f08d7251c55af0092e3dd426 100644 (file)
@@ -26,6 +26,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) |     \
@@ -91,7 +94,7 @@ static int create_strip_zones(struct mddev *mddev, struct r0conf **private_conf)
        char b[BDEVNAME_SIZE];
        char b2[BDEVNAME_SIZE];
        struct r0conf *conf = kzalloc(sizeof(*conf), GFP_KERNEL);
-       unsigned short blksize = 512;
+       unsigned blksize = 512;
 
        *private_conf = ERR_PTR(-ENOMEM);
        if (!conf)
@@ -146,6 +149,23 @@ 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 {
+               conf->layout = RAID0_ALT_MULTIZONE_LAYOUT;
+               pr_warn("md/raid0:%s: !!! DEFAULTING TO ALTERNATE LAYOUT !!!\n",
+                      mdname(mddev));
+               pr_warn("md/raid0: Please set raid0.default_layout to 1 or 2\n");
+               pr_warn("md/raid0: Read the following page for more information:\n");
+               pr_warn("md/raid0: https://wiki.ubuntu.com/Kernel/Raid0LayoutMigration\n");
+       }
        /*
         * now since we have the hard sector sizes, we can make sure
         * chunk size is a multiple of that sector size
@@ -552,17 +572,18 @@ 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;
 
-       if (unlikely(bio->bi_opf & REQ_PREFLUSH)) {
-               md_flush_request(mddev, bio);
+       if (unlikely(bio->bi_opf & REQ_PREFLUSH)
+           && md_flush_request(mddev, bio))
                return true;
-       }
 
        if (unlikely((bio_op(bio) == REQ_OP_DISCARD))) {
                raid0_handle_discard(mddev, bio);
@@ -588,8 +609,26 @@ 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(1, "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);
+               return true;
+       }
+
        bio_set_dev(bio, tmp_dev->bdev);
        bio->bi_iter.bi_sector = sector + zone->dev_start +
                tmp_dev->data_offset;