aboutsummaryrefslogtreecommitdiffstats
path: root/drivers/md/dm-ioctl.c
diff options
context:
space:
mode:
Diffstat (limited to 'drivers/md/dm-ioctl.c')
-rw-r--r--drivers/md/dm-ioctl.c100
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 */
601static struct hash_cell *__find_device_hash_cell(struct dm_ioctl *param) 602static 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
611static struct mapped_device *find_device(struct dm_ioctl *param) 622static 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
704static 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
747out:
748 dm_put(md);
749 return r;
750}
751
693static int do_suspend(struct dm_ioctl *param) 752static 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
1071out:
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;