From: Karel Zak Date: Wed, 5 Dec 2012 13:32:20 +0000 (+0100) Subject: libfdisk: add alignment code X-Git-Tag: v2.23-rc1~166 X-Git-Url: http://git.ipfire.org/?a=commitdiff_plain;h=9475cc78ff5318fb659a7b90bb181f9c9522de02;p=thirdparty%2Futil-linux.git libfdisk: add alignment code Signed-off-by: Karel Zak --- diff --git a/fdisks/fdisk.c b/fdisks/fdisk.c index dd06b9b229..f34617f08e 100644 --- a/fdisks/fdisk.c +++ b/fdisks/fdisk.c @@ -288,86 +288,6 @@ test_c(char **m, char *mesg) { return val; } -static int -lba_is_aligned(struct fdisk_context *cxt, sector_t lba) -{ - unsigned int granularity = max(cxt->phy_sector_size, cxt->min_io_size); - unsigned long long offset; - - if (cxt->grain > granularity) - granularity = cxt->grain; - offset = (lba * cxt->sector_size) & (granularity - 1); - - return !((granularity + cxt->alignment_offset - offset) & (granularity - 1)); -} - -static int -lba_is_phy_aligned(struct fdisk_context *cxt, unsigned long long lba) -{ - unsigned int granularity = max(cxt->phy_sector_size, cxt->min_io_size); - unsigned long long offset = (lba * cxt->sector_size) & (granularity - 1); - - return !((granularity + cxt->alignment_offset - offset) & (granularity - 1)); -} - -sector_t align_lba(struct fdisk_context *cxt, sector_t lba, int direction) -{ - sector_t res; - - if (lba_is_aligned(cxt, lba)) - res = lba; - else { - sector_t sects_in_phy = cxt->grain / cxt->sector_size; - - if (lba < cxt->first_lba) - res = cxt->first_lba; - - else if (direction == ALIGN_UP) - res = ((lba + sects_in_phy) / sects_in_phy) * sects_in_phy; - - else if (direction == ALIGN_DOWN) - res = (lba / sects_in_phy) * sects_in_phy; - - else /* ALIGN_NEAREST */ - res = ((lba + sects_in_phy / 2) / sects_in_phy) * sects_in_phy; - - if (cxt->alignment_offset && !lba_is_aligned(cxt, res) && - res > cxt->alignment_offset / cxt->sector_size) { - /* - * apply alignment_offset - * - * On disk with alignment compensation physical blocks starts - * at LBA < 0 (usually LBA -1). It means we have to move LBA - * according the offset to be on the physical boundary. - */ - /* fprintf(stderr, "LBA: %llu apply alignment_offset\n", res); */ - res -= (max(cxt->phy_sector_size, cxt->min_io_size) - - cxt->alignment_offset) / cxt->sector_size; - - if (direction == ALIGN_UP && res < lba) - res += sects_in_phy; - } - } - - return res; -} - - -sector_t align_lba_in_range(struct fdisk_context *cxt, - sector_t lba, sector_t start, sector_t stop) -{ - start = align_lba(cxt, start, ALIGN_UP); - stop = align_lba(cxt, stop, ALIGN_DOWN); - - lba = align_lba(cxt, lba, ALIGN_NEAREST); - - if (lba < start) - return start; - else if (lba > stop) - return stop; - return lba; -} - int warn_geometry(struct fdisk_context *cxt) { char *m = NULL; @@ -862,13 +782,6 @@ void check_consistency(struct fdisk_context *cxt, struct partition *p, int parti } } -void check_alignment(struct fdisk_context *cxt, sector_t lba, int partition) -{ - if (!lba_is_phy_aligned(cxt, lba)) - printf(_("Partition %i does not start on physical sector boundary.\n"), - partition + 1); -} - static void list_disk_geometry(struct fdisk_context *cxt) { unsigned long long bytes = cxt->total_sectors * cxt->sector_size; @@ -1111,7 +1024,7 @@ static void list_table(struct fdisk_context *cxt, int xtra) /* type id */ p->sys_ind, /* type name */ type ? type->name : _("Unknown")); check_consistency(cxt, p, i); - check_alignment(cxt, get_partition_start(pe), i); + fdisk_warn_alignment(cxt, get_partition_start(pe), i); } } @@ -1146,7 +1059,7 @@ x_list_table(struct fdisk_context *cxt, int extend) { (unsigned long) get_nr_sects(p), p->sys_ind); if (p->sys_ind) { check_consistency(cxt, p, i); - check_alignment(cxt, get_partition_start(pe), i); + fdisk_warn_alignment(cxt, get_partition_start(pe), i); } } } diff --git a/fdisks/fdisk.h b/fdisks/fdisk.h index 82313c91e8..4ea9b3b9c2 100644 --- a/fdisks/fdisk.h +++ b/fdisks/fdisk.h @@ -26,9 +26,6 @@ #define LINUX_LVM 0x8e #define LINUX_RAID 0xfd -#define ALIGN_UP 1 -#define ALIGN_DOWN 2 -#define ALIGN_NEAREST 3 #define LINE_LENGTH 800 @@ -95,16 +92,12 @@ extern struct fdisk_parttype *fdisk_get_partition_type(struct fdisk_context *cxt extern int fdisk_set_partition_type(struct fdisk_context *cxt, int partnum, struct fdisk_parttype *t); -extern sector_t fdisk_topology_get_first_lba(struct fdisk_context *cxt); -extern unsigned long fdisk_topology_get_grain(struct fdisk_context *cxt); - /* prototypes for fdisk.c */ extern char *line_ptr; extern int partitions; extern unsigned int display_in_cyl_units, units_per_sector; extern void check_consistency(struct fdisk_context *cxt, struct partition *p, int partition); -extern void check_alignment(struct fdisk_context *cxt, sector_t lba, int partition); extern void check(struct fdisk_context *cxt, int n, unsigned int h, unsigned int s, unsigned int c, unsigned int start); extern void fatal(struct fdisk_context *cxt, enum failure why); @@ -132,8 +125,6 @@ extern void warn_limits(struct fdisk_context *cxt); extern unsigned int read_int_with_suffix(struct fdisk_context *cxt, unsigned int low, unsigned int dflt, unsigned int high, unsigned int base, char *mesg, int *is_suffix_used); -extern sector_t align_lba(struct fdisk_context *cxt, sector_t lba, int direction); -extern sector_t align_lba_in_range(struct fdisk_context *cxt, sector_t lba, sector_t start, sector_t stop); extern int get_partition_dflt(struct fdisk_context *cxt, int warn, int max, int dflt); #define PLURAL 0 diff --git a/fdisks/fdiskdoslabel.c b/fdisks/fdiskdoslabel.c index ab940a010b..45343c8383 100644 --- a/fdisks/fdiskdoslabel.c +++ b/fdisks/fdiskdoslabel.c @@ -590,7 +590,7 @@ static int add_partition(struct fdisk_context *cxt, int n, struct fdisk_parttype /* the default sector should be aligned and unused */ do { - aligned = align_lba_in_range(cxt, dflt, dflt, limit); + aligned = fdisk_align_lba_in_range(cxt, dflt, dflt, limit); dflt = get_unused_start(cxt, n, aligned, first, last); } while (dflt != aligned && dflt > aligned && dflt < limit); @@ -664,7 +664,7 @@ static int add_partition(struct fdisk_context *cxt, int n, struct fdisk_parttype * and align the end of the partition. The next * partition will start at phy.block boundary. */ - stop = align_lba_in_range(cxt, stop, start, limit) - 1; + stop = fdisk_align_lba_in_range(cxt, stop, start, limit) - 1; if (stop > limit) stop = limit; } @@ -721,7 +721,7 @@ static int dos_verify_disklabel(struct fdisk_context *cxt) p = pe->part_table; if (p->sys_ind && !IS_EXTENDED (p->sys_ind)) { check_consistency(cxt, p, i); - check_alignment(cxt, get_partition_start(pe), i); + fdisk_warn_alignment(cxt, get_partition_start(pe), i); if (get_partition_start(pe) < first[i]) printf(_("Warning: bad start-of-data in " "partition %d\n"), i + 1); diff --git a/fdisks/gpt.c b/fdisks/gpt.c index 87efd2550d..0784d639a5 100644 --- a/fdisks/gpt.c +++ b/fdisks/gpt.c @@ -1144,7 +1144,7 @@ void gpt_list_table(struct fdisk_context *cxt, t->name, name); - check_alignment(cxt, start, i); + fdisk_warn_alignment(cxt, start, i); free(name); free(sizestr); @@ -1516,7 +1516,7 @@ static int gpt_add_partition(struct fdisk_context *cxt, int partnum, dflt_l = find_last_free(pheader, ents, dflt_f); /* align the default in range */ - dflt_f = align_lba_in_range(cxt, dflt_f, dflt_f, dflt_l); + dflt_f = fdisk_align_lba_in_range(cxt, dflt_f, dflt_f, dflt_l); if (t && t->typestr) string_to_uuid(t->typestr, &uuid); @@ -1550,7 +1550,7 @@ static int gpt_add_partition(struct fdisk_context *cxt, int partnum, &is_suffix_used); if (is_suffix_used) - user_l = align_lba_in_range(cxt, user_l, user_f, dflt_l) - 1; + user_l = fdisk_align_lba_in_range(cxt, user_l, user_f, dflt_l) - 1; if (user_l > user_f && user_l <= disk_l) break; diff --git a/libfdisk/src/Makemodule.am b/libfdisk/src/Makemodule.am index 66cbe872c9..3159432f51 100644 --- a/libfdisk/src/Makemodule.am +++ b/libfdisk/src/Makemodule.am @@ -9,6 +9,7 @@ libfdisk_la_SOURCES = \ libfdisk/src/libfdisk.h \ \ libfdisk/src/init.c \ + libfdisk/src/alignment.c \ libfdisk/src/parttype.c diff --git a/libfdisk/src/alignment.c b/libfdisk/src/alignment.c new file mode 100644 index 0000000000..b0d38ae235 --- /dev/null +++ b/libfdisk/src/alignment.c @@ -0,0 +1,101 @@ + +#include "fdiskP.h" + +/* + * Alignment according to logical granulity (usually 1MiB) + */ +static int lba_is_aligned(struct fdisk_context *cxt, sector_t lba) +{ + unsigned long granularity = max(cxt->phy_sector_size, cxt->min_io_size); + uintmax_t offset; + + if (cxt->grain > granularity) + granularity = cxt->grain; + offset = (lba * cxt->sector_size) & (granularity - 1); + + return !((granularity + cxt->alignment_offset - offset) & (granularity - 1)); +} + +/* + * Alignment according to physical device topology (usually minimal i/o size) + */ +static int lba_is_phy_aligned(struct fdisk_context *cxt, sector_t lba) +{ + unsigned long granularity = max(cxt->phy_sector_size, cxt->min_io_size); + uintmax_t offset = (lba * cxt->sector_size) & (granularity - 1); + + return !((granularity + cxt->alignment_offset - offset) & (granularity - 1)); +} + +/* + * Align @lba in @direction FDISK_ALIGN_{UP,DOWN,NEAREST} + */ +sector_t fdisk_align_lba(struct fdisk_context *cxt, sector_t lba, int direction) +{ + sector_t res; + + if (lba_is_aligned(cxt, lba)) + res = lba; + else { + sector_t sects_in_phy = cxt->grain / cxt->sector_size; + + if (lba < cxt->first_lba) + res = cxt->first_lba; + + else if (direction == FDISK_ALIGN_UP) + res = ((lba + sects_in_phy) / sects_in_phy) * sects_in_phy; + + else if (direction == FDISK_ALIGN_DOWN) + res = (lba / sects_in_phy) * sects_in_phy; + + else /* FDISK_ALIGN_NEAREST */ + res = ((lba + sects_in_phy / 2) / sects_in_phy) * sects_in_phy; + + if (cxt->alignment_offset && !lba_is_aligned(cxt, res) && + res > cxt->alignment_offset / cxt->sector_size) { + /* + * apply alignment_offset + * + * On disk with alignment compensation physical blocks starts + * at LBA < 0 (usually LBA -1). It means we have to move LBA + * according the offset to be on the physical boundary. + */ + /* fprintf(stderr, "LBA: %llu apply alignment_offset\n", res); */ + res -= (max(cxt->phy_sector_size, cxt->min_io_size) - + cxt->alignment_offset) / cxt->sector_size; + + if (direction == FDISK_ALIGN_UP && res < lba) + res += sects_in_phy; + } + } + + return res; +} + +/* + * Align @lba, the result has to be between @start and @stop + */ +sector_t fdisk_align_lba_in_range(struct fdisk_context *cxt, + sector_t lba, sector_t start, sector_t stop) +{ + start = fdisk_align_lba(cxt, start, FDISK_ALIGN_UP); + stop = fdisk_align_lba(cxt, stop, FDISK_ALIGN_DOWN); + lba = fdisk_align_lba(cxt, lba, FDISK_ALIGN_NEAREST); + + if (lba < start) + return start; + else if (lba > stop) + return stop; + return lba; +} + +/* + * Print warning if the partition @lba (start of the @partition) is not + * aligned to physical sector boundary. + */ +void fdisk_warn_alignment(struct fdisk_context *cxt, sector_t lba, int partition) +{ + if (!lba_is_phy_aligned(cxt, lba)) + printf(_("Partition %i does not start on physical sector boundary.\n"), + partition + 1); +} diff --git a/libfdisk/src/fdiskP.h b/libfdisk/src/fdiskP.h index 82443453aa..9ae258e13d 100644 --- a/libfdisk/src/fdiskP.h +++ b/libfdisk/src/fdiskP.h @@ -20,6 +20,8 @@ #include "c.h" #include "libfdisk.h" +#include "nls.h" /* temporary before dialog API will be implamented */ + /* features */ #define CONFIG_LIBFDISK_ASSERT #define CONFIG_LIBFDISK_DEBUG @@ -189,4 +191,20 @@ struct fdisk_label { int (*reset_alignment)(struct fdisk_context *cxt); }; +/* alignment.c */ +extern sector_t fdisk_topology_get_first_lba(struct fdisk_context *cxt); +extern unsigned long fdisk_topology_get_grain(struct fdisk_context *cxt); + +extern void fdisk_warn_alignment(struct fdisk_context *cxt, + sector_t lba, int partition); + + +#define FDISK_ALIGN_UP 1 +#define FDISK_ALIGN_DOWN 2 +#define FDISK_ALIGN_NEAREST 3 + +extern sector_t fdisk_align_lba(struct fdisk_context *cxt, sector_t lba, int direction); +extern sector_t fdisk_align_lba_in_range(struct fdisk_context *cxt, sector_t lba, + sector_t start, sector_t stop); + #endif /* _LIBFDISK_PRIVATE_H */