2
* Copyright (C) 2009-2010 by Andreas Dilger <adilger@sun.com>
4
* This file may be redistributed under the terms of the
5
* GNU Lesser General Public License.
16
#include "superblocks.h"
18
#define VDEV_LABEL_UBERBLOCK (128 * 1024ULL)
19
#define VDEV_LABEL_NVPAIR ( 16 * 1024ULL)
20
#define VDEV_LABEL_SIZE (256 * 1024ULL)
22
/* #include <sys/uberblock_impl.h> */
23
#define UBERBLOCK_MAGIC 0x00bab10c /* oo-ba-bloc! */
24
struct zfs_uberblock {
25
uint64_t ub_magic; /* UBERBLOCK_MAGIC */
26
uint64_t ub_version; /* SPA_VERSION */
27
uint64_t ub_txg; /* txg of last sync */
28
uint64_t ub_guid_sum; /* sum of all vdev guids */
29
uint64_t ub_timestamp; /* UTC time of last sync */
30
char ub_rootbp; /* MOS objset_phys_t */
31
} __attribute__((packed));
36
#define DATA_TYPE_UINT64 8
37
#define DATA_TYPE_STRING 9
43
char nvp_name[0]; /* aligned to 4 bytes */
44
/* aligned ptr array for string arrays */
45
/* aligned array of data for value */
52
unsigned char nvs_string[0];
62
uint32_t nvl_unknown[3];
63
struct nvpair nvl_nvpair;
66
#define nvdebug(fmt, ...) do { } while(0)
67
/*#define nvdebug(fmt, a...) printf(fmt, ##a)*/
69
static void zfs_extract_guid_name(blkid_probe pr, loff_t offset)
76
offset = (offset & ~(VDEV_LABEL_SIZE - 1)) + VDEV_LABEL_NVPAIR;
78
/* Note that we currently assume that the desired fields are within
79
* the first 4k (left) of the nvlist. This is true for all pools
80
* I've seen, and simplifies this code somewhat, because we don't
81
* have to handle an nvpair crossing a buffer boundary. */
82
nvl = (struct nvlist *)blkid_probe_get_buffer(pr, offset, left);
86
nvdebug("zfs_extract: nvlist offset %llu\n", offset);
88
nvp = &nvl->nvl_nvpair;
89
while (left > sizeof(*nvp) && nvp->nvp_size != 0 && found < 3) {
90
int avail; /* tracks that name/value data fits in nvp_size */
93
nvp->nvp_size = be32_to_cpu(nvp->nvp_size);
94
nvp->nvp_namelen = be32_to_cpu(nvp->nvp_namelen);
95
avail = nvp->nvp_size - nvp->nvp_namelen - sizeof(*nvp);
97
nvdebug("left %zd nvp_size %u\n", left, nvp->nvp_size);
98
if (left < nvp->nvp_size || avail < 0)
101
namesize = (nvp->nvp_namelen + 3) & ~3;
103
nvdebug("nvlist: size %u, namelen %u, name %*s\n",
104
nvp->nvp_size, nvp->nvp_namelen, nvp->nvp_namelen,
106
if (strncmp(nvp->nvp_name, "name", nvp->nvp_namelen) == 0) {
107
struct nvstring *nvs = (void *)(nvp->nvp_name+namesize);
109
nvs->nvs_type = be32_to_cpu(nvs->nvs_type);
110
nvs->nvs_strlen = be32_to_cpu(nvs->nvs_strlen);
111
avail -= nvs->nvs_strlen + sizeof(*nvs);
112
nvdebug("nvstring: type %u string %*s\n", nvs->nvs_type,
113
nvs->nvs_strlen, nvs->nvs_string);
114
if (nvs->nvs_type == DATA_TYPE_STRING && avail >= 0)
115
blkid_probe_set_label(pr, nvs->nvs_string,
118
} else if (strncmp(nvp->nvp_name, "guid",
119
nvp->nvp_namelen) == 0) {
120
struct nvuint64 *nvu = (void *)(nvp->nvp_name+namesize);
123
memcpy(&nvu_value, &nvu->nvu_value, sizeof(nvu_value));
124
nvu->nvu_type = be32_to_cpu(nvu->nvu_type);
125
nvu_value = be64_to_cpu(nvu_value);
126
avail -= sizeof(*nvu);
127
nvdebug("nvuint64: type %u value %"PRIu64"\n",
128
nvu->nvu_type, nvu_value);
129
if (nvu->nvu_type == DATA_TYPE_UINT64 && avail >= 0)
130
blkid_probe_sprintf_value(pr, "UUID_SUB",
131
"%"PRIu64, nvu_value);
133
} else if (strncmp(nvp->nvp_name, "pool_guid",
134
nvp->nvp_namelen) == 0) {
135
struct nvuint64 *nvu = (void *)(nvp->nvp_name+namesize);
138
memcpy(&nvu_value, &nvu->nvu_value, sizeof(nvu_value));
139
nvu->nvu_type = be32_to_cpu(nvu->nvu_type);
140
nvu_value = be64_to_cpu(nvu_value);
141
avail -= sizeof(*nvu);
142
nvdebug("nvuint64: type %u value %"PRIu64"\n",
143
nvu->nvu_type, nvu_value);
144
if (nvu->nvu_type == DATA_TYPE_UINT64 && avail >= 0)
145
blkid_probe_sprintf_uuid(pr, (unsigned char *)
148
"%"PRIu64, nvu_value);
151
if (left > nvp->nvp_size)
152
left -= nvp->nvp_size;
155
nvp = (struct nvpair *)((char *)nvp + nvp->nvp_size);
159
#define zdebug(fmt, ...) do {} while(0)
160
/*#define zdebug(fmt, a...) printf(fmt, ##a)*/
162
/* ZFS has 128x1kB host-endian root blocks, stored in 2 areas at the start
163
* of the disk, and 2 areas at the end of the disk. Check only some of them...
164
* #4 (@ 132kB) is the first one written on a new filesystem. */
165
static int probe_zfs(blkid_probe pr,
166
const struct blkid_idmag *mag __attribute__((__unused__)))
168
uint64_t swab_magic = swab64(UBERBLOCK_MAGIC);
169
struct zfs_uberblock *ub;
175
zdebug("probe_zfs\n");
176
/* Look for at least 4 uberblocks to ensure a positive match */
177
for (tried = found = 0, offset = VDEV_LABEL_UBERBLOCK;
178
tried < ZFS_TRIES && found < ZFS_WANT;
179
tried++, offset += 4096) {
180
/* also try the second uberblock copy */
181
if (tried == (ZFS_TRIES / 2))
182
offset = VDEV_LABEL_SIZE + VDEV_LABEL_UBERBLOCK;
184
ub = (struct zfs_uberblock *)
185
blkid_probe_get_buffer(pr, offset,
186
sizeof(struct zfs_uberblock));
190
if (ub->ub_magic == UBERBLOCK_MAGIC)
193
if ((swab_endian = (ub->ub_magic == swab_magic)))
196
zdebug("probe_zfs: found %s-endian uberblock at %llu\n",
197
swab_endian ? "big" : "little", offset >> 10);
203
/* If we found the 4th uberblock, then we will have exited from the
204
* scanning loop immediately, and ub will be a valid uberblock. */
205
blkid_probe_sprintf_version(pr, "%" PRIu64, swab_endian ?
206
swab64(ub->ub_version) : ub->ub_version);
208
zfs_extract_guid_name(pr, offset);
210
if (blkid_probe_set_magic(pr, offset,
211
sizeof(ub->ub_magic),
212
(unsigned char *) &ub->ub_magic))
218
const struct blkid_idinfo zfs_idinfo =
220
.name = "zfs_member",
221
.usage = BLKID_USAGE_RAID,
222
.probefunc = probe_zfs,
223
.minsz = 64 * 1024 * 1024,
224
.magics = BLKID_NONE_MAGIC