diff options
author | Karel Zak | 2012-12-05 14:32:20 +0100 |
---|---|---|
committer | Karel Zak | 2013-03-11 11:20:40 +0100 |
commit | 9475cc78ff5318fb659a7b90bb181f9c9522de02 (patch) | |
tree | 5a084b4eb71dfd2fad97d51b879fde061d9e0209 /libfdisk | |
parent | libfdisk: add parttype code (diff) | |
download | kernel-qcow2-util-linux-9475cc78ff5318fb659a7b90bb181f9c9522de02.tar.gz kernel-qcow2-util-linux-9475cc78ff5318fb659a7b90bb181f9c9522de02.tar.xz kernel-qcow2-util-linux-9475cc78ff5318fb659a7b90bb181f9c9522de02.zip |
libfdisk: add alignment code
Signed-off-by: Karel Zak <kzak@redhat.com>
Diffstat (limited to 'libfdisk')
-rw-r--r-- | libfdisk/src/Makemodule.am | 1 | ||||
-rw-r--r-- | libfdisk/src/alignment.c | 101 | ||||
-rw-r--r-- | libfdisk/src/fdiskP.h | 18 |
3 files changed, 120 insertions, 0 deletions
diff --git a/libfdisk/src/Makemodule.am b/libfdisk/src/Makemodule.am index 66cbe872c..3159432f5 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 000000000..b0d38ae23 --- /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 82443453a..9ae258e13 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 */ |