From: Eric Sandeen Date: Mon, 5 Aug 2013 23:09:35 +0000 (-0500) Subject: libblkid: Detect external XFS log device X-Git-Tag: v2.24-rc1~290 X-Git-Url: http://git.ipfire.org/cgi-bin/gitweb.cgi?a=commitdiff_plain;h=0a2002551d65f73576cb4514fb052765d46cc8c5;p=thirdparty%2Futil-linux.git 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 Signed-off-by: Karel Zak --- diff --git a/libblkid/src/superblocks/superblocks.c b/libblkid/src/superblocks/superblocks.c index 5f43b24861..c09d8285fc 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 2e52351135..90847151ba 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 1399fe13a4..285b7c4a2e 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 * Copyright (C) 2008 Karel Zak + * Copyright (C) 2013 Eric Sandeen * * 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, +};