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;
  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_requests = stripes;
 164        ti->num_discard_requests = stripes;
 165
 166        sc->chunk_size = chunk_size;
 167        if (chunk_size & (chunk_size - 1))
 168                sc->chunk_size_shift = -1;
 169        else
 170                sc->chunk_size_shift = __ffs(chunk_size);
 171
 172        /*
 173         * Get the stripe destinations.
 174         */
 175        for (i = 0; i < stripes; i++) {
 176                argv += 2;
 177
 178                r = get_stripe(ti, sc, i, argv);
 179                if (r < 0) {
 180                        ti->error = "Couldn't parse stripe destination";
 181                        while (i--)
 182                                dm_put_device(ti, sc->stripe[i].dev);
 183                        kfree(sc);
 184                        return r;
 185                }
 186                atomic_set(&(sc->stripe[i].error_count), 0);
 187        }
 188
 189        ti->private = sc;
 190
 191        return 0;
 192}
 193
 194static void stripe_dtr(struct dm_target *ti)
 195{
 196        unsigned int i;
 197        struct stripe_c *sc = (struct stripe_c *) ti->private;
 198
 199        for (i = 0; i < sc->stripes; i++)
 200                dm_put_device(ti, sc->stripe[i].dev);
 201
 202        flush_work_sync(&sc->trigger_event);
 203        kfree(sc);
 204}
 205
 206static void stripe_map_sector(struct stripe_c *sc, sector_t sector,
 207                              uint32_t *stripe, sector_t *result)
 208{
 209        sector_t chunk = dm_target_offset(sc->ti, sector);
 210        sector_t chunk_offset;
 211
 212        if (sc->chunk_size_shift < 0)
 213                chunk_offset = sector_div(chunk, sc->chunk_size);
 214        else {
 215                chunk_offset = chunk & (sc->chunk_size - 1);
 216                chunk >>= sc->chunk_size_shift;
 217        }
 218
 219        if (sc->stripes_shift < 0)
 220                *stripe = sector_div(chunk, sc->stripes);
 221        else {
 222                *stripe = chunk & (sc->stripes - 1);
 223                chunk >>= sc->stripes_shift;
 224        }
 225
 226        if (sc->chunk_size_shift < 0)
 227                chunk *= sc->chunk_size;
 228        else
 229                chunk <<= sc->chunk_size_shift;
 230
 231        *result = chunk + chunk_offset;
 232}
 233
 234static void stripe_map_range_sector(struct stripe_c *sc, sector_t sector,
 235                                    uint32_t target_stripe, sector_t *result)
 236{
 237        uint32_t stripe;
 238
 239        stripe_map_sector(sc, sector, &stripe, result);
 240        if (stripe == target_stripe)
 241                return;
 242
 243        /* round down */
 244        sector = *result;
 245        if (sc->chunk_size_shift < 0)
 246                *result -= sector_div(sector, sc->chunk_size);
 247        else
 248                *result = sector & ~(sector_t)(sc->chunk_size - 1);
 249
 250        if (target_stripe < stripe)
 251                *result += sc->chunk_size;              /* next chunk */
 252}
 253
 254static int stripe_map_discard(struct stripe_c *sc, struct bio *bio,
 255                              uint32_t target_stripe)
 256{
 257        sector_t begin, end;
 258
 259        stripe_map_range_sector(sc, bio->bi_sector, target_stripe, &begin);
 260        stripe_map_range_sector(sc, bio->bi_sector + bio_sectors(bio),
 261                                target_stripe, &end);
 262        if (begin < end) {
 263                bio->bi_bdev = sc->stripe[target_stripe].dev->bdev;
 264                bio->bi_sector = begin + sc->stripe[target_stripe].physical_start;
 265                bio->bi_size = to_bytes(end - begin);
 266                return DM_MAPIO_REMAPPED;
 267        } else {
 268                /* The range doesn't map to the target stripe */
 269                bio_endio(bio, 0);
 270                return DM_MAPIO_SUBMITTED;
 271        }
 272}
 273
 274static int stripe_map(struct dm_target *ti, struct bio *bio,
 275                      union map_info *map_context)
 276{
 277        struct stripe_c *sc = ti->private;
 278        uint32_t stripe;
 279        unsigned target_request_nr;
 280
 281        if (bio->bi_rw & REQ_FLUSH) {
 282                target_request_nr = map_context->target_request_nr;
 283                BUG_ON(target_request_nr >= sc->stripes);
 284                bio->bi_bdev = sc->stripe[target_request_nr].dev->bdev;
 285                return DM_MAPIO_REMAPPED;
 286        }
 287        if (unlikely(bio->bi_rw & REQ_DISCARD)) {
 288                target_request_nr = map_context->target_request_nr;
 289                BUG_ON(target_request_nr >= sc->stripes);
 290                return stripe_map_discard(sc, bio, target_request_nr);
 291        }
 292
 293        stripe_map_sector(sc, bio->bi_sector, &stripe, &bio->bi_sector);
 294
 295        bio->bi_sector += sc->stripe[stripe].physical_start;
 296        bio->bi_bdev = sc->stripe[stripe].dev->bdev;
 297
 298        return DM_MAPIO_REMAPPED;
 299}
 300
 301/*
 302 * Stripe status:
 303 *
 304 * INFO
 305 * #stripes [stripe_name <stripe_name>] [group word count]
 306 * [error count 'A|D' <error count 'A|D'>]
 307 *
 308 * TABLE
 309 * #stripes [stripe chunk size]
 310 * [stripe_name physical_start <stripe_name physical_start>]
 311 *
 312 */
 313
 314static int stripe_status(struct dm_target *ti, status_type_t type,
 315                         unsigned status_flags, char *result, unsigned maxlen)
 316{
 317        struct stripe_c *sc = (struct stripe_c *) ti->private;
 318        char buffer[sc->stripes + 1];
 319        unsigned int sz = 0;
 320        unsigned int i;
 321
 322        switch (type) {
 323        case STATUSTYPE_INFO:
 324                DMEMIT("%d ", sc->stripes);
 325                for (i = 0; i < sc->stripes; i++)  {
 326                        DMEMIT("%s ", sc->stripe[i].dev->name);
 327                        buffer[i] = atomic_read(&(sc->stripe[i].error_count)) ?
 328                                'D' : 'A';
 329                }
 330                buffer[i] = '\0';
 331                DMEMIT("1 %s", buffer);
 332                break;
 333
 334        case STATUSTYPE_TABLE:
 335                DMEMIT("%d %llu", sc->stripes,
 336                        (unsigned long long)sc->chunk_size);
 337                for (i = 0; i < sc->stripes; i++)
 338                        DMEMIT(" %s %llu", sc->stripe[i].dev->name,
 339                            (unsigned long long)sc->stripe[i].physical_start);
 340                break;
 341        }
 342        return 0;
 343}
 344
 345static int stripe_end_io(struct dm_target *ti, struct bio *bio,
 346                         int error, union map_info *map_context)
 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, 0},
 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.