]> err.no Git - util-linux/commitdiff
fdisk: add basic routines for LBA alignment
authorKarel Zak <kzak@redhat.com>
Wed, 4 Nov 2009 15:15:48 +0000 (16:15 +0100)
committerKarel Zak <kzak@redhat.com>
Wed, 18 Nov 2009 10:25:09 +0000 (11:25 +0100)
Signed-off-by: Karel Zak <kzak@redhat.com>
fdisk/fdisk.c

index 9b51ce9d4a40360ed70fc9257a82c7689e65ee20..9ccd32ee2c5726a036da489a95b724d6c9877e37 100644 (file)
@@ -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;