1cbe94e17SToomas Soome /*
2199767f8SToomas Soome * Copyright (c) 2007 Doug Rabson
3199767f8SToomas Soome * All rights reserved.
4199767f8SToomas Soome *
5199767f8SToomas Soome * Redistribution and use in source and binary forms, with or without
6199767f8SToomas Soome * modification, are permitted provided that the following conditions
7199767f8SToomas Soome * are met:
8199767f8SToomas Soome * 1. Redistributions of source code must retain the above copyright
9199767f8SToomas Soome * notice, this list of conditions and the following disclaimer.
10199767f8SToomas Soome * 2. Redistributions in binary form must reproduce the above copyright
11199767f8SToomas Soome * notice, this list of conditions and the following disclaimer in the
12199767f8SToomas Soome * documentation and/or other materials provided with the distribution.
13199767f8SToomas Soome *
14199767f8SToomas Soome * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND
15199767f8SToomas Soome * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
16199767f8SToomas Soome * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
17199767f8SToomas Soome * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE
18199767f8SToomas Soome * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
19199767f8SToomas Soome * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
20199767f8SToomas Soome * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
21199767f8SToomas Soome * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
22199767f8SToomas Soome * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
23199767f8SToomas Soome * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
24199767f8SToomas Soome * SUCH DAMAGE.
25199767f8SToomas Soome */
26199767f8SToomas Soome
27199767f8SToomas Soome #include <sys/cdefs.h>
28199767f8SToomas Soome
29199767f8SToomas Soome /*
30199767f8SToomas Soome * Stand-alone file reading package.
31199767f8SToomas Soome */
32199767f8SToomas Soome
33781f142dSToomas Soome #include <stand.h>
34199767f8SToomas Soome #include <sys/disk.h>
35199767f8SToomas Soome #include <sys/param.h>
36199767f8SToomas Soome #include <sys/time.h>
37199767f8SToomas Soome #include <sys/queue.h>
38781f142dSToomas Soome #include <disk.h>
39199767f8SToomas Soome #include <part.h>
40199767f8SToomas Soome #include <stddef.h>
41199767f8SToomas Soome #include <stdarg.h>
42199767f8SToomas Soome #include <string.h>
43199767f8SToomas Soome #include <bootstrap.h>
44f6dea603SToomas Soome #include <inttypes.h>
45199767f8SToomas Soome
46199767f8SToomas Soome #include "libzfs.h"
47199767f8SToomas Soome
48199767f8SToomas Soome #include "zfsimpl.c"
49199767f8SToomas Soome
50199767f8SToomas Soome /* Define the range of indexes to be populated with ZFS Boot Environments */
51199767f8SToomas Soome #define ZFS_BE_FIRST 4
52199767f8SToomas Soome #define ZFS_BE_LAST 8
53199767f8SToomas Soome
54fec66293SToomas Soome static int zfs_open(const char *, struct open_file *);
55fec66293SToomas Soome static int zfs_close(struct open_file *);
56fec66293SToomas Soome static int zfs_read(struct open_file *, void *, size_t, size_t *);
57fec66293SToomas Soome static off_t zfs_seek(struct open_file *, off_t, int);
58fec66293SToomas Soome static int zfs_stat(struct open_file *, struct stat *);
59fec66293SToomas Soome static int zfs_readdir(struct open_file *, struct dirent *);
60199767f8SToomas Soome
61199767f8SToomas Soome struct devsw zfs_dev;
62199767f8SToomas Soome
63199767f8SToomas Soome struct fs_ops zfs_fsops = {
64199767f8SToomas Soome "zfs",
65199767f8SToomas Soome zfs_open,
66199767f8SToomas Soome zfs_close,
67199767f8SToomas Soome zfs_read,
68cf837ed8SToomas Soome null_write,
69199767f8SToomas Soome zfs_seek,
70199767f8SToomas Soome zfs_stat,
71199767f8SToomas Soome zfs_readdir
72199767f8SToomas Soome };
73199767f8SToomas Soome
74199767f8SToomas Soome /*
75199767f8SToomas Soome * In-core open file.
76199767f8SToomas Soome */
77199767f8SToomas Soome struct file {
78199767f8SToomas Soome off_t f_seekp; /* seek pointer */
79199767f8SToomas Soome dnode_phys_t f_dnode;
80199767f8SToomas Soome uint64_t f_zap_type; /* zap type for readdir */
81199767f8SToomas Soome uint64_t f_num_leafs; /* number of fzap leaf blocks */
82199767f8SToomas Soome zap_leaf_phys_t *f_zap_leaf; /* zap leaf buffer */
83199767f8SToomas Soome };
84199767f8SToomas Soome
85fec66293SToomas Soome SLIST_HEAD(zfs_be_list, zfs_be_entry) zfs_be_head =
86fec66293SToomas Soome SLIST_HEAD_INITIALIZER(zfs_be_head);
87199767f8SToomas Soome struct zfs_be_list *zfs_be_headp;
88199767f8SToomas Soome struct zfs_be_entry {
89199767f8SToomas Soome const char *name;
90199767f8SToomas Soome SLIST_ENTRY(zfs_be_entry) entries;
91199767f8SToomas Soome } *zfs_be, *zfs_be_tmp;
92199767f8SToomas Soome
93199767f8SToomas Soome /*
94199767f8SToomas Soome * Open a file.
95199767f8SToomas Soome */
96199767f8SToomas Soome static int
zfs_open(const char * upath,struct open_file * f)97199767f8SToomas Soome zfs_open(const char *upath, struct open_file *f)
98199767f8SToomas Soome {
99199767f8SToomas Soome struct zfsmount *mount = (struct zfsmount *)f->f_devdata;
100199767f8SToomas Soome struct file *fp;
101199767f8SToomas Soome int rc;
102199767f8SToomas Soome
103199767f8SToomas Soome if (f->f_dev != &zfs_dev)
104199767f8SToomas Soome return (EINVAL);
105199767f8SToomas Soome
106199767f8SToomas Soome /* allocate file system specific data structure */
107777db879SToomas Soome fp = calloc(1, sizeof (struct file));
108777db879SToomas Soome if (fp == NULL)
109777db879SToomas Soome return (ENOMEM);
110777db879SToomas Soome f->f_fsdata = fp;
111199767f8SToomas Soome
112199767f8SToomas Soome rc = zfs_lookup(mount, upath, &fp->f_dnode);
113199767f8SToomas Soome fp->f_seekp = 0;
114199767f8SToomas Soome if (rc) {
115199767f8SToomas Soome f->f_fsdata = NULL;
116199767f8SToomas Soome free(fp);
117199767f8SToomas Soome }
118199767f8SToomas Soome return (rc);
119199767f8SToomas Soome }
120199767f8SToomas Soome
121199767f8SToomas Soome static int
zfs_close(struct open_file * f)122199767f8SToomas Soome zfs_close(struct open_file *f)
123199767f8SToomas Soome {
124199767f8SToomas Soome struct file *fp = (struct file *)f->f_fsdata;
125199767f8SToomas Soome
126b713c91eSToomas Soome dnode_cache_obj = NULL;
127777db879SToomas Soome f->f_fsdata = NULL;
128199767f8SToomas Soome
129199767f8SToomas Soome free(fp);
130199767f8SToomas Soome return (0);
131199767f8SToomas Soome }
132199767f8SToomas Soome
133199767f8SToomas Soome /*
134199767f8SToomas Soome * Copy a portion of a file into kernel memory.
135199767f8SToomas Soome * Cross block boundaries when necessary.
136199767f8SToomas Soome */
137199767f8SToomas Soome static int
zfs_read(struct open_file * f,void * start,size_t size,size_t * resid)138fec66293SToomas Soome zfs_read(struct open_file *f, void *start, size_t size, size_t *resid)
139199767f8SToomas Soome {
140199767f8SToomas Soome const spa_t *spa = ((struct zfsmount *)f->f_devdata)->spa;
141199767f8SToomas Soome struct file *fp = (struct file *)f->f_fsdata;
142199767f8SToomas Soome struct stat sb;
143199767f8SToomas Soome size_t n;
144199767f8SToomas Soome int rc;
145199767f8SToomas Soome
146199767f8SToomas Soome rc = zfs_stat(f, &sb);
147199767f8SToomas Soome if (rc)
148199767f8SToomas Soome return (rc);
149199767f8SToomas Soome n = size;
150199767f8SToomas Soome if (fp->f_seekp + n > sb.st_size)
151199767f8SToomas Soome n = sb.st_size - fp->f_seekp;
152199767f8SToomas Soome
153199767f8SToomas Soome rc = dnode_read(spa, &fp->f_dnode, fp->f_seekp, start, n);
154199767f8SToomas Soome if (rc)
155199767f8SToomas Soome return (rc);
156199767f8SToomas Soome
157199767f8SToomas Soome fp->f_seekp += n;
158199767f8SToomas Soome if (resid)
159199767f8SToomas Soome *resid = size - n;
160199767f8SToomas Soome
161199767f8SToomas Soome return (0);
162199767f8SToomas Soome }
163199767f8SToomas Soome
164199767f8SToomas Soome static off_t
zfs_seek(struct open_file * f,off_t offset,int where)165199767f8SToomas Soome zfs_seek(struct open_file *f, off_t offset, int where)
166199767f8SToomas Soome {
167199767f8SToomas Soome struct file *fp = (struct file *)f->f_fsdata;
168fec66293SToomas Soome struct stat sb;
169fec66293SToomas Soome int error;
170fec66293SToomas Soome
171199767f8SToomas Soome switch (where) {
172199767f8SToomas Soome case SEEK_SET:
173199767f8SToomas Soome fp->f_seekp = offset;
174199767f8SToomas Soome break;
175199767f8SToomas Soome case SEEK_CUR:
176199767f8SToomas Soome fp->f_seekp += offset;
177199767f8SToomas Soome break;
178199767f8SToomas Soome case SEEK_END:
179199767f8SToomas Soome error = zfs_stat(f, &sb);
180199767f8SToomas Soome if (error != 0) {
181199767f8SToomas Soome errno = error;
182199767f8SToomas Soome return (-1);
183199767f8SToomas Soome }
184199767f8SToomas Soome fp->f_seekp = sb.st_size - offset;
185199767f8SToomas Soome break;
186199767f8SToomas Soome default:
187199767f8SToomas Soome errno = EINVAL;
188199767f8SToomas Soome return (-1);
189199767f8SToomas Soome }
190199767f8SToomas Soome return (fp->f_seekp);
191199767f8SToomas Soome }
192199767f8SToomas Soome
193199767f8SToomas Soome static int
zfs_stat(struct open_file * f,struct stat * sb)194199767f8SToomas Soome zfs_stat(struct open_file *f, struct stat *sb)
195199767f8SToomas Soome {
196199767f8SToomas Soome const spa_t *spa = ((struct zfsmount *)f->f_devdata)->spa;
197199767f8SToomas Soome struct file *fp = (struct file *)f->f_fsdata;
198199767f8SToomas Soome
199199767f8SToomas Soome return (zfs_dnode_stat(spa, &fp->f_dnode, sb));
200199767f8SToomas Soome }
201199767f8SToomas Soome
202199767f8SToomas Soome static int
zfs_readdir(struct open_file * f,struct dirent * d)203199767f8SToomas Soome zfs_readdir(struct open_file *f, struct dirent *d)
204199767f8SToomas Soome {
205199767f8SToomas Soome const spa_t *spa = ((struct zfsmount *)f->f_devdata)->spa;
206199767f8SToomas Soome struct file *fp = (struct file *)f->f_fsdata;
207199767f8SToomas Soome mzap_ent_phys_t mze;
208199767f8SToomas Soome struct stat sb;
209199767f8SToomas Soome size_t bsize = fp->f_dnode.dn_datablkszsec << SPA_MINBLOCKSHIFT;
210199767f8SToomas Soome int rc;
211199767f8SToomas Soome
212199767f8SToomas Soome rc = zfs_stat(f, &sb);
213199767f8SToomas Soome if (rc)
214199767f8SToomas Soome return (rc);
215199767f8SToomas Soome if (!S_ISDIR(sb.st_mode))
216199767f8SToomas Soome return (ENOTDIR);
217199767f8SToomas Soome
218199767f8SToomas Soome /*
219199767f8SToomas Soome * If this is the first read, get the zap type.
220199767f8SToomas Soome */
221199767f8SToomas Soome if (fp->f_seekp == 0) {
222fec66293SToomas Soome rc = dnode_read(spa, &fp->f_dnode, 0, &fp->f_zap_type,
223fec66293SToomas Soome sizeof (fp->f_zap_type));
224199767f8SToomas Soome if (rc)
225199767f8SToomas Soome return (rc);
226199767f8SToomas Soome
227199767f8SToomas Soome if (fp->f_zap_type == ZBT_MICRO) {
228199767f8SToomas Soome fp->f_seekp = offsetof(mzap_phys_t, mz_chunk);
229199767f8SToomas Soome } else {
230199767f8SToomas Soome rc = dnode_read(spa, &fp->f_dnode,
231fec66293SToomas Soome offsetof(zap_phys_t, zap_num_leafs),
232fec66293SToomas Soome &fp->f_num_leafs, sizeof (fp->f_num_leafs));
233199767f8SToomas Soome if (rc)
234199767f8SToomas Soome return (rc);
235199767f8SToomas Soome
236199767f8SToomas Soome fp->f_seekp = bsize;
237777db879SToomas Soome fp->f_zap_leaf = malloc(bsize);
238777db879SToomas Soome if (fp->f_zap_leaf == NULL)
239777db879SToomas Soome return (ENOMEM);
240fec66293SToomas Soome rc = dnode_read(spa, &fp->f_dnode, fp->f_seekp,
241fec66293SToomas Soome fp->f_zap_leaf, bsize);
242199767f8SToomas Soome if (rc)
243199767f8SToomas Soome return (rc);
244199767f8SToomas Soome }
245199767f8SToomas Soome }
246199767f8SToomas Soome
247199767f8SToomas Soome if (fp->f_zap_type == ZBT_MICRO) {
248199767f8SToomas Soome mzap_next:
249199767f8SToomas Soome if (fp->f_seekp >= bsize)
250199767f8SToomas Soome return (ENOENT);
251199767f8SToomas Soome
252fec66293SToomas Soome rc = dnode_read(spa, &fp->f_dnode, fp->f_seekp, &mze,
253fec66293SToomas Soome sizeof (mze));
254199767f8SToomas Soome if (rc)
255199767f8SToomas Soome return (rc);
256fec66293SToomas Soome fp->f_seekp += sizeof (mze);
257199767f8SToomas Soome
258199767f8SToomas Soome if (!mze.mze_name[0])
259199767f8SToomas Soome goto mzap_next;
260199767f8SToomas Soome
261199767f8SToomas Soome d->d_fileno = ZFS_DIRENT_OBJ(mze.mze_value);
262199767f8SToomas Soome d->d_type = ZFS_DIRENT_TYPE(mze.mze_value);
263199767f8SToomas Soome strcpy(d->d_name, mze.mze_name);
264199767f8SToomas Soome d->d_namlen = strlen(d->d_name);
265199767f8SToomas Soome return (0);
266199767f8SToomas Soome } else {
267199767f8SToomas Soome zap_leaf_t zl;
268199767f8SToomas Soome zap_leaf_chunk_t *zc, *nc;
269199767f8SToomas Soome int chunk;
270199767f8SToomas Soome size_t namelen;
271199767f8SToomas Soome char *p;
272199767f8SToomas Soome uint64_t value;
273199767f8SToomas Soome
274199767f8SToomas Soome /*
275199767f8SToomas Soome * Initialise this so we can use the ZAP size
276199767f8SToomas Soome * calculating macros.
277199767f8SToomas Soome */
278199767f8SToomas Soome zl.l_bs = ilog2(bsize);
279199767f8SToomas Soome zl.l_phys = fp->f_zap_leaf;
280199767f8SToomas Soome
281199767f8SToomas Soome /*
282199767f8SToomas Soome * Figure out which chunk we are currently looking at
283199767f8SToomas Soome * and consider seeking to the next leaf. We use the
284199767f8SToomas Soome * low bits of f_seekp as a simple chunk index.
285199767f8SToomas Soome */
286199767f8SToomas Soome fzap_next:
287199767f8SToomas Soome chunk = fp->f_seekp & (bsize - 1);
288199767f8SToomas Soome if (chunk == ZAP_LEAF_NUMCHUNKS(&zl)) {
289199767f8SToomas Soome fp->f_seekp = (fp->f_seekp & ~(bsize - 1)) + bsize;
290199767f8SToomas Soome chunk = 0;
291199767f8SToomas Soome
292199767f8SToomas Soome /*
293199767f8SToomas Soome * Check for EOF and read the new leaf.
294199767f8SToomas Soome */
295199767f8SToomas Soome if (fp->f_seekp >= bsize * fp->f_num_leafs)
296199767f8SToomas Soome return (ENOENT);
297199767f8SToomas Soome
298fec66293SToomas Soome rc = dnode_read(spa, &fp->f_dnode, fp->f_seekp,
299fec66293SToomas Soome fp->f_zap_leaf, bsize);
300199767f8SToomas Soome if (rc)
301199767f8SToomas Soome return (rc);
302199767f8SToomas Soome }
303199767f8SToomas Soome
304199767f8SToomas Soome zc = &ZAP_LEAF_CHUNK(&zl, chunk);
305199767f8SToomas Soome fp->f_seekp++;
306199767f8SToomas Soome if (zc->l_entry.le_type != ZAP_CHUNK_ENTRY)
307199767f8SToomas Soome goto fzap_next;
308199767f8SToomas Soome
309199767f8SToomas Soome namelen = zc->l_entry.le_name_numints;
310fec66293SToomas Soome if (namelen > sizeof (d->d_name))
311fec66293SToomas Soome namelen = sizeof (d->d_name);
312199767f8SToomas Soome
313199767f8SToomas Soome /*
314199767f8SToomas Soome * Paste the name back together.
315199767f8SToomas Soome */
316199767f8SToomas Soome nc = &ZAP_LEAF_CHUNK(&zl, zc->l_entry.le_name_chunk);
317199767f8SToomas Soome p = d->d_name;
318199767f8SToomas Soome while (namelen > 0) {
319199767f8SToomas Soome int len;
320199767f8SToomas Soome len = namelen;
321199767f8SToomas Soome if (len > ZAP_LEAF_ARRAY_BYTES)
322199767f8SToomas Soome len = ZAP_LEAF_ARRAY_BYTES;
323199767f8SToomas Soome memcpy(p, nc->l_array.la_array, len);
324199767f8SToomas Soome p += len;
325199767f8SToomas Soome namelen -= len;
326199767f8SToomas Soome nc = &ZAP_LEAF_CHUNK(&zl, nc->l_array.la_next);
327199767f8SToomas Soome }
328fec66293SToomas Soome d->d_name[sizeof (d->d_name) - 1] = 0;
329199767f8SToomas Soome
330199767f8SToomas Soome /*
331199767f8SToomas Soome * Assume the first eight bytes of the value are
332199767f8SToomas Soome * a uint64_t.
333199767f8SToomas Soome */
334199767f8SToomas Soome value = fzap_leaf_value(&zl, zc);
335199767f8SToomas Soome
336199767f8SToomas Soome d->d_fileno = ZFS_DIRENT_OBJ(value);
337199767f8SToomas Soome d->d_type = ZFS_DIRENT_TYPE(value);
338199767f8SToomas Soome d->d_namlen = strlen(d->d_name);
339199767f8SToomas Soome
340199767f8SToomas Soome return (0);
341199767f8SToomas Soome }
342199767f8SToomas Soome }
343199767f8SToomas Soome
344199767f8SToomas Soome static int
vdev_read(vdev_t * vdev __unused,void * priv,off_t offset,void * buf,size_t bytes)3458eef2ab6SToomas Soome vdev_read(vdev_t *vdev __unused, void *priv, off_t offset, void *buf,
3468eef2ab6SToomas Soome size_t bytes)
347199767f8SToomas Soome {
348cbe94e17SToomas Soome int fd, ret;
349cb09bd3cSToomas Soome size_t res, head, tail, total_size, full_sec_size;
350cb09bd3cSToomas Soome unsigned secsz, do_tail_read;
351cb09bd3cSToomas Soome off_t start_sec;
352cb09bd3cSToomas Soome char *outbuf, *bouncebuf;
353199767f8SToomas Soome
354fec66293SToomas Soome fd = (uintptr_t)priv;
355cb09bd3cSToomas Soome outbuf = (char *)buf;
356cbe94e17SToomas Soome bouncebuf = NULL;
357cbe94e17SToomas Soome
358cbe94e17SToomas Soome ret = ioctl(fd, DIOCGSECTORSIZE, &secsz);
359cbe94e17SToomas Soome if (ret != 0)
360cbe94e17SToomas Soome return (ret);
361cbe94e17SToomas Soome
362b713c91eSToomas Soome /* BEGIN CSTYLED */
363cb09bd3cSToomas Soome /*
364cb09bd3cSToomas Soome * Handling reads of arbitrary offset and size - multi-sector case
365cb09bd3cSToomas Soome * and single-sector case.
366cb09bd3cSToomas Soome *
367cb09bd3cSToomas Soome * Multi-sector Case
368cb09bd3cSToomas Soome * (do_tail_read = true if tail > 0)
369cb09bd3cSToomas Soome *
370cb09bd3cSToomas Soome * |<----------------------total_size--------------------->|
371cb09bd3cSToomas Soome * | |
372cb09bd3cSToomas Soome * |<--head-->|<--------------bytes------------>|<--tail-->|
373cb09bd3cSToomas Soome * | | | |
374cb09bd3cSToomas Soome * | | |<~full_sec_size~>| | |
375cb09bd3cSToomas Soome * +------------------+ +------------------+
376cb09bd3cSToomas Soome * | |0101010| . . . |0101011| |
377cb09bd3cSToomas Soome * +------------------+ +------------------+
378cb09bd3cSToomas Soome * start_sec start_sec + n
379cb09bd3cSToomas Soome *
380cb09bd3cSToomas Soome *
381cb09bd3cSToomas Soome * Single-sector Case
382cb09bd3cSToomas Soome * (do_tail_read = false)
383cb09bd3cSToomas Soome *
384cb09bd3cSToomas Soome * |<------total_size = secsz----->|
385cb09bd3cSToomas Soome * | |
386cb09bd3cSToomas Soome * |<-head->|<---bytes--->|<-tail->|
387cb09bd3cSToomas Soome * +-------------------------------+
388cb09bd3cSToomas Soome * | |0101010101010| |
389cb09bd3cSToomas Soome * +-------------------------------+
390cb09bd3cSToomas Soome * start_sec
391cb09bd3cSToomas Soome */
392b713c91eSToomas Soome /* END CSTYLED */
393cb09bd3cSToomas Soome start_sec = offset / secsz;
394cb09bd3cSToomas Soome head = offset % secsz;
395cb09bd3cSToomas Soome total_size = roundup2(head + bytes, secsz);
396cb09bd3cSToomas Soome tail = total_size - (head + bytes);
397cb09bd3cSToomas Soome do_tail_read = ((tail > 0) && (head + bytes > secsz));
398cb09bd3cSToomas Soome full_sec_size = total_size;
399cb09bd3cSToomas Soome if (head > 0)
400cb09bd3cSToomas Soome full_sec_size -= secsz;
401cb09bd3cSToomas Soome if (do_tail_read)
402cb09bd3cSToomas Soome full_sec_size -= secsz;
403cb09bd3cSToomas Soome
404cb09bd3cSToomas Soome /* Return of partial sector data requires a bounce buffer. */
405cee39f3fSToomas Soome if ((head > 0) || do_tail_read || bytes < secsz) {
406cb09bd3cSToomas Soome bouncebuf = malloc(secsz);
407cbe94e17SToomas Soome if (bouncebuf == NULL) {
408cbe94e17SToomas Soome printf("vdev_read: out of memory\n");
409cbe94e17SToomas Soome return (ENOMEM);
410cbe94e17SToomas Soome }
411199767f8SToomas Soome }
412cbe94e17SToomas Soome
413cb09bd3cSToomas Soome if (lseek(fd, start_sec * secsz, SEEK_SET) == -1) {
414cb09bd3cSToomas Soome ret = errno;
415cb09bd3cSToomas Soome goto error;
416cb09bd3cSToomas Soome }
417cb09bd3cSToomas Soome
418cb09bd3cSToomas Soome /* Partial data return from first sector */
419cb09bd3cSToomas Soome if (head > 0) {
420cb09bd3cSToomas Soome res = read(fd, bouncebuf, secsz);
421cb09bd3cSToomas Soome if (res != secsz) {
422cb09bd3cSToomas Soome ret = EIO;
423cb09bd3cSToomas Soome goto error;
424cb09bd3cSToomas Soome }
425cb09bd3cSToomas Soome memcpy(outbuf, bouncebuf + head, min(secsz - head, bytes));
426cb09bd3cSToomas Soome outbuf += min(secsz - head, bytes);
427cb09bd3cSToomas Soome }
428cb09bd3cSToomas Soome
429cb09bd3cSToomas Soome /* Full data return from read sectors */
430cb09bd3cSToomas Soome if (full_sec_size > 0) {
431cee39f3fSToomas Soome if (bytes < full_sec_size) {
432cee39f3fSToomas Soome res = read(fd, bouncebuf, secsz);
433cee39f3fSToomas Soome if (res != secsz) {
434cee39f3fSToomas Soome ret = EIO;
435cee39f3fSToomas Soome goto error;
436cee39f3fSToomas Soome }
437cee39f3fSToomas Soome memcpy(outbuf, bouncebuf, bytes);
438cee39f3fSToomas Soome } else {
439cee39f3fSToomas Soome res = read(fd, outbuf, full_sec_size);
440cee39f3fSToomas Soome if (res != full_sec_size) {
441cee39f3fSToomas Soome ret = EIO;
442cee39f3fSToomas Soome goto error;
443cee39f3fSToomas Soome }
444cee39f3fSToomas Soome outbuf += full_sec_size;
445cb09bd3cSToomas Soome }
446cb09bd3cSToomas Soome }
447cb09bd3cSToomas Soome
448cb09bd3cSToomas Soome /* Partial data return from last sector */
449cb09bd3cSToomas Soome if (do_tail_read) {
450cb09bd3cSToomas Soome res = read(fd, bouncebuf, secsz);
451cb09bd3cSToomas Soome if (res != secsz) {
452cbe94e17SToomas Soome ret = EIO;
453cbe94e17SToomas Soome goto error;
454cbe94e17SToomas Soome }
455cb09bd3cSToomas Soome memcpy(outbuf, bouncebuf, secsz - tail);
456cbe94e17SToomas Soome }
457cbe94e17SToomas Soome
458cbe94e17SToomas Soome ret = 0;
459cbe94e17SToomas Soome error:
460cb09bd3cSToomas Soome free(bouncebuf);
461cbe94e17SToomas Soome return (ret);
462199767f8SToomas Soome }
463199767f8SToomas Soome
464b713c91eSToomas Soome static int
vdev_write(vdev_t * vdev,off_t offset,void * buf,size_t bytes)465b713c91eSToomas Soome vdev_write(vdev_t *vdev, off_t offset, void *buf, size_t bytes)
466b713c91eSToomas Soome {
467b713c91eSToomas Soome int fd, ret;
468b713c91eSToomas Soome size_t head, tail, total_size, full_sec_size;
469b713c91eSToomas Soome unsigned secsz, do_tail_write;
470b713c91eSToomas Soome off_t start_sec;
471b713c91eSToomas Soome ssize_t res;
472b713c91eSToomas Soome char *outbuf, *bouncebuf;
473b713c91eSToomas Soome
474b713c91eSToomas Soome fd = (uintptr_t)vdev->v_priv;
475b713c91eSToomas Soome outbuf = (char *)buf;
476b713c91eSToomas Soome bouncebuf = NULL;
477b713c91eSToomas Soome
478b713c91eSToomas Soome ret = ioctl(fd, DIOCGSECTORSIZE, &secsz);
479b713c91eSToomas Soome if (ret != 0)
480b713c91eSToomas Soome return (ret);
481b713c91eSToomas Soome
482b713c91eSToomas Soome start_sec = offset / secsz;
483b713c91eSToomas Soome head = offset % secsz;
484b713c91eSToomas Soome total_size = roundup2(head + bytes, secsz);
485b713c91eSToomas Soome tail = total_size - (head + bytes);
486b713c91eSToomas Soome do_tail_write = ((tail > 0) && (head + bytes > secsz));
487b713c91eSToomas Soome full_sec_size = total_size;
488b713c91eSToomas Soome if (head > 0)
489b713c91eSToomas Soome full_sec_size -= secsz;
490b713c91eSToomas Soome if (do_tail_write)
491b713c91eSToomas Soome full_sec_size -= secsz;
492b713c91eSToomas Soome
493b713c91eSToomas Soome /* Partial sector write requires a bounce buffer. */
494b713c91eSToomas Soome if ((head > 0) || do_tail_write || bytes < secsz) {
495b713c91eSToomas Soome bouncebuf = malloc(secsz);
496b713c91eSToomas Soome if (bouncebuf == NULL) {
497b713c91eSToomas Soome printf("vdev_write: out of memory\n");
498b713c91eSToomas Soome return (ENOMEM);
499b713c91eSToomas Soome }
500b713c91eSToomas Soome }
501b713c91eSToomas Soome
502b713c91eSToomas Soome if (lseek(fd, start_sec * secsz, SEEK_SET) == -1) {
503b713c91eSToomas Soome ret = errno;
504b713c91eSToomas Soome goto error;
505b713c91eSToomas Soome }
506b713c91eSToomas Soome
507b713c91eSToomas Soome /* Partial data for first sector */
508b713c91eSToomas Soome if (head > 0) {
509b713c91eSToomas Soome res = read(fd, bouncebuf, secsz);
510b713c91eSToomas Soome if ((unsigned)res != secsz) {
511b713c91eSToomas Soome ret = EIO;
512b713c91eSToomas Soome goto error;
513b713c91eSToomas Soome }
514b713c91eSToomas Soome memcpy(bouncebuf + head, outbuf, min(secsz - head, bytes));
515b713c91eSToomas Soome (void) lseek(fd, -secsz, SEEK_CUR);
516b713c91eSToomas Soome res = write(fd, bouncebuf, secsz);
517b713c91eSToomas Soome if ((unsigned)res != secsz) {
518b713c91eSToomas Soome ret = EIO;
519b713c91eSToomas Soome goto error;
520b713c91eSToomas Soome }
521b713c91eSToomas Soome outbuf += min(secsz - head, bytes);
522b713c91eSToomas Soome }
523b713c91eSToomas Soome
524b713c91eSToomas Soome /*
525b713c91eSToomas Soome * Full data write to sectors.
526b713c91eSToomas Soome * Note, there is still corner case where we write
527b713c91eSToomas Soome * to sector boundary, but less than sector size, e.g. write 512B
528b713c91eSToomas Soome * to 4k sector.
529b713c91eSToomas Soome */
530b713c91eSToomas Soome if (full_sec_size > 0) {
531b713c91eSToomas Soome if (bytes < full_sec_size) {
532b713c91eSToomas Soome res = read(fd, bouncebuf, secsz);
533b713c91eSToomas Soome if ((unsigned)res != secsz) {
534b713c91eSToomas Soome ret = EIO;
535b713c91eSToomas Soome goto error;
536b713c91eSToomas Soome }
537b713c91eSToomas Soome memcpy(bouncebuf, outbuf, bytes);
538b713c91eSToomas Soome (void) lseek(fd, -secsz, SEEK_CUR);
539b713c91eSToomas Soome res = write(fd, bouncebuf, secsz);
540b713c91eSToomas Soome if ((unsigned)res != secsz) {
541b713c91eSToomas Soome ret = EIO;
542b713c91eSToomas Soome goto error;
543b713c91eSToomas Soome }
544b713c91eSToomas Soome } else {
545b713c91eSToomas Soome res = write(fd, outbuf, full_sec_size);
546b713c91eSToomas Soome if ((unsigned)res != full_sec_size) {
547b713c91eSToomas Soome ret = EIO;
548b713c91eSToomas Soome goto error;
549b713c91eSToomas Soome }
550b713c91eSToomas Soome outbuf += full_sec_size;
551b713c91eSToomas Soome }
552b713c91eSToomas Soome }
553b713c91eSToomas Soome
554b713c91eSToomas Soome /* Partial data write to last sector */
555b713c91eSToomas Soome if (do_tail_write) {
556b713c91eSToomas Soome res = read(fd, bouncebuf, secsz);
557b713c91eSToomas Soome if ((unsigned)res != secsz) {
558b713c91eSToomas Soome ret = EIO;
559b713c91eSToomas Soome goto error;
560b713c91eSToomas Soome }
561b713c91eSToomas Soome memcpy(bouncebuf, outbuf, secsz - tail);
562b713c91eSToomas Soome (void) lseek(fd, -secsz, SEEK_CUR);
563b713c91eSToomas Soome res = write(fd, bouncebuf, secsz);
564b713c91eSToomas Soome if ((unsigned)res != secsz) {
565b713c91eSToomas Soome ret = EIO;
566b713c91eSToomas Soome goto error;
567b713c91eSToomas Soome }
568b713c91eSToomas Soome }
569b713c91eSToomas Soome
570b713c91eSToomas Soome ret = 0;
571b713c91eSToomas Soome error:
572b713c91eSToomas Soome free(bouncebuf);
573b713c91eSToomas Soome return (ret);
574b713c91eSToomas Soome }
575b713c91eSToomas Soome
576199767f8SToomas Soome static int
zfs_dev_init(void)577199767f8SToomas Soome zfs_dev_init(void)
578199767f8SToomas Soome {
579199767f8SToomas Soome spa_t *spa;
580199767f8SToomas Soome spa_t *next;
581199767f8SToomas Soome spa_t *prev;
582199767f8SToomas Soome
583199767f8SToomas Soome zfs_init();
584199767f8SToomas Soome if (archsw.arch_zfs_probe == NULL)
585199767f8SToomas Soome return (ENXIO);
586199767f8SToomas Soome archsw.arch_zfs_probe();
587199767f8SToomas Soome
588199767f8SToomas Soome prev = NULL;
589199767f8SToomas Soome spa = STAILQ_FIRST(&zfs_pools);
590199767f8SToomas Soome while (spa != NULL) {
591199767f8SToomas Soome next = STAILQ_NEXT(spa, spa_link);
592199767f8SToomas Soome if (zfs_spa_init(spa)) {
593199767f8SToomas Soome if (prev == NULL)
594199767f8SToomas Soome STAILQ_REMOVE_HEAD(&zfs_pools, spa_link);
595199767f8SToomas Soome else
596199767f8SToomas Soome STAILQ_REMOVE_AFTER(&zfs_pools, prev, spa_link);
597199767f8SToomas Soome } else
598199767f8SToomas Soome prev = spa;
599199767f8SToomas Soome spa = next;
600199767f8SToomas Soome }
601199767f8SToomas Soome return (0);
602199767f8SToomas Soome }
603199767f8SToomas Soome
604199767f8SToomas Soome struct zfs_probe_args {
605199767f8SToomas Soome int fd;
606199767f8SToomas Soome const char *devname;
607199767f8SToomas Soome uint64_t *pool_guid;
608fec66293SToomas Soome unsigned secsz;
609199767f8SToomas Soome };
610199767f8SToomas Soome
611199767f8SToomas Soome static int
zfs_diskread(void * arg,void * buf,size_t blocks,uint64_t offset)61279bea51bSToomas Soome zfs_diskread(void *arg, void *buf, size_t blocks, uint64_t offset)
613199767f8SToomas Soome {
614199767f8SToomas Soome struct zfs_probe_args *ppa;
615199767f8SToomas Soome
616199767f8SToomas Soome ppa = (struct zfs_probe_args *)arg;
617199767f8SToomas Soome return (vdev_read(NULL, (void *)(uintptr_t)ppa->fd,
618199767f8SToomas Soome offset * ppa->secsz, buf, blocks * ppa->secsz));
619199767f8SToomas Soome }
620199767f8SToomas Soome
621199767f8SToomas Soome static int
zfs_probe(int fd,uint64_t * pool_guid)622199767f8SToomas Soome zfs_probe(int fd, uint64_t *pool_guid)
623199767f8SToomas Soome {
624199767f8SToomas Soome spa_t *spa;
625199767f8SToomas Soome int ret;
626199767f8SToomas Soome
627cd8e64e2SToomas Soome spa = NULL;
628b713c91eSToomas Soome ret = vdev_probe(vdev_read, vdev_write, (void *)(uintptr_t)fd, &spa);
629199767f8SToomas Soome if (ret == 0 && pool_guid != NULL)
630199767f8SToomas Soome *pool_guid = spa->spa_guid;
631199767f8SToomas Soome return (ret);
632199767f8SToomas Soome }
633199767f8SToomas Soome
634199767f8SToomas Soome static int
zfs_probe_partition(void * arg,const char * partname,const struct ptable_entry * part)635199767f8SToomas Soome zfs_probe_partition(void *arg, const char *partname,
636199767f8SToomas Soome const struct ptable_entry *part)
637199767f8SToomas Soome {
638199767f8SToomas Soome struct zfs_probe_args *ppa, pa;
639199767f8SToomas Soome struct ptable *table;
640199767f8SToomas Soome char devname[32];
641199767f8SToomas Soome int ret = 0;
642199767f8SToomas Soome
643199767f8SToomas Soome /* filter out partitions *not* used by zfs */
644199767f8SToomas Soome switch (part->type) {
645553cfb3fSToomas Soome case PART_EFI: /* efi system partition */
646199767f8SToomas Soome case PART_RESERVED: /* efi reserverd */
647199767f8SToomas Soome case PART_VTOC_BOOT: /* vtoc boot area */
648199767f8SToomas Soome case PART_VTOC_SWAP:
649199767f8SToomas Soome return (ret);
650199767f8SToomas Soome default:
65131898fe7SToomas Soome break;
652199767f8SToomas Soome }
653199767f8SToomas Soome ppa = (struct zfs_probe_args *)arg;
654199767f8SToomas Soome strncpy(devname, ppa->devname, strlen(ppa->devname) - 1);
655199767f8SToomas Soome devname[strlen(ppa->devname) - 1] = '\0';
656b713c91eSToomas Soome snprintf(devname, sizeof (devname), "%s%s:", devname, partname);
657b713c91eSToomas Soome pa.fd = open(devname, O_RDWR);
658199767f8SToomas Soome if (pa.fd == -1)
659199767f8SToomas Soome return (ret);
660199767f8SToomas Soome ret = zfs_probe(pa.fd, ppa->pool_guid);
661199767f8SToomas Soome if (ret == 0)
662199767f8SToomas Soome return (ret);
663199767f8SToomas Soome if (part->type == PART_SOLARIS2) {
664199767f8SToomas Soome pa.devname = devname;
665199767f8SToomas Soome pa.pool_guid = ppa->pool_guid;
666199767f8SToomas Soome pa.secsz = ppa->secsz;
667199767f8SToomas Soome table = ptable_open(&pa, part->end - part->start + 1,
668199767f8SToomas Soome ppa->secsz, zfs_diskread);
669199767f8SToomas Soome if (table != NULL) {
6701cfad7ceSToomas Soome enum ptable_type pt = ptable_gettype(table);
6711cfad7ceSToomas Soome
6721cfad7ceSToomas Soome if (pt == PTABLE_VTOC8 || pt == PTABLE_VTOC)
67331898fe7SToomas Soome ptable_iterate(table, &pa, zfs_probe_partition);
674199767f8SToomas Soome ptable_close(table);
675199767f8SToomas Soome }
676199767f8SToomas Soome }
677199767f8SToomas Soome close(pa.fd);
678199767f8SToomas Soome return (0);
679199767f8SToomas Soome }
680199767f8SToomas Soome
681b713c91eSToomas Soome /*
682b713c91eSToomas Soome * Return bootenv nvlist from pool label.
683b713c91eSToomas Soome */
684b713c91eSToomas Soome int
zfs_get_bootenv(void * vdev,nvlist_t ** benvp)685b713c91eSToomas Soome zfs_get_bootenv(void *vdev, nvlist_t **benvp)
686b713c91eSToomas Soome {
687b713c91eSToomas Soome struct zfs_devdesc *dev = (struct zfs_devdesc *)vdev;
688b713c91eSToomas Soome nvlist_t *benv = NULL;
689b713c91eSToomas Soome vdev_t *vd;
690b713c91eSToomas Soome spa_t *spa;
691b713c91eSToomas Soome
692b713c91eSToomas Soome if (dev->dd.d_dev->dv_type != DEVT_ZFS)
693b713c91eSToomas Soome return (ENOTSUP);
694b713c91eSToomas Soome
695b713c91eSToomas Soome if ((spa = spa_find_by_dev(dev)) == NULL)
696b713c91eSToomas Soome return (ENXIO);
697b713c91eSToomas Soome
698b713c91eSToomas Soome if (spa->spa_bootenv == NULL) {
699b713c91eSToomas Soome STAILQ_FOREACH(vd, &spa->spa_root_vdev->v_children,
700b713c91eSToomas Soome v_childlink) {
701b713c91eSToomas Soome benv = vdev_read_bootenv(vd);
702b713c91eSToomas Soome
703b713c91eSToomas Soome if (benv != NULL)
704b713c91eSToomas Soome break;
705b713c91eSToomas Soome }
706b713c91eSToomas Soome spa->spa_bootenv = benv;
707b713c91eSToomas Soome } else {
708b713c91eSToomas Soome benv = spa->spa_bootenv;
709b713c91eSToomas Soome }
710b713c91eSToomas Soome
711b713c91eSToomas Soome if (benv == NULL)
712b713c91eSToomas Soome return (ENOENT);
713b713c91eSToomas Soome
714b713c91eSToomas Soome *benvp = benv;
715b713c91eSToomas Soome return (0);
716b713c91eSToomas Soome }
717b713c91eSToomas Soome
718b713c91eSToomas Soome /*
719b713c91eSToomas Soome * Store nvlist to pool label bootenv area. Also updates cached pointer in spa.
720b713c91eSToomas Soome */
721b713c91eSToomas Soome int
zfs_set_bootenv(void * vdev,nvlist_t * benv)722b713c91eSToomas Soome zfs_set_bootenv(void *vdev, nvlist_t *benv)
723b713c91eSToomas Soome {
724b713c91eSToomas Soome struct zfs_devdesc *dev = (struct zfs_devdesc *)vdev;
725b713c91eSToomas Soome spa_t *spa;
726b713c91eSToomas Soome vdev_t *vd;
727b713c91eSToomas Soome
728b713c91eSToomas Soome if (dev->dd.d_dev->dv_type != DEVT_ZFS)
729b713c91eSToomas Soome return (ENOTSUP);
730b713c91eSToomas Soome
731b713c91eSToomas Soome if ((spa = spa_find_by_dev(dev)) == NULL)
732b713c91eSToomas Soome return (ENXIO);
733b713c91eSToomas Soome
734b713c91eSToomas Soome STAILQ_FOREACH(vd, &spa->spa_root_vdev->v_children, v_childlink) {
735b713c91eSToomas Soome vdev_write_bootenv(vd, benv);
736b713c91eSToomas Soome }
737b713c91eSToomas Soome
738b713c91eSToomas Soome spa->spa_bootenv = benv;
739b713c91eSToomas Soome return (0);
740b713c91eSToomas Soome }
741b713c91eSToomas Soome
742b713c91eSToomas Soome /*
743b713c91eSToomas Soome * Get bootonce value by key. The bootonce <key, value> pair is removed
744b713c91eSToomas Soome * from the bootenv nvlist and the remaining nvlist is committed back to disk.
745b713c91eSToomas Soome */
746b713c91eSToomas Soome int
zfs_get_bootonce(void * vdev,const char * key,char * buf,size_t size)747b713c91eSToomas Soome zfs_get_bootonce(void *vdev, const char *key, char *buf, size_t size)
748b713c91eSToomas Soome {
749b713c91eSToomas Soome nvlist_t *benv;
750b713c91eSToomas Soome char *result = NULL;
751b713c91eSToomas Soome int result_size, rv;
752b713c91eSToomas Soome
753b713c91eSToomas Soome if ((rv = zfs_get_bootenv(vdev, &benv)) != 0)
754b713c91eSToomas Soome return (rv);
755b713c91eSToomas Soome
756b713c91eSToomas Soome if ((rv = nvlist_find(benv, key, DATA_TYPE_STRING, NULL,
757b713c91eSToomas Soome &result, &result_size)) == 0) {
758b713c91eSToomas Soome if (result_size == 0) {
759b713c91eSToomas Soome /* ignore empty string */
760b713c91eSToomas Soome rv = ENOENT;
761b713c91eSToomas Soome } else {
762b713c91eSToomas Soome size = MIN((size_t)result_size + 1, size);
763b713c91eSToomas Soome strlcpy(buf, result, size);
764b713c91eSToomas Soome }
765b713c91eSToomas Soome (void) nvlist_remove(benv, key, DATA_TYPE_STRING);
766b713c91eSToomas Soome (void) zfs_set_bootenv(vdev, benv);
767b713c91eSToomas Soome }
768b713c91eSToomas Soome
769b713c91eSToomas Soome return (rv);
770b713c91eSToomas Soome }
771b713c91eSToomas Soome
772b713c91eSToomas Soome /*
773b713c91eSToomas Soome * nvstore backend.
774b713c91eSToomas Soome */
775b713c91eSToomas Soome
776b713c91eSToomas Soome static int zfs_nvstore_setter(void *, int, const char *,
777b713c91eSToomas Soome const void *, size_t);
778b713c91eSToomas Soome static int zfs_nvstore_setter_str(void *, const char *, const char *,
779b713c91eSToomas Soome const char *);
780b713c91eSToomas Soome static int zfs_nvstore_unset_impl(void *, const char *, bool);
781b713c91eSToomas Soome static int zfs_nvstore_setenv(void *, void *);
782b713c91eSToomas Soome
783b713c91eSToomas Soome /*
784b713c91eSToomas Soome * nvstore is only present for current rootfs pool.
785b713c91eSToomas Soome */
786b713c91eSToomas Soome static int
zfs_nvstore_sethook(struct env_var * ev,int flags __unused,const void * value)787b713c91eSToomas Soome zfs_nvstore_sethook(struct env_var *ev, int flags __unused, const void *value)
788b713c91eSToomas Soome {
789b713c91eSToomas Soome struct zfs_devdesc *dev;
790b713c91eSToomas Soome int rv;
791b713c91eSToomas Soome
792b713c91eSToomas Soome archsw.arch_getdev((void **)&dev, NULL, NULL);
793b713c91eSToomas Soome if (dev == NULL)
794b713c91eSToomas Soome return (ENXIO);
795b713c91eSToomas Soome
796b713c91eSToomas Soome rv = zfs_nvstore_setter_str(dev, NULL, ev->ev_name, value);
797b713c91eSToomas Soome
798b713c91eSToomas Soome free(dev);
799b713c91eSToomas Soome return (rv);
800b713c91eSToomas Soome }
801b713c91eSToomas Soome
802b713c91eSToomas Soome /*
803b713c91eSToomas Soome * nvstore is only present for current rootfs pool.
804b713c91eSToomas Soome */
805b713c91eSToomas Soome static int
zfs_nvstore_unsethook(struct env_var * ev)806b713c91eSToomas Soome zfs_nvstore_unsethook(struct env_var *ev)
807b713c91eSToomas Soome {
808b713c91eSToomas Soome struct zfs_devdesc *dev;
809b713c91eSToomas Soome int rv;
810b713c91eSToomas Soome
811b713c91eSToomas Soome archsw.arch_getdev((void **)&dev, NULL, NULL);
812b713c91eSToomas Soome if (dev == NULL)
813b713c91eSToomas Soome return (ENXIO);
814b713c91eSToomas Soome
815b713c91eSToomas Soome rv = zfs_nvstore_unset_impl(dev, ev->ev_name, false);
816b713c91eSToomas Soome
817b713c91eSToomas Soome free(dev);
818b713c91eSToomas Soome return (rv);
819b713c91eSToomas Soome }
820b713c91eSToomas Soome
821b713c91eSToomas Soome static int
zfs_nvstore_getter(void * vdev,const char * name,void ** data)822b713c91eSToomas Soome zfs_nvstore_getter(void *vdev, const char *name, void **data)
823b713c91eSToomas Soome {
824b713c91eSToomas Soome struct zfs_devdesc *dev = (struct zfs_devdesc *)vdev;
825b713c91eSToomas Soome spa_t *spa;
826b713c91eSToomas Soome nvlist_t *nv;
827b713c91eSToomas Soome char *str, **ptr;
828b713c91eSToomas Soome int size;
829b713c91eSToomas Soome int rv;
830b713c91eSToomas Soome
831b713c91eSToomas Soome if (dev->dd.d_dev->dv_type != DEVT_ZFS)
832b713c91eSToomas Soome return (ENOTSUP);
833b713c91eSToomas Soome
834b713c91eSToomas Soome if ((spa = spa_find_by_dev(dev)) == NULL)
835b713c91eSToomas Soome return (ENXIO);
836b713c91eSToomas Soome
837b713c91eSToomas Soome if (spa->spa_bootenv == NULL)
838b713c91eSToomas Soome return (ENXIO);
839b713c91eSToomas Soome
840b713c91eSToomas Soome if (nvlist_find(spa->spa_bootenv, OS_NVSTORE, DATA_TYPE_NVLIST,
841b713c91eSToomas Soome NULL, &nv, NULL) != 0)
842b713c91eSToomas Soome return (ENOENT);
843b713c91eSToomas Soome
844b713c91eSToomas Soome rv = nvlist_find(nv, name, DATA_TYPE_STRING, NULL, &str, &size);
845b713c91eSToomas Soome if (rv == 0) {
846b713c91eSToomas Soome ptr = (char **)data;
847b713c91eSToomas Soome asprintf(ptr, "%.*s", size, str);
848b713c91eSToomas Soome if (*data == NULL)
849b713c91eSToomas Soome rv = ENOMEM;
850b713c91eSToomas Soome }
851b713c91eSToomas Soome nvlist_destroy(nv);
852b713c91eSToomas Soome return (rv);
853b713c91eSToomas Soome }
854b713c91eSToomas Soome
855b713c91eSToomas Soome static int
zfs_nvstore_setter(void * vdev,int type,const char * name,const void * data,size_t size)856b713c91eSToomas Soome zfs_nvstore_setter(void *vdev, int type, const char *name,
857b713c91eSToomas Soome const void *data, size_t size)
858b713c91eSToomas Soome {
859b713c91eSToomas Soome struct zfs_devdesc *dev = (struct zfs_devdesc *)vdev;
860b713c91eSToomas Soome spa_t *spa;
861b713c91eSToomas Soome nvlist_t *nv;
862b713c91eSToomas Soome int rv;
863b713c91eSToomas Soome bool env_set = true;
864b713c91eSToomas Soome
865b713c91eSToomas Soome if (dev->dd.d_dev->dv_type != DEVT_ZFS)
866b713c91eSToomas Soome return (ENOTSUP);
867b713c91eSToomas Soome
868b713c91eSToomas Soome if ((spa = spa_find_by_dev(dev)) == NULL)
869b713c91eSToomas Soome return (ENXIO);
870b713c91eSToomas Soome
871b713c91eSToomas Soome if (spa->spa_bootenv == NULL)
872b713c91eSToomas Soome return (ENXIO);
873b713c91eSToomas Soome
874b713c91eSToomas Soome if (nvlist_find(spa->spa_bootenv, OS_NVSTORE, DATA_TYPE_NVLIST,
875b713c91eSToomas Soome NULL, &nv, NULL) != 0) {
876b713c91eSToomas Soome nv = nvlist_create(NV_UNIQUE_NAME);
877b713c91eSToomas Soome if (nv == NULL)
878b713c91eSToomas Soome return (ENOMEM);
879b713c91eSToomas Soome }
880b713c91eSToomas Soome
881b713c91eSToomas Soome rv = 0;
882b713c91eSToomas Soome switch (type) {
883b713c91eSToomas Soome case DATA_TYPE_INT8:
884b713c91eSToomas Soome if (size != sizeof (int8_t)) {
885b713c91eSToomas Soome rv = EINVAL;
886b713c91eSToomas Soome break;
887b713c91eSToomas Soome }
888b713c91eSToomas Soome rv = nvlist_add_int8(nv, name, *(int8_t *)data);
889b713c91eSToomas Soome break;
890b713c91eSToomas Soome
891b713c91eSToomas Soome case DATA_TYPE_INT16:
892b713c91eSToomas Soome if (size != sizeof (int16_t)) {
893b713c91eSToomas Soome rv = EINVAL;
894b713c91eSToomas Soome break;
895b713c91eSToomas Soome }
896b713c91eSToomas Soome rv = nvlist_add_int16(nv, name, *(int16_t *)data);
897b713c91eSToomas Soome break;
898b713c91eSToomas Soome
899b713c91eSToomas Soome case DATA_TYPE_INT32:
900b713c91eSToomas Soome if (size != sizeof (int32_t)) {
901b713c91eSToomas Soome rv = EINVAL;
902b713c91eSToomas Soome break;
903b713c91eSToomas Soome }
904b713c91eSToomas Soome rv = nvlist_add_int32(nv, name, *(int32_t *)data);
905b713c91eSToomas Soome break;
906b713c91eSToomas Soome
907b713c91eSToomas Soome case DATA_TYPE_INT64:
908b713c91eSToomas Soome if (size != sizeof (int64_t)) {
909b713c91eSToomas Soome rv = EINVAL;
910b713c91eSToomas Soome break;
911b713c91eSToomas Soome }
912b713c91eSToomas Soome rv = nvlist_add_int64(nv, name, *(int64_t *)data);
913b713c91eSToomas Soome break;
914b713c91eSToomas Soome
915b713c91eSToomas Soome case DATA_TYPE_BYTE:
916b713c91eSToomas Soome if (size != sizeof (uint8_t)) {
917b713c91eSToomas Soome rv = EINVAL;
918b713c91eSToomas Soome break;
919b713c91eSToomas Soome }
920b713c91eSToomas Soome rv = nvlist_add_byte(nv, name, *(int8_t *)data);
921b713c91eSToomas Soome break;
922b713c91eSToomas Soome
923b713c91eSToomas Soome case DATA_TYPE_UINT8:
924b713c91eSToomas Soome if (size != sizeof (uint8_t)) {
925b713c91eSToomas Soome rv = EINVAL;
926b713c91eSToomas Soome break;
927b713c91eSToomas Soome }
928b713c91eSToomas Soome rv = nvlist_add_uint8(nv, name, *(int8_t *)data);
929b713c91eSToomas Soome break;
930b713c91eSToomas Soome case DATA_TYPE_UINT16:
931b713c91eSToomas Soome if (size != sizeof (uint16_t)) {
932b713c91eSToomas Soome rv = EINVAL;
933b713c91eSToomas Soome break;
934b713c91eSToomas Soome }
935b713c91eSToomas Soome rv = nvlist_add_uint16(nv, name, *(uint16_t *)data);
936b713c91eSToomas Soome break;
937b713c91eSToomas Soome
938b713c91eSToomas Soome case DATA_TYPE_UINT32:
939b713c91eSToomas Soome if (size != sizeof (uint32_t)) {
940b713c91eSToomas Soome rv = EINVAL;
941b713c91eSToomas Soome break;
942b713c91eSToomas Soome }
943b713c91eSToomas Soome rv = nvlist_add_uint32(nv, name, *(uint32_t *)data);
944b713c91eSToomas Soome break;
945b713c91eSToomas Soome
946b713c91eSToomas Soome case DATA_TYPE_UINT64:
947b713c91eSToomas Soome if (size != sizeof (uint64_t)) {
948b713c91eSToomas Soome rv = EINVAL;
949b713c91eSToomas Soome break;
950b713c91eSToomas Soome }
951b713c91eSToomas Soome rv = nvlist_add_uint64(nv, name, *(uint64_t *)data);
952b713c91eSToomas Soome break;
953b713c91eSToomas Soome
954b713c91eSToomas Soome case DATA_TYPE_STRING:
955b713c91eSToomas Soome rv = nvlist_add_string(nv, name, data);
956b713c91eSToomas Soome break;
957b713c91eSToomas Soome
958b713c91eSToomas Soome case DATA_TYPE_BOOLEAN_VALUE:
959b713c91eSToomas Soome if (size != sizeof (boolean_t)) {
960b713c91eSToomas Soome rv = EINVAL;
961b713c91eSToomas Soome break;
962b713c91eSToomas Soome }
963b713c91eSToomas Soome rv = nvlist_add_boolean_value(nv, name, *(boolean_t *)data);
964b713c91eSToomas Soome break;
965b713c91eSToomas Soome
966b713c91eSToomas Soome default:
967b713c91eSToomas Soome rv = EINVAL;
968b713c91eSToomas Soome break;
969b713c91eSToomas Soome }
970b713c91eSToomas Soome
971b713c91eSToomas Soome if (rv == 0) {
972b713c91eSToomas Soome rv = nvlist_add_nvlist(spa->spa_bootenv, OS_NVSTORE, nv);
973b713c91eSToomas Soome if (rv == 0) {
974b713c91eSToomas Soome rv = zfs_set_bootenv(vdev, spa->spa_bootenv);
975b713c91eSToomas Soome }
976b713c91eSToomas Soome if (rv == 0) {
977b713c91eSToomas Soome if (env_set) {
978b713c91eSToomas Soome rv = zfs_nvstore_setenv(vdev,
979b713c91eSToomas Soome nvpair_find(nv, name));
980b713c91eSToomas Soome } else {
981b713c91eSToomas Soome env_discard(env_getenv(name));
982b713c91eSToomas Soome rv = 0;
983b713c91eSToomas Soome }
984b713c91eSToomas Soome }
985b713c91eSToomas Soome }
986b713c91eSToomas Soome
987b713c91eSToomas Soome nvlist_destroy(nv);
988b713c91eSToomas Soome return (rv);
989b713c91eSToomas Soome }
990b713c91eSToomas Soome
991b713c91eSToomas Soome static int
get_int64(const char * data,int64_t * ip)992b713c91eSToomas Soome get_int64(const char *data, int64_t *ip)
993b713c91eSToomas Soome {
994b713c91eSToomas Soome char *end;
995b713c91eSToomas Soome int64_t val;
996b713c91eSToomas Soome
997b713c91eSToomas Soome errno = 0;
998b713c91eSToomas Soome val = strtoll(data, &end, 0);
999b713c91eSToomas Soome if (errno != 0 || *data == '\0' || *end != '\0')
1000b713c91eSToomas Soome return (EINVAL);
1001b713c91eSToomas Soome
1002b713c91eSToomas Soome *ip = val;
1003b713c91eSToomas Soome return (0);
1004b713c91eSToomas Soome }
1005b713c91eSToomas Soome
1006b713c91eSToomas Soome static int
get_uint64(const char * data,uint64_t * ip)1007b713c91eSToomas Soome get_uint64(const char *data, uint64_t *ip)
1008b713c91eSToomas Soome {
1009b713c91eSToomas Soome char *end;
1010b713c91eSToomas Soome uint64_t val;
1011b713c91eSToomas Soome
1012b713c91eSToomas Soome errno = 0;
1013b713c91eSToomas Soome val = strtoull(data, &end, 0);
1014b713c91eSToomas Soome if (errno != 0 || *data == '\0' || *end != '\0')
1015b713c91eSToomas Soome return (EINVAL);
1016b713c91eSToomas Soome
1017b713c91eSToomas Soome *ip = val;
1018b713c91eSToomas Soome return (0);
1019b713c91eSToomas Soome }
1020b713c91eSToomas Soome
1021b713c91eSToomas Soome /*
1022b713c91eSToomas Soome * Translate textual data to data type. If type is not set, and we are
1023b713c91eSToomas Soome * creating new pair, use DATA_TYPE_STRING.
1024b713c91eSToomas Soome */
1025b713c91eSToomas Soome static int
zfs_nvstore_setter_str(void * vdev,const char * type,const char * name,const char * data)1026b713c91eSToomas Soome zfs_nvstore_setter_str(void *vdev, const char *type, const char *name,
1027b713c91eSToomas Soome const char *data)
1028b713c91eSToomas Soome {
1029b713c91eSToomas Soome struct zfs_devdesc *dev = (struct zfs_devdesc *)vdev;
1030b713c91eSToomas Soome spa_t *spa;
1031b713c91eSToomas Soome nvlist_t *nv;
1032b713c91eSToomas Soome int rv;
1033b713c91eSToomas Soome data_type_t dt;
1034b713c91eSToomas Soome int64_t val;
1035b713c91eSToomas Soome uint64_t uval;
1036b713c91eSToomas Soome
1037b713c91eSToomas Soome if (dev->dd.d_dev->dv_type != DEVT_ZFS)
1038b713c91eSToomas Soome return (ENOTSUP);
1039b713c91eSToomas Soome
1040b713c91eSToomas Soome if ((spa = spa_find_by_dev(dev)) == NULL)
1041b713c91eSToomas Soome return (ENXIO);
1042b713c91eSToomas Soome
1043b713c91eSToomas Soome if (spa->spa_bootenv == NULL)
1044b713c91eSToomas Soome return (ENXIO);
1045b713c91eSToomas Soome
1046b713c91eSToomas Soome if (nvlist_find(spa->spa_bootenv, OS_NVSTORE, DATA_TYPE_NVLIST,
1047b713c91eSToomas Soome NULL, &nv, NULL) != 0) {
1048b713c91eSToomas Soome nv = NULL;
1049b713c91eSToomas Soome }
1050b713c91eSToomas Soome
1051b713c91eSToomas Soome if (type == NULL) {
1052b713c91eSToomas Soome nvp_header_t *nvh;
1053b713c91eSToomas Soome
1054b713c91eSToomas Soome /*
1055b713c91eSToomas Soome * if there is no existing pair, default to string.
1056b713c91eSToomas Soome * Otherwise, use type from existing pair.
1057b713c91eSToomas Soome */
1058b713c91eSToomas Soome nvh = nvpair_find(nv, name);
1059b713c91eSToomas Soome if (nvh == NULL) {
1060b713c91eSToomas Soome dt = DATA_TYPE_STRING;
1061b713c91eSToomas Soome } else {
1062b713c91eSToomas Soome nv_string_t *nvp_name;
1063b713c91eSToomas Soome nv_pair_data_t *nvp_data;
1064b713c91eSToomas Soome
1065b713c91eSToomas Soome nvp_name = (nv_string_t *)(nvh + 1);
1066b713c91eSToomas Soome nvp_data = (nv_pair_data_t *)(&nvp_name->nv_data[0] +
1067b713c91eSToomas Soome NV_ALIGN4(nvp_name->nv_size));
1068b713c91eSToomas Soome dt = nvp_data->nv_type;
1069b713c91eSToomas Soome }
1070b713c91eSToomas Soome } else {
1071b713c91eSToomas Soome dt = nvpair_type_from_name(type);
1072b713c91eSToomas Soome }
1073b713c91eSToomas Soome nvlist_destroy(nv);
1074b713c91eSToomas Soome
1075b713c91eSToomas Soome rv = 0;
1076b713c91eSToomas Soome switch (dt) {
1077b713c91eSToomas Soome case DATA_TYPE_INT8:
1078b713c91eSToomas Soome rv = get_int64(data, &val);
1079b713c91eSToomas Soome if (rv == 0) {
1080b713c91eSToomas Soome int8_t v = val;
1081b713c91eSToomas Soome
1082b713c91eSToomas Soome rv = zfs_nvstore_setter(vdev, dt, name, &v, sizeof (v));
1083b713c91eSToomas Soome }
1084b713c91eSToomas Soome break;
1085b713c91eSToomas Soome case DATA_TYPE_INT16:
1086b713c91eSToomas Soome rv = get_int64(data, &val);
1087b713c91eSToomas Soome if (rv == 0) {
1088b713c91eSToomas Soome int16_t v = val;
1089b713c91eSToomas Soome
1090b713c91eSToomas Soome rv = zfs_nvstore_setter(vdev, dt, name, &v, sizeof (v));
1091b713c91eSToomas Soome }
1092b713c91eSToomas Soome break;
1093b713c91eSToomas Soome case DATA_TYPE_INT32:
1094b713c91eSToomas Soome rv = get_int64(data, &val);
1095b713c91eSToomas Soome if (rv == 0) {
1096b713c91eSToomas Soome int32_t v = val;
1097b713c91eSToomas Soome
1098b713c91eSToomas Soome rv = zfs_nvstore_setter(vdev, dt, name, &v, sizeof (v));
1099b713c91eSToomas Soome }
1100b713c91eSToomas Soome break;
1101b713c91eSToomas Soome case DATA_TYPE_INT64:
1102b713c91eSToomas Soome rv = get_int64(data, &val);
1103b713c91eSToomas Soome if (rv == 0) {
1104b713c91eSToomas Soome rv = zfs_nvstore_setter(vdev, dt, name, &val,
1105b713c91eSToomas Soome sizeof (val));
1106b713c91eSToomas Soome }
1107b713c91eSToomas Soome break;
1108b713c91eSToomas Soome
1109b713c91eSToomas Soome case DATA_TYPE_BYTE:
1110b713c91eSToomas Soome rv = get_uint64(data, &uval);
1111b713c91eSToomas Soome if (rv == 0) {
1112b713c91eSToomas Soome uint8_t v = uval;
1113b713c91eSToomas Soome
1114b713c91eSToomas Soome rv = zfs_nvstore_setter(vdev, dt, name, &v, sizeof (v));
1115b713c91eSToomas Soome }
1116b713c91eSToomas Soome break;
1117b713c91eSToomas Soome
1118b713c91eSToomas Soome case DATA_TYPE_UINT8:
1119b713c91eSToomas Soome rv = get_uint64(data, &uval);
1120b713c91eSToomas Soome if (rv == 0) {
1121b713c91eSToomas Soome uint8_t v = uval;
1122b713c91eSToomas Soome
1123b713c91eSToomas Soome rv = zfs_nvstore_setter(vdev, dt, name, &v, sizeof (v));
1124b713c91eSToomas Soome }
1125b713c91eSToomas Soome break;
1126b713c91eSToomas Soome
1127b713c91eSToomas Soome case DATA_TYPE_UINT16:
1128b713c91eSToomas Soome rv = get_uint64(data, &uval);
1129b713c91eSToomas Soome if (rv == 0) {
1130b713c91eSToomas Soome uint16_t v = uval;
1131b713c91eSToomas Soome
1132b713c91eSToomas Soome rv = zfs_nvstore_setter(vdev, dt, name, &v, sizeof (v));
1133b713c91eSToomas Soome }
1134b713c91eSToomas Soome break;
1135b713c91eSToomas Soome
1136b713c91eSToomas Soome case DATA_TYPE_UINT32:
1137b713c91eSToomas Soome rv = get_uint64(data, &uval);
1138b713c91eSToomas Soome if (rv == 0) {
1139b713c91eSToomas Soome uint32_t v = uval;
1140b713c91eSToomas Soome
1141b713c91eSToomas Soome rv = zfs_nvstore_setter(vdev, dt, name, &v, sizeof (v));
1142b713c91eSToomas Soome }
1143b713c91eSToomas Soome break;
1144b713c91eSToomas Soome
1145b713c91eSToomas Soome case DATA_TYPE_UINT64:
1146b713c91eSToomas Soome rv = get_uint64(data, &uval);
1147b713c91eSToomas Soome if (rv == 0) {
1148b713c91eSToomas Soome rv = zfs_nvstore_setter(vdev, dt, name, &uval,
1149b713c91eSToomas Soome sizeof (uval));
1150b713c91eSToomas Soome }
1151b713c91eSToomas Soome break;
1152b713c91eSToomas Soome
1153b713c91eSToomas Soome case DATA_TYPE_STRING:
1154b713c91eSToomas Soome rv = zfs_nvstore_setter(vdev, dt, name, data, strlen(data) + 1);
1155b713c91eSToomas Soome break;
1156b713c91eSToomas Soome
1157b713c91eSToomas Soome case DATA_TYPE_BOOLEAN_VALUE:
1158b713c91eSToomas Soome rv = get_int64(data, &val);
1159b713c91eSToomas Soome if (rv == 0) {
1160b713c91eSToomas Soome boolean_t v = val;
1161b713c91eSToomas Soome
1162b713c91eSToomas Soome rv = zfs_nvstore_setter(vdev, dt, name, &v, sizeof (v));
1163b713c91eSToomas Soome }
1164b713c91eSToomas Soome break;
1165b713c91eSToomas Soome
1166b713c91eSToomas Soome default:
1167b713c91eSToomas Soome rv = EINVAL;
1168b713c91eSToomas Soome }
1169b713c91eSToomas Soome return (rv);
1170b713c91eSToomas Soome }
1171b713c91eSToomas Soome
1172b713c91eSToomas Soome static int
zfs_nvstore_unset_impl(void * vdev,const char * name,bool unset_env)1173b713c91eSToomas Soome zfs_nvstore_unset_impl(void *vdev, const char *name, bool unset_env)
1174b713c91eSToomas Soome {
1175b713c91eSToomas Soome struct zfs_devdesc *dev = (struct zfs_devdesc *)vdev;
1176b713c91eSToomas Soome spa_t *spa;
1177b713c91eSToomas Soome nvlist_t *nv;
1178b713c91eSToomas Soome int rv;
1179b713c91eSToomas Soome
1180b713c91eSToomas Soome if (dev->dd.d_dev->dv_type != DEVT_ZFS)
1181b713c91eSToomas Soome return (ENOTSUP);
1182b713c91eSToomas Soome
1183b713c91eSToomas Soome if ((spa = spa_find_by_dev(dev)) == NULL)
1184b713c91eSToomas Soome return (ENXIO);
1185b713c91eSToomas Soome
1186b713c91eSToomas Soome if (spa->spa_bootenv == NULL)
1187b713c91eSToomas Soome return (ENXIO);
1188b713c91eSToomas Soome
1189b713c91eSToomas Soome if (nvlist_find(spa->spa_bootenv, OS_NVSTORE, DATA_TYPE_NVLIST,
1190b713c91eSToomas Soome NULL, &nv, NULL) != 0)
1191b713c91eSToomas Soome return (ENOENT);
1192b713c91eSToomas Soome
1193b713c91eSToomas Soome rv = nvlist_remove(nv, name, DATA_TYPE_UNKNOWN);
1194b713c91eSToomas Soome if (rv == 0) {
1195b713c91eSToomas Soome if (nvlist_next_nvpair(nv, NULL) == NULL) {
1196b713c91eSToomas Soome rv = nvlist_remove(spa->spa_bootenv, OS_NVSTORE,
1197b713c91eSToomas Soome DATA_TYPE_NVLIST);
1198b713c91eSToomas Soome } else {
1199b713c91eSToomas Soome rv = nvlist_add_nvlist(spa->spa_bootenv,
1200b713c91eSToomas Soome OS_NVSTORE, nv);
1201b713c91eSToomas Soome }
1202b713c91eSToomas Soome if (rv == 0)
1203b713c91eSToomas Soome rv = zfs_set_bootenv(vdev, spa->spa_bootenv);
1204b713c91eSToomas Soome }
1205b713c91eSToomas Soome
1206*1b0fd692SToomas Soome if (unset_env) {
1207*1b0fd692SToomas Soome struct env_var *ev = env_getenv(name);
1208*1b0fd692SToomas Soome
1209*1b0fd692SToomas Soome if (ev != NULL)
1210*1b0fd692SToomas Soome env_discard(ev);
1211*1b0fd692SToomas Soome }
1212b713c91eSToomas Soome return (rv);
1213b713c91eSToomas Soome }
1214b713c91eSToomas Soome
1215b713c91eSToomas Soome static int
zfs_nvstore_unset(void * vdev,const char * name)1216b713c91eSToomas Soome zfs_nvstore_unset(void *vdev, const char *name)
1217b713c91eSToomas Soome {
1218b713c91eSToomas Soome return (zfs_nvstore_unset_impl(vdev, name, true));
1219b713c91eSToomas Soome }
1220b713c91eSToomas Soome
1221b713c91eSToomas Soome static int
zfs_nvstore_print(void * vdev __unused,void * ptr)1222b713c91eSToomas Soome zfs_nvstore_print(void *vdev __unused, void *ptr)
1223b713c91eSToomas Soome {
1224b713c91eSToomas Soome
1225b713c91eSToomas Soome nvpair_print(ptr, 0);
1226b713c91eSToomas Soome return (0);
1227b713c91eSToomas Soome }
1228b713c91eSToomas Soome
1229b713c91eSToomas Soome /*
1230b713c91eSToomas Soome * Create environment variable from nvpair.
1231b713c91eSToomas Soome * set hook will update nvstore with new value, unset hook will remove
1232b713c91eSToomas Soome * variable from nvstore.
1233b713c91eSToomas Soome */
1234b713c91eSToomas Soome static int
zfs_nvstore_setenv(void * vdev __unused,void * ptr)1235b713c91eSToomas Soome zfs_nvstore_setenv(void *vdev __unused, void *ptr)
1236b713c91eSToomas Soome {
1237b713c91eSToomas Soome nvp_header_t *nvh = ptr;
1238b713c91eSToomas Soome nv_string_t *nvp_name, *nvp_value;
1239b713c91eSToomas Soome nv_pair_data_t *nvp_data;
1240b713c91eSToomas Soome char *name, *value;
1241b713c91eSToomas Soome int rv = 0;
1242b713c91eSToomas Soome
1243b713c91eSToomas Soome if (nvh == NULL)
1244b713c91eSToomas Soome return (ENOENT);
1245b713c91eSToomas Soome
1246b713c91eSToomas Soome nvp_name = (nv_string_t *)(nvh + 1);
1247b713c91eSToomas Soome nvp_data = (nv_pair_data_t *)(&nvp_name->nv_data[0] +
1248b713c91eSToomas Soome NV_ALIGN4(nvp_name->nv_size));
1249b713c91eSToomas Soome
1250b713c91eSToomas Soome if ((name = nvstring_get(nvp_name)) == NULL)
1251b713c91eSToomas Soome return (ENOMEM);
1252b713c91eSToomas Soome
1253b713c91eSToomas Soome value = NULL;
1254b713c91eSToomas Soome switch (nvp_data->nv_type) {
1255b713c91eSToomas Soome case DATA_TYPE_BYTE:
1256b713c91eSToomas Soome case DATA_TYPE_UINT8:
1257b713c91eSToomas Soome (void) asprintf(&value, "%uc",
1258b713c91eSToomas Soome *(unsigned *)&nvp_data->nv_data[0]);
1259b713c91eSToomas Soome if (value == NULL)
1260b713c91eSToomas Soome rv = ENOMEM;
1261b713c91eSToomas Soome break;
1262b713c91eSToomas Soome
1263b713c91eSToomas Soome case DATA_TYPE_INT8:
1264b713c91eSToomas Soome (void) asprintf(&value, "%c", *(int *)&nvp_data->nv_data[0]);
1265b713c91eSToomas Soome if (value == NULL)
1266b713c91eSToomas Soome rv = ENOMEM;
1267b713c91eSToomas Soome break;
1268b713c91eSToomas Soome
1269b713c91eSToomas Soome case DATA_TYPE_INT16:
1270b713c91eSToomas Soome (void) asprintf(&value, "%hd", *(short *)&nvp_data->nv_data[0]);
1271b713c91eSToomas Soome if (value == NULL)
1272b713c91eSToomas Soome rv = ENOMEM;
1273b713c91eSToomas Soome break;
1274b713c91eSToomas Soome
1275b713c91eSToomas Soome case DATA_TYPE_UINT16:
1276b713c91eSToomas Soome (void) asprintf(&value, "%hu",
1277b713c91eSToomas Soome *(unsigned short *)&nvp_data->nv_data[0]);
1278b713c91eSToomas Soome if (value == NULL)
1279b713c91eSToomas Soome rv = ENOMEM;
1280b713c91eSToomas Soome break;
1281b713c91eSToomas Soome
1282b713c91eSToomas Soome case DATA_TYPE_BOOLEAN_VALUE:
1283b713c91eSToomas Soome case DATA_TYPE_INT32:
1284b713c91eSToomas Soome (void) asprintf(&value, "%d", *(int *)&nvp_data->nv_data[0]);
1285b713c91eSToomas Soome if (value == NULL)
1286b713c91eSToomas Soome rv = ENOMEM;
1287b713c91eSToomas Soome break;
1288b713c91eSToomas Soome
1289b713c91eSToomas Soome case DATA_TYPE_UINT32:
1290b713c91eSToomas Soome (void) asprintf(&value, "%u",
1291b713c91eSToomas Soome *(unsigned *)&nvp_data->nv_data[0]);
1292b713c91eSToomas Soome if (value == NULL)
1293b713c91eSToomas Soome rv = ENOMEM;
1294b713c91eSToomas Soome break;
1295b713c91eSToomas Soome
1296b713c91eSToomas Soome case DATA_TYPE_INT64:
1297b713c91eSToomas Soome (void) asprintf(&value, "%jd",
1298b713c91eSToomas Soome (intmax_t)*(int64_t *)&nvp_data->nv_data[0]);
1299b713c91eSToomas Soome if (value == NULL)
1300b713c91eSToomas Soome rv = ENOMEM;
1301b713c91eSToomas Soome break;
1302b713c91eSToomas Soome
1303b713c91eSToomas Soome case DATA_TYPE_UINT64:
1304b713c91eSToomas Soome (void) asprintf(&value, "%ju",
1305b713c91eSToomas Soome (uintmax_t)*(uint64_t *)&nvp_data->nv_data[0]);
1306b713c91eSToomas Soome if (value == NULL)
1307b713c91eSToomas Soome rv = ENOMEM;
1308b713c91eSToomas Soome break;
1309b713c91eSToomas Soome
1310b713c91eSToomas Soome case DATA_TYPE_STRING:
1311b713c91eSToomas Soome nvp_value = (nv_string_t *)&nvp_data->nv_data[0];
1312b713c91eSToomas Soome if ((value = nvstring_get(nvp_value)) == NULL) {
1313b713c91eSToomas Soome rv = ENOMEM;
1314b713c91eSToomas Soome break;
1315b713c91eSToomas Soome }
1316b713c91eSToomas Soome break;
1317b713c91eSToomas Soome
1318b713c91eSToomas Soome default:
1319b713c91eSToomas Soome rv = EINVAL;
1320b713c91eSToomas Soome break;
1321b713c91eSToomas Soome }
1322b713c91eSToomas Soome
1323b713c91eSToomas Soome if (value != NULL) {
1324b713c91eSToomas Soome rv = env_setenv(name, EV_VOLATILE | EV_NOHOOK, value,
1325b713c91eSToomas Soome zfs_nvstore_sethook, zfs_nvstore_unsethook);
1326b713c91eSToomas Soome free(value);
1327b713c91eSToomas Soome }
1328b713c91eSToomas Soome free(name);
1329b713c91eSToomas Soome return (rv);
1330b713c91eSToomas Soome }
1331b713c91eSToomas Soome
1332b713c91eSToomas Soome static int
zfs_nvstore_iterate(void * vdev,int (* cb)(void *,void *))1333b713c91eSToomas Soome zfs_nvstore_iterate(void *vdev, int (*cb)(void *, void *))
1334b713c91eSToomas Soome {
1335b713c91eSToomas Soome struct zfs_devdesc *dev = (struct zfs_devdesc *)vdev;
1336b713c91eSToomas Soome spa_t *spa;
1337b713c91eSToomas Soome nvlist_t *nv;
1338b713c91eSToomas Soome nvp_header_t *nvh;
1339b713c91eSToomas Soome int rv;
1340b713c91eSToomas Soome
1341b713c91eSToomas Soome if (dev->dd.d_dev->dv_type != DEVT_ZFS)
1342b713c91eSToomas Soome return (ENOTSUP);
1343b713c91eSToomas Soome
1344b713c91eSToomas Soome if ((spa = spa_find_by_dev(dev)) == NULL)
1345b713c91eSToomas Soome return (ENXIO);
1346b713c91eSToomas Soome
1347b713c91eSToomas Soome if (spa->spa_bootenv == NULL)
1348b713c91eSToomas Soome return (ENXIO);
1349b713c91eSToomas Soome
1350b713c91eSToomas Soome if (nvlist_find(spa->spa_bootenv, OS_NVSTORE, DATA_TYPE_NVLIST,
1351b713c91eSToomas Soome NULL, &nv, NULL) != 0)
1352b713c91eSToomas Soome return (ENOENT);
1353b713c91eSToomas Soome
1354b713c91eSToomas Soome rv = 0;
1355b713c91eSToomas Soome nvh = NULL;
1356b713c91eSToomas Soome while ((nvh = nvlist_next_nvpair(nv, nvh)) != NULL) {
1357b713c91eSToomas Soome rv = cb(vdev, nvh);
1358b713c91eSToomas Soome if (rv != 0)
1359b713c91eSToomas Soome break;
1360b713c91eSToomas Soome }
1361b713c91eSToomas Soome return (rv);
1362b713c91eSToomas Soome }
1363b713c91eSToomas Soome
1364b713c91eSToomas Soome nvs_callbacks_t nvstore_zfs_cb = {
1365b713c91eSToomas Soome .nvs_getter = zfs_nvstore_getter,
1366b713c91eSToomas Soome .nvs_setter = zfs_nvstore_setter,
1367b713c91eSToomas Soome .nvs_setter_str = zfs_nvstore_setter_str,
1368b713c91eSToomas Soome .nvs_unset = zfs_nvstore_unset,
1369b713c91eSToomas Soome .nvs_print = zfs_nvstore_print,
1370b713c91eSToomas Soome .nvs_iterate = zfs_nvstore_iterate
1371b713c91eSToomas Soome };
1372b713c91eSToomas Soome
1373b713c91eSToomas Soome int
zfs_attach_nvstore(void * vdev)1374b713c91eSToomas Soome zfs_attach_nvstore(void *vdev)
1375b713c91eSToomas Soome {
1376b713c91eSToomas Soome struct zfs_devdesc *dev = vdev;
1377b713c91eSToomas Soome spa_t *spa;
1378b713c91eSToomas Soome uint64_t version;
1379b713c91eSToomas Soome int rv;
1380b713c91eSToomas Soome
1381b713c91eSToomas Soome if (dev->dd.d_dev->dv_type != DEVT_ZFS)
1382b713c91eSToomas Soome return (ENOTSUP);
1383b713c91eSToomas Soome
1384b713c91eSToomas Soome if ((spa = spa_find_by_dev(dev)) == NULL)
1385b713c91eSToomas Soome return (ENXIO);
1386b713c91eSToomas Soome
1387b713c91eSToomas Soome rv = nvlist_find(spa->spa_bootenv, BOOTENV_VERSION, DATA_TYPE_UINT64,
1388b713c91eSToomas Soome NULL, &version, NULL);
1389b713c91eSToomas Soome
1390b713c91eSToomas Soome if (rv != 0 || version != VB_NVLIST) {
1391b713c91eSToomas Soome return (ENXIO);
1392b713c91eSToomas Soome }
1393b713c91eSToomas Soome
1394b713c91eSToomas Soome dev = malloc(sizeof (*dev));
1395b713c91eSToomas Soome if (dev == NULL)
1396b713c91eSToomas Soome return (ENOMEM);
1397b713c91eSToomas Soome memcpy(dev, vdev, sizeof (*dev));
1398b713c91eSToomas Soome
1399b713c91eSToomas Soome rv = nvstore_init(spa->spa_name, &nvstore_zfs_cb, dev);
1400b713c91eSToomas Soome if (rv != 0)
1401b713c91eSToomas Soome free(dev);
1402b713c91eSToomas Soome else
1403b713c91eSToomas Soome rv = zfs_nvstore_iterate(dev, zfs_nvstore_setenv);
1404b713c91eSToomas Soome return (rv);
1405b713c91eSToomas Soome }
1406b713c91eSToomas Soome
1407199767f8SToomas Soome int
zfs_probe_dev(const char * devname,uint64_t * pool_guid)1408199767f8SToomas Soome zfs_probe_dev(const char *devname, uint64_t *pool_guid)
1409199767f8SToomas Soome {
1410781f142dSToomas Soome struct disk_devdesc *dev;
1411199767f8SToomas Soome struct ptable *table;
1412199767f8SToomas Soome struct zfs_probe_args pa;
1413edb35047SToomas Soome uint64_t mediasz;
1414199767f8SToomas Soome int ret;
1415199767f8SToomas Soome
1416dbacaf56SToomas Soome if (pool_guid)
1417dbacaf56SToomas Soome *pool_guid = 0;
1418b713c91eSToomas Soome pa.fd = open(devname, O_RDWR);
1419199767f8SToomas Soome if (pa.fd == -1)
1420199767f8SToomas Soome return (ENXIO);
1421781f142dSToomas Soome /*
1422781f142dSToomas Soome * We will not probe the whole disk, we can not boot from such
1423781f142dSToomas Soome * disks and some systems will misreport the disk sizes and will
1424781f142dSToomas Soome * hang while accessing the disk.
1425781f142dSToomas Soome */
1426781f142dSToomas Soome if (archsw.arch_getdev((void **)&dev, devname, NULL) == 0) {
1427781f142dSToomas Soome int partition = dev->d_partition;
1428781f142dSToomas Soome int slice = dev->d_slice;
1429781f142dSToomas Soome
1430781f142dSToomas Soome free(dev);
14319a34674dSToomas Soome if (partition != D_PARTNONE && slice != D_SLICENONE) {
1432781f142dSToomas Soome ret = zfs_probe(pa.fd, pool_guid);
1433781f142dSToomas Soome if (ret == 0)
1434781f142dSToomas Soome return (0);
1435781f142dSToomas Soome }
1436781f142dSToomas Soome }
1437dbacaf56SToomas Soome
1438199767f8SToomas Soome /* Probe each partition */
1439199767f8SToomas Soome ret = ioctl(pa.fd, DIOCGMEDIASIZE, &mediasz);
1440199767f8SToomas Soome if (ret == 0)
1441199767f8SToomas Soome ret = ioctl(pa.fd, DIOCGSECTORSIZE, &pa.secsz);
1442199767f8SToomas Soome if (ret == 0) {
1443199767f8SToomas Soome pa.devname = devname;
1444199767f8SToomas Soome pa.pool_guid = pool_guid;
1445199767f8SToomas Soome table = ptable_open(&pa, mediasz / pa.secsz, pa.secsz,
1446199767f8SToomas Soome zfs_diskread);
1447199767f8SToomas Soome if (table != NULL) {
1448199767f8SToomas Soome ptable_iterate(table, &pa, zfs_probe_partition);
1449199767f8SToomas Soome ptable_close(table);
1450199767f8SToomas Soome }
1451199767f8SToomas Soome }
1452199767f8SToomas Soome close(pa.fd);
1453dbacaf56SToomas Soome if (pool_guid && *pool_guid == 0)
1454dbacaf56SToomas Soome ret = ENXIO;
1455199767f8SToomas Soome return (ret);
1456199767f8SToomas Soome }
1457199767f8SToomas Soome
1458199767f8SToomas Soome /*
1459199767f8SToomas Soome * Print information about ZFS pools
1460199767f8SToomas Soome */
1461199767f8SToomas Soome static int
zfs_dev_print(int verbose)1462199767f8SToomas Soome zfs_dev_print(int verbose)
1463199767f8SToomas Soome {
1464199767f8SToomas Soome spa_t *spa;
1465199767f8SToomas Soome char line[80];
1466199767f8SToomas Soome int ret = 0;
1467199767f8SToomas Soome
1468502b33a5SToomas Soome if (STAILQ_EMPTY(&zfs_pools))
1469502b33a5SToomas Soome return (0);
1470502b33a5SToomas Soome
1471502b33a5SToomas Soome printf("%s devices:", zfs_dev.dv_name);
1472502b33a5SToomas Soome if ((ret = pager_output("\n")) != 0)
1473502b33a5SToomas Soome return (ret);
1474502b33a5SToomas Soome
1475199767f8SToomas Soome if (verbose) {
1476199767f8SToomas Soome return (spa_all_status());
1477199767f8SToomas Soome }
1478199767f8SToomas Soome STAILQ_FOREACH(spa, &zfs_pools, spa_link) {
1479b713c91eSToomas Soome snprintf(line, sizeof (line), " zfs:%s\n", spa->spa_name);
1480199767f8SToomas Soome ret = pager_output(line);
1481199767f8SToomas Soome if (ret != 0)
1482199767f8SToomas Soome break;
1483199767f8SToomas Soome }
1484199767f8SToomas Soome return (ret);
1485199767f8SToomas Soome }
1486199767f8SToomas Soome
1487199767f8SToomas Soome /*
1488199767f8SToomas Soome * Attempt to open the pool described by (dev) for use by (f).
1489199767f8SToomas Soome */
1490199767f8SToomas Soome static int
zfs_dev_open(struct open_file * f,...)1491199767f8SToomas Soome zfs_dev_open(struct open_file *f, ...)
1492199767f8SToomas Soome {
1493199767f8SToomas Soome va_list args;
1494199767f8SToomas Soome struct zfs_devdesc *dev;
1495199767f8SToomas Soome struct zfsmount *mount;
1496199767f8SToomas Soome spa_t *spa;
1497199767f8SToomas Soome int rv;
1498199767f8SToomas Soome
1499199767f8SToomas Soome va_start(args, f);
1500199767f8SToomas Soome dev = va_arg(args, struct zfs_devdesc *);
1501199767f8SToomas Soome va_end(args);
1502199767f8SToomas Soome
1503b713c91eSToomas Soome if ((spa = spa_find_by_dev(dev)) == NULL)
1504199767f8SToomas Soome return (ENXIO);
1505b713c91eSToomas Soome
1506777db879SToomas Soome mount = malloc(sizeof (*mount));
1507777db879SToomas Soome if (mount == NULL)
1508777db879SToomas Soome rv = ENOMEM;
1509777db879SToomas Soome else
1510777db879SToomas Soome rv = zfs_mount(spa, dev->root_guid, mount);
1511199767f8SToomas Soome if (rv != 0) {
1512199767f8SToomas Soome free(mount);
1513199767f8SToomas Soome return (rv);
1514199767f8SToomas Soome }
1515199767f8SToomas Soome if (mount->objset.os_type != DMU_OST_ZFS) {
1516199767f8SToomas Soome printf("Unexpected object set type %ju\n",
1517199767f8SToomas Soome (uintmax_t)mount->objset.os_type);
1518199767f8SToomas Soome free(mount);
1519199767f8SToomas Soome return (EIO);
1520199767f8SToomas Soome }
1521199767f8SToomas Soome f->f_devdata = mount;
1522199767f8SToomas Soome free(dev);
1523199767f8SToomas Soome return (0);
1524199767f8SToomas Soome }
1525199767f8SToomas Soome
1526199767f8SToomas Soome static int
zfs_dev_close(struct open_file * f)1527199767f8SToomas Soome zfs_dev_close(struct open_file *f)
1528199767f8SToomas Soome {
1529199767f8SToomas Soome
1530199767f8SToomas Soome free(f->f_devdata);
1531199767f8SToomas Soome f->f_devdata = NULL;
1532199767f8SToomas Soome return (0);
1533199767f8SToomas Soome }
1534199767f8SToomas Soome
1535199767f8SToomas Soome static int
zfs_dev_strategy(void * devdata __unused,int rw __unused,daddr_t dblk __unused,size_t size __unused,char * buf __unused,size_t * rsize __unused)15368eef2ab6SToomas Soome zfs_dev_strategy(void *devdata __unused, int rw __unused,
15378eef2ab6SToomas Soome daddr_t dblk __unused, size_t size __unused,
15388eef2ab6SToomas Soome char *buf __unused, size_t *rsize __unused)
1539199767f8SToomas Soome {
1540199767f8SToomas Soome
1541199767f8SToomas Soome return (ENOSYS);
1542199767f8SToomas Soome }
1543199767f8SToomas Soome
1544199767f8SToomas Soome struct devsw zfs_dev = {
1545199767f8SToomas Soome .dv_name = "zfs",
1546199767f8SToomas Soome .dv_type = DEVT_ZFS,
1547199767f8SToomas Soome .dv_init = zfs_dev_init,
1548199767f8SToomas Soome .dv_strategy = zfs_dev_strategy,
1549199767f8SToomas Soome .dv_open = zfs_dev_open,
1550199767f8SToomas Soome .dv_close = zfs_dev_close,
1551199767f8SToomas Soome .dv_ioctl = noioctl,
1552199767f8SToomas Soome .dv_print = zfs_dev_print,
1553199767f8SToomas Soome .dv_cleanup = NULL
1554199767f8SToomas Soome };
1555199767f8SToomas Soome
1556199767f8SToomas Soome int
zfs_parsedev(struct zfs_devdesc * dev,const char * devspec,const char ** path)1557199767f8SToomas Soome zfs_parsedev(struct zfs_devdesc *dev, const char *devspec, const char **path)
1558199767f8SToomas Soome {
1559199767f8SToomas Soome static char rootname[ZFS_MAXNAMELEN];
1560199767f8SToomas Soome static char poolname[ZFS_MAXNAMELEN];
1561199767f8SToomas Soome spa_t *spa;
1562199767f8SToomas Soome const char *end;
1563199767f8SToomas Soome const char *np;
1564199767f8SToomas Soome const char *sep;
1565199767f8SToomas Soome int rv;
1566199767f8SToomas Soome
1567199767f8SToomas Soome np = devspec;
1568199767f8SToomas Soome if (*np != ':')
1569199767f8SToomas Soome return (EINVAL);
1570199767f8SToomas Soome np++;
15716f01cc52SToomas Soome end = strrchr(np, ':');
1572199767f8SToomas Soome if (end == NULL)
1573199767f8SToomas Soome return (EINVAL);
1574199767f8SToomas Soome sep = strchr(np, '/');
1575199767f8SToomas Soome if (sep == NULL || sep >= end)
1576199767f8SToomas Soome sep = end;
1577199767f8SToomas Soome memcpy(poolname, np, sep - np);
1578199767f8SToomas Soome poolname[sep - np] = '\0';
1579199767f8SToomas Soome if (sep < end) {
1580199767f8SToomas Soome sep++;
1581199767f8SToomas Soome memcpy(rootname, sep, end - sep);
1582199767f8SToomas Soome rootname[end - sep] = '\0';
1583199767f8SToomas Soome }
1584199767f8SToomas Soome else
1585199767f8SToomas Soome rootname[0] = '\0';
1586199767f8SToomas Soome
1587199767f8SToomas Soome spa = spa_find_by_name(poolname);
1588199767f8SToomas Soome if (!spa)
1589199767f8SToomas Soome return (ENXIO);
1590199767f8SToomas Soome dev->pool_guid = spa->spa_guid;
1591199767f8SToomas Soome rv = zfs_lookup_dataset(spa, rootname, &dev->root_guid);
1592199767f8SToomas Soome if (rv != 0)
1593199767f8SToomas Soome return (rv);
1594199767f8SToomas Soome if (path != NULL)
1595199767f8SToomas Soome *path = (*end == '\0') ? end : end + 1;
159676b35943SToomas Soome dev->dd.d_dev = &zfs_dev;
1597199767f8SToomas Soome return (0);
1598199767f8SToomas Soome }
1599199767f8SToomas Soome
1600199767f8SToomas Soome char *
zfs_bootfs(void * zdev)1601199767f8SToomas Soome zfs_bootfs(void *zdev)
1602199767f8SToomas Soome {
1603199767f8SToomas Soome static char rootname[ZFS_MAXNAMELEN];
1604199767f8SToomas Soome static char buf[2 * ZFS_MAXNAMELEN];
1605199767f8SToomas Soome struct zfs_devdesc *dev = (struct zfs_devdesc *)zdev;
1606199767f8SToomas Soome uint64_t objnum;
1607199767f8SToomas Soome spa_t *spa;
1608199767f8SToomas Soome int n;
1609199767f8SToomas Soome
1610199767f8SToomas Soome buf[0] = '\0';
1611c142ce19SToomas Soome if (dev->dd.d_dev->dv_type != DEVT_ZFS)
1612199767f8SToomas Soome return (buf);
1613199767f8SToomas Soome
1614199767f8SToomas Soome spa = spa_find_by_guid(dev->pool_guid);
1615199767f8SToomas Soome if (spa == NULL) {
1616199767f8SToomas Soome printf("ZFS: can't find pool by guid\n");
1617199767f8SToomas Soome return (buf);
1618199767f8SToomas Soome }
1619199767f8SToomas Soome if (zfs_rlookup(spa, dev->root_guid, rootname)) {
1620199767f8SToomas Soome printf("ZFS: can't find filesystem by guid\n");
1621199767f8SToomas Soome return (buf);
1622199767f8SToomas Soome }
1623199767f8SToomas Soome if (zfs_lookup_dataset(spa, rootname, &objnum)) {
1624199767f8SToomas Soome printf("ZFS: can't find filesystem by name\n");
1625199767f8SToomas Soome return (buf);
1626199767f8SToomas Soome }
1627199767f8SToomas Soome
16286369122cSToomas Soome /* Set the environment. */
1629f6dea603SToomas Soome snprintf(buf, sizeof (buf), "%" PRIu64, dev->pool_guid);
1630f6dea603SToomas Soome setenv("zfs-bootpool", buf, 1);
1631f6dea603SToomas Soome snprintf(buf, sizeof (buf), "%" PRIu64, spa->spa_boot_vdev->v_guid);
1632f6dea603SToomas Soome setenv("zfs-bootvdev", buf, 1);
1633f6dea603SToomas Soome snprintf(buf, sizeof (buf), "%s/%" PRIu64, spa->spa_name, objnum);
16346369122cSToomas Soome setenv("zfs-bootfs", buf, 1);
163545137058SToomas Soome if (spa->spa_boot_vdev->v_phys_path != NULL)
163645137058SToomas Soome setenv("bootpath", spa->spa_boot_vdev->v_phys_path, 1);
163745137058SToomas Soome if (spa->spa_boot_vdev->v_devid != NULL)
163845137058SToomas Soome setenv("diskdevid", spa->spa_boot_vdev->v_devid, 1);
16396369122cSToomas Soome
16406369122cSToomas Soome /*
16416369122cSToomas Soome * Build the command line string. Once our kernel will read
16426369122cSToomas Soome * the environment and we can stop caring about old kernels,
16436369122cSToomas Soome * we can remove this part.
16446369122cSToomas Soome */
1645fec66293SToomas Soome snprintf(buf, sizeof (buf), "zfs-bootfs=%s/%" PRIu64, spa->spa_name,
1646f6dea603SToomas Soome objnum);
1647199767f8SToomas Soome n = strlen(buf);
164845137058SToomas Soome if (spa->spa_boot_vdev->v_phys_path != NULL) {
16496369122cSToomas Soome snprintf(buf+n, sizeof (buf) - n, ",bootpath=\"%s\"",
165045137058SToomas Soome spa->spa_boot_vdev->v_phys_path);
1651199767f8SToomas Soome n = strlen(buf);
1652199767f8SToomas Soome }
165345137058SToomas Soome if (spa->spa_boot_vdev->v_devid != NULL) {
16546369122cSToomas Soome snprintf(buf+n, sizeof (buf) - n, ",diskdevid=\"%s\"",
165545137058SToomas Soome spa->spa_boot_vdev->v_devid);
1656199767f8SToomas Soome }
1657199767f8SToomas Soome return (buf);
1658199767f8SToomas Soome }
1659199767f8SToomas Soome
1660199767f8SToomas Soome char *
zfs_fmtdev(void * vdev)1661199767f8SToomas Soome zfs_fmtdev(void *vdev)
1662199767f8SToomas Soome {
1663199767f8SToomas Soome static char rootname[ZFS_MAXNAMELEN];
1664199767f8SToomas Soome static char buf[2 * ZFS_MAXNAMELEN + 8];
1665199767f8SToomas Soome struct zfs_devdesc *dev = (struct zfs_devdesc *)vdev;
1666199767f8SToomas Soome spa_t *spa;
1667199767f8SToomas Soome
1668199767f8SToomas Soome buf[0] = '\0';
1669c142ce19SToomas Soome if (dev->dd.d_dev->dv_type != DEVT_ZFS)
1670199767f8SToomas Soome return (buf);
1671199767f8SToomas Soome
1672c2e9ac5cSToomas Soome /* Do we have any pools? */
1673c2e9ac5cSToomas Soome spa = STAILQ_FIRST(&zfs_pools);
1674c2e9ac5cSToomas Soome if (spa == NULL)
1675c2e9ac5cSToomas Soome return (buf);
1676c2e9ac5cSToomas Soome
1677c2e9ac5cSToomas Soome if (dev->pool_guid == 0)
1678199767f8SToomas Soome dev->pool_guid = spa->spa_guid;
1679c2e9ac5cSToomas Soome else
1680199767f8SToomas Soome spa = spa_find_by_guid(dev->pool_guid);
1681c2e9ac5cSToomas Soome
1682199767f8SToomas Soome if (spa == NULL) {
1683199767f8SToomas Soome printf("ZFS: can't find pool by guid\n");
1684199767f8SToomas Soome return (buf);
1685199767f8SToomas Soome }
1686199767f8SToomas Soome if (dev->root_guid == 0 && zfs_get_root(spa, &dev->root_guid)) {
1687199767f8SToomas Soome printf("ZFS: can't find root filesystem\n");
1688199767f8SToomas Soome return (buf);
1689199767f8SToomas Soome }
1690199767f8SToomas Soome if (zfs_rlookup(spa, dev->root_guid, rootname)) {
1691199767f8SToomas Soome printf("ZFS: can't find filesystem by guid\n");
1692199767f8SToomas Soome return (buf);
1693199767f8SToomas Soome }
1694199767f8SToomas Soome
1695199767f8SToomas Soome if (rootname[0] == '\0')
1696b713c91eSToomas Soome snprintf(buf, sizeof (buf), "%s:%s:", dev->dd.d_dev->dv_name,
1697b713c91eSToomas Soome spa->spa_name);
1698199767f8SToomas Soome else
1699b713c91eSToomas Soome snprintf(buf, sizeof (buf), "%s:%s/%s:", dev->dd.d_dev->dv_name,
1700b713c91eSToomas Soome spa->spa_name, rootname);
1701199767f8SToomas Soome return (buf);
1702199767f8SToomas Soome }
1703199767f8SToomas Soome
1704199767f8SToomas Soome int
zfs_list(const char * name)1705199767f8SToomas Soome zfs_list(const char *name)
1706199767f8SToomas Soome {
1707199767f8SToomas Soome static char poolname[ZFS_MAXNAMELEN];
1708199767f8SToomas Soome uint64_t objid;
1709199767f8SToomas Soome spa_t *spa;
1710199767f8SToomas Soome const char *dsname;
1711199767f8SToomas Soome int len;
1712199767f8SToomas Soome int rv;
1713199767f8SToomas Soome
1714199767f8SToomas Soome len = strlen(name);
1715199767f8SToomas Soome dsname = strchr(name, '/');
1716199767f8SToomas Soome if (dsname != NULL) {
1717199767f8SToomas Soome len = dsname - name;
1718199767f8SToomas Soome dsname++;
1719199767f8SToomas Soome } else
1720199767f8SToomas Soome dsname = "";
1721199767f8SToomas Soome memcpy(poolname, name, len);
1722199767f8SToomas Soome poolname[len] = '\0';
1723199767f8SToomas Soome
1724199767f8SToomas Soome spa = spa_find_by_name(poolname);
1725199767f8SToomas Soome if (!spa)
1726199767f8SToomas Soome return (ENXIO);
1727199767f8SToomas Soome rv = zfs_lookup_dataset(spa, dsname, &objid);
1728199767f8SToomas Soome if (rv != 0)
1729199767f8SToomas Soome return (rv);
1730199767f8SToomas Soome
1731199767f8SToomas Soome return (zfs_list_dataset(spa, objid));
1732199767f8SToomas Soome }
1733