diff options
author | Darrick J. Wong <djwong@us.ibm.com> | 2006-03-27 04:17:54 -0500 |
---|---|---|
committer | Linus Torvalds <torvalds@g5.osdl.org> | 2006-03-27 11:44:59 -0500 |
commit | 3ac51e741a46af7a20f55e79d3e3aeaa93c6c544 (patch) | |
tree | cab595a4d9691d7602616337b7862a1a3d692b97 | |
parent | 1134e5ae79bab61c05657ca35a6297cf87202e35 (diff) |
[PATCH] dm store geometry
Allow drive geometry to be stored with a new DM_DEV_SET_GEOMETRY ioctl.
Device-mapper will now respond to HDIO_GETGEO. If the geometry information is
not available, zero will be returned for all of the parameters.
Signed-off-by: Darrick J. Wong <djwong@us.ibm.com>
Signed-off-by: Alasdair G Kergon <agk@redhat.com>
Signed-off-by: Andrew Morton <akpm@osdl.org>
Signed-off-by: Linus Torvalds <torvalds@osdl.org>
-rw-r--r-- | drivers/md/dm-ioctl.c | 52 | ||||
-rw-r--r-- | drivers/md/dm.c | 46 | ||||
-rw-r--r-- | drivers/md/dm.h | 7 | ||||
-rw-r--r-- | include/linux/compat_ioctl.h | 2 | ||||
-rw-r--r-- | include/linux/dm-ioctl.h | 17 |
5 files changed, 121 insertions, 3 deletions
diff --git a/drivers/md/dm-ioctl.c b/drivers/md/dm-ioctl.c index 65826bdac00..8edd6435414 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 | ||
@@ -700,6 +701,54 @@ static int dev_rename(struct dm_ioctl *param, size_t param_size) | |||
700 | return dm_hash_rename(param->name, new_name); | 701 | return dm_hash_rename(param->name, new_name); |
701 | } | 702 | } |
702 | 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 | |||
703 | static int do_suspend(struct dm_ioctl *param) | 752 | static int do_suspend(struct dm_ioctl *param) |
704 | { | 753 | { |
705 | int r = 0; | 754 | int r = 0; |
@@ -1234,7 +1283,8 @@ static ioctl_fn lookup_ioctl(unsigned int cmd) | |||
1234 | 1283 | ||
1235 | {DM_LIST_VERSIONS_CMD, list_versions}, | 1284 | {DM_LIST_VERSIONS_CMD, list_versions}, |
1236 | 1285 | ||
1237 | {DM_TARGET_MSG_CMD, target_message} | 1286 | {DM_TARGET_MSG_CMD, target_message}, |
1287 | {DM_DEV_SET_GEOMETRY_CMD, dev_set_geometry} | ||
1238 | }; | 1288 | }; |
1239 | 1289 | ||
1240 | return (cmd >= ARRAY_SIZE(_ioctls)) ? NULL : _ioctls[cmd].fn; | 1290 | return (cmd >= ARRAY_SIZE(_ioctls)) ? NULL : _ioctls[cmd].fn; |
diff --git a/drivers/md/dm.c b/drivers/md/dm.c index b99df48cffe..973e63d530a 100644 --- a/drivers/md/dm.c +++ b/drivers/md/dm.c | |||
@@ -17,6 +17,7 @@ | |||
17 | #include <linux/mempool.h> | 17 | #include <linux/mempool.h> |
18 | #include <linux/slab.h> | 18 | #include <linux/slab.h> |
19 | #include <linux/idr.h> | 19 | #include <linux/idr.h> |
20 | #include <linux/hdreg.h> | ||
20 | #include <linux/blktrace_api.h> | 21 | #include <linux/blktrace_api.h> |
21 | 22 | ||
22 | static const char *_name = DM_NAME; | 23 | static const char *_name = DM_NAME; |
@@ -102,6 +103,9 @@ struct mapped_device { | |||
102 | */ | 103 | */ |
103 | struct super_block *frozen_sb; | 104 | struct super_block *frozen_sb; |
104 | struct block_device *suspended_bdev; | 105 | struct block_device *suspended_bdev; |
106 | |||
107 | /* forced geometry settings */ | ||
108 | struct hd_geometry geometry; | ||
105 | }; | 109 | }; |
106 | 110 | ||
107 | #define MIN_IOS 256 | 111 | #define MIN_IOS 256 |
@@ -227,6 +231,13 @@ static int dm_blk_close(struct inode *inode, struct file *file) | |||
227 | return 0; | 231 | return 0; |
228 | } | 232 | } |
229 | 233 | ||
234 | static int dm_blk_getgeo(struct block_device *bdev, struct hd_geometry *geo) | ||
235 | { | ||
236 | struct mapped_device *md = bdev->bd_disk->private_data; | ||
237 | |||
238 | return dm_get_geometry(md, geo); | ||
239 | } | ||
240 | |||
230 | static inline struct dm_io *alloc_io(struct mapped_device *md) | 241 | static inline struct dm_io *alloc_io(struct mapped_device *md) |
231 | { | 242 | { |
232 | return mempool_alloc(md->io_pool, GFP_NOIO); | 243 | return mempool_alloc(md->io_pool, GFP_NOIO); |
@@ -313,6 +324,33 @@ struct dm_table *dm_get_table(struct mapped_device *md) | |||
313 | return t; | 324 | return t; |
314 | } | 325 | } |
315 | 326 | ||
327 | /* | ||
328 | * Get the geometry associated with a dm device | ||
329 | */ | ||
330 | int dm_get_geometry(struct mapped_device *md, struct hd_geometry *geo) | ||
331 | { | ||
332 | *geo = md->geometry; | ||
333 | |||
334 | return 0; | ||
335 | } | ||
336 | |||
337 | /* | ||
338 | * Set the geometry of a device. | ||
339 | */ | ||
340 | int dm_set_geometry(struct mapped_device *md, struct hd_geometry *geo) | ||
341 | { | ||
342 | sector_t sz = (sector_t)geo->cylinders * geo->heads * geo->sectors; | ||
343 | |||
344 | if (geo->start > sz) { | ||
345 | DMWARN("Start sector is beyond the geometry limits."); | ||
346 | return -EINVAL; | ||
347 | } | ||
348 | |||
349 | md->geometry = *geo; | ||
350 | |||
351 | return 0; | ||
352 | } | ||
353 | |||
316 | /*----------------------------------------------------------------- | 354 | /*----------------------------------------------------------------- |
317 | * CRUD START: | 355 | * CRUD START: |
318 | * A more elegant soln is in the works that uses the queue | 356 | * A more elegant soln is in the works that uses the queue |
@@ -906,6 +944,13 @@ static int __bind(struct mapped_device *md, struct dm_table *t) | |||
906 | sector_t size; | 944 | sector_t size; |
907 | 945 | ||
908 | size = dm_table_get_size(t); | 946 | size = dm_table_get_size(t); |
947 | |||
948 | /* | ||
949 | * Wipe any geometry if the size of the table changed. | ||
950 | */ | ||
951 | if (size != get_capacity(md->disk)) | ||
952 | memset(&md->geometry, 0, sizeof(md->geometry)); | ||
953 | |||
909 | __set_size(md, size); | 954 | __set_size(md, size); |
910 | if (size == 0) | 955 | if (size == 0) |
911 | return 0; | 956 | return 0; |
@@ -1261,6 +1306,7 @@ int dm_suspended(struct mapped_device *md) | |||
1261 | static struct block_device_operations dm_blk_dops = { | 1306 | static struct block_device_operations dm_blk_dops = { |
1262 | .open = dm_blk_open, | 1307 | .open = dm_blk_open, |
1263 | .release = dm_blk_close, | 1308 | .release = dm_blk_close, |
1309 | .getgeo = dm_blk_getgeo, | ||
1264 | .owner = THIS_MODULE | 1310 | .owner = THIS_MODULE |
1265 | }; | 1311 | }; |
1266 | 1312 | ||
diff --git a/drivers/md/dm.h b/drivers/md/dm.h index 79e800051a1..fd90bc8f9e4 100644 --- a/drivers/md/dm.h +++ b/drivers/md/dm.h | |||
@@ -14,6 +14,7 @@ | |||
14 | #include <linux/device-mapper.h> | 14 | #include <linux/device-mapper.h> |
15 | #include <linux/list.h> | 15 | #include <linux/list.h> |
16 | #include <linux/blkdev.h> | 16 | #include <linux/blkdev.h> |
17 | #include <linux/hdreg.h> | ||
17 | 18 | ||
18 | #define DM_NAME "device-mapper" | 19 | #define DM_NAME "device-mapper" |
19 | #define DMWARN(f, x...) printk(KERN_WARNING DM_NAME ": " f "\n" , ## x) | 20 | #define DMWARN(f, x...) printk(KERN_WARNING DM_NAME ": " f "\n" , ## x) |
@@ -85,6 +86,12 @@ int dm_wait_event(struct mapped_device *md, int event_nr); | |||
85 | struct gendisk *dm_disk(struct mapped_device *md); | 86 | struct gendisk *dm_disk(struct mapped_device *md); |
86 | int dm_suspended(struct mapped_device *md); | 87 | int dm_suspended(struct mapped_device *md); |
87 | 88 | ||
89 | /* | ||
90 | * Geometry functions. | ||
91 | */ | ||
92 | int dm_get_geometry(struct mapped_device *md, struct hd_geometry *geo); | ||
93 | int dm_set_geometry(struct mapped_device *md, struct hd_geometry *geo); | ||
94 | |||
88 | /*----------------------------------------------------------------- | 95 | /*----------------------------------------------------------------- |
89 | * Functions for manipulating a table. Tables are also reference | 96 | * Functions for manipulating a table. Tables are also reference |
90 | * counted. | 97 | * counted. |
diff --git a/include/linux/compat_ioctl.h b/include/linux/compat_ioctl.h index efb518f16bb..89ab677cb99 100644 --- a/include/linux/compat_ioctl.h +++ b/include/linux/compat_ioctl.h | |||
@@ -140,6 +140,7 @@ COMPATIBLE_IOCTL(DM_TABLE_DEPS_32) | |||
140 | COMPATIBLE_IOCTL(DM_TABLE_STATUS_32) | 140 | COMPATIBLE_IOCTL(DM_TABLE_STATUS_32) |
141 | COMPATIBLE_IOCTL(DM_LIST_VERSIONS_32) | 141 | COMPATIBLE_IOCTL(DM_LIST_VERSIONS_32) |
142 | COMPATIBLE_IOCTL(DM_TARGET_MSG_32) | 142 | COMPATIBLE_IOCTL(DM_TARGET_MSG_32) |
143 | COMPATIBLE_IOCTL(DM_DEV_SET_GEOMETRY_32) | ||
143 | COMPATIBLE_IOCTL(DM_VERSION) | 144 | COMPATIBLE_IOCTL(DM_VERSION) |
144 | COMPATIBLE_IOCTL(DM_REMOVE_ALL) | 145 | COMPATIBLE_IOCTL(DM_REMOVE_ALL) |
145 | COMPATIBLE_IOCTL(DM_LIST_DEVICES) | 146 | COMPATIBLE_IOCTL(DM_LIST_DEVICES) |
@@ -155,6 +156,7 @@ COMPATIBLE_IOCTL(DM_TABLE_DEPS) | |||
155 | COMPATIBLE_IOCTL(DM_TABLE_STATUS) | 156 | COMPATIBLE_IOCTL(DM_TABLE_STATUS) |
156 | COMPATIBLE_IOCTL(DM_LIST_VERSIONS) | 157 | COMPATIBLE_IOCTL(DM_LIST_VERSIONS) |
157 | COMPATIBLE_IOCTL(DM_TARGET_MSG) | 158 | COMPATIBLE_IOCTL(DM_TARGET_MSG) |
159 | COMPATIBLE_IOCTL(DM_DEV_SET_GEOMETRY) | ||
158 | /* Big K */ | 160 | /* Big K */ |
159 | COMPATIBLE_IOCTL(PIO_FONT) | 161 | COMPATIBLE_IOCTL(PIO_FONT) |
160 | COMPATIBLE_IOCTL(GIO_FONT) | 162 | COMPATIBLE_IOCTL(GIO_FONT) |
diff --git a/include/linux/dm-ioctl.h b/include/linux/dm-ioctl.h index fa75ba0d635..c67c6786612 100644 --- a/include/linux/dm-ioctl.h +++ b/include/linux/dm-ioctl.h | |||
@@ -80,6 +80,16 @@ | |||
80 | * | 80 | * |
81 | * DM_TARGET_MSG: | 81 | * DM_TARGET_MSG: |
82 | * Pass a message string to the target at a specific offset of a device. | 82 | * Pass a message string to the target at a specific offset of a device. |
83 | * | ||
84 | * DM_DEV_SET_GEOMETRY: | ||
85 | * Set the geometry of a device by passing in a string in this format: | ||
86 | * | ||
87 | * "cylinders heads sectors_per_track start_sector" | ||
88 | * | ||
89 | * Beware that CHS geometry is nearly obsolete and only provided | ||
90 | * for compatibility with dm devices that can be booted by a PC | ||
91 | * BIOS. See struct hd_geometry for range limits. Also note that | ||
92 | * the geometry is erased if the device size changes. | ||
83 | */ | 93 | */ |
84 | 94 | ||
85 | /* | 95 | /* |
@@ -218,6 +228,7 @@ enum { | |||
218 | /* Added later */ | 228 | /* Added later */ |
219 | DM_LIST_VERSIONS_CMD, | 229 | DM_LIST_VERSIONS_CMD, |
220 | DM_TARGET_MSG_CMD, | 230 | DM_TARGET_MSG_CMD, |
231 | DM_DEV_SET_GEOMETRY_CMD | ||
221 | }; | 232 | }; |
222 | 233 | ||
223 | /* | 234 | /* |
@@ -247,6 +258,7 @@ typedef char ioctl_struct[308]; | |||
247 | #define DM_TABLE_STATUS_32 _IOWR(DM_IOCTL, DM_TABLE_STATUS_CMD, ioctl_struct) | 258 | #define DM_TABLE_STATUS_32 _IOWR(DM_IOCTL, DM_TABLE_STATUS_CMD, ioctl_struct) |
248 | #define DM_LIST_VERSIONS_32 _IOWR(DM_IOCTL, DM_LIST_VERSIONS_CMD, ioctl_struct) | 259 | #define DM_LIST_VERSIONS_32 _IOWR(DM_IOCTL, DM_LIST_VERSIONS_CMD, ioctl_struct) |
249 | #define DM_TARGET_MSG_32 _IOWR(DM_IOCTL, DM_TARGET_MSG_CMD, ioctl_struct) | 260 | #define DM_TARGET_MSG_32 _IOWR(DM_IOCTL, DM_TARGET_MSG_CMD, ioctl_struct) |
261 | #define DM_DEV_SET_GEOMETRY_32 _IOWR(DM_IOCTL, DM_DEV_SET_GEOMETRY_CMD, ioctl_struct) | ||
250 | #endif | 262 | #endif |
251 | 263 | ||
252 | #define DM_IOCTL 0xfd | 264 | #define DM_IOCTL 0xfd |
@@ -270,11 +282,12 @@ typedef char ioctl_struct[308]; | |||
270 | #define DM_LIST_VERSIONS _IOWR(DM_IOCTL, DM_LIST_VERSIONS_CMD, struct dm_ioctl) | 282 | #define DM_LIST_VERSIONS _IOWR(DM_IOCTL, DM_LIST_VERSIONS_CMD, struct dm_ioctl) |
271 | 283 | ||
272 | #define DM_TARGET_MSG _IOWR(DM_IOCTL, DM_TARGET_MSG_CMD, struct dm_ioctl) | 284 | #define DM_TARGET_MSG _IOWR(DM_IOCTL, DM_TARGET_MSG_CMD, struct dm_ioctl) |
285 | #define DM_DEV_SET_GEOMETRY _IOWR(DM_IOCTL, DM_DEV_SET_GEOMETRY_CMD, struct dm_ioctl) | ||
273 | 286 | ||
274 | #define DM_VERSION_MAJOR 4 | 287 | #define DM_VERSION_MAJOR 4 |
275 | #define DM_VERSION_MINOR 5 | 288 | #define DM_VERSION_MINOR 6 |
276 | #define DM_VERSION_PATCHLEVEL 0 | 289 | #define DM_VERSION_PATCHLEVEL 0 |
277 | #define DM_VERSION_EXTRA "-ioctl (2005-10-04)" | 290 | #define DM_VERSION_EXTRA "-ioctl (2006-02-17)" |
278 | 291 | ||
279 | /* Status bits */ | 292 | /* Status bits */ |
280 | #define DM_READONLY_FLAG (1 << 0) /* In/Out */ | 293 | #define DM_READONLY_FLAG (1 << 0) /* In/Out */ |