Root/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
19struct stripe {
20    struct dm_dev *dev;
21    sector_t physical_start;
22
23    atomic_t error_count;
24};
25
26struct stripe_c {
27    uint32_t stripes;
28    int stripes_shift;
29
30    /* The size of this target / num. stripes */
31    sector_t stripe_width;
32
33    uint32_t chunk_size;
34    int chunk_size_shift;
35
36    /* Needed for handling events */
37    struct dm_target *ti;
38
39    /* Work struct used for triggering events*/
40    struct work_struct trigger_event;
41
42    struct stripe stripe[0];
43};
44
45/*
46 * An event is triggered whenever a drive
47 * drops out of a stripe volume.
48 */
49static void trigger_event(struct work_struct *work)
50{
51    struct stripe_c *sc = container_of(work, struct stripe_c,
52                       trigger_event);
53    dm_table_event(sc->ti->table);
54}
55
56static inline struct stripe_c *alloc_context(unsigned int stripes)
57{
58    size_t len;
59
60    if (dm_array_too_big(sizeof(struct stripe_c), sizeof(struct stripe),
61                 stripes))
62        return NULL;
63
64    len = sizeof(struct stripe_c) + (sizeof(struct stripe) * stripes);
65
66    return kmalloc(len, GFP_KERNEL);
67}
68
69/*
70 * Parse a single <dev> <sector> pair
71 */
72static int get_stripe(struct dm_target *ti, struct stripe_c *sc,
73              unsigned int stripe, char **argv)
74{
75    unsigned long long start;
76    char dummy;
77
78    if (sscanf(argv[1], "%llu%c", &start, &dummy) != 1)
79        return -EINVAL;
80
81    if (dm_get_device(ti, argv[0], dm_table_get_mode(ti->table),
82              &sc->stripe[stripe].dev))
83        return -ENXIO;
84
85    sc->stripe[stripe].physical_start = start;
86
87    return 0;
88}
89
90/*
91 * Construct a striped mapping.
92 * <number of stripes> <chunk size> [<dev_path> <offset>]+
93 */
94static int stripe_ctr(struct dm_target *ti, unsigned int argc, char **argv)
95{
96    struct stripe_c *sc;
97    sector_t width;
98    uint32_t stripes;
99    uint32_t chunk_size;
100    int r;
101    unsigned int i;
102
103    if (argc < 2) {
104        ti->error = "Not enough arguments";
105        return -EINVAL;
106    }
107
108    if (kstrtouint(argv[0], 10, &stripes) || !stripes) {
109        ti->error = "Invalid stripe count";
110        return -EINVAL;
111    }
112
113    if (kstrtouint(argv[1], 10, &chunk_size) || !chunk_size) {
114        ti->error = "Invalid chunk_size";
115        return -EINVAL;
116    }
117
118    width = ti->len;
119    if (sector_div(width, chunk_size)) {
120        ti->error = "Target length not divisible by "
121            "chunk size";
122        return -EINVAL;
123    }
124
125    if (sector_div(width, stripes)) {
126        ti->error = "Target length not divisible by "
127            "number of stripes";
128        return -EINVAL;
129    }
130
131    /*
132     * Do we have enough arguments for that many stripes ?
133     */
134    if (argc != (2 + 2 * stripes)) {
135        ti->error = "Not enough destinations "
136            "specified";
137        return -EINVAL;
138    }
139
140    sc = alloc_context(stripes);
141    if (!sc) {
142        ti->error = "Memory allocation for striped context "
143            "failed";
144        return -ENOMEM;
145    }
146
147    INIT_WORK(&sc->trigger_event, trigger_event);
148
149    /* Set pointer to dm target; used in trigger_event */
150    sc->ti = ti;
151    sc->stripes = stripes;
152    sc->stripe_width = width;
153
154    if (stripes & (stripes - 1))
155        sc->stripes_shift = -1;
156    else
157        sc->stripes_shift = __ffs(stripes);
158
159    r = dm_set_target_max_io_len(ti, chunk_size);
160    if (r)
161        return r;
162
163    ti->num_flush_bios = stripes;
164    ti->num_discard_bios = stripes;
165    ti->num_write_same_bios = stripes;
166
167    sc->chunk_size = chunk_size;
168    if (chunk_size & (chunk_size - 1))
169        sc->chunk_size_shift = -1;
170    else
171        sc->chunk_size_shift = __ffs(chunk_size);
172
173    /*
174     * Get the stripe destinations.
175     */
176    for (i = 0; i < stripes; i++) {
177        argv += 2;
178
179        r = get_stripe(ti, sc, i, argv);
180        if (r < 0) {
181            ti->error = "Couldn't parse stripe destination";
182            while (i--)
183                dm_put_device(ti, sc->stripe[i].dev);
184            kfree(sc);
185            return r;
186        }
187        atomic_set(&(sc->stripe[i].error_count), 0);
188    }
189
190    ti->private = sc;
191
192    return 0;
193}
194
195static void stripe_dtr(struct dm_target *ti)
196{
197    unsigned int i;
198    struct stripe_c *sc = (struct stripe_c *) ti->private;
199
200    for (i = 0; i < sc->stripes; i++)
201        dm_put_device(ti, sc->stripe[i].dev);
202
203    flush_work(&sc->trigger_event);
204    kfree(sc);
205}
206
207static void stripe_map_sector(struct stripe_c *sc, sector_t sector,
208                  uint32_t *stripe, sector_t *result)
209{
210    sector_t chunk = dm_target_offset(sc->ti, sector);
211    sector_t chunk_offset;
212
213    if (sc->chunk_size_shift < 0)
214        chunk_offset = sector_div(chunk, sc->chunk_size);
215    else {
216        chunk_offset = chunk & (sc->chunk_size - 1);
217        chunk >>= sc->chunk_size_shift;
218    }
219
220    if (sc->stripes_shift < 0)
221        *stripe = sector_div(chunk, sc->stripes);
222    else {
223        *stripe = chunk & (sc->stripes - 1);
224        chunk >>= sc->stripes_shift;
225    }
226
227    if (sc->chunk_size_shift < 0)
228        chunk *= sc->chunk_size;
229    else
230        chunk <<= sc->chunk_size_shift;
231
232    *result = chunk + chunk_offset;
233}
234
235static void stripe_map_range_sector(struct stripe_c *sc, sector_t sector,
236                    uint32_t target_stripe, sector_t *result)
237{
238    uint32_t stripe;
239
240    stripe_map_sector(sc, sector, &stripe, result);
241    if (stripe == target_stripe)
242        return;
243
244    /* round down */
245    sector = *result;
246    if (sc->chunk_size_shift < 0)
247        *result -= sector_div(sector, sc->chunk_size);
248    else
249        *result = sector & ~(sector_t)(sc->chunk_size - 1);
250
251    if (target_stripe < stripe)
252        *result += sc->chunk_size; /* next chunk */
253}
254
255static int stripe_map_range(struct stripe_c *sc, struct bio *bio,
256                uint32_t target_stripe)
257{
258    sector_t begin, end;
259
260    stripe_map_range_sector(sc, bio->bi_sector, target_stripe, &begin);
261    stripe_map_range_sector(sc, bio->bi_sector + bio_sectors(bio),
262                target_stripe, &end);
263    if (begin < end) {
264        bio->bi_bdev = sc->stripe[target_stripe].dev->bdev;
265        bio->bi_sector = begin + sc->stripe[target_stripe].physical_start;
266        bio->bi_size = to_bytes(end - begin);
267        return DM_MAPIO_REMAPPED;
268    } else {
269        /* The range doesn't map to the target stripe */
270        bio_endio(bio, 0);
271        return DM_MAPIO_SUBMITTED;
272    }
273}
274
275static int stripe_map(struct dm_target *ti, struct bio *bio)
276{
277    struct stripe_c *sc = ti->private;
278    uint32_t stripe;
279    unsigned target_bio_nr;
280
281    if (bio->bi_rw & REQ_FLUSH) {
282        target_bio_nr = dm_bio_get_target_bio_nr(bio);
283        BUG_ON(target_bio_nr >= sc->stripes);
284        bio->bi_bdev = sc->stripe[target_bio_nr].dev->bdev;
285        return DM_MAPIO_REMAPPED;
286    }
287    if (unlikely(bio->bi_rw & REQ_DISCARD) ||
288        unlikely(bio->bi_rw & REQ_WRITE_SAME)) {
289        target_bio_nr = dm_bio_get_target_bio_nr(bio);
290        BUG_ON(target_bio_nr >= sc->stripes);
291        return stripe_map_range(sc, bio, target_bio_nr);
292    }
293
294    stripe_map_sector(sc, bio->bi_sector, &stripe, &bio->bi_sector);
295
296    bio->bi_sector += sc->stripe[stripe].physical_start;
297    bio->bi_bdev = sc->stripe[stripe].dev->bdev;
298
299    return DM_MAPIO_REMAPPED;
300}
301
302/*
303 * Stripe status:
304 *
305 * INFO
306 * #stripes [stripe_name <stripe_name>] [group word count]
307 * [error count 'A|D' <error count 'A|D'>]
308 *
309 * TABLE
310 * #stripes [stripe chunk size]
311 * [stripe_name physical_start <stripe_name physical_start>]
312 *
313 */
314
315static void stripe_status(struct dm_target *ti, status_type_t type,
316              unsigned status_flags, char *result, unsigned maxlen)
317{
318    struct stripe_c *sc = (struct stripe_c *) ti->private;
319    char buffer[sc->stripes + 1];
320    unsigned int sz = 0;
321    unsigned int i;
322
323    switch (type) {
324    case STATUSTYPE_INFO:
325        DMEMIT("%d ", sc->stripes);
326        for (i = 0; i < sc->stripes; i++) {
327            DMEMIT("%s ", sc->stripe[i].dev->name);
328            buffer[i] = atomic_read(&(sc->stripe[i].error_count)) ?
329                'D' : 'A';
330        }
331        buffer[i] = '\0';
332        DMEMIT("1 %s", buffer);
333        break;
334
335    case STATUSTYPE_TABLE:
336        DMEMIT("%d %llu", sc->stripes,
337            (unsigned long long)sc->chunk_size);
338        for (i = 0; i < sc->stripes; i++)
339            DMEMIT(" %s %llu", sc->stripe[i].dev->name,
340                (unsigned long long)sc->stripe[i].physical_start);
341        break;
342    }
343}
344
345static int stripe_end_io(struct dm_target *ti, struct bio *bio, int error)
346{
347    unsigned i;
348    char major_minor[16];
349    struct stripe_c *sc = ti->private;
350
351    if (!error)
352        return 0; /* I/O complete */
353
354    if ((error == -EWOULDBLOCK) && (bio->bi_rw & REQ_RAHEAD))
355        return error;
356
357    if (error == -EOPNOTSUPP)
358        return error;
359
360    memset(major_minor, 0, sizeof(major_minor));
361    sprintf(major_minor, "%d:%d",
362        MAJOR(disk_devt(bio->bi_bdev->bd_disk)),
363        MINOR(disk_devt(bio->bi_bdev->bd_disk)));
364
365    /*
366     * Test to see which stripe drive triggered the event
367     * and increment error count for all stripes on that device.
368     * If the error count for a given device exceeds the threshold
369     * value we will no longer trigger any further events.
370     */
371    for (i = 0; i < sc->stripes; i++)
372        if (!strcmp(sc->stripe[i].dev->name, major_minor)) {
373            atomic_inc(&(sc->stripe[i].error_count));
374            if (atomic_read(&(sc->stripe[i].error_count)) <
375                DM_IO_ERROR_THRESHOLD)
376                schedule_work(&sc->trigger_event);
377        }
378
379    return error;
380}
381
382static int stripe_iterate_devices(struct dm_target *ti,
383                  iterate_devices_callout_fn fn, void *data)
384{
385    struct stripe_c *sc = ti->private;
386    int ret = 0;
387    unsigned i = 0;
388
389    do {
390        ret = fn(ti, sc->stripe[i].dev,
391             sc->stripe[i].physical_start,
392             sc->stripe_width, data);
393    } while (!ret && ++i < sc->stripes);
394
395    return ret;
396}
397
398static void stripe_io_hints(struct dm_target *ti,
399                struct queue_limits *limits)
400{
401    struct stripe_c *sc = ti->private;
402    unsigned chunk_size = sc->chunk_size << SECTOR_SHIFT;
403
404    blk_limits_io_min(limits, chunk_size);
405    blk_limits_io_opt(limits, chunk_size * sc->stripes);
406}
407
408static int stripe_merge(struct dm_target *ti, struct bvec_merge_data *bvm,
409            struct bio_vec *biovec, int max_size)
410{
411    struct stripe_c *sc = ti->private;
412    sector_t bvm_sector = bvm->bi_sector;
413    uint32_t stripe;
414    struct request_queue *q;
415
416    stripe_map_sector(sc, bvm_sector, &stripe, &bvm_sector);
417
418    q = bdev_get_queue(sc->stripe[stripe].dev->bdev);
419    if (!q->merge_bvec_fn)
420        return max_size;
421
422    bvm->bi_bdev = sc->stripe[stripe].dev->bdev;
423    bvm->bi_sector = sc->stripe[stripe].physical_start + bvm_sector;
424
425    return min(max_size, q->merge_bvec_fn(q, bvm, biovec));
426}
427
428static struct target_type stripe_target = {
429    .name = "striped",
430    .version = {1, 5, 1},
431    .module = THIS_MODULE,
432    .ctr = stripe_ctr,
433    .dtr = stripe_dtr,
434    .map = stripe_map,
435    .end_io = stripe_end_io,
436    .status = stripe_status,
437    .iterate_devices = stripe_iterate_devices,
438    .io_hints = stripe_io_hints,
439    .merge = stripe_merge,
440};
441
442int __init dm_stripe_init(void)
443{
444    int r;
445
446    r = dm_register_target(&stripe_target);
447    if (r < 0) {
448        DMWARN("target registration failed");
449        return r;
450    }
451
452    return r;
453}
454
455void dm_stripe_exit(void)
456{
457    dm_unregister_target(&stripe_target);
458}
459

Archive Download this file



interactive