From 71a16736a15e3fd11d283c42aa86bf704f6d25ff Mon Sep 17 00:00:00 2001 From: Namhyung Kim Date: Mon, 31 Oct 2011 20:18:54 +0000 Subject: dm: use local printk ratelimit printk_ratelimit() shares global ratelimiting state with all other subsystems, so its usage is discouraged. Instead, define and use dm's local state. Signed-off-by: Namhyung Kim Signed-off-by: Alasdair G Kergon --- include/linux/device-mapper.h | 17 +++++++++++++---- 1 file changed, 13 insertions(+), 4 deletions(-) (limited to 'include/linux') diff --git a/include/linux/device-mapper.h b/include/linux/device-mapper.h index 99e3e50b5c57..622678ccb5e0 100644 --- a/include/linux/device-mapper.h +++ b/include/linux/device-mapper.h @@ -10,6 +10,7 @@ #include #include +#include struct dm_dev; struct dm_target; @@ -375,6 +376,14 @@ void *dm_vcalloc(unsigned long nmemb, unsigned long elem_size); *---------------------------------------------------------------*/ #define DM_NAME "device-mapper" +#ifdef CONFIG_PRINTK +extern struct ratelimit_state dm_ratelimit_state; + +#define dm_ratelimit() __ratelimit(&dm_ratelimit_state) +#else +#define dm_ratelimit() 0 +#endif + #define DMCRIT(f, arg...) \ printk(KERN_CRIT DM_NAME ": " DM_MSG_PREFIX ": " f "\n", ## arg) @@ -382,7 +391,7 @@ void *dm_vcalloc(unsigned long nmemb, unsigned long elem_size); printk(KERN_ERR DM_NAME ": " DM_MSG_PREFIX ": " f "\n", ## arg) #define DMERR_LIMIT(f, arg...) \ do { \ - if (printk_ratelimit()) \ + if (dm_ratelimit()) \ printk(KERN_ERR DM_NAME ": " DM_MSG_PREFIX ": " \ f "\n", ## arg); \ } while (0) @@ -391,7 +400,7 @@ void *dm_vcalloc(unsigned long nmemb, unsigned long elem_size); printk(KERN_WARNING DM_NAME ": " DM_MSG_PREFIX ": " f "\n", ## arg) #define DMWARN_LIMIT(f, arg...) \ do { \ - if (printk_ratelimit()) \ + if (dm_ratelimit()) \ printk(KERN_WARNING DM_NAME ": " DM_MSG_PREFIX ": " \ f "\n", ## arg); \ } while (0) @@ -400,7 +409,7 @@ void *dm_vcalloc(unsigned long nmemb, unsigned long elem_size); printk(KERN_INFO DM_NAME ": " DM_MSG_PREFIX ": " f "\n", ## arg) #define DMINFO_LIMIT(f, arg...) \ do { \ - if (printk_ratelimit()) \ + if (dm_ratelimit()) \ printk(KERN_INFO DM_NAME ": " DM_MSG_PREFIX ": " f \ "\n", ## arg); \ } while (0) @@ -410,7 +419,7 @@ void *dm_vcalloc(unsigned long nmemb, unsigned long elem_size); printk(KERN_DEBUG DM_NAME ": " DM_MSG_PREFIX " DEBUG: " f "\n", ## arg) # define DMDEBUG_LIMIT(f, arg...) \ do { \ - if (printk_ratelimit()) \ + if (dm_ratelimit()) \ printk(KERN_DEBUG DM_NAME ": " DM_MSG_PREFIX ": " f \ "\n", ## arg); \ } while (0) -- cgit v1.2.3 From 7f06965390e4a10fb6906c886324bfd0a96961be Mon Sep 17 00:00:00 2001 From: Mikulas Patocka Date: Mon, 31 Oct 2011 20:18:58 +0000 Subject: dm kcopyd: add dm_kcopyd_zero to zero an area This patch introduces dm_kcopyd_zero() to make it easy to use kcopyd to write zeros into the requested areas instead instead of copying. It is implemented by passing a NULL copying source to dm_kcopyd_copy(). The forthcoming thin provisioning target uses this. Signed-off-by: Mikulas Patocka Signed-off-by: Alasdair G Kergon --- drivers/md/dm-kcopyd.c | 31 ++++++++++++++++++++++++++----- include/linux/dm-kcopyd.h | 4 ++++ 2 files changed, 30 insertions(+), 5 deletions(-) (limited to 'include/linux') diff --git a/drivers/md/dm-kcopyd.c b/drivers/md/dm-kcopyd.c index 32ac70861d66..bed444c93d8d 100644 --- a/drivers/md/dm-kcopyd.c +++ b/drivers/md/dm-kcopyd.c @@ -66,6 +66,8 @@ struct dm_kcopyd_client { struct list_head pages_jobs; }; +static struct page_list zero_page_list; + static void wake(struct dm_kcopyd_client *kc) { queue_work(kc->kcopyd_wq, &kc->kcopyd_work); @@ -254,6 +256,9 @@ int __init dm_kcopyd_init(void) if (!_job_cache) return -ENOMEM; + zero_page_list.next = &zero_page_list; + zero_page_list.page = ZERO_PAGE(0); + return 0; } @@ -322,7 +327,7 @@ static int run_complete_job(struct kcopyd_job *job) dm_kcopyd_notify_fn fn = job->fn; struct dm_kcopyd_client *kc = job->kc; - if (job->pages) + if (job->pages && job->pages != &zero_page_list) kcopyd_put_pages(kc, job->pages); /* * If this is the master job, the sub jobs have already @@ -484,6 +489,8 @@ static void dispatch_job(struct kcopyd_job *job) atomic_inc(&kc->nr_jobs); if (unlikely(!job->source.count)) push(&kc->complete_jobs, job); + else if (job->pages == &zero_page_list) + push(&kc->io_jobs, job); else push(&kc->pages_jobs, job); wake(kc); @@ -592,14 +599,20 @@ int dm_kcopyd_copy(struct dm_kcopyd_client *kc, struct dm_io_region *from, job->flags = flags; job->read_err = 0; job->write_err = 0; - job->rw = READ; - - job->source = *from; job->num_dests = num_dests; memcpy(&job->dests, dests, sizeof(*dests) * num_dests); - job->pages = NULL; + if (from) { + job->source = *from; + job->pages = NULL; + job->rw = READ; + } else { + memset(&job->source, 0, sizeof job->source); + job->source.count = job->dests[0].count; + job->pages = &zero_page_list; + job->rw = WRITE; + } job->fn = fn; job->context = context; @@ -617,6 +630,14 @@ int dm_kcopyd_copy(struct dm_kcopyd_client *kc, struct dm_io_region *from, } EXPORT_SYMBOL(dm_kcopyd_copy); +int dm_kcopyd_zero(struct dm_kcopyd_client *kc, + unsigned num_dests, struct dm_io_region *dests, + unsigned flags, dm_kcopyd_notify_fn fn, void *context) +{ + return dm_kcopyd_copy(kc, NULL, num_dests, dests, flags, fn, context); +} +EXPORT_SYMBOL(dm_kcopyd_zero); + void *dm_kcopyd_prepare_callback(struct dm_kcopyd_client *kc, dm_kcopyd_notify_fn fn, void *context) { diff --git a/include/linux/dm-kcopyd.h b/include/linux/dm-kcopyd.h index 5e54458e920f..47d9d376e4e7 100644 --- a/include/linux/dm-kcopyd.h +++ b/include/linux/dm-kcopyd.h @@ -57,5 +57,9 @@ void *dm_kcopyd_prepare_callback(struct dm_kcopyd_client *kc, dm_kcopyd_notify_fn fn, void *context); void dm_kcopyd_do_callback(void *job, int read_err, unsigned long write_err); +int dm_kcopyd_zero(struct dm_kcopyd_client *kc, + unsigned num_dests, struct dm_io_region *dests, + unsigned flags, dm_kcopyd_notify_fn fn, void *context); + #endif /* __KERNEL__ */ #endif /* _LINUX_DM_KCOPYD_H */ -- cgit v1.2.3 From 3791e2fc0e4b40d4188e79b0a99bfa6bce714a10 Mon Sep 17 00:00:00 2001 From: Alasdair G Kergon Date: Mon, 31 Oct 2011 20:19:00 +0000 Subject: dm table: add singleton feature Introduce the concept of a singleton table which contains exactly one target. If a target type sets the DM_TARGET_SINGLETON feature bit device-mapper will ensure that any table that includes that target contains no others. The thin provisioning pool target uses this. Signed-off-by: Alasdair G Kergon --- drivers/md/dm-table.c | 16 ++++++++++++++++ include/linux/device-mapper.h | 14 ++++++++++---- 2 files changed, 26 insertions(+), 4 deletions(-) (limited to 'include/linux') diff --git a/drivers/md/dm-table.c b/drivers/md/dm-table.c index 81cbbf375bd7..2ec3482e942a 100644 --- a/drivers/md/dm-table.c +++ b/drivers/md/dm-table.c @@ -55,6 +55,7 @@ struct dm_table { struct dm_target *targets; unsigned integrity_supported:1; + unsigned singleton:1; /* * Indicates the rw permissions for the new logical @@ -740,6 +741,12 @@ int dm_table_add_target(struct dm_table *t, const char *type, char **argv; struct dm_target *tgt; + if (t->singleton) { + DMERR("%s: target type %s must appear alone in table", + dm_device_name(t->md), t->targets->type->name); + return -EINVAL; + } + if ((r = check_space(t))) return r; @@ -758,6 +765,15 @@ int dm_table_add_target(struct dm_table *t, const char *type, return -EINVAL; } + if (dm_target_needs_singleton(tgt->type)) { + if (t->num_targets) { + DMERR("%s: target type %s must appear alone in table", + dm_device_name(t->md), type); + return -EINVAL; + } + t->singleton = 1; + } + tgt->table = t; tgt->begin = start; tgt->len = len; diff --git a/include/linux/device-mapper.h b/include/linux/device-mapper.h index 622678ccb5e0..294e78a7fccd 100644 --- a/include/linux/device-mapper.h +++ b/include/linux/device-mapper.h @@ -128,10 +128,6 @@ void dm_put_device(struct dm_target *ti, struct dm_dev *d); * Information about a target type */ -/* - * Target features - */ - struct target_type { uint64_t features; const char *name; @@ -160,6 +156,16 @@ struct target_type { struct list_head list; }; +/* + * Target features + */ + +/* + * Any table that contains an instance of this target must have only one. + */ +#define DM_TARGET_SINGLETON 0x00000001 +#define dm_target_needs_singleton(type) ((type)->features & DM_TARGET_SINGLETON) + struct dm_target { struct dm_table *table; struct target_type *type; -- cgit v1.2.3 From cc6cbe141a20f6d876b161b60af38d93935bfa85 Mon Sep 17 00:00:00 2001 From: Alasdair G Kergon Date: Mon, 31 Oct 2011 20:19:02 +0000 Subject: dm table: add always writeable feature Add a target feature flag DM_TARGET_ALWAYS_WRITEABLE to indicate that a target does not support read-only mode. The initial implementation of the thin provisioning target uses this. Signed-off-by: Alasdair G Kergon --- drivers/md/dm-table.c | 6 ++++++ include/linux/device-mapper.h | 7 +++++++ 2 files changed, 13 insertions(+) (limited to 'include/linux') diff --git a/drivers/md/dm-table.c b/drivers/md/dm-table.c index 2ec3482e942a..9917141729ef 100644 --- a/drivers/md/dm-table.c +++ b/drivers/md/dm-table.c @@ -774,6 +774,12 @@ int dm_table_add_target(struct dm_table *t, const char *type, t->singleton = 1; } + if (dm_target_always_writeable(tgt->type) && !(t->mode & FMODE_WRITE)) { + DMERR("%s: target type %s may not be included in read-only tables", + dm_device_name(t->md), type); + return -EINVAL; + } + tgt->table = t; tgt->begin = start; tgt->len = len; diff --git a/include/linux/device-mapper.h b/include/linux/device-mapper.h index 294e78a7fccd..cc58e2d7c032 100644 --- a/include/linux/device-mapper.h +++ b/include/linux/device-mapper.h @@ -166,6 +166,13 @@ struct target_type { #define DM_TARGET_SINGLETON 0x00000001 #define dm_target_needs_singleton(type) ((type)->features & DM_TARGET_SINGLETON) +/* + * Indicates that a target does not support read-only devices. + */ +#define DM_TARGET_ALWAYS_WRITEABLE 0x00000002 +#define dm_target_always_writeable(type) \ + ((type)->features & DM_TARGET_ALWAYS_WRITEABLE) + struct dm_target { struct dm_table *table; struct target_type *type; -- cgit v1.2.3 From 36a0456fbf2d9680bf9af81b39daf4a8e22cb1b8 Mon Sep 17 00:00:00 2001 From: Alasdair G Kergon Date: Mon, 31 Oct 2011 20:19:04 +0000 Subject: dm table: add immutable feature Introduce DM_TARGET_IMMUTABLE to indicate that the target type cannot be mixed with any other target type, and once loaded into a device, it cannot be replaced with a table containing a different type. The thin provisioning pool device will use this. Signed-off-by: Alasdair G Kergon --- drivers/md/dm-ioctl.c | 11 +++++++++++ drivers/md/dm-table.c | 21 +++++++++++++++++++++ drivers/md/dm.c | 9 +++++++++ drivers/md/dm.h | 2 ++ include/linux/device-mapper.h | 7 +++++++ include/linux/dm-ioctl.h | 4 ++-- 6 files changed, 52 insertions(+), 2 deletions(-) (limited to 'include/linux') diff --git a/drivers/md/dm-ioctl.c b/drivers/md/dm-ioctl.c index 2e9a3ca37bdd..31c2dc25886d 100644 --- a/drivers/md/dm-ioctl.c +++ b/drivers/md/dm-ioctl.c @@ -1215,6 +1215,7 @@ static int table_load(struct dm_ioctl *param, size_t param_size) struct hash_cell *hc; struct dm_table *t; struct mapped_device *md; + struct target_type *immutable_target_type; md = find_device(param); if (!md) @@ -1230,6 +1231,16 @@ static int table_load(struct dm_ioctl *param, size_t param_size) goto out; } + immutable_target_type = dm_get_immutable_target_type(md); + if (immutable_target_type && + (immutable_target_type != dm_table_get_immutable_target_type(t))) { + DMWARN("can't replace immutable target type %s", + immutable_target_type->name); + dm_table_destroy(t); + r = -EINVAL; + goto out; + } + /* Protect md->type and md->queue against concurrent table loads. */ dm_lock_md_type(md); if (dm_get_md_type(md) == DM_TYPE_NONE) diff --git a/drivers/md/dm-table.c b/drivers/md/dm-table.c index 9917141729ef..8e9132130142 100644 --- a/drivers/md/dm-table.c +++ b/drivers/md/dm-table.c @@ -54,6 +54,7 @@ struct dm_table { sector_t *highs; struct dm_target *targets; + struct target_type *immutable_target_type; unsigned integrity_supported:1; unsigned singleton:1; @@ -780,6 +781,21 @@ int dm_table_add_target(struct dm_table *t, const char *type, return -EINVAL; } + if (t->immutable_target_type) { + if (t->immutable_target_type != tgt->type) { + DMERR("%s: immutable target type %s cannot be mixed with other target types", + dm_device_name(t->md), t->immutable_target_type->name); + return -EINVAL; + } + } else if (dm_target_is_immutable(tgt->type)) { + if (t->num_targets) { + DMERR("%s: immutable target type %s cannot be mixed with other target types", + dm_device_name(t->md), tgt->type->name); + return -EINVAL; + } + t->immutable_target_type = tgt->type; + } + tgt->table = t; tgt->begin = start; tgt->len = len; @@ -937,6 +953,11 @@ unsigned dm_table_get_type(struct dm_table *t) return t->type; } +struct target_type *dm_table_get_immutable_target_type(struct dm_table *t) +{ + return t->immutable_target_type; +} + bool dm_table_request_based(struct dm_table *t) { return dm_table_get_type(t) == DM_TYPE_REQUEST_BASED; diff --git a/drivers/md/dm.c b/drivers/md/dm.c index 2fe3017ba97c..9836324e2118 100644 --- a/drivers/md/dm.c +++ b/drivers/md/dm.c @@ -140,6 +140,8 @@ struct mapped_device { /* Protect queue and type against concurrent access. */ struct mutex type_lock; + struct target_type *immutable_target_type; + struct gendisk *disk; char name[16]; @@ -2096,6 +2098,8 @@ static struct dm_table *__bind(struct mapped_device *md, struct dm_table *t, write_lock_irqsave(&md->map_lock, flags); old_map = md->map; md->map = t; + md->immutable_target_type = dm_table_get_immutable_target_type(t); + dm_table_set_restrictions(t, q, limits); if (merge_is_optional) set_bit(DMF_MERGE_IS_OPTIONAL, &md->flags); @@ -2166,6 +2170,11 @@ unsigned dm_get_md_type(struct mapped_device *md) return md->type; } +struct target_type *dm_get_immutable_target_type(struct mapped_device *md) +{ + return md->immutable_target_type; +} + /* * Fully initialize a request-based queue (->elevator, ->request_fn, etc). */ diff --git a/drivers/md/dm.h b/drivers/md/dm.h index 6745dbd278a4..b7dacd59d8d7 100644 --- a/drivers/md/dm.h +++ b/drivers/md/dm.h @@ -60,6 +60,7 @@ int dm_table_resume_targets(struct dm_table *t); int dm_table_any_congested(struct dm_table *t, int bdi_bits); int dm_table_any_busy_target(struct dm_table *t); unsigned dm_table_get_type(struct dm_table *t); +struct target_type *dm_table_get_immutable_target_type(struct dm_table *t); bool dm_table_request_based(struct dm_table *t); bool dm_table_supports_discards(struct dm_table *t); int dm_table_alloc_md_mempools(struct dm_table *t); @@ -72,6 +73,7 @@ void dm_lock_md_type(struct mapped_device *md); void dm_unlock_md_type(struct mapped_device *md); void dm_set_md_type(struct mapped_device *md, unsigned type); unsigned dm_get_md_type(struct mapped_device *md); +struct target_type *dm_get_immutable_target_type(struct mapped_device *md); int dm_setup_md_queue(struct mapped_device *md); diff --git a/include/linux/device-mapper.h b/include/linux/device-mapper.h index cc58e2d7c032..98f34b886f95 100644 --- a/include/linux/device-mapper.h +++ b/include/linux/device-mapper.h @@ -173,6 +173,13 @@ struct target_type { #define dm_target_always_writeable(type) \ ((type)->features & DM_TARGET_ALWAYS_WRITEABLE) +/* + * Any device that contains a table with an instance of this target may never + * have tables containing any different target type. + */ +#define DM_TARGET_IMMUTABLE 0x00000004 +#define dm_target_is_immutable(type) ((type)->features & DM_TARGET_IMMUTABLE) + struct dm_target { struct dm_table *table; struct target_type *type; diff --git a/include/linux/dm-ioctl.h b/include/linux/dm-ioctl.h index 0cb8eff76bd6..75fd5573516e 100644 --- a/include/linux/dm-ioctl.h +++ b/include/linux/dm-ioctl.h @@ -267,9 +267,9 @@ enum { #define DM_DEV_SET_GEOMETRY _IOWR(DM_IOCTL, DM_DEV_SET_GEOMETRY_CMD, struct dm_ioctl) #define DM_VERSION_MAJOR 4 -#define DM_VERSION_MINOR 21 +#define DM_VERSION_MINOR 22 #define DM_VERSION_PATCHLEVEL 0 -#define DM_VERSION_EXTRA "-ioctl (2011-07-06)" +#define DM_VERSION_EXTRA "-ioctl (2011-10-19)" /* Status bits */ #define DM_READONLY_FLAG (1 << 0) /* In/Out */ -- cgit v1.2.3 From 5a25f0eb707bbb4a5aaaf19c933605a6dbaf77a5 Mon Sep 17 00:00:00 2001 From: Jonathan E Brassow Date: Mon, 31 Oct 2011 20:21:24 +0000 Subject: dm log userspace: add log device dependency Allow userspace dm log implementations to register their log device so it is no longer missing from the list of device dependencies. When device mapper targets use a device they normally call dm_get_device which includes it in the device list returned to userspace applications such as LVM through the DM_TABLE_DEPS ioctl. Userspace log devices don't use dm_get_device as userspace opens them so they are missing from the list of dependencies. This patch extends the DM_ULOG_CTR operation to allow userspace to respond with the name of the log device (if appropriate) to be registered via 'dm_get_device'. DM_ULOG_REQUEST_VERSION is incremented. This is backwards compatible. If the kernel and userspace log server have both been updated, the new information will be passed down to the kernel and the device will be registered. If the kernel is new, but the log server is old, the log server will not pass down any device information and the kernel will simply bypass the device registration as before. If the kernel is old but the log server is new, the log server will see the old version number and not pass the device info. Signed-off-by: Jonathan Brassow Signed-off-by: Alasdair G Kergon --- drivers/md/dm-log-userspace-base.c | 35 ++++++++++++++++++++++++++++++++--- include/linux/dm-log-userspace.h | 18 +++++++++++++----- 2 files changed, 45 insertions(+), 8 deletions(-) (limited to 'include/linux') diff --git a/drivers/md/dm-log-userspace-base.c b/drivers/md/dm-log-userspace-base.c index 3c27978890b7..8db3862dade5 100644 --- a/drivers/md/dm-log-userspace-base.c +++ b/drivers/md/dm-log-userspace-base.c @@ -30,6 +30,7 @@ struct flush_entry { struct log_c { struct dm_target *ti; + struct dm_dev *log_dev; uint32_t region_size; region_t region_count; uint64_t luid; @@ -161,13 +162,15 @@ static int userspace_ctr(struct dm_dirty_log *log, struct dm_target *ti, struct log_c *lc = NULL; uint64_t rdata; size_t rdata_size = sizeof(rdata); + char *devices_rdata = NULL; + size_t devices_rdata_size = DM_NAME_LEN; if (argc < 3) { DMWARN("Too few arguments to userspace dirty log"); return -EINVAL; } - lc = kmalloc(sizeof(*lc), GFP_KERNEL); + lc = kzalloc(sizeof(*lc), GFP_KERNEL); if (!lc) { DMWARN("Unable to allocate userspace log context."); return -ENOMEM; @@ -195,9 +198,19 @@ static int userspace_ctr(struct dm_dirty_log *log, struct dm_target *ti, return str_size; } - /* Send table string */ + devices_rdata = kzalloc(devices_rdata_size, GFP_KERNEL); + if (!devices_rdata) { + DMERR("Failed to allocate memory for device information"); + r = -ENOMEM; + goto out; + } + + /* + * Send table string and get back any opened device. + */ r = dm_consult_userspace(lc->uuid, lc->luid, DM_ULOG_CTR, - ctr_str, str_size, NULL, NULL); + ctr_str, str_size, + devices_rdata, &devices_rdata_size); if (r < 0) { if (r == -ESRCH) @@ -220,7 +233,20 @@ static int userspace_ctr(struct dm_dirty_log *log, struct dm_target *ti, lc->region_size = (uint32_t)rdata; lc->region_count = dm_sector_div_up(ti->len, lc->region_size); + if (devices_rdata_size) { + if (devices_rdata[devices_rdata_size - 1] != '\0') { + DMERR("DM_ULOG_CTR device return string not properly terminated"); + r = -EINVAL; + goto out; + } + r = dm_get_device(ti, devices_rdata, + dm_table_get_mode(ti->table), &lc->log_dev); + if (r) + DMERR("Failed to register %s with device-mapper", + devices_rdata); + } out: + kfree(devices_rdata); if (r) { kfree(lc); kfree(ctr_str); @@ -241,6 +267,9 @@ static void userspace_dtr(struct dm_dirty_log *log) NULL, 0, NULL, NULL); + if (lc->log_dev) + dm_put_device(lc->ti, lc->log_dev); + kfree(lc->usr_argv_str); kfree(lc); diff --git a/include/linux/dm-log-userspace.h b/include/linux/dm-log-userspace.h index eeace7d3ff15..0678c2adc421 100644 --- a/include/linux/dm-log-userspace.h +++ b/include/linux/dm-log-userspace.h @@ -52,15 +52,20 @@ * Payload-to-userspace: * A single string containing all the argv arguments separated by ' 's * Payload-to-kernel: - * None. ('data_size' in the dm_ulog_request struct should be 0.) + * A NUL-terminated string that is the name of the device that is used + * as the backing store for the log data. 'dm_get_device' will be called + * on this device. ('dm_put_device' will be called on this device + * automatically after calling DM_ULOG_DTR.) If there is no device needed + * for log data, 'data_size' in the dm_ulog_request struct should be 0. * * The UUID contained in the dm_ulog_request structure is the reference that * will be used by all request types to a specific log. The constructor must - * record this assotiation with instance created. + * record this association with the instance created. * * When the request has been processed, user-space must return the - * dm_ulog_request to the kernel - setting the 'error' field and - * 'data_size' appropriately. + * dm_ulog_request to the kernel - setting the 'error' field, filling the + * data field with the log device if necessary, and setting 'data_size' + * appropriately. */ #define DM_ULOG_CTR 1 @@ -377,8 +382,11 @@ * dm_ulog_request or a change in the way requests are * issued/handled. Changes are outlined here: * version 1: Initial implementation + * version 2: DM_ULOG_CTR allowed to return a string containing a + * device name that is to be registered with DM via + * 'dm_get_device'. */ -#define DM_ULOG_REQUEST_VERSION 1 +#define DM_ULOG_REQUEST_VERSION 2 struct dm_ulog_request { /* -- cgit v1.2.3