Merge with Linux 2.5.74.
[linux-2.6/linux-mips.git] / drivers / md / dm-ioctl.c
blob744c3273e6e30117eb1832b541d42c221711ff05
1 /*
2 * Copyright (C) 2001, 2002 Sistina Software (UK) Limited.
4 * This file is released under the GPL.
5 */
7 #include "dm.h"
9 #include <linux/module.h>
10 #include <linux/vmalloc.h>
11 #include <linux/miscdevice.h>
12 #include <linux/dm-ioctl.h>
13 #include <linux/init.h>
14 #include <linux/wait.h>
15 #include <linux/blk.h>
16 #include <linux/slab.h>
17 #include <linux/devfs_fs_kernel.h>
19 #include <asm/uaccess.h>
21 #define DM_DRIVER_EMAIL "dm@uk.sistina.com"
23 /*-----------------------------------------------------------------
24 * The ioctl interface needs to be able to look up devices by
25 * name or uuid.
26 *---------------------------------------------------------------*/
27 struct hash_cell {
28 struct list_head name_list;
29 struct list_head uuid_list;
31 char *name;
32 char *uuid;
33 struct mapped_device *md;
36 #define NUM_BUCKETS 64
37 #define MASK_BUCKETS (NUM_BUCKETS - 1)
38 static struct list_head _name_buckets[NUM_BUCKETS];
39 static struct list_head _uuid_buckets[NUM_BUCKETS];
41 void dm_hash_remove_all(void);
44 * Guards access to all three tables.
46 static DECLARE_RWSEM(_hash_lock);
48 static void init_buckets(struct list_head *buckets)
50 unsigned int i;
52 for (i = 0; i < NUM_BUCKETS; i++)
53 INIT_LIST_HEAD(buckets + i);
56 int dm_hash_init(void)
58 init_buckets(_name_buckets);
59 init_buckets(_uuid_buckets);
60 devfs_mk_dir(DM_DIR);
61 return 0;
64 void dm_hash_exit(void)
66 dm_hash_remove_all();
67 devfs_remove(DM_DIR);
70 /*-----------------------------------------------------------------
71 * Hash function:
72 * We're not really concerned with the str hash function being
73 * fast since it's only used by the ioctl interface.
74 *---------------------------------------------------------------*/
75 static unsigned int hash_str(const char *str)
77 const unsigned int hash_mult = 2654435387U;
78 unsigned int h = 0;
80 while (*str)
81 h = (h + (unsigned int) *str++) * hash_mult;
83 return h & MASK_BUCKETS;
86 /*-----------------------------------------------------------------
87 * Code for looking up a device by name
88 *---------------------------------------------------------------*/
89 static struct hash_cell *__get_name_cell(const char *str)
91 struct list_head *tmp;
92 struct hash_cell *hc;
93 unsigned int h = hash_str(str);
95 list_for_each (tmp, _name_buckets + h) {
96 hc = list_entry(tmp, struct hash_cell, name_list);
97 if (!strcmp(hc->name, str))
98 return hc;
101 return NULL;
104 static struct hash_cell *__get_uuid_cell(const char *str)
106 struct list_head *tmp;
107 struct hash_cell *hc;
108 unsigned int h = hash_str(str);
110 list_for_each (tmp, _uuid_buckets + h) {
111 hc = list_entry(tmp, struct hash_cell, uuid_list);
112 if (!strcmp(hc->uuid, str))
113 return hc;
116 return NULL;
119 /*-----------------------------------------------------------------
120 * Inserting, removing and renaming a device.
121 *---------------------------------------------------------------*/
122 static inline char *kstrdup(const char *str)
124 char *r = kmalloc(strlen(str) + 1, GFP_KERNEL);
125 if (r)
126 strcpy(r, str);
127 return r;
130 static struct hash_cell *alloc_cell(const char *name, const char *uuid,
131 struct mapped_device *md)
133 struct hash_cell *hc;
135 hc = kmalloc(sizeof(*hc), GFP_KERNEL);
136 if (!hc)
137 return NULL;
139 hc->name = kstrdup(name);
140 if (!hc->name) {
141 kfree(hc);
142 return NULL;
145 if (!uuid)
146 hc->uuid = NULL;
148 else {
149 hc->uuid = kstrdup(uuid);
150 if (!hc->uuid) {
151 kfree(hc->name);
152 kfree(hc);
153 return NULL;
157 INIT_LIST_HEAD(&hc->name_list);
158 INIT_LIST_HEAD(&hc->uuid_list);
159 hc->md = md;
160 return hc;
163 static void free_cell(struct hash_cell *hc)
165 if (hc) {
166 kfree(hc->name);
167 kfree(hc->uuid);
168 kfree(hc);
173 * devfs stuff.
175 static int register_with_devfs(struct hash_cell *hc)
177 struct gendisk *disk = dm_disk(hc->md);
179 devfs_mk_bdev(MKDEV(disk->major, disk->first_minor),
180 S_IFBLK | S_IRUSR | S_IWUSR | S_IRGRP,
181 DM_DIR "/%s", hc->name);
182 return 0;
185 static int unregister_with_devfs(struct hash_cell *hc)
187 devfs_remove(DM_DIR"/%s", hc->name);
188 return 0;
192 * The kdev_t and uuid of a device can never change once it is
193 * initially inserted.
195 int dm_hash_insert(const char *name, const char *uuid, struct mapped_device *md)
197 struct hash_cell *cell;
200 * Allocate the new cells.
202 cell = alloc_cell(name, uuid, md);
203 if (!cell)
204 return -ENOMEM;
207 * Insert the cell into all three hash tables.
209 down_write(&_hash_lock);
210 if (__get_name_cell(name))
211 goto bad;
213 list_add(&cell->name_list, _name_buckets + hash_str(name));
215 if (uuid) {
216 if (__get_uuid_cell(uuid)) {
217 list_del(&cell->name_list);
218 goto bad;
220 list_add(&cell->uuid_list, _uuid_buckets + hash_str(uuid));
222 register_with_devfs(cell);
223 dm_get(md);
224 up_write(&_hash_lock);
226 return 0;
228 bad:
229 up_write(&_hash_lock);
230 free_cell(cell);
231 return -EBUSY;
234 void __hash_remove(struct hash_cell *hc)
236 /* remove from the dev hash */
237 list_del(&hc->uuid_list);
238 list_del(&hc->name_list);
239 unregister_with_devfs(hc);
240 dm_put(hc->md);
241 free_cell(hc);
244 void dm_hash_remove_all(void)
246 int i;
247 struct hash_cell *hc;
248 struct list_head *tmp, *n;
250 down_write(&_hash_lock);
251 for (i = 0; i < NUM_BUCKETS; i++) {
252 list_for_each_safe (tmp, n, _name_buckets + i) {
253 hc = list_entry(tmp, struct hash_cell, name_list);
254 __hash_remove(hc);
257 up_write(&_hash_lock);
260 int dm_hash_rename(const char *old, const char *new)
262 char *new_name, *old_name;
263 struct hash_cell *hc;
266 * duplicate new.
268 new_name = kstrdup(new);
269 if (!new_name)
270 return -ENOMEM;
272 down_write(&_hash_lock);
275 * Is new free ?
277 hc = __get_name_cell(new);
278 if (hc) {
279 DMWARN("asked to rename to an already existing name %s -> %s",
280 old, new);
281 up_write(&_hash_lock);
282 kfree(new_name);
283 return -EBUSY;
287 * Is there such a device as 'old' ?
289 hc = __get_name_cell(old);
290 if (!hc) {
291 DMWARN("asked to rename a non existent device %s -> %s",
292 old, new);
293 up_write(&_hash_lock);
294 kfree(new_name);
295 return -ENXIO;
299 * rename and move the name cell.
301 unregister_with_devfs(hc);
303 list_del(&hc->name_list);
304 old_name = hc->name;
305 hc->name = new_name;
306 list_add(&hc->name_list, _name_buckets + hash_str(new_name));
308 /* rename the device node in devfs */
309 register_with_devfs(hc);
311 up_write(&_hash_lock);
312 kfree(old_name);
313 return 0;
317 /*-----------------------------------------------------------------
318 * Implementation of the ioctl commands
319 *---------------------------------------------------------------*/
322 * All the ioctl commands get dispatched to functions with this
323 * prototype.
325 typedef int (*ioctl_fn)(struct dm_ioctl *param, struct dm_ioctl *user);
328 * Check a string doesn't overrun the chunk of
329 * memory we copied from userland.
331 static int valid_str(char *str, void *begin, void *end)
333 while (((void *) str >= begin) && ((void *) str < end))
334 if (!*str++)
335 return 0;
337 return -EINVAL;
340 static int next_target(struct dm_target_spec *last, uint32_t next,
341 void *begin, void *end,
342 struct dm_target_spec **spec, char **params)
344 *spec = (struct dm_target_spec *)
345 ((unsigned char *) last + next);
346 *params = (char *) (*spec + 1);
348 if (*spec < (last + 1) || ((void *) *spec > end))
349 return -EINVAL;
351 return valid_str(*params, begin, end);
354 static int populate_table(struct dm_table *table, struct dm_ioctl *args)
356 int r, first = 1;
357 unsigned int i = 0;
358 struct dm_target_spec *spec;
359 char *params;
360 void *begin, *end;
362 if (!args->target_count) {
363 DMWARN("populate_table: no targets specified");
364 return -EINVAL;
367 begin = (void *) args;
368 end = begin + args->data_size;
370 for (i = 0; i < args->target_count; i++) {
372 if (first)
373 r = next_target((struct dm_target_spec *) args,
374 args->data_start,
375 begin, end, &spec, &params);
376 else
377 r = next_target(spec, spec->next, begin, end,
378 &spec, &params);
380 if (r) {
381 DMWARN("unable to find target");
382 return -EINVAL;
385 r = dm_table_add_target(table, spec->target_type,
386 (sector_t) spec->sector_start,
387 (sector_t) spec->length,
388 params);
389 if (r) {
390 DMWARN("internal error adding target to table");
391 return -EINVAL;
394 first = 0;
397 return dm_table_complete(table);
401 * Round up the ptr to the next 'align' boundary. Obviously
402 * 'align' must be a power of 2.
404 static inline void *align_ptr(void *ptr, unsigned int align)
406 align--;
407 return (void *) (((unsigned long) (ptr + align)) & ~align);
411 * Copies a dm_ioctl and an optional additional payload to
412 * userland.
414 static int results_to_user(struct dm_ioctl *user, struct dm_ioctl *param,
415 void *data, uint32_t len)
417 int r;
418 void *ptr = NULL;
420 if (data) {
421 ptr = align_ptr(user + 1, sizeof(unsigned long));
422 param->data_start = ptr - (void *) user;
426 * The version number has already been filled in, so we
427 * just copy later fields.
429 r = copy_to_user(&user->data_size, &param->data_size,
430 sizeof(*param) - sizeof(param->version));
431 if (r)
432 return -EFAULT;
434 if (data) {
435 if (param->data_start + len > param->data_size)
436 return -ENOSPC;
438 if (copy_to_user(ptr, data, len))
439 r = -EFAULT;
442 return r;
446 * Fills in a dm_ioctl structure, ready for sending back to
447 * userland.
449 static int __info(struct mapped_device *md, struct dm_ioctl *param)
451 struct dm_table *table;
452 struct block_device *bdev;
453 struct gendisk *disk = dm_disk(md);
455 param->flags = DM_EXISTS_FLAG;
456 if (dm_suspended(md))
457 param->flags |= DM_SUSPEND_FLAG;
459 bdev = bdget_disk(disk, 0);
460 if (!bdev)
461 return -ENXIO;
463 param->dev = bdev->bd_dev;
464 param->open_count = bdev->bd_openers;
465 bdput(bdev);
467 if (disk->policy)
468 param->flags |= DM_READONLY_FLAG;
470 table = dm_get_table(md);
471 param->target_count = dm_table_get_num_targets(table);
472 dm_table_put(table);
474 return 0;
478 * Always use UUID for lookups if it's present, otherwise use name.
480 static inline struct mapped_device *find_device(struct dm_ioctl *param)
482 struct hash_cell *hc;
483 struct mapped_device *md = NULL;
485 down_read(&_hash_lock);
486 hc = *param->uuid ? __get_uuid_cell(param->uuid) :
487 __get_name_cell(param->name);
488 if (hc) {
489 md = hc->md;
492 * Sneakily write in both the name and the uuid
493 * while we have the cell.
495 strlcpy(param->name, hc->name, sizeof(param->name));
496 if (hc->uuid)
497 strlcpy(param->uuid, hc->uuid, sizeof(param->uuid));
498 else
499 param->uuid[0] = '\0';
501 dm_get(md);
503 up_read(&_hash_lock);
505 return md;
508 #define ALIGNMENT sizeof(int)
509 static void *_align(void *ptr, unsigned int a)
511 register unsigned long align = --a;
513 return (void *) (((unsigned long) ptr + align) & ~align);
517 * Copies device info back to user space, used by
518 * the create and info ioctls.
520 static int info(struct dm_ioctl *param, struct dm_ioctl *user)
522 struct mapped_device *md;
524 param->flags = 0;
526 md = find_device(param);
527 if (!md)
529 * Device not found - returns cleared exists flag.
531 goto out;
533 __info(md, param);
534 dm_put(md);
536 out:
537 return results_to_user(user, param, NULL, 0);
540 static inline int get_mode(struct dm_ioctl *param)
542 int mode = FMODE_READ | FMODE_WRITE;
544 if (param->flags & DM_READONLY_FLAG)
545 mode = FMODE_READ;
547 return mode;
550 static int check_name(const char *name)
552 if (name[0] == '/') {
553 DMWARN("invalid device name");
554 return -EINVAL;
557 return 0;
560 static int create(struct dm_ioctl *param, struct dm_ioctl *user)
562 int r;
563 struct dm_table *t;
564 struct mapped_device *md;
566 r = check_name(param->name);
567 if (r)
568 return r;
570 r = dm_table_create(&t, get_mode(param));
571 if (r)
572 return r;
574 r = populate_table(t, param);
575 if (r) {
576 dm_table_put(t);
577 return r;
580 if (param->flags & DM_PERSISTENT_DEV_FLAG)
581 r = dm_create_with_minor(minor(to_kdev_t(param->dev)), t, &md);
582 else
583 r = dm_create(t, &md);
585 if (r) {
586 dm_table_put(t);
587 return r;
589 dm_table_put(t); /* md will have grabbed its own reference */
591 set_disk_ro(dm_disk(md), (param->flags & DM_READONLY_FLAG) ? 1 : 0);
592 r = dm_hash_insert(param->name, *param->uuid ? param->uuid : NULL, md);
593 dm_put(md);
595 return r ? r : info(param, user);
599 * Build up the status struct for each target
601 static int __status(struct mapped_device *md, struct dm_ioctl *param,
602 char *outbuf, size_t *len)
604 unsigned int i, num_targets;
605 struct dm_target_spec *spec;
606 char *outptr;
607 status_type_t type;
608 struct dm_table *table = dm_get_table(md);
610 if (param->flags & DM_STATUS_TABLE_FLAG)
611 type = STATUSTYPE_TABLE;
612 else
613 type = STATUSTYPE_INFO;
615 outptr = outbuf;
617 /* Get all the target info */
618 num_targets = dm_table_get_num_targets(table);
619 for (i = 0; i < num_targets; i++) {
620 struct dm_target *ti = dm_table_get_target(table, i);
622 if (outptr - outbuf +
623 sizeof(struct dm_target_spec) > param->data_size) {
624 dm_table_put(table);
625 return -ENOMEM;
628 spec = (struct dm_target_spec *) outptr;
630 spec->status = 0;
631 spec->sector_start = ti->begin;
632 spec->length = ti->len;
633 strlcpy(spec->target_type, ti->type->name,
634 sizeof(spec->target_type));
636 outptr += sizeof(struct dm_target_spec);
638 /* Get the status/table string from the target driver */
639 if (ti->type->status)
640 ti->type->status(ti, type, outptr,
641 outbuf + param->data_size - outptr);
642 else
643 outptr[0] = '\0';
645 outptr += strlen(outptr) + 1;
646 _align(outptr, ALIGNMENT);
647 spec->next = outptr - outbuf;
650 param->target_count = num_targets;
651 *len = outptr - outbuf;
652 dm_table_put(table);
654 return 0;
658 * Return the status of a device as a text string for each
659 * target.
661 static int get_status(struct dm_ioctl *param, struct dm_ioctl *user)
663 struct mapped_device *md;
664 size_t len = 0;
665 int ret;
666 char *outbuf = NULL;
668 md = find_device(param);
669 if (!md)
671 * Device not found - returns cleared exists flag.
673 goto out;
675 /* We haven't a clue how long the resultant data will be so
676 just allocate as much as userland has allowed us and make sure
677 we don't overun it */
678 outbuf = kmalloc(param->data_size, GFP_KERNEL);
679 if (!outbuf)
680 goto out;
682 * Get the status of all targets
684 __status(md, param, outbuf, &len);
687 * Setup the basic dm_ioctl structure.
689 __info(md, param);
691 out:
692 if (md)
693 dm_put(md);
695 ret = results_to_user(user, param, outbuf, len);
697 if (outbuf)
698 kfree(outbuf);
700 return ret;
704 * Wait for a device to report an event
706 static int wait_device_event(struct dm_ioctl *param, struct dm_ioctl *user)
708 struct mapped_device *md;
709 struct dm_table *table;
710 DECLARE_WAITQUEUE(wq, current);
712 md = find_device(param);
713 if (!md)
715 * Device not found - returns cleared exists flag.
717 goto out;
720 * Setup the basic dm_ioctl structure.
722 __info(md, param);
725 * Wait for a notification event
727 set_current_state(TASK_INTERRUPTIBLE);
728 table = dm_get_table(md);
729 dm_table_add_wait_queue(table, &wq);
730 dm_table_put(table);
731 dm_put(md);
733 schedule();
735 out:
736 return results_to_user(user, param, NULL, 0);
740 * Retrieves a list of devices used by a particular dm device.
742 static int dep(struct dm_ioctl *param, struct dm_ioctl *user)
744 int r;
745 unsigned int count;
746 struct mapped_device *md;
747 struct list_head *tmp;
748 size_t len = 0;
749 struct dm_target_deps *deps = NULL;
750 struct dm_table *table;
752 md = find_device(param);
753 if (!md)
754 goto out;
755 table = dm_get_table(md);
758 * Setup the basic dm_ioctl structure.
760 __info(md, param);
763 * Count the devices.
765 count = 0;
766 list_for_each(tmp, dm_table_get_devices(table))
767 count++;
770 * Allocate a kernel space version of the dm_target_status
771 * struct.
773 if (array_too_big(sizeof(*deps), sizeof(*deps->dev), count)) {
774 dm_table_put(table);
775 dm_put(md);
776 return -ENOMEM;
779 len = sizeof(*deps) + (sizeof(*deps->dev) * count);
780 deps = kmalloc(len, GFP_KERNEL);
781 if (!deps) {
782 dm_table_put(table);
783 dm_put(md);
784 return -ENOMEM;
788 * Fill in the devices.
790 deps->count = count;
791 count = 0;
792 list_for_each(tmp, dm_table_get_devices(table)) {
793 struct dm_dev *dd = list_entry(tmp, struct dm_dev, list);
794 deps->dev[count++] = dd->bdev->bd_dev;
796 dm_table_put(table);
797 dm_put(md);
799 out:
800 r = results_to_user(user, param, deps, len);
802 kfree(deps);
803 return r;
806 static int remove(struct dm_ioctl *param, struct dm_ioctl *user)
808 struct hash_cell *hc;
810 down_write(&_hash_lock);
811 hc = *param->uuid ? __get_uuid_cell(param->uuid) :
812 __get_name_cell(param->name);
813 if (!hc) {
814 DMWARN("device doesn't appear to be in the dev hash table.");
815 up_write(&_hash_lock);
816 return -EINVAL;
820 * You may ask the interface to drop its reference to an
821 * in use device. This is no different to unlinking a
822 * file that someone still has open. The device will not
823 * actually be destroyed until the last opener closes it.
824 * The name and uuid of the device (both are interface
825 * properties) will be available for reuse immediately.
827 * You don't want to drop a _suspended_ device from the
828 * interface, since that will leave you with no way of
829 * resuming it.
831 if (dm_suspended(hc->md)) {
832 DMWARN("refusing to remove a suspended device.");
833 up_write(&_hash_lock);
834 return -EPERM;
837 __hash_remove(hc);
838 up_write(&_hash_lock);
839 return 0;
842 static int remove_all(struct dm_ioctl *param, struct dm_ioctl *user)
844 dm_hash_remove_all();
845 return 0;
848 static int suspend(struct dm_ioctl *param, struct dm_ioctl *user)
850 int r;
851 struct mapped_device *md;
853 md = find_device(param);
854 if (!md)
855 return -ENXIO;
857 if (param->flags & DM_SUSPEND_FLAG)
858 r = dm_suspend(md);
859 else
860 r = dm_resume(md);
862 dm_put(md);
863 return r;
866 static int reload(struct dm_ioctl *param, struct dm_ioctl *user)
868 int r;
869 struct mapped_device *md;
870 struct dm_table *t;
872 r = dm_table_create(&t, get_mode(param));
873 if (r)
874 return r;
876 r = populate_table(t, param);
877 if (r) {
878 dm_table_put(t);
879 return r;
882 md = find_device(param);
883 if (!md) {
884 dm_table_put(t);
885 return -ENXIO;
888 r = dm_swap_table(md, t);
889 if (r) {
890 dm_put(md);
891 dm_table_put(t);
892 return r;
894 dm_table_put(t); /* md will have taken its own reference */
896 set_disk_ro(dm_disk(md), (param->flags & DM_READONLY_FLAG) ? 1 : 0);
897 dm_put(md);
899 r = info(param, user);
900 return r;
903 static int rename(struct dm_ioctl *param, struct dm_ioctl *user)
905 int r;
906 char *new_name = (char *) param + param->data_start;
908 if (valid_str(new_name, (void *) param,
909 (void *) param + param->data_size)) {
910 DMWARN("Invalid new logical volume name supplied.");
911 return -EINVAL;
914 r = check_name(new_name);
915 if (r)
916 return r;
918 return dm_hash_rename(param->name, new_name);
922 /*-----------------------------------------------------------------
923 * Implementation of open/close/ioctl on the special char
924 * device.
925 *---------------------------------------------------------------*/
926 static ioctl_fn lookup_ioctl(unsigned int cmd)
928 static struct {
929 int cmd;
930 ioctl_fn fn;
931 } _ioctls[] = {
932 {DM_VERSION_CMD, NULL}, /* version is dealt with elsewhere */
933 {DM_REMOVE_ALL_CMD, remove_all},
934 {DM_DEV_CREATE_CMD, create},
935 {DM_DEV_REMOVE_CMD, remove},
936 {DM_DEV_RELOAD_CMD, reload},
937 {DM_DEV_RENAME_CMD, rename},
938 {DM_DEV_SUSPEND_CMD, suspend},
939 {DM_DEV_DEPS_CMD, dep},
940 {DM_DEV_STATUS_CMD, info},
941 {DM_TARGET_STATUS_CMD, get_status},
942 {DM_TARGET_WAIT_CMD, wait_device_event},
945 return (cmd >= ARRAY_SIZE(_ioctls)) ? NULL : _ioctls[cmd].fn;
949 * As well as checking the version compatibility this always
950 * copies the kernel interface version out.
952 static int check_version(unsigned int cmd, struct dm_ioctl *user)
954 uint32_t version[3];
955 int r = 0;
957 if (copy_from_user(version, user->version, sizeof(version)))
958 return -EFAULT;
960 if ((DM_VERSION_MAJOR != version[0]) ||
961 (DM_VERSION_MINOR < version[1])) {
962 DMWARN("ioctl interface mismatch: "
963 "kernel(%u.%u.%u), user(%u.%u.%u), cmd(%d)",
964 DM_VERSION_MAJOR, DM_VERSION_MINOR,
965 DM_VERSION_PATCHLEVEL,
966 version[0], version[1], version[2], cmd);
967 r = -EINVAL;
971 * Fill in the kernel version.
973 version[0] = DM_VERSION_MAJOR;
974 version[1] = DM_VERSION_MINOR;
975 version[2] = DM_VERSION_PATCHLEVEL;
976 if (copy_to_user(user->version, version, sizeof(version)))
977 return -EFAULT;
979 return r;
982 static void free_params(struct dm_ioctl *param)
984 vfree(param);
987 static int copy_params(struct dm_ioctl *user, struct dm_ioctl **param)
989 struct dm_ioctl tmp, *dmi;
991 if (copy_from_user(&tmp, user, sizeof(tmp)))
992 return -EFAULT;
994 if (tmp.data_size < sizeof(tmp))
995 return -EINVAL;
997 dmi = (struct dm_ioctl *) vmalloc(tmp.data_size);
998 if (!dmi)
999 return -ENOMEM;
1001 if (copy_from_user(dmi, user, tmp.data_size)) {
1002 vfree(dmi);
1003 return -EFAULT;
1006 *param = dmi;
1007 return 0;
1010 static int validate_params(uint cmd, struct dm_ioctl *param)
1012 /* Ignores parameters */
1013 if (cmd == DM_REMOVE_ALL_CMD)
1014 return 0;
1016 /* Unless creating, either name of uuid but not both */
1017 if (cmd != DM_DEV_CREATE_CMD) {
1018 if ((!*param->uuid && !*param->name) ||
1019 (*param->uuid && *param->name)) {
1020 DMWARN("one of name or uuid must be supplied");
1021 return -EINVAL;
1025 /* Ensure strings are terminated */
1026 param->name[DM_NAME_LEN - 1] = '\0';
1027 param->uuid[DM_UUID_LEN - 1] = '\0';
1029 return 0;
1032 static int ctl_ioctl(struct inode *inode, struct file *file,
1033 uint command, ulong u)
1035 int r = 0;
1036 unsigned int cmd;
1037 struct dm_ioctl *param;
1038 struct dm_ioctl *user = (struct dm_ioctl *) u;
1039 ioctl_fn fn = NULL;
1041 /* only root can play with this */
1042 if (!capable(CAP_SYS_ADMIN))
1043 return -EACCES;
1045 if (_IOC_TYPE(command) != DM_IOCTL)
1046 return -ENOTTY;
1048 cmd = _IOC_NR(command);
1051 * Check the interface version passed in. This also
1052 * writes out the kernels interface version.
1054 r = check_version(cmd, user);
1055 if (r)
1056 return r;
1059 * Nothing more to do for the version command.
1061 if (cmd == DM_VERSION_CMD)
1062 return 0;
1064 fn = lookup_ioctl(cmd);
1065 if (!fn) {
1066 DMWARN("dm_ctl_ioctl: unknown command 0x%x", command);
1067 return -ENOTTY;
1071 * Copy the parameters into kernel space.
1073 r = copy_params(user, &param);
1074 if (r)
1075 return r;
1077 r = validate_params(cmd, param);
1078 if (r) {
1079 free_params(param);
1080 return r;
1083 r = fn(param, user);
1084 free_params(param);
1085 return r;
1088 static struct file_operations _ctl_fops = {
1089 .ioctl = ctl_ioctl,
1090 .owner = THIS_MODULE,
1093 static struct miscdevice _dm_misc = {
1094 .minor = MISC_DYNAMIC_MINOR,
1095 .name = DM_NAME,
1096 .devfs_name = "mapper/control",
1097 .fops = &_ctl_fops
1101 * Create misc character device and link to DM_DIR/control.
1103 int __init dm_interface_init(void)
1105 int r;
1107 r = dm_hash_init();
1108 if (r)
1109 return r;
1111 r = misc_register(&_dm_misc);
1112 if (r) {
1113 DMERR("misc_register failed for control device");
1114 dm_hash_exit();
1115 return r;
1118 DMINFO("%d.%d.%d%s initialised: %s", DM_VERSION_MAJOR,
1119 DM_VERSION_MINOR, DM_VERSION_PATCHLEVEL, DM_VERSION_EXTRA,
1120 DM_DRIVER_EMAIL);
1121 return 0;
1123 if (misc_deregister(&_dm_misc) < 0)
1124 DMERR("misc_deregister failed for control device");
1125 dm_hash_exit();
1126 return r;
1129 void dm_interface_exit(void)
1131 if (misc_deregister(&_dm_misc) < 0)
1132 DMERR("misc_deregister failed for control device");
1133 dm_hash_exit();