1af1a8899SThomas Gleixner // SPDX-License-Identifier: GPL-2.0-or-later
21da177e4SLinus Torvalds /*
31da177e4SLinus Torvalds raid0.c : Multiple Devices driver for Linux
41da177e4SLinus Torvalds Copyright (C) 1994-96 Marc ZYNGIER
51da177e4SLinus Torvalds <zyngier@ufr-info-p7.ibp.fr> or
61da177e4SLinus Torvalds <maz@gloups.fdn.fr>
71da177e4SLinus Torvalds Copyright (C) 1999, 2000 Ingo Molnar, Red Hat
81da177e4SLinus Torvalds
91da177e4SLinus Torvalds RAID-0 management functions.
101da177e4SLinus Torvalds
111da177e4SLinus Torvalds */
121da177e4SLinus Torvalds
13bff61975SNeilBrown #include <linux/blkdev.h>
14bff61975SNeilBrown #include <linux/seq_file.h>
15056075c7SPaul Gortmaker #include <linux/module.h>
165a0e3ad6STejun Heo #include <linux/slab.h>
17109e3765SNeilBrown #include <trace/events/block.h>
1843b2e5d8SNeilBrown #include "md.h"
19ef740c37SChristoph Hellwig #include "raid0.h"
209af204cfSTrela, Maciej #include "raid5.h"
211da177e4SLinus Torvalds
22c84a1372SNeilBrown static int default_layout = 0;
23c84a1372SNeilBrown module_param(default_layout, int, 0644);
24c84a1372SNeilBrown
25394ed8e4SShaohua Li #define UNSUPPORTED_MDDEV_FLAGS \
26394ed8e4SShaohua Li ((1L << MD_HAS_JOURNAL) | \
27394ed8e4SShaohua Li (1L << MD_JOURNAL_CLEAN) | \
28ea0213e0SArtur Paszkiewicz (1L << MD_FAILFAST_SUPPORTED) |\
29ddc08823SPawel Baldysiak (1L << MD_HAS_PPL) | \
30ddc08823SPawel Baldysiak (1L << MD_HAS_MULTIPLE_PPLS))
31394ed8e4SShaohua Li
3246994191Sraz ben yehuda /*
3346994191Sraz ben yehuda * inform the user of the raid configuration
3446994191Sraz ben yehuda */
dump_zones(struct mddev * mddev)35fd01b88cSNeilBrown static void dump_zones(struct mddev *mddev)
3646994191Sraz ben yehuda {
3750de8df4SNeilBrown int j, k;
3846994191Sraz ben yehuda sector_t zone_size = 0;
3946994191Sraz ben yehuda sector_t zone_start = 0;
40e373ab10SNeilBrown struct r0conf *conf = mddev->private;
4184707f38SNeilBrown int raid_disks = conf->strip_zone[0].nb_dev;
4276603884SNeilBrown pr_debug("md: RAID0 configuration for %s - %d zone%s\n",
4350de8df4SNeilBrown mdname(mddev),
4450de8df4SNeilBrown conf->nr_strip_zones, conf->nr_strip_zones==1?"":"s");
4546994191Sraz ben yehuda for (j = 0; j < conf->nr_strip_zones; j++) {
4676603884SNeilBrown char line[200];
4776603884SNeilBrown int len = 0;
4876603884SNeilBrown
4946994191Sraz ben yehuda for (k = 0; k < conf->strip_zone[j].nb_dev; k++)
501727fd50SSaurabh Sengar len += scnprintf(line+len, 200-len, "%s%pg", k?"/":"",
51913cce5aSChristoph Hellwig conf->devlist[j * raid_disks + k]->bdev);
5276603884SNeilBrown pr_debug("md: zone%d=[%s]\n", j, line);
5346994191Sraz ben yehuda
5446994191Sraz ben yehuda zone_size = conf->strip_zone[j].zone_end - zone_start;
5576603884SNeilBrown pr_debug(" zone-offset=%10lluKB, device-offset=%10lluKB, size=%10lluKB\n",
5646994191Sraz ben yehuda (unsigned long long)zone_start>>1,
5746994191Sraz ben yehuda (unsigned long long)conf->strip_zone[j].dev_start>>1,
5846994191Sraz ben yehuda (unsigned long long)zone_size>>1);
5946994191Sraz ben yehuda zone_start = conf->strip_zone[j].zone_end;
6046994191Sraz ben yehuda }
6146994191Sraz ben yehuda }
6246994191Sraz ben yehuda
create_strip_zones(struct mddev * mddev,struct r0conf ** private_conf)63e373ab10SNeilBrown static int create_strip_zones(struct mddev *mddev, struct r0conf **private_conf)
641da177e4SLinus Torvalds {
65a9f326ebSNeilBrown int i, c, err;
6649f357a2SNeilBrown sector_t curr_zone_end, sectors;
673cb03002SNeilBrown struct md_rdev *smallest, *rdev1, *rdev2, *rdev, **dev;
681da177e4SLinus Torvalds struct strip_zone *zone;
691da177e4SLinus Torvalds int cnt;
70e373ab10SNeilBrown struct r0conf *conf = kzalloc(sizeof(*conf), GFP_KERNEL);
71ad6bf88aSMikulas Patocka unsigned blksize = 512;
721da177e4SLinus Torvalds
737dedd15dSDan Carpenter *private_conf = ERR_PTR(-ENOMEM);
74ed7b0038SAndre Noll if (!conf)
75ed7b0038SAndre Noll return -ENOMEM;
76dafb20faSNeilBrown rdev_for_each(rdev1, mddev) {
77913cce5aSChristoph Hellwig pr_debug("md/raid0:%s: looking at %pg\n",
78b5a20961SNeilBrown mdname(mddev),
79913cce5aSChristoph Hellwig rdev1->bdev);
801da177e4SLinus Torvalds c = 0;
8113f2682bSNeilBrown
8213f2682bSNeilBrown /* round size to chunk_size */
8313f2682bSNeilBrown sectors = rdev1->sectors;
8413f2682bSNeilBrown sector_div(sectors, mddev->chunk_sectors);
8513f2682bSNeilBrown rdev1->sectors = sectors * mddev->chunk_sectors;
8613f2682bSNeilBrown
87199dc6edSNeilBrown blksize = max(blksize, queue_logical_block_size(
88199dc6edSNeilBrown rdev1->bdev->bd_disk->queue));
89199dc6edSNeilBrown
90dafb20faSNeilBrown rdev_for_each(rdev2, mddev) {
91913cce5aSChristoph Hellwig pr_debug("md/raid0:%s: comparing %pg(%llu)"
92913cce5aSChristoph Hellwig " with %pg(%llu)\n",
93b5a20961SNeilBrown mdname(mddev),
94913cce5aSChristoph Hellwig rdev1->bdev,
9550de8df4SNeilBrown (unsigned long long)rdev1->sectors,
96913cce5aSChristoph Hellwig rdev2->bdev,
97dd8ac336SAndre Noll (unsigned long long)rdev2->sectors);
981da177e4SLinus Torvalds if (rdev2 == rdev1) {
9950de8df4SNeilBrown pr_debug("md/raid0:%s: END\n",
100b5a20961SNeilBrown mdname(mddev));
1011da177e4SLinus Torvalds break;
1021da177e4SLinus Torvalds }
103dd8ac336SAndre Noll if (rdev2->sectors == rdev1->sectors) {
1041da177e4SLinus Torvalds /*
1051da177e4SLinus Torvalds * Not unique, don't count it as a new
1061da177e4SLinus Torvalds * group
1071da177e4SLinus Torvalds */
10850de8df4SNeilBrown pr_debug("md/raid0:%s: EQUAL\n",
109b5a20961SNeilBrown mdname(mddev));
1101da177e4SLinus Torvalds c = 1;
1111da177e4SLinus Torvalds break;
1121da177e4SLinus Torvalds }
11350de8df4SNeilBrown pr_debug("md/raid0:%s: NOT EQUAL\n",
114b5a20961SNeilBrown mdname(mddev));
1151da177e4SLinus Torvalds }
1161da177e4SLinus Torvalds if (!c) {
11750de8df4SNeilBrown pr_debug("md/raid0:%s: ==> UNIQUE\n",
118b5a20961SNeilBrown mdname(mddev));
1191da177e4SLinus Torvalds conf->nr_strip_zones++;
12050de8df4SNeilBrown pr_debug("md/raid0:%s: %d zones\n",
121b5a20961SNeilBrown mdname(mddev), conf->nr_strip_zones);
1221da177e4SLinus Torvalds }
1231da177e4SLinus Torvalds }
12450de8df4SNeilBrown pr_debug("md/raid0:%s: FINAL %d zones\n",
125b5a20961SNeilBrown mdname(mddev), conf->nr_strip_zones);
126c84a1372SNeilBrown
127199dc6edSNeilBrown /*
128199dc6edSNeilBrown * now since we have the hard sector sizes, we can make sure
129199dc6edSNeilBrown * chunk size is a multiple of that sector size
130199dc6edSNeilBrown */
131199dc6edSNeilBrown if ((mddev->chunk_sectors << 9) % blksize) {
13276603884SNeilBrown pr_warn("md/raid0:%s: chunk_size of %d not multiple of block size %d\n",
133199dc6edSNeilBrown mdname(mddev),
134199dc6edSNeilBrown mddev->chunk_sectors << 9, blksize);
135199dc6edSNeilBrown err = -EINVAL;
136199dc6edSNeilBrown goto abort;
137199dc6edSNeilBrown }
138199dc6edSNeilBrown
139ed7b0038SAndre Noll err = -ENOMEM;
1406396bb22SKees Cook conf->strip_zone = kcalloc(conf->nr_strip_zones,
1416396bb22SKees Cook sizeof(struct strip_zone),
1426396bb22SKees Cook GFP_KERNEL);
1431da177e4SLinus Torvalds if (!conf->strip_zone)
144ed7b0038SAndre Noll goto abort;
1456396bb22SKees Cook conf->devlist = kzalloc(array3_size(sizeof(struct md_rdev *),
1466396bb22SKees Cook conf->nr_strip_zones,
1476396bb22SKees Cook mddev->raid_disks),
1481da177e4SLinus Torvalds GFP_KERNEL);
1491da177e4SLinus Torvalds if (!conf->devlist)
150ed7b0038SAndre Noll goto abort;
1511da177e4SLinus Torvalds
1521da177e4SLinus Torvalds /* The first zone must contain all devices, so here we check that
1531da177e4SLinus Torvalds * there is a proper alignment of slots to devices and find them all
1541da177e4SLinus Torvalds */
1551da177e4SLinus Torvalds zone = &conf->strip_zone[0];
1561da177e4SLinus Torvalds cnt = 0;
1571da177e4SLinus Torvalds smallest = NULL;
158b414579fSNeilBrown dev = conf->devlist;
159ed7b0038SAndre Noll err = -EINVAL;
160dafb20faSNeilBrown rdev_for_each(rdev1, mddev) {
1611da177e4SLinus Torvalds int j = rdev1->raid_disk;
1621da177e4SLinus Torvalds
163e93f68a1SNeilBrown if (mddev->level == 10) {
1649af204cfSTrela, Maciej /* taking over a raid10-n2 array */
1659af204cfSTrela, Maciej j /= 2;
166e93f68a1SNeilBrown rdev1->new_raid_disk = j;
167e93f68a1SNeilBrown }
1689af204cfSTrela, Maciej
169fc3a08b8SKrzysztof Wojcik if (mddev->level == 1) {
170fc3a08b8SKrzysztof Wojcik /* taiking over a raid1 array-
171fc3a08b8SKrzysztof Wojcik * we have only one active disk
172fc3a08b8SKrzysztof Wojcik */
173fc3a08b8SKrzysztof Wojcik j = 0;
174fc3a08b8SKrzysztof Wojcik rdev1->new_raid_disk = j;
175fc3a08b8SKrzysztof Wojcik }
176fc3a08b8SKrzysztof Wojcik
177f96c9f30SNeilBrown if (j < 0) {
17876603884SNeilBrown pr_warn("md/raid0:%s: remove inactive devices before converting to RAID0\n",
179f96c9f30SNeilBrown mdname(mddev));
180f96c9f30SNeilBrown goto abort;
181f96c9f30SNeilBrown }
182f96c9f30SNeilBrown if (j >= mddev->raid_disks) {
18376603884SNeilBrown pr_warn("md/raid0:%s: bad disk number %d - aborting!\n",
18476603884SNeilBrown mdname(mddev), j);
1851da177e4SLinus Torvalds goto abort;
1861da177e4SLinus Torvalds }
187b414579fSNeilBrown if (dev[j]) {
18876603884SNeilBrown pr_warn("md/raid0:%s: multiple devices for %d - aborting!\n",
18976603884SNeilBrown mdname(mddev), j);
1901da177e4SLinus Torvalds goto abort;
1911da177e4SLinus Torvalds }
192b414579fSNeilBrown dev[j] = rdev1;
1931da177e4SLinus Torvalds
194dd8ac336SAndre Noll if (!smallest || (rdev1->sectors < smallest->sectors))
1951da177e4SLinus Torvalds smallest = rdev1;
1961da177e4SLinus Torvalds cnt++;
1971da177e4SLinus Torvalds }
1981da177e4SLinus Torvalds if (cnt != mddev->raid_disks) {
19976603884SNeilBrown pr_warn("md/raid0:%s: too few disks (%d of %d) - aborting!\n",
20076603884SNeilBrown mdname(mddev), cnt, mddev->raid_disks);
2011da177e4SLinus Torvalds goto abort;
2021da177e4SLinus Torvalds }
2031da177e4SLinus Torvalds zone->nb_dev = cnt;
20449f357a2SNeilBrown zone->zone_end = smallest->sectors * cnt;
2051da177e4SLinus Torvalds
20649f357a2SNeilBrown curr_zone_end = zone->zone_end;
2071da177e4SLinus Torvalds
2081da177e4SLinus Torvalds /* now do the other zones */
2091da177e4SLinus Torvalds for (i = 1; i < conf->nr_strip_zones; i++)
2101da177e4SLinus Torvalds {
211a9f326ebSNeilBrown int j;
212a9f326ebSNeilBrown
2131da177e4SLinus Torvalds zone = conf->strip_zone + i;
214b414579fSNeilBrown dev = conf->devlist + i * mddev->raid_disks;
2151da177e4SLinus Torvalds
21650de8df4SNeilBrown pr_debug("md/raid0:%s: zone %d\n", mdname(mddev), i);
217d27a43abSNeilBrown zone->dev_start = smallest->sectors;
2181da177e4SLinus Torvalds smallest = NULL;
2191da177e4SLinus Torvalds c = 0;
2201da177e4SLinus Torvalds
2211da177e4SLinus Torvalds for (j=0; j<cnt; j++) {
222b414579fSNeilBrown rdev = conf->devlist[j];
22350de8df4SNeilBrown if (rdev->sectors <= zone->dev_start) {
224913cce5aSChristoph Hellwig pr_debug("md/raid0:%s: checking %pg ... nope\n",
225b5a20961SNeilBrown mdname(mddev),
226913cce5aSChristoph Hellwig rdev->bdev);
227dd8ac336SAndre Noll continue;
228dd8ac336SAndre Noll }
229913cce5aSChristoph Hellwig pr_debug("md/raid0:%s: checking %pg ..."
23050de8df4SNeilBrown " contained as device %d\n",
23150de8df4SNeilBrown mdname(mddev),
232913cce5aSChristoph Hellwig rdev->bdev, c);
233b414579fSNeilBrown dev[c] = rdev;
2341da177e4SLinus Torvalds c++;
235dd8ac336SAndre Noll if (!smallest || rdev->sectors < smallest->sectors) {
2361da177e4SLinus Torvalds smallest = rdev;
23750de8df4SNeilBrown pr_debug("md/raid0:%s: (%llu) is smallest!.\n",
238b5a20961SNeilBrown mdname(mddev),
239dd8ac336SAndre Noll (unsigned long long)rdev->sectors);
2401da177e4SLinus Torvalds }
2411da177e4SLinus Torvalds }
2421da177e4SLinus Torvalds
2431da177e4SLinus Torvalds zone->nb_dev = c;
24449f357a2SNeilBrown sectors = (smallest->sectors - zone->dev_start) * c;
24550de8df4SNeilBrown pr_debug("md/raid0:%s: zone->nb_dev: %d, sectors: %llu\n",
246b5a20961SNeilBrown mdname(mddev),
24749f357a2SNeilBrown zone->nb_dev, (unsigned long long)sectors);
2481da177e4SLinus Torvalds
24949f357a2SNeilBrown curr_zone_end += sectors;
250d27a43abSNeilBrown zone->zone_end = curr_zone_end;
2511da177e4SLinus Torvalds
25250de8df4SNeilBrown pr_debug("md/raid0:%s: current zone start: %llu\n",
253b5a20961SNeilBrown mdname(mddev),
254d27a43abSNeilBrown (unsigned long long)smallest->sectors);
2551da177e4SLinus Torvalds }
2561da177e4SLinus Torvalds
257ea23994eSPascal Hambourg if (conf->nr_strip_zones == 1 || conf->strip_zone[1].nb_dev == 1) {
258ea23994eSPascal Hambourg conf->layout = RAID0_ORIG_LAYOUT;
259ea23994eSPascal Hambourg } else if (mddev->layout == RAID0_ORIG_LAYOUT ||
260ea23994eSPascal Hambourg mddev->layout == RAID0_ALT_MULTIZONE_LAYOUT) {
261ea23994eSPascal Hambourg conf->layout = mddev->layout;
262ea23994eSPascal Hambourg } else if (default_layout == RAID0_ORIG_LAYOUT ||
263ea23994eSPascal Hambourg default_layout == RAID0_ALT_MULTIZONE_LAYOUT) {
264ea23994eSPascal Hambourg conf->layout = default_layout;
265ea23994eSPascal Hambourg } else {
266ea23994eSPascal Hambourg pr_err("md/raid0:%s: cannot assemble multi-zone RAID0 with default_layout setting\n",
267ea23994eSPascal Hambourg mdname(mddev));
268ea23994eSPascal Hambourg pr_err("md/raid0: please set raid0.default_layout to 1 or 2\n");
269ea23994eSPascal Hambourg err = -EOPNOTSUPP;
270ea23994eSPascal Hambourg goto abort;
271ea23994eSPascal Hambourg }
272ea23994eSPascal Hambourg
273e8360070SJason Baron if (conf->layout == RAID0_ORIG_LAYOUT) {
274e8360070SJason Baron for (i = 1; i < conf->nr_strip_zones; i++) {
275e8360070SJason Baron sector_t first_sector = conf->strip_zone[i-1].zone_end;
276e8360070SJason Baron
277e8360070SJason Baron sector_div(first_sector, mddev->chunk_sectors);
278e8360070SJason Baron zone = conf->strip_zone + i;
279e8360070SJason Baron /* disk_shift is first disk index used in the zone */
280e8360070SJason Baron zone->disk_shift = sector_div(first_sector,
281e8360070SJason Baron zone->nb_dev);
282e8360070SJason Baron }
283e8360070SJason Baron }
284e8360070SJason Baron
28550de8df4SNeilBrown pr_debug("md/raid0:%s: done.\n", mdname(mddev));
2869af204cfSTrela, Maciej *private_conf = conf;
2879af204cfSTrela, Maciej
2881da177e4SLinus Torvalds return 0;
2891da177e4SLinus Torvalds abort:
290ed7b0038SAndre Noll kfree(conf->strip_zone);
291ed7b0038SAndre Noll kfree(conf->devlist);
292ed7b0038SAndre Noll kfree(conf);
29358ebb34cSNeilBrown *private_conf = ERR_PTR(err);
294ed7b0038SAndre Noll return err;
2951da177e4SLinus Torvalds }
2961da177e4SLinus Torvalds
297ba13da47SNeilBrown /* Find the zone which holds a particular offset
298ba13da47SNeilBrown * Update *sectorp to be an offset in that zone
299ba13da47SNeilBrown */
find_zone(struct r0conf * conf,sector_t * sectorp)300ba13da47SNeilBrown static struct strip_zone *find_zone(struct r0conf *conf,
301ba13da47SNeilBrown sector_t *sectorp)
302ba13da47SNeilBrown {
303ba13da47SNeilBrown int i;
304ba13da47SNeilBrown struct strip_zone *z = conf->strip_zone;
305ba13da47SNeilBrown sector_t sector = *sectorp;
306ba13da47SNeilBrown
307ba13da47SNeilBrown for (i = 0; i < conf->nr_strip_zones; i++)
308ba13da47SNeilBrown if (sector < z[i].zone_end) {
309ba13da47SNeilBrown if (i)
310ba13da47SNeilBrown *sectorp = sector - z[i-1].zone_end;
311ba13da47SNeilBrown return z + i;
312ba13da47SNeilBrown }
313ba13da47SNeilBrown BUG();
314ba13da47SNeilBrown }
315ba13da47SNeilBrown
316ba13da47SNeilBrown /*
317ba13da47SNeilBrown * remaps the bio to the target device. we separate two flows.
31847d68979SNeilBrown * power 2 flow and a general flow for the sake of performance
319ba13da47SNeilBrown */
map_sector(struct mddev * mddev,struct strip_zone * zone,sector_t sector,sector_t * sector_offset)320ba13da47SNeilBrown static struct md_rdev *map_sector(struct mddev *mddev, struct strip_zone *zone,
321ba13da47SNeilBrown sector_t sector, sector_t *sector_offset)
322ba13da47SNeilBrown {
323ba13da47SNeilBrown unsigned int sect_in_chunk;
324ba13da47SNeilBrown sector_t chunk;
325ba13da47SNeilBrown struct r0conf *conf = mddev->private;
326ba13da47SNeilBrown int raid_disks = conf->strip_zone[0].nb_dev;
327ba13da47SNeilBrown unsigned int chunk_sects = mddev->chunk_sectors;
328ba13da47SNeilBrown
329ba13da47SNeilBrown if (is_power_of_2(chunk_sects)) {
330ba13da47SNeilBrown int chunksect_bits = ffz(~chunk_sects);
331ba13da47SNeilBrown /* find the sector offset inside the chunk */
332ba13da47SNeilBrown sect_in_chunk = sector & (chunk_sects - 1);
333ba13da47SNeilBrown sector >>= chunksect_bits;
334ba13da47SNeilBrown /* chunk in zone */
335ba13da47SNeilBrown chunk = *sector_offset;
336ba13da47SNeilBrown /* quotient is the chunk in real device*/
337ba13da47SNeilBrown sector_div(chunk, zone->nb_dev << chunksect_bits);
338ba13da47SNeilBrown } else{
339ba13da47SNeilBrown sect_in_chunk = sector_div(sector, chunk_sects);
340ba13da47SNeilBrown chunk = *sector_offset;
341ba13da47SNeilBrown sector_div(chunk, chunk_sects * zone->nb_dev);
342ba13da47SNeilBrown }
343ba13da47SNeilBrown /*
344ba13da47SNeilBrown * position the bio over the real device
345ba13da47SNeilBrown * real sector = chunk in device + starting of zone
346ba13da47SNeilBrown * + the position in the chunk
347ba13da47SNeilBrown */
348ba13da47SNeilBrown *sector_offset = (chunk * chunk_sects) + sect_in_chunk;
349ba13da47SNeilBrown return conf->devlist[(zone - conf->strip_zone)*raid_disks
350ba13da47SNeilBrown + sector_div(sector, zone->nb_dev)];
351ba13da47SNeilBrown }
352ba13da47SNeilBrown
raid0_size(struct mddev * mddev,sector_t sectors,int raid_disks)353fd01b88cSNeilBrown static sector_t raid0_size(struct mddev *mddev, sector_t sectors, int raid_disks)
35480c3a6ceSDan Williams {
35580c3a6ceSDan Williams sector_t array_sectors = 0;
3563cb03002SNeilBrown struct md_rdev *rdev;
35780c3a6ceSDan Williams
35880c3a6ceSDan Williams WARN_ONCE(sectors || raid_disks,
35980c3a6ceSDan Williams "%s does not support generic reshape\n", __func__);
36080c3a6ceSDan Williams
361dafb20faSNeilBrown rdev_for_each(rdev, mddev)
362a6468539SNeilBrown array_sectors += (rdev->sectors &
363a6468539SNeilBrown ~(sector_t)(mddev->chunk_sectors-1));
36480c3a6ceSDan Williams
36580c3a6ceSDan Williams return array_sectors;
36680c3a6ceSDan Williams }
36780c3a6ceSDan Williams
free_conf(struct mddev * mddev,struct r0conf * conf)3680c031fd3SXiao Ni static void free_conf(struct mddev *mddev, struct r0conf *conf)
3690c031fd3SXiao Ni {
3700c031fd3SXiao Ni kfree(conf->strip_zone);
3710c031fd3SXiao Ni kfree(conf->devlist);
3720c031fd3SXiao Ni kfree(conf);
3730c031fd3SXiao Ni }
3740c031fd3SXiao Ni
raid0_free(struct mddev * mddev,void * priv)3750c031fd3SXiao Ni static void raid0_free(struct mddev *mddev, void *priv)
3760c031fd3SXiao Ni {
3770c031fd3SXiao Ni struct r0conf *conf = priv;
3780c031fd3SXiao Ni
3790c031fd3SXiao Ni free_conf(mddev, conf);
3800c031fd3SXiao Ni }
3810366ef84Smajianpeng
raid0_run(struct mddev * mddev)382fd01b88cSNeilBrown static int raid0_run(struct mddev *mddev)
3831da177e4SLinus Torvalds {
384e373ab10SNeilBrown struct r0conf *conf;
3855568a603SAndre Noll int ret;
3861da177e4SLinus Torvalds
3879d8f0363SAndre Noll if (mddev->chunk_sectors == 0) {
38876603884SNeilBrown pr_warn("md/raid0:%s: chunk size must be set.\n", mdname(mddev));
3892604b703SNeilBrown return -EINVAL;
3902604b703SNeilBrown }
3910894cc30SAndre Noll if (md_check_no_bitmap(mddev))
3920894cc30SAndre Noll return -EINVAL;
393753f2856SHeinz Mauelshagen
3949af204cfSTrela, Maciej /* if private is not null, we are here after takeover */
3959af204cfSTrela, Maciej if (mddev->private == NULL) {
3969af204cfSTrela, Maciej ret = create_strip_zones(mddev, &conf);
3975568a603SAndre Noll if (ret < 0)
398c567c86bSYu Kuai return ret;
3999af204cfSTrela, Maciej mddev->private = conf;
4009af204cfSTrela, Maciej }
4019af204cfSTrela, Maciej conf = mddev->private;
402199dc6edSNeilBrown if (mddev->queue) {
403199dc6edSNeilBrown struct md_rdev *rdev;
404199dc6edSNeilBrown
405199dc6edSNeilBrown blk_queue_max_hw_sectors(mddev->queue, mddev->chunk_sectors);
4063deff1a7SChristoph Hellwig blk_queue_max_write_zeroes_sectors(mddev->queue, mddev->chunk_sectors);
407199dc6edSNeilBrown
408199dc6edSNeilBrown blk_queue_io_min(mddev->queue, mddev->chunk_sectors << 9);
409199dc6edSNeilBrown blk_queue_io_opt(mddev->queue,
410199dc6edSNeilBrown (mddev->chunk_sectors << 9) * mddev->raid_disks);
411199dc6edSNeilBrown
41266eefe5dSNeilBrown rdev_for_each(rdev, mddev) {
41366eefe5dSNeilBrown disk_stack_limits(mddev->gendisk, rdev->bdev,
41466eefe5dSNeilBrown rdev->data_offset << 9);
41566eefe5dSNeilBrown }
416199dc6edSNeilBrown }
4171da177e4SLinus Torvalds
4181da177e4SLinus Torvalds /* calculate array device size */
4191f403624SDan Williams md_set_array_sectors(mddev, raid0_size(mddev, 0, 0));
4201da177e4SLinus Torvalds
42176603884SNeilBrown pr_debug("md/raid0:%s: md_size is %llu sectors.\n",
422b5a20961SNeilBrown mdname(mddev),
423ccacc7d2SAndre Noll (unsigned long long)mddev->array_sectors);
424753f2856SHeinz Mauelshagen
42546994191Sraz ben yehuda dump_zones(mddev);
4260366ef84Smajianpeng
4270366ef84Smajianpeng ret = md_integrity_register(mddev);
4280c031fd3SXiao Ni if (ret)
4290c031fd3SXiao Ni free_conf(mddev, conf);
430c567c86bSYu Kuai
4310c031fd3SXiao Ni return ret;
4321da177e4SLinus Torvalds }
4331da177e4SLinus Torvalds
434e8360070SJason Baron /*
435e8360070SJason Baron * Convert disk_index to the disk order in which it is read/written.
436e8360070SJason Baron * For example, if we have 4 disks, they are numbered 0,1,2,3. If we
437e8360070SJason Baron * write the disks starting at disk 3, then the read/write order would
438e8360070SJason Baron * be disk 3, then 0, then 1, and then disk 2 and we want map_disk_shift()
439e8360070SJason Baron * to map the disks as follows 0,1,2,3 => 1,2,3,0. So disk 0 would map
440e8360070SJason Baron * to 1, 1 to 2, 2 to 3, and 3 to 0. That way we can compare disks in
441e8360070SJason Baron * that 'output' space to understand the read/write disk ordering.
442e8360070SJason Baron */
map_disk_shift(int disk_index,int num_disks,int disk_shift)443e8360070SJason Baron static int map_disk_shift(int disk_index, int num_disks, int disk_shift)
444e8360070SJason Baron {
445e8360070SJason Baron return ((disk_index + num_disks - disk_shift) % num_disks);
446e8360070SJason Baron }
447e8360070SJason Baron
raid0_handle_discard(struct mddev * mddev,struct bio * bio)44829efc390SShaohua Li static void raid0_handle_discard(struct mddev *mddev, struct bio *bio)
44929efc390SShaohua Li {
45029efc390SShaohua Li struct r0conf *conf = mddev->private;
45129efc390SShaohua Li struct strip_zone *zone;
45229efc390SShaohua Li sector_t start = bio->bi_iter.bi_sector;
45329efc390SShaohua Li sector_t end;
45429efc390SShaohua Li unsigned int stripe_size;
45529efc390SShaohua Li sector_t first_stripe_index, last_stripe_index;
45629efc390SShaohua Li sector_t start_disk_offset;
45729efc390SShaohua Li unsigned int start_disk_index;
45829efc390SShaohua Li sector_t end_disk_offset;
45929efc390SShaohua Li unsigned int end_disk_index;
46029efc390SShaohua Li unsigned int disk;
461e8360070SJason Baron sector_t orig_start, orig_end;
46229efc390SShaohua Li
463e8360070SJason Baron orig_start = start;
46429efc390SShaohua Li zone = find_zone(conf, &start);
46529efc390SShaohua Li
46629efc390SShaohua Li if (bio_end_sector(bio) > zone->zone_end) {
46729efc390SShaohua Li struct bio *split = bio_split(bio,
46829efc390SShaohua Li zone->zone_end - bio->bi_iter.bi_sector, GFP_NOIO,
469afeee514SKent Overstreet &mddev->bio_set);
47029efc390SShaohua Li bio_chain(split, bio);
471ed00aabdSChristoph Hellwig submit_bio_noacct(bio);
47229efc390SShaohua Li bio = split;
47329efc390SShaohua Li end = zone->zone_end;
47429efc390SShaohua Li } else
47529efc390SShaohua Li end = bio_end_sector(bio);
47629efc390SShaohua Li
477e8360070SJason Baron orig_end = end;
47829efc390SShaohua Li if (zone != conf->strip_zone)
47929efc390SShaohua Li end = end - zone[-1].zone_end;
48029efc390SShaohua Li
48129efc390SShaohua Li /* Now start and end is the offset in zone */
48229efc390SShaohua Li stripe_size = zone->nb_dev * mddev->chunk_sectors;
48329efc390SShaohua Li
48429efc390SShaohua Li first_stripe_index = start;
48529efc390SShaohua Li sector_div(first_stripe_index, stripe_size);
48629efc390SShaohua Li last_stripe_index = end;
48729efc390SShaohua Li sector_div(last_stripe_index, stripe_size);
48829efc390SShaohua Li
489e8360070SJason Baron /* In the first zone the original and alternate layouts are the same */
490e8360070SJason Baron if ((conf->layout == RAID0_ORIG_LAYOUT) && (zone != conf->strip_zone)) {
491e8360070SJason Baron sector_div(orig_start, mddev->chunk_sectors);
492e8360070SJason Baron start_disk_index = sector_div(orig_start, zone->nb_dev);
493e8360070SJason Baron start_disk_index = map_disk_shift(start_disk_index,
494e8360070SJason Baron zone->nb_dev,
495e8360070SJason Baron zone->disk_shift);
496e8360070SJason Baron sector_div(orig_end, mddev->chunk_sectors);
497e8360070SJason Baron end_disk_index = sector_div(orig_end, zone->nb_dev);
498e8360070SJason Baron end_disk_index = map_disk_shift(end_disk_index,
499e8360070SJason Baron zone->nb_dev, zone->disk_shift);
500e8360070SJason Baron } else {
50129efc390SShaohua Li start_disk_index = (int)(start - first_stripe_index * stripe_size) /
50229efc390SShaohua Li mddev->chunk_sectors;
503e8360070SJason Baron end_disk_index = (int)(end - last_stripe_index * stripe_size) /
504e8360070SJason Baron mddev->chunk_sectors;
505e8360070SJason Baron }
50629efc390SShaohua Li start_disk_offset = ((int)(start - first_stripe_index * stripe_size) %
50729efc390SShaohua Li mddev->chunk_sectors) +
50829efc390SShaohua Li first_stripe_index * mddev->chunk_sectors;
50929efc390SShaohua Li end_disk_offset = ((int)(end - last_stripe_index * stripe_size) %
51029efc390SShaohua Li mddev->chunk_sectors) +
51129efc390SShaohua Li last_stripe_index * mddev->chunk_sectors;
51229efc390SShaohua Li
51329efc390SShaohua Li for (disk = 0; disk < zone->nb_dev; disk++) {
51429efc390SShaohua Li sector_t dev_start, dev_end;
51529efc390SShaohua Li struct md_rdev *rdev;
516e8360070SJason Baron int compare_disk;
51729efc390SShaohua Li
518e8360070SJason Baron compare_disk = map_disk_shift(disk, zone->nb_dev,
519e8360070SJason Baron zone->disk_shift);
520e8360070SJason Baron
521e8360070SJason Baron if (compare_disk < start_disk_index)
52229efc390SShaohua Li dev_start = (first_stripe_index + 1) *
52329efc390SShaohua Li mddev->chunk_sectors;
524e8360070SJason Baron else if (compare_disk > start_disk_index)
52529efc390SShaohua Li dev_start = first_stripe_index * mddev->chunk_sectors;
52629efc390SShaohua Li else
52729efc390SShaohua Li dev_start = start_disk_offset;
52829efc390SShaohua Li
529e8360070SJason Baron if (compare_disk < end_disk_index)
53029efc390SShaohua Li dev_end = (last_stripe_index + 1) * mddev->chunk_sectors;
531e8360070SJason Baron else if (compare_disk > end_disk_index)
53229efc390SShaohua Li dev_end = last_stripe_index * mddev->chunk_sectors;
53329efc390SShaohua Li else
53429efc390SShaohua Li dev_end = end_disk_offset;
53529efc390SShaohua Li
53629efc390SShaohua Li if (dev_end <= dev_start)
53729efc390SShaohua Li continue;
53829efc390SShaohua Li
53929efc390SShaohua Li rdev = conf->devlist[(zone - conf->strip_zone) *
54029efc390SShaohua Li conf->strip_zone[0].nb_dev + disk];
541cf78408fSXiao Ni md_submit_discard_bio(mddev, rdev, bio,
54229efc390SShaohua Li dev_start + zone->dev_start + rdev->data_offset,
543cf78408fSXiao Ni dev_end - dev_start);
54429efc390SShaohua Li }
54529efc390SShaohua Li bio_endio(bio);
54629efc390SShaohua Li }
54729efc390SShaohua Li
raid0_map_submit_bio(struct mddev * mddev,struct bio * bio)548af50e20aSJan Kara static void raid0_map_submit_bio(struct mddev *mddev, struct bio *bio)
5491da177e4SLinus Torvalds {
550c84a1372SNeilBrown struct r0conf *conf = mddev->private;
5511da177e4SLinus Torvalds struct strip_zone *zone;
5523cb03002SNeilBrown struct md_rdev *tmp_dev;
553af50e20aSJan Kara sector_t bio_sector = bio->bi_iter.bi_sector;
554af50e20aSJan Kara sector_t sector = bio_sector;
555af50e20aSJan Kara
556af50e20aSJan Kara md_account_bio(mddev, &bio);
557af50e20aSJan Kara
558af50e20aSJan Kara zone = find_zone(mddev->private, §or);
559af50e20aSJan Kara switch (conf->layout) {
560af50e20aSJan Kara case RAID0_ORIG_LAYOUT:
561af50e20aSJan Kara tmp_dev = map_sector(mddev, zone, bio_sector, §or);
562af50e20aSJan Kara break;
563af50e20aSJan Kara case RAID0_ALT_MULTIZONE_LAYOUT:
564af50e20aSJan Kara tmp_dev = map_sector(mddev, zone, sector, §or);
565af50e20aSJan Kara break;
566af50e20aSJan Kara default:
567af50e20aSJan Kara WARN(1, "md/raid0:%s: Invalid layout\n", mdname(mddev));
568af50e20aSJan Kara bio_io_error(bio);
569af50e20aSJan Kara return;
570af50e20aSJan Kara }
571af50e20aSJan Kara
572af50e20aSJan Kara if (unlikely(is_rdev_broken(tmp_dev))) {
573af50e20aSJan Kara bio_io_error(bio);
574af50e20aSJan Kara md_error(mddev, tmp_dev);
575af50e20aSJan Kara return;
576af50e20aSJan Kara }
577af50e20aSJan Kara
578af50e20aSJan Kara bio_set_dev(bio, tmp_dev->bdev);
579af50e20aSJan Kara bio->bi_iter.bi_sector = sector + zone->dev_start +
580af50e20aSJan Kara tmp_dev->data_offset;
581af50e20aSJan Kara
582af50e20aSJan Kara if (mddev->gendisk)
583af50e20aSJan Kara trace_block_bio_remap(bio, disk_devt(mddev->gendisk),
584af50e20aSJan Kara bio_sector);
585af50e20aSJan Kara mddev_check_write_zeroes(mddev, bio);
586af50e20aSJan Kara submit_bio_noacct(bio);
587af50e20aSJan Kara }
588af50e20aSJan Kara
raid0_make_request(struct mddev * mddev,struct bio * bio)589af50e20aSJan Kara static bool raid0_make_request(struct mddev *mddev, struct bio *bio)
590af50e20aSJan Kara {
591f00d7c85SNeilBrown sector_t sector;
592f00d7c85SNeilBrown unsigned chunk_sects;
593f00d7c85SNeilBrown unsigned sectors;
5941da177e4SLinus Torvalds
595775d7831SDavid Jeffery if (unlikely(bio->bi_opf & REQ_PREFLUSH)
596775d7831SDavid Jeffery && md_flush_request(mddev, bio))
597cc27b0c7SNeilBrown return true;
598e5dcdd80SNeilBrown
59929efc390SShaohua Li if (unlikely((bio_op(bio) == REQ_OP_DISCARD))) {
60029efc390SShaohua Li raid0_handle_discard(mddev, bio);
601cc27b0c7SNeilBrown return true;
60229efc390SShaohua Li }
60329efc390SShaohua Li
604af50e20aSJan Kara sector = bio->bi_iter.bi_sector;
605f00d7c85SNeilBrown chunk_sects = mddev->chunk_sectors;
60620d0189bSKent Overstreet
607f00d7c85SNeilBrown sectors = chunk_sects -
60820d0189bSKent Overstreet (likely(is_power_of_2(chunk_sects))
60920d0189bSKent Overstreet ? (sector & (chunk_sects-1))
61020d0189bSKent Overstreet : sector_div(sector, chunk_sects));
61120d0189bSKent Overstreet
61220d0189bSKent Overstreet if (sectors < bio_sectors(bio)) {
613afeee514SKent Overstreet struct bio *split = bio_split(bio, sectors, GFP_NOIO,
614afeee514SKent Overstreet &mddev->bio_set);
61520d0189bSKent Overstreet bio_chain(split, bio);
616*319ff40aSJan Kara raid0_map_submit_bio(mddev, bio);
617f00d7c85SNeilBrown bio = split;
6181da177e4SLinus Torvalds }
6191da177e4SLinus Torvalds
620af50e20aSJan Kara raid0_map_submit_bio(mddev, bio);
621cc27b0c7SNeilBrown return true;
622109e3765SNeilBrown }
6231da177e4SLinus Torvalds
raid0_status(struct seq_file * seq,struct mddev * mddev)624fd01b88cSNeilBrown static void raid0_status(struct seq_file *seq, struct mddev *mddev)
6251da177e4SLinus Torvalds {
6269d8f0363SAndre Noll seq_printf(seq, " %dk chunks", mddev->chunk_sectors / 2);
6271da177e4SLinus Torvalds return;
6281da177e4SLinus Torvalds }
6291da177e4SLinus Torvalds
raid0_error(struct mddev * mddev,struct md_rdev * rdev)630c31fea2fSMariusz Tkaczyk static void raid0_error(struct mddev *mddev, struct md_rdev *rdev)
631c31fea2fSMariusz Tkaczyk {
632c31fea2fSMariusz Tkaczyk if (!test_and_set_bit(MD_BROKEN, &mddev->flags)) {
633c31fea2fSMariusz Tkaczyk char *md_name = mdname(mddev);
634c31fea2fSMariusz Tkaczyk
635c31fea2fSMariusz Tkaczyk pr_crit("md/raid0%s: Disk failure on %pg detected, failing array.\n",
636c31fea2fSMariusz Tkaczyk md_name, rdev->bdev);
637c31fea2fSMariusz Tkaczyk }
638c31fea2fSMariusz Tkaczyk }
639c31fea2fSMariusz Tkaczyk
raid0_takeover_raid45(struct mddev * mddev)640fd01b88cSNeilBrown static void *raid0_takeover_raid45(struct mddev *mddev)
6419af204cfSTrela, Maciej {
6423cb03002SNeilBrown struct md_rdev *rdev;
643e373ab10SNeilBrown struct r0conf *priv_conf;
6449af204cfSTrela, Maciej
6459af204cfSTrela, Maciej if (mddev->degraded != 1) {
64676603884SNeilBrown pr_warn("md/raid0:%s: raid5 must be degraded! Degraded disks: %d\n",
647b5a20961SNeilBrown mdname(mddev),
6489af204cfSTrela, Maciej mddev->degraded);
6499af204cfSTrela, Maciej return ERR_PTR(-EINVAL);
6509af204cfSTrela, Maciej }
6519af204cfSTrela, Maciej
652dafb20faSNeilBrown rdev_for_each(rdev, mddev) {
6539af204cfSTrela, Maciej /* check slot number for a disk */
6549af204cfSTrela, Maciej if (rdev->raid_disk == mddev->raid_disks-1) {
65576603884SNeilBrown pr_warn("md/raid0:%s: raid5 must have missing parity disk!\n",
656b5a20961SNeilBrown mdname(mddev));
6579af204cfSTrela, Maciej return ERR_PTR(-EINVAL);
6589af204cfSTrela, Maciej }
659eea136d6SNeilBrown rdev->sectors = mddev->dev_sectors;
6609af204cfSTrela, Maciej }
6619af204cfSTrela, Maciej
6629af204cfSTrela, Maciej /* Set new parameters */
6639af204cfSTrela, Maciej mddev->new_level = 0;
664001048a3SMaciej Trela mddev->new_layout = 0;
6659af204cfSTrela, Maciej mddev->new_chunk_sectors = mddev->chunk_sectors;
6669af204cfSTrela, Maciej mddev->raid_disks--;
6679af204cfSTrela, Maciej mddev->delta_disks = -1;
6689af204cfSTrela, Maciej /* make sure it will be not marked as dirty */
6699af204cfSTrela, Maciej mddev->recovery_cp = MaxSector;
670394ed8e4SShaohua Li mddev_clear_unsupported_flags(mddev, UNSUPPORTED_MDDEV_FLAGS);
6719af204cfSTrela, Maciej
6729af204cfSTrela, Maciej create_strip_zones(mddev, &priv_conf);
6736995f0b2SShaohua Li
6749af204cfSTrela, Maciej return priv_conf;
6759af204cfSTrela, Maciej }
6769af204cfSTrela, Maciej
raid0_takeover_raid10(struct mddev * mddev)677fd01b88cSNeilBrown static void *raid0_takeover_raid10(struct mddev *mddev)
6789af204cfSTrela, Maciej {
679e373ab10SNeilBrown struct r0conf *priv_conf;
6809af204cfSTrela, Maciej
6819af204cfSTrela, Maciej /* Check layout:
6829af204cfSTrela, Maciej * - far_copies must be 1
6839af204cfSTrela, Maciej * - near_copies must be 2
6849af204cfSTrela, Maciej * - disks number must be even
6859af204cfSTrela, Maciej * - all mirrors must be already degraded
6869af204cfSTrela, Maciej */
6879af204cfSTrela, Maciej if (mddev->layout != ((1 << 8) + 2)) {
68876603884SNeilBrown pr_warn("md/raid0:%s:: Raid0 cannot takeover layout: 0x%x\n",
689b5a20961SNeilBrown mdname(mddev),
6909af204cfSTrela, Maciej mddev->layout);
6919af204cfSTrela, Maciej return ERR_PTR(-EINVAL);
6929af204cfSTrela, Maciej }
6939af204cfSTrela, Maciej if (mddev->raid_disks & 1) {
69476603884SNeilBrown pr_warn("md/raid0:%s: Raid0 cannot takeover Raid10 with odd disk number.\n",
695b5a20961SNeilBrown mdname(mddev));
6969af204cfSTrela, Maciej return ERR_PTR(-EINVAL);
6979af204cfSTrela, Maciej }
6989af204cfSTrela, Maciej if (mddev->degraded != (mddev->raid_disks>>1)) {
69976603884SNeilBrown pr_warn("md/raid0:%s: All mirrors must be already degraded!\n",
700b5a20961SNeilBrown mdname(mddev));
7019af204cfSTrela, Maciej return ERR_PTR(-EINVAL);
7029af204cfSTrela, Maciej }
7039af204cfSTrela, Maciej
7049af204cfSTrela, Maciej /* Set new parameters */
7059af204cfSTrela, Maciej mddev->new_level = 0;
706001048a3SMaciej Trela mddev->new_layout = 0;
7079af204cfSTrela, Maciej mddev->new_chunk_sectors = mddev->chunk_sectors;
7089af204cfSTrela, Maciej mddev->delta_disks = - mddev->raid_disks / 2;
7099af204cfSTrela, Maciej mddev->raid_disks += mddev->delta_disks;
7109af204cfSTrela, Maciej mddev->degraded = 0;
7119af204cfSTrela, Maciej /* make sure it will be not marked as dirty */
7129af204cfSTrela, Maciej mddev->recovery_cp = MaxSector;
713394ed8e4SShaohua Li mddev_clear_unsupported_flags(mddev, UNSUPPORTED_MDDEV_FLAGS);
7149af204cfSTrela, Maciej
7159af204cfSTrela, Maciej create_strip_zones(mddev, &priv_conf);
7169af204cfSTrela, Maciej return priv_conf;
7179af204cfSTrela, Maciej }
7189af204cfSTrela, Maciej
raid0_takeover_raid1(struct mddev * mddev)719fd01b88cSNeilBrown static void *raid0_takeover_raid1(struct mddev *mddev)
720fc3a08b8SKrzysztof Wojcik {
721e373ab10SNeilBrown struct r0conf *priv_conf;
72224b961f8SJes Sorensen int chunksect;
723fc3a08b8SKrzysztof Wojcik
724fc3a08b8SKrzysztof Wojcik /* Check layout:
725fc3a08b8SKrzysztof Wojcik * - (N - 1) mirror drives must be already faulty
726fc3a08b8SKrzysztof Wojcik */
727fc3a08b8SKrzysztof Wojcik if ((mddev->raid_disks - 1) != mddev->degraded) {
72876603884SNeilBrown pr_err("md/raid0:%s: (N - 1) mirrors drives must be already faulty!\n",
729fc3a08b8SKrzysztof Wojcik mdname(mddev));
730fc3a08b8SKrzysztof Wojcik return ERR_PTR(-EINVAL);
731fc3a08b8SKrzysztof Wojcik }
732fc3a08b8SKrzysztof Wojcik
73324b961f8SJes Sorensen /*
73424b961f8SJes Sorensen * a raid1 doesn't have the notion of chunk size, so
73524b961f8SJes Sorensen * figure out the largest suitable size we can use.
73624b961f8SJes Sorensen */
73724b961f8SJes Sorensen chunksect = 64 * 2; /* 64K by default */
73824b961f8SJes Sorensen
73924b961f8SJes Sorensen /* The array must be an exact multiple of chunksize */
74024b961f8SJes Sorensen while (chunksect && (mddev->array_sectors & (chunksect - 1)))
74124b961f8SJes Sorensen chunksect >>= 1;
74224b961f8SJes Sorensen
74324b961f8SJes Sorensen if ((chunksect << 9) < PAGE_SIZE)
74424b961f8SJes Sorensen /* array size does not allow a suitable chunk size */
74524b961f8SJes Sorensen return ERR_PTR(-EINVAL);
74624b961f8SJes Sorensen
747fc3a08b8SKrzysztof Wojcik /* Set new parameters */
748fc3a08b8SKrzysztof Wojcik mddev->new_level = 0;
749fc3a08b8SKrzysztof Wojcik mddev->new_layout = 0;
75024b961f8SJes Sorensen mddev->new_chunk_sectors = chunksect;
75124b961f8SJes Sorensen mddev->chunk_sectors = chunksect;
752fc3a08b8SKrzysztof Wojcik mddev->delta_disks = 1 - mddev->raid_disks;
753f7bee809SKrzysztof Wojcik mddev->raid_disks = 1;
754fc3a08b8SKrzysztof Wojcik /* make sure it will be not marked as dirty */
755fc3a08b8SKrzysztof Wojcik mddev->recovery_cp = MaxSector;
756394ed8e4SShaohua Li mddev_clear_unsupported_flags(mddev, UNSUPPORTED_MDDEV_FLAGS);
757fc3a08b8SKrzysztof Wojcik
758fc3a08b8SKrzysztof Wojcik create_strip_zones(mddev, &priv_conf);
759fc3a08b8SKrzysztof Wojcik return priv_conf;
760fc3a08b8SKrzysztof Wojcik }
761fc3a08b8SKrzysztof Wojcik
raid0_takeover(struct mddev * mddev)762fd01b88cSNeilBrown static void *raid0_takeover(struct mddev *mddev)
7639af204cfSTrela, Maciej {
7649af204cfSTrela, Maciej /* raid0 can take over:
765049d6c1eSMaciej Trela * raid4 - if all data disks are active.
7669af204cfSTrela, Maciej * raid5 - providing it is Raid4 layout and one disk is faulty
7679af204cfSTrela, Maciej * raid10 - assuming we have all necessary active disks
768fc3a08b8SKrzysztof Wojcik * raid1 - with (N -1) mirror drives faulty
7699af204cfSTrela, Maciej */
770a8461a61SNeilBrown
771a8461a61SNeilBrown if (mddev->bitmap) {
77276603884SNeilBrown pr_warn("md/raid0: %s: cannot takeover array with bitmap\n",
773a8461a61SNeilBrown mdname(mddev));
774a8461a61SNeilBrown return ERR_PTR(-EBUSY);
775a8461a61SNeilBrown }
776049d6c1eSMaciej Trela if (mddev->level == 4)
777049d6c1eSMaciej Trela return raid0_takeover_raid45(mddev);
778049d6c1eSMaciej Trela
7799af204cfSTrela, Maciej if (mddev->level == 5) {
7809af204cfSTrela, Maciej if (mddev->layout == ALGORITHM_PARITY_N)
781049d6c1eSMaciej Trela return raid0_takeover_raid45(mddev);
7829af204cfSTrela, Maciej
78376603884SNeilBrown pr_warn("md/raid0:%s: Raid can only takeover Raid5 with layout: %d\n",
784b5a20961SNeilBrown mdname(mddev), ALGORITHM_PARITY_N);
7859af204cfSTrela, Maciej }
7869af204cfSTrela, Maciej
7879af204cfSTrela, Maciej if (mddev->level == 10)
7889af204cfSTrela, Maciej return raid0_takeover_raid10(mddev);
7899af204cfSTrela, Maciej
790fc3a08b8SKrzysztof Wojcik if (mddev->level == 1)
791fc3a08b8SKrzysztof Wojcik return raid0_takeover_raid1(mddev);
792fc3a08b8SKrzysztof Wojcik
79376603884SNeilBrown pr_warn("Takeover from raid%i to raid0 not supported\n",
794fc3a08b8SKrzysztof Wojcik mddev->level);
795fc3a08b8SKrzysztof Wojcik
7969af204cfSTrela, Maciej return ERR_PTR(-EINVAL);
7979af204cfSTrela, Maciej }
7989af204cfSTrela, Maciej
raid0_quiesce(struct mddev * mddev,int quiesce)799b03e0ccbSNeilBrown static void raid0_quiesce(struct mddev *mddev, int quiesce)
8009af204cfSTrela, Maciej {
8019af204cfSTrela, Maciej }
8029af204cfSTrela, Maciej
80384fc4b56SNeilBrown static struct md_personality raid0_personality=
8041da177e4SLinus Torvalds {
8051da177e4SLinus Torvalds .name = "raid0",
8062604b703SNeilBrown .level = 0,
8071da177e4SLinus Torvalds .owner = THIS_MODULE,
8081da177e4SLinus Torvalds .make_request = raid0_make_request,
8091da177e4SLinus Torvalds .run = raid0_run,
810afa0f557SNeilBrown .free = raid0_free,
8111da177e4SLinus Torvalds .status = raid0_status,
81280c3a6ceSDan Williams .size = raid0_size,
8139af204cfSTrela, Maciej .takeover = raid0_takeover,
8149af204cfSTrela, Maciej .quiesce = raid0_quiesce,
815c31fea2fSMariusz Tkaczyk .error_handler = raid0_error,
8161da177e4SLinus Torvalds };
8171da177e4SLinus Torvalds
raid0_init(void)8181da177e4SLinus Torvalds static int __init raid0_init (void)
8191da177e4SLinus Torvalds {
8202604b703SNeilBrown return register_md_personality (&raid0_personality);
8211da177e4SLinus Torvalds }
8221da177e4SLinus Torvalds
raid0_exit(void)8231da177e4SLinus Torvalds static void raid0_exit (void)
8241da177e4SLinus Torvalds {
8252604b703SNeilBrown unregister_md_personality (&raid0_personality);
8261da177e4SLinus Torvalds }
8271da177e4SLinus Torvalds
8281da177e4SLinus Torvalds module_init(raid0_init);
8291da177e4SLinus Torvalds module_exit(raid0_exit);
8301da177e4SLinus Torvalds MODULE_LICENSE("GPL");
8310efb9e61SNeilBrown MODULE_DESCRIPTION("RAID0 (striping) personality for MD");
8321da177e4SLinus Torvalds MODULE_ALIAS("md-personality-2"); /* RAID0 */
833d9d166c2SNeilBrown MODULE_ALIAS("md-raid0");
8342604b703SNeilBrown MODULE_ALIAS("md-level-0");
835