summaryrefslogtreecommitdiff
path: root/fdisk
diff options
context:
space:
mode:
authorKarel Zak <kzak@redhat.com>2009-11-04 16:15:48 +0100
committerKarel Zak <kzak@redhat.com>2009-11-18 11:25:09 +0100
commitb39a46413f7c78e7dc31665739ffe7bdfa74b126 (patch)
tree0c4113507599c0a4e25a51d5830097699c302910 /fdisk
parent05dc9645f64e21167d297f435951a7bf2a43c43e (diff)
downloadutil-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.c73
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;