xref: /openbmc/linux/drivers/md/dm-stripe.c (revision 26cb62a2)
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