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