diff options
author | Karel Zak | 2012-12-06 12:12:41 +0100 |
---|---|---|
committer | Karel Zak | 2013-03-11 11:20:41 +0100 |
commit | aa42788d5f6beded3b36fb45cfaf4a27fff25698 (patch) | |
tree | e453964dc3422dadcd65fce5fa84494b6f9abfed /libfdisk/src | |
parent | libfdisk: add firstsector utils (diff) | |
download | kernel-qcow2-util-linux-aa42788d5f6beded3b36fb45cfaf4a27fff25698.tar.gz kernel-qcow2-util-linux-aa42788d5f6beded3b36fb45cfaf4a27fff25698.tar.xz kernel-qcow2-util-linux-aa42788d5f6beded3b36fb45cfaf4a27fff25698.zip |
libfdisk: add topology and geometry functions
- rename __discovery_* to fdisk_discovery_*
- rename fdisk_context_force_sector_size() to fdisk_override_sector_size()
- rename fdisk_context_set_user_geometry() to fdisk_override_geometry()
- remove non-default sector size warning
Signed-off-by: Karel Zak <kzak@redhat.com>
Diffstat (limited to 'libfdisk/src')
-rw-r--r-- | libfdisk/src/alignment.c | 251 | ||||
-rw-r--r-- | libfdisk/src/fdiskP.h | 8 |
2 files changed, 259 insertions, 0 deletions
diff --git a/libfdisk/src/alignment.c b/libfdisk/src/alignment.c index b0d38ae23..e06e1afb0 100644 --- a/libfdisk/src/alignment.c +++ b/libfdisk/src/alignment.c @@ -1,6 +1,14 @@ +#ifdef HAVE_LIBBLKID +#include <blkid.h> +#endif +#include "blkdev.h" + #include "fdiskP.h" +/* temporary */ +extern int fdisk_reset_alignment(struct fdisk_context *cxt); + /* * Alignment according to logical granulity (usually 1MiB) */ @@ -99,3 +107,246 @@ void fdisk_warn_alignment(struct fdisk_context *cxt, sector_t lba, int partition printf(_("Partition %i does not start on physical sector boundary.\n"), partition + 1); } + +static unsigned long get_sector_size(int fd) +{ + int sect_sz; + + if (!blkdev_get_sector_size(fd, §_sz)) + return (unsigned long) sect_sz; + return DEFAULT_SECTOR_SIZE; +} + +/** + * fdisk_override_sector_size: + * @cxt: fdisk context + * @s: required sector size + * + * Overwrites logical and physical sector size. Note that the default sector + * size is discovered by fdisk_new_context_from_device() from device topology. + * + * Don't use this function, rely on the default behavioer is more safe. + * + * Returns: 0 on success, < 0 on error. + */ +int fdisk_override_sector_size(struct fdisk_context *cxt, sector_t s) +{ + if (!cxt) + return -EINVAL; + + cxt->phy_sector_size = cxt->sector_size = s; + cxt->min_io_size = cxt->io_size = s; + + fdisk_reset_alignment(cxt); + return 0; +} + +static void recount_geometry(struct fdisk_context *cxt) +{ + cxt->geom.cylinders = cxt->total_sectors / + (cxt->geom.heads * cxt->geom.sectors); +} + +/** + * fdisk_override_geometry: + * @cxt: fdisk context + * @cylinders: user specified cylinders + * @heads: user specified heads + * @sectors: user specified sectors + * + * Overrides autodiscovery and apply user specified geometry. + * + * Returns: 0 on success, < 0 on error. + */ +int fdisk_override_geometry(struct fdisk_context *cxt, + unsigned int cylinders, + unsigned int heads, + unsigned int sectors) +{ + if (!cxt) + return -EINVAL; + if (heads) + cxt->geom.heads = heads; + if (sectors) + cxt->geom.sectors = sectors; + + if (cylinders) + cxt->geom.cylinders = cylinders; + else + recount_geometry(cxt); + + fdisk_reset_alignment(cxt); + return 0; +} + +/* + * Generic (label independent) geometry + */ +int fdisk_discover_geometry(struct fdisk_context *cxt) +{ + sector_t nsects; + unsigned int h = 0, s = 0; + + assert(cxt); + assert(!cxt->geom.heads); + + /* get number of 512-byte sectors, and convert it the real sectors */ + if (!blkdev_get_sectors(cxt->dev_fd, &nsects)) + cxt->total_sectors = (nsects / (cxt->sector_size >> 9)); + + /* what the kernel/bios thinks the geometry is */ + blkdev_get_geometry(cxt->dev_fd, &h, &s); + if (!h && !s) { + /* unable to discover geometry, use default values */ + s = 63; + h = 255; + } + + /* obtained heads and sectors */ + cxt->geom.heads = h; + cxt->geom.sectors = s; + recount_geometry(cxt); + + DBG(GEOMETRY, dbgprint("geometry discovered for %s: C/H/S: %lld/%d/%lld", + cxt->dev_path, cxt->geom.cylinders, + cxt->geom.heads, cxt->geom.sectors)); + return 0; +} + +int fdisk_discover_topology(struct fdisk_context *cxt) +{ + assert(cxt); + assert(cxt->sector_size == 0); + +#ifdef HAVE_LIBBLKID + blkid_probe pr; + + DBG(TOPOLOGY, dbgprint("initialize libblkid prober")); + + pr = blkid_new_probe(); + if (pr && blkid_probe_set_device(pr, cxt->dev_fd, 0, 0) == 0) { + blkid_topology tp = blkid_probe_get_topology(pr); + + if (tp) { + cxt->min_io_size = blkid_topology_get_minimum_io_size(tp); + cxt->optimal_io_size = blkid_topology_get_optimal_io_size(tp); + cxt->phy_sector_size = blkid_topology_get_physical_sector_size(tp); + cxt->alignment_offset = blkid_topology_get_alignment_offset(tp); + + /* I/O size used by fdisk */ + cxt->io_size = cxt->optimal_io_size; + if (!cxt->io_size) + /* optimal IO is optional, default to minimum IO */ + cxt->io_size = cxt->min_io_size; + } + } + blkid_free_probe(pr); +#endif + + cxt->sector_size = get_sector_size(cxt->dev_fd); + if (!cxt->phy_sector_size) /* could not discover physical size */ + cxt->phy_sector_size = cxt->sector_size; + + /* no blkid or error, use default values */ + if (!cxt->min_io_size) + cxt->min_io_size = cxt->sector_size; + if (!cxt->io_size) + cxt->io_size = cxt->sector_size; + + DBG(TOPOLOGY, dbgprint("topology discovered for %s:\n" + "\tlogical/physical sector sizes: %ld/%ld\n" + "\tfdisk/minimal/optimal io sizes: %ld/%ld/%ld\n", + cxt->dev_path, cxt->sector_size, cxt->phy_sector_size, + cxt->io_size, cxt->optimal_io_size, cxt->min_io_size)); + return 0; +} + +static int has_topology(struct fdisk_context *cxt) +{ + /* + * Assume that the device provides topology info if + * optimal_io_size is set or alignment_offset is set or + * minimum_io_size is not power of 2. + */ + if (cxt && + (cxt->optimal_io_size || + cxt->alignment_offset || + !is_power_of_2(cxt->min_io_size))) + return 1; + return 0; +} + +/* + * The LBA of the first partition is based on the device geometry and topology. + * This offset is generic (and recommended) for all labels. + * + * Returns: 0 on error or number of logical sectors. + */ +sector_t fdisk_topology_get_first_lba(struct fdisk_context *cxt) +{ + sector_t x = 0, res; + + if (!cxt) + return 0; + + if (!cxt->io_size) + fdisk_discover_topology(cxt); + + /* + * Align the begin of partitions to: + * + * a) topology + * a2) alignment offset + * a1) or physical sector (minimal_io_size, aka "grain") + * + * b) or default to 1MiB (2048 sectrors, Windows Vista default) + * + * c) or for very small devices use 1 phy.sector + */ + if (has_topology(cxt)) { + if (cxt->alignment_offset) + x = cxt->alignment_offset; + else if (cxt->io_size > 2048 * 512) + x = cxt->io_size; + } + /* default to 1MiB */ + if (!x) + x = 2048 * 512; + + res = x / cxt->sector_size; + + /* don't use huge offset on small devices */ + if (cxt->total_sectors <= res * 4) + res = cxt->phy_sector_size / cxt->sector_size; + + return res; +} + +/* + * The LBA of the first partition is based on the device geometry and topology. + * This offset is generic generic (and recommended) for all labels. + * + * Returns: 0 on error or number of bytes. + */ +unsigned long fdisk_topology_get_grain(struct fdisk_context *cxt) +{ + unsigned long res; + + if (!cxt) + return 0; + + if (!cxt->io_size) + fdisk_discover_topology(cxt); + + res = cxt->io_size; + + /* use 1MiB grain always when possible */ + if (res < 2048 * 512) + res = 2048 * 512; + + /* don't use huge grain on small devices */ + if (cxt->total_sectors <= (res * 4 / cxt->sector_size)) + res = cxt->phy_sector_size; + + return res; +} diff --git a/libfdisk/src/fdiskP.h b/libfdisk/src/fdiskP.h index 4f5585733..e9c21ca89 100644 --- a/libfdisk/src/fdiskP.h +++ b/libfdisk/src/fdiskP.h @@ -192,6 +192,14 @@ extern sector_t fdisk_align_lba_in_range(struct fdisk_context *cxt, sector_t lba sector_t start, sector_t stop); +extern int fdisk_override_sector_size(struct fdisk_context *cxt, sector_t s); +extern int fdisk_override_geometry(struct fdisk_context *cxt, + unsigned int cylinders, unsigned int heads, + unsigned int sectors); + +extern int fdisk_discover_geometry(struct fdisk_context *cxt); +extern int fdisk_discover_topology(struct fdisk_context *cxt); + /* utils.c */ extern void fdisk_zeroize_firstsector(struct fdisk_context *cxt); extern int fdisk_read_firstsector(struct fdisk_context *cxt); |