diff options
Diffstat (limited to 'drivers')
-rw-r--r-- | drivers/md/dm-exception-store.c | 162 | ||||
-rw-r--r-- | drivers/md/dm-exception-store.h | 19 | ||||
-rw-r--r-- | drivers/md/dm-snap-persistent.c | 67 | ||||
-rw-r--r-- | drivers/md/dm-snap-transient.c | 65 | ||||
-rw-r--r-- | drivers/md/dm-snap.c | 41 | ||||
-rw-r--r-- | drivers/md/dm-snap.h | 2 |
6 files changed, 307 insertions, 49 deletions
diff --git a/drivers/md/dm-exception-store.c b/drivers/md/dm-exception-store.c index dccbfb0e010f..8912a3637cae 100644 --- a/drivers/md/dm-exception-store.c +++ b/drivers/md/dm-exception-store.c @@ -14,6 +14,168 @@ #define DM_MSG_PREFIX "snapshot exception stores" +static LIST_HEAD(_exception_store_types); +static DEFINE_SPINLOCK(_lock); + +static struct dm_exception_store_type *__find_exception_store_type(const char *name) +{ + struct dm_exception_store_type *type; + + list_for_each_entry(type, &_exception_store_types, list) + if (!strcmp(name, type->name)) + return type; + + return NULL; +} + +static struct dm_exception_store_type *_get_exception_store_type(const char *name) +{ + struct dm_exception_store_type *type; + + spin_lock(&_lock); + + type = __find_exception_store_type(name); + + if (type && !try_module_get(type->module)) + type = NULL; + + spin_unlock(&_lock); + + return type; +} + +/* + * get_type + * @type_name + * + * Attempt to retrieve the dm_exception_store_type by name. If not already + * available, attempt to load the appropriate module. + * + * Exstore modules are named "dm-exstore-" followed by the 'type_name'. + * Modules may contain multiple types. + * This function will first try the module "dm-exstore-<type_name>", + * then truncate 'type_name' on the last '-' and try again. + * + * For example, if type_name was "clustered-shared", it would search + * 'dm-exstore-clustered-shared' then 'dm-exstore-clustered'. + * + * 'dm-exception-store-<type_name>' is too long of a name in my + * opinion, which is why I've chosen to have the files + * containing exception store implementations be 'dm-exstore-<type_name>'. + * If you want your module to be autoloaded, you will follow this + * naming convention. + * + * Returns: dm_exception_store_type* on success, NULL on failure + */ +static struct dm_exception_store_type *get_type(const char *type_name) +{ + char *p, *type_name_dup; + struct dm_exception_store_type *type; + + type = _get_exception_store_type(type_name); + if (type) + return type; + + type_name_dup = kstrdup(type_name, GFP_KERNEL); + if (!type_name_dup) { + DMERR("No memory left to attempt load for \"%s\"", type_name); + return NULL; + } + + while (request_module("dm-exstore-%s", type_name_dup) || + !(type = _get_exception_store_type(type_name))) { + p = strrchr(type_name_dup, '-'); + if (!p) + break; + p[0] = '\0'; + } + + if (!type) + DMWARN("Module for exstore type \"%s\" not found.", type_name); + + kfree(type_name_dup); + + return type; +} + +static void put_type(struct dm_exception_store_type *type) +{ + spin_lock(&_lock); + module_put(type->module); + spin_unlock(&_lock); +} + +int dm_exception_store_type_register(struct dm_exception_store_type *type) +{ + int r = 0; + + spin_lock(&_lock); + if (!__find_exception_store_type(type->name)) + list_add(&type->list, &_exception_store_types); + else + r = -EEXIST; + spin_unlock(&_lock); + + return r; +} +EXPORT_SYMBOL(dm_exception_store_type_register); + +int dm_exception_store_type_unregister(struct dm_exception_store_type *type) +{ + spin_lock(&_lock); + + if (!__find_exception_store_type(type->name)) { + spin_unlock(&_lock); + return -EINVAL; + } + + list_del(&type->list); + + spin_unlock(&_lock); + + return 0; +} +EXPORT_SYMBOL(dm_exception_store_type_unregister); + +int dm_exception_store_create(const char *type_name, + struct dm_exception_store **store) +{ + int r = 0; + struct dm_exception_store_type *type; + struct dm_exception_store *tmp_store; + + tmp_store = kmalloc(sizeof(*tmp_store), GFP_KERNEL); + if (!tmp_store) + return -ENOMEM; + + type = get_type(type_name); + if (!type) { + kfree(tmp_store); + return -EINVAL; + } + + tmp_store->type = type; + + r = type->ctr(tmp_store, 0, NULL); + if (r) { + put_type(type); + kfree(tmp_store); + return r; + } + + *store = tmp_store; + return 0; +} +EXPORT_SYMBOL(dm_exception_store_create); + +void dm_exception_store_destroy(struct dm_exception_store *store) +{ + store->type->dtr(store); + put_type(store->type); + kfree(store); +} +EXPORT_SYMBOL(dm_exception_store_destroy); + int dm_exception_store_init(void) { int r; diff --git a/drivers/md/dm-exception-store.h b/drivers/md/dm-exception-store.h index aed1f1172f9e..31377150080e 100644 --- a/drivers/md/dm-exception-store.h +++ b/drivers/md/dm-exception-store.h @@ -39,6 +39,9 @@ struct dm_snap_exception { */ struct dm_exception_store; struct dm_exception_store_type { + const char *name; + struct module *module; + int (*ctr) (struct dm_exception_store *store, unsigned argc, char **argv); @@ -85,10 +88,13 @@ struct dm_exception_store_type { void (*fraction_full) (struct dm_exception_store *store, sector_t *numerator, sector_t *denominator); + + /* For internal device-mapper use only. */ + struct list_head list; }; struct dm_exception_store { - struct dm_exception_store_type type; + struct dm_exception_store_type *type; struct dm_snapshot *snap; @@ -138,6 +144,13 @@ static inline void dm_consecutive_chunk_count_inc(struct dm_snap_exception *e) # endif +int dm_exception_store_type_register(struct dm_exception_store_type *type); +int dm_exception_store_type_unregister(struct dm_exception_store_type *type); + +int dm_exception_store_create(const char *type_name, + struct dm_exception_store **store); +void dm_exception_store_destroy(struct dm_exception_store *store); + int dm_exception_store_init(void); void dm_exception_store_exit(void); @@ -150,8 +163,4 @@ void dm_persistent_snapshot_exit(void); int dm_transient_snapshot_init(void); void dm_transient_snapshot_exit(void); -int dm_create_persistent(struct dm_exception_store *store); - -int dm_create_transient(struct dm_exception_store *store); - #endif /* _LINUX_DM_EXCEPTION_STORE */ diff --git a/drivers/md/dm-snap-persistent.c b/drivers/md/dm-snap-persistent.c index 0bbbe3b7431e..e85b7a186a13 100644 --- a/drivers/md/dm-snap-persistent.c +++ b/drivers/md/dm-snap-persistent.c @@ -478,7 +478,7 @@ static void persistent_fraction_full(struct dm_exception_store *store, *denominator = get_dev_size(store->snap->cow->bdev); } -static void persistent_destroy(struct dm_exception_store *store) +static void persistent_dtr(struct dm_exception_store *store) { struct pstore *ps = get_info(store); @@ -656,7 +656,8 @@ static void persistent_drop_snapshot(struct dm_exception_store *store) DMWARN("write header failed"); } -int dm_create_persistent(struct dm_exception_store *store) +static int persistent_ctr(struct dm_exception_store *store, + unsigned argc, char **argv) { struct pstore *ps; @@ -683,23 +684,69 @@ int dm_create_persistent(struct dm_exception_store *store) return -ENOMEM; } - store->type.dtr = persistent_destroy; - store->type.read_metadata = persistent_read_metadata; - store->type.prepare_exception = persistent_prepare_exception; - store->type.commit_exception = persistent_commit_exception; - store->type.drop_snapshot = persistent_drop_snapshot; - store->type.fraction_full = persistent_fraction_full; - store->context = ps; return 0; } +static int persistent_status(struct dm_exception_store *store, + status_type_t status, char *result, + unsigned int maxlen) +{ + int sz = 0; + + return sz; +} + +static struct dm_exception_store_type _persistent_type = { + .name = "persistent", + .module = THIS_MODULE, + .ctr = persistent_ctr, + .dtr = persistent_dtr, + .read_metadata = persistent_read_metadata, + .prepare_exception = persistent_prepare_exception, + .commit_exception = persistent_commit_exception, + .drop_snapshot = persistent_drop_snapshot, + .fraction_full = persistent_fraction_full, + .status = persistent_status, +}; + +static struct dm_exception_store_type _persistent_compat_type = { + .name = "P", + .module = THIS_MODULE, + .ctr = persistent_ctr, + .dtr = persistent_dtr, + .read_metadata = persistent_read_metadata, + .prepare_exception = persistent_prepare_exception, + .commit_exception = persistent_commit_exception, + .drop_snapshot = persistent_drop_snapshot, + .fraction_full = persistent_fraction_full, + .status = persistent_status, +}; + int dm_persistent_snapshot_init(void) { - return 0; + int r; + + r = dm_exception_store_type_register(&_persistent_type); + if (r) { + DMERR("Unable to register persistent exception store type"); + return r; + } + + r = dm_exception_store_type_register(&_persistent_compat_type); + if (r) { + DMERR("Unable to register old-style persistent exception " + "store type"); + dm_exception_store_type_unregister(&_persistent_type); + return r; + } + + return r; } void dm_persistent_snapshot_exit(void) { + dm_exception_store_type_unregister(&_persistent_type); + dm_exception_store_type_unregister(&_persistent_compat_type); } diff --git a/drivers/md/dm-snap-transient.c b/drivers/md/dm-snap-transient.c index b558176ff020..51bc4a78ce9a 100644 --- a/drivers/md/dm-snap-transient.c +++ b/drivers/md/dm-snap-transient.c @@ -23,7 +23,7 @@ struct transient_c { sector_t next_free; }; -static void transient_destroy(struct dm_exception_store *store) +static void transient_dtr(struct dm_exception_store *store) { kfree(store->context); } @@ -67,17 +67,11 @@ static void transient_fraction_full(struct dm_exception_store *store, *denominator = get_dev_size(store->snap->cow->bdev); } -int dm_create_transient(struct dm_exception_store *store) +static int transient_ctr(struct dm_exception_store *store, + unsigned argc, char **argv) { struct transient_c *tc; - store->type.dtr = transient_destroy; - store->type.read_metadata = transient_read_metadata; - store->type.prepare_exception = transient_prepare_exception; - store->type.commit_exception = transient_commit_exception; - store->type.drop_snapshot = NULL; - store->type.fraction_full = transient_fraction_full; - tc = kmalloc(sizeof(struct transient_c), GFP_KERNEL); if (!tc) return -ENOMEM; @@ -88,11 +82,62 @@ int dm_create_transient(struct dm_exception_store *store) return 0; } +static int transient_status(struct dm_exception_store *store, + status_type_t status, char *result, + unsigned maxlen) +{ + int sz = 0; + + return sz; +} + +static struct dm_exception_store_type _transient_type = { + .name = "transient", + .module = THIS_MODULE, + .ctr = transient_ctr, + .dtr = transient_dtr, + .read_metadata = transient_read_metadata, + .prepare_exception = transient_prepare_exception, + .commit_exception = transient_commit_exception, + .fraction_full = transient_fraction_full, + .status = transient_status, +}; + +static struct dm_exception_store_type _transient_compat_type = { + .name = "N", + .module = THIS_MODULE, + .ctr = transient_ctr, + .dtr = transient_dtr, + .read_metadata = transient_read_metadata, + .prepare_exception = transient_prepare_exception, + .commit_exception = transient_commit_exception, + .fraction_full = transient_fraction_full, + .status = transient_status, +}; + int dm_transient_snapshot_init(void) { - return 0; + int r; + + r = dm_exception_store_type_register(&_transient_type); + if (r) { + DMWARN("Unable to register transient exception store type"); + return r; + } + + r = dm_exception_store_type_register(&_transient_compat_type); + if (r) { + DMWARN("Unable to register old-style transient " + "exception store type"); + dm_exception_store_type_unregister(&_transient_type); + return r; + } + + return r; } void dm_transient_snapshot_exit(void) { + dm_exception_store_type_unregister(&_transient_type); + dm_exception_store_type_unregister(&_transient_compat_type); } diff --git a/drivers/md/dm-snap.c b/drivers/md/dm-snap.c index dabd58e9aafc..be698f3a4ae4 100644 --- a/drivers/md/dm-snap.c +++ b/drivers/md/dm-snap.c @@ -610,8 +610,6 @@ static int snapshot_ctr(struct dm_target *ti, unsigned int argc, char **argv) if (r) goto bad3; - s->type = persistent; - s->valid = 1; s->active = 0; atomic_set(&s->pending_exceptions_count, 0); @@ -626,19 +624,15 @@ static int snapshot_ctr(struct dm_target *ti, unsigned int argc, char **argv) goto bad3; } - s->store.snap = s; - - if (persistent == 'P') - r = dm_create_persistent(&s->store); - else - r = dm_create_transient(&s->store); - + r = dm_exception_store_create(argv[2], &s->store); if (r) { ti->error = "Couldn't create exception store"; r = -EINVAL; goto bad4; } + s->store->snap = s; + r = dm_kcopyd_client_create(SNAPSHOT_PAGES, &s->kcopyd_client); if (r) { ti->error = "Could not create kcopyd client"; @@ -665,7 +659,8 @@ static int snapshot_ctr(struct dm_target *ti, unsigned int argc, char **argv) spin_lock_init(&s->tracked_chunk_lock); /* Metadata must only be loaded into one table at once */ - r = s->store.type.read_metadata(&s->store, dm_add_exception, (void *)s); + r = s->store->type->read_metadata(s->store, dm_add_exception, + (void *)s); if (r < 0) { ti->error = "Failed to read snapshot metadata"; goto bad_load_and_register; @@ -700,7 +695,7 @@ static int snapshot_ctr(struct dm_target *ti, unsigned int argc, char **argv) dm_kcopyd_client_destroy(s->kcopyd_client); bad5: - s->store.type.dtr(&s->store); + s->store->type->dtr(s->store); bad4: exit_exception_table(&s->pending, pending_cache); @@ -725,7 +720,7 @@ static void __free_exceptions(struct dm_snapshot *s) exit_exception_table(&s->pending, pending_cache); exit_exception_table(&s->complete, exception_cache); - s->store.type.dtr(&s->store); + s->store->type->dtr(s->store); } static void snapshot_dtr(struct dm_target *ti) @@ -820,8 +815,8 @@ static void __invalidate_snapshot(struct dm_snapshot *s, int err) else if (err == -ENOMEM) DMERR("Invalidating snapshot: Unable to allocate exception."); - if (s->store.type.drop_snapshot) - s->store.type.drop_snapshot(&s->store); + if (s->store->type->drop_snapshot) + s->store->type->drop_snapshot(s->store); s->valid = 0; @@ -943,8 +938,8 @@ static void copy_callback(int read_err, unsigned long write_err, void *context) else /* Update the metadata if we are persistent */ - s->store.type.commit_exception(&s->store, &pe->e, - commit_callback, pe); + s->store->type->commit_exception(s->store, &pe->e, + commit_callback, pe); } /* @@ -1010,7 +1005,7 @@ __find_pending_exception(struct dm_snapshot *s, atomic_set(&pe->ref_count, 0); pe->started = 0; - if (s->store.type.prepare_exception(&s->store, &pe->e)) { + if (s->store->type->prepare_exception(s->store, &pe->e)) { free_pending_exception(pe); return NULL; } @@ -1149,11 +1144,11 @@ static int snapshot_status(struct dm_target *ti, status_type_t type, if (!snap->valid) snprintf(result, maxlen, "Invalid"); else { - if (snap->store.type.fraction_full) { + if (snap->store->type->fraction_full) { sector_t numerator, denominator; - snap->store.type.fraction_full(&snap->store, - &numerator, - &denominator); + snap->store->type->fraction_full(snap->store, + &numerator, + &denominator); snprintf(result, maxlen, "%llu/%llu", (unsigned long long)numerator, (unsigned long long)denominator); @@ -1169,9 +1164,9 @@ static int snapshot_status(struct dm_target *ti, status_type_t type, * to make private copies if the output is to * make sense. */ - snprintf(result, maxlen, "%s %s %c %llu", + snprintf(result, maxlen, "%s %s %s %llu", snap->origin->name, snap->cow->name, - snap->type, + snap->store->type->name, (unsigned long long)snap->chunk_size); break; } diff --git a/drivers/md/dm-snap.h b/drivers/md/dm-snap.h index d9e62b43cf85..627be0f52c32 100644 --- a/drivers/md/dm-snap.h +++ b/drivers/md/dm-snap.h @@ -61,7 +61,7 @@ struct dm_snapshot { spinlock_t pe_lock; /* The on disk metadata handler */ - struct dm_exception_store store; + struct dm_exception_store *store; struct dm_kcopyd_client *kcopyd_client; |