linux/drivers/md/dm-log.c
<<
>>
Prefs
   1/*
   2 * Copyright (C) 2003 Sistina Software
   3 * Copyright (C) 2004-2008 Red Hat, Inc. All rights reserved.
   4 *
   5 * This file is released under the LGPL.
   6 */
   7
   8#include <linux/init.h>
   9#include <linux/slab.h>
  10#include <linux/module.h>
  11#include <linux/vmalloc.h>
  12#include <linux/dm-io.h>
  13#include <linux/dm-dirty-log.h>
  14
  15#include <linux/device-mapper.h>
  16
  17#define DM_MSG_PREFIX "dirty region log"
  18
  19static LIST_HEAD(_log_types);
  20static DEFINE_SPINLOCK(_lock);
  21
  22static struct dm_dirty_log_type *__find_dirty_log_type(const char *name)
  23{
  24        struct dm_dirty_log_type *log_type;
  25
  26        list_for_each_entry(log_type, &_log_types, list)
  27                if (!strcmp(name, log_type->name))
  28                        return log_type;
  29
  30        return NULL;
  31}
  32
  33static struct dm_dirty_log_type *_get_dirty_log_type(const char *name)
  34{
  35        struct dm_dirty_log_type *log_type;
  36
  37        spin_lock(&_lock);
  38
  39        log_type = __find_dirty_log_type(name);
  40        if (log_type && !try_module_get(log_type->module))
  41                log_type = NULL;
  42
  43        spin_unlock(&_lock);
  44
  45        return log_type;
  46}
  47
  48/*
  49 * get_type
  50 * @type_name
  51 *
  52 * Attempt to retrieve the dm_dirty_log_type by name.  If not already
  53 * available, attempt to load the appropriate module.
  54 *
  55 * Log modules are named "dm-log-" followed by the 'type_name'.
  56 * Modules may contain multiple types.
  57 * This function will first try the module "dm-log-<type_name>",
  58 * then truncate 'type_name' on the last '-' and try again.
  59 *
  60 * For example, if type_name was "clustered-disk", it would search
  61 * 'dm-log-clustered-disk' then 'dm-log-clustered'.
  62 *
  63 * Returns: dirty_log_type* on success, NULL on failure
  64 */
  65static struct dm_dirty_log_type *get_type(const char *type_name)
  66{
  67        char *p, *type_name_dup;
  68        struct dm_dirty_log_type *log_type;
  69
  70        if (!type_name)
  71                return NULL;
  72
  73        log_type = _get_dirty_log_type(type_name);
  74        if (log_type)
  75                return log_type;
  76
  77        type_name_dup = kstrdup(type_name, GFP_KERNEL);
  78        if (!type_name_dup) {
  79                DMWARN("No memory left to attempt log module load for \"%s\"",
  80                       type_name);
  81                return NULL;
  82        }
  83
  84        while (request_module("dm-log-%s", type_name_dup) ||
  85               !(log_type = _get_dirty_log_type(type_name))) {
  86                p = strrchr(type_name_dup, '-');
  87                if (!p)
  88                        break;
  89                p[0] = '\0';
  90        }
  91
  92        if (!log_type)
  93                DMWARN("Module for logging type \"%s\" not found.", type_name);
  94
  95        kfree(type_name_dup);
  96
  97        return log_type;
  98}
  99
 100static void put_type(struct dm_dirty_log_type *type)
 101{
 102        if (!type)
 103                return;
 104
 105        spin_lock(&_lock);
 106        if (!__find_dirty_log_type(type->name))
 107                goto out;
 108
 109        module_put(type->module);
 110
 111out:
 112        spin_unlock(&_lock);
 113}
 114
 115int dm_dirty_log_type_register(struct dm_dirty_log_type *type)
 116{
 117        int r = 0;
 118
 119        spin_lock(&_lock);
 120        if (!__find_dirty_log_type(type->name))
 121                list_add(&type->list, &_log_types);
 122        else
 123                r = -EEXIST;
 124        spin_unlock(&_lock);
 125
 126        return r;
 127}
 128EXPORT_SYMBOL(dm_dirty_log_type_register);
 129
 130int dm_dirty_log_type_unregister(struct dm_dirty_log_type *type)
 131{
 132        spin_lock(&_lock);
 133
 134        if (!__find_dirty_log_type(type->name)) {
 135                spin_unlock(&_lock);
 136                return -EINVAL;
 137        }
 138
 139        list_del(&type->list);
 140
 141        spin_unlock(&_lock);
 142
 143        return 0;
 144}
 145EXPORT_SYMBOL(dm_dirty_log_type_unregister);
 146
 147struct dm_dirty_log *dm_dirty_log_create(const char *type_name,
 148                                         struct dm_target *ti,
 149                                         unsigned int argc, char **argv)
 150{
 151        struct dm_dirty_log_type *type;
 152        struct dm_dirty_log *log;
 153
 154        log = kmalloc(sizeof(*log), GFP_KERNEL);
 155        if (!log)
 156                return NULL;
 157
 158        type = get_type(type_name);
 159        if (!type) {
 160                kfree(log);
 161                return NULL;
 162        }
 163
 164        log->type = type;
 165        if (type->ctr(log, ti, argc, argv)) {
 166                kfree(log);
 167                put_type(type);
 168                return NULL;
 169        }
 170
 171        return log;
 172}
 173EXPORT_SYMBOL(dm_dirty_log_create);
 174
 175void dm_dirty_log_destroy(struct dm_dirty_log *log)
 176{
 177        log->type->dtr(log);
 178        put_type(log->type);
 179        kfree(log);
 180}
 181EXPORT_SYMBOL(dm_dirty_log_destroy);
 182
 183/*-----------------------------------------------------------------
 184 * Persistent and core logs share a lot of their implementation.
 185 * FIXME: need a reload method to be called from a resume
 186 *---------------------------------------------------------------*/
 187/*
 188 * Magic for persistent mirrors: "MiRr"
 189 */
 190#define MIRROR_MAGIC 0x4D695272
 191
 192/*
 193 * The on-disk version of the metadata.
 194 */
 195#define MIRROR_DISK_VERSION 2
 196#define LOG_OFFSET 2
 197
 198struct log_header {
 199        uint32_t magic;
 200
 201        /*
 202         * Simple, incrementing version. no backward
 203         * compatibility.
 204         */
 205        uint32_t version;
 206        sector_t nr_regions;
 207};
 208
 209struct log_c {
 210        struct dm_target *ti;
 211        int touched;
 212        uint32_t region_size;
 213        unsigned int region_count;
 214        region_t sync_count;
 215
 216        unsigned bitset_uint32_count;
 217        uint32_t *clean_bits;
 218        uint32_t *sync_bits;
 219        uint32_t *recovering_bits;      /* FIXME: this seems excessive */
 220
 221        int sync_search;
 222
 223        /* Resync flag */
 224        enum sync {
 225                DEFAULTSYNC,    /* Synchronize if necessary */
 226                NOSYNC,         /* Devices known to be already in sync */
 227                FORCESYNC,      /* Force a sync to happen */
 228        } sync;
 229
 230        struct dm_io_request io_req;
 231
 232        /*
 233         * Disk log fields
 234         */
 235        int log_dev_failed;
 236        struct dm_dev *log_dev;
 237        struct log_header header;
 238
 239        struct dm_io_region header_location;
 240        struct log_header *disk_header;
 241};
 242
 243/*
 244 * The touched member needs to be updated every time we access
 245 * one of the bitsets.
 246 */
 247static inline int log_test_bit(uint32_t *bs, unsigned bit)
 248{
 249        return ext2_test_bit(bit, (unsigned long *) bs) ? 1 : 0;
 250}
 251
 252static inline void log_set_bit(struct log_c *l,
 253                               uint32_t *bs, unsigned bit)
 254{
 255        ext2_set_bit(bit, (unsigned long *) bs);
 256        l->touched = 1;
 257}
 258
 259static inline void log_clear_bit(struct log_c *l,
 260                                 uint32_t *bs, unsigned bit)
 261{
 262        ext2_clear_bit(bit, (unsigned long *) bs);
 263        l->touched = 1;
 264}
 265
 266/*----------------------------------------------------------------
 267 * Header IO
 268 *--------------------------------------------------------------*/
 269static void header_to_disk(struct log_header *core, struct log_header *disk)
 270{
 271        disk->magic = cpu_to_le32(core->magic);
 272        disk->version = cpu_to_le32(core->version);
 273        disk->nr_regions = cpu_to_le64(core->nr_regions);
 274}
 275
 276static void header_from_disk(struct log_header *core, struct log_header *disk)
 277{
 278        core->magic = le32_to_cpu(disk->magic);
 279        core->version = le32_to_cpu(disk->version);
 280        core->nr_regions = le64_to_cpu(disk->nr_regions);
 281}
 282
 283static int rw_header(struct log_c *lc, int rw)
 284{
 285        lc->io_req.bi_rw = rw;
 286
 287        return dm_io(&lc->io_req, 1, &lc->header_location, NULL);
 288}
 289
 290static int read_header(struct log_c *log)
 291{
 292        int r;
 293
 294        r = rw_header(log, READ);
 295        if (r)
 296                return r;
 297
 298        header_from_disk(&log->header, log->disk_header);
 299
 300        /* New log required? */
 301        if (log->sync != DEFAULTSYNC || log->header.magic != MIRROR_MAGIC) {
 302                log->header.magic = MIRROR_MAGIC;
 303                log->header.version = MIRROR_DISK_VERSION;
 304                log->header.nr_regions = 0;
 305        }
 306
 307#ifdef __LITTLE_ENDIAN
 308        if (log->header.version == 1)
 309                log->header.version = 2;
 310#endif
 311
 312        if (log->header.version != MIRROR_DISK_VERSION) {
 313                DMWARN("incompatible disk log version");
 314                return -EINVAL;
 315        }
 316
 317        return 0;
 318}
 319
 320static int _check_region_size(struct dm_target *ti, uint32_t region_size)
 321{
 322        if (region_size < 2 || region_size > ti->len)
 323                return 0;
 324
 325        if (!is_power_of_2(region_size))
 326                return 0;
 327
 328        return 1;
 329}
 330
 331/*----------------------------------------------------------------
 332 * core log constructor/destructor
 333 *
 334 * argv contains region_size followed optionally by [no]sync
 335 *--------------------------------------------------------------*/
 336#define BYTE_SHIFT 3
 337static int create_log_context(struct dm_dirty_log *log, struct dm_target *ti,
 338                              unsigned int argc, char **argv,
 339                              struct dm_dev *dev)
 340{
 341        enum sync sync = DEFAULTSYNC;
 342
 343        struct log_c *lc;
 344        uint32_t region_size;
 345        unsigned int region_count;
 346        size_t bitset_size, buf_size;
 347        int r;
 348
 349        if (argc < 1 || argc > 2) {
 350                DMWARN("wrong number of arguments to dirty region log");
 351                return -EINVAL;
 352        }
 353
 354        if (argc > 1) {
 355                if (!strcmp(argv[1], "sync"))
 356                        sync = FORCESYNC;
 357                else if (!strcmp(argv[1], "nosync"))
 358                        sync = NOSYNC;
 359                else {
 360                        DMWARN("unrecognised sync argument to "
 361                               "dirty region log: %s", argv[1]);
 362                        return -EINVAL;
 363                }
 364        }
 365
 366        if (sscanf(argv[0], "%u", &region_size) != 1 ||
 367            !_check_region_size(ti, region_size)) {
 368                DMWARN("invalid region size %s", argv[0]);
 369                return -EINVAL;
 370        }
 371
 372        region_count = dm_sector_div_up(ti->len, region_size);
 373
 374        lc = kmalloc(sizeof(*lc), GFP_KERNEL);
 375        if (!lc) {
 376                DMWARN("couldn't allocate core log");
 377                return -ENOMEM;
 378        }
 379
 380        lc->ti = ti;
 381        lc->touched = 0;
 382        lc->region_size = region_size;
 383        lc->region_count = region_count;
 384        lc->sync = sync;
 385
 386        /*
 387         * Work out how many "unsigned long"s we need to hold the bitset.
 388         */
 389        bitset_size = dm_round_up(region_count,
 390                                  sizeof(*lc->clean_bits) << BYTE_SHIFT);
 391        bitset_size >>= BYTE_SHIFT;
 392
 393        lc->bitset_uint32_count = bitset_size / sizeof(*lc->clean_bits);
 394
 395        /*
 396         * Disk log?
 397         */
 398        if (!dev) {
 399                lc->clean_bits = vmalloc(bitset_size);
 400                if (!lc->clean_bits) {
 401                        DMWARN("couldn't allocate clean bitset");
 402                        kfree(lc);
 403                        return -ENOMEM;
 404                }
 405                lc->disk_header = NULL;
 406        } else {
 407                lc->log_dev = dev;
 408                lc->log_dev_failed = 0;
 409                lc->header_location.bdev = lc->log_dev->bdev;
 410                lc->header_location.sector = 0;
 411
 412                /*
 413                 * Buffer holds both header and bitset.
 414                 */
 415                buf_size =
 416                    dm_round_up((LOG_OFFSET << SECTOR_SHIFT) + bitset_size,
 417                                bdev_logical_block_size(lc->header_location.
 418                                                            bdev));
 419
 420                if (buf_size > i_size_read(dev->bdev->bd_inode)) {
 421                        DMWARN("log device %s too small: need %llu bytes",
 422                                dev->name, (unsigned long long)buf_size);
 423                        kfree(lc);
 424                        return -EINVAL;
 425                }
 426
 427                lc->header_location.count = buf_size >> SECTOR_SHIFT;
 428
 429                lc->io_req.mem.type = DM_IO_VMA;
 430                lc->io_req.notify.fn = NULL;
 431                lc->io_req.client = dm_io_client_create(dm_div_up(buf_size,
 432                                                                   PAGE_SIZE));
 433                if (IS_ERR(lc->io_req.client)) {
 434                        r = PTR_ERR(lc->io_req.client);
 435                        DMWARN("couldn't allocate disk io client");
 436                        kfree(lc);
 437                        return -ENOMEM;
 438                }
 439
 440                lc->disk_header = vmalloc(buf_size);
 441                if (!lc->disk_header) {
 442                        DMWARN("couldn't allocate disk log buffer");
 443                        dm_io_client_destroy(lc->io_req.client);
 444                        kfree(lc);
 445                        return -ENOMEM;
 446                }
 447
 448                lc->io_req.mem.ptr.vma = lc->disk_header;
 449                lc->clean_bits = (void *)lc->disk_header +
 450                                 (LOG_OFFSET << SECTOR_SHIFT);
 451        }
 452
 453        memset(lc->clean_bits, -1, bitset_size);
 454
 455        lc->sync_bits = vmalloc(bitset_size);
 456        if (!lc->sync_bits) {
 457                DMWARN("couldn't allocate sync bitset");
 458                if (!dev)
 459                        vfree(lc->clean_bits);
 460                else
 461                        dm_io_client_destroy(lc->io_req.client);
 462                vfree(lc->disk_header);
 463                kfree(lc);
 464                return -ENOMEM;
 465        }
 466        memset(lc->sync_bits, (sync == NOSYNC) ? -1 : 0, bitset_size);
 467        lc->sync_count = (sync == NOSYNC) ? region_count : 0;
 468
 469        lc->recovering_bits = vmalloc(bitset_size);
 470        if (!lc->recovering_bits) {
 471                DMWARN("couldn't allocate sync bitset");
 472                vfree(lc->sync_bits);
 473                if (!dev)
 474                        vfree(lc->clean_bits);
 475                else
 476                        dm_io_client_destroy(lc->io_req.client);
 477                vfree(lc->disk_header);
 478                kfree(lc);
 479                return -ENOMEM;
 480        }
 481        memset(lc->recovering_bits, 0, bitset_size);
 482        lc->sync_search = 0;
 483        log->context = lc;
 484
 485        return 0;
 486}
 487
 488static int core_ctr(struct dm_dirty_log *log, struct dm_target *ti,
 489                    unsigned int argc, char **argv)
 490{
 491        return create_log_context(log, ti, argc, argv, NULL);
 492}
 493
 494static void destroy_log_context(struct log_c *lc)
 495{
 496        vfree(lc->sync_bits);
 497        vfree(lc->recovering_bits);
 498        kfree(lc);
 499}
 500
 501static void core_dtr(struct dm_dirty_log *log)
 502{
 503        struct log_c *lc = (struct log_c *) log->context;
 504
 505        vfree(lc->clean_bits);
 506        destroy_log_context(lc);
 507}
 508
 509/*----------------------------------------------------------------
 510 * disk log constructor/destructor
 511 *
 512 * argv contains log_device region_size followed optionally by [no]sync
 513 *--------------------------------------------------------------*/
 514static int disk_ctr(struct dm_dirty_log *log, struct dm_target *ti,
 515                    unsigned int argc, char **argv)
 516{
 517        int r;
 518        struct dm_dev *dev;
 519
 520        if (argc < 2 || argc > 3) {
 521                DMWARN("wrong number of arguments to disk dirty region log");
 522                return -EINVAL;
 523        }
 524
 525        r = dm_get_device(ti, argv[0], 0, 0 /* FIXME */,
 526                          FMODE_READ | FMODE_WRITE, &dev);
 527        if (r)
 528                return r;
 529
 530        r = create_log_context(log, ti, argc - 1, argv + 1, dev);
 531        if (r) {
 532                dm_put_device(ti, dev);
 533                return r;
 534        }
 535
 536        return 0;
 537}
 538
 539static void disk_dtr(struct dm_dirty_log *log)
 540{
 541        struct log_c *lc = (struct log_c *) log->context;
 542
 543        dm_put_device(lc->ti, lc->log_dev);
 544        vfree(lc->disk_header);
 545        dm_io_client_destroy(lc->io_req.client);
 546        destroy_log_context(lc);
 547}
 548
 549static int count_bits32(uint32_t *addr, unsigned size)
 550{
 551        int count = 0, i;
 552
 553        for (i = 0; i < size; i++) {
 554                count += hweight32(*(addr+i));
 555        }
 556        return count;
 557}
 558
 559static void fail_log_device(struct log_c *lc)
 560{
 561        if (lc->log_dev_failed)
 562                return;
 563
 564        lc->log_dev_failed = 1;
 565        dm_table_event(lc->ti->table);
 566}
 567
 568static int disk_resume(struct dm_dirty_log *log)
 569{
 570        int r;
 571        unsigned i;
 572        struct log_c *lc = (struct log_c *) log->context;
 573        size_t size = lc->bitset_uint32_count * sizeof(uint32_t);
 574
 575        /* read the disk header */
 576        r = read_header(lc);
 577        if (r) {
 578                DMWARN("%s: Failed to read header on dirty region log device",
 579                       lc->log_dev->name);
 580                fail_log_device(lc);
 581                /*
 582                 * If the log device cannot be read, we must assume
 583                 * all regions are out-of-sync.  If we simply return
 584                 * here, the state will be uninitialized and could
 585                 * lead us to return 'in-sync' status for regions
 586                 * that are actually 'out-of-sync'.
 587                 */
 588                lc->header.nr_regions = 0;
 589        }
 590
 591        /* set or clear any new bits -- device has grown */
 592        if (lc->sync == NOSYNC)
 593                for (i = lc->header.nr_regions; i < lc->region_count; i++)
 594                        /* FIXME: amazingly inefficient */
 595                        log_set_bit(lc, lc->clean_bits, i);
 596        else
 597                for (i = lc->header.nr_regions; i < lc->region_count; i++)
 598                        /* FIXME: amazingly inefficient */
 599                        log_clear_bit(lc, lc->clean_bits, i);
 600
 601        /* clear any old bits -- device has shrunk */
 602        for (i = lc->region_count; i % (sizeof(*lc->clean_bits) << BYTE_SHIFT); i++)
 603                log_clear_bit(lc, lc->clean_bits, i);
 604
 605        /* copy clean across to sync */
 606        memcpy(lc->sync_bits, lc->clean_bits, size);
 607        lc->sync_count = count_bits32(lc->clean_bits, lc->bitset_uint32_count);
 608        lc->sync_search = 0;
 609
 610        /* set the correct number of regions in the header */
 611        lc->header.nr_regions = lc->region_count;
 612
 613        header_to_disk(&lc->header, lc->disk_header);
 614
 615        /* write the new header */
 616        r = rw_header(lc, WRITE);
 617        if (r) {
 618                DMWARN("%s: Failed to write header on dirty region log device",
 619                       lc->log_dev->name);
 620                fail_log_device(lc);
 621        }
 622
 623        return r;
 624}
 625
 626static uint32_t core_get_region_size(struct dm_dirty_log *log)
 627{
 628        struct log_c *lc = (struct log_c *) log->context;
 629        return lc->region_size;
 630}
 631
 632static int core_resume(struct dm_dirty_log *log)
 633{
 634        struct log_c *lc = (struct log_c *) log->context;
 635        lc->sync_search = 0;
 636        return 0;
 637}
 638
 639static int core_is_clean(struct dm_dirty_log *log, region_t region)
 640{
 641        struct log_c *lc = (struct log_c *) log->context;
 642        return log_test_bit(lc->clean_bits, region);
 643}
 644
 645static int core_in_sync(struct dm_dirty_log *log, region_t region, int block)
 646{
 647        struct log_c *lc = (struct log_c *) log->context;
 648        return log_test_bit(lc->sync_bits, region);
 649}
 650
 651static int core_flush(struct dm_dirty_log *log)
 652{
 653        /* no op */
 654        return 0;
 655}
 656
 657static int disk_flush(struct dm_dirty_log *log)
 658{
 659        int r;
 660        struct log_c *lc = (struct log_c *) log->context;
 661
 662        /* only write if the log has changed */
 663        if (!lc->touched)
 664                return 0;
 665
 666        r = rw_header(lc, WRITE);
 667        if (r)
 668                fail_log_device(lc);
 669        else
 670                lc->touched = 0;
 671
 672        return r;
 673}
 674
 675static void core_mark_region(struct dm_dirty_log *log, region_t region)
 676{
 677        struct log_c *lc = (struct log_c *) log->context;
 678        log_clear_bit(lc, lc->clean_bits, region);
 679}
 680
 681static void core_clear_region(struct dm_dirty_log *log, region_t region)
 682{
 683        struct log_c *lc = (struct log_c *) log->context;
 684        log_set_bit(lc, lc->clean_bits, region);
 685}
 686
 687static int core_get_resync_work(struct dm_dirty_log *log, region_t *region)
 688{
 689        struct log_c *lc = (struct log_c *) log->context;
 690
 691        if (lc->sync_search >= lc->region_count)
 692                return 0;
 693
 694        do {
 695                *region = ext2_find_next_zero_bit(
 696                                             (unsigned long *) lc->sync_bits,
 697                                             lc->region_count,
 698                                             lc->sync_search);
 699                lc->sync_search = *region + 1;
 700
 701                if (*region >= lc->region_count)
 702                        return 0;
 703
 704        } while (log_test_bit(lc->recovering_bits, *region));
 705
 706        log_set_bit(lc, lc->recovering_bits, *region);
 707        return 1;
 708}
 709
 710static void core_set_region_sync(struct dm_dirty_log *log, region_t region,
 711                                 int in_sync)
 712{
 713        struct log_c *lc = (struct log_c *) log->context;
 714
 715        log_clear_bit(lc, lc->recovering_bits, region);
 716        if (in_sync) {
 717                log_set_bit(lc, lc->sync_bits, region);
 718                lc->sync_count++;
 719        } else if (log_test_bit(lc->sync_bits, region)) {
 720                lc->sync_count--;
 721                log_clear_bit(lc, lc->sync_bits, region);
 722        }
 723}
 724
 725static region_t core_get_sync_count(struct dm_dirty_log *log)
 726{
 727        struct log_c *lc = (struct log_c *) log->context;
 728
 729        return lc->sync_count;
 730}
 731
 732#define DMEMIT_SYNC \
 733        if (lc->sync != DEFAULTSYNC) \
 734                DMEMIT("%ssync ", lc->sync == NOSYNC ? "no" : "")
 735
 736static int core_status(struct dm_dirty_log *log, status_type_t status,
 737                       char *result, unsigned int maxlen)
 738{
 739        int sz = 0;
 740        struct log_c *lc = log->context;
 741
 742        switch(status) {
 743        case STATUSTYPE_INFO:
 744                DMEMIT("1 %s", log->type->name);
 745                break;
 746
 747        case STATUSTYPE_TABLE:
 748                DMEMIT("%s %u %u ", log->type->name,
 749                       lc->sync == DEFAULTSYNC ? 1 : 2, lc->region_size);
 750                DMEMIT_SYNC;
 751        }
 752
 753        return sz;
 754}
 755
 756static int disk_status(struct dm_dirty_log *log, status_type_t status,
 757                       char *result, unsigned int maxlen)
 758{
 759        int sz = 0;
 760        struct log_c *lc = log->context;
 761
 762        switch(status) {
 763        case STATUSTYPE_INFO:
 764                DMEMIT("3 %s %s %c", log->type->name, lc->log_dev->name,
 765                       lc->log_dev_failed ? 'D' : 'A');
 766                break;
 767
 768        case STATUSTYPE_TABLE:
 769                DMEMIT("%s %u %s %u ", log->type->name,
 770                       lc->sync == DEFAULTSYNC ? 2 : 3, lc->log_dev->name,
 771                       lc->region_size);
 772                DMEMIT_SYNC;
 773        }
 774
 775        return sz;
 776}
 777
 778static struct dm_dirty_log_type _core_type = {
 779        .name = "core",
 780        .module = THIS_MODULE,
 781        .ctr = core_ctr,
 782        .dtr = core_dtr,
 783        .resume = core_resume,
 784        .get_region_size = core_get_region_size,
 785        .is_clean = core_is_clean,
 786        .in_sync = core_in_sync,
 787        .flush = core_flush,
 788        .mark_region = core_mark_region,
 789        .clear_region = core_clear_region,
 790        .get_resync_work = core_get_resync_work,
 791        .set_region_sync = core_set_region_sync,
 792        .get_sync_count = core_get_sync_count,
 793        .status = core_status,
 794};
 795
 796static struct dm_dirty_log_type _disk_type = {
 797        .name = "disk",
 798        .module = THIS_MODULE,
 799        .ctr = disk_ctr,
 800        .dtr = disk_dtr,
 801        .postsuspend = disk_flush,
 802        .resume = disk_resume,
 803        .get_region_size = core_get_region_size,
 804        .is_clean = core_is_clean,
 805        .in_sync = core_in_sync,
 806        .flush = disk_flush,
 807        .mark_region = core_mark_region,
 808        .clear_region = core_clear_region,
 809        .get_resync_work = core_get_resync_work,
 810        .set_region_sync = core_set_region_sync,
 811        .get_sync_count = core_get_sync_count,
 812        .status = disk_status,
 813};
 814
 815static int __init dm_dirty_log_init(void)
 816{
 817        int r;
 818
 819        r = dm_dirty_log_type_register(&_core_type);
 820        if (r)
 821                DMWARN("couldn't register core log");
 822
 823        r = dm_dirty_log_type_register(&_disk_type);
 824        if (r) {
 825                DMWARN("couldn't register disk type");
 826                dm_dirty_log_type_unregister(&_core_type);
 827        }
 828
 829        return r;
 830}
 831
 832static void __exit dm_dirty_log_exit(void)
 833{
 834        dm_dirty_log_type_unregister(&_disk_type);
 835        dm_dirty_log_type_unregister(&_core_type);
 836}
 837
 838module_init(dm_dirty_log_init);
 839module_exit(dm_dirty_log_exit);
 840
 841MODULE_DESCRIPTION(DM_NAME " dirty region log");
 842MODULE_AUTHOR("Joe Thornber, Heinz Mauelshagen <dm-devel@redhat.com>");
 843MODULE_LICENSE("GPL");
 844