linux/drivers/md/dm-stripe.c
<<
>>
Prefs
   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, tmp_len;
  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, stripes)) {
 120                ti->error = "Target length not divisible by "
 121                    "number of stripes";
 122                return -EINVAL;
 123        }
 124
 125        tmp_len = width;
 126        if (sector_div(tmp_len, chunk_size)) {
 127                ti->error = "Target length not divisible by "
 128                    "chunk size";
 129                return -EINVAL;
 130        }
 131
 132        /*
 133         * Do we have enough arguments for that many stripes ?
 134         */
 135        if (argc != (2 + 2 * stripes)) {
 136                ti->error = "Not enough destinations "
 137                        "specified";
 138                return -EINVAL;
 139        }
 140
 141        sc = alloc_context(stripes);
 142        if (!sc) {
 143                ti->error = "Memory allocation for striped context "
 144                    "failed";
 145                return -ENOMEM;
 146        }
 147
 148        INIT_WORK(&sc->trigger_event, trigger_event);
 149
 150        /* Set pointer to dm target; used in trigger_event */
 151        sc->ti = ti;
 152        sc->stripes = stripes;
 153        sc->stripe_width = width;
 154
 155        if (stripes & (stripes - 1))
 156                sc->stripes_shift = -1;
 157        else
 158                sc->stripes_shift = __ffs(stripes);
 159
 160        r = dm_set_target_max_io_len(ti, chunk_size);
 161        if (r)
 162                return r;
 163
 164        ti->num_flush_bios = stripes;
 165        ti->num_discard_bios = stripes;
 166        ti->num_write_same_bios = stripes;
 167
 168        sc->chunk_size = chunk_size;
 169        if (chunk_size & (chunk_size - 1))
 170                sc->chunk_size_shift = -1;
 171        else
 172                sc->chunk_size_shift = __ffs(chunk_size);
 173
 174        /*
 175         * Get the stripe destinations.
 176         */
 177        for (i = 0; i < stripes; i++) {
 178                argv += 2;
 179
 180                r = get_stripe(ti, sc, i, argv);
 181                if (r < 0) {
 182                        ti->error = "Couldn't parse stripe destination";
 183                        while (i--)
 184                                dm_put_device(ti, sc->stripe[i].dev);
 185                        kfree(sc);
 186                        return r;
 187                }
 188                atomic_set(&(sc->stripe[i].error_count), 0);
 189        }
 190
 191        ti->private = sc;
 192
 193        return 0;
 194}
 195
 196static void stripe_dtr(struct dm_target *ti)
 197{
 198        unsigned int i;
 199        struct stripe_c *sc = (struct stripe_c *) ti->private;
 200
 201        for (i = 0; i < sc->stripes; i++)
 202                dm_put_device(ti, sc->stripe[i].dev);
 203
 204        flush_work(&sc->trigger_event);
 205        kfree(sc);
 206}
 207
 208static void stripe_map_sector(struct stripe_c *sc, sector_t sector,
 209                              uint32_t *stripe, sector_t *result)
 210{
 211        sector_t chunk = dm_target_offset(sc->ti, sector);
 212        sector_t chunk_offset;
 213
 214        if (sc->chunk_size_shift < 0)
 215                chunk_offset = sector_div(chunk, sc->chunk_size);
 216        else {
 217                chunk_offset = chunk & (sc->chunk_size - 1);
 218                chunk >>= sc->chunk_size_shift;
 219        }
 220
 221        if (sc->stripes_shift < 0)
 222                *stripe = sector_div(chunk, sc->stripes);
 223        else {
 224                *stripe = chunk & (sc->stripes - 1);
 225                chunk >>= sc->stripes_shift;
 226        }
 227
 228        if (sc->chunk_size_shift < 0)
 229                chunk *= sc->chunk_size;
 230        else
 231                chunk <<= sc->chunk_size_shift;
 232
 233        *result = chunk + chunk_offset;
 234}
 235
 236static void stripe_map_range_sector(struct stripe_c *sc, sector_t sector,
 237                                    uint32_t target_stripe, sector_t *result)
 238{
 239        uint32_t stripe;
 240
 241        stripe_map_sector(sc, sector, &stripe, result);
 242        if (stripe == target_stripe)
 243                return;
 244
 245        /* round down */
 246        sector = *result;
 247        if (sc->chunk_size_shift < 0)
 248                *result -= sector_div(sector, sc->chunk_size);
 249        else
 250                *result = sector & ~(sector_t)(sc->chunk_size - 1);
 251
 252        if (target_stripe < stripe)
 253                *result += sc->chunk_size;              /* next chunk */
 254}
 255
 256static int stripe_map_range(struct stripe_c *sc, struct bio *bio,
 257                            uint32_t target_stripe)
 258{
 259        sector_t begin, end;
 260
 261        stripe_map_range_sector(sc, bio->bi_sector, target_stripe, &begin);
 262        stripe_map_range_sector(sc, bio_end_sector(bio),
 263                                target_stripe, &end);
 264        if (begin < end) {
 265                bio->bi_bdev = sc->stripe[target_stripe].dev->bdev;
 266                bio->bi_sector = begin + sc->stripe[target_stripe].physical_start;
 267                bio->bi_size = to_bytes(end - begin);
 268                return DM_MAPIO_REMAPPED;
 269        } else {
 270                /* The range doesn't map to the target stripe */
 271                bio_endio(bio, 0);
 272                return DM_MAPIO_SUBMITTED;
 273        }
 274}
 275
 276static int stripe_map(struct dm_target *ti, struct bio *bio)
 277{
 278        struct stripe_c *sc = ti->private;
 279        uint32_t stripe;
 280        unsigned target_bio_nr;
 281
 282        if (bio->bi_rw & REQ_FLUSH) {
 283                target_bio_nr = dm_bio_get_target_bio_nr(bio);
 284                BUG_ON(target_bio_nr >= sc->stripes);
 285                bio->bi_bdev = sc->stripe[target_bio_nr].dev->bdev;
 286                return DM_MAPIO_REMAPPED;
 287        }
 288        if (unlikely(bio->bi_rw & REQ_DISCARD) ||
 289            unlikely(bio->bi_rw & REQ_WRITE_SAME)) {
 290                target_bio_nr = dm_bio_get_target_bio_nr(bio);
 291                BUG_ON(target_bio_nr >= sc->stripes);
 292                return stripe_map_range(sc, bio, target_bio_nr);
 293        }
 294
 295        stripe_map_sector(sc, bio->bi_sector, &stripe, &bio->bi_sector);
 296
 297        bio->bi_sector += sc->stripe[stripe].physical_start;
 298        bio->bi_bdev = sc->stripe[stripe].dev->bdev;
 299
 300        return DM_MAPIO_REMAPPED;
 301}
 302
 303/*
 304 * Stripe status:
 305 *
 306 * INFO
 307 * #stripes [stripe_name <stripe_name>] [group word count]
 308 * [error count 'A|D' <error count 'A|D'>]
 309 *
 310 * TABLE
 311 * #stripes [stripe chunk size]
 312 * [stripe_name physical_start <stripe_name physical_start>]
 313 *
 314 */
 315
 316static void stripe_status(struct dm_target *ti, status_type_t type,
 317                          unsigned status_flags, char *result, unsigned maxlen)
 318{
 319        struct stripe_c *sc = (struct stripe_c *) ti->private;
 320        char buffer[sc->stripes + 1];
 321        unsigned int sz = 0;
 322        unsigned int i;
 323
 324        switch (type) {
 325        case STATUSTYPE_INFO:
 326                DMEMIT("%d ", sc->stripes);
 327                for (i = 0; i < sc->stripes; i++)  {
 328                        DMEMIT("%s ", sc->stripe[i].dev->name);
 329                        buffer[i] = atomic_read(&(sc->stripe[i].error_count)) ?
 330                                'D' : 'A';
 331                }
 332                buffer[i] = '\0';
 333                DMEMIT("1 %s", buffer);
 334                break;
 335
 336        case STATUSTYPE_TABLE:
 337                DMEMIT("%d %llu", sc->stripes,
 338                        (unsigned long long)sc->chunk_size);
 339                for (i = 0; i < sc->stripes; i++)
 340                        DMEMIT(" %s %llu", sc->stripe[i].dev->name,
 341                            (unsigned long long)sc->stripe[i].physical_start);
 342                break;
 343        }
 344}
 345
 346static int stripe_end_io(struct dm_target *ti, struct bio *bio, int error)
 347{
 348        unsigned i;
 349        char major_minor[16];
 350        struct stripe_c *sc = ti->private;
 351
 352        if (!error)
 353                return 0; /* I/O complete */
 354
 355        if ((error == -EWOULDBLOCK) && (bio->bi_rw & REQ_RAHEAD))
 356                return error;
 357
 358        if (error == -EOPNOTSUPP)
 359                return error;
 360
 361        memset(major_minor, 0, sizeof(major_minor));
 362        sprintf(major_minor, "%d:%d",
 363                MAJOR(disk_devt(bio->bi_bdev->bd_disk)),
 364                MINOR(disk_devt(bio->bi_bdev->bd_disk)));
 365
 366        /*
 367         * Test to see which stripe drive triggered the event
 368         * and increment error count for all stripes on that device.
 369         * If the error count for a given device exceeds the threshold
 370         * value we will no longer trigger any further events.
 371         */
 372        for (i = 0; i < sc->stripes; i++)
 373                if (!strcmp(sc->stripe[i].dev->name, major_minor)) {
 374                        atomic_inc(&(sc->stripe[i].error_count));
 375                        if (atomic_read(&(sc->stripe[i].error_count)) <
 376                            DM_IO_ERROR_THRESHOLD)
 377                                schedule_work(&sc->trigger_event);
 378                }
 379
 380        return error;
 381}
 382
 383static int stripe_iterate_devices(struct dm_target *ti,
 384                                  iterate_devices_callout_fn fn, void *data)
 385{
 386        struct stripe_c *sc = ti->private;
 387        int ret = 0;
 388        unsigned i = 0;
 389
 390        do {
 391                ret = fn(ti, sc->stripe[i].dev,
 392                         sc->stripe[i].physical_start,
 393                         sc->stripe_width, data);
 394        } while (!ret && ++i < sc->stripes);
 395
 396        return ret;
 397}
 398
 399static void stripe_io_hints(struct dm_target *ti,
 400                            struct queue_limits *limits)
 401{
 402        struct stripe_c *sc = ti->private;
 403        unsigned chunk_size = sc->chunk_size << SECTOR_SHIFT;
 404
 405        blk_limits_io_min(limits, chunk_size);
 406        blk_limits_io_opt(limits, chunk_size * sc->stripes);
 407}
 408
 409static int stripe_merge(struct dm_target *ti, struct bvec_merge_data *bvm,
 410                        struct bio_vec *biovec, int max_size)
 411{
 412        struct stripe_c *sc = ti->private;
 413        sector_t bvm_sector = bvm->bi_sector;
 414        uint32_t stripe;
 415        struct request_queue *q;
 416
 417        stripe_map_sector(sc, bvm_sector, &stripe, &bvm_sector);
 418
 419        q = bdev_get_queue(sc->stripe[stripe].dev->bdev);
 420        if (!q->merge_bvec_fn)
 421                return max_size;
 422
 423        bvm->bi_bdev = sc->stripe[stripe].dev->bdev;
 424        bvm->bi_sector = sc->stripe[stripe].physical_start + bvm_sector;
 425
 426        return min(max_size, q->merge_bvec_fn(q, bvm, biovec));
 427}
 428
 429static struct target_type stripe_target = {
 430        .name   = "striped",
 431        .version = {1, 5, 1},
 432        .module = THIS_MODULE,
 433        .ctr    = stripe_ctr,
 434        .dtr    = stripe_dtr,
 435        .map    = stripe_map,
 436        .end_io = stripe_end_io,
 437        .status = stripe_status,
 438        .iterate_devices = stripe_iterate_devices,
 439        .io_hints = stripe_io_hints,
 440        .merge  = stripe_merge,
 441};
 442
 443int __init dm_stripe_init(void)
 444{
 445        int r;
 446
 447        r = dm_register_target(&stripe_target);
 448        if (r < 0) {
 449                DMWARN("target registration failed");
 450                return r;
 451        }
 452
 453        return r;
 454}
 455
 456void dm_stripe_exit(void)
 457{
 458        dm_unregister_target(&stripe_target);
 459}
 460
lxr.linux.no kindly hosted by Redpill Linpro AS, provider of Linux consulting and operations services since 1995.