|
|
05ad79 |
From 8646f60d1b421b48b43405fa286548a0bf3f5da4 Mon Sep 17 00:00:00 2001
|
|
|
05ad79 |
From: Michal Humpula <michal.humpula@hudrydum.cz>
|
|
|
05ad79 |
Date: Sat, 28 Feb 2015 21:19:42 +0100
|
|
|
05ad79 |
Subject: [PATCH 109/116] zfs: make less syscalls
|
|
|
05ad79 |
|
|
|
05ad79 |
Upstream: https://github.com/karelzak/util-linux/commit/e44a4c7ac9522c03b76d8b62ce88b443771fdb0b
|
|
|
05ad79 |
Addresses: https://bugzilla.redhat.com/show_bug.cgi?id=1392661
|
|
|
05ad79 |
Signed-off-by: Karel Zak <kzak@redhat.com>
|
|
|
05ad79 |
---
|
|
|
05ad79 |
libblkid/src/superblocks/zfs.c | 95 ++++++++++++++++++++++++++----------------
|
|
|
05ad79 |
1 file changed, 58 insertions(+), 37 deletions(-)
|
|
|
05ad79 |
|
|
|
05ad79 |
diff --git a/libblkid/src/superblocks/zfs.c b/libblkid/src/superblocks/zfs.c
|
|
|
05ad79 |
index 4a64a03..9b5601e 100644
|
|
|
05ad79 |
--- a/libblkid/src/superblocks/zfs.c
|
|
|
05ad79 |
+++ b/libblkid/src/superblocks/zfs.c
|
|
|
05ad79 |
@@ -20,6 +20,7 @@
|
|
|
05ad79 |
#define VDEV_LABEL_NVPAIR ( 16 * 1024ULL)
|
|
|
05ad79 |
#define VDEV_LABEL_SIZE (256 * 1024ULL)
|
|
|
05ad79 |
#define UBERBLOCK_SIZE 1024ULL
|
|
|
05ad79 |
+#define UBERBLOCKS_COUNT 128
|
|
|
05ad79 |
|
|
|
05ad79 |
/* #include <sys/uberblock_impl.h> */
|
|
|
05ad79 |
#define UBERBLOCK_MAGIC 0x00bab10c /* oo-ba-bloc! */
|
|
|
05ad79 |
@@ -32,7 +33,6 @@ struct zfs_uberblock {
|
|
|
05ad79 |
char ub_rootbp; /* MOS objset_phys_t */
|
|
|
05ad79 |
} __attribute__((packed));
|
|
|
05ad79 |
|
|
|
05ad79 |
-#define ZFS_TRIES 512
|
|
|
05ad79 |
#define ZFS_WANT 4
|
|
|
05ad79 |
|
|
|
05ad79 |
#define DATA_TYPE_UINT64 8
|
|
|
05ad79 |
@@ -163,61 +163,82 @@ static void zfs_extract_guid_name(blkid_probe pr, loff_t offset)
|
|
|
05ad79 |
#define zdebug(fmt, ...) do {} while(0)
|
|
|
05ad79 |
/*#define zdebug(fmt, a...) fprintf(stderr, fmt, ##a)*/
|
|
|
05ad79 |
|
|
|
05ad79 |
-/* ZFS has 128x1kB host-endian root blocks, stored in 2 areas (labels)
|
|
|
05ad79 |
- * at the start of the disk, and 2 areas at the end of the disk.
|
|
|
05ad79 |
- */
|
|
|
05ad79 |
+static int find_uberblocks(const void *label, loff_t *ub_offset, int *swap_endian)
|
|
|
05ad79 |
+{
|
|
|
05ad79 |
+ uint64_t swab_magic = swab64(UBERBLOCK_MAGIC);
|
|
|
05ad79 |
+ struct zfs_uberblock *ub;
|
|
|
05ad79 |
+ int i, found = 0;
|
|
|
05ad79 |
+ loff_t offset = VDEV_LABEL_UBERBLOCK;
|
|
|
05ad79 |
+
|
|
|
05ad79 |
+ for (i = 0; i < UBERBLOCKS_COUNT; i++, offset += UBERBLOCK_SIZE) {
|
|
|
05ad79 |
+ ub = (struct zfs_uberblock *)(label + offset);
|
|
|
05ad79 |
+
|
|
|
05ad79 |
+ if (ub->ub_magic == UBERBLOCK_MAGIC) {
|
|
|
05ad79 |
+ *ub_offset = offset;
|
|
|
05ad79 |
+ *swap_endian = 0;
|
|
|
05ad79 |
+ found++;
|
|
|
05ad79 |
+ zdebug("probe_zfs: found little-endian uberblock at %llu\n", offset >> 10);
|
|
|
05ad79 |
+ }
|
|
|
05ad79 |
+
|
|
|
05ad79 |
+ if (ub->ub_magic == swab_magic) {
|
|
|
05ad79 |
+ *ub_offset = offset;
|
|
|
05ad79 |
+ *swap_endian = 1;
|
|
|
05ad79 |
+ found++;
|
|
|
05ad79 |
+ zdebug("probe_zfs: found big-endian uberblock at %llu\n", offset >> 10);
|
|
|
05ad79 |
+ }
|
|
|
05ad79 |
+ }
|
|
|
05ad79 |
+
|
|
|
05ad79 |
+ return found;
|
|
|
05ad79 |
+}
|
|
|
05ad79 |
+
|
|
|
05ad79 |
+/* ZFS has 128x1kB host-endian root blocks, stored in 2 areas at the start
|
|
|
05ad79 |
+ * of the disk, and 2 areas at the end of the disk. Check only some of them...
|
|
|
05ad79 |
+ * #4 (@ 132kB) is the first one written on a new filesystem. */
|
|
|
05ad79 |
static int probe_zfs(blkid_probe pr, const struct blkid_idmag *mag)
|
|
|
05ad79 |
{
|
|
|
05ad79 |
uint64_t swab_magic = swab64(UBERBLOCK_MAGIC);
|
|
|
05ad79 |
+ int swab_endian = 0;
|
|
|
05ad79 |
struct zfs_uberblock *ub;
|
|
|
05ad79 |
- int swab_endian;
|
|
|
05ad79 |
loff_t offset, ub_offset = 0;
|
|
|
05ad79 |
- int tried;
|
|
|
05ad79 |
- int found;
|
|
|
05ad79 |
+ int label_no, found = 0, found_in_label;
|
|
|
05ad79 |
+ void *label;
|
|
|
05ad79 |
loff_t blk_align = (pr->size % (256 * 1024ULL));
|
|
|
05ad79 |
|
|
|
05ad79 |
zdebug("probe_zfs\n");
|
|
|
05ad79 |
- /* Look for at least 4 uberblocks to ensure a positive match.
|
|
|
05ad79 |
- Begin with Label 0 (L0) at the start of the block device. */
|
|
|
05ad79 |
- for (tried = found = 0, offset = VDEV_LABEL_UBERBLOCK;
|
|
|
05ad79 |
- found < ZFS_WANT && tried < ZFS_TRIES;
|
|
|
05ad79 |
- tried++, offset += UBERBLOCK_SIZE)
|
|
|
05ad79 |
- {
|
|
|
05ad79 |
- /* Leave L0 to try other labels */
|
|
|
05ad79 |
- switch(tried) {
|
|
|
05ad79 |
- case 128: // jump to L1, just after L0
|
|
|
05ad79 |
- offset = VDEV_LABEL_SIZE + VDEV_LABEL_UBERBLOCK;
|
|
|
05ad79 |
+ /* Look for at least 4 uberblocks to ensure a positive match */
|
|
|
05ad79 |
+ for (label_no = 0; label_no < 4; label_no++) {
|
|
|
05ad79 |
+ switch(label_no) {
|
|
|
05ad79 |
+ case 0: // jump to L0
|
|
|
05ad79 |
+ offset = 0;
|
|
|
05ad79 |
break;
|
|
|
05ad79 |
- case 256: // jump to L2 near the far end of the block device
|
|
|
05ad79 |
- offset = pr->size - 2 * VDEV_LABEL_SIZE + VDEV_LABEL_UBERBLOCK - blk_align;
|
|
|
05ad79 |
- zdebug("probe_zfs: l2 offset %llu\n", offset >> 10);
|
|
|
05ad79 |
+ case 1: // jump to L1
|
|
|
05ad79 |
+ offset = VDEV_LABEL_SIZE;
|
|
|
05ad79 |
break;
|
|
|
05ad79 |
- case 384: // jump to L3 at the furthest end of the block device
|
|
|
05ad79 |
- offset = pr->size - VDEV_LABEL_SIZE + VDEV_LABEL_UBERBLOCK - blk_align;
|
|
|
05ad79 |
- zdebug("probe_zfs: l3 offset %llu\n", offset >> 10);
|
|
|
05ad79 |
+ case 2: // jump to L2
|
|
|
05ad79 |
+ offset = pr->size - 2 * VDEV_LABEL_SIZE - blk_align;
|
|
|
05ad79 |
+ break;
|
|
|
05ad79 |
+ case 3: // jump to L3
|
|
|
05ad79 |
+ offset = pr->size - VDEV_LABEL_SIZE - blk_align;
|
|
|
05ad79 |
break;
|
|
|
05ad79 |
}
|
|
|
05ad79 |
|
|
|
05ad79 |
- ub = (struct zfs_uberblock *)
|
|
|
05ad79 |
- blkid_probe_get_buffer(pr, offset,
|
|
|
05ad79 |
- sizeof(struct zfs_uberblock));
|
|
|
05ad79 |
- if (ub == NULL)
|
|
|
05ad79 |
+ label = blkid_probe_get_buffer(pr, offset, VDEV_LABEL_SIZE);
|
|
|
05ad79 |
+ if (label == NULL)
|
|
|
05ad79 |
return errno ? -errno : 1;
|
|
|
05ad79 |
|
|
|
05ad79 |
- if (ub->ub_magic == UBERBLOCK_MAGIC) {
|
|
|
05ad79 |
- ub_offset = offset;
|
|
|
05ad79 |
- found++;
|
|
|
05ad79 |
- zdebug("probe_zfs: found little-endian uberblock at %llu\n", offset >> 10);
|
|
|
05ad79 |
- }
|
|
|
05ad79 |
+ found_in_label = find_uberblocks(label, &ub_offset, &swab_endian);
|
|
|
05ad79 |
|
|
|
05ad79 |
- if ((swab_endian = (ub->ub_magic == swab_magic))) {
|
|
|
05ad79 |
- ub_offset = offset;
|
|
|
05ad79 |
- found++;
|
|
|
05ad79 |
- zdebug("probe_zfs: found big-endian uberblock at %llu\n", offset >> 10);
|
|
|
05ad79 |
+ if (found_in_label > 0) {
|
|
|
05ad79 |
+ found+= found_in_label;
|
|
|
05ad79 |
+ ub = (struct zfs_uberblock *)(label + ub_offset);
|
|
|
05ad79 |
+ ub_offset += offset;
|
|
|
05ad79 |
+
|
|
|
05ad79 |
+ if (found >= ZFS_WANT)
|
|
|
05ad79 |
+ break;
|
|
|
05ad79 |
}
|
|
|
05ad79 |
}
|
|
|
05ad79 |
|
|
|
05ad79 |
- if (found < 4)
|
|
|
05ad79 |
+ if (found < ZFS_WANT)
|
|
|
05ad79 |
return 1;
|
|
|
05ad79 |
|
|
|
05ad79 |
/* If we found the 4th uberblock, then we will have exited from the
|
|
|
05ad79 |
--
|
|
|
05ad79 |
2.9.3
|
|
|
05ad79 |
|