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.
-0.95.12-cvs (2002-06-13)
+0.96.01-cvs (2002-06-19)
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
-
-
-
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
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
lib/Makefile \
lib/libdm-common.h \
kernel/Makefile \
-kernel/common/dm.c \
-kernel/ioctl/dm-ioctl.h \
man/Makefile \
"}
EOF
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)
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
lib/Makefile \
lib/libdm-common.h \
kernel/Makefile \
-kernel/common/dm.c \
-kernel/ioctl/dm-ioctl.h \
man/Makefile \
)
clean:
distclean:
- $(RM) Makefile common/dm.c ioctl/dm-ioctl.h
+ $(RM) Makefile
.PHONY: install clean distclean all
+++ /dev/null
-0.94.12-cvs (2002-06-13)
}
if (err) {
- DMERR("Mirror block IO failed"); /* More detail to follow... */
+ DMERR("Mirror block IO failed"); /* More detail to follow... */
lc->error = 1;
return;
}
#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;
_dev_dir = devfs_mk_dir(0, DM_DIR, NULL);
- DMINFO("%s initialised: %s", _version, _email);
return 0;
}
hardsect_size[_major] = NULL;
_major = 0;
- DMINFO("%s cleaned up", _version);
+ DMINFO("cleaned up");
}
/*
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;
}
#include <linux/init.h>
#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))
#include <linux/init.h>
#include <linux/wait.h>
-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;
}
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)
{
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");
* 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;
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
*/
{
int i;
struct dm_target_spec *spec;
- unsigned long long sector = 0LL;
+ uint64_t sector = 0LL;
char *outptr;
status_type_t type;
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.
*/
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;
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;
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;
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 */
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 */
}
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:
--- /dev/null
+/*
+ * 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 */
+++ /dev/null
-/*
- * 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 */
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
distclean: distclean_lib
.PHONY: distclean_lib distclean
+
#include <errno.h>
#include <linux/kdev_t.h>
-#include <linux/fs.h>
+#include <linux/limits.h>
#include <sys/ioctl.h>
#include <linux/dm-ioctl.h>
#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)
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);
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;
}
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)