diff options
Diffstat (limited to 'drivers/md/dm-ioctl.c')
-rw-r--r-- | drivers/md/dm-ioctl.c | 100 |
1 files changed, 85 insertions, 15 deletions
diff --git a/drivers/md/dm-ioctl.c b/drivers/md/dm-ioctl.c index 442e2be6052e..8edd6435414d 100644 --- a/drivers/md/dm-ioctl.c +++ b/drivers/md/dm-ioctl.c | |||
@@ -15,6 +15,7 @@ | |||
15 | #include <linux/slab.h> | 15 | #include <linux/slab.h> |
16 | #include <linux/devfs_fs_kernel.h> | 16 | #include <linux/devfs_fs_kernel.h> |
17 | #include <linux/dm-ioctl.h> | 17 | #include <linux/dm-ioctl.h> |
18 | #include <linux/hdreg.h> | ||
18 | 19 | ||
19 | #include <asm/uaccess.h> | 20 | #include <asm/uaccess.h> |
20 | 21 | ||
@@ -244,9 +245,9 @@ static void __hash_remove(struct hash_cell *hc) | |||
244 | dm_table_put(table); | 245 | dm_table_put(table); |
245 | } | 246 | } |
246 | 247 | ||
247 | dm_put(hc->md); | ||
248 | if (hc->new_map) | 248 | if (hc->new_map) |
249 | dm_table_put(hc->new_map); | 249 | dm_table_put(hc->new_map); |
250 | dm_put(hc->md); | ||
250 | free_cell(hc); | 251 | free_cell(hc); |
251 | } | 252 | } |
252 | 253 | ||
@@ -600,12 +601,22 @@ static int dev_create(struct dm_ioctl *param, size_t param_size) | |||
600 | */ | 601 | */ |
601 | static struct hash_cell *__find_device_hash_cell(struct dm_ioctl *param) | 602 | static struct hash_cell *__find_device_hash_cell(struct dm_ioctl *param) |
602 | { | 603 | { |
604 | struct mapped_device *md; | ||
605 | void *mdptr = NULL; | ||
606 | |||
603 | if (*param->uuid) | 607 | if (*param->uuid) |
604 | return __get_uuid_cell(param->uuid); | 608 | return __get_uuid_cell(param->uuid); |
605 | else if (*param->name) | 609 | |
610 | if (*param->name) | ||
606 | return __get_name_cell(param->name); | 611 | return __get_name_cell(param->name); |
607 | else | 612 | |
608 | return dm_get_mdptr(huge_decode_dev(param->dev)); | 613 | md = dm_get_md(huge_decode_dev(param->dev)); |
614 | if (md) { | ||
615 | mdptr = dm_get_mdptr(md); | ||
616 | dm_put(md); | ||
617 | } | ||
618 | |||
619 | return mdptr; | ||
609 | } | 620 | } |
610 | 621 | ||
611 | static struct mapped_device *find_device(struct dm_ioctl *param) | 622 | static struct mapped_device *find_device(struct dm_ioctl *param) |
@@ -690,6 +701,54 @@ static int dev_rename(struct dm_ioctl *param, size_t param_size) | |||
690 | return dm_hash_rename(param->name, new_name); | 701 | return dm_hash_rename(param->name, new_name); |
691 | } | 702 | } |
692 | 703 | ||
704 | static int dev_set_geometry(struct dm_ioctl *param, size_t param_size) | ||
705 | { | ||
706 | int r = -EINVAL, x; | ||
707 | struct mapped_device *md; | ||
708 | struct hd_geometry geometry; | ||
709 | unsigned long indata[4]; | ||
710 | char *geostr = (char *) param + param->data_start; | ||
711 | |||
712 | md = find_device(param); | ||
713 | if (!md) | ||
714 | return -ENXIO; | ||
715 | |||
716 | if (geostr < (char *) (param + 1) || | ||
717 | invalid_str(geostr, (void *) param + param_size)) { | ||
718 | DMWARN("Invalid geometry supplied."); | ||
719 | goto out; | ||
720 | } | ||
721 | |||
722 | x = sscanf(geostr, "%lu %lu %lu %lu", indata, | ||
723 | indata + 1, indata + 2, indata + 3); | ||
724 | |||
725 | if (x != 4) { | ||
726 | DMWARN("Unable to interpret geometry settings."); | ||
727 | goto out; | ||
728 | } | ||
729 | |||
730 | if (indata[0] > 65535 || indata[1] > 255 || | ||
731 | indata[2] > 255 || indata[3] > ULONG_MAX) { | ||
732 | DMWARN("Geometry exceeds range limits."); | ||
733 | goto out; | ||
734 | } | ||
735 | |||
736 | geometry.cylinders = indata[0]; | ||
737 | geometry.heads = indata[1]; | ||
738 | geometry.sectors = indata[2]; | ||
739 | geometry.start = indata[3]; | ||
740 | |||
741 | r = dm_set_geometry(md, &geometry); | ||
742 | if (!r) | ||
743 | r = __dev_status(md, param); | ||
744 | |||
745 | param->data_size = 0; | ||
746 | |||
747 | out: | ||
748 | dm_put(md); | ||
749 | return r; | ||
750 | } | ||
751 | |||
693 | static int do_suspend(struct dm_ioctl *param) | 752 | static int do_suspend(struct dm_ioctl *param) |
694 | { | 753 | { |
695 | int r = 0; | 754 | int r = 0; |
@@ -975,33 +1034,43 @@ static int table_load(struct dm_ioctl *param, size_t param_size) | |||
975 | int r; | 1034 | int r; |
976 | struct hash_cell *hc; | 1035 | struct hash_cell *hc; |
977 | struct dm_table *t; | 1036 | struct dm_table *t; |
1037 | struct mapped_device *md; | ||
978 | 1038 | ||
979 | r = dm_table_create(&t, get_mode(param), param->target_count); | 1039 | md = find_device(param); |
1040 | if (!md) | ||
1041 | return -ENXIO; | ||
1042 | |||
1043 | r = dm_table_create(&t, get_mode(param), param->target_count, md); | ||
980 | if (r) | 1044 | if (r) |
981 | return r; | 1045 | goto out; |
982 | 1046 | ||
983 | r = populate_table(t, param, param_size); | 1047 | r = populate_table(t, param, param_size); |
984 | if (r) { | 1048 | if (r) { |
985 | dm_table_put(t); | 1049 | dm_table_put(t); |
986 | return r; | 1050 | goto out; |
987 | } | 1051 | } |
988 | 1052 | ||
989 | down_write(&_hash_lock); | 1053 | down_write(&_hash_lock); |
990 | hc = __find_device_hash_cell(param); | 1054 | hc = dm_get_mdptr(md); |
991 | if (!hc) { | 1055 | if (!hc || hc->md != md) { |
992 | DMWARN("device doesn't appear to be in the dev hash table."); | 1056 | DMWARN("device has been removed from the dev hash table."); |
993 | up_write(&_hash_lock); | ||
994 | dm_table_put(t); | 1057 | dm_table_put(t); |
995 | return -ENXIO; | 1058 | up_write(&_hash_lock); |
1059 | r = -ENXIO; | ||
1060 | goto out; | ||
996 | } | 1061 | } |
997 | 1062 | ||
998 | if (hc->new_map) | 1063 | if (hc->new_map) |
999 | dm_table_put(hc->new_map); | 1064 | dm_table_put(hc->new_map); |
1000 | hc->new_map = t; | 1065 | hc->new_map = t; |
1066 | up_write(&_hash_lock); | ||
1067 | |||
1001 | param->flags |= DM_INACTIVE_PRESENT_FLAG; | 1068 | param->flags |= DM_INACTIVE_PRESENT_FLAG; |
1069 | r = __dev_status(md, param); | ||
1070 | |||
1071 | out: | ||
1072 | dm_put(md); | ||
1002 | 1073 | ||
1003 | r = __dev_status(hc->md, param); | ||
1004 | up_write(&_hash_lock); | ||
1005 | return r; | 1074 | return r; |
1006 | } | 1075 | } |
1007 | 1076 | ||
@@ -1214,7 +1283,8 @@ static ioctl_fn lookup_ioctl(unsigned int cmd) | |||
1214 | 1283 | ||
1215 | {DM_LIST_VERSIONS_CMD, list_versions}, | 1284 | {DM_LIST_VERSIONS_CMD, list_versions}, |
1216 | 1285 | ||
1217 | {DM_TARGET_MSG_CMD, target_message} | 1286 | {DM_TARGET_MSG_CMD, target_message}, |
1287 | {DM_DEV_SET_GEOMETRY_CMD, dev_set_geometry} | ||
1218 | }; | 1288 | }; |
1219 | 1289 | ||
1220 | return (cmd >= ARRAY_SIZE(_ioctls)) ? NULL : _ioctls[cmd].fn; | 1290 | return (cmd >= ARRAY_SIZE(_ioctls)) ? NULL : _ioctls[cmd].fn; |