lists.openwall.net   lists  /  announce  owl-users  owl-dev  john-users  john-dev  passwdqc-users  yescrypt  popa3d-users  /  oss-security  kernel-hardening  musl  sabotage  tlsify  passwords  /  crypt-dev  xvendor  /  Bugtraq  Full-Disclosure  linux-kernel  linux-netdev  linux-ext4  linux-hardening  linux-cve-announce  PHC 
Open Source and information security mailing list archives
 
Hash Suite: Windows password security audit tool. GUI, reports in PDF.
[<prev] [next>] [<thread-prev] [thread-next>] [day] [month] [year] [list]
Date:	Mon, 14 Apr 2008 14:57:45 +0200
From:	Seewer Philippe <philippe.seewer@....ch>
To:	Francis Moreau <francis.moro@...il.com>
CC:	linux-kernel@...r.kernel.org
Subject: Re: Disk geometry from /sys

Hi Francis, 

Francis Moreau wrote:
> Hi,
> 
> I'm trying to know the geometry of my hard disk from a bash script
> and that's the reason I'm looking in /sys. The reason is that I'd like
> to figure out the size of a cylinder without doing a
> ioctl(bdev, HDIO_GETGEO, &geo)
> 
> Unfortunately I can't find anything useful and this is certainly a sign
> that I'm doing something wrong.
> 
> Or maybe can I simply assume from my script that the geometry
> is always heads=255 and the number of sectors per track is 63 for all
> disks.
> 
> Looking at parted(8) source code, I  can find this:
> 
> /* The GETGEO ioctl is no longer useful (as of linux 2.6.x).  We could
>  * still use it in 2.4.x, but this is contentious.  Perhaps we should
>  * move to EDD. */
> 
> Could anybody give me some advices ?

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)
 
--
To unsubscribe from this list: send the line "unsubscribe linux-kernel" in
the body of a message to majordomo@...r.kernel.org
More majordomo info at  http://vger.kernel.org/majordomo-info.html
Please read the FAQ at  http://www.tux.org/lkml/

Powered by blists - more mailing lists

Powered by Openwall GNU/*/Linux Powered by OpenVZ