2 * Copyright (C) 1999 by Andries Brouwer
3 * Copyright (C) 1999, 2000, 2003 by Theodore Ts'o
4 * Copyright (C) 2001 by Andreas Dilger
5 * Copyright (C) 2004 Kay Sievers <kay.sievers@vrfy.org>
6 * Copyright (C) 2008 Karel Zak <kzak@redhat.com>
8 * This file may be redistributed under the terms of the
9 * GNU Lesser General Public License.
19 #define LVM1_ID_LEN 128
20 #define LVM2_ID_LEN 32
22 struct lvm2_pv_label_header {
24 uint8_t id[8]; /* LABELONE */
25 uint64_t sector_xl; /* Sector number of this label */
26 uint32_t crc_xl; /* From next field to end of sector */
27 uint32_t offset_xl; /* Offset from start of struct to contents */
28 uint8_t type[8]; /* LVM2 001 */
30 uint8_t pv_uuid[LVM2_ID_LEN];
31 } __attribute__ ((packed));
33 struct lvm1_pv_label_header {
34 uint8_t id[2]; /* HM */
35 uint16_t version; /* version 1 or 2 */
36 uint32_t _notused[10]; /* lvm1 internals */
37 uint8_t pv_uuid[LVM1_ID_LEN];
38 } __attribute__ ((packed));
40 #define LVM2_LABEL_SIZE 512
41 static unsigned int lvm2_calc_crc(const void *buf, unsigned int size)
43 static const unsigned int crctab[] = {
44 0x00000000, 0x1db71064, 0x3b6e20c8, 0x26d930ac,
45 0x76dc4190, 0x6b6b51f4, 0x4db26158, 0x5005713c,
46 0xedb88320, 0xf00f9344, 0xd6d6a3e8, 0xcb61b38c,
47 0x9b64c2b0, 0x86d3d2d4, 0xa00ae278, 0xbdbdf21c
49 unsigned int i, crc = 0xf597a6cf;
50 const uint8_t *data = (const uint8_t *) buf;
52 for (i = 0; i < size; i++) {
54 crc = (crc >> 4) ^ crctab[crc & 0xf];
55 crc = (crc >> 4) ^ crctab[crc & 0xf];
60 /* Length of real UUID is always LVM2_ID_LEN */
61 static void format_lvm_uuid(char *dst_uuid, char *src_uuid)
65 for (i = 0, b = 1; i < LVM2_ID_LEN; i++, b <<= 1) {
68 *dst_uuid++ = *src_uuid++;
73 static int probe_lvm2(blkid_probe pr, const struct blkid_idmag *mag)
75 int sector = mag->kboff << 1;
76 struct lvm2_pv_label_header *label;
77 char uuid[LVM2_ID_LEN + 7];
80 buf = blkid_probe_get_buffer(pr,
82 512 + sizeof(struct lvm2_pv_label_header));
86 /* buf is at 0k or 1k offset; find label inside */
87 if (memcmp(buf, "LABELONE", 8) == 0) {
88 label = (struct lvm2_pv_label_header *) buf;
89 } else if (memcmp(buf + 512, "LABELONE", 8) == 0) {
90 label = (struct lvm2_pv_label_header *)(buf + 512);
96 if (le64_to_cpu(label->sector_xl) != (unsigned) sector)
99 if (lvm2_calc_crc(&label->offset_xl, LVM2_LABEL_SIZE -
100 ((char *) &label->offset_xl - (char *) label)) !=
101 le32_to_cpu(label->crc_xl)) {
103 printf("LVM2: label checksum incorrect at sector %d\n",
108 format_lvm_uuid(uuid, (char *) label->pv_uuid);
109 blkid_probe_sprintf_uuid(pr, label->pv_uuid, sizeof(label->pv_uuid),
112 /* the mag->magic is the same string as label->type,
113 * but zero terminated */
114 blkid_probe_set_version(pr, mag->magic);
118 static int probe_lvm1(blkid_probe pr, const struct blkid_idmag *mag)
120 struct lvm1_pv_label_header *label;
121 char uuid[LVM2_ID_LEN + 7];
122 unsigned int version;
124 label = blkid_probe_get_sb(pr, mag, struct lvm1_pv_label_header);
128 version = le16_to_cpu(label->version);
129 if (version != 1 && version != 2)
132 format_lvm_uuid(uuid, (char *) label->pv_uuid);
133 blkid_probe_sprintf_uuid(pr, label->pv_uuid, sizeof(label->pv_uuid),
139 /* NOTE: the original libblkid uses "lvm2pv" as a name */
140 const struct blkid_idinfo lvm2_idinfo =
142 .name = "LVM2_member",
143 .usage = BLKID_USAGE_RAID,
144 .probefunc = probe_lvm2,
147 { .magic = "LVM2 001", .len = 8, .sboff = 0x218 },
148 { .magic = "LVM2 001", .len = 8, .sboff = 0x018 },
149 { .magic = "LVM2 001", .len = 8, .kboff = 1, .sboff = 0x018 },
150 { .magic = "LVM2 001", .len = 8, .kboff = 1, .sboff = 0x218 },
155 const struct blkid_idinfo lvm1_idinfo =
157 .name = "LVM1_member",
158 .usage = BLKID_USAGE_RAID,
159 .probefunc = probe_lvm1,
162 { .magic = "HM", .len = 2 },
167 const struct blkid_idinfo snapcow_idinfo =
169 .name = "DM_snapshot_cow",
170 .usage = BLKID_USAGE_OTHER,
173 { .magic = "SnAp", .len = 4 },