13bd94003SHeinz Mauelshagen // SPDX-License-Identifier: GPL-2.0-only
21da177e4SLinus Torvalds /*
31da177e4SLinus Torvalds * Copyright (C) 2001-2003 Sistina Software (UK) Limited.
41da177e4SLinus Torvalds *
51da177e4SLinus Torvalds * This file is released under the GPL.
61da177e4SLinus Torvalds */
71da177e4SLinus Torvalds
87fff5e8fSMike Snitzer #include "dm.h"
9586e80e6SMikulas Patocka #include <linux/device-mapper.h>
101da177e4SLinus Torvalds
111da177e4SLinus Torvalds #include <linux/module.h>
121da177e4SLinus Torvalds #include <linux/init.h>
131da177e4SLinus Torvalds #include <linux/blkdev.h>
141da177e4SLinus Torvalds #include <linux/bio.h>
15817bf402SDan Williams #include <linux/dax.h>
161da177e4SLinus Torvalds #include <linux/slab.h>
176f3c3f0aSvignesh babu #include <linux/log2.h>
181da177e4SLinus Torvalds
19a7e8f7fbSTetsuo Handa static struct workqueue_struct *dm_stripe_wq;
20a7e8f7fbSTetsuo Handa
2172d94861SAlasdair G Kergon #define DM_MSG_PREFIX "striped"
22a25eb944SBrian Wood #define DM_IO_ERROR_THRESHOLD 15
2372d94861SAlasdair G Kergon
241da177e4SLinus Torvalds struct stripe {
251da177e4SLinus Torvalds struct dm_dev *dev;
261da177e4SLinus Torvalds sector_t physical_start;
27a25eb944SBrian Wood
28a25eb944SBrian Wood atomic_t error_count;
291da177e4SLinus Torvalds };
301da177e4SLinus Torvalds
311da177e4SLinus Torvalds struct stripe_c {
321da177e4SLinus Torvalds uint32_t stripes;
33c96053b7SMikulas Patocka int stripes_shift;
341da177e4SLinus Torvalds
351da177e4SLinus Torvalds /* The size of this target / num. stripes */
361da177e4SLinus Torvalds sector_t stripe_width;
371da177e4SLinus Torvalds
38eb850de6SMike Snitzer uint32_t chunk_size;
3933d07c0dSMikulas Patocka int chunk_size_shift;
401da177e4SLinus Torvalds
41a25eb944SBrian Wood /* Needed for handling events */
42a25eb944SBrian Wood struct dm_target *ti;
43a25eb944SBrian Wood
44a25eb944SBrian Wood /* Work struct used for triggering events*/
45f521f074STejun Heo struct work_struct trigger_event;
46a25eb944SBrian Wood
47b18ae8ddSGustavo A. R. Silva struct stripe stripe[];
481da177e4SLinus Torvalds };
491da177e4SLinus Torvalds
50a25eb944SBrian Wood /*
51a25eb944SBrian Wood * An event is triggered whenever a drive
52a25eb944SBrian Wood * drops out of a stripe volume.
53a25eb944SBrian Wood */
trigger_event(struct work_struct * work)54a25eb944SBrian Wood static void trigger_event(struct work_struct *work)
55a25eb944SBrian Wood {
56f521f074STejun Heo struct stripe_c *sc = container_of(work, struct stripe_c,
57f521f074STejun Heo trigger_event);
58a25eb944SBrian Wood dm_table_event(sc->ti->table);
59a25eb944SBrian Wood }
60a25eb944SBrian Wood
611da177e4SLinus Torvalds /*
621da177e4SLinus Torvalds * Parse a single <dev> <sector> pair
631da177e4SLinus Torvalds */
get_stripe(struct dm_target * ti,struct stripe_c * sc,unsigned int stripe,char ** argv)641da177e4SLinus Torvalds static int get_stripe(struct dm_target *ti, struct stripe_c *sc,
651da177e4SLinus Torvalds unsigned int stripe, char **argv)
661da177e4SLinus Torvalds {
674ee218cdSAndrew Morton unsigned long long start;
6831998ef1SMikulas Patocka char dummy;
69e80d1c80SVivek Goyal int ret;
701da177e4SLinus Torvalds
7131998ef1SMikulas Patocka if (sscanf(argv[1], "%llu%c", &start, &dummy) != 1)
721da177e4SLinus Torvalds return -EINVAL;
731da177e4SLinus Torvalds
74e80d1c80SVivek Goyal ret = dm_get_device(ti, argv[0], dm_table_get_mode(ti->table),
75e80d1c80SVivek Goyal &sc->stripe[stripe].dev);
76e80d1c80SVivek Goyal if (ret)
77e80d1c80SVivek Goyal return ret;
781da177e4SLinus Torvalds
791da177e4SLinus Torvalds sc->stripe[stripe].physical_start = start;
80a25eb944SBrian Wood
811da177e4SLinus Torvalds return 0;
821da177e4SLinus Torvalds }
831da177e4SLinus Torvalds
841da177e4SLinus Torvalds /*
851da177e4SLinus Torvalds * Construct a striped mapping.
86eb850de6SMike Snitzer * <number of stripes> <chunk size> [<dev_path> <offset>]+
871da177e4SLinus Torvalds */
stripe_ctr(struct dm_target * ti,unsigned int argc,char ** argv)881da177e4SLinus Torvalds static int stripe_ctr(struct dm_target *ti, unsigned int argc, char **argv)
891da177e4SLinus Torvalds {
901da177e4SLinus Torvalds struct stripe_c *sc;
91d793e684SMike Snitzer sector_t width, tmp_len;
921da177e4SLinus Torvalds uint32_t stripes;
931da177e4SLinus Torvalds uint32_t chunk_size;
941da177e4SLinus Torvalds int r;
951da177e4SLinus Torvalds unsigned int i;
961da177e4SLinus Torvalds
971da177e4SLinus Torvalds if (argc < 2) {
9872d94861SAlasdair G Kergon ti->error = "Not enough arguments";
991da177e4SLinus Torvalds return -EINVAL;
1001da177e4SLinus Torvalds }
1011da177e4SLinus Torvalds
1021a66a08aSmajianpeng if (kstrtouint(argv[0], 10, &stripes) || !stripes) {
10372d94861SAlasdair G Kergon ti->error = "Invalid stripe count";
1041da177e4SLinus Torvalds return -EINVAL;
1051da177e4SLinus Torvalds }
1061da177e4SLinus Torvalds
1078f069b41SMikulas Patocka if (kstrtouint(argv[1], 10, &chunk_size) || !chunk_size) {
10872d94861SAlasdair G Kergon ti->error = "Invalid chunk_size";
1091da177e4SLinus Torvalds return -EINVAL;
1101da177e4SLinus Torvalds }
1111da177e4SLinus Torvalds
112eb850de6SMike Snitzer width = ti->len;
1131da177e4SLinus Torvalds if (sector_div(width, stripes)) {
1142e84fecfSHeinz Mauelshagen ti->error = "Target length not divisible by number of stripes";
1151da177e4SLinus Torvalds return -EINVAL;
1161da177e4SLinus Torvalds }
1171da177e4SLinus Torvalds
118d793e684SMike Snitzer tmp_len = width;
119d793e684SMike Snitzer if (sector_div(tmp_len, chunk_size)) {
1202e84fecfSHeinz Mauelshagen ti->error = "Target length not divisible by chunk size";
121d793e684SMike Snitzer return -EINVAL;
122d793e684SMike Snitzer }
123d793e684SMike Snitzer
1241da177e4SLinus Torvalds /*
1251da177e4SLinus Torvalds * Do we have enough arguments for that many stripes ?
1261da177e4SLinus Torvalds */
1271da177e4SLinus Torvalds if (argc != (2 + 2 * stripes)) {
1282e84fecfSHeinz Mauelshagen ti->error = "Not enough destinations specified";
1291da177e4SLinus Torvalds return -EINVAL;
1301da177e4SLinus Torvalds }
1311da177e4SLinus Torvalds
1328adeac3bSGustavo A. R. Silva sc = kmalloc(struct_size(sc, stripe, stripes), GFP_KERNEL);
1331da177e4SLinus Torvalds if (!sc) {
1342e84fecfSHeinz Mauelshagen ti->error = "Memory allocation for striped context failed";
1351da177e4SLinus Torvalds return -ENOMEM;
1361da177e4SLinus Torvalds }
1371da177e4SLinus Torvalds
138f521f074STejun Heo INIT_WORK(&sc->trigger_event, trigger_event);
139a25eb944SBrian Wood
140a25eb944SBrian Wood /* Set pointer to dm target; used in trigger_event */
141a25eb944SBrian Wood sc->ti = ti;
1421da177e4SLinus Torvalds sc->stripes = stripes;
1431da177e4SLinus Torvalds sc->stripe_width = width;
144c96053b7SMikulas Patocka
145c96053b7SMikulas Patocka if (stripes & (stripes - 1))
146c96053b7SMikulas Patocka sc->stripes_shift = -1;
1471df05483SMikulas Patocka else
1481df05483SMikulas Patocka sc->stripes_shift = __ffs(stripes);
149c96053b7SMikulas Patocka
150542f9038SMike Snitzer r = dm_set_target_max_io_len(ti, chunk_size);
151a3f2af25SPavitra Kumar if (r) {
152a3f2af25SPavitra Kumar kfree(sc);
153542f9038SMike Snitzer return r;
154a3f2af25SPavitra Kumar }
155542f9038SMike Snitzer
15655a62eefSAlasdair G Kergon ti->num_flush_bios = stripes;
15755a62eefSAlasdair G Kergon ti->num_discard_bios = stripes;
15800716545SDenis Semakin ti->num_secure_erase_bios = stripes;
159ac62d620SChristoph Hellwig ti->num_write_zeroes_bios = stripes;
1601da177e4SLinus Torvalds
161eb850de6SMike Snitzer sc->chunk_size = chunk_size;
16233d07c0dSMikulas Patocka if (chunk_size & (chunk_size - 1))
16333d07c0dSMikulas Patocka sc->chunk_size_shift = -1;
16433d07c0dSMikulas Patocka else
16533d07c0dSMikulas Patocka sc->chunk_size_shift = __ffs(chunk_size);
1661da177e4SLinus Torvalds
1671da177e4SLinus Torvalds /*
1681da177e4SLinus Torvalds * Get the stripe destinations.
1691da177e4SLinus Torvalds */
1701da177e4SLinus Torvalds for (i = 0; i < stripes; i++) {
1711da177e4SLinus Torvalds argv += 2;
1721da177e4SLinus Torvalds
1731da177e4SLinus Torvalds r = get_stripe(ti, sc, i, argv);
1741da177e4SLinus Torvalds if (r < 0) {
17572d94861SAlasdair G Kergon ti->error = "Couldn't parse stripe destination";
1761da177e4SLinus Torvalds while (i--)
1771da177e4SLinus Torvalds dm_put_device(ti, sc->stripe[i].dev);
1781da177e4SLinus Torvalds kfree(sc);
1791da177e4SLinus Torvalds return r;
1801da177e4SLinus Torvalds }
181a25eb944SBrian Wood atomic_set(&(sc->stripe[i].error_count), 0);
1821da177e4SLinus Torvalds }
1831da177e4SLinus Torvalds
1841da177e4SLinus Torvalds ti->private = sc;
185a25eb944SBrian Wood
1861da177e4SLinus Torvalds return 0;
1871da177e4SLinus Torvalds }
1881da177e4SLinus Torvalds
stripe_dtr(struct dm_target * ti)1891da177e4SLinus Torvalds static void stripe_dtr(struct dm_target *ti)
1901da177e4SLinus Torvalds {
1911da177e4SLinus Torvalds unsigned int i;
192*26cb62a2SYu Zhe struct stripe_c *sc = ti->private;
1931da177e4SLinus Torvalds
1941da177e4SLinus Torvalds for (i = 0; i < sc->stripes; i++)
1951da177e4SLinus Torvalds dm_put_device(ti, sc->stripe[i].dev);
1961da177e4SLinus Torvalds
19743829731STejun Heo flush_work(&sc->trigger_event);
1981da177e4SLinus Torvalds kfree(sc);
1991da177e4SLinus Torvalds }
2001da177e4SLinus Torvalds
stripe_map_sector(struct stripe_c * sc,sector_t sector,uint32_t * stripe,sector_t * result)20165988525SMikulas Patocka static void stripe_map_sector(struct stripe_c *sc, sector_t sector,
20265988525SMikulas Patocka uint32_t *stripe, sector_t *result)
20365988525SMikulas Patocka {
204eb850de6SMike Snitzer sector_t chunk = dm_target_offset(sc->ti, sector);
20533d07c0dSMikulas Patocka sector_t chunk_offset;
20633d07c0dSMikulas Patocka
20733d07c0dSMikulas Patocka if (sc->chunk_size_shift < 0)
20833d07c0dSMikulas Patocka chunk_offset = sector_div(chunk, sc->chunk_size);
20933d07c0dSMikulas Patocka else {
21033d07c0dSMikulas Patocka chunk_offset = chunk & (sc->chunk_size - 1);
21133d07c0dSMikulas Patocka chunk >>= sc->chunk_size_shift;
21233d07c0dSMikulas Patocka }
21365988525SMikulas Patocka
214c96053b7SMikulas Patocka if (sc->stripes_shift < 0)
21565988525SMikulas Patocka *stripe = sector_div(chunk, sc->stripes);
216c96053b7SMikulas Patocka else {
2171df05483SMikulas Patocka *stripe = chunk & (sc->stripes - 1);
218c96053b7SMikulas Patocka chunk >>= sc->stripes_shift;
219c96053b7SMikulas Patocka }
220c96053b7SMikulas Patocka
22133d07c0dSMikulas Patocka if (sc->chunk_size_shift < 0)
22233d07c0dSMikulas Patocka chunk *= sc->chunk_size;
22333d07c0dSMikulas Patocka else
22433d07c0dSMikulas Patocka chunk <<= sc->chunk_size_shift;
22533d07c0dSMikulas Patocka
22633d07c0dSMikulas Patocka *result = chunk + chunk_offset;
22765988525SMikulas Patocka }
22865988525SMikulas Patocka
stripe_map_range_sector(struct stripe_c * sc,sector_t sector,uint32_t target_stripe,sector_t * result)2297b76ec11SMikulas Patocka static void stripe_map_range_sector(struct stripe_c *sc, sector_t sector,
2307b76ec11SMikulas Patocka uint32_t target_stripe, sector_t *result)
2317b76ec11SMikulas Patocka {
2327b76ec11SMikulas Patocka uint32_t stripe;
2337b76ec11SMikulas Patocka
2347b76ec11SMikulas Patocka stripe_map_sector(sc, sector, &stripe, result);
2357b76ec11SMikulas Patocka if (stripe == target_stripe)
2367b76ec11SMikulas Patocka return;
237eb850de6SMike Snitzer
238eb850de6SMike Snitzer /* round down */
239eb850de6SMike Snitzer sector = *result;
24033d07c0dSMikulas Patocka if (sc->chunk_size_shift < 0)
241eb850de6SMike Snitzer *result -= sector_div(sector, sc->chunk_size);
24233d07c0dSMikulas Patocka else
24333d07c0dSMikulas Patocka *result = sector & ~(sector_t)(sc->chunk_size - 1);
244eb850de6SMike Snitzer
2457b76ec11SMikulas Patocka if (target_stripe < stripe)
246eb850de6SMike Snitzer *result += sc->chunk_size; /* next chunk */
2477b76ec11SMikulas Patocka }
2487b76ec11SMikulas Patocka
stripe_map_range(struct stripe_c * sc,struct bio * bio,uint32_t target_stripe)24945e621d4SMike Snitzer static int stripe_map_range(struct stripe_c *sc, struct bio *bio,
2507b76ec11SMikulas Patocka uint32_t target_stripe)
2517b76ec11SMikulas Patocka {
2527b76ec11SMikulas Patocka sector_t begin, end;
2537b76ec11SMikulas Patocka
2544f024f37SKent Overstreet stripe_map_range_sector(sc, bio->bi_iter.bi_sector,
2554f024f37SKent Overstreet target_stripe, &begin);
256f73a1c7dSKent Overstreet stripe_map_range_sector(sc, bio_end_sector(bio),
2577b76ec11SMikulas Patocka target_stripe, &end);
2587b76ec11SMikulas Patocka if (begin < end) {
25974d46992SChristoph Hellwig bio_set_dev(bio, sc->stripe[target_stripe].dev->bdev);
2604f024f37SKent Overstreet bio->bi_iter.bi_sector = begin +
2614f024f37SKent Overstreet sc->stripe[target_stripe].physical_start;
2624f024f37SKent Overstreet bio->bi_iter.bi_size = to_bytes(end - begin);
2637b76ec11SMikulas Patocka return DM_MAPIO_REMAPPED;
2641c3fe2faSHeinz Mauelshagen }
2651c3fe2faSHeinz Mauelshagen
2667b76ec11SMikulas Patocka /* The range doesn't map to the target stripe */
2674246a0b6SChristoph Hellwig bio_endio(bio);
2687b76ec11SMikulas Patocka return DM_MAPIO_SUBMITTED;
2697b76ec11SMikulas Patocka }
2707b76ec11SMikulas Patocka
stripe_map(struct dm_target * ti,struct bio * bio)2717de3ee57SMikulas Patocka static int stripe_map(struct dm_target *ti, struct bio *bio)
2721da177e4SLinus Torvalds {
27365988525SMikulas Patocka struct stripe_c *sc = ti->private;
274374bf7e7SMikulas Patocka uint32_t stripe;
27586a3238cSHeinz Mauelshagen unsigned int target_bio_nr;
2761da177e4SLinus Torvalds
2771eff9d32SJens Axboe if (bio->bi_opf & REQ_PREFLUSH) {
27855a62eefSAlasdair G Kergon target_bio_nr = dm_bio_get_target_bio_nr(bio);
27955a62eefSAlasdair G Kergon BUG_ON(target_bio_nr >= sc->stripes);
28074d46992SChristoph Hellwig bio_set_dev(bio, sc->stripe[target_bio_nr].dev->bdev);
281374bf7e7SMikulas Patocka return DM_MAPIO_REMAPPED;
282374bf7e7SMikulas Patocka }
283e6047149SMike Christie if (unlikely(bio_op(bio) == REQ_OP_DISCARD) ||
28400716545SDenis Semakin unlikely(bio_op(bio) == REQ_OP_SECURE_ERASE) ||
285a773187eSChristoph Hellwig unlikely(bio_op(bio) == REQ_OP_WRITE_ZEROES)) {
28655a62eefSAlasdair G Kergon target_bio_nr = dm_bio_get_target_bio_nr(bio);
28755a62eefSAlasdair G Kergon BUG_ON(target_bio_nr >= sc->stripes);
28855a62eefSAlasdair G Kergon return stripe_map_range(sc, bio, target_bio_nr);
2897b76ec11SMikulas Patocka }
290374bf7e7SMikulas Patocka
2914f024f37SKent Overstreet stripe_map_sector(sc, bio->bi_iter.bi_sector,
2924f024f37SKent Overstreet &stripe, &bio->bi_iter.bi_sector);
2931da177e4SLinus Torvalds
2944f024f37SKent Overstreet bio->bi_iter.bi_sector += sc->stripe[stripe].physical_start;
29574d46992SChristoph Hellwig bio_set_dev(bio, sc->stripe[stripe].dev->bdev);
29665988525SMikulas Patocka
297d2a7ad29SKiyoshi Ueda return DM_MAPIO_REMAPPED;
2981da177e4SLinus Torvalds }
2991da177e4SLinus Torvalds
3005d2a228bSChristoph Hellwig #if IS_ENABLED(CONFIG_FS_DAX)
stripe_dax_pgoff(struct dm_target * ti,pgoff_t * pgoff)3012a68553eSChristoph Hellwig static struct dax_device *stripe_dax_pgoff(struct dm_target *ti, pgoff_t *pgoff)
3022a68553eSChristoph Hellwig {
3032a68553eSChristoph Hellwig struct stripe_c *sc = ti->private;
3042a68553eSChristoph Hellwig struct block_device *bdev;
3052a68553eSChristoph Hellwig sector_t dev_sector;
3062a68553eSChristoph Hellwig uint32_t stripe;
3072a68553eSChristoph Hellwig
3082a68553eSChristoph Hellwig stripe_map_sector(sc, *pgoff * PAGE_SECTORS, &stripe, &dev_sector);
3092a68553eSChristoph Hellwig dev_sector += sc->stripe[stripe].physical_start;
3102a68553eSChristoph Hellwig bdev = sc->stripe[stripe].dev->bdev;
3112a68553eSChristoph Hellwig
3122a68553eSChristoph Hellwig *pgoff = (get_start_sect(bdev) + dev_sector) >> PAGE_SECTORS_SHIFT;
3132a68553eSChristoph Hellwig return sc->stripe[stripe].dev->dax_dev;
3142a68553eSChristoph Hellwig }
3152a68553eSChristoph Hellwig
stripe_dax_direct_access(struct dm_target * ti,pgoff_t pgoff,long nr_pages,enum dax_access_mode mode,void ** kaddr,pfn_t * pfn)316817bf402SDan Williams static long stripe_dax_direct_access(struct dm_target *ti, pgoff_t pgoff,
317e511c4a3SJane Chu long nr_pages, enum dax_access_mode mode, void **kaddr,
318e511c4a3SJane Chu pfn_t *pfn)
319beec25b4SToshi Kani {
3202a68553eSChristoph Hellwig struct dax_device *dax_dev = stripe_dax_pgoff(ti, &pgoff);
321beec25b4SToshi Kani
322e511c4a3SJane Chu return dax_direct_access(dax_dev, pgoff, nr_pages, mode, kaddr, pfn);
323beec25b4SToshi Kani }
324beec25b4SToshi Kani
stripe_dax_zero_page_range(struct dm_target * ti,pgoff_t pgoff,size_t nr_pages)325cdf6cdcdSVivek Goyal static int stripe_dax_zero_page_range(struct dm_target *ti, pgoff_t pgoff,
326cdf6cdcdSVivek Goyal size_t nr_pages)
327cdf6cdcdSVivek Goyal {
3282a68553eSChristoph Hellwig struct dax_device *dax_dev = stripe_dax_pgoff(ti, &pgoff);
329cdf6cdcdSVivek Goyal
330cdf6cdcdSVivek Goyal return dax_zero_page_range(dax_dev, pgoff, nr_pages);
331cdf6cdcdSVivek Goyal }
332cdf6cdcdSVivek Goyal
stripe_dax_recovery_write(struct dm_target * ti,pgoff_t pgoff,void * addr,size_t bytes,struct iov_iter * i)333047218ecSJane Chu static size_t stripe_dax_recovery_write(struct dm_target *ti, pgoff_t pgoff,
334047218ecSJane Chu void *addr, size_t bytes, struct iov_iter *i)
335047218ecSJane Chu {
336047218ecSJane Chu struct dax_device *dax_dev = stripe_dax_pgoff(ti, &pgoff);
337047218ecSJane Chu
338047218ecSJane Chu return dax_recovery_write(dax_dev, pgoff, addr, bytes, i);
339047218ecSJane Chu }
340047218ecSJane Chu
341976431b0SDan Williams #else
342976431b0SDan Williams #define stripe_dax_direct_access NULL
343cdf6cdcdSVivek Goyal #define stripe_dax_zero_page_range NULL
344047218ecSJane Chu #define stripe_dax_recovery_write NULL
345976431b0SDan Williams #endif
346976431b0SDan Williams
3474f7f5c67SBrian Wood /*
3484f7f5c67SBrian Wood * Stripe status:
3494f7f5c67SBrian Wood *
3504f7f5c67SBrian Wood * INFO
3514f7f5c67SBrian Wood * #stripes [stripe_name <stripe_name>] [group word count]
3524f7f5c67SBrian Wood * [error count 'A|D' <error count 'A|D'>]
3534f7f5c67SBrian Wood *
3544f7f5c67SBrian Wood * TABLE
3554f7f5c67SBrian Wood * #stripes [stripe chunk size]
3564f7f5c67SBrian Wood * [stripe_name physical_start <stripe_name physical_start>]
3574f7f5c67SBrian Wood *
3584f7f5c67SBrian Wood */
3594f7f5c67SBrian Wood
stripe_status(struct dm_target * ti,status_type_t type,unsigned int status_flags,char * result,unsigned int maxlen)360fd7c092eSMikulas Patocka static void stripe_status(struct dm_target *ti, status_type_t type,
36186a3238cSHeinz Mauelshagen unsigned int status_flags, char *result, unsigned int maxlen)
3621da177e4SLinus Torvalds {
363*26cb62a2SYu Zhe struct stripe_c *sc = ti->private;
3641da177e4SLinus Torvalds unsigned int sz = 0;
3651da177e4SLinus Torvalds unsigned int i;
3661da177e4SLinus Torvalds
3671da177e4SLinus Torvalds switch (type) {
3681da177e4SLinus Torvalds case STATUSTYPE_INFO:
3694f7f5c67SBrian Wood DMEMIT("%d ", sc->stripes);
3702d0f25cbSHeinz Mauelshagen for (i = 0; i < sc->stripes; i++)
3714f7f5c67SBrian Wood DMEMIT("%s ", sc->stripe[i].dev->name);
3722d0f25cbSHeinz Mauelshagen
373706dd22fSTycho Andersen DMEMIT("1 ");
3742d0f25cbSHeinz Mauelshagen for (i = 0; i < sc->stripes; i++)
3752d0f25cbSHeinz Mauelshagen DMEMIT("%c", atomic_read(&(sc->stripe[i].error_count)) ? 'D' : 'A');
3761da177e4SLinus Torvalds break;
3771da177e4SLinus Torvalds
3781da177e4SLinus Torvalds case STATUSTYPE_TABLE:
3794ee218cdSAndrew Morton DMEMIT("%d %llu", sc->stripes,
380eb850de6SMike Snitzer (unsigned long long)sc->chunk_size);
3811da177e4SLinus Torvalds for (i = 0; i < sc->stripes; i++)
3824ee218cdSAndrew Morton DMEMIT(" %s %llu", sc->stripe[i].dev->name,
3834ee218cdSAndrew Morton (unsigned long long)sc->stripe[i].physical_start);
3841da177e4SLinus Torvalds break;
3858ec45662STushar Sugandhi
3868ec45662STushar Sugandhi case STATUSTYPE_IMA:
3878ec45662STushar Sugandhi DMEMIT_TARGET_NAME_VERSION(ti->type);
3888ec45662STushar Sugandhi DMEMIT(",stripes=%d,chunk_size=%llu", sc->stripes,
3898ec45662STushar Sugandhi (unsigned long long)sc->chunk_size);
3908ec45662STushar Sugandhi
3918ec45662STushar Sugandhi for (i = 0; i < sc->stripes; i++) {
3928ec45662STushar Sugandhi DMEMIT(",stripe_%d_device_name=%s", i, sc->stripe[i].dev->name);
3938ec45662STushar Sugandhi DMEMIT(",stripe_%d_physical_start=%llu", i,
3948ec45662STushar Sugandhi (unsigned long long)sc->stripe[i].physical_start);
3958ec45662STushar Sugandhi DMEMIT(",stripe_%d_status=%c", i,
3968ec45662STushar Sugandhi atomic_read(&(sc->stripe[i].error_count)) ? 'D' : 'A');
3978ec45662STushar Sugandhi }
3988ec45662STushar Sugandhi DMEMIT(";");
3998ec45662STushar Sugandhi break;
4001da177e4SLinus Torvalds }
4011da177e4SLinus Torvalds }
4021da177e4SLinus Torvalds
stripe_end_io(struct dm_target * ti,struct bio * bio,blk_status_t * error)4034e4cbee9SChristoph Hellwig static int stripe_end_io(struct dm_target *ti, struct bio *bio,
4044e4cbee9SChristoph Hellwig blk_status_t *error)
405a25eb944SBrian Wood {
40686a3238cSHeinz Mauelshagen unsigned int i;
407a25eb944SBrian Wood char major_minor[16];
408a25eb944SBrian Wood struct stripe_c *sc = ti->private;
409a25eb944SBrian Wood
4101be56909SChristoph Hellwig if (!*error)
4111be56909SChristoph Hellwig return DM_ENDIO_DONE; /* I/O complete */
412a25eb944SBrian Wood
4139966afafSChristoph Hellwig if (bio->bi_opf & REQ_RAHEAD)
4141be56909SChristoph Hellwig return DM_ENDIO_DONE;
415a25eb944SBrian Wood
4164e4cbee9SChristoph Hellwig if (*error == BLK_STS_NOTSUPP)
4171be56909SChristoph Hellwig return DM_ENDIO_DONE;
418a25eb944SBrian Wood
419a25eb944SBrian Wood memset(major_minor, 0, sizeof(major_minor));
42074d46992SChristoph Hellwig sprintf(major_minor, "%d:%d", MAJOR(bio_dev(bio)), MINOR(bio_dev(bio)));
421a25eb944SBrian Wood
422a25eb944SBrian Wood /*
423a25eb944SBrian Wood * Test to see which stripe drive triggered the event
424a25eb944SBrian Wood * and increment error count for all stripes on that device.
425a25eb944SBrian Wood * If the error count for a given device exceeds the threshold
426a25eb944SBrian Wood * value we will no longer trigger any further events.
427a25eb944SBrian Wood */
428a25eb944SBrian Wood for (i = 0; i < sc->stripes; i++)
429a25eb944SBrian Wood if (!strcmp(sc->stripe[i].dev->name, major_minor)) {
430a25eb944SBrian Wood atomic_inc(&(sc->stripe[i].error_count));
431a25eb944SBrian Wood if (atomic_read(&(sc->stripe[i].error_count)) <
432a25eb944SBrian Wood DM_IO_ERROR_THRESHOLD)
433a7e8f7fbSTetsuo Handa queue_work(dm_stripe_wq, &sc->trigger_event);
434a25eb944SBrian Wood }
435a25eb944SBrian Wood
4361be56909SChristoph Hellwig return DM_ENDIO_DONE;
437a25eb944SBrian Wood }
438a25eb944SBrian Wood
stripe_iterate_devices(struct dm_target * ti,iterate_devices_callout_fn fn,void * data)439af4874e0SMike Snitzer static int stripe_iterate_devices(struct dm_target *ti,
440af4874e0SMike Snitzer iterate_devices_callout_fn fn, void *data)
441af4874e0SMike Snitzer {
442af4874e0SMike Snitzer struct stripe_c *sc = ti->private;
443af4874e0SMike Snitzer int ret = 0;
44486a3238cSHeinz Mauelshagen unsigned int i = 0;
445af4874e0SMike Snitzer
4465dea271bSMike Snitzer do {
447af4874e0SMike Snitzer ret = fn(ti, sc->stripe[i].dev,
4485dea271bSMike Snitzer sc->stripe[i].physical_start,
4495dea271bSMike Snitzer sc->stripe_width, data);
4505dea271bSMike Snitzer } while (!ret && ++i < sc->stripes);
451af4874e0SMike Snitzer
452af4874e0SMike Snitzer return ret;
453af4874e0SMike Snitzer }
454af4874e0SMike Snitzer
stripe_io_hints(struct dm_target * ti,struct queue_limits * limits)45540bea431SMike Snitzer static void stripe_io_hints(struct dm_target *ti,
45640bea431SMike Snitzer struct queue_limits *limits)
45740bea431SMike Snitzer {
45840bea431SMike Snitzer struct stripe_c *sc = ti->private;
45986a3238cSHeinz Mauelshagen unsigned int chunk_size = sc->chunk_size << SECTOR_SHIFT;
46040bea431SMike Snitzer
46140bea431SMike Snitzer blk_limits_io_min(limits, chunk_size);
4623c5820c7SMartin K. Petersen blk_limits_io_opt(limits, chunk_size * sc->stripes);
46340bea431SMike Snitzer }
46440bea431SMike Snitzer
4651da177e4SLinus Torvalds static struct target_type stripe_target = {
4661da177e4SLinus Torvalds .name = "striped",
467beec25b4SToshi Kani .version = {1, 6, 0},
468410fe220SJeffle Xu .features = DM_TARGET_PASSES_INTEGRITY | DM_TARGET_NOWAIT,
4691da177e4SLinus Torvalds .module = THIS_MODULE,
4701da177e4SLinus Torvalds .ctr = stripe_ctr,
4711da177e4SLinus Torvalds .dtr = stripe_dtr,
4721da177e4SLinus Torvalds .map = stripe_map,
473a25eb944SBrian Wood .end_io = stripe_end_io,
4741da177e4SLinus Torvalds .status = stripe_status,
475af4874e0SMike Snitzer .iterate_devices = stripe_iterate_devices,
47640bea431SMike Snitzer .io_hints = stripe_io_hints,
477817bf402SDan Williams .direct_access = stripe_dax_direct_access,
478cdf6cdcdSVivek Goyal .dax_zero_page_range = stripe_dax_zero_page_range,
479047218ecSJane Chu .dax_recovery_write = stripe_dax_recovery_write,
4801da177e4SLinus Torvalds };
4811da177e4SLinus Torvalds
dm_stripe_init(void)4821da177e4SLinus Torvalds int __init dm_stripe_init(void)
4831da177e4SLinus Torvalds {
4841da177e4SLinus Torvalds int r;
4851da177e4SLinus Torvalds
486a7e8f7fbSTetsuo Handa dm_stripe_wq = alloc_workqueue("dm_stripe_wq", 0, 0);
487a7e8f7fbSTetsuo Handa if (!dm_stripe_wq)
488a7e8f7fbSTetsuo Handa return -ENOMEM;
4891da177e4SLinus Torvalds r = dm_register_target(&stripe_target);
490a7e8f7fbSTetsuo Handa if (r < 0) {
491a7e8f7fbSTetsuo Handa destroy_workqueue(dm_stripe_wq);
49272d94861SAlasdair G Kergon DMWARN("target registration failed");
493a7e8f7fbSTetsuo Handa }
4941da177e4SLinus Torvalds
4951da177e4SLinus Torvalds return r;
4961da177e4SLinus Torvalds }
4971da177e4SLinus Torvalds
dm_stripe_exit(void)4981da177e4SLinus Torvalds void dm_stripe_exit(void)
4991da177e4SLinus Torvalds {
50010d3bd09SMikulas Patocka dm_unregister_target(&stripe_target);
501a7e8f7fbSTetsuo Handa destroy_workqueue(dm_stripe_wq);
5021da177e4SLinus Torvalds }
503