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                        int (*flush_callback_fn)(struct dm_target *ti),
 150                        unsigned int argc, char **argv)
 151{
 152        struct dm_dirty_log_type *type;
 153        struct dm_dirty_log *log;
 154
 155        log = kmalloc(sizeof(*log), GFP_KERNEL);
 156        if (!log)
 157                return NULL;
 158
 159        type = get_type(type_name);
 160        if (!type) {
 161                kfree(log);
 162                return NULL;
 163        }
 164
 165        log->flush_callback_fn = flush_callback_fn;
 166        log->type = type;
 167        if (type->ctr(log, ti, argc, argv)) {
 168                kfree(log);
 169                put_type(type);
 170                return NULL;
 171        }
 172
 173        return log;
 174}
 175EXPORT_SYMBOL(dm_dirty_log_create);
 176
 177void dm_dirty_log_destroy(struct dm_dirty_log *log)
 178{
 179        log->type->dtr(log);
 180        put_type(log->type);
 181        kfree(log);
 182}
 183EXPORT_SYMBOL(dm_dirty_log_destroy);
 184
 185/*-----------------------------------------------------------------
 186 * Persistent and core logs share a lot of their implementation.
 187 * FIXME: need a reload method to be called from a resume
 188 *---------------------------------------------------------------*/
 189/*
 190 * Magic for persistent mirrors: "MiRr"
 191 */
 192#define MIRROR_MAGIC 0x4D695272
 193
 194/*
 195 * The on-disk version of the metadata.
 196 */
 197#define MIRROR_DISK_VERSION 2
 198#define LOG_OFFSET 2
 199
 200struct log_header_disk {
 201        __le32 magic;
 202
 203        /*
 204         * Simple, incrementing version. no backward
 205         * compatibility.
 206         */
 207        __le32 version;
 208        __le64 nr_regions;
 209} __packed;
 210
 211struct log_header_core {
 212        uint32_t magic;
 213        uint32_t version;
 214        uint64_t nr_regions;
 215};
 216
 217struct log_c {
 218        struct dm_target *ti;
 219        int touched_dirtied;
 220        int touched_cleaned;
 221        int flush_failed;
 222        uint32_t region_size;
 223        unsigned int region_count;
 224        region_t sync_count;
 225
 226        unsigned bitset_uint32_count;
 227        uint32_t *clean_bits;
 228        uint32_t *sync_bits;
 229        uint32_t *recovering_bits;      /* FIXME: this seems excessive */
 230
 231        int sync_search;
 232
 233        /* Resync flag */
 234        enum sync {
 235                DEFAULTSYNC,    /* Synchronize if necessary */
 236                NOSYNC,         /* Devices known to be already in sync */
 237                FORCESYNC,      /* Force a sync to happen */
 238        } sync;
 239
 240        struct dm_io_request io_req;
 241
 242        /*
 243         * Disk log fields
 244         */
 245        int log_dev_failed;
 246        int log_dev_flush_failed;
 247        struct dm_dev *log_dev;
 248        struct log_header_core header;
 249
 250        struct dm_io_region header_location;
 251        struct log_header_disk *disk_header;
 252};
 253
 254/*
 255 * The touched member needs to be updated every time we access
 256 * one of the bitsets.
 257 */
 258static inline int log_test_bit(uint32_t *bs, unsigned bit)
 259{
 260        return test_bit_le(bit, bs) ? 1 : 0;
 261}
 262
 263static inline void log_set_bit(struct log_c *l,
 264                               uint32_t *bs, unsigned bit)
 265{
 266        __set_bit_le(bit, bs);
 267        l->touched_cleaned = 1;
 268}
 269
 270static inline void log_clear_bit(struct log_c *l,
 271                                 uint32_t *bs, unsigned bit)
 272{
 273        __clear_bit_le(bit, bs);
 274        l->touched_dirtied = 1;
 275}
 276
 277/*----------------------------------------------------------------
 278 * Header IO
 279 *--------------------------------------------------------------*/
 280static void header_to_disk(struct log_header_core *core, struct log_header_disk *disk)
 281{
 282        disk->magic = cpu_to_le32(core->magic);
 283        disk->version = cpu_to_le32(core->version);
 284        disk->nr_regions = cpu_to_le64(core->nr_regions);
 285}
 286
 287static void header_from_disk(struct log_header_core *core, struct log_header_disk *disk)
 288{
 289        core->magic = le32_to_cpu(disk->magic);
 290        core->version = le32_to_cpu(disk->version);
 291        core->nr_regions = le64_to_cpu(disk->nr_regions);
 292}
 293
 294static int rw_header(struct log_c *lc, int op)
 295{
 296        lc->io_req.bi_op = op;
 297        lc->io_req.bi_op_flags = 0;
 298
 299        return dm_io(&lc->io_req, 1, &lc->header_location, NULL);
 300}
 301
 302static int flush_header(struct log_c *lc)
 303{
 304        struct dm_io_region null_location = {
 305                .bdev = lc->header_location.bdev,
 306                .sector = 0,
 307                .count = 0,
 308        };
 309
 310        lc->io_req.bi_op = REQ_OP_WRITE;
 311        lc->io_req.bi_op_flags = REQ_PREFLUSH;
 312
 313        return dm_io(&lc->io_req, 1, &null_location, NULL);
 314}
 315
 316static int read_header(struct log_c *log)
 317{
 318        int r;
 319
 320        r = rw_header(log, REQ_OP_READ);
 321        if (r)
 322                return r;
 323
 324        header_from_disk(&log->header, log->disk_header);
 325
 326        /* New log required? */
 327        if (log->sync != DEFAULTSYNC || log->header.magic != MIRROR_MAGIC) {
 328                log->header.magic = MIRROR_MAGIC;
 329                log->header.version = MIRROR_DISK_VERSION;
 330                log->header.nr_regions = 0;
 331        }
 332
 333#ifdef __LITTLE_ENDIAN
 334        if (log->header.version == 1)
 335                log->header.version = 2;
 336#endif
 337
 338        if (log->header.version != MIRROR_DISK_VERSION) {
 339                DMWARN("incompatible disk log version");
 340                return -EINVAL;
 341        }
 342
 343        return 0;
 344}
 345
 346static int _check_region_size(struct dm_target *ti, uint32_t region_size)
 347{
 348        if (region_size < 2 || region_size > ti->len)
 349                return 0;
 350
 351        if (!is_power_of_2(region_size))
 352                return 0;
 353
 354        return 1;
 355}
 356
 357/*----------------------------------------------------------------
 358 * core log constructor/destructor
 359 *
 360 * argv contains region_size followed optionally by [no]sync
 361 *--------------------------------------------------------------*/
 362#define BYTE_SHIFT 3
 363static int create_log_context(struct dm_dirty_log *log, struct dm_target *ti,
 364                              unsigned int argc, char **argv,
 365                              struct dm_dev *dev)
 366{
 367        enum sync sync = DEFAULTSYNC;
 368
 369        struct log_c *lc;
 370        uint32_t region_size;
 371        unsigned int region_count;
 372        size_t bitset_size, buf_size;
 373        int r;
 374        char dummy;
 375
 376        if (argc < 1 || argc > 2) {
 377                DMWARN("wrong number of arguments to dirty region log");
 378                return -EINVAL;
 379        }
 380
 381        if (argc > 1) {
 382                if (!strcmp(argv[1], "sync"))
 383                        sync = FORCESYNC;
 384                else if (!strcmp(argv[1], "nosync"))
 385                        sync = NOSYNC;
 386                else {
 387                        DMWARN("unrecognised sync argument to "
 388                               "dirty region log: %s", argv[1]);
 389                        return -EINVAL;
 390                }
 391        }
 392
 393        if (sscanf(argv[0], "%u%c", &region_size, &dummy) != 1 ||
 394            !_check_region_size(ti, region_size)) {
 395                DMWARN("invalid region size %s", argv[0]);
 396                return -EINVAL;
 397        }
 398
 399        region_count = dm_sector_div_up(ti->len, region_size);
 400
 401        lc = kmalloc(sizeof(*lc), GFP_KERNEL);
 402        if (!lc) {
 403                DMWARN("couldn't allocate core log");
 404                return -ENOMEM;
 405        }
 406
 407        lc->ti = ti;
 408        lc->touched_dirtied = 0;
 409        lc->touched_cleaned = 0;
 410        lc->flush_failed = 0;
 411        lc->region_size = region_size;
 412        lc->region_count = region_count;
 413        lc->sync = sync;
 414
 415        /*
 416         * Work out how many "unsigned long"s we need to hold the bitset.
 417         */
 418        bitset_size = dm_round_up(region_count,
 419                                  sizeof(*lc->clean_bits) << BYTE_SHIFT);
 420        bitset_size >>= BYTE_SHIFT;
 421
 422        lc->bitset_uint32_count = bitset_size / sizeof(*lc->clean_bits);
 423
 424        /*
 425         * Disk log?
 426         */
 427        if (!dev) {
 428                lc->clean_bits = vmalloc(bitset_size);
 429                if (!lc->clean_bits) {
 430                        DMWARN("couldn't allocate clean bitset");
 431                        kfree(lc);
 432                        return -ENOMEM;
 433                }
 434                lc->disk_header = NULL;
 435        } else {
 436                lc->log_dev = dev;
 437                lc->log_dev_failed = 0;
 438                lc->log_dev_flush_failed = 0;
 439                lc->header_location.bdev = lc->log_dev->bdev;
 440                lc->header_location.sector = 0;
 441
 442                /*
 443                 * Buffer holds both header and bitset.
 444                 */
 445                buf_size =
 446                    dm_round_up((LOG_OFFSET << SECTOR_SHIFT) + bitset_size,
 447                                bdev_logical_block_size(lc->header_location.
 448                                                            bdev));
 449
 450                if (buf_size > i_size_read(dev->bdev->bd_inode)) {
 451                        DMWARN("log device %s too small: need %llu bytes",
 452                                dev->name, (unsigned long long)buf_size);
 453                        kfree(lc);
 454                        return -EINVAL;
 455                }
 456
 457                lc->header_location.count = buf_size >> SECTOR_SHIFT;
 458
 459                lc->io_req.mem.type = DM_IO_VMA;
 460                lc->io_req.notify.fn = NULL;
 461                lc->io_req.client = dm_io_client_create();
 462                if (IS_ERR(lc->io_req.client)) {
 463                        r = PTR_ERR(lc->io_req.client);
 464                        DMWARN("couldn't allocate disk io client");
 465                        kfree(lc);
 466                        return r;
 467                }
 468
 469                lc->disk_header = vmalloc(buf_size);
 470                if (!lc->disk_header) {
 471                        DMWARN("couldn't allocate disk log buffer");
 472                        dm_io_client_destroy(lc->io_req.client);
 473                        kfree(lc);
 474                        return -ENOMEM;
 475                }
 476
 477                lc->io_req.mem.ptr.vma = lc->disk_header;
 478                lc->clean_bits = (void *)lc->disk_header +
 479                                 (LOG_OFFSET << SECTOR_SHIFT);
 480        }
 481
 482        memset(lc->clean_bits, -1, bitset_size);
 483
 484        lc->sync_bits = vmalloc(bitset_size);
 485        if (!lc->sync_bits) {
 486                DMWARN("couldn't allocate sync bitset");
 487                if (!dev)
 488                        vfree(lc->clean_bits);
 489                else
 490                        dm_io_client_destroy(lc->io_req.client);
 491                vfree(lc->disk_header);
 492                kfree(lc);
 493                return -ENOMEM;
 494        }
 495        memset(lc->sync_bits, (sync == NOSYNC) ? -1 : 0, bitset_size);
 496        lc->sync_count = (sync == NOSYNC) ? region_count : 0;
 497
 498        lc->recovering_bits = vzalloc(bitset_size);
 499        if (!lc->recovering_bits) {
 500                DMWARN("couldn't allocate sync bitset");
 501                vfree(lc->sync_bits);
 502                if (!dev)
 503                        vfree(lc->clean_bits);
 504                else
 505                        dm_io_client_destroy(lc->io_req.client);
 506                vfree(lc->disk_header);
 507                kfree(lc);
 508                return -ENOMEM;
 509        }
 510        lc->sync_search = 0;
 511        log->context = lc;
 512
 513        return 0;
 514}
 515
 516static int core_ctr(struct dm_dirty_log *log, struct dm_target *ti,
 517                    unsigned int argc, char **argv)
 518{
 519        return create_log_context(log, ti, argc, argv, NULL);
 520}
 521
 522static void destroy_log_context(struct log_c *lc)
 523{
 524        vfree(lc->sync_bits);
 525        vfree(lc->recovering_bits);
 526        kfree(lc);
 527}
 528
 529static void core_dtr(struct dm_dirty_log *log)
 530{
 531        struct log_c *lc = (struct log_c *) log->context;
 532
 533        vfree(lc->clean_bits);
 534        destroy_log_context(lc);
 535}
 536
 537/*----------------------------------------------------------------
 538 * disk log constructor/destructor
 539 *
 540 * argv contains log_device region_size followed optionally by [no]sync
 541 *--------------------------------------------------------------*/
 542static int disk_ctr(struct dm_dirty_log *log, struct dm_target *ti,
 543                    unsigned int argc, char **argv)
 544{
 545        int r;
 546        struct dm_dev *dev;
 547
 548        if (argc < 2 || argc > 3) {
 549                DMWARN("wrong number of arguments to disk dirty region log");
 550                return -EINVAL;
 551        }
 552
 553        r = dm_get_device(ti, argv[0], dm_table_get_mode(ti->table), &dev);
 554        if (r)
 555                return r;
 556
 557        r = create_log_context(log, ti, argc - 1, argv + 1, dev);
 558        if (r) {
 559                dm_put_device(ti, dev);
 560                return r;
 561        }
 562
 563        return 0;
 564}
 565
 566static void disk_dtr(struct dm_dirty_log *log)
 567{
 568        struct log_c *lc = (struct log_c *) log->context;
 569
 570        dm_put_device(lc->ti, lc->log_dev);
 571        vfree(lc->disk_header);
 572        dm_io_client_destroy(lc->io_req.client);
 573        destroy_log_context(lc);
 574}
 575
 576static void fail_log_device(struct log_c *lc)
 577{
 578        if (lc->log_dev_failed)
 579                return;
 580
 581        lc->log_dev_failed = 1;
 582        dm_table_event(lc->ti->table);
 583}
 584
 585static int disk_resume(struct dm_dirty_log *log)
 586{
 587        int r;
 588        unsigned i;
 589        struct log_c *lc = (struct log_c *) log->context;
 590        size_t size = lc->bitset_uint32_count * sizeof(uint32_t);
 591
 592        /* read the disk header */
 593        r = read_header(lc);
 594        if (r) {
 595                DMWARN("%s: Failed to read header on dirty region log device",
 596                       lc->log_dev->name);
 597                fail_log_device(lc);
 598                /*
 599                 * If the log device cannot be read, we must assume
 600                 * all regions are out-of-sync.  If we simply return
 601                 * here, the state will be uninitialized and could
 602                 * lead us to return 'in-sync' status for regions
 603                 * that are actually 'out-of-sync'.
 604                 */
 605                lc->header.nr_regions = 0;
 606        }
 607
 608        /* set or clear any new bits -- device has grown */
 609        if (lc->sync == NOSYNC)
 610                for (i = lc->header.nr_regions; i < lc->region_count; i++)
 611                        /* FIXME: amazingly inefficient */
 612                        log_set_bit(lc, lc->clean_bits, i);
 613        else
 614                for (i = lc->header.nr_regions; i < lc->region_count; i++)
 615                        /* FIXME: amazingly inefficient */
 616                        log_clear_bit(lc, lc->clean_bits, i);
 617
 618        /* clear any old bits -- device has shrunk */
 619        for (i = lc->region_count; i % (sizeof(*lc->clean_bits) << BYTE_SHIFT); i++)
 620                log_clear_bit(lc, lc->clean_bits, i);
 621
 622        /* copy clean across to sync */
 623        memcpy(lc->sync_bits, lc->clean_bits, size);
 624        lc->sync_count = memweight(lc->clean_bits,
 625                                lc->bitset_uint32_count * sizeof(uint32_t));
 626        lc->sync_search = 0;
 627
 628        /* set the correct number of regions in the header */
 629        lc->header.nr_regions = lc->region_count;
 630
 631        header_to_disk(&lc->header, lc->disk_header);
 632
 633        /* write the new header */
 634        r = rw_header(lc, REQ_OP_WRITE);
 635        if (!r) {
 636                r = flush_header(lc);
 637                if (r)
 638                        lc->log_dev_flush_failed = 1;
 639        }
 640        if (r) {
 641                DMWARN("%s: Failed to write header on dirty region log device",
 642                       lc->log_dev->name);
 643                fail_log_device(lc);
 644        }
 645
 646        return r;
 647}
 648
 649static uint32_t core_get_region_size(struct dm_dirty_log *log)
 650{
 651        struct log_c *lc = (struct log_c *) log->context;
 652        return lc->region_size;
 653}
 654
 655static int core_resume(struct dm_dirty_log *log)
 656{
 657        struct log_c *lc = (struct log_c *) log->context;
 658        lc->sync_search = 0;
 659        return 0;
 660}
 661
 662static int core_is_clean(struct dm_dirty_log *log, region_t region)
 663{
 664        struct log_c *lc = (struct log_c *) log->context;
 665        return log_test_bit(lc->clean_bits, region);
 666}
 667
 668static int core_in_sync(struct dm_dirty_log *log, region_t region, int block)
 669{
 670        struct log_c *lc = (struct log_c *) log->context;
 671        return log_test_bit(lc->sync_bits, region);
 672}
 673
 674static int core_flush(struct dm_dirty_log *log)
 675{
 676        /* no op */
 677        return 0;
 678}
 679
 680static int disk_flush(struct dm_dirty_log *log)
 681{
 682        int r, i;
 683        struct log_c *lc = log->context;
 684
 685        /* only write if the log has changed */
 686        if (!lc->touched_cleaned && !lc->touched_dirtied)
 687                return 0;
 688
 689        if (lc->touched_cleaned && log->flush_callback_fn &&
 690            log->flush_callback_fn(lc->ti)) {
 691                /*
 692                 * At this point it is impossible to determine which
 693                 * regions are clean and which are dirty (without
 694                 * re-reading the log off disk). So mark all of them
 695                 * dirty.
 696                 */
 697                lc->flush_failed = 1;
 698                for (i = 0; i < lc->region_count; i++)
 699                        log_clear_bit(lc, lc->clean_bits, i);
 700        }
 701
 702        r = rw_header(lc, REQ_OP_WRITE);
 703        if (r)
 704                fail_log_device(lc);
 705        else {
 706                if (lc->touched_dirtied) {
 707                        r = flush_header(lc);
 708                        if (r) {
 709                                lc->log_dev_flush_failed = 1;
 710                                fail_log_device(lc);
 711                        } else
 712                                lc->touched_dirtied = 0;
 713                }
 714                lc->touched_cleaned = 0;
 715        }
 716
 717        return r;
 718}
 719
 720static void core_mark_region(struct dm_dirty_log *log, region_t region)
 721{
 722        struct log_c *lc = (struct log_c *) log->context;
 723        log_clear_bit(lc, lc->clean_bits, region);
 724}
 725
 726static void core_clear_region(struct dm_dirty_log *log, region_t region)
 727{
 728        struct log_c *lc = (struct log_c *) log->context;
 729        if (likely(!lc->flush_failed))
 730                log_set_bit(lc, lc->clean_bits, region);
 731}
 732
 733static int core_get_resync_work(struct dm_dirty_log *log, region_t *region)
 734{
 735        struct log_c *lc = (struct log_c *) log->context;
 736
 737        if (lc->sync_search >= lc->region_count)
 738                return 0;
 739
 740        do {
 741                *region = find_next_zero_bit_le(lc->sync_bits,
 742                                             lc->region_count,
 743                                             lc->sync_search);
 744                lc->sync_search = *region + 1;
 745
 746                if (*region >= lc->region_count)
 747                        return 0;
 748
 749        } while (log_test_bit(lc->recovering_bits, *region));
 750
 751        log_set_bit(lc, lc->recovering_bits, *region);
 752        return 1;
 753}
 754
 755static void core_set_region_sync(struct dm_dirty_log *log, region_t region,
 756                                 int in_sync)
 757{
 758        struct log_c *lc = (struct log_c *) log->context;
 759
 760        log_clear_bit(lc, lc->recovering_bits, region);
 761        if (in_sync) {
 762                log_set_bit(lc, lc->sync_bits, region);
 763                lc->sync_count++;
 764        } else if (log_test_bit(lc->sync_bits, region)) {
 765                lc->sync_count--;
 766                log_clear_bit(lc, lc->sync_bits, region);
 767        }
 768}
 769
 770static region_t core_get_sync_count(struct dm_dirty_log *log)
 771{
 772        struct log_c *lc = (struct log_c *) log->context;
 773
 774        return lc->sync_count;
 775}
 776
 777#define DMEMIT_SYNC \
 778        if (lc->sync != DEFAULTSYNC) \
 779                DMEMIT("%ssync ", lc->sync == NOSYNC ? "no" : "")
 780
 781static int core_status(struct dm_dirty_log *log, status_type_t status,
 782                       char *result, unsigned int maxlen)
 783{
 784        int sz = 0;
 785        struct log_c *lc = log->context;
 786
 787        switch(status) {
 788        case STATUSTYPE_INFO:
 789                DMEMIT("1 %s", log->type->name);
 790                break;
 791
 792        case STATUSTYPE_TABLE:
 793                DMEMIT("%s %u %u ", log->type->name,
 794                       lc->sync == DEFAULTSYNC ? 1 : 2, lc->region_size);
 795                DMEMIT_SYNC;
 796        }
 797
 798        return sz;
 799}
 800
 801static int disk_status(struct dm_dirty_log *log, status_type_t status,
 802                       char *result, unsigned int maxlen)
 803{
 804        int sz = 0;
 805        struct log_c *lc = log->context;
 806
 807        switch(status) {
 808        case STATUSTYPE_INFO:
 809                DMEMIT("3 %s %s %c", log->type->name, lc->log_dev->name,
 810                       lc->log_dev_flush_failed ? 'F' :
 811                       lc->log_dev_failed ? 'D' :
 812                       'A');
 813                break;
 814
 815        case STATUSTYPE_TABLE:
 816                DMEMIT("%s %u %s %u ", log->type->name,
 817                       lc->sync == DEFAULTSYNC ? 2 : 3, lc->log_dev->name,
 818                       lc->region_size);
 819                DMEMIT_SYNC;
 820        }
 821
 822        return sz;
 823}
 824
 825static struct dm_dirty_log_type _core_type = {
 826        .name = "core",
 827        .module = THIS_MODULE,
 828        .ctr = core_ctr,
 829        .dtr = core_dtr,
 830        .resume = core_resume,
 831        .get_region_size = core_get_region_size,
 832        .is_clean = core_is_clean,
 833        .in_sync = core_in_sync,
 834        .flush = core_flush,
 835        .mark_region = core_mark_region,
 836        .clear_region = core_clear_region,
 837        .get_resync_work = core_get_resync_work,
 838        .set_region_sync = core_set_region_sync,
 839        .get_sync_count = core_get_sync_count,
 840        .status = core_status,
 841};
 842
 843static struct dm_dirty_log_type _disk_type = {
 844        .name = "disk",
 845        .module = THIS_MODULE,
 846        .ctr = disk_ctr,
 847        .dtr = disk_dtr,
 848        .postsuspend = disk_flush,
 849        .resume = disk_resume,
 850        .get_region_size = core_get_region_size,
 851        .is_clean = core_is_clean,
 852        .in_sync = core_in_sync,
 853        .flush = disk_flush,
 854        .mark_region = core_mark_region,
 855        .clear_region = core_clear_region,
 856        .get_resync_work = core_get_resync_work,
 857        .set_region_sync = core_set_region_sync,
 858        .get_sync_count = core_get_sync_count,
 859        .status = disk_status,
 860};
 861
 862static int __init dm_dirty_log_init(void)
 863{
 864        int r;
 865
 866        r = dm_dirty_log_type_register(&_core_type);
 867        if (r)
 868                DMWARN("couldn't register core log");
 869
 870        r = dm_dirty_log_type_register(&_disk_type);
 871        if (r) {
 872                DMWARN("couldn't register disk type");
 873                dm_dirty_log_type_unregister(&_core_type);
 874        }
 875
 876        return r;
 877}
 878
 879static void __exit dm_dirty_log_exit(void)
 880{
 881        dm_dirty_log_type_unregister(&_disk_type);
 882        dm_dirty_log_type_unregister(&_core_type);
 883}
 884
 885module_init(dm_dirty_log_init);
 886module_exit(dm_dirty_log_exit);
 887
 888MODULE_DESCRIPTION(DM_NAME " dirty region log");
 889MODULE_AUTHOR("Joe Thornber, Heinz Mauelshagen <dm-devel@redhat.com>");
 890MODULE_LICENSE("GPL");
 891