From: Karel Zak Date: Thu, 6 Dec 2012 11:12:41 +0000 (+0100) Subject: libfdisk: add topology and geometry functions X-Git-Tag: v2.23-rc1~162 X-Git-Url: http://git.ipfire.org/cgi-bin/gitweb.cgi?a=commitdiff_plain;h=aa42788d5f6beded3b36fb45cfaf4a27fff25698;p=thirdparty%2Futil-linux.git 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 --- diff --git a/fdisks/fdisk.c b/fdisks/fdisk.c index f34617f08e..866d8fe21c 100644 --- a/fdisks/fdisk.c +++ b/fdisks/fdisk.c @@ -1301,7 +1301,7 @@ expert_command_prompt(struct fdisk_context *cxt) case 'c': user_cylinders = read_int(cxt, 1, cxt->geom.cylinders, 1048576, 0, _("Number of cylinders")); - fdisk_context_set_user_geometry(cxt, user_cylinders, user_heads, user_sectors); + fdisk_override_geometry(cxt, user_cylinders, user_heads, user_sectors); if (fdisk_is_disklabel(cxt, SUN)) sun_set_ncyl(cxt, cxt->geom.cylinders); break; @@ -1327,7 +1327,7 @@ expert_command_prompt(struct fdisk_context *cxt) case 'h': user_heads = read_int(cxt, 1, cxt->geom.heads, 256, 0, _("Number of heads")); - fdisk_context_set_user_geometry(cxt, user_cylinders, user_heads, user_sectors); + fdisk_override_geometry(cxt, user_cylinders, user_heads, user_sectors); break; case 'i': if (fdisk_is_disklabel(cxt, SUN)) @@ -1356,7 +1356,7 @@ expert_command_prompt(struct fdisk_context *cxt) fprintf(stderr, _("Warning: setting " "sector offset for DOS " "compatibility\n")); - fdisk_context_set_user_geometry(cxt, user_cylinders, user_heads, user_sectors); + fdisk_override_geometry(cxt, user_cylinders, user_heads, user_sectors); break; case 'v': verify(cxt); @@ -1396,10 +1396,10 @@ static void print_partition_table_from_option(char *device, unsigned long sector err(EXIT_FAILURE, _("cannot open %s"), device); if (sector_size) /* passed -b option, override autodiscovery */ - fdisk_context_force_sector_size(cxt, sector_size); + fdisk_override_sector_size(cxt, sector_size); if (user_cylinders || user_heads || user_sectors) - fdisk_context_set_user_geometry(cxt, user_cylinders, + fdisk_override_geometry(cxt, user_cylinders, user_heads, user_sectors); if (!fdisk_dev_has_disklabel(cxt)) { @@ -1697,18 +1697,14 @@ int main(int argc, char **argv) err(EXIT_FAILURE, _("cannot open %s"), argv[optind]); if (sector_size) /* passed -b option, override autodiscovery */ - fdisk_context_force_sector_size(cxt, sector_size); + fdisk_override_sector_size(cxt, sector_size); if (user_cylinders || user_heads || user_sectors) - fdisk_context_set_user_geometry(cxt, user_cylinders, + fdisk_override_geometry(cxt, user_cylinders, user_heads, user_sectors); print_welcome(); - if (!fdisk_dev_sectsz_is_default(cxt)) - printf(_("Note: sector size is %ld (not %d)\n"), - cxt->sector_size, DEFAULT_SECTOR_SIZE); - if (!fdisk_dev_has_disklabel(cxt)) { update_units(cxt); /* to provide compatible 'p'rint output */ fprintf(stderr, diff --git a/fdisks/fdisk.h b/fdisks/fdisk.h index 4736bccb9b..cdbc40886d 100644 --- a/fdisks/fdisk.h +++ b/fdisks/fdisk.h @@ -72,13 +72,7 @@ extern const struct fdisk_label sgi_label; extern const struct fdisk_label gpt_label; extern struct fdisk_context *fdisk_new_context_from_filename(const char *fname, int readonly); -extern int fdisk_dev_has_topology(struct fdisk_context *cxt); -extern int fdisk_dev_sectsz_is_default(struct fdisk_context *cxt); extern void fdisk_free_context(struct fdisk_context *cxt); -extern int fdisk_context_force_sector_size(struct fdisk_context *cxt, sector_t s); -extern int fdisk_context_set_user_geometry(struct fdisk_context *cxt, - unsigned int cylinders, unsigned int heads, - unsigned int sectors); extern int fdisk_create_disklabel(struct fdisk_context *cxt, const char *name); extern int fdisk_reset_alignment(struct fdisk_context *cxt); extern struct fdisk_parttype *fdisk_get_partition_type(struct fdisk_context *cxt, int partnum); diff --git a/fdisks/utils.c b/fdisks/utils.c index 24f169efd0..15278bf7d2 100644 --- a/fdisks/utils.c +++ b/fdisks/utils.c @@ -69,262 +69,6 @@ static int __probe_labels(struct fdisk_context *cxt) return 1; /* not found */ } -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_context_force_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_context_force_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_context_set_user_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_context_set_user_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 - */ -static int __discover_system_geometry(struct fdisk_context *cxt) -{ - sector_t nsects; - unsigned int h = 0, s = 0; - - /* 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; -} - -static int __discover_topology(struct fdisk_context *cxt) -{ -#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; -} - -/** - * fdisk_dev_sectsz_is_default: - * @cxt: fdisk context - * - * Returns 1 if the device's sector size is the default value, otherwise 0. - */ -int fdisk_dev_sectsz_is_default(struct fdisk_context *cxt) -{ - if (!cxt) - return -EINVAL; - - return cxt->sector_size == DEFAULT_SECTOR_SIZE; -} - -/** - * fdisk_dev_has_topology: - * @cxt: fdisk context - * - * Returns 1 if the device provides topology information, otherwise 0. - */ -int fdisk_dev_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) - __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 (fdisk_dev_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) - __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; -} /** * fdisk_reset_alignment: @@ -437,8 +181,8 @@ struct fdisk_context *fdisk_new_context_from_filename(const char *fname, int rea if (!cxt->dev_path) goto fail; - __discover_topology(cxt); - __discover_system_geometry(cxt); + fdisk_discover_topology(cxt); + fdisk_discover_geometry(cxt); if (fdisk_read_firstsector(cxt) < 0) goto fail; diff --git a/libfdisk/src/alignment.c b/libfdisk/src/alignment.c index b0d38ae235..e06e1afb0f 100644 --- a/libfdisk/src/alignment.c +++ b/libfdisk/src/alignment.c @@ -1,6 +1,14 @@ +#ifdef HAVE_LIBBLKID +#include +#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 4f5585733a..e9c21ca898 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);