Set geometry information for multipath maps
authorHannes Reinecke <hare@suse.de>
Fri, 18 Jun 2010 10:32:21 +0000 (12:32 +0200)
committerChristophe Varoqui <christophe.varoqui@opensvc.com>
Wed, 1 Dec 2010 08:58:15 +0000 (09:58 +0100)
Some programs (most notably grub) try to get the device geometry
information via the HDIO_GETGEO ioctl. While device-mapper provides
this ioctl, it's values have to be set previously.
So we can just use the geometry information from the first path
to set this information for the multipath map.

Signed-off-by: Hannes Reinecke <hare@suse.de>
libmultipath/configure.c
libmultipath/devmapper.c
libmultipath/devmapper.h
libmultipath/discovery.c
libmultipath/structs.h

index a40bef3f561303f77569d3cb50e39bf24cf8db06..9530d8ea741dc2230cbbc226efa6c792b379855f 100644 (file)
@@ -421,6 +421,7 @@ domap (struct multipath * mpp)
                        if (mpp->action != ACT_CREATE)
                                mpp->action = ACT_NOTHING;
                }
+               dm_setgeometry(mpp);
                return DOMAP_OK;
        }
        return DOMAP_FAIL;
index fb69ee8d03d44de7f0403422ab6acefb3a4e5d7d..4a25563cd520e7a9969d44cdbc1d9ef011900145 100644 (file)
@@ -1133,3 +1133,51 @@ out:
        dm_task_destroy(dmt);
        return r;
 }
+
+int dm_setgeometry(struct multipath *mpp)
+{
+       struct dm_task *dmt;
+       struct path *pp;
+       char heads[4], sectors[4];
+       char cylinders[10], start[32];
+       int r = 0;
+
+       if (!mpp)
+               return 1;
+
+       pp = first_path(mpp);
+       if (!pp) {
+               condlog(3, "%s: no path for geometry", mpp->alias);
+               return 1;
+       }
+       if (pp->geom.cylinders == 0 ||
+           pp->geom.heads == 0 ||
+           pp->geom.sectors == 0) {
+               condlog(3, "%s: invalid geometry on %s", mpp->alias, pp->dev);
+               return 1;
+       }
+
+       if (!(dmt = dm_task_create(DM_DEVICE_SET_GEOMETRY)))
+               return 0;
+
+       if (!dm_task_set_name(dmt, mpp->alias))
+               goto out;
+
+       dm_task_no_open_count(dmt);
+
+       /* What a sick interface ... */
+       snprintf(heads, 4, "%u", pp->geom.heads);
+       snprintf(sectors, 4, "%u", pp->geom.sectors);
+       snprintf(cylinders, 10, "%u", pp->geom.cylinders);
+       snprintf(start, 32, "%lu", pp->geom.start);
+       if (!dm_task_set_geometry(dmt, cylinders, heads, sectors, start)) {
+               condlog(3, "%s: Failed to set geometry", mpp->alias);
+               goto out;
+       }
+
+       r = dm_task_run(dmt);
+out:
+       dm_task_destroy(dmt);
+
+       return r;
+}
index 6c22bf3bfc6aa805e3a7c9b4970758ab74c192e5..d2dd572be0648f3e4dffdf94883dc6371f56d636 100644 (file)
@@ -38,5 +38,6 @@ int dm_get_uuid(char *name, char *uuid);
 int dm_get_info (char * mapname, struct dm_info ** dmi);
 int dm_rename (char * old, char * new);
 char * dm_get_name(char * uuid);
+int dm_setgeometry(struct multipath *mpp);
 
 #endif /* _DEVMAPPER_H */
index c371b47ff76442da3c1b1bc2ce82ee0ff7af497b..5b04e2e243422e552b40fb2beb43d74812156c70 100644 (file)
@@ -500,6 +500,23 @@ get_inq (char * dev, char * vendor, char * product, char * rev, int fd)
        return 0;
 }
 
+static int
+get_geometry(struct path *pp)
+{
+       if (pp->fd < 0)
+               return 1;
+
+       if (ioctl(pp->fd, HDIO_GETGEO, &pp->geom)) {
+               condlog(2, "%s: HDIO_GETGEO failed with %d", pp->dev, errno);
+               memset(&pp->geom, 0, sizeof(pp->geom));
+               return 1;
+       }
+       condlog(3, "%s: %u cyl, %u heads, %u sectors/track, start at %lu",
+               pp->dev, pp->geom.cylinders, pp->geom.heads,
+               pp->geom.sectors, pp->geom.start);
+       return 0;
+}
+
 static int
 scsi_sysfs_pathinfo (struct path * pp, struct sysfs_device * parent)
 {
@@ -895,6 +912,9 @@ pathinfo (struct path *pp, vector hwtable, int mask)
                goto blank;
        }
 
+       if (mask & DI_SERIAL)
+               get_geometry(pp);
+
        if (pp->bus == SYSFS_BUS_SCSI &&
            scsi_ioctl_pathinfo(pp, mask))
                goto blank;
index fc6413bed29f709363a2114fb3fdafe1ff53fb90..78ba81e60e54312aea6cb0e53e80660091df18eb 100644 (file)
@@ -119,12 +119,23 @@ struct sysfs_device {
        char driver[NAME_SIZE];                 /* device driver name */
 };
 
+# ifndef HDIO_GETGEO
+#  define HDIO_GETGEO  0x0301  /* get device geometry */
+
+struct hd_geometry {
+      unsigned char heads;
+      unsigned char sectors;
+      unsigned short cylinders;
+      unsigned long start;
+};
+#endif
 struct path {
        char dev[FILE_NAME_SIZE];
        char dev_t[BLK_DEV_SIZE];
        struct sysfs_device *sysdev;
        struct scsi_idlun scsi_id;
        struct sg_id sg_id;
+       struct hd_geometry geom;
        char wwid[WWID_SIZE];
        char vendor_id[SCSI_VENDOR_SIZE];
        char product_id[SCSI_PRODUCT_SIZE];
@@ -146,7 +157,7 @@ struct path {
        struct checker checker;
        struct multipath * mpp;
        int fd;
-       
+
        /* configlet pointers */
        struct hwentry * hwe;
 };