xref: /openbmc/linux/drivers/md/dm-stripe.c (revision ddbd658f)
11da177e4SLinus Torvalds /*
21da177e4SLinus Torvalds  * Copyright (C) 2001-2003 Sistina Software (UK) Limited.
31da177e4SLinus Torvalds  *
41da177e4SLinus Torvalds  * This file is released under the GPL.
51da177e4SLinus Torvalds  */
61da177e4SLinus Torvalds 
7586e80e6SMikulas Patocka #include <linux/device-mapper.h>
81da177e4SLinus Torvalds 
91da177e4SLinus Torvalds #include <linux/module.h>
101da177e4SLinus Torvalds #include <linux/init.h>
111da177e4SLinus Torvalds #include <linux/blkdev.h>
121da177e4SLinus Torvalds #include <linux/bio.h>
131da177e4SLinus Torvalds #include <linux/slab.h>
146f3c3f0aSvignesh babu #include <linux/log2.h>
151da177e4SLinus Torvalds 
1672d94861SAlasdair G Kergon #define DM_MSG_PREFIX "striped"
17a25eb944SBrian Wood #define DM_IO_ERROR_THRESHOLD 15
1872d94861SAlasdair G Kergon 
191da177e4SLinus Torvalds struct stripe {
201da177e4SLinus Torvalds 	struct dm_dev *dev;
211da177e4SLinus Torvalds 	sector_t physical_start;
22a25eb944SBrian Wood 
23a25eb944SBrian Wood 	atomic_t error_count;
241da177e4SLinus Torvalds };
251da177e4SLinus Torvalds 
261da177e4SLinus Torvalds struct stripe_c {
271da177e4SLinus Torvalds 	uint32_t stripes;
28c96053b7SMikulas Patocka 	int stripes_shift;
291da177e4SLinus Torvalds 
301da177e4SLinus Torvalds 	/* The size of this target / num. stripes */
311da177e4SLinus Torvalds 	sector_t stripe_width;
321da177e4SLinus Torvalds 
33eb850de6SMike Snitzer 	uint32_t chunk_size;
3433d07c0dSMikulas Patocka 	int chunk_size_shift;
351da177e4SLinus Torvalds 
36a25eb944SBrian Wood 	/* Needed for handling events */
37a25eb944SBrian Wood 	struct dm_target *ti;
38a25eb944SBrian Wood 
39a25eb944SBrian Wood 	/* Work struct used for triggering events*/
40f521f074STejun Heo 	struct work_struct trigger_event;
41a25eb944SBrian Wood 
421da177e4SLinus Torvalds 	struct stripe stripe[0];
431da177e4SLinus Torvalds };
441da177e4SLinus Torvalds 
45a25eb944SBrian Wood /*
46a25eb944SBrian Wood  * An event is triggered whenever a drive
47a25eb944SBrian Wood  * drops out of a stripe volume.
48a25eb944SBrian Wood  */
49a25eb944SBrian Wood static void trigger_event(struct work_struct *work)
50a25eb944SBrian Wood {
51f521f074STejun Heo 	struct stripe_c *sc = container_of(work, struct stripe_c,
52f521f074STejun Heo 					   trigger_event);
53a25eb944SBrian Wood 	dm_table_event(sc->ti->table);
54a25eb944SBrian Wood }
55a25eb944SBrian Wood 
561da177e4SLinus Torvalds static inline struct stripe_c *alloc_context(unsigned int stripes)
571da177e4SLinus Torvalds {
581da177e4SLinus Torvalds 	size_t len;
591da177e4SLinus Torvalds 
60d63a5ce3SMikulas Patocka 	if (dm_array_too_big(sizeof(struct stripe_c), sizeof(struct stripe),
611da177e4SLinus Torvalds 			     stripes))
621da177e4SLinus Torvalds 		return NULL;
631da177e4SLinus Torvalds 
641da177e4SLinus Torvalds 	len = sizeof(struct stripe_c) + (sizeof(struct stripe) * stripes);
651da177e4SLinus Torvalds 
661da177e4SLinus Torvalds 	return kmalloc(len, GFP_KERNEL);
671da177e4SLinus Torvalds }
681da177e4SLinus Torvalds 
691da177e4SLinus Torvalds /*
701da177e4SLinus Torvalds  * Parse a single <dev> <sector> pair
711da177e4SLinus Torvalds  */
721da177e4SLinus Torvalds static int get_stripe(struct dm_target *ti, struct stripe_c *sc,
731da177e4SLinus Torvalds 		      unsigned int stripe, char **argv)
741da177e4SLinus Torvalds {
754ee218cdSAndrew Morton 	unsigned long long start;
7631998ef1SMikulas Patocka 	char dummy;
771da177e4SLinus Torvalds 
7831998ef1SMikulas Patocka 	if (sscanf(argv[1], "%llu%c", &start, &dummy) != 1)
791da177e4SLinus Torvalds 		return -EINVAL;
801da177e4SLinus Torvalds 
818215d6ecSNikanth Karthikesan 	if (dm_get_device(ti, argv[0], dm_table_get_mode(ti->table),
821da177e4SLinus Torvalds 			  &sc->stripe[stripe].dev))
831da177e4SLinus Torvalds 		return -ENXIO;
841da177e4SLinus Torvalds 
851da177e4SLinus Torvalds 	sc->stripe[stripe].physical_start = start;
86a25eb944SBrian Wood 
871da177e4SLinus Torvalds 	return 0;
881da177e4SLinus Torvalds }
891da177e4SLinus Torvalds 
901da177e4SLinus Torvalds /*
911da177e4SLinus Torvalds  * Construct a striped mapping.
92eb850de6SMike Snitzer  * <number of stripes> <chunk size> [<dev_path> <offset>]+
931da177e4SLinus Torvalds  */
941da177e4SLinus Torvalds static int stripe_ctr(struct dm_target *ti, unsigned int argc, char **argv)
951da177e4SLinus Torvalds {
961da177e4SLinus Torvalds 	struct stripe_c *sc;
971da177e4SLinus Torvalds 	sector_t width;
981da177e4SLinus Torvalds 	uint32_t stripes;
991da177e4SLinus Torvalds 	uint32_t chunk_size;
1001da177e4SLinus Torvalds 	int r;
1011da177e4SLinus Torvalds 	unsigned int i;
1021da177e4SLinus Torvalds 
1031da177e4SLinus Torvalds 	if (argc < 2) {
10472d94861SAlasdair G Kergon 		ti->error = "Not enough arguments";
1051da177e4SLinus Torvalds 		return -EINVAL;
1061da177e4SLinus Torvalds 	}
1071da177e4SLinus Torvalds 
1081a66a08aSmajianpeng 	if (kstrtouint(argv[0], 10, &stripes) || !stripes) {
10972d94861SAlasdair G Kergon 		ti->error = "Invalid stripe count";
1101da177e4SLinus Torvalds 		return -EINVAL;
1111da177e4SLinus Torvalds 	}
1121da177e4SLinus Torvalds 
1138f069b41SMikulas Patocka 	if (kstrtouint(argv[1], 10, &chunk_size) || !chunk_size) {
11472d94861SAlasdair G Kergon 		ti->error = "Invalid chunk_size";
1151da177e4SLinus Torvalds 		return -EINVAL;
1161da177e4SLinus Torvalds 	}
1171da177e4SLinus Torvalds 
118eb850de6SMike Snitzer 	width = ti->len;
119eb850de6SMike Snitzer 	if (sector_div(width, chunk_size)) {
12072d94861SAlasdair G Kergon 		ti->error = "Target length not divisible by "
1218ba32fdeSKevin Corry 		    "chunk size";
1228ba32fdeSKevin Corry 		return -EINVAL;
1238ba32fdeSKevin Corry 	}
1248ba32fdeSKevin Corry 
1251da177e4SLinus Torvalds 	if (sector_div(width, stripes)) {
12672d94861SAlasdair G Kergon 		ti->error = "Target length not divisible by "
1271da177e4SLinus Torvalds 		    "number of stripes";
1281da177e4SLinus Torvalds 		return -EINVAL;
1291da177e4SLinus Torvalds 	}
1301da177e4SLinus Torvalds 
1311da177e4SLinus Torvalds 	/*
1321da177e4SLinus Torvalds 	 * Do we have enough arguments for that many stripes ?
1331da177e4SLinus Torvalds 	 */
1341da177e4SLinus Torvalds 	if (argc != (2 + 2 * stripes)) {
13572d94861SAlasdair G Kergon 		ti->error = "Not enough destinations "
1361da177e4SLinus Torvalds 			"specified";
1371da177e4SLinus Torvalds 		return -EINVAL;
1381da177e4SLinus Torvalds 	}
1391da177e4SLinus Torvalds 
1401da177e4SLinus Torvalds 	sc = alloc_context(stripes);
1411da177e4SLinus Torvalds 	if (!sc) {
14272d94861SAlasdair G Kergon 		ti->error = "Memory allocation for striped context "
1431da177e4SLinus Torvalds 		    "failed";
1441da177e4SLinus Torvalds 		return -ENOMEM;
1451da177e4SLinus Torvalds 	}
1461da177e4SLinus Torvalds 
147f521f074STejun Heo 	INIT_WORK(&sc->trigger_event, trigger_event);
148a25eb944SBrian Wood 
149a25eb944SBrian Wood 	/* Set pointer to dm target; used in trigger_event */
150a25eb944SBrian Wood 	sc->ti = ti;
1511da177e4SLinus Torvalds 	sc->stripes = stripes;
1521da177e4SLinus Torvalds 	sc->stripe_width = width;
153c96053b7SMikulas Patocka 
154c96053b7SMikulas Patocka 	if (stripes & (stripes - 1))
155c96053b7SMikulas Patocka 		sc->stripes_shift = -1;
1561df05483SMikulas Patocka 	else
1571df05483SMikulas Patocka 		sc->stripes_shift = __ffs(stripes);
158c96053b7SMikulas Patocka 
159542f9038SMike Snitzer 	r = dm_set_target_max_io_len(ti, chunk_size);
160542f9038SMike Snitzer 	if (r)
161542f9038SMike Snitzer 		return r;
162542f9038SMike Snitzer 
163374bf7e7SMikulas Patocka 	ti->num_flush_requests = stripes;
1647b76ec11SMikulas Patocka 	ti->num_discard_requests = stripes;
1651da177e4SLinus Torvalds 
166eb850de6SMike Snitzer 	sc->chunk_size = chunk_size;
16733d07c0dSMikulas Patocka 	if (chunk_size & (chunk_size - 1))
16833d07c0dSMikulas Patocka 		sc->chunk_size_shift = -1;
16933d07c0dSMikulas Patocka 	else
17033d07c0dSMikulas Patocka 		sc->chunk_size_shift = __ffs(chunk_size);
1711da177e4SLinus Torvalds 
1721da177e4SLinus Torvalds 	/*
1731da177e4SLinus Torvalds 	 * Get the stripe destinations.
1741da177e4SLinus Torvalds 	 */
1751da177e4SLinus Torvalds 	for (i = 0; i < stripes; i++) {
1761da177e4SLinus Torvalds 		argv += 2;
1771da177e4SLinus Torvalds 
1781da177e4SLinus Torvalds 		r = get_stripe(ti, sc, i, argv);
1791da177e4SLinus Torvalds 		if (r < 0) {
18072d94861SAlasdair G Kergon 			ti->error = "Couldn't parse stripe destination";
1811da177e4SLinus Torvalds 			while (i--)
1821da177e4SLinus Torvalds 				dm_put_device(ti, sc->stripe[i].dev);
1831da177e4SLinus Torvalds 			kfree(sc);
1841da177e4SLinus Torvalds 			return r;
1851da177e4SLinus Torvalds 		}
186a25eb944SBrian Wood 		atomic_set(&(sc->stripe[i].error_count), 0);
1871da177e4SLinus Torvalds 	}
1881da177e4SLinus Torvalds 
1891da177e4SLinus Torvalds 	ti->private = sc;
190a25eb944SBrian Wood 
1911da177e4SLinus Torvalds 	return 0;
1921da177e4SLinus Torvalds }
1931da177e4SLinus Torvalds 
1941da177e4SLinus Torvalds static void stripe_dtr(struct dm_target *ti)
1951da177e4SLinus Torvalds {
1961da177e4SLinus Torvalds 	unsigned int i;
1971da177e4SLinus Torvalds 	struct stripe_c *sc = (struct stripe_c *) ti->private;
1981da177e4SLinus Torvalds 
1991da177e4SLinus Torvalds 	for (i = 0; i < sc->stripes; i++)
2001da177e4SLinus Torvalds 		dm_put_device(ti, sc->stripe[i].dev);
2011da177e4SLinus Torvalds 
20243829731STejun Heo 	flush_work(&sc->trigger_event);
2031da177e4SLinus Torvalds 	kfree(sc);
2041da177e4SLinus Torvalds }
2051da177e4SLinus Torvalds 
20665988525SMikulas Patocka static void stripe_map_sector(struct stripe_c *sc, sector_t sector,
20765988525SMikulas Patocka 			      uint32_t *stripe, sector_t *result)
20865988525SMikulas Patocka {
209eb850de6SMike Snitzer 	sector_t chunk = dm_target_offset(sc->ti, sector);
21033d07c0dSMikulas Patocka 	sector_t chunk_offset;
21133d07c0dSMikulas Patocka 
21233d07c0dSMikulas Patocka 	if (sc->chunk_size_shift < 0)
21333d07c0dSMikulas Patocka 		chunk_offset = sector_div(chunk, sc->chunk_size);
21433d07c0dSMikulas Patocka 	else {
21533d07c0dSMikulas Patocka 		chunk_offset = chunk & (sc->chunk_size - 1);
21633d07c0dSMikulas Patocka 		chunk >>= sc->chunk_size_shift;
21733d07c0dSMikulas Patocka 	}
21865988525SMikulas Patocka 
219c96053b7SMikulas Patocka 	if (sc->stripes_shift < 0)
22065988525SMikulas Patocka 		*stripe = sector_div(chunk, sc->stripes);
221c96053b7SMikulas Patocka 	else {
2221df05483SMikulas Patocka 		*stripe = chunk & (sc->stripes - 1);
223c96053b7SMikulas Patocka 		chunk >>= sc->stripes_shift;
224c96053b7SMikulas Patocka 	}
225c96053b7SMikulas Patocka 
22633d07c0dSMikulas Patocka 	if (sc->chunk_size_shift < 0)
22733d07c0dSMikulas Patocka 		chunk *= sc->chunk_size;
22833d07c0dSMikulas Patocka 	else
22933d07c0dSMikulas Patocka 		chunk <<= sc->chunk_size_shift;
23033d07c0dSMikulas Patocka 
23133d07c0dSMikulas Patocka 	*result = chunk + chunk_offset;
23265988525SMikulas Patocka }
23365988525SMikulas Patocka 
2347b76ec11SMikulas Patocka static void stripe_map_range_sector(struct stripe_c *sc, sector_t sector,
2357b76ec11SMikulas Patocka 				    uint32_t target_stripe, sector_t *result)
2367b76ec11SMikulas Patocka {
2377b76ec11SMikulas Patocka 	uint32_t stripe;
2387b76ec11SMikulas Patocka 
2397b76ec11SMikulas Patocka 	stripe_map_sector(sc, sector, &stripe, result);
2407b76ec11SMikulas Patocka 	if (stripe == target_stripe)
2417b76ec11SMikulas Patocka 		return;
242eb850de6SMike Snitzer 
243eb850de6SMike Snitzer 	/* round down */
244eb850de6SMike Snitzer 	sector = *result;
24533d07c0dSMikulas Patocka 	if (sc->chunk_size_shift < 0)
246eb850de6SMike Snitzer 		*result -= sector_div(sector, sc->chunk_size);
24733d07c0dSMikulas Patocka 	else
24833d07c0dSMikulas Patocka 		*result = sector & ~(sector_t)(sc->chunk_size - 1);
249eb850de6SMike Snitzer 
2507b76ec11SMikulas Patocka 	if (target_stripe < stripe)
251eb850de6SMike Snitzer 		*result += sc->chunk_size;		/* next chunk */
2527b76ec11SMikulas Patocka }
2537b76ec11SMikulas Patocka 
2547b76ec11SMikulas Patocka static int stripe_map_discard(struct stripe_c *sc, struct bio *bio,
2557b76ec11SMikulas Patocka 			      uint32_t target_stripe)
2567b76ec11SMikulas Patocka {
2577b76ec11SMikulas Patocka 	sector_t begin, end;
2587b76ec11SMikulas Patocka 
2597b76ec11SMikulas Patocka 	stripe_map_range_sector(sc, bio->bi_sector, target_stripe, &begin);
2607b76ec11SMikulas Patocka 	stripe_map_range_sector(sc, bio->bi_sector + bio_sectors(bio),
2617b76ec11SMikulas Patocka 				target_stripe, &end);
2627b76ec11SMikulas Patocka 	if (begin < end) {
2637b76ec11SMikulas Patocka 		bio->bi_bdev = sc->stripe[target_stripe].dev->bdev;
2647b76ec11SMikulas Patocka 		bio->bi_sector = begin + sc->stripe[target_stripe].physical_start;
2657b76ec11SMikulas Patocka 		bio->bi_size = to_bytes(end - begin);
2667b76ec11SMikulas Patocka 		return DM_MAPIO_REMAPPED;
2677b76ec11SMikulas Patocka 	} else {
2687b76ec11SMikulas Patocka 		/* The range doesn't map to the target stripe */
2697b76ec11SMikulas Patocka 		bio_endio(bio, 0);
2707b76ec11SMikulas Patocka 		return DM_MAPIO_SUBMITTED;
2717b76ec11SMikulas Patocka 	}
2727b76ec11SMikulas Patocka }
2737b76ec11SMikulas Patocka 
2741da177e4SLinus Torvalds static int stripe_map(struct dm_target *ti, struct bio *bio,
2751da177e4SLinus Torvalds 		      union map_info *map_context)
2761da177e4SLinus Torvalds {
27765988525SMikulas Patocka 	struct stripe_c *sc = ti->private;
278374bf7e7SMikulas Patocka 	uint32_t stripe;
27957cba5d3SMike Snitzer 	unsigned target_request_nr;
2801da177e4SLinus Torvalds 
281d87f4c14STejun Heo 	if (bio->bi_rw & REQ_FLUSH) {
282ddbd658fSMikulas Patocka 		target_request_nr = dm_bio_get_target_request_nr(bio);
28357cba5d3SMike Snitzer 		BUG_ON(target_request_nr >= sc->stripes);
28457cba5d3SMike Snitzer 		bio->bi_bdev = sc->stripe[target_request_nr].dev->bdev;
285374bf7e7SMikulas Patocka 		return DM_MAPIO_REMAPPED;
286374bf7e7SMikulas Patocka 	}
2877b76ec11SMikulas Patocka 	if (unlikely(bio->bi_rw & REQ_DISCARD)) {
288ddbd658fSMikulas Patocka 		target_request_nr = dm_bio_get_target_request_nr(bio);
2897b76ec11SMikulas Patocka 		BUG_ON(target_request_nr >= sc->stripes);
2907b76ec11SMikulas Patocka 		return stripe_map_discard(sc, bio, target_request_nr);
2917b76ec11SMikulas Patocka 	}
292374bf7e7SMikulas Patocka 
29365988525SMikulas Patocka 	stripe_map_sector(sc, bio->bi_sector, &stripe, &bio->bi_sector);
2941da177e4SLinus Torvalds 
29565988525SMikulas Patocka 	bio->bi_sector += sc->stripe[stripe].physical_start;
2961da177e4SLinus Torvalds 	bio->bi_bdev = sc->stripe[stripe].dev->bdev;
29765988525SMikulas Patocka 
298d2a7ad29SKiyoshi Ueda 	return DM_MAPIO_REMAPPED;
2991da177e4SLinus Torvalds }
3001da177e4SLinus Torvalds 
3014f7f5c67SBrian Wood /*
3024f7f5c67SBrian Wood  * Stripe status:
3034f7f5c67SBrian Wood  *
3044f7f5c67SBrian Wood  * INFO
3054f7f5c67SBrian Wood  * #stripes [stripe_name <stripe_name>] [group word count]
3064f7f5c67SBrian Wood  * [error count 'A|D' <error count 'A|D'>]
3074f7f5c67SBrian Wood  *
3084f7f5c67SBrian Wood  * TABLE
3094f7f5c67SBrian Wood  * #stripes [stripe chunk size]
3104f7f5c67SBrian Wood  * [stripe_name physical_start <stripe_name physical_start>]
3114f7f5c67SBrian Wood  *
3124f7f5c67SBrian Wood  */
3134f7f5c67SBrian Wood 
3141f4e0ff0SAlasdair G Kergon static int stripe_status(struct dm_target *ti, status_type_t type,
3151f4e0ff0SAlasdair G Kergon 			 unsigned status_flags, char *result, unsigned maxlen)
3161da177e4SLinus Torvalds {
3171da177e4SLinus Torvalds 	struct stripe_c *sc = (struct stripe_c *) ti->private;
3184f7f5c67SBrian Wood 	char buffer[sc->stripes + 1];
3191da177e4SLinus Torvalds 	unsigned int sz = 0;
3201da177e4SLinus Torvalds 	unsigned int i;
3211da177e4SLinus Torvalds 
3221da177e4SLinus Torvalds 	switch (type) {
3231da177e4SLinus Torvalds 	case STATUSTYPE_INFO:
3244f7f5c67SBrian Wood 		DMEMIT("%d ", sc->stripes);
3254f7f5c67SBrian Wood 		for (i = 0; i < sc->stripes; i++)  {
3264f7f5c67SBrian Wood 			DMEMIT("%s ", sc->stripe[i].dev->name);
3274f7f5c67SBrian Wood 			buffer[i] = atomic_read(&(sc->stripe[i].error_count)) ?
3284f7f5c67SBrian Wood 				'D' : 'A';
3294f7f5c67SBrian Wood 		}
3304f7f5c67SBrian Wood 		buffer[i] = '\0';
3314f7f5c67SBrian Wood 		DMEMIT("1 %s", buffer);
3321da177e4SLinus Torvalds 		break;
3331da177e4SLinus Torvalds 
3341da177e4SLinus Torvalds 	case STATUSTYPE_TABLE:
3354ee218cdSAndrew Morton 		DMEMIT("%d %llu", sc->stripes,
336eb850de6SMike Snitzer 			(unsigned long long)sc->chunk_size);
3371da177e4SLinus Torvalds 		for (i = 0; i < sc->stripes; i++)
3384ee218cdSAndrew Morton 			DMEMIT(" %s %llu", sc->stripe[i].dev->name,
3394ee218cdSAndrew Morton 			    (unsigned long long)sc->stripe[i].physical_start);
3401da177e4SLinus Torvalds 		break;
3411da177e4SLinus Torvalds 	}
3421da177e4SLinus Torvalds 	return 0;
3431da177e4SLinus Torvalds }
3441da177e4SLinus Torvalds 
345a25eb944SBrian Wood static int stripe_end_io(struct dm_target *ti, struct bio *bio,
346a25eb944SBrian Wood 			 int error, union map_info *map_context)
347a25eb944SBrian Wood {
348a25eb944SBrian Wood 	unsigned i;
349a25eb944SBrian Wood 	char major_minor[16];
350a25eb944SBrian Wood 	struct stripe_c *sc = ti->private;
351a25eb944SBrian Wood 
352a25eb944SBrian Wood 	if (!error)
353a25eb944SBrian Wood 		return 0; /* I/O complete */
354a25eb944SBrian Wood 
3557b6d91daSChristoph Hellwig 	if ((error == -EWOULDBLOCK) && (bio->bi_rw & REQ_RAHEAD))
356a25eb944SBrian Wood 		return error;
357a25eb944SBrian Wood 
358a25eb944SBrian Wood 	if (error == -EOPNOTSUPP)
359a25eb944SBrian Wood 		return error;
360a25eb944SBrian Wood 
361a25eb944SBrian Wood 	memset(major_minor, 0, sizeof(major_minor));
362a25eb944SBrian Wood 	sprintf(major_minor, "%d:%d",
363f331c029STejun Heo 		MAJOR(disk_devt(bio->bi_bdev->bd_disk)),
364f331c029STejun Heo 		MINOR(disk_devt(bio->bi_bdev->bd_disk)));
365a25eb944SBrian Wood 
366a25eb944SBrian Wood 	/*
367a25eb944SBrian Wood 	 * Test to see which stripe drive triggered the event
368a25eb944SBrian Wood 	 * and increment error count for all stripes on that device.
369a25eb944SBrian Wood 	 * If the error count for a given device exceeds the threshold
370a25eb944SBrian Wood 	 * value we will no longer trigger any further events.
371a25eb944SBrian Wood 	 */
372a25eb944SBrian Wood 	for (i = 0; i < sc->stripes; i++)
373a25eb944SBrian Wood 		if (!strcmp(sc->stripe[i].dev->name, major_minor)) {
374a25eb944SBrian Wood 			atomic_inc(&(sc->stripe[i].error_count));
375a25eb944SBrian Wood 			if (atomic_read(&(sc->stripe[i].error_count)) <
376a25eb944SBrian Wood 			    DM_IO_ERROR_THRESHOLD)
377f521f074STejun Heo 				schedule_work(&sc->trigger_event);
378a25eb944SBrian Wood 		}
379a25eb944SBrian Wood 
380a25eb944SBrian Wood 	return error;
381a25eb944SBrian Wood }
382a25eb944SBrian Wood 
383af4874e0SMike Snitzer static int stripe_iterate_devices(struct dm_target *ti,
384af4874e0SMike Snitzer 				  iterate_devices_callout_fn fn, void *data)
385af4874e0SMike Snitzer {
386af4874e0SMike Snitzer 	struct stripe_c *sc = ti->private;
387af4874e0SMike Snitzer 	int ret = 0;
388af4874e0SMike Snitzer 	unsigned i = 0;
389af4874e0SMike Snitzer 
3905dea271bSMike Snitzer 	do {
391af4874e0SMike Snitzer 		ret = fn(ti, sc->stripe[i].dev,
3925dea271bSMike Snitzer 			 sc->stripe[i].physical_start,
3935dea271bSMike Snitzer 			 sc->stripe_width, data);
3945dea271bSMike Snitzer 	} while (!ret && ++i < sc->stripes);
395af4874e0SMike Snitzer 
396af4874e0SMike Snitzer 	return ret;
397af4874e0SMike Snitzer }
398af4874e0SMike Snitzer 
39940bea431SMike Snitzer static void stripe_io_hints(struct dm_target *ti,
40040bea431SMike Snitzer 			    struct queue_limits *limits)
40140bea431SMike Snitzer {
40240bea431SMike Snitzer 	struct stripe_c *sc = ti->private;
403eb850de6SMike Snitzer 	unsigned chunk_size = sc->chunk_size << SECTOR_SHIFT;
40440bea431SMike Snitzer 
40540bea431SMike Snitzer 	blk_limits_io_min(limits, chunk_size);
4063c5820c7SMartin K. Petersen 	blk_limits_io_opt(limits, chunk_size * sc->stripes);
40740bea431SMike Snitzer }
40840bea431SMike Snitzer 
40929915202SMustafa Mesanovic static int stripe_merge(struct dm_target *ti, struct bvec_merge_data *bvm,
41029915202SMustafa Mesanovic 			struct bio_vec *biovec, int max_size)
41129915202SMustafa Mesanovic {
41229915202SMustafa Mesanovic 	struct stripe_c *sc = ti->private;
41329915202SMustafa Mesanovic 	sector_t bvm_sector = bvm->bi_sector;
41429915202SMustafa Mesanovic 	uint32_t stripe;
41529915202SMustafa Mesanovic 	struct request_queue *q;
41629915202SMustafa Mesanovic 
41729915202SMustafa Mesanovic 	stripe_map_sector(sc, bvm_sector, &stripe, &bvm_sector);
41829915202SMustafa Mesanovic 
41929915202SMustafa Mesanovic 	q = bdev_get_queue(sc->stripe[stripe].dev->bdev);
42029915202SMustafa Mesanovic 	if (!q->merge_bvec_fn)
42129915202SMustafa Mesanovic 		return max_size;
42229915202SMustafa Mesanovic 
42329915202SMustafa Mesanovic 	bvm->bi_bdev = sc->stripe[stripe].dev->bdev;
42429915202SMustafa Mesanovic 	bvm->bi_sector = sc->stripe[stripe].physical_start + bvm_sector;
42529915202SMustafa Mesanovic 
42629915202SMustafa Mesanovic 	return min(max_size, q->merge_bvec_fn(q, bvm, biovec));
42729915202SMustafa Mesanovic }
42829915202SMustafa Mesanovic 
4291da177e4SLinus Torvalds static struct target_type stripe_target = {
4301da177e4SLinus Torvalds 	.name   = "striped",
431eb850de6SMike Snitzer 	.version = {1, 5, 0},
4321da177e4SLinus Torvalds 	.module = THIS_MODULE,
4331da177e4SLinus Torvalds 	.ctr    = stripe_ctr,
4341da177e4SLinus Torvalds 	.dtr    = stripe_dtr,
4351da177e4SLinus Torvalds 	.map    = stripe_map,
436a25eb944SBrian Wood 	.end_io = stripe_end_io,
4371da177e4SLinus Torvalds 	.status = stripe_status,
438af4874e0SMike Snitzer 	.iterate_devices = stripe_iterate_devices,
43940bea431SMike Snitzer 	.io_hints = stripe_io_hints,
44029915202SMustafa Mesanovic 	.merge  = stripe_merge,
4411da177e4SLinus Torvalds };
4421da177e4SLinus Torvalds 
4431da177e4SLinus Torvalds int __init dm_stripe_init(void)
4441da177e4SLinus Torvalds {
4451da177e4SLinus Torvalds 	int r;
4461da177e4SLinus Torvalds 
4471da177e4SLinus Torvalds 	r = dm_register_target(&stripe_target);
4486edebdeeSHeinz Mauelshagen 	if (r < 0) {
44972d94861SAlasdair G Kergon 		DMWARN("target registration failed");
4506edebdeeSHeinz Mauelshagen 		return r;
4516edebdeeSHeinz Mauelshagen 	}
4521da177e4SLinus Torvalds 
4531da177e4SLinus Torvalds 	return r;
4541da177e4SLinus Torvalds }
4551da177e4SLinus Torvalds 
4561da177e4SLinus Torvalds void dm_stripe_exit(void)
4571da177e4SLinus Torvalds {
45810d3bd09SMikulas Patocka 	dm_unregister_target(&stripe_target);
4591da177e4SLinus Torvalds }
460