dm stripe: optimize sector division
[platform/adaptation/renesas_rcar/renesas_kernel.git] / drivers / md / dm-stripe.c
1 /*
2  * Copyright (C) 2001-2003 Sistina Software (UK) Limited.
3  *
4  * This file is released under the GPL.
5  */
6
7 #include <linux/device-mapper.h>
8
9 #include <linux/module.h>
10 #include <linux/init.h>
11 #include <linux/blkdev.h>
12 #include <linux/bio.h>
13 #include <linux/slab.h>
14 #include <linux/log2.h>
15
16 #define DM_MSG_PREFIX "striped"
17 #define DM_IO_ERROR_THRESHOLD 15
18
19 struct stripe {
20         struct dm_dev *dev;
21         sector_t physical_start;
22
23         atomic_t error_count;
24 };
25
26 struct stripe_c {
27         uint32_t stripes;
28         int stripes_shift;
29         sector_t stripes_mask;
30
31         /* The size of this target / num. stripes */
32         sector_t stripe_width;
33
34         /* stripe chunk size */
35         uint32_t chunk_shift;
36         sector_t chunk_mask;
37
38         /* Needed for handling events */
39         struct dm_target *ti;
40
41         /* Work struct used for triggering events*/
42         struct work_struct kstriped_ws;
43
44         struct stripe stripe[0];
45 };
46
47 static struct workqueue_struct *kstriped;
48
49 /*
50  * An event is triggered whenever a drive
51  * drops out of a stripe volume.
52  */
53 static void trigger_event(struct work_struct *work)
54 {
55         struct stripe_c *sc = container_of(work, struct stripe_c, kstriped_ws);
56
57         dm_table_event(sc->ti->table);
58
59 }
60
61 static inline struct stripe_c *alloc_context(unsigned int stripes)
62 {
63         size_t len;
64
65         if (dm_array_too_big(sizeof(struct stripe_c), sizeof(struct stripe),
66                              stripes))
67                 return NULL;
68
69         len = sizeof(struct stripe_c) + (sizeof(struct stripe) * stripes);
70
71         return kmalloc(len, GFP_KERNEL);
72 }
73
74 /*
75  * Parse a single <dev> <sector> pair
76  */
77 static int get_stripe(struct dm_target *ti, struct stripe_c *sc,
78                       unsigned int stripe, char **argv)
79 {
80         unsigned long long start;
81
82         if (sscanf(argv[1], "%llu", &start) != 1)
83                 return -EINVAL;
84
85         if (dm_get_device(ti, argv[0], dm_table_get_mode(ti->table),
86                           &sc->stripe[stripe].dev))
87                 return -ENXIO;
88
89         sc->stripe[stripe].physical_start = start;
90
91         return 0;
92 }
93
94 /*
95  * Construct a striped mapping.
96  * <number of stripes> <chunk size (2^^n)> [<dev_path> <offset>]+
97  */
98 static int stripe_ctr(struct dm_target *ti, unsigned int argc, char **argv)
99 {
100         struct stripe_c *sc;
101         sector_t width;
102         uint32_t stripes;
103         uint32_t chunk_size;
104         char *end;
105         int r;
106         unsigned int i;
107
108         if (argc < 2) {
109                 ti->error = "Not enough arguments";
110                 return -EINVAL;
111         }
112
113         stripes = simple_strtoul(argv[0], &end, 10);
114         if (!stripes || *end) {
115                 ti->error = "Invalid stripe count";
116                 return -EINVAL;
117         }
118
119         chunk_size = simple_strtoul(argv[1], &end, 10);
120         if (*end) {
121                 ti->error = "Invalid chunk_size";
122                 return -EINVAL;
123         }
124
125         /*
126          * chunk_size is a power of two
127          */
128         if (!is_power_of_2(chunk_size) ||
129             (chunk_size < (PAGE_SIZE >> SECTOR_SHIFT))) {
130                 ti->error = "Invalid chunk size";
131                 return -EINVAL;
132         }
133
134         if (ti->len & (chunk_size - 1)) {
135                 ti->error = "Target length not divisible by "
136                     "chunk size";
137                 return -EINVAL;
138         }
139
140         width = ti->len;
141         if (sector_div(width, stripes)) {
142                 ti->error = "Target length not divisible by "
143                     "number of stripes";
144                 return -EINVAL;
145         }
146
147         /*
148          * Do we have enough arguments for that many stripes ?
149          */
150         if (argc != (2 + 2 * stripes)) {
151                 ti->error = "Not enough destinations "
152                         "specified";
153                 return -EINVAL;
154         }
155
156         sc = alloc_context(stripes);
157         if (!sc) {
158                 ti->error = "Memory allocation for striped context "
159                     "failed";
160                 return -ENOMEM;
161         }
162
163         INIT_WORK(&sc->kstriped_ws, trigger_event);
164
165         /* Set pointer to dm target; used in trigger_event */
166         sc->ti = ti;
167         sc->stripes = stripes;
168         sc->stripe_width = width;
169
170         if (stripes & (stripes - 1))
171                 sc->stripes_shift = -1;
172         else {
173                 sc->stripes_shift = ffs(stripes) - 1;
174                 sc->stripes_mask = ((sector_t) stripes) - 1;
175         }
176
177         ti->split_io = chunk_size;
178         ti->num_flush_requests = stripes;
179
180         sc->chunk_shift = ffs(chunk_size) - 1;
181         sc->chunk_mask = ((sector_t) chunk_size) - 1;
182
183         /*
184          * Get the stripe destinations.
185          */
186         for (i = 0; i < stripes; i++) {
187                 argv += 2;
188
189                 r = get_stripe(ti, sc, i, argv);
190                 if (r < 0) {
191                         ti->error = "Couldn't parse stripe destination";
192                         while (i--)
193                                 dm_put_device(ti, sc->stripe[i].dev);
194                         kfree(sc);
195                         return r;
196                 }
197                 atomic_set(&(sc->stripe[i].error_count), 0);
198         }
199
200         ti->private = sc;
201
202         return 0;
203 }
204
205 static void stripe_dtr(struct dm_target *ti)
206 {
207         unsigned int i;
208         struct stripe_c *sc = (struct stripe_c *) ti->private;
209
210         for (i = 0; i < sc->stripes; i++)
211                 dm_put_device(ti, sc->stripe[i].dev);
212
213         flush_workqueue(kstriped);
214         kfree(sc);
215 }
216
217 static void stripe_map_sector(struct stripe_c *sc, sector_t sector,
218                               uint32_t *stripe, sector_t *result)
219 {
220         sector_t offset = dm_target_offset(sc->ti, sector);
221         sector_t chunk = offset >> sc->chunk_shift;
222
223         if (sc->stripes_shift < 0)
224                 *stripe = sector_div(chunk, sc->stripes);
225         else {
226                 *stripe = chunk & sc->stripes_mask;
227                 chunk >>= sc->stripes_shift;
228         }
229
230         *result = (chunk << sc->chunk_shift) | (offset & sc->chunk_mask);
231 }
232
233 static int stripe_map(struct dm_target *ti, struct bio *bio,
234                       union map_info *map_context)
235 {
236         struct stripe_c *sc = ti->private;
237         uint32_t stripe;
238         unsigned target_request_nr;
239
240         if (unlikely(bio_empty_barrier(bio))) {
241                 target_request_nr = map_context->target_request_nr;
242                 BUG_ON(target_request_nr >= sc->stripes);
243                 bio->bi_bdev = sc->stripe[target_request_nr].dev->bdev;
244                 return DM_MAPIO_REMAPPED;
245         }
246
247         stripe_map_sector(sc, bio->bi_sector, &stripe, &bio->bi_sector);
248
249         bio->bi_sector += sc->stripe[stripe].physical_start;
250         bio->bi_bdev = sc->stripe[stripe].dev->bdev;
251
252         return DM_MAPIO_REMAPPED;
253 }
254
255 /*
256  * Stripe status:
257  *
258  * INFO
259  * #stripes [stripe_name <stripe_name>] [group word count]
260  * [error count 'A|D' <error count 'A|D'>]
261  *
262  * TABLE
263  * #stripes [stripe chunk size]
264  * [stripe_name physical_start <stripe_name physical_start>]
265  *
266  */
267
268 static int stripe_status(struct dm_target *ti,
269                          status_type_t type, char *result, unsigned int maxlen)
270 {
271         struct stripe_c *sc = (struct stripe_c *) ti->private;
272         char buffer[sc->stripes + 1];
273         unsigned int sz = 0;
274         unsigned int i;
275
276         switch (type) {
277         case STATUSTYPE_INFO:
278                 DMEMIT("%d ", sc->stripes);
279                 for (i = 0; i < sc->stripes; i++)  {
280                         DMEMIT("%s ", sc->stripe[i].dev->name);
281                         buffer[i] = atomic_read(&(sc->stripe[i].error_count)) ?
282                                 'D' : 'A';
283                 }
284                 buffer[i] = '\0';
285                 DMEMIT("1 %s", buffer);
286                 break;
287
288         case STATUSTYPE_TABLE:
289                 DMEMIT("%d %llu", sc->stripes,
290                         (unsigned long long)sc->chunk_mask + 1);
291                 for (i = 0; i < sc->stripes; i++)
292                         DMEMIT(" %s %llu", sc->stripe[i].dev->name,
293                             (unsigned long long)sc->stripe[i].physical_start);
294                 break;
295         }
296         return 0;
297 }
298
299 static int stripe_end_io(struct dm_target *ti, struct bio *bio,
300                          int error, union map_info *map_context)
301 {
302         unsigned i;
303         char major_minor[16];
304         struct stripe_c *sc = ti->private;
305
306         if (!error)
307                 return 0; /* I/O complete */
308
309         if ((error == -EWOULDBLOCK) && (bio->bi_rw & REQ_RAHEAD))
310                 return error;
311
312         if (error == -EOPNOTSUPP)
313                 return error;
314
315         memset(major_minor, 0, sizeof(major_minor));
316         sprintf(major_minor, "%d:%d",
317                 MAJOR(disk_devt(bio->bi_bdev->bd_disk)),
318                 MINOR(disk_devt(bio->bi_bdev->bd_disk)));
319
320         /*
321          * Test to see which stripe drive triggered the event
322          * and increment error count for all stripes on that device.
323          * If the error count for a given device exceeds the threshold
324          * value we will no longer trigger any further events.
325          */
326         for (i = 0; i < sc->stripes; i++)
327                 if (!strcmp(sc->stripe[i].dev->name, major_minor)) {
328                         atomic_inc(&(sc->stripe[i].error_count));
329                         if (atomic_read(&(sc->stripe[i].error_count)) <
330                             DM_IO_ERROR_THRESHOLD)
331                                 queue_work(kstriped, &sc->kstriped_ws);
332                 }
333
334         return error;
335 }
336
337 static int stripe_iterate_devices(struct dm_target *ti,
338                                   iterate_devices_callout_fn fn, void *data)
339 {
340         struct stripe_c *sc = ti->private;
341         int ret = 0;
342         unsigned i = 0;
343
344         do {
345                 ret = fn(ti, sc->stripe[i].dev,
346                          sc->stripe[i].physical_start,
347                          sc->stripe_width, data);
348         } while (!ret && ++i < sc->stripes);
349
350         return ret;
351 }
352
353 static void stripe_io_hints(struct dm_target *ti,
354                             struct queue_limits *limits)
355 {
356         struct stripe_c *sc = ti->private;
357         unsigned chunk_size = (sc->chunk_mask + 1) << 9;
358
359         blk_limits_io_min(limits, chunk_size);
360         blk_limits_io_opt(limits, chunk_size * sc->stripes);
361 }
362
363 static struct target_type stripe_target = {
364         .name   = "striped",
365         .version = {1, 3, 0},
366         .module = THIS_MODULE,
367         .ctr    = stripe_ctr,
368         .dtr    = stripe_dtr,
369         .map    = stripe_map,
370         .end_io = stripe_end_io,
371         .status = stripe_status,
372         .iterate_devices = stripe_iterate_devices,
373         .io_hints = stripe_io_hints,
374 };
375
376 int __init dm_stripe_init(void)
377 {
378         int r;
379
380         r = dm_register_target(&stripe_target);
381         if (r < 0) {
382                 DMWARN("target registration failed");
383                 return r;
384         }
385
386         kstriped = create_singlethread_workqueue("kstriped");
387         if (!kstriped) {
388                 DMERR("failed to create workqueue kstriped");
389                 dm_unregister_target(&stripe_target);
390                 return -ENOMEM;
391         }
392
393         return r;
394 }
395
396 void dm_stripe_exit(void)
397 {
398         dm_unregister_target(&stripe_target);
399         destroy_workqueue(kstriped);
400
401         return;
402 }