[syslinux:master] extlinux: try to get the disk offset from sysfs
syslinux-bot for H. Peter Anvin
hpa at linux.intel.com
Fri Aug 13 17:30:35 PDT 2010
Commit-ID: 460675909dd059f5fa84985402fcd6490503c884
Gitweb: http://syslinux.zytor.com/commit/460675909dd059f5fa84985402fcd6490503c884
Author: H. Peter Anvin <hpa at linux.intel.com>
AuthorDate: Fri, 13 Aug 2010 17:27:44 -0700
Committer: H. Peter Anvin <hpa at linux.intel.com>
CommitDate: Fri, 13 Aug 2010 17:27:44 -0700
extlinux: try to get the disk offset from sysfs
It is possible(?) that HDIO_GETGEO can't return the full offset, and
in either case it is too small -- only 32 bits on 32-bit platforms.
Thus query sysfs for the real value, if available.
sysfs also contains information for slave devices -- this is going to
really matter for the md/lvm issues.
Signed-off-by: H. Peter Anvin <hpa at linux.intel.com>
---
extlinux/main.c | 43 ++++++++++++++++++++++++++++++++++++++-----
1 files changed, 38 insertions(+), 5 deletions(-)
diff --git a/extlinux/main.c b/extlinux/main.c
index 002cecd..30422c2 100755
--- a/extlinux/main.c
+++ b/extlinux/main.c
@@ -100,6 +100,32 @@ struct geometry_table {
struct hd_geometry g;
};
+static int sysfs_get_offset(int devfd, unsigned long *start)
+{
+ struct stat st;
+ char sysfs_name[128];
+ FILE *f;
+ int rv;
+
+ if (fstat(devfd, &st))
+ return -1;
+
+ if ((size_t)snprintf(sysfs_name, sizeof sysfs_name,
+ "/sys/dev/block/%u:%u/start",
+ major(st.st_dev), minor(st.st_dev))
+ >= sizeof sysfs_name)
+ return -1;
+
+ f = fopen(sysfs_name, "r");
+ if (!f)
+ return -1;
+
+ rv = fscanf(f, "%lu", start);
+ fclose(f);
+
+ return (rv == 1) ? 0 : -1;
+}
+
/* Standard floppy disk geometries, plus LS-120. Zipdisk geometry
(x/64/32) is the final fallback. I don't know what LS-240 has
as its geometry, since I don't have one and don't know anyone that does,
@@ -123,24 +149,25 @@ int get_geometry(int devfd, uint64_t totalbytes, struct hd_geometry *geo)
struct loop_info li;
struct loop_info64 li64;
const struct geometry_table *gp;
+ int rv = 0;
memset(geo, 0, sizeof *geo);
if (!ioctl(devfd, HDIO_GETGEO, &geo)) {
- return 0;
+ goto ok;
} else if (!ioctl(devfd, FDGETPRM, &fd_str)) {
geo->heads = fd_str.head;
geo->sectors = fd_str.sect;
geo->cylinders = fd_str.track;
geo->start = 0;
- return 0;
+ goto ok;
}
/* Didn't work. Let's see if this is one of the standard geometries */
for (gp = standard_geometries; gp->bytes; gp++) {
if (gp->bytes == totalbytes) {
memcpy(geo, &gp->g, sizeof *geo);
- return 0;
+ goto ok;
}
}
@@ -153,19 +180,25 @@ int get_geometry(int devfd, uint64_t totalbytes, struct hd_geometry *geo)
geo->cylinders = totalbytes / (geo->heads * geo->sectors << SECTOR_SHIFT);
geo->start = 0;
- if (!opt.sectors && !opt.heads)
+ if (!opt.sectors && !opt.heads) {
fprintf(stderr,
"Warning: unable to obtain device geometry (defaulting to %d heads, %d sectors)\n"
" (on hard disks, this is usually harmless.)\n",
geo->heads, geo->sectors);
+ rv = 1; /* Suboptimal result */
+ }
+ok:
/* If this is a loopback device, try to set the start */
if (!ioctl(devfd, LOOP_GET_STATUS64, &li64))
geo->start = li64.lo_offset >> SECTOR_SHIFT;
else if (!ioctl(devfd, LOOP_GET_STATUS, &li))
geo->start = (unsigned int)li.lo_offset >> SECTOR_SHIFT;
+ else if (!sysfs_get_offset(devfd, &geo->start)) {
+ /* OK */
+ }
- return 1;
+ return rv;
}
/*
More information about the Syslinux-commits
mailing list