xref: /openbmc/linux/drivers/md/dm-stripe.c (revision fd7c092e)
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;
16545e621d4SMike Snitzer 	ti->num_write_same_requests = stripes;
1661da177e4SLinus Torvalds 
167eb850de6SMike Snitzer 	sc->chunk_size = chunk_size;
16833d07c0dSMikulas Patocka 	if (chunk_size & (chunk_size - 1))
16933d07c0dSMikulas Patocka 		sc->chunk_size_shift = -1;
17033d07c0dSMikulas Patocka 	else
17133d07c0dSMikulas Patocka 		sc->chunk_size_shift = __ffs(chunk_size);
1721da177e4SLinus Torvalds 
1731da177e4SLinus Torvalds 	/*
1741da177e4SLinus Torvalds 	 * Get the stripe destinations.
1751da177e4SLinus Torvalds 	 */
1761da177e4SLinus Torvalds 	for (i = 0; i < stripes; i++) {
1771da177e4SLinus Torvalds 		argv += 2;
1781da177e4SLinus Torvalds 
1791da177e4SLinus Torvalds 		r = get_stripe(ti, sc, i, argv);
1801da177e4SLinus Torvalds 		if (r < 0) {
18172d94861SAlasdair G Kergon 			ti->error = "Couldn't parse stripe destination";
1821da177e4SLinus Torvalds 			while (i--)
1831da177e4SLinus Torvalds 				dm_put_device(ti, sc->stripe[i].dev);
1841da177e4SLinus Torvalds 			kfree(sc);
1851da177e4SLinus Torvalds 			return r;
1861da177e4SLinus Torvalds 		}
187a25eb944SBrian Wood 		atomic_set(&(sc->stripe[i].error_count), 0);
1881da177e4SLinus Torvalds 	}
1891da177e4SLinus Torvalds 
1901da177e4SLinus Torvalds 	ti->private = sc;
191a25eb944SBrian Wood 
1921da177e4SLinus Torvalds 	return 0;
1931da177e4SLinus Torvalds }
1941da177e4SLinus Torvalds 
1951da177e4SLinus Torvalds static void stripe_dtr(struct dm_target *ti)
1961da177e4SLinus Torvalds {
1971da177e4SLinus Torvalds 	unsigned int i;
1981da177e4SLinus Torvalds 	struct stripe_c *sc = (struct stripe_c *) ti->private;
1991da177e4SLinus Torvalds 
2001da177e4SLinus Torvalds 	for (i = 0; i < sc->stripes; i++)
2011da177e4SLinus Torvalds 		dm_put_device(ti, sc->stripe[i].dev);
2021da177e4SLinus Torvalds 
20343829731STejun Heo 	flush_work(&sc->trigger_event);
2041da177e4SLinus Torvalds 	kfree(sc);
2051da177e4SLinus Torvalds }
2061da177e4SLinus Torvalds 
20765988525SMikulas Patocka static void stripe_map_sector(struct stripe_c *sc, sector_t sector,
20865988525SMikulas Patocka 			      uint32_t *stripe, sector_t *result)
20965988525SMikulas Patocka {
210eb850de6SMike Snitzer 	sector_t chunk = dm_target_offset(sc->ti, sector);
21133d07c0dSMikulas Patocka 	sector_t chunk_offset;
21233d07c0dSMikulas Patocka 
21333d07c0dSMikulas Patocka 	if (sc->chunk_size_shift < 0)
21433d07c0dSMikulas Patocka 		chunk_offset = sector_div(chunk, sc->chunk_size);
21533d07c0dSMikulas Patocka 	else {
21633d07c0dSMikulas Patocka 		chunk_offset = chunk & (sc->chunk_size - 1);
21733d07c0dSMikulas Patocka 		chunk >>= sc->chunk_size_shift;
21833d07c0dSMikulas Patocka 	}
21965988525SMikulas Patocka 
220c96053b7SMikulas Patocka 	if (sc->stripes_shift < 0)
22165988525SMikulas Patocka 		*stripe = sector_div(chunk, sc->stripes);
222c96053b7SMikulas Patocka 	else {
2231df05483SMikulas Patocka 		*stripe = chunk & (sc->stripes - 1);
224c96053b7SMikulas Patocka 		chunk >>= sc->stripes_shift;
225c96053b7SMikulas Patocka 	}
226c96053b7SMikulas Patocka 
22733d07c0dSMikulas Patocka 	if (sc->chunk_size_shift < 0)
22833d07c0dSMikulas Patocka 		chunk *= sc->chunk_size;
22933d07c0dSMikulas Patocka 	else
23033d07c0dSMikulas Patocka 		chunk <<= sc->chunk_size_shift;
23133d07c0dSMikulas Patocka 
23233d07c0dSMikulas Patocka 	*result = chunk + chunk_offset;
23365988525SMikulas Patocka }
23465988525SMikulas Patocka 
2357b76ec11SMikulas Patocka static void stripe_map_range_sector(struct stripe_c *sc, sector_t sector,
2367b76ec11SMikulas Patocka 				    uint32_t target_stripe, sector_t *result)
2377b76ec11SMikulas Patocka {
2387b76ec11SMikulas Patocka 	uint32_t stripe;
2397b76ec11SMikulas Patocka 
2407b76ec11SMikulas Patocka 	stripe_map_sector(sc, sector, &stripe, result);
2417b76ec11SMikulas Patocka 	if (stripe == target_stripe)
2427b76ec11SMikulas Patocka 		return;
243eb850de6SMike Snitzer 
244eb850de6SMike Snitzer 	/* round down */
245eb850de6SMike Snitzer 	sector = *result;
24633d07c0dSMikulas Patocka 	if (sc->chunk_size_shift < 0)
247eb850de6SMike Snitzer 		*result -= sector_div(sector, sc->chunk_size);
24833d07c0dSMikulas Patocka 	else
24933d07c0dSMikulas Patocka 		*result = sector & ~(sector_t)(sc->chunk_size - 1);
250eb850de6SMike Snitzer 
2517b76ec11SMikulas Patocka 	if (target_stripe < stripe)
252eb850de6SMike Snitzer 		*result += sc->chunk_size;		/* next chunk */
2537b76ec11SMikulas Patocka }
2547b76ec11SMikulas Patocka 
25545e621d4SMike Snitzer static int stripe_map_range(struct stripe_c *sc, struct bio *bio,
2567b76ec11SMikulas Patocka 			    uint32_t target_stripe)
2577b76ec11SMikulas Patocka {
2587b76ec11SMikulas Patocka 	sector_t begin, end;
2597b76ec11SMikulas Patocka 
2607b76ec11SMikulas Patocka 	stripe_map_range_sector(sc, bio->bi_sector, target_stripe, &begin);
2617b76ec11SMikulas Patocka 	stripe_map_range_sector(sc, bio->bi_sector + bio_sectors(bio),
2627b76ec11SMikulas Patocka 				target_stripe, &end);
2637b76ec11SMikulas Patocka 	if (begin < end) {
2647b76ec11SMikulas Patocka 		bio->bi_bdev = sc->stripe[target_stripe].dev->bdev;
2657b76ec11SMikulas Patocka 		bio->bi_sector = begin + sc->stripe[target_stripe].physical_start;
2667b76ec11SMikulas Patocka 		bio->bi_size = to_bytes(end - begin);
2677b76ec11SMikulas Patocka 		return DM_MAPIO_REMAPPED;
2687b76ec11SMikulas Patocka 	} else {
2697b76ec11SMikulas Patocka 		/* The range doesn't map to the target stripe */
2707b76ec11SMikulas Patocka 		bio_endio(bio, 0);
2717b76ec11SMikulas Patocka 		return DM_MAPIO_SUBMITTED;
2727b76ec11SMikulas Patocka 	}
2737b76ec11SMikulas Patocka }
2747b76ec11SMikulas Patocka 
2757de3ee57SMikulas Patocka static int stripe_map(struct dm_target *ti, struct bio *bio)
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 	}
28745e621d4SMike Snitzer 	if (unlikely(bio->bi_rw & REQ_DISCARD) ||
28845e621d4SMike Snitzer 	    unlikely(bio->bi_rw & REQ_WRITE_SAME)) {
289ddbd658fSMikulas Patocka 		target_request_nr = dm_bio_get_target_request_nr(bio);
2907b76ec11SMikulas Patocka 		BUG_ON(target_request_nr >= sc->stripes);
29145e621d4SMike Snitzer 		return stripe_map_range(sc, bio, target_request_nr);
2927b76ec11SMikulas Patocka 	}
293374bf7e7SMikulas Patocka 
29465988525SMikulas Patocka 	stripe_map_sector(sc, bio->bi_sector, &stripe, &bio->bi_sector);
2951da177e4SLinus Torvalds 
29665988525SMikulas Patocka 	bio->bi_sector += sc->stripe[stripe].physical_start;
2971da177e4SLinus Torvalds 	bio->bi_bdev = sc->stripe[stripe].dev->bdev;
29865988525SMikulas Patocka 
299d2a7ad29SKiyoshi Ueda 	return DM_MAPIO_REMAPPED;
3001da177e4SLinus Torvalds }
3011da177e4SLinus Torvalds 
3024f7f5c67SBrian Wood /*
3034f7f5c67SBrian Wood  * Stripe status:
3044f7f5c67SBrian Wood  *
3054f7f5c67SBrian Wood  * INFO
3064f7f5c67SBrian Wood  * #stripes [stripe_name <stripe_name>] [group word count]
3074f7f5c67SBrian Wood  * [error count 'A|D' <error count 'A|D'>]
3084f7f5c67SBrian Wood  *
3094f7f5c67SBrian Wood  * TABLE
3104f7f5c67SBrian Wood  * #stripes [stripe chunk size]
3114f7f5c67SBrian Wood  * [stripe_name physical_start <stripe_name physical_start>]
3124f7f5c67SBrian Wood  *
3134f7f5c67SBrian Wood  */
3144f7f5c67SBrian Wood 
315fd7c092eSMikulas Patocka static void stripe_status(struct dm_target *ti, status_type_t type,
3161f4e0ff0SAlasdair G Kergon 			  unsigned status_flags, char *result, unsigned maxlen)
3171da177e4SLinus Torvalds {
3181da177e4SLinus Torvalds 	struct stripe_c *sc = (struct stripe_c *) ti->private;
3194f7f5c67SBrian Wood 	char buffer[sc->stripes + 1];
3201da177e4SLinus Torvalds 	unsigned int sz = 0;
3211da177e4SLinus Torvalds 	unsigned int i;
3221da177e4SLinus Torvalds 
3231da177e4SLinus Torvalds 	switch (type) {
3241da177e4SLinus Torvalds 	case STATUSTYPE_INFO:
3254f7f5c67SBrian Wood 		DMEMIT("%d ", sc->stripes);
3264f7f5c67SBrian Wood 		for (i = 0; i < sc->stripes; i++)  {
3274f7f5c67SBrian Wood 			DMEMIT("%s ", sc->stripe[i].dev->name);
3284f7f5c67SBrian Wood 			buffer[i] = atomic_read(&(sc->stripe[i].error_count)) ?
3294f7f5c67SBrian Wood 				'D' : 'A';
3304f7f5c67SBrian Wood 		}
3314f7f5c67SBrian Wood 		buffer[i] = '\0';
3324f7f5c67SBrian Wood 		DMEMIT("1 %s", buffer);
3331da177e4SLinus Torvalds 		break;
3341da177e4SLinus Torvalds 
3351da177e4SLinus Torvalds 	case STATUSTYPE_TABLE:
3364ee218cdSAndrew Morton 		DMEMIT("%d %llu", sc->stripes,
337eb850de6SMike Snitzer 			(unsigned long long)sc->chunk_size);
3381da177e4SLinus Torvalds 		for (i = 0; i < sc->stripes; i++)
3394ee218cdSAndrew Morton 			DMEMIT(" %s %llu", sc->stripe[i].dev->name,
3404ee218cdSAndrew Morton 			    (unsigned long long)sc->stripe[i].physical_start);
3411da177e4SLinus Torvalds 		break;
3421da177e4SLinus Torvalds 	}
3431da177e4SLinus Torvalds }
3441da177e4SLinus Torvalds 
3457de3ee57SMikulas Patocka static int stripe_end_io(struct dm_target *ti, struct bio *bio, int error)
346a25eb944SBrian Wood {
347a25eb944SBrian Wood 	unsigned i;
348a25eb944SBrian Wood 	char major_minor[16];
349a25eb944SBrian Wood 	struct stripe_c *sc = ti->private;
350a25eb944SBrian Wood 
351a25eb944SBrian Wood 	if (!error)
352a25eb944SBrian Wood 		return 0; /* I/O complete */
353a25eb944SBrian Wood 
3547b6d91daSChristoph Hellwig 	if ((error == -EWOULDBLOCK) && (bio->bi_rw & REQ_RAHEAD))
355a25eb944SBrian Wood 		return error;
356a25eb944SBrian Wood 
357a25eb944SBrian Wood 	if (error == -EOPNOTSUPP)
358a25eb944SBrian Wood 		return error;
359a25eb944SBrian Wood 
360a25eb944SBrian Wood 	memset(major_minor, 0, sizeof(major_minor));
361a25eb944SBrian Wood 	sprintf(major_minor, "%d:%d",
362f331c029STejun Heo 		MAJOR(disk_devt(bio->bi_bdev->bd_disk)),
363f331c029STejun Heo 		MINOR(disk_devt(bio->bi_bdev->bd_disk)));
364a25eb944SBrian Wood 
365a25eb944SBrian Wood 	/*
366a25eb944SBrian Wood 	 * Test to see which stripe drive triggered the event
367a25eb944SBrian Wood 	 * and increment error count for all stripes on that device.
368a25eb944SBrian Wood 	 * If the error count for a given device exceeds the threshold
369a25eb944SBrian Wood 	 * value we will no longer trigger any further events.
370a25eb944SBrian Wood 	 */
371a25eb944SBrian Wood 	for (i = 0; i < sc->stripes; i++)
372a25eb944SBrian Wood 		if (!strcmp(sc->stripe[i].dev->name, major_minor)) {
373a25eb944SBrian Wood 			atomic_inc(&(sc->stripe[i].error_count));
374a25eb944SBrian Wood 			if (atomic_read(&(sc->stripe[i].error_count)) <
375a25eb944SBrian Wood 			    DM_IO_ERROR_THRESHOLD)
376f521f074STejun Heo 				schedule_work(&sc->trigger_event);
377a25eb944SBrian Wood 		}
378a25eb944SBrian Wood 
379a25eb944SBrian Wood 	return error;
380a25eb944SBrian Wood }
381a25eb944SBrian Wood 
382af4874e0SMike Snitzer static int stripe_iterate_devices(struct dm_target *ti,
383af4874e0SMike Snitzer 				  iterate_devices_callout_fn fn, void *data)
384af4874e0SMike Snitzer {
385af4874e0SMike Snitzer 	struct stripe_c *sc = ti->private;
386af4874e0SMike Snitzer 	int ret = 0;
387af4874e0SMike Snitzer 	unsigned i = 0;
388af4874e0SMike Snitzer 
3895dea271bSMike Snitzer 	do {
390af4874e0SMike Snitzer 		ret = fn(ti, sc->stripe[i].dev,
3915dea271bSMike Snitzer 			 sc->stripe[i].physical_start,
3925dea271bSMike Snitzer 			 sc->stripe_width, data);
3935dea271bSMike Snitzer 	} while (!ret && ++i < sc->stripes);
394af4874e0SMike Snitzer 
395af4874e0SMike Snitzer 	return ret;
396af4874e0SMike Snitzer }
397af4874e0SMike Snitzer 
39840bea431SMike Snitzer static void stripe_io_hints(struct dm_target *ti,
39940bea431SMike Snitzer 			    struct queue_limits *limits)
40040bea431SMike Snitzer {
40140bea431SMike Snitzer 	struct stripe_c *sc = ti->private;
402eb850de6SMike Snitzer 	unsigned chunk_size = sc->chunk_size << SECTOR_SHIFT;
40340bea431SMike Snitzer 
40440bea431SMike Snitzer 	blk_limits_io_min(limits, chunk_size);
4053c5820c7SMartin K. Petersen 	blk_limits_io_opt(limits, chunk_size * sc->stripes);
40640bea431SMike Snitzer }
40740bea431SMike Snitzer 
40829915202SMustafa Mesanovic static int stripe_merge(struct dm_target *ti, struct bvec_merge_data *bvm,
40929915202SMustafa Mesanovic 			struct bio_vec *biovec, int max_size)
41029915202SMustafa Mesanovic {
41129915202SMustafa Mesanovic 	struct stripe_c *sc = ti->private;
41229915202SMustafa Mesanovic 	sector_t bvm_sector = bvm->bi_sector;
41329915202SMustafa Mesanovic 	uint32_t stripe;
41429915202SMustafa Mesanovic 	struct request_queue *q;
41529915202SMustafa Mesanovic 
41629915202SMustafa Mesanovic 	stripe_map_sector(sc, bvm_sector, &stripe, &bvm_sector);
41729915202SMustafa Mesanovic 
41829915202SMustafa Mesanovic 	q = bdev_get_queue(sc->stripe[stripe].dev->bdev);
41929915202SMustafa Mesanovic 	if (!q->merge_bvec_fn)
42029915202SMustafa Mesanovic 		return max_size;
42129915202SMustafa Mesanovic 
42229915202SMustafa Mesanovic 	bvm->bi_bdev = sc->stripe[stripe].dev->bdev;
42329915202SMustafa Mesanovic 	bvm->bi_sector = sc->stripe[stripe].physical_start + bvm_sector;
42429915202SMustafa Mesanovic 
42529915202SMustafa Mesanovic 	return min(max_size, q->merge_bvec_fn(q, bvm, biovec));
42629915202SMustafa Mesanovic }
42729915202SMustafa Mesanovic 
4281da177e4SLinus Torvalds static struct target_type stripe_target = {
4291da177e4SLinus Torvalds 	.name   = "striped",
430fd7c092eSMikulas Patocka 	.version = {1, 5, 1},
4311da177e4SLinus Torvalds 	.module = THIS_MODULE,
4321da177e4SLinus Torvalds 	.ctr    = stripe_ctr,
4331da177e4SLinus Torvalds 	.dtr    = stripe_dtr,
4341da177e4SLinus Torvalds 	.map    = stripe_map,
435a25eb944SBrian Wood 	.end_io = stripe_end_io,
4361da177e4SLinus Torvalds 	.status = stripe_status,
437af4874e0SMike Snitzer 	.iterate_devices = stripe_iterate_devices,
43840bea431SMike Snitzer 	.io_hints = stripe_io_hints,
43929915202SMustafa Mesanovic 	.merge  = stripe_merge,
4401da177e4SLinus Torvalds };
4411da177e4SLinus Torvalds 
4421da177e4SLinus Torvalds int __init dm_stripe_init(void)
4431da177e4SLinus Torvalds {
4441da177e4SLinus Torvalds 	int r;
4451da177e4SLinus Torvalds 
4461da177e4SLinus Torvalds 	r = dm_register_target(&stripe_target);
4476edebdeeSHeinz Mauelshagen 	if (r < 0) {
44872d94861SAlasdair G Kergon 		DMWARN("target registration failed");
4496edebdeeSHeinz Mauelshagen 		return r;
4506edebdeeSHeinz Mauelshagen 	}
4511da177e4SLinus Torvalds 
4521da177e4SLinus Torvalds 	return r;
4531da177e4SLinus Torvalds }
4541da177e4SLinus Torvalds 
4551da177e4SLinus Torvalds void dm_stripe_exit(void)
4561da177e4SLinus Torvalds {
45710d3bd09SMikulas Patocka 	dm_unregister_target(&stripe_target);
4581da177e4SLinus Torvalds }
459