summaryrefslogtreecommitdiffstats
path: root/libblkid/src
diff options
context:
space:
mode:
authorEric Sandeen2013-08-06 01:09:35 +0200
committerKarel Zak2013-09-11 10:29:33 +0200
commit0a2002551d65f73576cb4514fb052765d46cc8c5 (patch)
treee71af0f69682eaff4963200d6acece8ce603ffce /libblkid/src
parentlib: rename time-util.c to timeutils.c, fix headers (diff)
downloadkernel-qcow2-util-linux-0a2002551d65f73576cb4514fb052765d46cc8c5.tar.gz
kernel-qcow2-util-linux-0a2002551d65f73576cb4514fb052765d46cc8c5.tar.xz
kernel-qcow2-util-linux-0a2002551d65f73576cb4514fb052765d46cc8c5.zip
libblkid: Detect external XFS log device
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>
Diffstat (limited to 'libblkid/src')
-rw-r--r--libblkid/src/superblocks/superblocks.c3
-rw-r--r--libblkid/src/superblocks/superblocks.h1
-rw-r--r--libblkid/src/superblocks/xfs.c86
3 files changed, 90 insertions, 0 deletions
diff --git a/libblkid/src/superblocks/superblocks.c b/libblkid/src/superblocks/superblocks.c
index 5f43b2486..c09d8285f 100644
--- a/libblkid/src/superblocks/superblocks.c
+++ b/libblkid/src/superblocks/superblocks.c
@@ -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,
diff --git a/libblkid/src/superblocks/superblocks.h b/libblkid/src/superblocks/superblocks.h
index 2e5235113..90847151b 100644
--- a/libblkid/src/superblocks/superblocks.h
+++ b/libblkid/src/superblocks/superblocks.h
@@ -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;
diff --git a/libblkid/src/superblocks/xfs.c b/libblkid/src/superblocks/xfs.c
index 1399fe13a..285b7c4a2 100644
--- a/libblkid/src/superblocks/xfs.c
+++ b/libblkid/src/superblocks/xfs.c
@@ -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,
+};