From: Alasdair Kergon Date: Wed, 19 Jun 2002 13:07:00 +0000 (+0000) Subject: o Long-awaited ioctl interface clean-up. *** Not backwardly compatible *** X-Git-Tag: beta4~4 X-Git-Url: https://sourceware.org/git/?a=commitdiff_plain;h=7e497a3124428342b48e749392a2ae460ecf9c92;p=dm.git o Long-awaited ioctl interface clean-up. *** Not backwardly compatible *** o Various other kernel side tidy-ups. o Version number changes so we have the option of adding new ioctl commands in future without affecting the use of existing ones should you later revert to an older kernel but not revert the userspace library/tools. o Better separation of kernel/userspace elements in the build process to prepare for independent distribution of the kernel driver. --- diff --git a/VERSION b/VERSION index 2d97eb4..004953f 100644 --- a/VERSION +++ b/VERSION @@ -1 +1 @@ -0.95.12-cvs (2002-06-13) +0.96.01-cvs (2002-06-19) diff --git a/configure b/configure index 57a3c11..f2a1284 100755 --- a/configure +++ b/configure @@ -1962,16 +1962,6 @@ else DM_LIB_VERSION="Unknown version ($interface)" fi -if test "-f kernel/VERSION"; then - DM_DRIVER_VERSION="\"`cat kernel/VERSION|sed -e \"s/[0-9.]*/\0-$interface/\"`\"" - DM_IOCTL_VERSION="\"`cat kernel/VERSION| awk -F '.' '{printf \"%s.%s\",\$1,\$2}'`\"" -else - DM_DRIVER_VERSION="Unknown" - DM_IOCTL_VERSION="Unknown" -fi - - - @@ -2102,8 +2092,6 @@ dmsetup/Makefile \ lib/Makefile \ lib/libdm-common.h \ kernel/Makefile \ -kernel/common/dm.c \ -kernel/ioctl/dm-ioctl.h \ man/Makefile \ " | sed "s/:[^ ]*//g"` conftest*; exit 1' 1 2 15 EOF @@ -2153,8 +2141,6 @@ s%@interface@%$interface%g s%@kerneldir@%$kerneldir%g s%@kernelvsn@%$kernelvsn%g s%@tmpdir@%$tmpdir%g -s%@DM_DRIVER_VERSION@%$DM_DRIVER_VERSION%g -s%@DM_IOCTL_VERSION@%$DM_IOCTL_VERSION%g s%@DM_LIB_VERSION@%$DM_LIB_VERSION%g CEOF @@ -2205,8 +2191,6 @@ dmsetup/Makefile \ lib/Makefile \ lib/libdm-common.h \ kernel/Makefile \ -kernel/common/dm.c \ -kernel/ioctl/dm-ioctl.h \ man/Makefile \ "} EOF diff --git a/configure.in b/configure.in index bac3460..a8fd6f2 100644 --- a/configure.in +++ b/configure.in @@ -149,14 +149,6 @@ else DM_LIB_VERSION="Unknown version ($interface)" fi -if test "-f kernel/VERSION"; then - DM_DRIVER_VERSION="\"`cat kernel/VERSION|sed -e \"s/[[0-9.]]*/\0-$interface/\"`\"" - DM_IOCTL_VERSION="\"`cat kernel/VERSION| awk -F '.' '{printf \"%s.%s\",\$1,\$2}'`\"" -else - DM_DRIVER_VERSION="Unknown" - DM_IOCTL_VERSION="Unknown" -fi - AC_SUBST(JOBS) AC_SUBST(OWNER) AC_SUBST(GROUP) @@ -165,8 +157,6 @@ AC_SUBST(interface) AC_SUBST(kerneldir) AC_SUBST(kernelvsn) AC_SUBST(tmpdir) -AC_SUBST(DM_DRIVER_VERSION) -AC_SUBST(DM_IOCTL_VERSION) AC_SUBST(DM_LIB_VERSION) dnl First and last lines should not contain files to generate in order to dnl keep utility scripts running properly @@ -178,7 +168,5 @@ dmsetup/Makefile \ lib/Makefile \ lib/libdm-common.h \ kernel/Makefile \ -kernel/common/dm.c \ -kernel/ioctl/dm-ioctl.h \ man/Makefile \ ) diff --git a/kernel/Makefile.in b/kernel/Makefile.in index 7d39750..16897f6 100644 --- a/kernel/Makefile.in +++ b/kernel/Makefile.in @@ -123,7 +123,7 @@ install: clean: distclean: - $(RM) Makefile common/dm.c ioctl/dm-ioctl.h + $(RM) Makefile .PHONY: install clean distclean all diff --git a/kernel/VERSION b/kernel/VERSION deleted file mode 100644 index 9eed8ca..0000000 --- a/kernel/VERSION +++ /dev/null @@ -1 +0,0 @@ -0.94.12-cvs (2002-06-13) diff --git a/kernel/common/dm-mirror.c b/kernel/common/dm-mirror.c index 9d85acc..64a5337 100644 --- a/kernel/common/dm-mirror.c +++ b/kernel/common/dm-mirror.c @@ -93,7 +93,7 @@ static void copy_callback(int err, void *context) } if (err) { - DMERR("Mirror block IO failed"); /* More detail to follow... */ + DMERR("Mirror block IO failed"); /* More detail to follow... */ lc->error = 1; return; } diff --git a/kernel/common/dm.c.in b/kernel/common/dm.c similarity index 99% rename from kernel/common/dm.c.in rename to kernel/common/dm.c index 87f5edf..f58b896 100644 --- a/kernel/common/dm.c.in +++ b/kernel/common/dm.c @@ -16,8 +16,6 @@ #define DEFAULT_READ_AHEAD 64 static const char *_name = DM_NAME; -static const char *_version = @DM_DRIVER_VERSION@; -static const char *_email = "lvm-devel@lists.sistina.com"; static int major = 0; static int _major = 0; @@ -235,7 +233,6 @@ static __init int local_init(void) _dev_dir = devfs_mk_dir(0, DM_DIR, NULL); - DMINFO("%s initialised: %s", _version, _email); return 0; } @@ -254,7 +251,7 @@ static void local_exit(void) hardsect_size[_major] = NULL; _major = 0; - DMINFO("%s cleaned up", _version); + DMINFO("cleaned up"); } /* @@ -818,6 +815,14 @@ static int __find_hardsect_size(struct list_head *devices) if (size < result) result = size; } + + /* + * I think it's safe to assume that no block devices have + * a hard sector size this large. + */ + if (result == INT_MAX) + result = 512; + return result; } diff --git a/kernel/common/dm.h b/kernel/common/dm.h index c629407..6ba0bb5 100644 --- a/kernel/common/dm.h +++ b/kernel/common/dm.h @@ -26,6 +26,7 @@ #include #define DM_NAME "device-mapper" /* Name for messaging */ +#define DM_DRIVER_EMAIL "lvm-devel@lists.sistina.com" #define MAX_DEPTH 16 #define NODE_SIZE L1_CACHE_BYTES #define KEYS_PER_NODE (NODE_SIZE / sizeof(offset_t)) diff --git a/kernel/ioctl/dm-ioctl.c b/kernel/ioctl/dm-ioctl.c index 7e7baa8..3bd4433 100644 --- a/kernel/ioctl/dm-ioctl.c +++ b/kernel/ioctl/dm-ioctl.c @@ -11,59 +11,22 @@ #include #include -static void free_params(struct dm_ioctl *param) -{ - vfree(param); -} - -static int version(struct dm_ioctl *user) -{ - return copy_to_user(user, DM_DRIVER_VERSION, sizeof(DM_DRIVER_VERSION)); -} - -static int copy_params(struct dm_ioctl *user, struct dm_ioctl **param) -{ - struct dm_ioctl tmp, *dmi; - - if (copy_from_user(&tmp, user, sizeof(tmp))) - return -EFAULT; - - if (strcmp(DM_IOCTL_VERSION, tmp.version)) { - DMWARN("struct dm_ioctl version incompatible"); - return -EINVAL; - } +/*----------------------------------------------------------------- + * Implementation of the ioctl commands + *---------------------------------------------------------------*/ - if (tmp.data_size < sizeof(tmp)) - return -EINVAL; - - dmi = (struct dm_ioctl *) vmalloc(tmp.data_size); - if (!dmi) - return -ENOMEM; - - if (copy_from_user(dmi, user, tmp.data_size)) { - vfree(dmi); - return -EFAULT; - } - - *param = dmi; - return 0; -} +/* + * All the ioctl commands get dispatched to functions with this + * prototype. + */ +typedef int (*ioctl_fn)(struct dm_ioctl *param, struct dm_ioctl *user); -static int validate_params(uint cmd, struct dm_ioctl *param) +/* + * This is really a debug only call. + */ +static int remove_all(struct dm_ioctl *param, struct dm_ioctl *user) { - /* Unless creating, either name of uuid but not both */ - if (cmd != DM_CREATE_CMD) { - if ((!*param->uuid && !*param->name) || - (*param->uuid && *param->name)) { - DMWARN("one of name or uuid must be supplied"); - return -EINVAL; - } - } - - /* Ensure strings are terminated */ - param->name[DM_NAME_LEN - 1] = '\0'; - param->uuid[DM_UUID_LEN - 1] = '\0'; - + dm_destroy_all(); return 0; } @@ -80,7 +43,7 @@ static int valid_str(char *str, void *begin, void *end) return -EINVAL; } -static int next_target(struct dm_target_spec *last, unsigned long next, +static int next_target(struct dm_target_spec *last, uint32_t next, void *begin, void *end, struct dm_target_spec **spec, char **params) { @@ -130,10 +93,13 @@ static int populate_table(struct dm_table *table, struct dm_ioctl *args) for (i = 0; i < args->target_count; i++) { - r = first ? next_target((struct dm_target_spec *) args, + if (first) + r = next_target((struct dm_target_spec *) args, args->data_start, - begin, end, &spec, ¶ms) : - next_target(spec, spec->next, begin, end, &spec, ¶ms); + begin, end, &spec, ¶ms); + else + r = next_target(spec, spec->next, begin, end, + &spec, ¶ms); if (r) PARSE_ERROR("unable to find target"); @@ -187,26 +153,31 @@ static inline void *align_ptr(void *ptr, unsigned int align) * userland. */ static int results_to_user(struct dm_ioctl *user, struct dm_ioctl *param, - void *data, unsigned long len) + void *data, uint32_t len) { int r; void *ptr = NULL; - strncpy(param->version, DM_IOCTL_VERSION, sizeof(param->version)); - if (data) { ptr = align_ptr(user + 1, sizeof(unsigned long)); param->data_start = ptr - (void *) user; } - r = copy_to_user(user, param, sizeof(*param)); + /* + * The version number has already been filled in, so we + * just copy later fields. + */ + r = copy_to_user(&user->data_size, ¶m->data_size, + sizeof(*param) - sizeof(param->version)); if (r) - return r; + return -EFAULT; if (data) { if (param->data_start + len > param->data_size) return -ENOSPC; - r = copy_to_user(ptr, data, len); + + if (copy_to_user(ptr, data, len)) + r = -EFAULT; } return r; @@ -257,6 +228,63 @@ static void *_align(void *ptr, unsigned int a) return (void *) (((unsigned long) ptr + align) & ~align); } +/* + * Copies device info back to user space, used by + * the create and info ioctls. + */ +static int info(struct dm_ioctl *param, struct dm_ioctl *user) +{ + struct mapped_device *md; + + param->flags = 0; + + md = dm_get_name_r(lookup_name(param), lookup_type(param)); + if (!md) + /* + * Device not found - returns cleared exists flag. + */ + goto out; + + __info(md, param); + dm_put_r(md); + + out: + return results_to_user(user, param, NULL, 0); +} + +static int create(struct dm_ioctl *param, struct dm_ioctl *user) +{ + int r, ro; + struct dm_table *t; + int minor; + + r = dm_table_create(&t); + if (r) + return r; + + r = populate_table(t, param); + if (r) { + dm_table_destroy(t); + return r; + } + + minor = (param->flags & DM_PERSISTENT_DEV_FLAG) ? + MINOR(to_kdev_t(param->dev)) : -1; + + ro = (param->flags & DM_READONLY_FLAG) ? 1 : 0; + + r = dm_create(param->name, param->uuid, minor, ro, t); + if (r) { + dm_table_destroy(t); + return r; + } + + r = info(param, user); + return r; +} + + + /* * Build up the status struct for each target */ @@ -265,7 +293,7 @@ static int __status(struct mapped_device *md, struct dm_ioctl *param, { int i; struct dm_target_spec *spec; - unsigned long long sector = 0LL; + uint64_t sector = 0LL; char *outptr; status_type_t type; @@ -396,30 +424,6 @@ static int wait_device_event(struct dm_ioctl *param, struct dm_ioctl *user) return results_to_user(user, param, NULL, 0); } -/* - * Copies device info back to user space, used by - * the create and info ioctls. - */ -static int info(struct dm_ioctl *param, struct dm_ioctl *user) -{ - struct mapped_device *md; - - param->flags = 0; - - md = dm_get_name_r(lookup_name(param), lookup_type(param)); - if (!md) - /* - * Device not found - returns cleared exists flag. - */ - goto out; - - __info(md, param); - dm_put_r(md); - - out: - return results_to_user(user, param, NULL, 0); -} - /* * Retrieves a list of devices used by a particular dm device. */ @@ -481,38 +485,7 @@ static int dep(struct dm_ioctl *param, struct dm_ioctl *user) return r; } -static int create(struct dm_ioctl *param, struct dm_ioctl *user) -{ - int r, ro; - struct dm_table *t; - int minor; - - r = dm_table_create(&t); - if (r) - return r; - - r = populate_table(t, param); - if (r) { - dm_table_destroy(t); - return r; - } - - minor = (param->flags & DM_PERSISTENT_DEV_FLAG) ? - MINOR(to_kdev_t(param->dev)) : -1; - - ro = (param->flags & DM_READONLY_FLAG) ? 1 : 0; - - r = dm_create(param->name, param->uuid, minor, ro, t); - if (r) { - dm_table_destroy(t); - return r; - } - - r = info(param, user); - return r; -} - -static int remove(struct dm_ioctl *param) +static int remove(struct dm_ioctl *param, struct dm_ioctl *user) { int r; struct mapped_device *md; @@ -529,7 +502,7 @@ static int remove(struct dm_ioctl *param) return r; } -static int suspend(struct dm_ioctl *param) +static int suspend(struct dm_ioctl *param, struct dm_ioctl *user) { int r; struct mapped_device *md; @@ -580,7 +553,7 @@ static int reload(struct dm_ioctl *param, struct dm_ioctl *user) return r; } -static int rename(struct dm_ioctl *param) +static int rename(struct dm_ioctl *param, struct dm_ioctl *user) { char *newname = (char *) param + param->data_start; @@ -594,6 +567,11 @@ static int rename(struct dm_ioctl *param) return 0; } + +/*----------------------------------------------------------------- + * Implementation of open/close/ioctl on the special char + * device. + *---------------------------------------------------------------*/ static int ctl_open(struct inode *inode, struct file *file) { /* only root can open this */ @@ -611,97 +589,174 @@ static int ctl_close(struct inode *inode, struct file *file) return 0; } -static int ctl_ioctl(struct inode *inode, struct file *file, - uint command, ulong u) +static ioctl_fn lookup_ioctl(unsigned int cmd) +{ + static struct { + int cmd; + ioctl_fn fn; + } _ioctls[] = { + {DM_VERSION_CMD, NULL}, /* version is dealt with elsewhere */ + {DM_REMOVE_ALL_CMD, remove_all}, + {DM_DEV_CREATE_CMD, create}, + {DM_DEV_REMOVE_CMD, remove}, + {DM_DEV_RELOAD_CMD, reload}, + {DM_DEV_RENAME_CMD, rename}, + {DM_DEV_SUSPEND_CMD, suspend}, + {DM_DEV_DEPS_CMD, dep}, + {DM_DEV_STATUS_CMD, info}, + {DM_TARGET_STATUS_CMD, get_status}, + {DM_TARGET_WAIT_CMD, wait_device_event}, + }; + static int nelts = sizeof(_ioctls) / sizeof(*_ioctls); + + return (cmd >= nelts) ? NULL : _ioctls[cmd].fn; +} + +/* + * As well as checking the version compatibility this always + * copies the kernel interface version out. + */ +static int check_version(int cmd, struct dm_ioctl *user) { + uint32_t version[3]; int r = 0; - struct dm_ioctl *param; - struct dm_ioctl *user = (struct dm_ioctl *) u; - uint cmd = _IOC_NR(command); - - /* Process commands without params first - always return version */ - switch (cmd) { - case DM_REMOVE_ALL_CMD: - dm_destroy_all(); - case DM_VERSION_CMD: - return version(user); - default: - break; + + if (copy_from_user(version, user->version, sizeof(version))) + return -EFAULT; + + if ((DM_VERSION_MAJOR != version[0]) || + (DM_VERSION_MINOR < version[1])) { + DMWARN("ioctl interface mismatch: " + "kernel(%u.%u.%u), user(%u.%u.%u), cmd(%d)", + DM_VERSION_MAJOR, DM_VERSION_MINOR, + DM_VERSION_PATCHLEVEL, + version[0], version[1], version[2], cmd); + r = -EINVAL; } - r = copy_params(user, ¶m); - if (r) - goto err; + /* + * Fill in the kernel version. + */ + version[0] = DM_VERSION_MAJOR; + version[1] = DM_VERSION_MINOR; + version[2] = DM_VERSION_PATCHLEVEL; + if (copy_to_user(user->version, version, sizeof(version))) + return -EFAULT; - r = validate_params(cmd, param); - if (r) { - free_params(param); - goto err; + return r; +} + +static void free_params(struct dm_ioctl *param) +{ + vfree(param); +} + +static int copy_params(struct dm_ioctl *user, struct dm_ioctl **param) +{ + struct dm_ioctl tmp, *dmi; + + if (copy_from_user(&tmp, user, sizeof(tmp))) + return -EFAULT; + + if (tmp.data_size < sizeof(tmp)) + return -EINVAL; + + dmi = (struct dm_ioctl *) vmalloc(tmp.data_size); + if (!dmi) + return -ENOMEM; + + if (copy_from_user(dmi, user, tmp.data_size)) { + vfree(dmi); + return -EFAULT; } - switch (cmd) { - case DM_INFO_CMD: - r = info(param, user); - break; + *param = dmi; + return 0; +} + +static int validate_params(uint cmd, struct dm_ioctl *param) +{ + /* Unless creating, either name of uuid but not both */ + if (cmd != DM_DEV_CREATE_CMD) { + if ((!*param->uuid && !*param->name) || + (*param->uuid && *param->name)) { + DMWARN("one of name or uuid must be supplied"); + return -EINVAL; + } + } - case DM_SUSPEND_CMD: - r = suspend(param); - break; + /* Ensure strings are terminated */ + param->name[DM_NAME_LEN - 1] = '\0'; + param->uuid[DM_UUID_LEN - 1] = '\0'; - case DM_CREATE_CMD: - r = create(param, user); - break; + return 0; +} - case DM_RELOAD_CMD: - r = reload(param, user); - break; +static int ctl_ioctl(struct inode *inode, struct file *file, + uint command, ulong u) +{ - case DM_REMOVE_CMD: - r = remove(param); - break; + int r = 0, cmd; + struct dm_ioctl *param; + struct dm_ioctl *user = (struct dm_ioctl *) u; + ioctl_fn fn = NULL; - case DM_RENAME_CMD: - r = rename(param); - break; + if (_IOC_TYPE(command) != DM_IOCTL) + return -ENOTTY; - case DM_DEPS_CMD: - r = dep(param, user); - break; + cmd = _IOC_NR(command); - case DM_GET_STATUS_CMD: - r = get_status(param, user); - break; + /* + * Check the interface version passed in. This also + * writes out the kernel's interface version. + */ + r = check_version(cmd, user); + if (r) + return r; - case DM_WAIT_EVENT_CMD: - r = wait_device_event(param, user); - break; + /* + * Nothing more to do for the version command. + */ + if (cmd == DM_VERSION_CMD) + return 0; - default: + fn = lookup_ioctl(cmd); + if (!fn) { DMWARN("dm_ctl_ioctl: unknown command 0x%x", command); - r = -ENOTTY; + return -ENOTTY; } - free_params(param); - return r; + /* + * Copy the parameters into kernel space. + */ + r = copy_params(user, ¶m); + if (r) + return r; + + r = validate_params(cmd, param); + if (r) { + free_params(param); + return r; + } - err: - version(user); + r = fn(param, user); + free_params(param); return r; } static struct file_operations _ctl_fops = { - open: ctl_open, - release:ctl_close, - ioctl: ctl_ioctl, - owner: THIS_MODULE, + open: ctl_open, + release: ctl_close, + ioctl: ctl_ioctl, + owner: THIS_MODULE, }; static devfs_handle_t _ctl_handle; static struct miscdevice _dm_misc = { - minor: MISC_DYNAMIC_MINOR, - name: DM_NAME, - fops: &_ctl_fops + minor: MISC_DYNAMIC_MINOR, + name: DM_NAME, + fops: &_ctl_fops }; /* Create misc character device and link to DM_DIR/control */ @@ -735,6 +790,9 @@ int __init dm_interface_init(void) } devfs_auto_unregister(_dm_misc.devfs_handle, _ctl_handle); + DMINFO("%d.%d.%d%s initialised: %s", DM_VERSION_MAJOR, + DM_VERSION_MINOR, DM_VERSION_PATCHLEVEL, DM_VERSION_EXTRA, + DM_DRIVER_EMAIL); return 0; failed: diff --git a/kernel/ioctl/dm-ioctl.h b/kernel/ioctl/dm-ioctl.h new file mode 100644 index 0000000..a5e72e0 --- /dev/null +++ b/kernel/ioctl/dm-ioctl.h @@ -0,0 +1,145 @@ +/* + * Copyright (C) 2001 Sistina Software (UK) Limited. + * + * This file is released under the LGPL. + */ + +#ifndef _LINUX_DM_IOCTL_H +#define _LINUX_DM_IOCTL_H + +#include "device-mapper.h" +#include "types.h" + +/* + * Implements a traditional ioctl interface to the device mapper. + */ + +/* + * All ioctl arguments consist of a single chunk of memory, with + * this structure at the start. If a uuid is specified any + * lookup (eg. for a DM_INFO) will be done on that, *not* the + * name. + */ +struct dm_ioctl { + /* + * The version number is made up of three parts: + * major - no backward or forward compatibility, + * minor - only backwards compatible, + * patch - both backwards and forwards compatible. + * + * All clients of the ioctl interface should fill in the + * version number of the interface that they were + * compiled with. + * + * All recognised ioctl commands (ie. those that don't + * return -ENOTTY) fill out this field, even if the + * command failed. + */ + uint32_t version[3]; /* in/out */ + uint32_t data_size; /* total size of data passed in + * including this struct */ + + uint32_t data_start; /* offset to start of data + * relative to start of this struct */ + + uint32_t target_count; /* in/out */ + uint32_t open_count; /* out */ + uint32_t flags; /* in/out */ + + __kernel_dev_t dev; /* in/out */ + + char name[DM_NAME_LEN]; /* device name */ + char uuid[DM_UUID_LEN]; /* unique identifier for + * the block device */ +}; + +/* + * Used to specify tables. These structures appear after the + * dm_ioctl. + */ +struct dm_target_spec { + int32_t status; /* used when reading from kernel only */ + uint64_t sector_start; + uint32_t length; + + /* + * Offset in bytes (from the start of this struct) to + * next target_spec. + */ + uint32_t next; + + char target_type[DM_MAX_TYPE_NAME]; + + /* + * Parameter string starts immediately after this object. + * Be careful to add padding after string to ensure correct + * alignment of subsequent dm_target_spec. + */ +}; + +/* + * Used to retrieve the target dependencies. + */ +struct dm_target_deps { + uint32_t count; + + __kernel_dev_t dev[0]; /* out */ +}; + +/* + * If you change this make sure you make the corresponding change + * to dm-ioctl.c:lookup_ioctl() + */ +enum { + /* Top level cmds */ + DM_VERSION_CMD = 0, + DM_REMOVE_ALL_CMD, + + /* device level cmds */ + DM_DEV_CREATE_CMD, + DM_DEV_REMOVE_CMD, + DM_DEV_RELOAD_CMD, + DM_DEV_RENAME_CMD, + DM_DEV_SUSPEND_CMD, + DM_DEV_DEPS_CMD, + DM_DEV_STATUS_CMD, + + /* target level cmds */ + DM_TARGET_STATUS_CMD, + DM_TARGET_WAIT_CMD +}; + +#define DM_IOCTL 0xfd + +#define DM_VERSION _IOWR(DM_IOCTL, DM_VERSION_CMD, struct dm_ioctl) +#define DM_REMOVE_ALL _IOWR(DM_IOCTL, DM_REMOVE_ALL_CMD, struct dm_ioctl) + +#define DM_DEV_CREATE _IOWR(DM_IOCTL, DM_DEV_CREATE_CMD, struct dm_ioctl) +#define DM_DEV_REMOVE _IOWR(DM_IOCTL, DM_DEV_REMOVE_CMD, struct dm_ioctl) +#define DM_DEV_RELOAD _IOWR(DM_IOCTL, DM_DEV_RELOAD_CMD, struct dm_ioctl) +#define DM_DEV_SUSPEND _IOWR(DM_IOCTL, DM_DEV_SUSPEND_CMD, struct dm_ioctl) +#define DM_DEV_RENAME _IOWR(DM_IOCTL, DM_DEV_RENAME_CMD, struct dm_ioctl) +#define DM_DEV_DEPS _IOWR(DM_IOCTL, DM_DEV_DEPS_CMD, struct dm_ioctl) +#define DM_DEV_STATUS _IOWR(DM_IOCTL, DM_DEV_STATUS_CMD, struct dm_ioctl) + +#define DM_TARGET_STATUS _IOWR(DM_IOCTL, DM_TARGET_STATUS_CMD, struct dm_ioctl) +#define DM_TARGET_WAIT _IOWR(DM_IOCTL, DM_TARGET_WAIT_CMD, struct dm_ioctl) + +#define DM_VERSION_MAJOR 1 +#define DM_VERSION_MINOR 0 +#define DM_VERSION_PATCHLEVEL 0 +#define DM_VERSION_EXTRA "-ioctl-cvs (2002-06-19)" + +/* Status bits */ +#define DM_READONLY_FLAG 0x00000001 +#define DM_SUSPEND_FLAG 0x00000002 +#define DM_EXISTS_FLAG 0x00000004 +#define DM_PERSISTENT_DEV_FLAG 0x00000008 + +/* + * Flag passed into ioctl STATUS command to get table information + * rather than current status. + */ +#define DM_STATUS_TABLE_FLAG 0x00000010 + +#endif /* _LINUX_DM_IOCTL_H */ diff --git a/kernel/ioctl/dm-ioctl.h.in b/kernel/ioctl/dm-ioctl.h.in deleted file mode 100644 index 3a2961d..0000000 --- a/kernel/ioctl/dm-ioctl.h.in +++ /dev/null @@ -1,113 +0,0 @@ -/* - * Copyright (C) 2001 Sistina Software (UK) Limited. - * - * This file is released under the LGPL. - */ - -#ifndef _LINUX_DM_IOCTL_H -#define _LINUX_DM_IOCTL_H - -#include "device-mapper.h" - -/* - * Implements a traditional ioctl interface to the device mapper. - */ - -/* - * All ioctl arguments consist of a single chunk of memory, with - * this structure at the start. If a uuid is specified any - * lookup (eg. for a DM_INFO) will be done on that, *not* the - * name. - */ -struct dm_ioctl { - char version[16]; - - unsigned long data_size; /* total size of data passed in - * including this struct */ - - unsigned long data_start; /* offset to start of data - * relative to start of this struct */ - - char name[DM_NAME_LEN]; /* device name */ - - unsigned int target_count; /* in/out */ - unsigned int open_count; /* out */ - unsigned int flags; /* in/out */ - - __kernel_dev_t dev; /* in/out */ - - char uuid[DM_UUID_LEN]; /* unique identifier for - * the block device */ -}; - -/* - * Used to specify tables. These structures appear after the - * dm_ioctl. - */ -struct dm_target_spec { - int32_t status; /* used when reading from kernel only */ - unsigned long long sector_start; - unsigned long long length; - - char target_type[DM_MAX_TYPE_NAME]; - - unsigned long next; /* offset in bytes to next target_spec */ - - /* - * Parameter string starts immediately after this object. - * Be careful to add padding after string to ensure correct - * alignment of subsequent dm_target_spec. - */ -}; - -/* - * Used to retrieve the target dependencies. - */ -struct dm_target_deps { - unsigned int count; - - __kernel_dev_t dev[0]; /* out */ -}; - -#define DM_IOCTL 0xfd - -enum { - DM_CREATE_CMD = 0, - DM_REMOVE_CMD, - DM_SUSPEND_CMD, - DM_RELOAD_CMD, - DM_INFO_CMD, - DM_RENAME_CMD, - DM_VERSION_CMD, - DM_DEPS_CMD, - DM_REMOVE_ALL_CMD, - DM_GET_STATUS_CMD, - DM_WAIT_EVENT_CMD -}; - -#define DM_CREATE _IOWR(DM_IOCTL, DM_CREATE_CMD, struct dm_ioctl) -#define DM_REMOVE _IOW(DM_IOCTL, DM_REMOVE_CMD, struct dm_ioctl) -#define DM_SUSPEND _IOW(DM_IOCTL, DM_SUSPEND_CMD, struct dm_ioctl) -#define DM_RELOAD _IOW(DM_IOCTL, DM_RELOAD_CMD, struct dm_ioctl) -#define DM_INFO _IOWR(DM_IOCTL, DM_INFO_CMD, struct dm_ioctl) -#define DM_RENAME _IOW(DM_IOCTL, DM_RENAME_CMD, struct dm_ioctl) -#define DM_VERSION _IOWR(DM_IOCTL, DM_VERSION_CMD, struct dm_ioctl) -#define DM_DEPS _IOWR(DM_IOCTL, DM_DEPS_CMD, struct dm_ioctl) -#define DM_REMOVE_ALL _IOR(DM_IOCTL, DM_REMOVE_ALL_CMD, struct dm_ioctl) -#define DM_GET_STATUS _IOWR(DM_IOCTL, DM_GET_STATUS_CMD, struct dm_ioctl) -#define DM_WAIT_EVENT _IOR(DM_IOCTL, DM_WAIT_EVENT_CMD, struct dm_ioctl) - -#define DM_IOCTL_VERSION @DM_IOCTL_VERSION@ -#define DM_DRIVER_VERSION @DM_DRIVER_VERSION@ - -/* Status bits */ -#define DM_READONLY_FLAG 0x00000001 -#define DM_SUSPEND_FLAG 0x00000002 -#define DM_EXISTS_FLAG 0x00000004 -#define DM_PERSISTENT_DEV_FLAG 0x00000008 - -/* Flag passed into ioctl STATUS command to get table information - rather than current status */ -#define DM_STATUS_TABLE_FLAG 0x00000010 - -#endif /* _LINUX_DM_IOCTL_H */ diff --git a/lib/Makefile.in b/lib/Makefile.in index 53fa82d..ae1a251 100644 --- a/lib/Makefile.in +++ b/lib/Makefile.in @@ -31,18 +31,7 @@ install_fs: fs/libdevmapper.so install_ioctl: ioctl/libdevmapper.so $(INSTALL) -D -o $(OWNER) -g $(GROUP) -m 555 $(STRIP) $< \ - $(libdir)/libdevmapper.so.$(LIB_VERSION).$(IOCTL_VERSION) - $(LN_S) -f libdevmapper.so.$(LIB_VERSION).$(IOCTL_VERSION) \ - $(libdir)/libdevmapper.so.$(LIB_VERSION) - -#ioctl/libdevmapper.o: ioctl_version - -#ioctl_version: ioctl/libdevmapper.c -# @echo Checking library version compatible with kernel version in dm-ioctl.h -# test "$(IOCTL_VERSION)" = \ -# "$(shell $(CC) -E -dM $(INCLUDES) $(CFLAGS) \ -# ioctl/libdevmapper.c | \ -# awk -F '[ \t\"]+' '/DM_IOCTL_VERSION/ {print $$3}' )" + $(libdir)/libdevmapper.so.$(LIB_VERSION) distclean_lib: $(RM) libdm-common.h @@ -50,3 +39,4 @@ distclean_lib: distclean: distclean_lib .PHONY: distclean_lib distclean + diff --git a/lib/ioctl/libdevmapper.c b/lib/ioctl/libdevmapper.c index f0545c0..b33e533 100644 --- a/lib/ioctl/libdevmapper.c +++ b/lib/ioctl/libdevmapper.c @@ -16,7 +16,7 @@ #include #include -#include +#include #include #include @@ -25,20 +25,32 @@ #define ALIGNMENT sizeof(int) -static char *dm_cmd_list[] = { - "create", - "reload", - "remove", - "remove_all", - "suspend", - "resume", - "info", - "deps", - "rename", - "version", - "status", - "table", - "waitevent" +/* + * Ensure build compatibility. The hard-coded version here (major, minor) + * is the highest present in the _cmd_data array below. + */ +#if DM_VERSION_MAJOR != 1 || DM_VERSION_MINOR < 0 + #error The version of dm-ioctl.h included is incompatible. +#endif + +static struct { + char *name; + int cmd; + int version[3]; +} _cmd_data[] = { + { "create", DM_DEV_CREATE, {1, 0, 0} }, + { "reload", DM_DEV_RELOAD, {1, 0, 0} }, + { "remove", DM_DEV_REMOVE, {1, 0, 0} }, + { "remove_all", DM_REMOVE_ALL, {1, 0, 0} }, + { "suspend", DM_DEV_SUSPEND, {1, 0, 0} }, + { "resume", DM_DEV_SUSPEND, {1, 0, 0} }, + { "info", DM_DEV_STATUS, {1, 0, 0} }, + { "deps", DM_DEV_DEPS, {1, 0, 0} }, + { "rename", DM_DEV_RENAME, {1, 0, 0} }, + { "version", DM_VERSION, {1, 0, 0} }, + { "status", DM_TARGET_STATUS, {1, 0, 0} }, + { "table", DM_TARGET_STATUS, {1, 0, 0} }, + { "waitevent", DM_TARGET_WAIT, {1, 0, 0} }, }; static void *_align(void *ptr, unsigned int a) @@ -283,9 +295,9 @@ static struct dm_ioctl *_flatten(struct dm_task *dmt) memset(dmi, 0, len); - dmi->version[0] = DM_IOCTL_MAJOR; - dmi->version[1] = DM_IOCTL_MINOR; - dmi->version[2] = DM_IOCTL_PATCH; + dmi->version[0] = _cmd_data[dmt->type].version[0]; + dmi->version[1] = _cmd_data[dmt->type].version[1]; + dmi->version[2] = _cmd_data[dmt->type].version[2]; dmi->data_size = len; dmi->data_start = sizeof(struct dm_ioctl); @@ -343,71 +355,23 @@ int dm_task_run(struct dm_task *dmt) goto bad; } - switch (dmt->type) { - case DM_DEVICE_CREATE: - command = DM_DEV_CREATE; - break; - - case DM_DEVICE_RELOAD: - command = DM_DEV_RELOAD; - break; - - case DM_DEVICE_REMOVE: - command = DM_DEV_REMOVE; - break; - - case DM_DEVICE_REMOVE_ALL: - command = DM_REMOVE_ALL; - break; - - case DM_DEVICE_SUSPEND: - command = DM_DEV_SUSPEND; - break; - - case DM_DEVICE_RESUME: - command = DM_DEV_SUSPEND; - break; - - case DM_DEVICE_INFO: - command = DM_DEV_STATUS; - break; - - case DM_DEVICE_DEPS: - command = DM_DEV_DEPS; - break; - - case DM_DEVICE_RENAME: - command = DM_DEV_RENAME; - break; - - case DM_DEVICE_VERSION: - command = DM_VERSION; - break; - - case DM_DEVICE_STATUS: - command = DM_TARGET_STATUS; - break; - - case DM_DEVICE_TABLE: - dmi->flags |= DM_STATUS_TABLE_FLAG; - command = DM_TARGET_STATUS; - break; - - case DM_DEVICE_WAITEVENT: - command = DM_TARGET_WAIT; - break; - - default: + if (dmt->type >= (sizeof(_cmd_data) / sizeof(*_cmd_data))) { log_error("Internal error: unknown device-mapper task %d", dmt->type); goto bad; } - log_debug("dm %s %s %s %s", dm_cmd_list[dmt->type], dmi->name, + command = _cmd_data[dmt->type].cmd; + + if (dmt->type == DM_DEVICE_TABLE) + dmi->flags |= DM_STATUS_TABLE_FLAG; + + + log_debug("dm %s %s %s %s", _cmd_data[dmt->type].name, dmi->name, dmi->uuid, dmt->newname ? dmt->newname : ""); if (ioctl(fd, command, dmi) < 0) { - log_error("device-mapper ioctl cmd %d failed: %s", dmt->type, - strerror(errno)); + log_error("device-mapper ioctl cmd %d failed: %s", + _IOC_NR(command), strerror(errno)); goto bad; } diff --git a/make.tmpl.in b/make.tmpl.in index 7e50a15..9906164 100644 --- a/make.tmpl.in +++ b/make.tmpl.in @@ -69,16 +69,12 @@ STRIP= LIB_VERSION := $(shell cat $(top_srcdir)/VERSION | \ awk -F '.' '{printf "%s.%s",$$1,$$2}') -IOCTL_VERSION := $(shell cat $(top_srcdir)/kernel/VERSION | \ - awk -F '.' '{printf "%s.%s",$$1,$$2}') - INCLUDES+=-I. -I$(top_srcdir)/include -I$(kerneldir)/include INC_LNS=$(top_srcdir)/include/.symlinks_created LD_FLAGS+=-L$(interfacedir) -DEPS=$(top_srcdir)/make.tmpl $(top_srcdir)/VERSION \ - $(top_srcdir)/kernel/VERSION Makefile $(INC_LNS) +DEPS=$(top_srcdir)/make.tmpl $(top_srcdir)/VERSION Makefile $(INC_LNS) OBJECTS=$(SOURCES:%.c=%.o)