11da177e4SLinus Torvalds /* 21da177e4SLinus Torvalds * Copyright (C) 2003 Sistina Software 3b7fd54a7SHeinz Mauelshagen * Copyright (C) 2004-2008 Red Hat, Inc. All rights reserved. 41da177e4SLinus Torvalds * 51da177e4SLinus Torvalds * This file is released under the LGPL. 61da177e4SLinus Torvalds */ 71da177e4SLinus Torvalds 81da177e4SLinus Torvalds #include <linux/init.h> 91da177e4SLinus Torvalds #include <linux/slab.h> 101da177e4SLinus Torvalds #include <linux/module.h> 111da177e4SLinus Torvalds #include <linux/vmalloc.h> 12*a765e20eSAlasdair G Kergon #include <linux/dm-io.h> 13*a765e20eSAlasdair G Kergon #include <linux/dm-dirty-log.h> 141da177e4SLinus Torvalds 15416cd17bSHeinz Mauelshagen #include "dm.h" 161da177e4SLinus Torvalds 17b7fd54a7SHeinz Mauelshagen #define DM_MSG_PREFIX "dirty region log" 1872d94861SAlasdair G Kergon 192a23aa1dSJonathan Brassow struct dm_dirty_log_internal { 202a23aa1dSJonathan Brassow struct dm_dirty_log_type *type; 212a23aa1dSJonathan Brassow 222a23aa1dSJonathan Brassow struct list_head list; 232a23aa1dSJonathan Brassow long use; 242a23aa1dSJonathan Brassow }; 252a23aa1dSJonathan Brassow 261da177e4SLinus Torvalds static LIST_HEAD(_log_types); 271da177e4SLinus Torvalds static DEFINE_SPINLOCK(_lock); 281da177e4SLinus Torvalds 292a23aa1dSJonathan Brassow static struct dm_dirty_log_internal *__find_dirty_log_type(const char *name) 301da177e4SLinus Torvalds { 312a23aa1dSJonathan Brassow struct dm_dirty_log_internal *log_type; 322a23aa1dSJonathan Brassow 332a23aa1dSJonathan Brassow list_for_each_entry(log_type, &_log_types, list) 342a23aa1dSJonathan Brassow if (!strcmp(name, log_type->type->name)) 352a23aa1dSJonathan Brassow return log_type; 362a23aa1dSJonathan Brassow 372a23aa1dSJonathan Brassow return NULL; 382a23aa1dSJonathan Brassow } 392a23aa1dSJonathan Brassow 402a23aa1dSJonathan Brassow static struct dm_dirty_log_internal *_get_dirty_log_type(const char *name) 412a23aa1dSJonathan Brassow { 422a23aa1dSJonathan Brassow struct dm_dirty_log_internal *log_type; 431da177e4SLinus Torvalds 441da177e4SLinus Torvalds spin_lock(&_lock); 452a23aa1dSJonathan Brassow 462a23aa1dSJonathan Brassow log_type = __find_dirty_log_type(name); 472a23aa1dSJonathan Brassow if (log_type) { 482a23aa1dSJonathan Brassow if (!log_type->use && !try_module_get(log_type->type->module)) 492a23aa1dSJonathan Brassow log_type = NULL; 502a23aa1dSJonathan Brassow else 512a23aa1dSJonathan Brassow log_type->use++; 521da177e4SLinus Torvalds } 531da177e4SLinus Torvalds 541da177e4SLinus Torvalds spin_unlock(&_lock); 552a23aa1dSJonathan Brassow 562a23aa1dSJonathan Brassow return log_type; 571da177e4SLinus Torvalds } 581da177e4SLinus Torvalds 59fb8b2848SJonathan Brassow /* 60fb8b2848SJonathan Brassow * get_type 61fb8b2848SJonathan Brassow * @type_name 62fb8b2848SJonathan Brassow * 632a23aa1dSJonathan Brassow * Attempt to retrieve the dm_dirty_log_type by name. If not already 64fb8b2848SJonathan Brassow * available, attempt to load the appropriate module. 65fb8b2848SJonathan Brassow * 66fb8b2848SJonathan Brassow * Log modules are named "dm-log-" followed by the 'type_name'. 67fb8b2848SJonathan Brassow * Modules may contain multiple types. 68fb8b2848SJonathan Brassow * This function will first try the module "dm-log-<type_name>", 69fb8b2848SJonathan Brassow * then truncate 'type_name' on the last '-' and try again. 70fb8b2848SJonathan Brassow * 71fb8b2848SJonathan Brassow * For example, if type_name was "clustered-disk", it would search 72fb8b2848SJonathan Brassow * 'dm-log-clustered-disk' then 'dm-log-clustered'. 73fb8b2848SJonathan Brassow * 74fb8b2848SJonathan Brassow * Returns: dirty_log_type* on success, NULL on failure 75fb8b2848SJonathan Brassow */ 76416cd17bSHeinz Mauelshagen static struct dm_dirty_log_type *get_type(const char *type_name) 77fb8b2848SJonathan Brassow { 78fb8b2848SJonathan Brassow char *p, *type_name_dup; 792a23aa1dSJonathan Brassow struct dm_dirty_log_internal *log_type; 80fb8b2848SJonathan Brassow 812a23aa1dSJonathan Brassow if (!type_name) 822a23aa1dSJonathan Brassow return NULL; 832a23aa1dSJonathan Brassow 842a23aa1dSJonathan Brassow log_type = _get_dirty_log_type(type_name); 852a23aa1dSJonathan Brassow if (log_type) 862a23aa1dSJonathan Brassow return log_type->type; 87fb8b2848SJonathan Brassow 88fb8b2848SJonathan Brassow type_name_dup = kstrdup(type_name, GFP_KERNEL); 89fb8b2848SJonathan Brassow if (!type_name_dup) { 90fb8b2848SJonathan Brassow DMWARN("No memory left to attempt log module load for \"%s\"", 91fb8b2848SJonathan Brassow type_name); 92fb8b2848SJonathan Brassow return NULL; 93fb8b2848SJonathan Brassow } 94fb8b2848SJonathan Brassow 95fb8b2848SJonathan Brassow while (request_module("dm-log-%s", type_name_dup) || 962a23aa1dSJonathan Brassow !(log_type = _get_dirty_log_type(type_name))) { 97fb8b2848SJonathan Brassow p = strrchr(type_name_dup, '-'); 98fb8b2848SJonathan Brassow if (!p) 99fb8b2848SJonathan Brassow break; 100fb8b2848SJonathan Brassow p[0] = '\0'; 101fb8b2848SJonathan Brassow } 102fb8b2848SJonathan Brassow 1032a23aa1dSJonathan Brassow if (!log_type) 104fb8b2848SJonathan Brassow DMWARN("Module for logging type \"%s\" not found.", type_name); 105fb8b2848SJonathan Brassow 106fb8b2848SJonathan Brassow kfree(type_name_dup); 107fb8b2848SJonathan Brassow 1082a23aa1dSJonathan Brassow return log_type ? log_type->type : NULL; 109fb8b2848SJonathan Brassow } 110fb8b2848SJonathan Brassow 111416cd17bSHeinz Mauelshagen static void put_type(struct dm_dirty_log_type *type) 1121da177e4SLinus Torvalds { 1132a23aa1dSJonathan Brassow struct dm_dirty_log_internal *log_type; 1142a23aa1dSJonathan Brassow 1152a23aa1dSJonathan Brassow if (!type) 1162a23aa1dSJonathan Brassow return; 1172a23aa1dSJonathan Brassow 1181da177e4SLinus Torvalds spin_lock(&_lock); 1192a23aa1dSJonathan Brassow log_type = __find_dirty_log_type(type->name); 1202a23aa1dSJonathan Brassow if (!log_type) 1212a23aa1dSJonathan Brassow goto out; 1222a23aa1dSJonathan Brassow 1232a23aa1dSJonathan Brassow if (!--log_type->use) 1241da177e4SLinus Torvalds module_put(type->module); 1252a23aa1dSJonathan Brassow 1262a23aa1dSJonathan Brassow BUG_ON(log_type->use < 0); 1272a23aa1dSJonathan Brassow 1282a23aa1dSJonathan Brassow out: 1291da177e4SLinus Torvalds spin_unlock(&_lock); 1301da177e4SLinus Torvalds } 1311da177e4SLinus Torvalds 1322a23aa1dSJonathan Brassow static struct dm_dirty_log_internal *_alloc_dirty_log_type(struct dm_dirty_log_type *type) 1332a23aa1dSJonathan Brassow { 1342a23aa1dSJonathan Brassow struct dm_dirty_log_internal *log_type = kzalloc(sizeof(*log_type), 1352a23aa1dSJonathan Brassow GFP_KERNEL); 1362a23aa1dSJonathan Brassow 1372a23aa1dSJonathan Brassow if (log_type) 1382a23aa1dSJonathan Brassow log_type->type = type; 1392a23aa1dSJonathan Brassow 1402a23aa1dSJonathan Brassow return log_type; 1412a23aa1dSJonathan Brassow } 1422a23aa1dSJonathan Brassow 143b8206bc3SAlasdair G Kergon int dm_dirty_log_type_register(struct dm_dirty_log_type *type) 144b8206bc3SAlasdair G Kergon { 1452a23aa1dSJonathan Brassow struct dm_dirty_log_internal *log_type = _alloc_dirty_log_type(type); 1462a23aa1dSJonathan Brassow int r = 0; 1472a23aa1dSJonathan Brassow 1482a23aa1dSJonathan Brassow if (!log_type) 1492a23aa1dSJonathan Brassow return -ENOMEM; 1502a23aa1dSJonathan Brassow 151b8206bc3SAlasdair G Kergon spin_lock(&_lock); 1522a23aa1dSJonathan Brassow if (!__find_dirty_log_type(type->name)) 1532a23aa1dSJonathan Brassow list_add(&log_type->list, &_log_types); 1542a23aa1dSJonathan Brassow else { 1552a23aa1dSJonathan Brassow kfree(log_type); 1562a23aa1dSJonathan Brassow r = -EEXIST; 1572a23aa1dSJonathan Brassow } 158b8206bc3SAlasdair G Kergon spin_unlock(&_lock); 159b8206bc3SAlasdair G Kergon 1602a23aa1dSJonathan Brassow return r; 161b8206bc3SAlasdair G Kergon } 162b8206bc3SAlasdair G Kergon EXPORT_SYMBOL(dm_dirty_log_type_register); 163b8206bc3SAlasdair G Kergon 164b8206bc3SAlasdair G Kergon int dm_dirty_log_type_unregister(struct dm_dirty_log_type *type) 165b8206bc3SAlasdair G Kergon { 1662a23aa1dSJonathan Brassow struct dm_dirty_log_internal *log_type; 1672a23aa1dSJonathan Brassow 168b8206bc3SAlasdair G Kergon spin_lock(&_lock); 169b8206bc3SAlasdair G Kergon 1702a23aa1dSJonathan Brassow log_type = __find_dirty_log_type(type->name); 1712a23aa1dSJonathan Brassow if (!log_type) { 1722a23aa1dSJonathan Brassow spin_unlock(&_lock); 1732a23aa1dSJonathan Brassow return -EINVAL; 1742a23aa1dSJonathan Brassow } 1752a23aa1dSJonathan Brassow 1762a23aa1dSJonathan Brassow if (log_type->use) { 1772a23aa1dSJonathan Brassow spin_unlock(&_lock); 1782a23aa1dSJonathan Brassow return -ETXTBSY; 1792a23aa1dSJonathan Brassow } 1802a23aa1dSJonathan Brassow 1812a23aa1dSJonathan Brassow list_del(&log_type->list); 182b8206bc3SAlasdair G Kergon 183b8206bc3SAlasdair G Kergon spin_unlock(&_lock); 1842a23aa1dSJonathan Brassow kfree(log_type); 185b8206bc3SAlasdair G Kergon 186b8206bc3SAlasdair G Kergon return 0; 187b8206bc3SAlasdair G Kergon } 188b8206bc3SAlasdair G Kergon EXPORT_SYMBOL(dm_dirty_log_type_unregister); 189b8206bc3SAlasdair G Kergon 190416cd17bSHeinz Mauelshagen struct dm_dirty_log *dm_dirty_log_create(const char *type_name, 191416cd17bSHeinz Mauelshagen struct dm_target *ti, 1921da177e4SLinus Torvalds unsigned int argc, char **argv) 1931da177e4SLinus Torvalds { 194416cd17bSHeinz Mauelshagen struct dm_dirty_log_type *type; 195416cd17bSHeinz Mauelshagen struct dm_dirty_log *log; 1961da177e4SLinus Torvalds 1971da177e4SLinus Torvalds log = kmalloc(sizeof(*log), GFP_KERNEL); 1981da177e4SLinus Torvalds if (!log) 1991da177e4SLinus Torvalds return NULL; 2001da177e4SLinus Torvalds 2011da177e4SLinus Torvalds type = get_type(type_name); 2021da177e4SLinus Torvalds if (!type) { 2031da177e4SLinus Torvalds kfree(log); 2041da177e4SLinus Torvalds return NULL; 2051da177e4SLinus Torvalds } 2061da177e4SLinus Torvalds 2071da177e4SLinus Torvalds log->type = type; 2081da177e4SLinus Torvalds if (type->ctr(log, ti, argc, argv)) { 2091da177e4SLinus Torvalds kfree(log); 2101da177e4SLinus Torvalds put_type(type); 2111da177e4SLinus Torvalds return NULL; 2121da177e4SLinus Torvalds } 2131da177e4SLinus Torvalds 2141da177e4SLinus Torvalds return log; 2151da177e4SLinus Torvalds } 216416cd17bSHeinz Mauelshagen EXPORT_SYMBOL(dm_dirty_log_create); 2171da177e4SLinus Torvalds 218416cd17bSHeinz Mauelshagen void dm_dirty_log_destroy(struct dm_dirty_log *log) 2191da177e4SLinus Torvalds { 2201da177e4SLinus Torvalds log->type->dtr(log); 2211da177e4SLinus Torvalds put_type(log->type); 2221da177e4SLinus Torvalds kfree(log); 2231da177e4SLinus Torvalds } 224416cd17bSHeinz Mauelshagen EXPORT_SYMBOL(dm_dirty_log_destroy); 2251da177e4SLinus Torvalds 2261da177e4SLinus Torvalds /*----------------------------------------------------------------- 2271da177e4SLinus Torvalds * Persistent and core logs share a lot of their implementation. 2281da177e4SLinus Torvalds * FIXME: need a reload method to be called from a resume 2291da177e4SLinus Torvalds *---------------------------------------------------------------*/ 2301da177e4SLinus Torvalds /* 2311da177e4SLinus Torvalds * Magic for persistent mirrors: "MiRr" 2321da177e4SLinus Torvalds */ 2331da177e4SLinus Torvalds #define MIRROR_MAGIC 0x4D695272 2341da177e4SLinus Torvalds 2351da177e4SLinus Torvalds /* 2361da177e4SLinus Torvalds * The on-disk version of the metadata. 2371da177e4SLinus Torvalds */ 238a4fc4717SPatrick Caulfield #define MIRROR_DISK_VERSION 2 2391da177e4SLinus Torvalds #define LOG_OFFSET 2 2401da177e4SLinus Torvalds 2411da177e4SLinus Torvalds struct log_header { 2421da177e4SLinus Torvalds uint32_t magic; 2431da177e4SLinus Torvalds 2441da177e4SLinus Torvalds /* 2451da177e4SLinus Torvalds * Simple, incrementing version. no backward 2461da177e4SLinus Torvalds * compatibility. 2471da177e4SLinus Torvalds */ 2481da177e4SLinus Torvalds uint32_t version; 2491da177e4SLinus Torvalds sector_t nr_regions; 2501da177e4SLinus Torvalds }; 2511da177e4SLinus Torvalds 2521da177e4SLinus Torvalds struct log_c { 2531da177e4SLinus Torvalds struct dm_target *ti; 2541da177e4SLinus Torvalds int touched; 2551da177e4SLinus Torvalds uint32_t region_size; 2561da177e4SLinus Torvalds unsigned int region_count; 2571da177e4SLinus Torvalds region_t sync_count; 2581da177e4SLinus Torvalds 2591da177e4SLinus Torvalds unsigned bitset_uint32_count; 2601da177e4SLinus Torvalds uint32_t *clean_bits; 2611da177e4SLinus Torvalds uint32_t *sync_bits; 2621da177e4SLinus Torvalds uint32_t *recovering_bits; /* FIXME: this seems excessive */ 2631da177e4SLinus Torvalds 2641da177e4SLinus Torvalds int sync_search; 2651da177e4SLinus Torvalds 2661da177e4SLinus Torvalds /* Resync flag */ 2671da177e4SLinus Torvalds enum sync { 2681da177e4SLinus Torvalds DEFAULTSYNC, /* Synchronize if necessary */ 2691da177e4SLinus Torvalds NOSYNC, /* Devices known to be already in sync */ 2701da177e4SLinus Torvalds FORCESYNC, /* Force a sync to happen */ 2711da177e4SLinus Torvalds } sync; 2721da177e4SLinus Torvalds 2735d234d1eSHeinz Mauelshagen struct dm_io_request io_req; 2745d234d1eSHeinz Mauelshagen 2751da177e4SLinus Torvalds /* 2761da177e4SLinus Torvalds * Disk log fields 2771da177e4SLinus Torvalds */ 27801d03a66SJonathan E Brassow int log_dev_failed; 2791da177e4SLinus Torvalds struct dm_dev *log_dev; 2801da177e4SLinus Torvalds struct log_header header; 2811da177e4SLinus Torvalds 28222a1ceb1SHeinz Mauelshagen struct dm_io_region header_location; 2831da177e4SLinus Torvalds struct log_header *disk_header; 2841da177e4SLinus Torvalds }; 2851da177e4SLinus Torvalds 2861da177e4SLinus Torvalds /* 2871da177e4SLinus Torvalds * The touched member needs to be updated every time we access 2881da177e4SLinus Torvalds * one of the bitsets. 2891da177e4SLinus Torvalds */ 2901da177e4SLinus Torvalds static inline int log_test_bit(uint32_t *bs, unsigned bit) 2911da177e4SLinus Torvalds { 292a4fc4717SPatrick Caulfield return ext2_test_bit(bit, (unsigned long *) bs) ? 1 : 0; 2931da177e4SLinus Torvalds } 2941da177e4SLinus Torvalds 2951da177e4SLinus Torvalds static inline void log_set_bit(struct log_c *l, 2961da177e4SLinus Torvalds uint32_t *bs, unsigned bit) 2971da177e4SLinus Torvalds { 298a4fc4717SPatrick Caulfield ext2_set_bit(bit, (unsigned long *) bs); 2991da177e4SLinus Torvalds l->touched = 1; 3001da177e4SLinus Torvalds } 3011da177e4SLinus Torvalds 3021da177e4SLinus Torvalds static inline void log_clear_bit(struct log_c *l, 3031da177e4SLinus Torvalds uint32_t *bs, unsigned bit) 3041da177e4SLinus Torvalds { 305a4fc4717SPatrick Caulfield ext2_clear_bit(bit, (unsigned long *) bs); 3061da177e4SLinus Torvalds l->touched = 1; 3071da177e4SLinus Torvalds } 3081da177e4SLinus Torvalds 3091da177e4SLinus Torvalds /*---------------------------------------------------------------- 3101da177e4SLinus Torvalds * Header IO 3111da177e4SLinus Torvalds *--------------------------------------------------------------*/ 3121da177e4SLinus Torvalds static void header_to_disk(struct log_header *core, struct log_header *disk) 3131da177e4SLinus Torvalds { 3141da177e4SLinus Torvalds disk->magic = cpu_to_le32(core->magic); 3151da177e4SLinus Torvalds disk->version = cpu_to_le32(core->version); 3161da177e4SLinus Torvalds disk->nr_regions = cpu_to_le64(core->nr_regions); 3171da177e4SLinus Torvalds } 3181da177e4SLinus Torvalds 3191da177e4SLinus Torvalds static void header_from_disk(struct log_header *core, struct log_header *disk) 3201da177e4SLinus Torvalds { 3211da177e4SLinus Torvalds core->magic = le32_to_cpu(disk->magic); 3221da177e4SLinus Torvalds core->version = le32_to_cpu(disk->version); 3231da177e4SLinus Torvalds core->nr_regions = le64_to_cpu(disk->nr_regions); 3241da177e4SLinus Torvalds } 3251da177e4SLinus Torvalds 3265d234d1eSHeinz Mauelshagen static int rw_header(struct log_c *lc, int rw) 3275d234d1eSHeinz Mauelshagen { 3285d234d1eSHeinz Mauelshagen lc->io_req.bi_rw = rw; 3295d234d1eSHeinz Mauelshagen lc->io_req.mem.ptr.vma = lc->disk_header; 3305d234d1eSHeinz Mauelshagen lc->io_req.notify.fn = NULL; 3315d234d1eSHeinz Mauelshagen 3325d234d1eSHeinz Mauelshagen return dm_io(&lc->io_req, 1, &lc->header_location, NULL); 3335d234d1eSHeinz Mauelshagen } 3345d234d1eSHeinz Mauelshagen 3351da177e4SLinus Torvalds static int read_header(struct log_c *log) 3361da177e4SLinus Torvalds { 3371da177e4SLinus Torvalds int r; 3381da177e4SLinus Torvalds 3395d234d1eSHeinz Mauelshagen r = rw_header(log, READ); 3401da177e4SLinus Torvalds if (r) 3411da177e4SLinus Torvalds return r; 3421da177e4SLinus Torvalds 3431da177e4SLinus Torvalds header_from_disk(&log->header, log->disk_header); 3441da177e4SLinus Torvalds 3451da177e4SLinus Torvalds /* New log required? */ 3461da177e4SLinus Torvalds if (log->sync != DEFAULTSYNC || log->header.magic != MIRROR_MAGIC) { 3471da177e4SLinus Torvalds log->header.magic = MIRROR_MAGIC; 3481da177e4SLinus Torvalds log->header.version = MIRROR_DISK_VERSION; 3491da177e4SLinus Torvalds log->header.nr_regions = 0; 3501da177e4SLinus Torvalds } 3511da177e4SLinus Torvalds 352a4fc4717SPatrick Caulfield #ifdef __LITTLE_ENDIAN 353a4fc4717SPatrick Caulfield if (log->header.version == 1) 354a4fc4717SPatrick Caulfield log->header.version = 2; 355a4fc4717SPatrick Caulfield #endif 356a4fc4717SPatrick Caulfield 3571da177e4SLinus Torvalds if (log->header.version != MIRROR_DISK_VERSION) { 3581da177e4SLinus Torvalds DMWARN("incompatible disk log version"); 3591da177e4SLinus Torvalds return -EINVAL; 3601da177e4SLinus Torvalds } 3611da177e4SLinus Torvalds 3621da177e4SLinus Torvalds return 0; 3631da177e4SLinus Torvalds } 3641da177e4SLinus Torvalds 3651da177e4SLinus Torvalds static inline int write_header(struct log_c *log) 3661da177e4SLinus Torvalds { 3671da177e4SLinus Torvalds header_to_disk(&log->header, log->disk_header); 3685d234d1eSHeinz Mauelshagen return rw_header(log, WRITE); 3691da177e4SLinus Torvalds } 3701da177e4SLinus Torvalds 3711da177e4SLinus Torvalds /*---------------------------------------------------------------- 3721da177e4SLinus Torvalds * core log constructor/destructor 3731da177e4SLinus Torvalds * 3741da177e4SLinus Torvalds * argv contains region_size followed optionally by [no]sync 3751da177e4SLinus Torvalds *--------------------------------------------------------------*/ 3761da177e4SLinus Torvalds #define BYTE_SHIFT 3 377416cd17bSHeinz Mauelshagen static int create_log_context(struct dm_dirty_log *log, struct dm_target *ti, 378b7cca195SAlasdair G Kergon unsigned int argc, char **argv, 379b7cca195SAlasdair G Kergon struct dm_dev *dev) 3801da177e4SLinus Torvalds { 3811da177e4SLinus Torvalds enum sync sync = DEFAULTSYNC; 3821da177e4SLinus Torvalds 3831da177e4SLinus Torvalds struct log_c *lc; 3841da177e4SLinus Torvalds uint32_t region_size; 3851da177e4SLinus Torvalds unsigned int region_count; 386b7cca195SAlasdair G Kergon size_t bitset_size, buf_size; 3875d234d1eSHeinz Mauelshagen int r; 3881da177e4SLinus Torvalds 3891da177e4SLinus Torvalds if (argc < 1 || argc > 2) { 390b7fd54a7SHeinz Mauelshagen DMWARN("wrong number of arguments to dirty region log"); 3911da177e4SLinus Torvalds return -EINVAL; 3921da177e4SLinus Torvalds } 3931da177e4SLinus Torvalds 3941da177e4SLinus Torvalds if (argc > 1) { 3951da177e4SLinus Torvalds if (!strcmp(argv[1], "sync")) 3961da177e4SLinus Torvalds sync = FORCESYNC; 3971da177e4SLinus Torvalds else if (!strcmp(argv[1], "nosync")) 3981da177e4SLinus Torvalds sync = NOSYNC; 3991da177e4SLinus Torvalds else { 400b7fd54a7SHeinz Mauelshagen DMWARN("unrecognised sync argument to " 401b7fd54a7SHeinz Mauelshagen "dirty region log: %s", argv[1]); 4021da177e4SLinus Torvalds return -EINVAL; 4031da177e4SLinus Torvalds } 4041da177e4SLinus Torvalds } 4051da177e4SLinus Torvalds 4061da177e4SLinus Torvalds if (sscanf(argv[0], "%u", ®ion_size) != 1) { 4071da177e4SLinus Torvalds DMWARN("invalid region size string"); 4081da177e4SLinus Torvalds return -EINVAL; 4091da177e4SLinus Torvalds } 4101da177e4SLinus Torvalds 4111da177e4SLinus Torvalds region_count = dm_sector_div_up(ti->len, region_size); 4121da177e4SLinus Torvalds 4131da177e4SLinus Torvalds lc = kmalloc(sizeof(*lc), GFP_KERNEL); 4141da177e4SLinus Torvalds if (!lc) { 4151da177e4SLinus Torvalds DMWARN("couldn't allocate core log"); 4161da177e4SLinus Torvalds return -ENOMEM; 4171da177e4SLinus Torvalds } 4181da177e4SLinus Torvalds 4191da177e4SLinus Torvalds lc->ti = ti; 4201da177e4SLinus Torvalds lc->touched = 0; 4211da177e4SLinus Torvalds lc->region_size = region_size; 4221da177e4SLinus Torvalds lc->region_count = region_count; 4231da177e4SLinus Torvalds lc->sync = sync; 4241da177e4SLinus Torvalds 4251da177e4SLinus Torvalds /* 4260e56822dSAlasdair G Kergon * Work out how many "unsigned long"s we need to hold the bitset. 4271da177e4SLinus Torvalds */ 4281da177e4SLinus Torvalds bitset_size = dm_round_up(region_count, 42929121bd0SAlasdair G Kergon sizeof(*lc->clean_bits) << BYTE_SHIFT); 4301da177e4SLinus Torvalds bitset_size >>= BYTE_SHIFT; 4311da177e4SLinus Torvalds 43229121bd0SAlasdair G Kergon lc->bitset_uint32_count = bitset_size / sizeof(*lc->clean_bits); 433b7cca195SAlasdair G Kergon 434b7cca195SAlasdair G Kergon /* 435b7cca195SAlasdair G Kergon * Disk log? 436b7cca195SAlasdair G Kergon */ 437b7cca195SAlasdair G Kergon if (!dev) { 4381da177e4SLinus Torvalds lc->clean_bits = vmalloc(bitset_size); 4391da177e4SLinus Torvalds if (!lc->clean_bits) { 4401da177e4SLinus Torvalds DMWARN("couldn't allocate clean bitset"); 4411da177e4SLinus Torvalds kfree(lc); 4421da177e4SLinus Torvalds return -ENOMEM; 4431da177e4SLinus Torvalds } 444b7cca195SAlasdair G Kergon lc->disk_header = NULL; 445b7cca195SAlasdair G Kergon } else { 446b7cca195SAlasdair G Kergon lc->log_dev = dev; 44701d03a66SJonathan E Brassow lc->log_dev_failed = 0; 448b7cca195SAlasdair G Kergon lc->header_location.bdev = lc->log_dev->bdev; 449b7cca195SAlasdair G Kergon lc->header_location.sector = 0; 450b7cca195SAlasdair G Kergon 451b7cca195SAlasdair G Kergon /* 452b7cca195SAlasdair G Kergon * Buffer holds both header and bitset. 453b7cca195SAlasdair G Kergon */ 454b7cca195SAlasdair G Kergon buf_size = dm_round_up((LOG_OFFSET << SECTOR_SHIFT) + 455b7cca195SAlasdair G Kergon bitset_size, ti->limits.hardsect_size); 456b7cca195SAlasdair G Kergon lc->header_location.count = buf_size >> SECTOR_SHIFT; 4575d234d1eSHeinz Mauelshagen lc->io_req.mem.type = DM_IO_VMA; 4585d234d1eSHeinz Mauelshagen lc->io_req.client = dm_io_client_create(dm_div_up(buf_size, 4595d234d1eSHeinz Mauelshagen PAGE_SIZE)); 4605d234d1eSHeinz Mauelshagen if (IS_ERR(lc->io_req.client)) { 4615d234d1eSHeinz Mauelshagen r = PTR_ERR(lc->io_req.client); 4625d234d1eSHeinz Mauelshagen DMWARN("couldn't allocate disk io client"); 4635d234d1eSHeinz Mauelshagen kfree(lc); 4645d234d1eSHeinz Mauelshagen return -ENOMEM; 4655d234d1eSHeinz Mauelshagen } 466b7cca195SAlasdair G Kergon 467b7cca195SAlasdair G Kergon lc->disk_header = vmalloc(buf_size); 468b7cca195SAlasdair G Kergon if (!lc->disk_header) { 469b7cca195SAlasdair G Kergon DMWARN("couldn't allocate disk log buffer"); 470b7cca195SAlasdair G Kergon kfree(lc); 471b7cca195SAlasdair G Kergon return -ENOMEM; 472b7cca195SAlasdair G Kergon } 473b7cca195SAlasdair G Kergon 474b7cca195SAlasdair G Kergon lc->clean_bits = (void *)lc->disk_header + 475b7cca195SAlasdair G Kergon (LOG_OFFSET << SECTOR_SHIFT); 476b7cca195SAlasdair G Kergon } 477b7cca195SAlasdair G Kergon 4781da177e4SLinus Torvalds memset(lc->clean_bits, -1, bitset_size); 4791da177e4SLinus Torvalds 4801da177e4SLinus Torvalds lc->sync_bits = vmalloc(bitset_size); 4811da177e4SLinus Torvalds if (!lc->sync_bits) { 4821da177e4SLinus Torvalds DMWARN("couldn't allocate sync bitset"); 483b7cca195SAlasdair G Kergon if (!dev) 4841da177e4SLinus Torvalds vfree(lc->clean_bits); 485b7cca195SAlasdair G Kergon vfree(lc->disk_header); 4861da177e4SLinus Torvalds kfree(lc); 4871da177e4SLinus Torvalds return -ENOMEM; 4881da177e4SLinus Torvalds } 4891da177e4SLinus Torvalds memset(lc->sync_bits, (sync == NOSYNC) ? -1 : 0, bitset_size); 4901da177e4SLinus Torvalds lc->sync_count = (sync == NOSYNC) ? region_count : 0; 4911da177e4SLinus Torvalds 4921da177e4SLinus Torvalds lc->recovering_bits = vmalloc(bitset_size); 4931da177e4SLinus Torvalds if (!lc->recovering_bits) { 4941da177e4SLinus Torvalds DMWARN("couldn't allocate sync bitset"); 4951da177e4SLinus Torvalds vfree(lc->sync_bits); 496b7cca195SAlasdair G Kergon if (!dev) 4971da177e4SLinus Torvalds vfree(lc->clean_bits); 498b7cca195SAlasdair G Kergon vfree(lc->disk_header); 4991da177e4SLinus Torvalds kfree(lc); 5001da177e4SLinus Torvalds return -ENOMEM; 5011da177e4SLinus Torvalds } 5021da177e4SLinus Torvalds memset(lc->recovering_bits, 0, bitset_size); 5031da177e4SLinus Torvalds lc->sync_search = 0; 5041da177e4SLinus Torvalds log->context = lc; 505b7cca195SAlasdair G Kergon 5061da177e4SLinus Torvalds return 0; 5071da177e4SLinus Torvalds } 5081da177e4SLinus Torvalds 509416cd17bSHeinz Mauelshagen static int core_ctr(struct dm_dirty_log *log, struct dm_target *ti, 510b7cca195SAlasdair G Kergon unsigned int argc, char **argv) 511b7cca195SAlasdair G Kergon { 512b7cca195SAlasdair G Kergon return create_log_context(log, ti, argc, argv, NULL); 513b7cca195SAlasdair G Kergon } 514b7cca195SAlasdair G Kergon 515b7cca195SAlasdair G Kergon static void destroy_log_context(struct log_c *lc) 516b7cca195SAlasdair G Kergon { 517b7cca195SAlasdair G Kergon vfree(lc->sync_bits); 518b7cca195SAlasdair G Kergon vfree(lc->recovering_bits); 519b7cca195SAlasdair G Kergon kfree(lc); 520b7cca195SAlasdair G Kergon } 521b7cca195SAlasdair G Kergon 522416cd17bSHeinz Mauelshagen static void core_dtr(struct dm_dirty_log *log) 5231da177e4SLinus Torvalds { 5241da177e4SLinus Torvalds struct log_c *lc = (struct log_c *) log->context; 525b7cca195SAlasdair G Kergon 5261da177e4SLinus Torvalds vfree(lc->clean_bits); 527b7cca195SAlasdair G Kergon destroy_log_context(lc); 5281da177e4SLinus Torvalds } 5291da177e4SLinus Torvalds 5301da177e4SLinus Torvalds /*---------------------------------------------------------------- 5311da177e4SLinus Torvalds * disk log constructor/destructor 5321da177e4SLinus Torvalds * 5331da177e4SLinus Torvalds * argv contains log_device region_size followed optionally by [no]sync 5341da177e4SLinus Torvalds *--------------------------------------------------------------*/ 535416cd17bSHeinz Mauelshagen static int disk_ctr(struct dm_dirty_log *log, struct dm_target *ti, 5361da177e4SLinus Torvalds unsigned int argc, char **argv) 5371da177e4SLinus Torvalds { 5381da177e4SLinus Torvalds int r; 5391da177e4SLinus Torvalds struct dm_dev *dev; 5401da177e4SLinus Torvalds 5411da177e4SLinus Torvalds if (argc < 2 || argc > 3) { 542b7fd54a7SHeinz Mauelshagen DMWARN("wrong number of arguments to disk dirty region log"); 5431da177e4SLinus Torvalds return -EINVAL; 5441da177e4SLinus Torvalds } 5451da177e4SLinus Torvalds 5461da177e4SLinus Torvalds r = dm_get_device(ti, argv[0], 0, 0 /* FIXME */, 5471da177e4SLinus Torvalds FMODE_READ | FMODE_WRITE, &dev); 5481da177e4SLinus Torvalds if (r) 5491da177e4SLinus Torvalds return r; 5501da177e4SLinus Torvalds 551b7cca195SAlasdair G Kergon r = create_log_context(log, ti, argc - 1, argv + 1, dev); 5521da177e4SLinus Torvalds if (r) { 5531da177e4SLinus Torvalds dm_put_device(ti, dev); 5541da177e4SLinus Torvalds return r; 5551da177e4SLinus Torvalds } 5561da177e4SLinus Torvalds 5571da177e4SLinus Torvalds return 0; 5581da177e4SLinus Torvalds } 5591da177e4SLinus Torvalds 560416cd17bSHeinz Mauelshagen static void disk_dtr(struct dm_dirty_log *log) 5611da177e4SLinus Torvalds { 5621da177e4SLinus Torvalds struct log_c *lc = (struct log_c *) log->context; 563b7cca195SAlasdair G Kergon 5641da177e4SLinus Torvalds dm_put_device(lc->ti, lc->log_dev); 5651da177e4SLinus Torvalds vfree(lc->disk_header); 5665d234d1eSHeinz Mauelshagen dm_io_client_destroy(lc->io_req.client); 567b7cca195SAlasdair G Kergon destroy_log_context(lc); 5681da177e4SLinus Torvalds } 5691da177e4SLinus Torvalds 5701da177e4SLinus Torvalds static int count_bits32(uint32_t *addr, unsigned size) 5711da177e4SLinus Torvalds { 5721da177e4SLinus Torvalds int count = 0, i; 5731da177e4SLinus Torvalds 5741da177e4SLinus Torvalds for (i = 0; i < size; i++) { 5751da177e4SLinus Torvalds count += hweight32(*(addr+i)); 5761da177e4SLinus Torvalds } 5771da177e4SLinus Torvalds return count; 5781da177e4SLinus Torvalds } 5791da177e4SLinus Torvalds 58001d03a66SJonathan E Brassow static void fail_log_device(struct log_c *lc) 58101d03a66SJonathan E Brassow { 58201d03a66SJonathan E Brassow if (lc->log_dev_failed) 58301d03a66SJonathan E Brassow return; 58401d03a66SJonathan E Brassow 58501d03a66SJonathan E Brassow lc->log_dev_failed = 1; 58601d03a66SJonathan E Brassow dm_table_event(lc->ti->table); 58701d03a66SJonathan E Brassow } 58801d03a66SJonathan E Brassow 589416cd17bSHeinz Mauelshagen static int disk_resume(struct dm_dirty_log *log) 5901da177e4SLinus Torvalds { 5911da177e4SLinus Torvalds int r; 5921da177e4SLinus Torvalds unsigned i; 5931da177e4SLinus Torvalds struct log_c *lc = (struct log_c *) log->context; 5941da177e4SLinus Torvalds size_t size = lc->bitset_uint32_count * sizeof(uint32_t); 5951da177e4SLinus Torvalds 5961da177e4SLinus Torvalds /* read the disk header */ 5971da177e4SLinus Torvalds r = read_header(lc); 59801d03a66SJonathan E Brassow if (r) { 599b7fd54a7SHeinz Mauelshagen DMWARN("%s: Failed to read header on dirty region log device", 60001d03a66SJonathan E Brassow lc->log_dev->name); 60101d03a66SJonathan E Brassow fail_log_device(lc); 602ba8b45ceSJonathan Brassow /* 603ba8b45ceSJonathan Brassow * If the log device cannot be read, we must assume 604ba8b45ceSJonathan Brassow * all regions are out-of-sync. If we simply return 605ba8b45ceSJonathan Brassow * here, the state will be uninitialized and could 606ba8b45ceSJonathan Brassow * lead us to return 'in-sync' status for regions 607ba8b45ceSJonathan Brassow * that are actually 'out-of-sync'. 608ba8b45ceSJonathan Brassow */ 609ba8b45ceSJonathan Brassow lc->header.nr_regions = 0; 61001d03a66SJonathan E Brassow } 6111da177e4SLinus Torvalds 6128a835f11SAlasdair G Kergon /* set or clear any new bits -- device has grown */ 6131da177e4SLinus Torvalds if (lc->sync == NOSYNC) 6141da177e4SLinus Torvalds for (i = lc->header.nr_regions; i < lc->region_count; i++) 6151da177e4SLinus Torvalds /* FIXME: amazingly inefficient */ 6161da177e4SLinus Torvalds log_set_bit(lc, lc->clean_bits, i); 6171da177e4SLinus Torvalds else 6181da177e4SLinus Torvalds for (i = lc->header.nr_regions; i < lc->region_count; i++) 6191da177e4SLinus Torvalds /* FIXME: amazingly inefficient */ 6201da177e4SLinus Torvalds log_clear_bit(lc, lc->clean_bits, i); 6211da177e4SLinus Torvalds 6228a835f11SAlasdair G Kergon /* clear any old bits -- device has shrunk */ 6238a835f11SAlasdair G Kergon for (i = lc->region_count; i % (sizeof(*lc->clean_bits) << BYTE_SHIFT); i++) 6248a835f11SAlasdair G Kergon log_clear_bit(lc, lc->clean_bits, i); 6258a835f11SAlasdair G Kergon 6261da177e4SLinus Torvalds /* copy clean across to sync */ 6271da177e4SLinus Torvalds memcpy(lc->sync_bits, lc->clean_bits, size); 6281da177e4SLinus Torvalds lc->sync_count = count_bits32(lc->clean_bits, lc->bitset_uint32_count); 62988b20a1aSJonathan E Brassow lc->sync_search = 0; 6301da177e4SLinus Torvalds 6311da177e4SLinus Torvalds /* set the correct number of regions in the header */ 6321da177e4SLinus Torvalds lc->header.nr_regions = lc->region_count; 6331da177e4SLinus Torvalds 6341da177e4SLinus Torvalds /* write the new header */ 63501d03a66SJonathan E Brassow r = write_header(lc); 63601d03a66SJonathan E Brassow if (r) { 637b7fd54a7SHeinz Mauelshagen DMWARN("%s: Failed to write header on dirty region log device", 63801d03a66SJonathan E Brassow lc->log_dev->name); 63901d03a66SJonathan E Brassow fail_log_device(lc); 64001d03a66SJonathan E Brassow } 64101d03a66SJonathan E Brassow 64201d03a66SJonathan E Brassow return r; 6431da177e4SLinus Torvalds } 6441da177e4SLinus Torvalds 645416cd17bSHeinz Mauelshagen static uint32_t core_get_region_size(struct dm_dirty_log *log) 6461da177e4SLinus Torvalds { 6471da177e4SLinus Torvalds struct log_c *lc = (struct log_c *) log->context; 6481da177e4SLinus Torvalds return lc->region_size; 6491da177e4SLinus Torvalds } 6501da177e4SLinus Torvalds 651416cd17bSHeinz Mauelshagen static int core_resume(struct dm_dirty_log *log) 65288b20a1aSJonathan E Brassow { 65388b20a1aSJonathan E Brassow struct log_c *lc = (struct log_c *) log->context; 65488b20a1aSJonathan E Brassow lc->sync_search = 0; 65588b20a1aSJonathan E Brassow return 0; 65688b20a1aSJonathan E Brassow } 65788b20a1aSJonathan E Brassow 658416cd17bSHeinz Mauelshagen static int core_is_clean(struct dm_dirty_log *log, region_t region) 6591da177e4SLinus Torvalds { 6601da177e4SLinus Torvalds struct log_c *lc = (struct log_c *) log->context; 6611da177e4SLinus Torvalds return log_test_bit(lc->clean_bits, region); 6621da177e4SLinus Torvalds } 6631da177e4SLinus Torvalds 664416cd17bSHeinz Mauelshagen static int core_in_sync(struct dm_dirty_log *log, region_t region, int block) 6651da177e4SLinus Torvalds { 6661da177e4SLinus Torvalds struct log_c *lc = (struct log_c *) log->context; 6671da177e4SLinus Torvalds return log_test_bit(lc->sync_bits, region); 6681da177e4SLinus Torvalds } 6691da177e4SLinus Torvalds 670416cd17bSHeinz Mauelshagen static int core_flush(struct dm_dirty_log *log) 6711da177e4SLinus Torvalds { 6721da177e4SLinus Torvalds /* no op */ 6731da177e4SLinus Torvalds return 0; 6741da177e4SLinus Torvalds } 6751da177e4SLinus Torvalds 676416cd17bSHeinz Mauelshagen static int disk_flush(struct dm_dirty_log *log) 6771da177e4SLinus Torvalds { 6781da177e4SLinus Torvalds int r; 6791da177e4SLinus Torvalds struct log_c *lc = (struct log_c *) log->context; 6801da177e4SLinus Torvalds 6811da177e4SLinus Torvalds /* only write if the log has changed */ 6821da177e4SLinus Torvalds if (!lc->touched) 6831da177e4SLinus Torvalds return 0; 6841da177e4SLinus Torvalds 685702ca6f0SKevin Corry r = write_header(lc); 68601d03a66SJonathan E Brassow if (r) 68701d03a66SJonathan E Brassow fail_log_device(lc); 68801d03a66SJonathan E Brassow else 6891da177e4SLinus Torvalds lc->touched = 0; 6901da177e4SLinus Torvalds 6911da177e4SLinus Torvalds return r; 6921da177e4SLinus Torvalds } 6931da177e4SLinus Torvalds 694416cd17bSHeinz Mauelshagen static void core_mark_region(struct dm_dirty_log *log, region_t region) 6951da177e4SLinus Torvalds { 6961da177e4SLinus Torvalds struct log_c *lc = (struct log_c *) log->context; 6971da177e4SLinus Torvalds log_clear_bit(lc, lc->clean_bits, region); 6981da177e4SLinus Torvalds } 6991da177e4SLinus Torvalds 700416cd17bSHeinz Mauelshagen static void core_clear_region(struct dm_dirty_log *log, region_t region) 7011da177e4SLinus Torvalds { 7021da177e4SLinus Torvalds struct log_c *lc = (struct log_c *) log->context; 7031da177e4SLinus Torvalds log_set_bit(lc, lc->clean_bits, region); 7041da177e4SLinus Torvalds } 7051da177e4SLinus Torvalds 706416cd17bSHeinz Mauelshagen static int core_get_resync_work(struct dm_dirty_log *log, region_t *region) 7071da177e4SLinus Torvalds { 7081da177e4SLinus Torvalds struct log_c *lc = (struct log_c *) log->context; 7091da177e4SLinus Torvalds 7101da177e4SLinus Torvalds if (lc->sync_search >= lc->region_count) 7111da177e4SLinus Torvalds return 0; 7121da177e4SLinus Torvalds 7131da177e4SLinus Torvalds do { 7141113a7e9SStefan Bader *region = ext2_find_next_zero_bit( 7151113a7e9SStefan Bader (unsigned long *) lc->sync_bits, 7161da177e4SLinus Torvalds lc->region_count, 7171da177e4SLinus Torvalds lc->sync_search); 7181da177e4SLinus Torvalds lc->sync_search = *region + 1; 7191da177e4SLinus Torvalds 720ac81b2eeSDarrick J. Wong if (*region >= lc->region_count) 7211da177e4SLinus Torvalds return 0; 7221da177e4SLinus Torvalds 7231da177e4SLinus Torvalds } while (log_test_bit(lc->recovering_bits, *region)); 7241da177e4SLinus Torvalds 7251da177e4SLinus Torvalds log_set_bit(lc, lc->recovering_bits, *region); 7261da177e4SLinus Torvalds return 1; 7271da177e4SLinus Torvalds } 7281da177e4SLinus Torvalds 729416cd17bSHeinz Mauelshagen static void core_set_region_sync(struct dm_dirty_log *log, region_t region, 730f3ee6b2fSJonathan E Brassow int in_sync) 7311da177e4SLinus Torvalds { 7321da177e4SLinus Torvalds struct log_c *lc = (struct log_c *) log->context; 7331da177e4SLinus Torvalds 7341da177e4SLinus Torvalds log_clear_bit(lc, lc->recovering_bits, region); 735f3ee6b2fSJonathan E Brassow if (in_sync) { 7361da177e4SLinus Torvalds log_set_bit(lc, lc->sync_bits, region); 7371da177e4SLinus Torvalds lc->sync_count++; 738f3ee6b2fSJonathan E Brassow } else if (log_test_bit(lc->sync_bits, region)) { 739f3ee6b2fSJonathan E Brassow lc->sync_count--; 740f3ee6b2fSJonathan E Brassow log_clear_bit(lc, lc->sync_bits, region); 7411da177e4SLinus Torvalds } 7421da177e4SLinus Torvalds } 7431da177e4SLinus Torvalds 744416cd17bSHeinz Mauelshagen static region_t core_get_sync_count(struct dm_dirty_log *log) 7451da177e4SLinus Torvalds { 7461da177e4SLinus Torvalds struct log_c *lc = (struct log_c *) log->context; 7471da177e4SLinus Torvalds 7481da177e4SLinus Torvalds return lc->sync_count; 7491da177e4SLinus Torvalds } 7501da177e4SLinus Torvalds 7511da177e4SLinus Torvalds #define DMEMIT_SYNC \ 7521da177e4SLinus Torvalds if (lc->sync != DEFAULTSYNC) \ 7531da177e4SLinus Torvalds DMEMIT("%ssync ", lc->sync == NOSYNC ? "no" : "") 7541da177e4SLinus Torvalds 755416cd17bSHeinz Mauelshagen static int core_status(struct dm_dirty_log *log, status_type_t status, 7561da177e4SLinus Torvalds char *result, unsigned int maxlen) 7571da177e4SLinus Torvalds { 7581da177e4SLinus Torvalds int sz = 0; 7591da177e4SLinus Torvalds struct log_c *lc = log->context; 7601da177e4SLinus Torvalds 7611da177e4SLinus Torvalds switch(status) { 7621da177e4SLinus Torvalds case STATUSTYPE_INFO: 763315dcc22SJonathan E Brassow DMEMIT("1 %s", log->type->name); 7641da177e4SLinus Torvalds break; 7651da177e4SLinus Torvalds 7661da177e4SLinus Torvalds case STATUSTYPE_TABLE: 7671da177e4SLinus Torvalds DMEMIT("%s %u %u ", log->type->name, 7681da177e4SLinus Torvalds lc->sync == DEFAULTSYNC ? 1 : 2, lc->region_size); 7691da177e4SLinus Torvalds DMEMIT_SYNC; 7701da177e4SLinus Torvalds } 7711da177e4SLinus Torvalds 7721da177e4SLinus Torvalds return sz; 7731da177e4SLinus Torvalds } 7741da177e4SLinus Torvalds 775416cd17bSHeinz Mauelshagen static int disk_status(struct dm_dirty_log *log, status_type_t status, 7761da177e4SLinus Torvalds char *result, unsigned int maxlen) 7771da177e4SLinus Torvalds { 7781da177e4SLinus Torvalds int sz = 0; 7791da177e4SLinus Torvalds struct log_c *lc = log->context; 7801da177e4SLinus Torvalds 7811da177e4SLinus Torvalds switch(status) { 7821da177e4SLinus Torvalds case STATUSTYPE_INFO: 783315dcc22SJonathan E Brassow DMEMIT("3 %s %s %c", log->type->name, lc->log_dev->name, 784315dcc22SJonathan E Brassow lc->log_dev_failed ? 'D' : 'A'); 7851da177e4SLinus Torvalds break; 7861da177e4SLinus Torvalds 7871da177e4SLinus Torvalds case STATUSTYPE_TABLE: 7881da177e4SLinus Torvalds DMEMIT("%s %u %s %u ", log->type->name, 789315dcc22SJonathan E Brassow lc->sync == DEFAULTSYNC ? 2 : 3, lc->log_dev->name, 7901da177e4SLinus Torvalds lc->region_size); 7911da177e4SLinus Torvalds DMEMIT_SYNC; 7921da177e4SLinus Torvalds } 7931da177e4SLinus Torvalds 7941da177e4SLinus Torvalds return sz; 7951da177e4SLinus Torvalds } 7961da177e4SLinus Torvalds 797416cd17bSHeinz Mauelshagen static struct dm_dirty_log_type _core_type = { 7981da177e4SLinus Torvalds .name = "core", 7991da177e4SLinus Torvalds .module = THIS_MODULE, 8001da177e4SLinus Torvalds .ctr = core_ctr, 8011da177e4SLinus Torvalds .dtr = core_dtr, 80288b20a1aSJonathan E Brassow .resume = core_resume, 8031da177e4SLinus Torvalds .get_region_size = core_get_region_size, 8041da177e4SLinus Torvalds .is_clean = core_is_clean, 8051da177e4SLinus Torvalds .in_sync = core_in_sync, 8061da177e4SLinus Torvalds .flush = core_flush, 8071da177e4SLinus Torvalds .mark_region = core_mark_region, 8081da177e4SLinus Torvalds .clear_region = core_clear_region, 8091da177e4SLinus Torvalds .get_resync_work = core_get_resync_work, 810f3ee6b2fSJonathan E Brassow .set_region_sync = core_set_region_sync, 8111da177e4SLinus Torvalds .get_sync_count = core_get_sync_count, 8121da177e4SLinus Torvalds .status = core_status, 8131da177e4SLinus Torvalds }; 8141da177e4SLinus Torvalds 815416cd17bSHeinz Mauelshagen static struct dm_dirty_log_type _disk_type = { 8161da177e4SLinus Torvalds .name = "disk", 8171da177e4SLinus Torvalds .module = THIS_MODULE, 8181da177e4SLinus Torvalds .ctr = disk_ctr, 8191da177e4SLinus Torvalds .dtr = disk_dtr, 8206b3df0d7SJonathan Brassow .postsuspend = disk_flush, 8211da177e4SLinus Torvalds .resume = disk_resume, 8221da177e4SLinus Torvalds .get_region_size = core_get_region_size, 8231da177e4SLinus Torvalds .is_clean = core_is_clean, 8241da177e4SLinus Torvalds .in_sync = core_in_sync, 8251da177e4SLinus Torvalds .flush = disk_flush, 8261da177e4SLinus Torvalds .mark_region = core_mark_region, 8271da177e4SLinus Torvalds .clear_region = core_clear_region, 8281da177e4SLinus Torvalds .get_resync_work = core_get_resync_work, 829f3ee6b2fSJonathan E Brassow .set_region_sync = core_set_region_sync, 8301da177e4SLinus Torvalds .get_sync_count = core_get_sync_count, 8311da177e4SLinus Torvalds .status = disk_status, 8321da177e4SLinus Torvalds }; 8331da177e4SLinus Torvalds 8341da177e4SLinus Torvalds int __init dm_dirty_log_init(void) 8351da177e4SLinus Torvalds { 8361da177e4SLinus Torvalds int r; 8371da177e4SLinus Torvalds 838416cd17bSHeinz Mauelshagen r = dm_dirty_log_type_register(&_core_type); 8391da177e4SLinus Torvalds if (r) 8401da177e4SLinus Torvalds DMWARN("couldn't register core log"); 8411da177e4SLinus Torvalds 842416cd17bSHeinz Mauelshagen r = dm_dirty_log_type_register(&_disk_type); 8431da177e4SLinus Torvalds if (r) { 8441da177e4SLinus Torvalds DMWARN("couldn't register disk type"); 845416cd17bSHeinz Mauelshagen dm_dirty_log_type_unregister(&_core_type); 8461da177e4SLinus Torvalds } 8471da177e4SLinus Torvalds 8481da177e4SLinus Torvalds return r; 8491da177e4SLinus Torvalds } 8501da177e4SLinus Torvalds 851769aef30SHeinz Mauelshagen void __exit dm_dirty_log_exit(void) 8521da177e4SLinus Torvalds { 853416cd17bSHeinz Mauelshagen dm_dirty_log_type_unregister(&_disk_type); 854416cd17bSHeinz Mauelshagen dm_dirty_log_type_unregister(&_core_type); 8551da177e4SLinus Torvalds } 8561da177e4SLinus Torvalds 857769aef30SHeinz Mauelshagen module_init(dm_dirty_log_init); 858769aef30SHeinz Mauelshagen module_exit(dm_dirty_log_exit); 859769aef30SHeinz Mauelshagen 860769aef30SHeinz Mauelshagen MODULE_DESCRIPTION(DM_NAME " dirty region log"); 861769aef30SHeinz Mauelshagen MODULE_AUTHOR("Joe Thornber, Heinz Mauelshagen <dm-devel@redhat.com>"); 862769aef30SHeinz Mauelshagen MODULE_LICENSE("GPL"); 863