Back to home page

OSCL-LXR

 
 

    


0001 /*
0002  * Copyright (C) 2003 Sistina Software
0003  * Copyright (C) 2004-2008 Red Hat, Inc. All rights reserved.
0004  *
0005  * This file is released under the LGPL.
0006  */
0007 
0008 #include <linux/init.h>
0009 #include <linux/slab.h>
0010 #include <linux/module.h>
0011 #include <linux/vmalloc.h>
0012 #include <linux/dm-io.h>
0013 #include <linux/dm-dirty-log.h>
0014 
0015 #include <linux/device-mapper.h>
0016 
0017 #define DM_MSG_PREFIX "dirty region log"
0018 
0019 static LIST_HEAD(_log_types);
0020 static DEFINE_SPINLOCK(_lock);
0021 
0022 static struct dm_dirty_log_type *__find_dirty_log_type(const char *name)
0023 {
0024     struct dm_dirty_log_type *log_type;
0025 
0026     list_for_each_entry(log_type, &_log_types, list)
0027         if (!strcmp(name, log_type->name))
0028             return log_type;
0029 
0030     return NULL;
0031 }
0032 
0033 static struct dm_dirty_log_type *_get_dirty_log_type(const char *name)
0034 {
0035     struct dm_dirty_log_type *log_type;
0036 
0037     spin_lock(&_lock);
0038 
0039     log_type = __find_dirty_log_type(name);
0040     if (log_type && !try_module_get(log_type->module))
0041         log_type = NULL;
0042 
0043     spin_unlock(&_lock);
0044 
0045     return log_type;
0046 }
0047 
0048 /*
0049  * get_type
0050  * @type_name
0051  *
0052  * Attempt to retrieve the dm_dirty_log_type by name.  If not already
0053  * available, attempt to load the appropriate module.
0054  *
0055  * Log modules are named "dm-log-" followed by the 'type_name'.
0056  * Modules may contain multiple types.
0057  * This function will first try the module "dm-log-<type_name>",
0058  * then truncate 'type_name' on the last '-' and try again.
0059  *
0060  * For example, if type_name was "clustered-disk", it would search
0061  * 'dm-log-clustered-disk' then 'dm-log-clustered'.
0062  *
0063  * Returns: dirty_log_type* on success, NULL on failure
0064  */
0065 static struct dm_dirty_log_type *get_type(const char *type_name)
0066 {
0067     char *p, *type_name_dup;
0068     struct dm_dirty_log_type *log_type;
0069 
0070     if (!type_name)
0071         return NULL;
0072 
0073     log_type = _get_dirty_log_type(type_name);
0074     if (log_type)
0075         return log_type;
0076 
0077     type_name_dup = kstrdup(type_name, GFP_KERNEL);
0078     if (!type_name_dup) {
0079         DMWARN("No memory left to attempt log module load for \"%s\"",
0080                type_name);
0081         return NULL;
0082     }
0083 
0084     while (request_module("dm-log-%s", type_name_dup) ||
0085            !(log_type = _get_dirty_log_type(type_name))) {
0086         p = strrchr(type_name_dup, '-');
0087         if (!p)
0088             break;
0089         p[0] = '\0';
0090     }
0091 
0092     if (!log_type)
0093         DMWARN("Module for logging type \"%s\" not found.", type_name);
0094 
0095     kfree(type_name_dup);
0096 
0097     return log_type;
0098 }
0099 
0100 static void put_type(struct dm_dirty_log_type *type)
0101 {
0102     if (!type)
0103         return;
0104 
0105     spin_lock(&_lock);
0106     if (!__find_dirty_log_type(type->name))
0107         goto out;
0108 
0109     module_put(type->module);
0110 
0111 out:
0112     spin_unlock(&_lock);
0113 }
0114 
0115 int dm_dirty_log_type_register(struct dm_dirty_log_type *type)
0116 {
0117     int r = 0;
0118 
0119     spin_lock(&_lock);
0120     if (!__find_dirty_log_type(type->name))
0121         list_add(&type->list, &_log_types);
0122     else
0123         r = -EEXIST;
0124     spin_unlock(&_lock);
0125 
0126     return r;
0127 }
0128 EXPORT_SYMBOL(dm_dirty_log_type_register);
0129 
0130 int dm_dirty_log_type_unregister(struct dm_dirty_log_type *type)
0131 {
0132     spin_lock(&_lock);
0133 
0134     if (!__find_dirty_log_type(type->name)) {
0135         spin_unlock(&_lock);
0136         return -EINVAL;
0137     }
0138 
0139     list_del(&type->list);
0140 
0141     spin_unlock(&_lock);
0142 
0143     return 0;
0144 }
0145 EXPORT_SYMBOL(dm_dirty_log_type_unregister);
0146 
0147 struct dm_dirty_log *dm_dirty_log_create(const char *type_name,
0148             struct dm_target *ti,
0149             int (*flush_callback_fn)(struct dm_target *ti),
0150             unsigned int argc, char **argv)
0151 {
0152     struct dm_dirty_log_type *type;
0153     struct dm_dirty_log *log;
0154 
0155     log = kmalloc(sizeof(*log), GFP_KERNEL);
0156     if (!log)
0157         return NULL;
0158 
0159     type = get_type(type_name);
0160     if (!type) {
0161         kfree(log);
0162         return NULL;
0163     }
0164 
0165     log->flush_callback_fn = flush_callback_fn;
0166     log->type = type;
0167     if (type->ctr(log, ti, argc, argv)) {
0168         kfree(log);
0169         put_type(type);
0170         return NULL;
0171     }
0172 
0173     return log;
0174 }
0175 EXPORT_SYMBOL(dm_dirty_log_create);
0176 
0177 void dm_dirty_log_destroy(struct dm_dirty_log *log)
0178 {
0179     log->type->dtr(log);
0180     put_type(log->type);
0181     kfree(log);
0182 }
0183 EXPORT_SYMBOL(dm_dirty_log_destroy);
0184 
0185 /*-----------------------------------------------------------------
0186  * Persistent and core logs share a lot of their implementation.
0187  * FIXME: need a reload method to be called from a resume
0188  *---------------------------------------------------------------*/
0189 /*
0190  * Magic for persistent mirrors: "MiRr"
0191  */
0192 #define MIRROR_MAGIC 0x4D695272
0193 
0194 /*
0195  * The on-disk version of the metadata.
0196  */
0197 #define MIRROR_DISK_VERSION 2
0198 #define LOG_OFFSET 2
0199 
0200 struct log_header_disk {
0201     __le32 magic;
0202 
0203     /*
0204      * Simple, incrementing version. no backward
0205      * compatibility.
0206      */
0207     __le32 version;
0208     __le64 nr_regions;
0209 } __packed;
0210 
0211 struct log_header_core {
0212     uint32_t magic;
0213     uint32_t version;
0214     uint64_t nr_regions;
0215 };
0216 
0217 struct log_c {
0218     struct dm_target *ti;
0219     int touched_dirtied;
0220     int touched_cleaned;
0221     int flush_failed;
0222     uint32_t region_size;
0223     unsigned int region_count;
0224     region_t sync_count;
0225 
0226     unsigned bitset_uint32_count;
0227     uint32_t *clean_bits;
0228     uint32_t *sync_bits;
0229     uint32_t *recovering_bits;  /* FIXME: this seems excessive */
0230 
0231     int sync_search;
0232 
0233     /* Resync flag */
0234     enum sync {
0235         DEFAULTSYNC,    /* Synchronize if necessary */
0236         NOSYNC,     /* Devices known to be already in sync */
0237         FORCESYNC,  /* Force a sync to happen */
0238     } sync;
0239 
0240     struct dm_io_request io_req;
0241 
0242     /*
0243      * Disk log fields
0244      */
0245     int log_dev_failed;
0246     int log_dev_flush_failed;
0247     struct dm_dev *log_dev;
0248     struct log_header_core header;
0249 
0250     struct dm_io_region header_location;
0251     struct log_header_disk *disk_header;
0252 };
0253 
0254 /*
0255  * The touched member needs to be updated every time we access
0256  * one of the bitsets.
0257  */
0258 static inline int log_test_bit(uint32_t *bs, unsigned bit)
0259 {
0260     return test_bit_le(bit, bs) ? 1 : 0;
0261 }
0262 
0263 static inline void log_set_bit(struct log_c *l,
0264                    uint32_t *bs, unsigned bit)
0265 {
0266     __set_bit_le(bit, bs);
0267     l->touched_cleaned = 1;
0268 }
0269 
0270 static inline void log_clear_bit(struct log_c *l,
0271                  uint32_t *bs, unsigned bit)
0272 {
0273     __clear_bit_le(bit, bs);
0274     l->touched_dirtied = 1;
0275 }
0276 
0277 /*----------------------------------------------------------------
0278  * Header IO
0279  *--------------------------------------------------------------*/
0280 static void header_to_disk(struct log_header_core *core, struct log_header_disk *disk)
0281 {
0282     disk->magic = cpu_to_le32(core->magic);
0283     disk->version = cpu_to_le32(core->version);
0284     disk->nr_regions = cpu_to_le64(core->nr_regions);
0285 }
0286 
0287 static void header_from_disk(struct log_header_core *core, struct log_header_disk *disk)
0288 {
0289     core->magic = le32_to_cpu(disk->magic);
0290     core->version = le32_to_cpu(disk->version);
0291     core->nr_regions = le64_to_cpu(disk->nr_regions);
0292 }
0293 
0294 static int rw_header(struct log_c *lc, enum req_op op)
0295 {
0296     lc->io_req.bi_opf = op;
0297 
0298     return dm_io(&lc->io_req, 1, &lc->header_location, NULL);
0299 }
0300 
0301 static int flush_header(struct log_c *lc)
0302 {
0303     struct dm_io_region null_location = {
0304         .bdev = lc->header_location.bdev,
0305         .sector = 0,
0306         .count = 0,
0307     };
0308 
0309     lc->io_req.bi_opf = REQ_OP_WRITE | REQ_PREFLUSH;
0310 
0311     return dm_io(&lc->io_req, 1, &null_location, NULL);
0312 }
0313 
0314 static int read_header(struct log_c *log)
0315 {
0316     int r;
0317 
0318     r = rw_header(log, REQ_OP_READ);
0319     if (r)
0320         return r;
0321 
0322     header_from_disk(&log->header, log->disk_header);
0323 
0324     /* New log required? */
0325     if (log->sync != DEFAULTSYNC || log->header.magic != MIRROR_MAGIC) {
0326         log->header.magic = MIRROR_MAGIC;
0327         log->header.version = MIRROR_DISK_VERSION;
0328         log->header.nr_regions = 0;
0329     }
0330 
0331 #ifdef __LITTLE_ENDIAN
0332     if (log->header.version == 1)
0333         log->header.version = 2;
0334 #endif
0335 
0336     if (log->header.version != MIRROR_DISK_VERSION) {
0337         DMWARN("incompatible disk log version");
0338         return -EINVAL;
0339     }
0340 
0341     return 0;
0342 }
0343 
0344 static int _check_region_size(struct dm_target *ti, uint32_t region_size)
0345 {
0346     if (region_size < 2 || region_size > ti->len)
0347         return 0;
0348 
0349     if (!is_power_of_2(region_size))
0350         return 0;
0351 
0352     return 1;
0353 }
0354 
0355 /*----------------------------------------------------------------
0356  * core log constructor/destructor
0357  *
0358  * argv contains region_size followed optionally by [no]sync
0359  *--------------------------------------------------------------*/
0360 #define BYTE_SHIFT 3
0361 static int create_log_context(struct dm_dirty_log *log, struct dm_target *ti,
0362                   unsigned int argc, char **argv,
0363                   struct dm_dev *dev)
0364 {
0365     enum sync sync = DEFAULTSYNC;
0366 
0367     struct log_c *lc;
0368     uint32_t region_size;
0369     unsigned int region_count;
0370     size_t bitset_size, buf_size;
0371     int r;
0372     char dummy;
0373 
0374     if (argc < 1 || argc > 2) {
0375         DMWARN("wrong number of arguments to dirty region log");
0376         return -EINVAL;
0377     }
0378 
0379     if (argc > 1) {
0380         if (!strcmp(argv[1], "sync"))
0381             sync = FORCESYNC;
0382         else if (!strcmp(argv[1], "nosync"))
0383             sync = NOSYNC;
0384         else {
0385             DMWARN("unrecognised sync argument to "
0386                    "dirty region log: %s", argv[1]);
0387             return -EINVAL;
0388         }
0389     }
0390 
0391     if (sscanf(argv[0], "%u%c", &region_size, &dummy) != 1 ||
0392         !_check_region_size(ti, region_size)) {
0393         DMWARN("invalid region size %s", argv[0]);
0394         return -EINVAL;
0395     }
0396 
0397     region_count = dm_sector_div_up(ti->len, region_size);
0398 
0399     lc = kmalloc(sizeof(*lc), GFP_KERNEL);
0400     if (!lc) {
0401         DMWARN("couldn't allocate core log");
0402         return -ENOMEM;
0403     }
0404 
0405     lc->ti = ti;
0406     lc->touched_dirtied = 0;
0407     lc->touched_cleaned = 0;
0408     lc->flush_failed = 0;
0409     lc->region_size = region_size;
0410     lc->region_count = region_count;
0411     lc->sync = sync;
0412 
0413     /*
0414      * Work out how many "unsigned long"s we need to hold the bitset.
0415      */
0416     bitset_size = dm_round_up(region_count, BITS_PER_LONG);
0417     bitset_size >>= BYTE_SHIFT;
0418 
0419     lc->bitset_uint32_count = bitset_size / sizeof(*lc->clean_bits);
0420 
0421     /*
0422      * Disk log?
0423      */
0424     if (!dev) {
0425         lc->clean_bits = vmalloc(bitset_size);
0426         if (!lc->clean_bits) {
0427             DMWARN("couldn't allocate clean bitset");
0428             kfree(lc);
0429             return -ENOMEM;
0430         }
0431         lc->disk_header = NULL;
0432     } else {
0433         lc->log_dev = dev;
0434         lc->log_dev_failed = 0;
0435         lc->log_dev_flush_failed = 0;
0436         lc->header_location.bdev = lc->log_dev->bdev;
0437         lc->header_location.sector = 0;
0438 
0439         /*
0440          * Buffer holds both header and bitset.
0441          */
0442         buf_size =
0443             dm_round_up((LOG_OFFSET << SECTOR_SHIFT) + bitset_size,
0444                 bdev_logical_block_size(lc->header_location.
0445                                 bdev));
0446 
0447         if (buf_size > bdev_nr_bytes(dev->bdev)) {
0448             DMWARN("log device %s too small: need %llu bytes",
0449                 dev->name, (unsigned long long)buf_size);
0450             kfree(lc);
0451             return -EINVAL;
0452         }
0453 
0454         lc->header_location.count = buf_size >> SECTOR_SHIFT;
0455 
0456         lc->io_req.mem.type = DM_IO_VMA;
0457         lc->io_req.notify.fn = NULL;
0458         lc->io_req.client = dm_io_client_create();
0459         if (IS_ERR(lc->io_req.client)) {
0460             r = PTR_ERR(lc->io_req.client);
0461             DMWARN("couldn't allocate disk io client");
0462             kfree(lc);
0463             return r;
0464         }
0465 
0466         lc->disk_header = vmalloc(buf_size);
0467         if (!lc->disk_header) {
0468             DMWARN("couldn't allocate disk log buffer");
0469             dm_io_client_destroy(lc->io_req.client);
0470             kfree(lc);
0471             return -ENOMEM;
0472         }
0473 
0474         lc->io_req.mem.ptr.vma = lc->disk_header;
0475         lc->clean_bits = (void *)lc->disk_header +
0476                  (LOG_OFFSET << SECTOR_SHIFT);
0477     }
0478 
0479     memset(lc->clean_bits, -1, bitset_size);
0480 
0481     lc->sync_bits = vmalloc(bitset_size);
0482     if (!lc->sync_bits) {
0483         DMWARN("couldn't allocate sync bitset");
0484         if (!dev)
0485             vfree(lc->clean_bits);
0486         else
0487             dm_io_client_destroy(lc->io_req.client);
0488         vfree(lc->disk_header);
0489         kfree(lc);
0490         return -ENOMEM;
0491     }
0492     memset(lc->sync_bits, (sync == NOSYNC) ? -1 : 0, bitset_size);
0493     lc->sync_count = (sync == NOSYNC) ? region_count : 0;
0494 
0495     lc->recovering_bits = vzalloc(bitset_size);
0496     if (!lc->recovering_bits) {
0497         DMWARN("couldn't allocate sync bitset");
0498         vfree(lc->sync_bits);
0499         if (!dev)
0500             vfree(lc->clean_bits);
0501         else
0502             dm_io_client_destroy(lc->io_req.client);
0503         vfree(lc->disk_header);
0504         kfree(lc);
0505         return -ENOMEM;
0506     }
0507     lc->sync_search = 0;
0508     log->context = lc;
0509 
0510     return 0;
0511 }
0512 
0513 static int core_ctr(struct dm_dirty_log *log, struct dm_target *ti,
0514             unsigned int argc, char **argv)
0515 {
0516     return create_log_context(log, ti, argc, argv, NULL);
0517 }
0518 
0519 static void destroy_log_context(struct log_c *lc)
0520 {
0521     vfree(lc->sync_bits);
0522     vfree(lc->recovering_bits);
0523     kfree(lc);
0524 }
0525 
0526 static void core_dtr(struct dm_dirty_log *log)
0527 {
0528     struct log_c *lc = (struct log_c *) log->context;
0529 
0530     vfree(lc->clean_bits);
0531     destroy_log_context(lc);
0532 }
0533 
0534 /*----------------------------------------------------------------
0535  * disk log constructor/destructor
0536  *
0537  * argv contains log_device region_size followed optionally by [no]sync
0538  *--------------------------------------------------------------*/
0539 static int disk_ctr(struct dm_dirty_log *log, struct dm_target *ti,
0540             unsigned int argc, char **argv)
0541 {
0542     int r;
0543     struct dm_dev *dev;
0544 
0545     if (argc < 2 || argc > 3) {
0546         DMWARN("wrong number of arguments to disk dirty region log");
0547         return -EINVAL;
0548     }
0549 
0550     r = dm_get_device(ti, argv[0], dm_table_get_mode(ti->table), &dev);
0551     if (r)
0552         return r;
0553 
0554     r = create_log_context(log, ti, argc - 1, argv + 1, dev);
0555     if (r) {
0556         dm_put_device(ti, dev);
0557         return r;
0558     }
0559 
0560     return 0;
0561 }
0562 
0563 static void disk_dtr(struct dm_dirty_log *log)
0564 {
0565     struct log_c *lc = (struct log_c *) log->context;
0566 
0567     dm_put_device(lc->ti, lc->log_dev);
0568     vfree(lc->disk_header);
0569     dm_io_client_destroy(lc->io_req.client);
0570     destroy_log_context(lc);
0571 }
0572 
0573 static void fail_log_device(struct log_c *lc)
0574 {
0575     if (lc->log_dev_failed)
0576         return;
0577 
0578     lc->log_dev_failed = 1;
0579     dm_table_event(lc->ti->table);
0580 }
0581 
0582 static int disk_resume(struct dm_dirty_log *log)
0583 {
0584     int r;
0585     unsigned i;
0586     struct log_c *lc = (struct log_c *) log->context;
0587     size_t size = lc->bitset_uint32_count * sizeof(uint32_t);
0588 
0589     /* read the disk header */
0590     r = read_header(lc);
0591     if (r) {
0592         DMWARN("%s: Failed to read header on dirty region log device",
0593                lc->log_dev->name);
0594         fail_log_device(lc);
0595         /*
0596          * If the log device cannot be read, we must assume
0597          * all regions are out-of-sync.  If we simply return
0598          * here, the state will be uninitialized and could
0599          * lead us to return 'in-sync' status for regions
0600          * that are actually 'out-of-sync'.
0601          */
0602         lc->header.nr_regions = 0;
0603     }
0604 
0605     /* set or clear any new bits -- device has grown */
0606     if (lc->sync == NOSYNC)
0607         for (i = lc->header.nr_regions; i < lc->region_count; i++)
0608             /* FIXME: amazingly inefficient */
0609             log_set_bit(lc, lc->clean_bits, i);
0610     else
0611         for (i = lc->header.nr_regions; i < lc->region_count; i++)
0612             /* FIXME: amazingly inefficient */
0613             log_clear_bit(lc, lc->clean_bits, i);
0614 
0615     /* clear any old bits -- device has shrunk */
0616     for (i = lc->region_count; i % BITS_PER_LONG; i++)
0617         log_clear_bit(lc, lc->clean_bits, i);
0618 
0619     /* copy clean across to sync */
0620     memcpy(lc->sync_bits, lc->clean_bits, size);
0621     lc->sync_count = memweight(lc->clean_bits,
0622                 lc->bitset_uint32_count * sizeof(uint32_t));
0623     lc->sync_search = 0;
0624 
0625     /* set the correct number of regions in the header */
0626     lc->header.nr_regions = lc->region_count;
0627 
0628     header_to_disk(&lc->header, lc->disk_header);
0629 
0630     /* write the new header */
0631     r = rw_header(lc, REQ_OP_WRITE);
0632     if (!r) {
0633         r = flush_header(lc);
0634         if (r)
0635             lc->log_dev_flush_failed = 1;
0636     }
0637     if (r) {
0638         DMWARN("%s: Failed to write header on dirty region log device",
0639                lc->log_dev->name);
0640         fail_log_device(lc);
0641     }
0642 
0643     return r;
0644 }
0645 
0646 static uint32_t core_get_region_size(struct dm_dirty_log *log)
0647 {
0648     struct log_c *lc = (struct log_c *) log->context;
0649     return lc->region_size;
0650 }
0651 
0652 static int core_resume(struct dm_dirty_log *log)
0653 {
0654     struct log_c *lc = (struct log_c *) log->context;
0655     lc->sync_search = 0;
0656     return 0;
0657 }
0658 
0659 static int core_is_clean(struct dm_dirty_log *log, region_t region)
0660 {
0661     struct log_c *lc = (struct log_c *) log->context;
0662     return log_test_bit(lc->clean_bits, region);
0663 }
0664 
0665 static int core_in_sync(struct dm_dirty_log *log, region_t region, int block)
0666 {
0667     struct log_c *lc = (struct log_c *) log->context;
0668     return log_test_bit(lc->sync_bits, region);
0669 }
0670 
0671 static int core_flush(struct dm_dirty_log *log)
0672 {
0673     /* no op */
0674     return 0;
0675 }
0676 
0677 static int disk_flush(struct dm_dirty_log *log)
0678 {
0679     int r, i;
0680     struct log_c *lc = log->context;
0681 
0682     /* only write if the log has changed */
0683     if (!lc->touched_cleaned && !lc->touched_dirtied)
0684         return 0;
0685 
0686     if (lc->touched_cleaned && log->flush_callback_fn &&
0687         log->flush_callback_fn(lc->ti)) {
0688         /*
0689          * At this point it is impossible to determine which
0690          * regions are clean and which are dirty (without
0691          * re-reading the log off disk). So mark all of them
0692          * dirty.
0693          */
0694         lc->flush_failed = 1;
0695         for (i = 0; i < lc->region_count; i++)
0696             log_clear_bit(lc, lc->clean_bits, i);
0697     }
0698 
0699     r = rw_header(lc, REQ_OP_WRITE);
0700     if (r)
0701         fail_log_device(lc);
0702     else {
0703         if (lc->touched_dirtied) {
0704             r = flush_header(lc);
0705             if (r) {
0706                 lc->log_dev_flush_failed = 1;
0707                 fail_log_device(lc);
0708             } else
0709                 lc->touched_dirtied = 0;
0710         }
0711         lc->touched_cleaned = 0;
0712     }
0713 
0714     return r;
0715 }
0716 
0717 static void core_mark_region(struct dm_dirty_log *log, region_t region)
0718 {
0719     struct log_c *lc = (struct log_c *) log->context;
0720     log_clear_bit(lc, lc->clean_bits, region);
0721 }
0722 
0723 static void core_clear_region(struct dm_dirty_log *log, region_t region)
0724 {
0725     struct log_c *lc = (struct log_c *) log->context;
0726     if (likely(!lc->flush_failed))
0727         log_set_bit(lc, lc->clean_bits, region);
0728 }
0729 
0730 static int core_get_resync_work(struct dm_dirty_log *log, region_t *region)
0731 {
0732     struct log_c *lc = (struct log_c *) log->context;
0733 
0734     if (lc->sync_search >= lc->region_count)
0735         return 0;
0736 
0737     do {
0738         *region = find_next_zero_bit_le(lc->sync_bits,
0739                          lc->region_count,
0740                          lc->sync_search);
0741         lc->sync_search = *region + 1;
0742 
0743         if (*region >= lc->region_count)
0744             return 0;
0745 
0746     } while (log_test_bit(lc->recovering_bits, *region));
0747 
0748     log_set_bit(lc, lc->recovering_bits, *region);
0749     return 1;
0750 }
0751 
0752 static void core_set_region_sync(struct dm_dirty_log *log, region_t region,
0753                  int in_sync)
0754 {
0755     struct log_c *lc = (struct log_c *) log->context;
0756 
0757     log_clear_bit(lc, lc->recovering_bits, region);
0758     if (in_sync) {
0759         log_set_bit(lc, lc->sync_bits, region);
0760                 lc->sync_count++;
0761         } else if (log_test_bit(lc->sync_bits, region)) {
0762         lc->sync_count--;
0763         log_clear_bit(lc, lc->sync_bits, region);
0764     }
0765 }
0766 
0767 static region_t core_get_sync_count(struct dm_dirty_log *log)
0768 {
0769         struct log_c *lc = (struct log_c *) log->context;
0770 
0771         return lc->sync_count;
0772 }
0773 
0774 #define DMEMIT_SYNC \
0775     if (lc->sync != DEFAULTSYNC) \
0776         DMEMIT("%ssync ", lc->sync == NOSYNC ? "no" : "")
0777 
0778 static int core_status(struct dm_dirty_log *log, status_type_t status,
0779                char *result, unsigned int maxlen)
0780 {
0781     int sz = 0;
0782     struct log_c *lc = log->context;
0783 
0784     switch(status) {
0785     case STATUSTYPE_INFO:
0786         DMEMIT("1 %s", log->type->name);
0787         break;
0788 
0789     case STATUSTYPE_TABLE:
0790         DMEMIT("%s %u %u ", log->type->name,
0791                lc->sync == DEFAULTSYNC ? 1 : 2, lc->region_size);
0792         DMEMIT_SYNC;
0793         break;
0794 
0795     case STATUSTYPE_IMA:
0796         *result = '\0';
0797         break;
0798     }
0799 
0800     return sz;
0801 }
0802 
0803 static int disk_status(struct dm_dirty_log *log, status_type_t status,
0804                char *result, unsigned int maxlen)
0805 {
0806     int sz = 0;
0807     struct log_c *lc = log->context;
0808 
0809     switch(status) {
0810     case STATUSTYPE_INFO:
0811         DMEMIT("3 %s %s %c", log->type->name, lc->log_dev->name,
0812                lc->log_dev_flush_failed ? 'F' :
0813                lc->log_dev_failed ? 'D' :
0814                'A');
0815         break;
0816 
0817     case STATUSTYPE_TABLE:
0818         DMEMIT("%s %u %s %u ", log->type->name,
0819                lc->sync == DEFAULTSYNC ? 2 : 3, lc->log_dev->name,
0820                lc->region_size);
0821         DMEMIT_SYNC;
0822         break;
0823 
0824     case STATUSTYPE_IMA:
0825         *result = '\0';
0826         break;
0827     }
0828 
0829     return sz;
0830 }
0831 
0832 static struct dm_dirty_log_type _core_type = {
0833     .name = "core",
0834     .module = THIS_MODULE,
0835     .ctr = core_ctr,
0836     .dtr = core_dtr,
0837     .resume = core_resume,
0838     .get_region_size = core_get_region_size,
0839     .is_clean = core_is_clean,
0840     .in_sync = core_in_sync,
0841     .flush = core_flush,
0842     .mark_region = core_mark_region,
0843     .clear_region = core_clear_region,
0844     .get_resync_work = core_get_resync_work,
0845     .set_region_sync = core_set_region_sync,
0846     .get_sync_count = core_get_sync_count,
0847     .status = core_status,
0848 };
0849 
0850 static struct dm_dirty_log_type _disk_type = {
0851     .name = "disk",
0852     .module = THIS_MODULE,
0853     .ctr = disk_ctr,
0854     .dtr = disk_dtr,
0855     .postsuspend = disk_flush,
0856     .resume = disk_resume,
0857     .get_region_size = core_get_region_size,
0858     .is_clean = core_is_clean,
0859     .in_sync = core_in_sync,
0860     .flush = disk_flush,
0861     .mark_region = core_mark_region,
0862     .clear_region = core_clear_region,
0863     .get_resync_work = core_get_resync_work,
0864     .set_region_sync = core_set_region_sync,
0865     .get_sync_count = core_get_sync_count,
0866     .status = disk_status,
0867 };
0868 
0869 static int __init dm_dirty_log_init(void)
0870 {
0871     int r;
0872 
0873     r = dm_dirty_log_type_register(&_core_type);
0874     if (r)
0875         DMWARN("couldn't register core log");
0876 
0877     r = dm_dirty_log_type_register(&_disk_type);
0878     if (r) {
0879         DMWARN("couldn't register disk type");
0880         dm_dirty_log_type_unregister(&_core_type);
0881     }
0882 
0883     return r;
0884 }
0885 
0886 static void __exit dm_dirty_log_exit(void)
0887 {
0888     dm_dirty_log_type_unregister(&_disk_type);
0889     dm_dirty_log_type_unregister(&_core_type);
0890 }
0891 
0892 module_init(dm_dirty_log_init);
0893 module_exit(dm_dirty_log_exit);
0894 
0895 MODULE_DESCRIPTION(DM_NAME " dirty region log");
0896 MODULE_AUTHOR("Joe Thornber, Heinz Mauelshagen <dm-devel@redhat.com>");
0897 MODULE_LICENSE("GPL");