summaryrefslogtreecommitdiffstats
path: root/libfdisk
diff options
context:
space:
mode:
authorKarel Zak2012-12-05 14:32:20 +0100
committerKarel Zak2013-03-11 11:20:40 +0100
commit9475cc78ff5318fb659a7b90bb181f9c9522de02 (patch)
tree5a084b4eb71dfd2fad97d51b879fde061d9e0209 /libfdisk
parentlibfdisk: add parttype code (diff)
downloadkernel-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.am1
-rw-r--r--libfdisk/src/alignment.c101
-rw-r--r--libfdisk/src/fdiskP.h18
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 */