diff options
author | Karel Zak <kzak@redhat.com> | 2009-11-04 16:15:48 +0100 |
---|---|---|
committer | Karel Zak <kzak@redhat.com> | 2009-11-18 11:25:09 +0100 |
commit | b39a46413f7c78e7dc31665739ffe7bdfa74b126 (patch) | |
tree | 0c4113507599c0a4e25a51d5830097699c302910 /fdisk | |
parent | 05dc9645f64e21167d297f435951a7bf2a43c43e (diff) | |
download | util-linux-old-b39a46413f7c78e7dc31665739ffe7bdfa74b126.tar.gz |
fdisk: add basic routines for LBA alignment
Signed-off-by: Karel Zak <kzak@redhat.com>
Diffstat (limited to 'fdisk')
-rw-r--r-- | fdisk/fdisk.c | 73 |
1 files changed, 73 insertions, 0 deletions
diff --git a/fdisk/fdisk.c b/fdisk/fdisk.c index 9b51ce9d..9ccd32ee 100644 --- a/fdisk/fdisk.c +++ b/fdisk/fdisk.c @@ -637,6 +637,79 @@ test_c(char **m, char *mesg) { return val; } +#define alignment_required (minimum_io_size != sector_size) + +static int +lba_is_aligned(unsigned long long lba) +{ + unsigned long long bytes, phy_sectors; + + bytes = lba * sector_size; + phy_sectors = bytes / minimum_io_size; + + return (alignment_offset + (phy_sectors * minimum_io_size) == bytes); +} + +#define ALIGN_UP 1 +#define ALIGN_DOWN 2 +#define ALIGN_NEAREST 3 + +static unsigned long long +align_lba(unsigned long long lba, int direction) +{ + unsigned long long sects_in_phy, res; + + if (lba_is_aligned(lba)) + return lba; + + sects_in_phy = minimum_io_size / sector_size; + + if (lba < sects_in_phy) + /* align to the first physical sector */ + res = sects_in_phy; + + 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 (alignment_offset) + /* + * apply alignment_offset + * + * On disk with alignment compensation physical blocks start + * at LBA < 0 (usually LBA -1). It means we have to move LBA + * according the offset to be on the physical boundary. + */ + res -= (minimum_io_size - alignment_offset) / sector_size; + + /* fprintf(stderr, "LBA %llu -align-> %llu (%s)\n", lba, res, + * lba_is_aligned(res) ? "OK" : "FALSE"); + */ + return res; +} + +static unsigned long long +align_lba_in_range( unsigned long long lba, + unsigned long long start, + unsigned long long stop) +{ + start = align_lba(start, ALIGN_UP); + stop = align_lba(stop, ALIGN_DOWN); + + lba = align_lba(lba, ALIGN_NEAREST); + + if (lba < start) + return start; + else if (lba > stop) + return stop; + return lba; +} + static int warn_geometry(void) { char *m = NULL; |