Re: Disk geometry from /sys

Previous message: [thread] [date] [author]
Next message: [thread] [date] [author]
From: Seewer Philippe
Date: Monday, April 14, 2008 - 5:57 am

Hi Francis, 

Francis Moreau wrote:

As you've problably seen from the other answers, disk geometry is (except for a few older devices) unneeded inside the Linux kernel. I'd say thats the reason why there's no sysfs export and I'd further guess disk geometry is an artifact most would like to get rid of (or pushed into userspace).

Anyway, if you really need it, try the patch below. Should apply cleanly to version 2.6.23.1 and gives you a geometry/ directory for each block device providing the getgeo function. It adds a setgeo counterpart for some subsystems as well, allowing 'echo something > ...' so please be careful.

---
diff -uprN -X linux-2.6.23.1-vanilla/Documentation/dontdiff linux-2.6.23.1-vanilla/block/Makefile linux-2.6.23.1/block/Makefile
--- linux-2.6.23.1-vanilla/block/Makefile	2007-10-12 18:43:44.000000000 +0200
+++ linux-2.6.23.1/block/Makefile	2007-10-19 11:51:54.000000000 +0200
@@ -2,7 +2,7 @@
 # Makefile for the kernel block layer
 #
 
-obj-$(CONFIG_BLOCK) := elevator.o ll_rw_blk.o ioctl.o genhd.o scsi_ioctl.o
+obj-$(CONFIG_BLOCK) := elevator.o ll_rw_blk.o ioctl.o genhd.o gengeo.o scsi_ioctl.o
 
 obj-$(CONFIG_BLK_DEV_BSG)	+= bsg.o
 obj-$(CONFIG_IOSCHED_NOOP)	+= noop-iosched.o
diff -uprN -X linux-2.6.23.1-vanilla/Documentation/dontdiff linux-2.6.23.1-vanilla/block/gengeo.c linux-2.6.23.1/block/gengeo.c
--- linux-2.6.23.1-vanilla/block/gengeo.c	1970-01-01 01:00:00.000000000 +0100
+++ linux-2.6.23.1/block/gengeo.c	2007-10-19 11:51:54.000000000 +0200
@@ -0,0 +1,153 @@
+/**
+ *  generic geometry handling. utility for gendisk.c
+ */
+
+#include <linux/module.h>
+#include <linux/fs.h>
+#include <linux/genhd.h>
+#include <linux/kernel.h>
+#include <linux/blkdev.h>
+#include <linux/kmod.h>
+#include <linux/hdreg.h>
+
+/*
+ * General show method invoked by attribute->show.
+ *
+ * Gets the "real" block device, invokes getgeo and delegates output
+ * to the corresponding format function.
+ */
+static ssize_t disk_geom_attr_show(struct gendisk *disk, char *buf,
+				   ssize_t(*format) (const struct hd_geometry *
+						     geo, char *buf))
+{
+	ssize_t ret = -EIO;
+
+	struct hd_geometry geo;
+	struct block_device *bdev = bdget_disk(disk, 0);
+	blkdev_get(bdev, FMODE_READ, 0);
+
+	if (bdev) {
+		geo.start = get_start_sect(bdev);
+		disk->fops->getgeo(bdev, &geo);
+		ret = (*format) (&geo, buf);
+	} else {
+		ret = -ENODEV;
+	}
+	return ret;
+}
+
+/*
+ * General store method invoked by attribute->store.
+ *
+ * Gets the "real" block device, invokes getgeo, delegates input to
+ * the corresponding set function and invokes setgeo.
+ */
+static ssize_t disk_geom_attr_store(struct gendisk *disk, const char *buf,
+				    size_t count,
+				    int (*set) (struct hd_geometry * geo,
+						unsigned long value))
+{
+	ssize_t ret = 0;
+	char *endp;
+	unsigned long value;
+	struct hd_geometry geo;
+	struct block_device *bdev = bdget_disk(disk, 0);
+	blkdev_get(bdev, FMODE_READ, 0);
+
+	value = simple_strtoul(buf, &endp, 0);
+	if (endp == buf)
+		return -EINVAL;
+
+	if (bdev) {
+		geo.start = get_start_sect(bdev);
+		disk->fops->getgeo(bdev, &geo);
+		if ((ret = (*set) (&geo, value)) == 0) {
+			disk->fops->setgeo(bdev, &geo);
+			ret = count;
+		}
+	} else {
+		ret = -ENODEV;
+	}
+	return ret;
+}
+
+/* Generate a show function for field */
+#define DISKGEOM_SHOW(field, format_string) \
+static ssize_t disk_geom_format_##field(const struct hd_geometry *geo, char *buf) \
+{ \
+  return sprintf(buf, format_string, geo->field); \
+} \
+static ssize_t disk_geom_show_##field(struct gendisk * disk, char *buf) \
+{ \
+  return disk_geom_attr_show(disk, buf, disk_geom_format_##field); \
+} \
+static struct disk_attribute disk_geom_attr_ro_##field = __ATTR(field, S_IRUGO, disk_geom_show_##field, NULL);
+
+/* Generate a store function for field */
+#define DISKGEOM_STORE(field, max) \
+static int disk_geom_set_##field(struct hd_geometry *geo, unsigned long value) \
+{ \
+  if (value > max) \
+    return -EINVAL; \
+  geo->field = value; \
+  return 0; \
+} \
+static ssize_t disk_geom_store_##field(struct gendisk *disk, const char *buf, size_t count) \
+{ \
+  return disk_geom_attr_store(disk, buf, count, disk_geom_set_##field); \
+} \
+static struct disk_attribute disk_geom_attr_rw_##field = __ATTR(field, S_IRUGO | S_IWUSR, disk_geom_show_##field, disk_geom_store_##field);
+
+DISKGEOM_SHOW(heads, "%d\n");
+DISKGEOM_SHOW(sectors, "%d\n");
+DISKGEOM_SHOW(cylinders, "%d\n");
+DISKGEOM_SHOW(start, "%ld\n");
+
+DISKGEOM_STORE(heads, 255);
+DISKGEOM_STORE(sectors, 63);
+DISKGEOM_STORE(cylinders, 65535);
+
+static struct attribute *disk_geom_attrs_ro[] = {
+	&disk_geom_attr_ro_heads.attr,
+	&disk_geom_attr_ro_sectors.attr,
+	&disk_geom_attr_ro_cylinders.attr,
+	&disk_geom_attr_ro_start.attr,
+	NULL
+};
+
+static struct attribute *disk_geom_attrs_rw[] = {
+	&disk_geom_attr_rw_heads.attr,
+	&disk_geom_attr_rw_sectors.attr,
+	&disk_geom_attr_rw_cylinders.attr,
+	&disk_geom_attr_ro_start.attr,
+	NULL
+};
+
+static struct attribute_group disk_geom_ro_attrgroup = {
+	.name = "geometry",
+	.attrs = disk_geom_attrs_ro,
+};
+
+static struct attribute_group disk_geom_rw_attrgroup = {
+	.name = "geometry",
+	.attrs = disk_geom_attrs_rw,
+};
+
+/* function called from add_disk in genhd */
+int add_geometry(struct gendisk *disk)
+{
+	if (disk->fops->setgeo) {
+		return sysfs_create_group(&disk->kobj, &disk_geom_rw_attrgroup);
+	} else {
+		return sysfs_create_group(&disk->kobj, &disk_geom_ro_attrgroup);
+	}
+}
+
+/* function called from disk_release in genhd */
+void remove_geometry(struct gendisk *disk)
+{
+	if (disk->fops->setgeo)
+		sysfs_remove_group(&disk->kobj, &disk_geom_rw_attrgroup);
+	else
+		sysfs_remove_group(&disk->kobj, &disk_geom_ro_attrgroup);
+}
diff -uprN -X linux-2.6.23.1-vanilla/Documentation/dontdiff linux-2.6.23.1-vanilla/block/genhd.c linux-2.6.23.1/block/genhd.c
--- linux-2.6.23.1-vanilla/block/genhd.c	2007-10-12 18:43:44.000000000 +0200
+++ linux-2.6.23.1/block/genhd.c	2007-10-19 11:51:54.000000000 +0200
@@ -168,6 +168,10 @@ static int exact_lock(dev_t dev, void *d
 	return 0;
 }
 
+/* Extern in gengeo.c */
+extern int add_geometry(struct gendisk *disk);
+extern void remove_geometry(struct gendisk *disk);
+
 /**
  * add_disk - add partitioning information to kernel list
  * @disk: per-device partitioning information
@@ -181,6 +185,8 @@ void add_disk(struct gendisk *disk)
 	blk_register_region(MKDEV(disk->major, disk->first_minor),
 			    disk->minors, NULL, exact_match, exact_lock, disk);
 	register_disk(disk);
+	if (disk->fops->getgeo)
+	        add_geometry(disk);
 	blk_register_queue(disk);
 }
 
@@ -521,6 +527,7 @@ static void disk_release(struct kobject 
 	struct gendisk *disk = to_disk(kobj);
 	kfree(disk->random);
 	kfree(disk->part);
+	remove_geometry(disk);
 	free_disk_stats(disk);
 	kfree(disk);
 }
diff -uprN -X linux-2.6.23.1-vanilla/Documentation/dontdiff linux-2.6.23.1-vanilla/drivers/ide/ide-disk.c linux-2.6.23.1/drivers/ide/ide-disk.c
--- linux-2.6.23.1-vanilla/drivers/ide/ide-disk.c	2007-10-12 18:43:44.000000000 +0200
+++ linux-2.6.23.1/drivers/ide/ide-disk.c	2007-10-19 11:51:54.000000000 +0200
@@ -1183,6 +1183,17 @@ static int idedisk_getgeo(struct block_d
 	return 0;
 }
 
+static int idedisk_setgeo(struct block_device *bdev, struct hd_geometry *geo)
+{
+	struct ide_disk_obj *idkp = ide_disk_g(bdev->bd_disk);
+	ide_drive_t *drive = idkp->drive;
+
+	drive->bios_head = geo->heads;
+	drive->bios_sect = geo->sectors;
+	drive->bios_cyl  = geo->cylinders;
+	return 0;
+}
+
 static int idedisk_ioctl(struct inode *inode, struct file *file,
 			unsigned int cmd, unsigned long arg)
 {
@@ -1258,6 +1269,7 @@ static struct block_device_operations id
 	.release	= idedisk_release,
 	.ioctl		= idedisk_ioctl,
 	.getgeo		= idedisk_getgeo,
+	.setgeo		= idedisk_setgeo,
 	.media_changed	= idedisk_media_changed,
 	.revalidate_disk= idedisk_revalidate_disk
 };
diff -uprN -X linux-2.6.23.1-vanilla/Documentation/dontdiff linux-2.6.23.1-vanilla/drivers/scsi/sd.c linux-2.6.23.1/drivers/scsi/sd.c
--- linux-2.6.23.1-vanilla/drivers/scsi/sd.c	2007-10-12 18:43:44.000000000 +0200
+++ linux-2.6.23.1/drivers/scsi/sd.c	2007-10-19 11:51:54.000000000 +0200
@@ -620,20 +620,38 @@ static int sd_getgeo(struct block_device
 	struct Scsi_Host *host = sdp->host;
 	int diskinfo[4];
 
-	/* default to most commonly used values */
-        diskinfo[0] = 0x40;	/* 1 << 6 */
-       	diskinfo[1] = 0x20;	/* 1 << 5 */
-       	diskinfo[2] = sdkp->capacity >> 11;
-	
-	/* override with calculated, extended default, or driver values */
-	if (host->hostt->bios_param)
-		host->hostt->bios_param(sdp, bdev, sdkp->capacity, diskinfo);
-	else
-		scsicam_bios_param(bdev, sdkp->capacity, diskinfo);
+	if (sdkp->heads && sdkp->sectors && sdkp->cylinders) {
+		geo->heads     = sdkp->heads;
+		geo->sectors   = sdkp->sectors;
+		geo->cylinders = sdkp->cylinders;
+	} else {
+		/* default to most commonly used values */
+		diskinfo[0] = 0x40;	/* 1 << 6 */
+		diskinfo[1] = 0x20;	/* 1 << 5 */
+		diskinfo[2] = sdkp->capacity >> 11;
+
+		/* override with calculated, extended default, or driver values */
+		if (host->hostt->bios_param)
+			host->hostt->bios_param(sdp, bdev, sdkp->capacity,
+						diskinfo);
+		else
+			scsicam_bios_param(bdev, sdkp->capacity, diskinfo);
+
+		geo->heads = diskinfo[0];
+		geo->sectors = diskinfo[1];
+		geo->cylinders = diskinfo[2];
+	}
+	return 0;
+}
+
+static int sd_setgeo(struct block_device *bdev, struct hd_geometry *geo)
+{
+	struct scsi_disk *sdkp = scsi_disk(bdev->bd_disk);
+
+	sdkp->heads     = geo->heads;
+	sdkp->sectors   = geo->sectors;
+	sdkp->cylinders = geo->cylinders;
 
-	geo->heads = diskinfo[0];
-	geo->sectors = diskinfo[1];
-	geo->cylinders = diskinfo[2];
 	return 0;
 }
 
@@ -881,6 +899,7 @@ static struct block_device_operations sd
 	.release		= sd_release,
 	.ioctl			= sd_ioctl,
 	.getgeo			= sd_getgeo,
+	.setgeo			= sd_setgeo,
 #ifdef CONFIG_COMPAT
 	.compat_ioctl		= sd_compat_ioctl,
 #endif
diff -uprN -X linux-2.6.23.1-vanilla/Documentation/dontdiff linux-2.6.23.1-vanilla/include/linux/fs.h linux-2.6.23.1/include/linux/fs.h
--- linux-2.6.23.1-vanilla/include/linux/fs.h	2007-10-12 18:43:44.000000000 +0200
+++ linux-2.6.23.1/include/linux/fs.h	2007-10-19 11:51:54.000000000 +0200
@@ -1067,6 +1067,7 @@ struct block_device_operations {
 	int (*media_changed) (struct gendisk *);
 	int (*revalidate_disk) (struct gendisk *);
 	int (*getgeo)(struct block_device *, struct hd_geometry *);
+	int (*setgeo)(struct block_device *, struct hd_geometry *);
 	struct module *owner;
 };
 
diff -uprN -X linux-2.6.23.1-vanilla/Documentation/dontdiff linux-2.6.23.1-vanilla/include/scsi/sd.h linux-2.6.23.1/include/scsi/sd.h
--- linux-2.6.23.1-vanilla/include/scsi/sd.h	2007-10-12 18:43:44.000000000 +0200
+++ linux-2.6.23.1/include/scsi/sd.h	2007-10-19 12:01:58.000000000 +0200
@@ -44,6 +44,12 @@ struct scsi_disk {
 	unsigned	WCE : 1;	/* state of disk WCE bit */
 	unsigned	RCD : 1;	/* state of disk RCD bit, unused */
 	unsigned	DPOFUA : 1;	/* state of disk DPOFUA bit */
+
+
+	/* Disk geometry for overwrite */
+	unsigned char   heads;
+	unsigned char   sectors;
+	unsigned short  cylinders;
 };
 #define to_scsi_disk(obj) container_of(obj,struct scsi_disk,cdev)
 
--
Previous message: [thread] [date] [author]
Next message: [thread] [date] [author]

Messages in current thread:
Disk geometry from /sys, Francis Moreau, (Wed Apr 9, 1:53 pm)
Re: Disk geometry from /sys, Lennart Sorensen, (Wed Apr 9, 2:28 pm)
Re: Disk geometry from /sys, Alan Cox, (Wed Apr 9, 2:52 pm)
Re: Disk geometry from /sys, Mark Lord, (Wed Apr 9, 2:57 pm)
Re: Disk geometry from /sys, Bernd Eckenfels, (Wed Apr 9, 3:16 pm)
Re: Disk geometry from /sys, linux-os (Dick Johnson), (Thu Apr 10, 5:22 am)
Re: Disk geometry from /sys, Bill Davidsen, (Thu Apr 10, 6:58 am)
Re: Disk geometry from /sys, Lennart Sorensen, (Thu Apr 10, 7:52 am)
Re: Disk geometry from /sys, Francis Moreau, (Thu Apr 10, 12:05 pm)
Re: Disk geometry from /sys, Francis Moreau, (Thu Apr 10, 12:15 pm)
Re: Disk geometry from /sys, Francis Moreau, (Thu Apr 10, 12:23 pm)
Re: Disk geometry from /sys, Mark Lord, (Thu Apr 10, 12:53 pm)
Re: Disk geometry from /sys, Seewer Philippe, (Mon Apr 14, 5:57 am)
Re: Disk geometry from /sys, Francis Moreau, (Tue Apr 15, 12:40 am)
Re: Disk geometry from /sys, Seewer Philippe, (Wed Apr 16, 12:49 am)
Re: Disk geometry from /sys, Francis Moreau, (Thu Apr 17, 7:09 am)
Re: Disk geometry from /sys, Seewer Philippe, (Thu Apr 17, 7:49 am)
Re: Disk geometry from /sys, Mark Lord, (Fri Apr 18, 6:22 am)
Re: Disk geometry from /sys, Seewer Philippe, (Fri Apr 18, 6:37 am)
Re: Disk geometry from /sys, Francis Moreau, (Tue Apr 22, 1:10 pm)
Re: Disk geometry from /sys, Francis Moreau, (Tue Apr 22, 1:11 pm)
Re: Disk geometry from /sys, Francis Moreau, (Tue Apr 22, 1:16 pm)
Re: Disk geometry from /sys, Mark Lord, (Tue Apr 22, 3:44 pm)
Re: Disk geometry from /sys, Seewer Philippe, (Tue Apr 22, 11:44 pm)
Re: Disk geometry from /sys, Seewer Philippe, (Tue Apr 22, 11:48 pm)
Re: Disk geometry from /sys, Seewer Philippe, (Tue Apr 22, 11:53 pm)
Re: Disk geometry from /sys, Francis Moreau, (Tue Apr 22, 11:56 pm)
Re: Disk geometry from /sys, Francis Moreau, (Wed Apr 23, 12:02 am)
Re: Disk geometry from /sys, Seewer Philippe, (Wed Apr 23, 2:33 am)
Re: Disk geometry from /sys, Mark Lord, (Wed Apr 23, 6:47 am)