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