diff options
author | Eric Sandeen | 2013-08-06 01:09:35 +0200 |
---|---|---|
committer | Karel Zak | 2013-09-11 10:29:33 +0200 |
commit | 0a2002551d65f73576cb4514fb052765d46cc8c5 (patch) | |
tree | e71af0f69682eaff4963200d6acece8ce603ffce /libblkid/src | |
parent | lib: rename time-util.c to timeutils.c, fix headers (diff) | |
download | kernel-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.c | 3 | ||||
-rw-r--r-- | libblkid/src/superblocks/superblocks.h | 1 | ||||
-rw-r--r-- | libblkid/src/superblocks/xfs.c | 86 |
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, +}; |