]> git.ipfire.org Git - thirdparty/util-linux.git/commitdiff
libblkid: Detect external XFS log device
authorEric Sandeen <sandeen@redhat.com>
Mon, 5 Aug 2013 23:09:35 +0000 (18:09 -0500)
committerKarel Zak <kzak@redhat.com>
Wed, 11 Sep 2013 08:29:33 +0000 (10:29 +0200)
Detects external XFS log devices with a minimum size of 10MB.  It's possible to
craft a smaller log, but that would be very unlikely; it'd require a small XFS
filesystem and an intentionally small log, which would defeat the performance
goal of an external log in the first place.

[kzak@redhat.com: - use UUID_LOG variable name for the log uuid]

Signed-off-by: Eric Sandeen <sandeen@redhat.com>
Signed-off-by: Karel Zak <kzak@redhat.com>
libblkid/src/superblocks/superblocks.c
libblkid/src/superblocks/superblocks.h
libblkid/src/superblocks/xfs.c

index 5f43b24861ed540372a200a6f84401d2be81bbfd..c09d8285fc15309b6d70398917ec9f0741d7fbbe 100644 (file)
@@ -49,6 +49,8 @@
  *
  * @UUID_SUB: subvolume uuid (e.g. btrfs)
  *
+ * @UUID_LOG: external log UUID (e.g. xfs)
+ *
  * @UUID_RAW: raw UUID from FS superblock
  *
  * @EXT_JOURNAL: external journal UUID
@@ -113,6 +115,7 @@ static const struct blkid_idinfo *idinfos[] =
        &swsuspend_idinfo,
        &swap_idinfo,
        &xfs_idinfo,
+       &xfs_log_idinfo,
        &ext4dev_idinfo,
        &ext4_idinfo,
        &ext3_idinfo,
index 2e523511358741ec25fe4160c832f6a47c76dba5..90847151ba48ba15f6c9037f052158bf1c7b1a47 100644 (file)
@@ -29,6 +29,7 @@ extern const struct blkid_idinfo ext2_idinfo;
 extern const struct blkid_idinfo jbd_idinfo;
 extern const struct blkid_idinfo jfs_idinfo;
 extern const struct blkid_idinfo xfs_idinfo;
+extern const struct blkid_idinfo xfs_log_idinfo;
 extern const struct blkid_idinfo gfs_idinfo;
 extern const struct blkid_idinfo gfs2_idinfo;
 extern const struct blkid_idinfo romfs_idinfo;
index 1399fe13a4c08592034b0f804c97fe392ea3e645..285b7c4a2e5432827996d3ae242c7bdbda276006 100644 (file)
@@ -4,6 +4,7 @@
  * Copyright (C) 2001 by Andreas Dilger
  * Copyright (C) 2004 Kay Sievers <kay.sievers@vrfy.org>
  * Copyright (C) 2008 Karel Zak <kzak@redhat.com>
+ * Copyright (C) 2013 Eric Sandeen <sandeen@redhat.com>
  *
  * This file may be redistributed under the terms of the
  * GNU Lesser General Public License.
@@ -61,3 +62,88 @@ const struct blkid_idinfo xfs_idinfo =
        }
 };
 
+struct xlog_rec_header {
+       uint32_t        h_magicno;
+       uint32_t        h_dummy1[1];
+       uint32_t        h_version;
+       uint32_t        h_len;
+       uint32_t        h_dummy2[71];
+       uint32_t        h_fmt;
+       unsigned char   h_uuid[16];
+} __attribute__((packed));
+
+#define XLOG_HEADER_MAGIC_NUM 0xFEEDbabe
+
+/*
+ * For very small filesystems, the minimum log size
+ * can be smaller, but that seems vanishingly unlikely
+ * when used with an external log (which is used for
+ * performance reasons; tiny conflicts with that goal).
+ */
+#define XFS_MIN_LOG_BYTES      (10 * 1024 * 1024)
+
+#define XLOG_FMT_LINUX_LE      1
+#define XLOG_FMT_LINUX_BE      2
+#define XLOG_FMT_IRIX_BE       3
+
+#define XLOG_VERSION_1         1
+#define XLOG_VERSION_2         2       /* Large IClogs, Log sunit */
+#define XLOG_VERSION_OKBITS    (XLOG_VERSION_1 | XLOG_VERSION_2)
+
+static int xlog_valid_rec_header(struct xlog_rec_header *rhead)
+{
+       int hlen;
+
+       if (rhead->h_magicno != cpu_to_be32(XLOG_HEADER_MAGIC_NUM))
+               return 0;
+
+       if (!rhead->h_version ||
+            (be32_to_cpu(rhead->h_version) & (~XLOG_VERSION_OKBITS)))
+               return 0;
+
+       /* LR body must have data or it wouldn't have been written */
+       hlen = be32_to_cpu(rhead->h_len);
+       if (hlen <= 0 || hlen > INT_MAX)
+               return 0;
+
+       if (rhead->h_fmt != cpu_to_be32(XLOG_FMT_LINUX_LE) &&
+           rhead->h_fmt != cpu_to_be32(XLOG_FMT_LINUX_BE) &&
+           rhead->h_fmt != cpu_to_be32(XLOG_FMT_IRIX_BE))
+               return 0;
+
+       return 1;
+}
+
+/* xlog record header will be in some sector in the first 256k */
+static int probe_xfs_log(blkid_probe pr, const struct blkid_idmag *mag)
+{
+       int i;
+       struct xlog_rec_header *rhead;
+       unsigned char *buf;
+
+       buf = blkid_probe_get_buffer(pr, 0, 256*1024);
+       if (!buf)
+               return -1;
+
+       /* check the first 512 512-byte sectors */
+       for (i = 0; i < 512; i++) {
+               rhead = (struct xlog_rec_header *)&buf[i*512];
+
+               if (xlog_valid_rec_header(rhead)) {
+                       blkid_probe_set_uuid(pr, rhead->h_uuid);
+                       blkid_probe_set_uuid_as(pr, rhead->h_uuid, "UUID_LOG");
+                       return 0;
+               }
+       }
+
+       return -1;
+}
+
+const struct blkid_idinfo xfs_log_idinfo =
+{
+       .name           = "xfs_external_log",
+       .usage          = BLKID_USAGE_OTHER,
+       .probefunc      = probe_xfs_log,
+       .magics         = BLKID_NONE_MAGIC,
+       .minsz          = XFS_MIN_LOG_BYTES,
+};