Index: stable/11/stand/zfs32/Makefile =================================================================== --- stable/11/stand/zfs32/Makefile (revision 344376) +++ stable/11/stand/zfs32/Makefile (nonexistent) @@ -1,5 +0,0 @@ -# $FreeBSD$ - -DO32=1 - -.include "${.CURDIR}/../zfs/Makefile" Property changes on: stable/11/stand/zfs32/Makefile ___________________________________________________________________ Deleted: svn:eol-style ## -1 +0,0 ## -native \ No newline at end of property Deleted: svn:keywords ## -1 +0,0 ## -FreeBSD=%H \ No newline at end of property Deleted: svn:mime-type ## -1 +0,0 ## -text/plain \ No newline at end of property Index: stable/11/stand/zfs/Makefile.depend =================================================================== --- stable/11/stand/zfs/Makefile.depend (revision 344376) +++ stable/11/stand/zfs/Makefile.depend (nonexistent) @@ -1,13 +0,0 @@ -# $FreeBSD$ -# Autogenerated - do NOT edit! - -DIRDEPS = \ - include \ - include/xlocale \ - - -.include - -.if ${DEP_RELDIR} == ${_DEP_RELDIR} -# local dependencies - needed for -jN in clean tree -.endif Property changes on: stable/11/stand/zfs/Makefile.depend ___________________________________________________________________ Deleted: svn:eol-style ## -1 +0,0 ## -native \ No newline at end of property Deleted: svn:keywords ## -1 +0,0 ## -FreeBSD=%H \ No newline at end of property Deleted: svn:mime-type ## -1 +0,0 ## -text/plain \ No newline at end of property Index: stable/11/stand/zfs/zfs.c =================================================================== --- stable/11/stand/zfs/zfs.c (revision 344376) +++ stable/11/stand/zfs/zfs.c (nonexistent) @@ -1,1002 +0,0 @@ -/*- - * Copyright (c) 2007 Doug Rabson - * All rights reserved. - * - * Redistribution and use in source and binary forms, with or without - * modification, are permitted provided that the following conditions - * are met: - * 1. Redistributions of source code must retain the above copyright - * notice, this list of conditions and the following disclaimer. - * 2. Redistributions in binary form must reproduce the above copyright - * notice, this list of conditions and the following disclaimer in the - * documentation and/or other materials provided with the distribution. - * - * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND - * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE - * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE - * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE - * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL - * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS - * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) - * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT - * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY - * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF - * SUCH DAMAGE. - * - * $FreeBSD$ - */ - -#include -__FBSDID("$FreeBSD$"); - -/* - * Stand-alone file reading package. - */ - -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include - -#include "libzfs.h" - -#include "zfsimpl.c" - -/* Define the range of indexes to be populated with ZFS Boot Environments */ -#define ZFS_BE_FIRST 4 -#define ZFS_BE_LAST 8 - -static int zfs_open(const char *path, struct open_file *f); -static int zfs_close(struct open_file *f); -static int zfs_read(struct open_file *f, void *buf, size_t size, size_t *resid); -static off_t zfs_seek(struct open_file *f, off_t offset, int where); -static int zfs_stat(struct open_file *f, struct stat *sb); -static int zfs_readdir(struct open_file *f, struct dirent *d); - -static void zfs_bootenv_initial(const char *); - -struct devsw zfs_dev; - -struct fs_ops zfs_fsops = { - "zfs", - zfs_open, - zfs_close, - zfs_read, - null_write, - zfs_seek, - zfs_stat, - zfs_readdir -}; - -/* - * In-core open file. - */ -struct file { - off_t f_seekp; /* seek pointer */ - dnode_phys_t f_dnode; - uint64_t f_zap_type; /* zap type for readdir */ - uint64_t f_num_leafs; /* number of fzap leaf blocks */ - zap_leaf_phys_t *f_zap_leaf; /* zap leaf buffer */ -}; - -static int zfs_env_index; -static int zfs_env_count; - -SLIST_HEAD(zfs_be_list, zfs_be_entry) zfs_be_head = SLIST_HEAD_INITIALIZER(zfs_be_head); -struct zfs_be_list *zfs_be_headp; -struct zfs_be_entry { - const char *name; - SLIST_ENTRY(zfs_be_entry) entries; -} *zfs_be, *zfs_be_tmp; - -/* - * Open a file. - */ -static int -zfs_open(const char *upath, struct open_file *f) -{ - struct zfsmount *mount = (struct zfsmount *)f->f_devdata; - struct file *fp; - int rc; - - if (f->f_dev != &zfs_dev) - return (EINVAL); - - /* allocate file system specific data structure */ - fp = malloc(sizeof(struct file)); - bzero(fp, sizeof(struct file)); - f->f_fsdata = (void *)fp; - - rc = zfs_lookup(mount, upath, &fp->f_dnode); - fp->f_seekp = 0; - if (rc) { - f->f_fsdata = NULL; - free(fp); - } - return (rc); -} - -static int -zfs_close(struct open_file *f) -{ - struct file *fp = (struct file *)f->f_fsdata; - - dnode_cache_obj = NULL; - f->f_fsdata = (void *)0; - if (fp == (struct file *)0) - return (0); - - free(fp); - return (0); -} - -/* - * Copy a portion of a file into kernel memory. - * Cross block boundaries when necessary. - */ -static int -zfs_read(struct open_file *f, void *start, size_t size, size_t *resid /* out */) -{ - const spa_t *spa = ((struct zfsmount *)f->f_devdata)->spa; - struct file *fp = (struct file *)f->f_fsdata; - struct stat sb; - size_t n; - int rc; - - rc = zfs_stat(f, &sb); - if (rc) - return (rc); - n = size; - if (fp->f_seekp + n > sb.st_size) - n = sb.st_size - fp->f_seekp; - - rc = dnode_read(spa, &fp->f_dnode, fp->f_seekp, start, n); - if (rc) - return (rc); - - if (0) { - int i; - for (i = 0; i < n; i++) - putchar(((char*) start)[i]); - } - fp->f_seekp += n; - if (resid) - *resid = size - n; - - return (0); -} - -static off_t -zfs_seek(struct open_file *f, off_t offset, int where) -{ - struct file *fp = (struct file *)f->f_fsdata; - - switch (where) { - case SEEK_SET: - fp->f_seekp = offset; - break; - case SEEK_CUR: - fp->f_seekp += offset; - break; - case SEEK_END: - { - struct stat sb; - int error; - - error = zfs_stat(f, &sb); - if (error != 0) { - errno = error; - return (-1); - } - fp->f_seekp = sb.st_size - offset; - break; - } - default: - errno = EINVAL; - return (-1); - } - return (fp->f_seekp); -} - -static int -zfs_stat(struct open_file *f, struct stat *sb) -{ - const spa_t *spa = ((struct zfsmount *)f->f_devdata)->spa; - struct file *fp = (struct file *)f->f_fsdata; - - return (zfs_dnode_stat(spa, &fp->f_dnode, sb)); -} - -static int -zfs_readdir(struct open_file *f, struct dirent *d) -{ - const spa_t *spa = ((struct zfsmount *)f->f_devdata)->spa; - struct file *fp = (struct file *)f->f_fsdata; - mzap_ent_phys_t mze; - struct stat sb; - size_t bsize = fp->f_dnode.dn_datablkszsec << SPA_MINBLOCKSHIFT; - int rc; - - rc = zfs_stat(f, &sb); - if (rc) - return (rc); - if (!S_ISDIR(sb.st_mode)) - return (ENOTDIR); - - /* - * If this is the first read, get the zap type. - */ - if (fp->f_seekp == 0) { - rc = dnode_read(spa, &fp->f_dnode, - 0, &fp->f_zap_type, sizeof(fp->f_zap_type)); - if (rc) - return (rc); - - if (fp->f_zap_type == ZBT_MICRO) { - fp->f_seekp = offsetof(mzap_phys_t, mz_chunk); - } else { - rc = dnode_read(spa, &fp->f_dnode, - offsetof(zap_phys_t, zap_num_leafs), - &fp->f_num_leafs, - sizeof(fp->f_num_leafs)); - if (rc) - return (rc); - - fp->f_seekp = bsize; - fp->f_zap_leaf = (zap_leaf_phys_t *)malloc(bsize); - rc = dnode_read(spa, &fp->f_dnode, - fp->f_seekp, - fp->f_zap_leaf, - bsize); - if (rc) - return (rc); - } - } - - if (fp->f_zap_type == ZBT_MICRO) { - mzap_next: - if (fp->f_seekp >= bsize) - return (ENOENT); - - rc = dnode_read(spa, &fp->f_dnode, - fp->f_seekp, &mze, sizeof(mze)); - if (rc) - return (rc); - fp->f_seekp += sizeof(mze); - - if (!mze.mze_name[0]) - goto mzap_next; - - d->d_fileno = ZFS_DIRENT_OBJ(mze.mze_value); - d->d_type = ZFS_DIRENT_TYPE(mze.mze_value); - strcpy(d->d_name, mze.mze_name); - d->d_namlen = strlen(d->d_name); - return (0); - } else { - zap_leaf_t zl; - zap_leaf_chunk_t *zc, *nc; - int chunk; - size_t namelen; - char *p; - uint64_t value; - - /* - * Initialise this so we can use the ZAP size - * calculating macros. - */ - zl.l_bs = ilog2(bsize); - zl.l_phys = fp->f_zap_leaf; - - /* - * Figure out which chunk we are currently looking at - * and consider seeking to the next leaf. We use the - * low bits of f_seekp as a simple chunk index. - */ - fzap_next: - chunk = fp->f_seekp & (bsize - 1); - if (chunk == ZAP_LEAF_NUMCHUNKS(&zl)) { - fp->f_seekp = rounddown2(fp->f_seekp, bsize) + bsize; - chunk = 0; - - /* - * Check for EOF and read the new leaf. - */ - if (fp->f_seekp >= bsize * fp->f_num_leafs) - return (ENOENT); - - rc = dnode_read(spa, &fp->f_dnode, - fp->f_seekp, - fp->f_zap_leaf, - bsize); - if (rc) - return (rc); - } - - zc = &ZAP_LEAF_CHUNK(&zl, chunk); - fp->f_seekp++; - if (zc->l_entry.le_type != ZAP_CHUNK_ENTRY) - goto fzap_next; - - namelen = zc->l_entry.le_name_numints; - if (namelen > sizeof(d->d_name)) - namelen = sizeof(d->d_name); - - /* - * Paste the name back together. - */ - nc = &ZAP_LEAF_CHUNK(&zl, zc->l_entry.le_name_chunk); - p = d->d_name; - while (namelen > 0) { - int len; - len = namelen; - if (len > ZAP_LEAF_ARRAY_BYTES) - len = ZAP_LEAF_ARRAY_BYTES; - memcpy(p, nc->l_array.la_array, len); - p += len; - namelen -= len; - nc = &ZAP_LEAF_CHUNK(&zl, nc->l_array.la_next); - } - d->d_name[sizeof(d->d_name) - 1] = 0; - - /* - * Assume the first eight bytes of the value are - * a uint64_t. - */ - value = fzap_leaf_value(&zl, zc); - - d->d_fileno = ZFS_DIRENT_OBJ(value); - d->d_type = ZFS_DIRENT_TYPE(value); - d->d_namlen = strlen(d->d_name); - - return (0); - } -} - -static int -vdev_read(vdev_t *vdev, void *priv, off_t offset, void *buf, size_t bytes) -{ - int fd, ret; - size_t res, size, remainder, rb_size, blksz; - unsigned secsz; - off_t off; - char *bouncebuf, *rb_buf; - - fd = (uintptr_t) priv; - bouncebuf = NULL; - - ret = ioctl(fd, DIOCGSECTORSIZE, &secsz); - if (ret != 0) - return (ret); - - off = offset / secsz; - remainder = offset % secsz; - if (lseek(fd, off * secsz, SEEK_SET) == -1) - return (errno); - - rb_buf = buf; - rb_size = bytes; - size = roundup2(bytes + remainder, secsz); - blksz = size; - if (remainder != 0 || size != bytes) { - bouncebuf = zfs_alloc(secsz); - if (bouncebuf == NULL) { - printf("vdev_read: out of memory\n"); - return (ENOMEM); - } - rb_buf = bouncebuf; - blksz = rb_size - remainder; - } - - while (bytes > 0) { - res = read(fd, rb_buf, rb_size); - if (res != rb_size) { - ret = EIO; - goto error; - } - if (bytes < blksz) - blksz = bytes; - if (bouncebuf != NULL) - memcpy(buf, rb_buf + remainder, blksz); - buf = (void *)((uintptr_t)buf + blksz); - bytes -= blksz; - remainder = 0; - blksz = rb_size; - } - - ret = 0; -error: - if (bouncebuf != NULL) - zfs_free(bouncebuf, secsz); - return (ret); -} - -static int -zfs_dev_init(void) -{ - spa_t *spa; - spa_t *next; - spa_t *prev; - - zfs_init(); - if (archsw.arch_zfs_probe == NULL) - return (ENXIO); - archsw.arch_zfs_probe(); - - prev = NULL; - spa = STAILQ_FIRST(&zfs_pools); - while (spa != NULL) { - next = STAILQ_NEXT(spa, spa_link); - if (zfs_spa_init(spa)) { - if (prev == NULL) - STAILQ_REMOVE_HEAD(&zfs_pools, spa_link); - else - STAILQ_REMOVE_AFTER(&zfs_pools, prev, spa_link); - } else - prev = spa; - spa = next; - } - return (0); -} - -struct zfs_probe_args { - int fd; - const char *devname; - uint64_t *pool_guid; - u_int secsz; -}; - -static int -zfs_diskread(void *arg, void *buf, size_t blocks, uint64_t offset) -{ - struct zfs_probe_args *ppa; - - ppa = (struct zfs_probe_args *)arg; - return (vdev_read(NULL, (void *)(uintptr_t)ppa->fd, - offset * ppa->secsz, buf, blocks * ppa->secsz)); -} - -static int -zfs_probe(int fd, uint64_t *pool_guid) -{ - spa_t *spa; - int ret; - - ret = vdev_probe(vdev_read, (void *)(uintptr_t)fd, &spa); - if (ret == 0 && pool_guid != NULL) - *pool_guid = spa->spa_guid; - return (ret); -} - -static int -zfs_probe_partition(void *arg, const char *partname, - const struct ptable_entry *part) -{ - struct zfs_probe_args *ppa, pa; - struct ptable *table; - char devname[32]; - int ret; - - /* Probe only freebsd-zfs and freebsd partitions */ - if (part->type != PART_FREEBSD && - part->type != PART_FREEBSD_ZFS) - return (0); - - ppa = (struct zfs_probe_args *)arg; - strncpy(devname, ppa->devname, strlen(ppa->devname) - 1); - devname[strlen(ppa->devname) - 1] = '\0'; - sprintf(devname, "%s%s:", devname, partname); - pa.fd = open(devname, O_RDONLY); - if (pa.fd == -1) - return (0); - ret = zfs_probe(pa.fd, ppa->pool_guid); - if (ret == 0) - return (0); - /* Do we have BSD label here? */ - if (part->type == PART_FREEBSD) { - pa.devname = devname; - pa.pool_guid = ppa->pool_guid; - pa.secsz = ppa->secsz; - table = ptable_open(&pa, part->end - part->start + 1, - ppa->secsz, zfs_diskread); - if (table != NULL) { - ptable_iterate(table, &pa, zfs_probe_partition); - ptable_close(table); - } - } - close(pa.fd); - return (0); -} - -int -zfs_probe_dev(const char *devname, uint64_t *pool_guid) -{ - struct ptable *table; - struct zfs_probe_args pa; - uint64_t mediasz; - int ret; - - if (pool_guid) - *pool_guid = 0; - pa.fd = open(devname, O_RDONLY); - if (pa.fd == -1) - return (ENXIO); - /* Probe the whole disk */ - ret = zfs_probe(pa.fd, pool_guid); - if (ret == 0) - return (0); - - /* Probe each partition */ - ret = ioctl(pa.fd, DIOCGMEDIASIZE, &mediasz); - if (ret == 0) - ret = ioctl(pa.fd, DIOCGSECTORSIZE, &pa.secsz); - if (ret == 0) { - pa.devname = devname; - pa.pool_guid = pool_guid; - table = ptable_open(&pa, mediasz / pa.secsz, pa.secsz, - zfs_diskread); - if (table != NULL) { - ptable_iterate(table, &pa, zfs_probe_partition); - ptable_close(table); - } - } - close(pa.fd); - if (pool_guid && *pool_guid == 0) - ret = ENXIO; - return (ret); -} - -/* - * Print information about ZFS pools - */ -static int -zfs_dev_print(int verbose) -{ - spa_t *spa; - char line[80]; - int ret = 0; - - if (STAILQ_EMPTY(&zfs_pools)) - return (0); - - printf("%s devices:", zfs_dev.dv_name); - if ((ret = pager_output("\n")) != 0) - return (ret); - - if (verbose) { - return (spa_all_status()); - } - STAILQ_FOREACH(spa, &zfs_pools, spa_link) { - snprintf(line, sizeof(line), " zfs:%s\n", spa->spa_name); - ret = pager_output(line); - if (ret != 0) - break; - } - return (ret); -} - -/* - * Attempt to open the pool described by (dev) for use by (f). - */ -static int -zfs_dev_open(struct open_file *f, ...) -{ - va_list args; - struct zfs_devdesc *dev; - struct zfsmount *mount; - spa_t *spa; - int rv; - - va_start(args, f); - dev = va_arg(args, struct zfs_devdesc *); - va_end(args); - - if (dev->pool_guid == 0) - spa = STAILQ_FIRST(&zfs_pools); - else - spa = spa_find_by_guid(dev->pool_guid); - if (!spa) - return (ENXIO); - mount = malloc(sizeof(*mount)); - rv = zfs_mount(spa, dev->root_guid, mount); - if (rv != 0) { - free(mount); - return (rv); - } - if (mount->objset.os_type != DMU_OST_ZFS) { - printf("Unexpected object set type %ju\n", - (uintmax_t)mount->objset.os_type); - free(mount); - return (EIO); - } - f->f_devdata = mount; - free(dev); - return (0); -} - -static int -zfs_dev_close(struct open_file *f) -{ - - free(f->f_devdata); - f->f_devdata = NULL; - return (0); -} - -static int -zfs_dev_strategy(void *devdata, int rw, daddr_t dblk, size_t size, char *buf, size_t *rsize) -{ - - return (ENOSYS); -} - -struct devsw zfs_dev = { - .dv_name = "zfs", - .dv_type = DEVT_ZFS, - .dv_init = zfs_dev_init, - .dv_strategy = zfs_dev_strategy, - .dv_open = zfs_dev_open, - .dv_close = zfs_dev_close, - .dv_ioctl = noioctl, - .dv_print = zfs_dev_print, - .dv_cleanup = NULL -}; - -int -zfs_parsedev(struct zfs_devdesc *dev, const char *devspec, const char **path) -{ - static char rootname[ZFS_MAXNAMELEN]; - static char poolname[ZFS_MAXNAMELEN]; - spa_t *spa; - const char *end; - const char *np; - const char *sep; - int rv; - - np = devspec; - if (*np != ':') - return (EINVAL); - np++; - end = strrchr(np, ':'); - if (end == NULL) - return (EINVAL); - sep = strchr(np, '/'); - if (sep == NULL || sep >= end) - sep = end; - memcpy(poolname, np, sep - np); - poolname[sep - np] = '\0'; - if (sep < end) { - sep++; - memcpy(rootname, sep, end - sep); - rootname[end - sep] = '\0'; - } - else - rootname[0] = '\0'; - - spa = spa_find_by_name(poolname); - if (!spa) - return (ENXIO); - dev->pool_guid = spa->spa_guid; - rv = zfs_lookup_dataset(spa, rootname, &dev->root_guid); - if (rv != 0) - return (rv); - if (path != NULL) - *path = (*end == '\0') ? end : end + 1; - dev->dd.d_dev = &zfs_dev; - return (0); -} - -char * -zfs_fmtdev(void *vdev) -{ - static char rootname[ZFS_MAXNAMELEN]; - static char buf[2 * ZFS_MAXNAMELEN + 8]; - struct zfs_devdesc *dev = (struct zfs_devdesc *)vdev; - spa_t *spa; - - buf[0] = '\0'; - if (dev->dd.d_dev->dv_type != DEVT_ZFS) - return (buf); - - if (dev->pool_guid == 0) { - spa = STAILQ_FIRST(&zfs_pools); - dev->pool_guid = spa->spa_guid; - } else - spa = spa_find_by_guid(dev->pool_guid); - if (spa == NULL) { - printf("ZFS: can't find pool by guid\n"); - return (buf); - } - if (dev->root_guid == 0 && zfs_get_root(spa, &dev->root_guid)) { - printf("ZFS: can't find root filesystem\n"); - return (buf); - } - if (zfs_rlookup(spa, dev->root_guid, rootname)) { - printf("ZFS: can't find filesystem by guid\n"); - return (buf); - } - - if (rootname[0] == '\0') - sprintf(buf, "%s:%s:", dev->dd.d_dev->dv_name, spa->spa_name); - else - sprintf(buf, "%s:%s/%s:", dev->dd.d_dev->dv_name, spa->spa_name, - rootname); - return (buf); -} - -int -zfs_list(const char *name) -{ - static char poolname[ZFS_MAXNAMELEN]; - uint64_t objid; - spa_t *spa; - const char *dsname; - int len; - int rv; - - len = strlen(name); - dsname = strchr(name, '/'); - if (dsname != NULL) { - len = dsname - name; - dsname++; - } else - dsname = ""; - memcpy(poolname, name, len); - poolname[len] = '\0'; - - spa = spa_find_by_name(poolname); - if (!spa) - return (ENXIO); - rv = zfs_lookup_dataset(spa, dsname, &objid); - if (rv != 0) - return (rv); - - return (zfs_list_dataset(spa, objid)); -} - -void -init_zfs_bootenv(const char *currdev_in) -{ - char *beroot, *currdev; - int currdev_len; - - currdev = NULL; - currdev_len = strlen(currdev_in); - if (currdev_len == 0) - return; - if (strncmp(currdev_in, "zfs:", 4) != 0) - return; - currdev = strdup(currdev_in); - if (currdev == NULL) - return; - /* Remove the trailing : */ - currdev[currdev_len - 1] = '\0'; - setenv("zfs_be_active", currdev, 1); - setenv("zfs_be_currpage", "1", 1); - /* Remove the last element (current bootenv) */ - beroot = strrchr(currdev, '/'); - if (beroot != NULL) - beroot[0] = '\0'; - beroot = strchr(currdev, ':') + 1; - setenv("zfs_be_root", beroot, 1); - zfs_bootenv_initial(beroot); - free(currdev); -} - -static void -zfs_bootenv_initial(const char *name) -{ - char poolname[ZFS_MAXNAMELEN], *dsname; - char envname[32], envval[256]; - uint64_t objid; - spa_t *spa; - int bootenvs_idx, len, rv; - - SLIST_INIT(&zfs_be_head); - zfs_env_count = 0; - len = strlen(name); - dsname = strchr(name, '/'); - if (dsname != NULL) { - len = dsname - name; - dsname++; - } else - dsname = ""; - strlcpy(poolname, name, len + 1); - spa = spa_find_by_name(poolname); - if (spa == NULL) - return; - rv = zfs_lookup_dataset(spa, dsname, &objid); - if (rv != 0) - return; - rv = zfs_callback_dataset(spa, objid, zfs_belist_add); - bootenvs_idx = 0; - /* Populate the initial environment variables */ - SLIST_FOREACH_SAFE(zfs_be, &zfs_be_head, entries, zfs_be_tmp) { - /* Enumerate all bootenvs for general usage */ - snprintf(envname, sizeof(envname), "bootenvs[%d]", bootenvs_idx); - snprintf(envval, sizeof(envval), "zfs:%s/%s", name, zfs_be->name); - rv = setenv(envname, envval, 1); - if (rv != 0) - break; - bootenvs_idx++; - } - snprintf(envval, sizeof(envval), "%d", bootenvs_idx); - setenv("bootenvs_count", envval, 1); - - /* Clean up the SLIST of ZFS BEs */ - while (!SLIST_EMPTY(&zfs_be_head)) { - zfs_be = SLIST_FIRST(&zfs_be_head); - SLIST_REMOVE_HEAD(&zfs_be_head, entries); - free(zfs_be); - } - - return; - -} - -int -zfs_bootenv(const char *name) -{ - static char poolname[ZFS_MAXNAMELEN], *dsname, *root; - char becount[4]; - uint64_t objid; - spa_t *spa; - int len, rv, pages, perpage, currpage; - - if (name == NULL) - return (EINVAL); - if ((root = getenv("zfs_be_root")) == NULL) - return (EINVAL); - - if (strcmp(name, root) != 0) { - if (setenv("zfs_be_root", name, 1) != 0) - return (ENOMEM); - } - - SLIST_INIT(&zfs_be_head); - zfs_env_count = 0; - len = strlen(name); - dsname = strchr(name, '/'); - if (dsname != NULL) { - len = dsname - name; - dsname++; - } else - dsname = ""; - memcpy(poolname, name, len); - poolname[len] = '\0'; - - spa = spa_find_by_name(poolname); - if (!spa) - return (ENXIO); - rv = zfs_lookup_dataset(spa, dsname, &objid); - if (rv != 0) - return (rv); - rv = zfs_callback_dataset(spa, objid, zfs_belist_add); - - /* Calculate and store the number of pages of BEs */ - perpage = (ZFS_BE_LAST - ZFS_BE_FIRST + 1); - pages = (zfs_env_count / perpage) + ((zfs_env_count % perpage) > 0 ? 1 : 0); - snprintf(becount, 4, "%d", pages); - if (setenv("zfs_be_pages", becount, 1) != 0) - return (ENOMEM); - - /* Roll over the page counter if it has exceeded the maximum */ - currpage = strtol(getenv("zfs_be_currpage"), NULL, 10); - if (currpage > pages) { - if (setenv("zfs_be_currpage", "1", 1) != 0) - return (ENOMEM); - } - - /* Populate the menu environment variables */ - zfs_set_env(); - - /* Clean up the SLIST of ZFS BEs */ - while (!SLIST_EMPTY(&zfs_be_head)) { - zfs_be = SLIST_FIRST(&zfs_be_head); - SLIST_REMOVE_HEAD(&zfs_be_head, entries); - free(zfs_be); - } - - return (rv); -} - -int -zfs_belist_add(const char *name, uint64_t value __unused) -{ - - /* Skip special datasets that start with a $ character */ - if (strncmp(name, "$", 1) == 0) { - return (0); - } - /* Add the boot environment to the head of the SLIST */ - zfs_be = malloc(sizeof(struct zfs_be_entry)); - if (zfs_be == NULL) { - return (ENOMEM); - } - zfs_be->name = name; - SLIST_INSERT_HEAD(&zfs_be_head, zfs_be, entries); - zfs_env_count++; - - return (0); -} - -int -zfs_set_env(void) -{ - char envname[32], envval[256]; - char *beroot, *pagenum; - int rv, page, ctr; - - beroot = getenv("zfs_be_root"); - if (beroot == NULL) { - return (1); - } - - pagenum = getenv("zfs_be_currpage"); - if (pagenum != NULL) { - page = strtol(pagenum, NULL, 10); - } else { - page = 1; - } - - ctr = 1; - rv = 0; - zfs_env_index = ZFS_BE_FIRST; - SLIST_FOREACH_SAFE(zfs_be, &zfs_be_head, entries, zfs_be_tmp) { - /* Skip to the requested page number */ - if (ctr <= ((ZFS_BE_LAST - ZFS_BE_FIRST + 1) * (page - 1))) { - ctr++; - continue; - } - - snprintf(envname, sizeof(envname), "bootenvmenu_caption[%d]", zfs_env_index); - snprintf(envval, sizeof(envval), "%s", zfs_be->name); - rv = setenv(envname, envval, 1); - if (rv != 0) { - break; - } - - snprintf(envname, sizeof(envname), "bootenvansi_caption[%d]", zfs_env_index); - rv = setenv(envname, envval, 1); - if (rv != 0){ - break; - } - - snprintf(envname, sizeof(envname), "bootenvmenu_command[%d]", zfs_env_index); - rv = setenv(envname, "set_bootenv", 1); - if (rv != 0){ - break; - } - - snprintf(envname, sizeof(envname), "bootenv_root[%d]", zfs_env_index); - snprintf(envval, sizeof(envval), "zfs:%s/%s", beroot, zfs_be->name); - rv = setenv(envname, envval, 1); - if (rv != 0){ - break; - } - - zfs_env_index++; - if (zfs_env_index > ZFS_BE_LAST) { - break; - } - - } - - for (; zfs_env_index <= ZFS_BE_LAST; zfs_env_index++) { - snprintf(envname, sizeof(envname), "bootenvmenu_caption[%d]", zfs_env_index); - (void)unsetenv(envname); - snprintf(envname, sizeof(envname), "bootenvansi_caption[%d]", zfs_env_index); - (void)unsetenv(envname); - snprintf(envname, sizeof(envname), "bootenvmenu_command[%d]", zfs_env_index); - (void)unsetenv(envname); - snprintf(envname, sizeof(envname), "bootenv_root[%d]", zfs_env_index); - (void)unsetenv(envname); - } - - return (rv); -} Property changes on: stable/11/stand/zfs/zfs.c ___________________________________________________________________ Deleted: svn:eol-style ## -1 +0,0 ## -native \ No newline at end of property Deleted: svn:keywords ## -1 +0,0 ## -FreeBSD=%H \ No newline at end of property Deleted: svn:mime-type ## -1 +0,0 ## -text/plain \ No newline at end of property Index: stable/11/stand/zfs/zfsimpl.c =================================================================== --- stable/11/stand/zfs/zfsimpl.c (revision 344376) +++ stable/11/stand/zfs/zfsimpl.c (nonexistent) @@ -1,2537 +0,0 @@ -/*- - * Copyright (c) 2007 Doug Rabson - * All rights reserved. - * - * Redistribution and use in source and binary forms, with or without - * modification, are permitted provided that the following conditions - * are met: - * 1. Redistributions of source code must retain the above copyright - * notice, this list of conditions and the following disclaimer. - * 2. Redistributions in binary form must reproduce the above copyright - * notice, this list of conditions and the following disclaimer in the - * documentation and/or other materials provided with the distribution. - * - * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND - * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE - * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE - * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE - * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL - * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS - * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) - * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT - * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY - * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF - * SUCH DAMAGE. - */ - -#include -__FBSDID("$FreeBSD$"); - -/* - * Stand-alone ZFS file reader. - */ - -#include -#include - -#include "zfsimpl.h" -#include "zfssubr.c" - - -struct zfsmount { - const spa_t *spa; - objset_phys_t objset; - uint64_t rootobj; -}; -static struct zfsmount zfsmount __unused; - -/* - * List of all vdevs, chained through v_alllink. - */ -static vdev_list_t zfs_vdevs; - - /* - * List of ZFS features supported for read - */ -static const char *features_for_read[] = { - "org.illumos:lz4_compress", - "com.delphix:hole_birth", - "com.delphix:extensible_dataset", - "com.delphix:embedded_data", - "org.open-zfs:large_blocks", - "org.illumos:sha512", - "org.illumos:skein", - "org.zfsonlinux:large_dnode", - NULL -}; - -/* - * List of all pools, chained through spa_link. - */ -static spa_list_t zfs_pools; - -static const dnode_phys_t *dnode_cache_obj; -static uint64_t dnode_cache_bn; -static char *dnode_cache_buf; -static char *zap_scratch; -static char *zfs_temp_buf, *zfs_temp_end, *zfs_temp_ptr; - -#define TEMP_SIZE (1024 * 1024) - -static int zio_read(const spa_t *spa, const blkptr_t *bp, void *buf); -static int zfs_get_root(const spa_t *spa, uint64_t *objid); -static int zfs_rlookup(const spa_t *spa, uint64_t objnum, char *result); -static int zap_lookup(const spa_t *spa, const dnode_phys_t *dnode, - const char *name, uint64_t integer_size, uint64_t num_integers, - void *value); - -static void -zfs_init(void) -{ - STAILQ_INIT(&zfs_vdevs); - STAILQ_INIT(&zfs_pools); - - zfs_temp_buf = malloc(TEMP_SIZE); - zfs_temp_end = zfs_temp_buf + TEMP_SIZE; - zfs_temp_ptr = zfs_temp_buf; - dnode_cache_buf = malloc(SPA_MAXBLOCKSIZE); - zap_scratch = malloc(SPA_MAXBLOCKSIZE); - - zfs_init_crc(); -} - -static void * -zfs_alloc(size_t size) -{ - char *ptr; - - if (zfs_temp_ptr + size > zfs_temp_end) { - printf("ZFS: out of temporary buffer space\n"); - for (;;) ; - } - ptr = zfs_temp_ptr; - zfs_temp_ptr += size; - - return (ptr); -} - -static void -zfs_free(void *ptr, size_t size) -{ - - zfs_temp_ptr -= size; - if (zfs_temp_ptr != ptr) { - printf("ZFS: zfs_alloc()/zfs_free() mismatch\n"); - for (;;) ; - } -} - -static int -xdr_int(const unsigned char **xdr, int *ip) -{ - *ip = ((*xdr)[0] << 24) - | ((*xdr)[1] << 16) - | ((*xdr)[2] << 8) - | ((*xdr)[3] << 0); - (*xdr) += 4; - return (0); -} - -static int -xdr_u_int(const unsigned char **xdr, u_int *ip) -{ - *ip = ((*xdr)[0] << 24) - | ((*xdr)[1] << 16) - | ((*xdr)[2] << 8) - | ((*xdr)[3] << 0); - (*xdr) += 4; - return (0); -} - -static int -xdr_uint64_t(const unsigned char **xdr, uint64_t *lp) -{ - u_int hi, lo; - - xdr_u_int(xdr, &hi); - xdr_u_int(xdr, &lo); - *lp = (((uint64_t) hi) << 32) | lo; - return (0); -} - -static int -nvlist_find(const unsigned char *nvlist, const char *name, int type, - int* elementsp, void *valuep) -{ - const unsigned char *p, *pair; - int junk; - int encoded_size, decoded_size; - - p = nvlist; - xdr_int(&p, &junk); - xdr_int(&p, &junk); - - pair = p; - xdr_int(&p, &encoded_size); - xdr_int(&p, &decoded_size); - while (encoded_size && decoded_size) { - int namelen, pairtype, elements; - const char *pairname; - - xdr_int(&p, &namelen); - pairname = (const char*) p; - p += roundup(namelen, 4); - xdr_int(&p, &pairtype); - - if (!memcmp(name, pairname, namelen) && type == pairtype) { - xdr_int(&p, &elements); - if (elementsp) - *elementsp = elements; - if (type == DATA_TYPE_UINT64) { - xdr_uint64_t(&p, (uint64_t *) valuep); - return (0); - } else if (type == DATA_TYPE_STRING) { - int len; - xdr_int(&p, &len); - (*(const char**) valuep) = (const char*) p; - return (0); - } else if (type == DATA_TYPE_NVLIST - || type == DATA_TYPE_NVLIST_ARRAY) { - (*(const unsigned char**) valuep) = - (const unsigned char*) p; - return (0); - } else { - return (EIO); - } - } else { - /* - * Not the pair we are looking for, skip to the next one. - */ - p = pair + encoded_size; - } - - pair = p; - xdr_int(&p, &encoded_size); - xdr_int(&p, &decoded_size); - } - - return (EIO); -} - -static int -nvlist_check_features_for_read(const unsigned char *nvlist) -{ - const unsigned char *p, *pair; - int junk; - int encoded_size, decoded_size; - int rc; - - rc = 0; - - p = nvlist; - xdr_int(&p, &junk); - xdr_int(&p, &junk); - - pair = p; - xdr_int(&p, &encoded_size); - xdr_int(&p, &decoded_size); - while (encoded_size && decoded_size) { - int namelen, pairtype; - const char *pairname; - int i, found; - - found = 0; - - xdr_int(&p, &namelen); - pairname = (const char*) p; - p += roundup(namelen, 4); - xdr_int(&p, &pairtype); - - for (i = 0; features_for_read[i] != NULL; i++) { - if (!memcmp(pairname, features_for_read[i], namelen)) { - found = 1; - break; - } - } - - if (!found) { - printf("ZFS: unsupported feature: %s\n", pairname); - rc = EIO; - } - - p = pair + encoded_size; - - pair = p; - xdr_int(&p, &encoded_size); - xdr_int(&p, &decoded_size); - } - - return (rc); -} - -/* - * Return the next nvlist in an nvlist array. - */ -static const unsigned char * -nvlist_next(const unsigned char *nvlist) -{ - const unsigned char *p, *pair; - int junk; - int encoded_size, decoded_size; - - p = nvlist; - xdr_int(&p, &junk); - xdr_int(&p, &junk); - - pair = p; - xdr_int(&p, &encoded_size); - xdr_int(&p, &decoded_size); - while (encoded_size && decoded_size) { - p = pair + encoded_size; - - pair = p; - xdr_int(&p, &encoded_size); - xdr_int(&p, &decoded_size); - } - - return p; -} - -#ifdef TEST - -static const unsigned char * -nvlist_print(const unsigned char *nvlist, unsigned int indent) -{ - static const char* typenames[] = { - "DATA_TYPE_UNKNOWN", - "DATA_TYPE_BOOLEAN", - "DATA_TYPE_BYTE", - "DATA_TYPE_INT16", - "DATA_TYPE_UINT16", - "DATA_TYPE_INT32", - "DATA_TYPE_UINT32", - "DATA_TYPE_INT64", - "DATA_TYPE_UINT64", - "DATA_TYPE_STRING", - "DATA_TYPE_BYTE_ARRAY", - "DATA_TYPE_INT16_ARRAY", - "DATA_TYPE_UINT16_ARRAY", - "DATA_TYPE_INT32_ARRAY", - "DATA_TYPE_UINT32_ARRAY", - "DATA_TYPE_INT64_ARRAY", - "DATA_TYPE_UINT64_ARRAY", - "DATA_TYPE_STRING_ARRAY", - "DATA_TYPE_HRTIME", - "DATA_TYPE_NVLIST", - "DATA_TYPE_NVLIST_ARRAY", - "DATA_TYPE_BOOLEAN_VALUE", - "DATA_TYPE_INT8", - "DATA_TYPE_UINT8", - "DATA_TYPE_BOOLEAN_ARRAY", - "DATA_TYPE_INT8_ARRAY", - "DATA_TYPE_UINT8_ARRAY" - }; - - unsigned int i, j; - const unsigned char *p, *pair; - int junk; - int encoded_size, decoded_size; - - p = nvlist; - xdr_int(&p, &junk); - xdr_int(&p, &junk); - - pair = p; - xdr_int(&p, &encoded_size); - xdr_int(&p, &decoded_size); - while (encoded_size && decoded_size) { - int namelen, pairtype, elements; - const char *pairname; - - xdr_int(&p, &namelen); - pairname = (const char*) p; - p += roundup(namelen, 4); - xdr_int(&p, &pairtype); - - for (i = 0; i < indent; i++) - printf(" "); - printf("%s %s", typenames[pairtype], pairname); - - xdr_int(&p, &elements); - switch (pairtype) { - case DATA_TYPE_UINT64: { - uint64_t val; - xdr_uint64_t(&p, &val); - printf(" = 0x%jx\n", (uintmax_t)val); - break; - } - - case DATA_TYPE_STRING: { - int len; - xdr_int(&p, &len); - printf(" = \"%s\"\n", p); - break; - } - - case DATA_TYPE_NVLIST: - printf("\n"); - nvlist_print(p, indent + 1); - break; - - case DATA_TYPE_NVLIST_ARRAY: - for (j = 0; j < elements; j++) { - printf("[%d]\n", j); - p = nvlist_print(p, indent + 1); - if (j != elements - 1) { - for (i = 0; i < indent; i++) - printf(" "); - printf("%s %s", typenames[pairtype], pairname); - } - } - break; - - default: - printf("\n"); - } - - p = pair + encoded_size; - - pair = p; - xdr_int(&p, &encoded_size); - xdr_int(&p, &decoded_size); - } - - return p; -} - -#endif - -static int -vdev_read_phys(vdev_t *vdev, const blkptr_t *bp, void *buf, - off_t offset, size_t size) -{ - size_t psize; - int rc; - - if (!vdev->v_phys_read) - return (EIO); - - if (bp) { - psize = BP_GET_PSIZE(bp); - } else { - psize = size; - } - - /*printf("ZFS: reading %zu bytes at 0x%jx to %p\n", psize, (uintmax_t)offset, buf);*/ - rc = vdev->v_phys_read(vdev, vdev->v_read_priv, offset, buf, psize); - if (rc) - return (rc); - if (bp && zio_checksum_verify(vdev->spa, bp, buf)) - return (EIO); - - return (0); -} - -static int -vdev_disk_read(vdev_t *vdev, const blkptr_t *bp, void *buf, - off_t offset, size_t bytes) -{ - - return (vdev_read_phys(vdev, bp, buf, - offset + VDEV_LABEL_START_SIZE, bytes)); -} - - -static int -vdev_mirror_read(vdev_t *vdev, const blkptr_t *bp, void *buf, - off_t offset, size_t bytes) -{ - vdev_t *kid; - int rc; - - rc = EIO; - STAILQ_FOREACH(kid, &vdev->v_children, v_childlink) { - if (kid->v_state != VDEV_STATE_HEALTHY) - continue; - rc = kid->v_read(kid, bp, buf, offset, bytes); - if (!rc) - return (0); - } - - return (rc); -} - -static int -vdev_replacing_read(vdev_t *vdev, const blkptr_t *bp, void *buf, - off_t offset, size_t bytes) -{ - vdev_t *kid; - - /* - * Here we should have two kids: - * First one which is the one we are replacing and we can trust - * only this one to have valid data, but it might not be present. - * Second one is that one we are replacing with. It is most likely - * healthy, but we can't trust it has needed data, so we won't use it. - */ - kid = STAILQ_FIRST(&vdev->v_children); - if (kid == NULL) - return (EIO); - if (kid->v_state != VDEV_STATE_HEALTHY) - return (EIO); - return (kid->v_read(kid, bp, buf, offset, bytes)); -} - -static vdev_t * -vdev_find(uint64_t guid) -{ - vdev_t *vdev; - - STAILQ_FOREACH(vdev, &zfs_vdevs, v_alllink) - if (vdev->v_guid == guid) - return (vdev); - - return (0); -} - -static vdev_t * -vdev_create(uint64_t guid, vdev_read_t *_read) -{ - vdev_t *vdev; - - vdev = malloc(sizeof(vdev_t)); - memset(vdev, 0, sizeof(vdev_t)); - STAILQ_INIT(&vdev->v_children); - vdev->v_guid = guid; - vdev->v_state = VDEV_STATE_OFFLINE; - vdev->v_read = _read; - vdev->v_phys_read = 0; - vdev->v_read_priv = 0; - STAILQ_INSERT_TAIL(&zfs_vdevs, vdev, v_alllink); - - return (vdev); -} - -static int -vdev_init_from_nvlist(const unsigned char *nvlist, vdev_t *pvdev, - vdev_t **vdevp, int is_newer) -{ - int rc; - uint64_t guid, id, ashift, nparity; - const char *type; - const char *path; - vdev_t *vdev, *kid; - const unsigned char *kids; - int nkids, i, is_new; - uint64_t is_offline, is_faulted, is_degraded, is_removed, isnt_present; - - if (nvlist_find(nvlist, ZPOOL_CONFIG_GUID, DATA_TYPE_UINT64, - NULL, &guid) - || nvlist_find(nvlist, ZPOOL_CONFIG_ID, DATA_TYPE_UINT64, NULL, &id) - || nvlist_find(nvlist, ZPOOL_CONFIG_TYPE, DATA_TYPE_STRING, - NULL, &type)) { - printf("ZFS: can't find vdev details\n"); - return (ENOENT); - } - - if (strcmp(type, VDEV_TYPE_MIRROR) - && strcmp(type, VDEV_TYPE_DISK) -#ifdef ZFS_TEST - && strcmp(type, VDEV_TYPE_FILE) -#endif - && strcmp(type, VDEV_TYPE_RAIDZ) - && strcmp(type, VDEV_TYPE_REPLACING)) { - printf("ZFS: can only boot from disk, mirror, raidz1, raidz2 and raidz3 vdevs\n"); - return (EIO); - } - - is_offline = is_removed = is_faulted = is_degraded = isnt_present = 0; - - nvlist_find(nvlist, ZPOOL_CONFIG_OFFLINE, DATA_TYPE_UINT64, NULL, - &is_offline); - nvlist_find(nvlist, ZPOOL_CONFIG_REMOVED, DATA_TYPE_UINT64, NULL, - &is_removed); - nvlist_find(nvlist, ZPOOL_CONFIG_FAULTED, DATA_TYPE_UINT64, NULL, - &is_faulted); - nvlist_find(nvlist, ZPOOL_CONFIG_DEGRADED, DATA_TYPE_UINT64, NULL, - &is_degraded); - nvlist_find(nvlist, ZPOOL_CONFIG_NOT_PRESENT, DATA_TYPE_UINT64, NULL, - &isnt_present); - - vdev = vdev_find(guid); - if (!vdev) { - is_new = 1; - - if (!strcmp(type, VDEV_TYPE_MIRROR)) - vdev = vdev_create(guid, vdev_mirror_read); - else if (!strcmp(type, VDEV_TYPE_RAIDZ)) - vdev = vdev_create(guid, vdev_raidz_read); - else if (!strcmp(type, VDEV_TYPE_REPLACING)) - vdev = vdev_create(guid, vdev_replacing_read); - else - vdev = vdev_create(guid, vdev_disk_read); - - vdev->v_id = id; - vdev->v_top = pvdev != NULL ? pvdev : vdev; - if (nvlist_find(nvlist, ZPOOL_CONFIG_ASHIFT, - DATA_TYPE_UINT64, NULL, &ashift) == 0) { - vdev->v_ashift = ashift; - } else { - vdev->v_ashift = 0; - } - if (nvlist_find(nvlist, ZPOOL_CONFIG_NPARITY, - DATA_TYPE_UINT64, NULL, &nparity) == 0) { - vdev->v_nparity = nparity; - } else { - vdev->v_nparity = 0; - } - if (nvlist_find(nvlist, ZPOOL_CONFIG_PATH, - DATA_TYPE_STRING, NULL, &path) == 0) { - if (strncmp(path, "/dev/", 5) == 0) - path += 5; - vdev->v_name = strdup(path); - } else { - if (!strcmp(type, "raidz")) { - if (vdev->v_nparity == 1) - vdev->v_name = "raidz1"; - else if (vdev->v_nparity == 2) - vdev->v_name = "raidz2"; - else if (vdev->v_nparity == 3) - vdev->v_name = "raidz3"; - else { - printf("ZFS: can only boot from disk, mirror, raidz1, raidz2 and raidz3 vdevs\n"); - return (EIO); - } - } else { - vdev->v_name = strdup(type); - } - } - } else { - is_new = 0; - } - - if (is_new || is_newer) { - /* - * This is either new vdev or we've already seen this vdev, - * but from an older vdev label, so let's refresh its state - * from the newer label. - */ - if (is_offline) - vdev->v_state = VDEV_STATE_OFFLINE; - else if (is_removed) - vdev->v_state = VDEV_STATE_REMOVED; - else if (is_faulted) - vdev->v_state = VDEV_STATE_FAULTED; - else if (is_degraded) - vdev->v_state = VDEV_STATE_DEGRADED; - else if (isnt_present) - vdev->v_state = VDEV_STATE_CANT_OPEN; - } - - rc = nvlist_find(nvlist, ZPOOL_CONFIG_CHILDREN, DATA_TYPE_NVLIST_ARRAY, - &nkids, &kids); - /* - * Its ok if we don't have any kids. - */ - if (rc == 0) { - vdev->v_nchildren = nkids; - for (i = 0; i < nkids; i++) { - rc = vdev_init_from_nvlist(kids, vdev, &kid, is_newer); - if (rc) - return (rc); - if (is_new) - STAILQ_INSERT_TAIL(&vdev->v_children, kid, - v_childlink); - kids = nvlist_next(kids); - } - } else { - vdev->v_nchildren = 0; - } - - if (vdevp) - *vdevp = vdev; - return (0); -} - -static void -vdev_set_state(vdev_t *vdev) -{ - vdev_t *kid; - int good_kids; - int bad_kids; - - /* - * A mirror or raidz is healthy if all its kids are healthy. A - * mirror is degraded if any of its kids is healthy; a raidz - * is degraded if at most nparity kids are offline. - */ - if (STAILQ_FIRST(&vdev->v_children)) { - good_kids = 0; - bad_kids = 0; - STAILQ_FOREACH(kid, &vdev->v_children, v_childlink) { - if (kid->v_state == VDEV_STATE_HEALTHY) - good_kids++; - else - bad_kids++; - } - if (bad_kids == 0) { - vdev->v_state = VDEV_STATE_HEALTHY; - } else { - if (vdev->v_read == vdev_mirror_read) { - if (good_kids) { - vdev->v_state = VDEV_STATE_DEGRADED; - } else { - vdev->v_state = VDEV_STATE_OFFLINE; - } - } else if (vdev->v_read == vdev_raidz_read) { - if (bad_kids > vdev->v_nparity) { - vdev->v_state = VDEV_STATE_OFFLINE; - } else { - vdev->v_state = VDEV_STATE_DEGRADED; - } - } - } - } -} - -static spa_t * -spa_find_by_guid(uint64_t guid) -{ - spa_t *spa; - - STAILQ_FOREACH(spa, &zfs_pools, spa_link) - if (spa->spa_guid == guid) - return (spa); - - return (0); -} - -static spa_t * -spa_find_by_name(const char *name) -{ - spa_t *spa; - - STAILQ_FOREACH(spa, &zfs_pools, spa_link) - if (!strcmp(spa->spa_name, name)) - return (spa); - - return (0); -} - -#ifdef BOOT2 -static spa_t * -spa_get_primary(void) -{ - - return (STAILQ_FIRST(&zfs_pools)); -} - -static vdev_t * -spa_get_primary_vdev(const spa_t *spa) -{ - vdev_t *vdev; - vdev_t *kid; - - if (spa == NULL) - spa = spa_get_primary(); - if (spa == NULL) - return (NULL); - vdev = STAILQ_FIRST(&spa->spa_vdevs); - if (vdev == NULL) - return (NULL); - for (kid = STAILQ_FIRST(&vdev->v_children); kid != NULL; - kid = STAILQ_FIRST(&vdev->v_children)) - vdev = kid; - return (vdev); -} -#endif - -static spa_t * -spa_create(uint64_t guid, const char *name) -{ - spa_t *spa; - - if ((spa = malloc(sizeof(spa_t))) == NULL) - return (NULL); - memset(spa, 0, sizeof(spa_t)); - if ((spa->spa_name = strdup(name)) == NULL) { - free(spa); - return (NULL); - } - STAILQ_INIT(&spa->spa_vdevs); - spa->spa_guid = guid; - STAILQ_INSERT_TAIL(&zfs_pools, spa, spa_link); - - return (spa); -} - -static const char * -state_name(vdev_state_t state) -{ - static const char* names[] = { - "UNKNOWN", - "CLOSED", - "OFFLINE", - "REMOVED", - "CANT_OPEN", - "FAULTED", - "DEGRADED", - "ONLINE" - }; - return names[state]; -} - -#ifdef BOOT2 - -#define pager_printf printf - -#else - -static int -pager_printf(const char *fmt, ...) -{ - char line[80]; - va_list args; - - va_start(args, fmt); - vsprintf(line, fmt, args); - va_end(args); - - return (pager_output(line)); -} - -#endif - -#define STATUS_FORMAT " %s %s\n" - -static int -print_state(int indent, const char *name, vdev_state_t state) -{ - char buf[512]; - int i; - - buf[0] = 0; - for (i = 0; i < indent; i++) - strcat(buf, " "); - strcat(buf, name); - - return (pager_printf(STATUS_FORMAT, buf, state_name(state))); -} - -static int -vdev_status(vdev_t *vdev, int indent) -{ - vdev_t *kid; - int ret; - ret = print_state(indent, vdev->v_name, vdev->v_state); - if (ret != 0) - return (ret); - - STAILQ_FOREACH(kid, &vdev->v_children, v_childlink) { - ret = vdev_status(kid, indent + 1); - if (ret != 0) - return (ret); - } - return (ret); -} - -static int -spa_status(spa_t *spa) -{ - static char bootfs[ZFS_MAXNAMELEN]; - uint64_t rootid; - vdev_t *vdev; - int good_kids, bad_kids, degraded_kids, ret; - vdev_state_t state; - - ret = pager_printf(" pool: %s\n", spa->spa_name); - if (ret != 0) - return (ret); - - if (zfs_get_root(spa, &rootid) == 0 && - zfs_rlookup(spa, rootid, bootfs) == 0) { - if (bootfs[0] == '\0') - ret = pager_printf("bootfs: %s\n", spa->spa_name); - else - ret = pager_printf("bootfs: %s/%s\n", spa->spa_name, - bootfs); - if (ret != 0) - return (ret); - } - ret = pager_printf("config:\n\n"); - if (ret != 0) - return (ret); - ret = pager_printf(STATUS_FORMAT, "NAME", "STATE"); - if (ret != 0) - return (ret); - - good_kids = 0; - degraded_kids = 0; - bad_kids = 0; - STAILQ_FOREACH(vdev, &spa->spa_vdevs, v_childlink) { - if (vdev->v_state == VDEV_STATE_HEALTHY) - good_kids++; - else if (vdev->v_state == VDEV_STATE_DEGRADED) - degraded_kids++; - else - bad_kids++; - } - - state = VDEV_STATE_CLOSED; - if (good_kids > 0 && (degraded_kids + bad_kids) == 0) - state = VDEV_STATE_HEALTHY; - else if ((good_kids + degraded_kids) > 0) - state = VDEV_STATE_DEGRADED; - - ret = print_state(0, spa->spa_name, state); - if (ret != 0) - return (ret); - STAILQ_FOREACH(vdev, &spa->spa_vdevs, v_childlink) { - ret = vdev_status(vdev, 1); - if (ret != 0) - return (ret); - } - return (ret); -} - -static int -spa_all_status(void) -{ - spa_t *spa; - int first = 1, ret = 0; - - STAILQ_FOREACH(spa, &zfs_pools, spa_link) { - if (!first) { - ret = pager_printf("\n"); - if (ret != 0) - return (ret); - } - first = 0; - ret = spa_status(spa); - if (ret != 0) - return (ret); - } - return (ret); -} - -static uint64_t -vdev_label_offset(uint64_t psize, int l, uint64_t offset) -{ - uint64_t label_offset; - - if (l < VDEV_LABELS / 2) - label_offset = 0; - else - label_offset = psize - VDEV_LABELS * sizeof (vdev_label_t); - - return (offset + l * sizeof (vdev_label_t) + label_offset); -} - -static int -vdev_probe(vdev_phys_read_t *_read, void *read_priv, spa_t **spap) -{ - vdev_t vtmp; - vdev_phys_t *vdev_label = (vdev_phys_t *) zap_scratch; - vdev_phys_t *tmp_label; - spa_t *spa; - vdev_t *vdev, *top_vdev, *pool_vdev; - off_t off; - blkptr_t bp; - const unsigned char *nvlist = NULL; - uint64_t val; - uint64_t guid; - uint64_t best_txg = 0; - uint64_t pool_txg, pool_guid; - uint64_t psize; - const char *pool_name; - const unsigned char *vdevs; - const unsigned char *features; - int i, l, rc, is_newer; - char *upbuf; - const struct uberblock *up; - - /* - * Load the vdev label and figure out which - * uberblock is most current. - */ - memset(&vtmp, 0, sizeof(vtmp)); - vtmp.v_phys_read = _read; - vtmp.v_read_priv = read_priv; - psize = P2ALIGN(ldi_get_size(read_priv), - (uint64_t)sizeof (vdev_label_t)); - - /* Test for minimum pool size. */ - if (psize < SPA_MINDEVSIZE) - return (EIO); - - tmp_label = zfs_alloc(sizeof(vdev_phys_t)); - - for (l = 0; l < VDEV_LABELS; l++) { - off = vdev_label_offset(psize, l, - offsetof(vdev_label_t, vl_vdev_phys)); - - BP_ZERO(&bp); - BP_SET_LSIZE(&bp, sizeof(vdev_phys_t)); - BP_SET_PSIZE(&bp, sizeof(vdev_phys_t)); - BP_SET_CHECKSUM(&bp, ZIO_CHECKSUM_LABEL); - BP_SET_COMPRESS(&bp, ZIO_COMPRESS_OFF); - DVA_SET_OFFSET(BP_IDENTITY(&bp), off); - ZIO_SET_CHECKSUM(&bp.blk_cksum, off, 0, 0, 0); - - if (vdev_read_phys(&vtmp, &bp, tmp_label, off, 0)) - continue; - - if (tmp_label->vp_nvlist[0] != NV_ENCODE_XDR) - continue; - - nvlist = (const unsigned char *) tmp_label->vp_nvlist + 4; - if (nvlist_find(nvlist, ZPOOL_CONFIG_POOL_TXG, - DATA_TYPE_UINT64, NULL, &pool_txg) != 0) - continue; - - if (best_txg <= pool_txg) { - best_txg = pool_txg; - memcpy(vdev_label, tmp_label, sizeof (vdev_phys_t)); - } - } - - zfs_free(tmp_label, sizeof (vdev_phys_t)); - - if (best_txg == 0) - return (EIO); - - if (vdev_label->vp_nvlist[0] != NV_ENCODE_XDR) - return (EIO); - - nvlist = (const unsigned char *) vdev_label->vp_nvlist + 4; - - if (nvlist_find(nvlist, ZPOOL_CONFIG_VERSION, DATA_TYPE_UINT64, - NULL, &val) != 0) { - return (EIO); - } - - if (!SPA_VERSION_IS_SUPPORTED(val)) { - printf("ZFS: unsupported ZFS version %u (should be %u)\n", - (unsigned) val, (unsigned) SPA_VERSION); - return (EIO); - } - - /* Check ZFS features for read */ - if (nvlist_find(nvlist, ZPOOL_CONFIG_FEATURES_FOR_READ, - DATA_TYPE_NVLIST, NULL, &features) == 0 && - nvlist_check_features_for_read(features) != 0) { - return (EIO); - } - - if (nvlist_find(nvlist, ZPOOL_CONFIG_POOL_STATE, DATA_TYPE_UINT64, - NULL, &val) != 0) { - return (EIO); - } - - if (val == POOL_STATE_DESTROYED) { - /* We don't boot only from destroyed pools. */ - return (EIO); - } - - if (nvlist_find(nvlist, ZPOOL_CONFIG_POOL_TXG, DATA_TYPE_UINT64, - NULL, &pool_txg) != 0 || - nvlist_find(nvlist, ZPOOL_CONFIG_POOL_GUID, DATA_TYPE_UINT64, - NULL, &pool_guid) != 0 || - nvlist_find(nvlist, ZPOOL_CONFIG_POOL_NAME, DATA_TYPE_STRING, - NULL, &pool_name) != 0) { - /* - * Cache and spare devices end up here - just ignore - * them. - */ - /*printf("ZFS: can't find pool details\n");*/ - return (EIO); - } - - if (nvlist_find(nvlist, ZPOOL_CONFIG_IS_LOG, DATA_TYPE_UINT64, - NULL, &val) == 0 && val != 0) { - return (EIO); - } - - /* - * Create the pool if this is the first time we've seen it. - */ - spa = spa_find_by_guid(pool_guid); - if (spa == NULL) { - spa = spa_create(pool_guid, pool_name); - if (spa == NULL) - return (ENOMEM); - } - if (pool_txg > spa->spa_txg) { - spa->spa_txg = pool_txg; - is_newer = 1; - } else { - is_newer = 0; - } - - /* - * Get the vdev tree and create our in-core copy of it. - * If we already have a vdev with this guid, this must - * be some kind of alias (overlapping slices, dangerously dedicated - * disks etc). - */ - if (nvlist_find(nvlist, ZPOOL_CONFIG_GUID, DATA_TYPE_UINT64, - NULL, &guid) != 0) { - return (EIO); - } - vdev = vdev_find(guid); - if (vdev && vdev->v_phys_read) /* Has this vdev already been inited? */ - return (EIO); - - if (nvlist_find(nvlist, ZPOOL_CONFIG_VDEV_TREE, DATA_TYPE_NVLIST, - NULL, &vdevs)) { - return (EIO); - } - - rc = vdev_init_from_nvlist(vdevs, NULL, &top_vdev, is_newer); - if (rc != 0) - return (rc); - - /* - * Add the toplevel vdev to the pool if its not already there. - */ - STAILQ_FOREACH(pool_vdev, &spa->spa_vdevs, v_childlink) - if (top_vdev == pool_vdev) - break; - if (!pool_vdev && top_vdev) { - top_vdev->spa = spa; - STAILQ_INSERT_TAIL(&spa->spa_vdevs, top_vdev, v_childlink); - } - - /* - * We should already have created an incomplete vdev for this - * vdev. Find it and initialise it with our read proc. - */ - vdev = vdev_find(guid); - if (vdev) { - vdev->v_phys_read = _read; - vdev->v_read_priv = read_priv; - vdev->v_state = VDEV_STATE_HEALTHY; - } else { - printf("ZFS: inconsistent nvlist contents\n"); - return (EIO); - } - - /* - * Re-evaluate top-level vdev state. - */ - vdev_set_state(top_vdev); - - /* - * Ok, we are happy with the pool so far. Lets find - * the best uberblock and then we can actually access - * the contents of the pool. - */ - upbuf = zfs_alloc(VDEV_UBERBLOCK_SIZE(vdev)); - up = (const struct uberblock *)upbuf; - for (l = 0; l < VDEV_LABELS; l++) { - for (i = 0; i < VDEV_UBERBLOCK_COUNT(vdev); i++) { - off = vdev_label_offset(psize, l, - VDEV_UBERBLOCK_OFFSET(vdev, i)); - BP_ZERO(&bp); - DVA_SET_OFFSET(&bp.blk_dva[0], off); - BP_SET_LSIZE(&bp, VDEV_UBERBLOCK_SIZE(vdev)); - BP_SET_PSIZE(&bp, VDEV_UBERBLOCK_SIZE(vdev)); - BP_SET_CHECKSUM(&bp, ZIO_CHECKSUM_LABEL); - BP_SET_COMPRESS(&bp, ZIO_COMPRESS_OFF); - ZIO_SET_CHECKSUM(&bp.blk_cksum, off, 0, 0, 0); - - if (vdev_read_phys(vdev, &bp, upbuf, off, 0)) - continue; - - if (up->ub_magic != UBERBLOCK_MAGIC) - continue; - if (up->ub_txg < spa->spa_txg) - continue; - if (up->ub_txg > spa->spa_uberblock.ub_txg || - (up->ub_txg == spa->spa_uberblock.ub_txg && - up->ub_timestamp > - spa->spa_uberblock.ub_timestamp)) { - spa->spa_uberblock = *up; - } - } - } - zfs_free(upbuf, VDEV_UBERBLOCK_SIZE(vdev)); - - vdev->spa = spa; - if (spap != NULL) - *spap = spa; - return (0); -} - -static int -ilog2(int n) -{ - int v; - - for (v = 0; v < 32; v++) - if (n == (1 << v)) - return v; - return -1; -} - -static int -zio_read_gang(const spa_t *spa, const blkptr_t *bp, void *buf) -{ - blkptr_t gbh_bp; - zio_gbh_phys_t zio_gb; - char *pbuf; - int i; - - /* Artificial BP for gang block header. */ - gbh_bp = *bp; - BP_SET_PSIZE(&gbh_bp, SPA_GANGBLOCKSIZE); - BP_SET_LSIZE(&gbh_bp, SPA_GANGBLOCKSIZE); - BP_SET_CHECKSUM(&gbh_bp, ZIO_CHECKSUM_GANG_HEADER); - BP_SET_COMPRESS(&gbh_bp, ZIO_COMPRESS_OFF); - for (i = 0; i < SPA_DVAS_PER_BP; i++) - DVA_SET_GANG(&gbh_bp.blk_dva[i], 0); - - /* Read gang header block using the artificial BP. */ - if (zio_read(spa, &gbh_bp, &zio_gb)) - return (EIO); - - pbuf = buf; - for (i = 0; i < SPA_GBH_NBLKPTRS; i++) { - blkptr_t *gbp = &zio_gb.zg_blkptr[i]; - - if (BP_IS_HOLE(gbp)) - continue; - if (zio_read(spa, gbp, pbuf)) - return (EIO); - pbuf += BP_GET_PSIZE(gbp); - } - - if (zio_checksum_verify(spa, bp, buf)) - return (EIO); - return (0); -} - -static int -zio_read(const spa_t *spa, const blkptr_t *bp, void *buf) -{ - int cpfunc = BP_GET_COMPRESS(bp); - uint64_t align, size; - void *pbuf; - int i, error; - - /* - * Process data embedded in block pointer - */ - if (BP_IS_EMBEDDED(bp)) { - ASSERT(BPE_GET_ETYPE(bp) == BP_EMBEDDED_TYPE_DATA); - - size = BPE_GET_PSIZE(bp); - ASSERT(size <= BPE_PAYLOAD_SIZE); - - if (cpfunc != ZIO_COMPRESS_OFF) - pbuf = zfs_alloc(size); - else - pbuf = buf; - - decode_embedded_bp_compressed(bp, pbuf); - error = 0; - - if (cpfunc != ZIO_COMPRESS_OFF) { - error = zio_decompress_data(cpfunc, pbuf, - size, buf, BP_GET_LSIZE(bp)); - zfs_free(pbuf, size); - } - if (error != 0) - printf("ZFS: i/o error - unable to decompress block pointer data, error %d\n", - error); - return (error); - } - - error = EIO; - - for (i = 0; i < SPA_DVAS_PER_BP; i++) { - const dva_t *dva = &bp->blk_dva[i]; - vdev_t *vdev; - int vdevid; - off_t offset; - - if (!dva->dva_word[0] && !dva->dva_word[1]) - continue; - - vdevid = DVA_GET_VDEV(dva); - offset = DVA_GET_OFFSET(dva); - STAILQ_FOREACH(vdev, &spa->spa_vdevs, v_childlink) { - if (vdev->v_id == vdevid) - break; - } - if (!vdev || !vdev->v_read) - continue; - - size = BP_GET_PSIZE(bp); - if (vdev->v_read == vdev_raidz_read) { - align = 1ULL << vdev->v_top->v_ashift; - if (P2PHASE(size, align) != 0) - size = P2ROUNDUP(size, align); - } - if (size != BP_GET_PSIZE(bp) || cpfunc != ZIO_COMPRESS_OFF) - pbuf = zfs_alloc(size); - else - pbuf = buf; - - if (DVA_GET_GANG(dva)) - error = zio_read_gang(spa, bp, pbuf); - else - error = vdev->v_read(vdev, bp, pbuf, offset, size); - if (error == 0) { - if (cpfunc != ZIO_COMPRESS_OFF) - error = zio_decompress_data(cpfunc, pbuf, - BP_GET_PSIZE(bp), buf, BP_GET_LSIZE(bp)); - else if (size != BP_GET_PSIZE(bp)) - bcopy(pbuf, buf, BP_GET_PSIZE(bp)); - } - if (buf != pbuf) - zfs_free(pbuf, size); - if (error == 0) - break; - } - if (error != 0) - printf("ZFS: i/o error - all block copies unavailable\n"); - return (error); -} - -static int -dnode_read(const spa_t *spa, const dnode_phys_t *dnode, off_t offset, void *buf, size_t buflen) -{ - int ibshift = dnode->dn_indblkshift - SPA_BLKPTRSHIFT; - int bsize = dnode->dn_datablkszsec << SPA_MINBLOCKSHIFT; - int nlevels = dnode->dn_nlevels; - int i, rc; - - if (bsize > SPA_MAXBLOCKSIZE) { - printf("ZFS: I/O error - blocks larger than %llu are not " - "supported\n", SPA_MAXBLOCKSIZE); - return (EIO); - } - - /* - * Note: bsize may not be a power of two here so we need to do an - * actual divide rather than a bitshift. - */ - while (buflen > 0) { - uint64_t bn = offset / bsize; - int boff = offset % bsize; - int ibn; - const blkptr_t *indbp; - blkptr_t bp; - - if (bn > dnode->dn_maxblkid) - return (EIO); - - if (dnode == dnode_cache_obj && bn == dnode_cache_bn) - goto cached; - - indbp = dnode->dn_blkptr; - for (i = 0; i < nlevels; i++) { - /* - * Copy the bp from the indirect array so that - * we can re-use the scratch buffer for multi-level - * objects. - */ - ibn = bn >> ((nlevels - i - 1) * ibshift); - ibn &= ((1 << ibshift) - 1); - bp = indbp[ibn]; - if (BP_IS_HOLE(&bp)) { - memset(dnode_cache_buf, 0, bsize); - break; - } - rc = zio_read(spa, &bp, dnode_cache_buf); - if (rc) - return (rc); - indbp = (const blkptr_t *) dnode_cache_buf; - } - dnode_cache_obj = dnode; - dnode_cache_bn = bn; - cached: - - /* - * The buffer contains our data block. Copy what we - * need from it and loop. - */ - i = bsize - boff; - if (i > buflen) i = buflen; - memcpy(buf, &dnode_cache_buf[boff], i); - buf = ((char*) buf) + i; - offset += i; - buflen -= i; - } - - return (0); -} - -/* - * Lookup a value in a microzap directory. Assumes that the zap - * scratch buffer contains the directory contents. - */ -static int -mzap_lookup(const dnode_phys_t *dnode, const char *name, uint64_t *value) -{ - const mzap_phys_t *mz; - const mzap_ent_phys_t *mze; - size_t size; - int chunks, i; - - /* - * Microzap objects use exactly one block. Read the whole - * thing. - */ - size = dnode->dn_datablkszsec * 512; - - mz = (const mzap_phys_t *) zap_scratch; - chunks = size / MZAP_ENT_LEN - 1; - - for (i = 0; i < chunks; i++) { - mze = &mz->mz_chunk[i]; - if (!strcmp(mze->mze_name, name)) { - *value = mze->mze_value; - return (0); - } - } - - return (ENOENT); -} - -/* - * Compare a name with a zap leaf entry. Return non-zero if the name - * matches. - */ -static int -fzap_name_equal(const zap_leaf_t *zl, const zap_leaf_chunk_t *zc, const char *name) -{ - size_t namelen; - const zap_leaf_chunk_t *nc; - const char *p; - - namelen = zc->l_entry.le_name_numints; - - nc = &ZAP_LEAF_CHUNK(zl, zc->l_entry.le_name_chunk); - p = name; - while (namelen > 0) { - size_t len; - len = namelen; - if (len > ZAP_LEAF_ARRAY_BYTES) - len = ZAP_LEAF_ARRAY_BYTES; - if (memcmp(p, nc->l_array.la_array, len)) - return (0); - p += len; - namelen -= len; - nc = &ZAP_LEAF_CHUNK(zl, nc->l_array.la_next); - } - - return 1; -} - -/* - * Extract a uint64_t value from a zap leaf entry. - */ -static uint64_t -fzap_leaf_value(const zap_leaf_t *zl, const zap_leaf_chunk_t *zc) -{ - const zap_leaf_chunk_t *vc; - int i; - uint64_t value; - const uint8_t *p; - - vc = &ZAP_LEAF_CHUNK(zl, zc->l_entry.le_value_chunk); - for (i = 0, value = 0, p = vc->l_array.la_array; i < 8; i++) { - value = (value << 8) | p[i]; - } - - return value; -} - -static void -stv(int len, void *addr, uint64_t value) -{ - switch (len) { - case 1: - *(uint8_t *)addr = value; - return; - case 2: - *(uint16_t *)addr = value; - return; - case 4: - *(uint32_t *)addr = value; - return; - case 8: - *(uint64_t *)addr = value; - return; - } -} - -/* - * Extract a array from a zap leaf entry. - */ -static void -fzap_leaf_array(const zap_leaf_t *zl, const zap_leaf_chunk_t *zc, - uint64_t integer_size, uint64_t num_integers, void *buf) -{ - uint64_t array_int_len = zc->l_entry.le_value_intlen; - uint64_t value = 0; - uint64_t *u64 = buf; - char *p = buf; - int len = MIN(zc->l_entry.le_value_numints, num_integers); - int chunk = zc->l_entry.le_value_chunk; - int byten = 0; - - if (integer_size == 8 && len == 1) { - *u64 = fzap_leaf_value(zl, zc); - return; - } - - while (len > 0) { - struct zap_leaf_array *la = &ZAP_LEAF_CHUNK(zl, chunk).l_array; - int i; - - ASSERT3U(chunk, <, ZAP_LEAF_NUMCHUNKS(zl)); - for (i = 0; i < ZAP_LEAF_ARRAY_BYTES && len > 0; i++) { - value = (value << 8) | la->la_array[i]; - byten++; - if (byten == array_int_len) { - stv(integer_size, p, value); - byten = 0; - len--; - if (len == 0) - return; - p += integer_size; - } - } - chunk = la->la_next; - } -} - -/* - * Lookup a value in a fatzap directory. Assumes that the zap scratch - * buffer contains the directory header. - */ -static int -fzap_lookup(const spa_t *spa, const dnode_phys_t *dnode, const char *name, - uint64_t integer_size, uint64_t num_integers, void *value) -{ - int bsize = dnode->dn_datablkszsec << SPA_MINBLOCKSHIFT; - zap_phys_t zh = *(zap_phys_t *) zap_scratch; - fat_zap_t z; - uint64_t *ptrtbl; - uint64_t hash; - int rc; - - if (zh.zap_magic != ZAP_MAGIC) - return (EIO); - - z.zap_block_shift = ilog2(bsize); - z.zap_phys = (zap_phys_t *) zap_scratch; - - /* - * Figure out where the pointer table is and read it in if necessary. - */ - if (zh.zap_ptrtbl.zt_blk) { - rc = dnode_read(spa, dnode, zh.zap_ptrtbl.zt_blk * bsize, - zap_scratch, bsize); - if (rc) - return (rc); - ptrtbl = (uint64_t *) zap_scratch; - } else { - ptrtbl = &ZAP_EMBEDDED_PTRTBL_ENT(&z, 0); - } - - hash = zap_hash(zh.zap_salt, name); - - zap_leaf_t zl; - zl.l_bs = z.zap_block_shift; - - off_t off = ptrtbl[hash >> (64 - zh.zap_ptrtbl.zt_shift)] << zl.l_bs; - zap_leaf_chunk_t *zc; - - rc = dnode_read(spa, dnode, off, zap_scratch, bsize); - if (rc) - return (rc); - - zl.l_phys = (zap_leaf_phys_t *) zap_scratch; - - /* - * Make sure this chunk matches our hash. - */ - if (zl.l_phys->l_hdr.lh_prefix_len > 0 - && zl.l_phys->l_hdr.lh_prefix - != hash >> (64 - zl.l_phys->l_hdr.lh_prefix_len)) - return (ENOENT); - - /* - * Hash within the chunk to find our entry. - */ - int shift = (64 - ZAP_LEAF_HASH_SHIFT(&zl) - zl.l_phys->l_hdr.lh_prefix_len); - int h = (hash >> shift) & ((1 << ZAP_LEAF_HASH_SHIFT(&zl)) - 1); - h = zl.l_phys->l_hash[h]; - if (h == 0xffff) - return (ENOENT); - zc = &ZAP_LEAF_CHUNK(&zl, h); - while (zc->l_entry.le_hash != hash) { - if (zc->l_entry.le_next == 0xffff) { - zc = NULL; - break; - } - zc = &ZAP_LEAF_CHUNK(&zl, zc->l_entry.le_next); - } - if (fzap_name_equal(&zl, zc, name)) { - if (zc->l_entry.le_value_intlen * zc->l_entry.le_value_numints > - integer_size * num_integers) - return (E2BIG); - fzap_leaf_array(&zl, zc, integer_size, num_integers, value); - return (0); - } - - return (ENOENT); -} - -/* - * Lookup a name in a zap object and return its value as a uint64_t. - */ -static int -zap_lookup(const spa_t *spa, const dnode_phys_t *dnode, const char *name, - uint64_t integer_size, uint64_t num_integers, void *value) -{ - int rc; - uint64_t zap_type; - size_t size = dnode->dn_datablkszsec << SPA_MINBLOCKSHIFT; - - rc = dnode_read(spa, dnode, 0, zap_scratch, size); - if (rc) - return (rc); - - zap_type = *(uint64_t *) zap_scratch; - if (zap_type == ZBT_MICRO) - return mzap_lookup(dnode, name, value); - else if (zap_type == ZBT_HEADER) { - return fzap_lookup(spa, dnode, name, integer_size, - num_integers, value); - } - printf("ZFS: invalid zap_type=%d\n", (int)zap_type); - return (EIO); -} - -/* - * List a microzap directory. Assumes that the zap scratch buffer contains - * the directory contents. - */ -static int -mzap_list(const dnode_phys_t *dnode, int (*callback)(const char *, uint64_t)) -{ - const mzap_phys_t *mz; - const mzap_ent_phys_t *mze; - size_t size; - int chunks, i, rc; - - /* - * Microzap objects use exactly one block. Read the whole - * thing. - */ - size = dnode->dn_datablkszsec * 512; - mz = (const mzap_phys_t *) zap_scratch; - chunks = size / MZAP_ENT_LEN - 1; - - for (i = 0; i < chunks; i++) { - mze = &mz->mz_chunk[i]; - if (mze->mze_name[0]) { - rc = callback(mze->mze_name, mze->mze_value); - if (rc != 0) - return (rc); - } - } - - return (0); -} - -/* - * List a fatzap directory. Assumes that the zap scratch buffer contains - * the directory header. - */ -static int -fzap_list(const spa_t *spa, const dnode_phys_t *dnode, int (*callback)(const char *, uint64_t)) -{ - int bsize = dnode->dn_datablkszsec << SPA_MINBLOCKSHIFT; - zap_phys_t zh = *(zap_phys_t *) zap_scratch; - fat_zap_t z; - int i, j, rc; - - if (zh.zap_magic != ZAP_MAGIC) - return (EIO); - - z.zap_block_shift = ilog2(bsize); - z.zap_phys = (zap_phys_t *) zap_scratch; - - /* - * This assumes that the leaf blocks start at block 1. The - * documentation isn't exactly clear on this. - */ - zap_leaf_t zl; - zl.l_bs = z.zap_block_shift; - for (i = 0; i < zh.zap_num_leafs; i++) { - off_t off = (i + 1) << zl.l_bs; - char name[256], *p; - uint64_t value; - - if (dnode_read(spa, dnode, off, zap_scratch, bsize)) - return (EIO); - - zl.l_phys = (zap_leaf_phys_t *) zap_scratch; - - for (j = 0; j < ZAP_LEAF_NUMCHUNKS(&zl); j++) { - zap_leaf_chunk_t *zc, *nc; - int namelen; - - zc = &ZAP_LEAF_CHUNK(&zl, j); - if (zc->l_entry.le_type != ZAP_CHUNK_ENTRY) - continue; - namelen = zc->l_entry.le_name_numints; - if (namelen > sizeof(name)) - namelen = sizeof(name); - - /* - * Paste the name back together. - */ - nc = &ZAP_LEAF_CHUNK(&zl, zc->l_entry.le_name_chunk); - p = name; - while (namelen > 0) { - int len; - len = namelen; - if (len > ZAP_LEAF_ARRAY_BYTES) - len = ZAP_LEAF_ARRAY_BYTES; - memcpy(p, nc->l_array.la_array, len); - p += len; - namelen -= len; - nc = &ZAP_LEAF_CHUNK(&zl, nc->l_array.la_next); - } - - /* - * Assume the first eight bytes of the value are - * a uint64_t. - */ - value = fzap_leaf_value(&zl, zc); - - //printf("%s 0x%jx\n", name, (uintmax_t)value); - rc = callback((const char *)name, value); - if (rc != 0) - return (rc); - } - } - - return (0); -} - -static int zfs_printf(const char *name, uint64_t value __unused) -{ - - printf("%s\n", name); - - return (0); -} - -/* - * List a zap directory. - */ -static int -zap_list(const spa_t *spa, const dnode_phys_t *dnode) -{ - uint64_t zap_type; - size_t size = dnode->dn_datablkszsec * 512; - - if (dnode_read(spa, dnode, 0, zap_scratch, size)) - return (EIO); - - zap_type = *(uint64_t *) zap_scratch; - if (zap_type == ZBT_MICRO) - return mzap_list(dnode, zfs_printf); - else - return fzap_list(spa, dnode, zfs_printf); -} - -static int -objset_get_dnode(const spa_t *spa, const objset_phys_t *os, uint64_t objnum, dnode_phys_t *dnode) -{ - off_t offset; - - offset = objnum * sizeof(dnode_phys_t); - return dnode_read(spa, &os->os_meta_dnode, offset, - dnode, sizeof(dnode_phys_t)); -} - -static int -mzap_rlookup(const spa_t *spa, const dnode_phys_t *dnode, char *name, uint64_t value) -{ - const mzap_phys_t *mz; - const mzap_ent_phys_t *mze; - size_t size; - int chunks, i; - - /* - * Microzap objects use exactly one block. Read the whole - * thing. - */ - size = dnode->dn_datablkszsec * 512; - - mz = (const mzap_phys_t *) zap_scratch; - chunks = size / MZAP_ENT_LEN - 1; - - for (i = 0; i < chunks; i++) { - mze = &mz->mz_chunk[i]; - if (value == mze->mze_value) { - strcpy(name, mze->mze_name); - return (0); - } - } - - return (ENOENT); -} - -static void -fzap_name_copy(const zap_leaf_t *zl, const zap_leaf_chunk_t *zc, char *name) -{ - size_t namelen; - const zap_leaf_chunk_t *nc; - char *p; - - namelen = zc->l_entry.le_name_numints; - - nc = &ZAP_LEAF_CHUNK(zl, zc->l_entry.le_name_chunk); - p = name; - while (namelen > 0) { - size_t len; - len = namelen; - if (len > ZAP_LEAF_ARRAY_BYTES) - len = ZAP_LEAF_ARRAY_BYTES; - memcpy(p, nc->l_array.la_array, len); - p += len; - namelen -= len; - nc = &ZAP_LEAF_CHUNK(zl, nc->l_array.la_next); - } - - *p = '\0'; -} - -static int -fzap_rlookup(const spa_t *spa, const dnode_phys_t *dnode, char *name, uint64_t value) -{ - int bsize = dnode->dn_datablkszsec << SPA_MINBLOCKSHIFT; - zap_phys_t zh = *(zap_phys_t *) zap_scratch; - fat_zap_t z; - int i, j; - - if (zh.zap_magic != ZAP_MAGIC) - return (EIO); - - z.zap_block_shift = ilog2(bsize); - z.zap_phys = (zap_phys_t *) zap_scratch; - - /* - * This assumes that the leaf blocks start at block 1. The - * documentation isn't exactly clear on this. - */ - zap_leaf_t zl; - zl.l_bs = z.zap_block_shift; - for (i = 0; i < zh.zap_num_leafs; i++) { - off_t off = (i + 1) << zl.l_bs; - - if (dnode_read(spa, dnode, off, zap_scratch, bsize)) - return (EIO); - - zl.l_phys = (zap_leaf_phys_t *) zap_scratch; - - for (j = 0; j < ZAP_LEAF_NUMCHUNKS(&zl); j++) { - zap_leaf_chunk_t *zc; - - zc = &ZAP_LEAF_CHUNK(&zl, j); - if (zc->l_entry.le_type != ZAP_CHUNK_ENTRY) - continue; - if (zc->l_entry.le_value_intlen != 8 || - zc->l_entry.le_value_numints != 1) - continue; - - if (fzap_leaf_value(&zl, zc) == value) { - fzap_name_copy(&zl, zc, name); - return (0); - } - } - } - - return (ENOENT); -} - -static int -zap_rlookup(const spa_t *spa, const dnode_phys_t *dnode, char *name, uint64_t value) -{ - int rc; - uint64_t zap_type; - size_t size = dnode->dn_datablkszsec * 512; - - rc = dnode_read(spa, dnode, 0, zap_scratch, size); - if (rc) - return (rc); - - zap_type = *(uint64_t *) zap_scratch; - if (zap_type == ZBT_MICRO) - return mzap_rlookup(spa, dnode, name, value); - else - return fzap_rlookup(spa, dnode, name, value); -} - -static int -zfs_rlookup(const spa_t *spa, uint64_t objnum, char *result) -{ - char name[256]; - char component[256]; - uint64_t dir_obj, parent_obj, child_dir_zapobj; - dnode_phys_t child_dir_zap, dataset, dir, parent; - dsl_dir_phys_t *dd; - dsl_dataset_phys_t *ds; - char *p; - int len; - - p = &name[sizeof(name) - 1]; - *p = '\0'; - - if (objset_get_dnode(spa, &spa->spa_mos, objnum, &dataset)) { - printf("ZFS: can't find dataset %ju\n", (uintmax_t)objnum); - return (EIO); - } - ds = (dsl_dataset_phys_t *)&dataset.dn_bonus; - dir_obj = ds->ds_dir_obj; - - for (;;) { - if (objset_get_dnode(spa, &spa->spa_mos, dir_obj, &dir) != 0) - return (EIO); - dd = (dsl_dir_phys_t *)&dir.dn_bonus; - - /* Actual loop condition. */ - parent_obj = dd->dd_parent_obj; - if (parent_obj == 0) - break; - - if (objset_get_dnode(spa, &spa->spa_mos, parent_obj, &parent) != 0) - return (EIO); - dd = (dsl_dir_phys_t *)&parent.dn_bonus; - child_dir_zapobj = dd->dd_child_dir_zapobj; - if (objset_get_dnode(spa, &spa->spa_mos, child_dir_zapobj, &child_dir_zap) != 0) - return (EIO); - if (zap_rlookup(spa, &child_dir_zap, component, dir_obj) != 0) - return (EIO); - - len = strlen(component); - p -= len; - memcpy(p, component, len); - --p; - *p = '/'; - - /* Actual loop iteration. */ - dir_obj = parent_obj; - } - - if (*p != '\0') - ++p; - strcpy(result, p); - - return (0); -} - -static int -zfs_lookup_dataset(const spa_t *spa, const char *name, uint64_t *objnum) -{ - char element[256]; - uint64_t dir_obj, child_dir_zapobj; - dnode_phys_t child_dir_zap, dir; - dsl_dir_phys_t *dd; - const char *p, *q; - - if (objset_get_dnode(spa, &spa->spa_mos, DMU_POOL_DIRECTORY_OBJECT, &dir)) - return (EIO); - if (zap_lookup(spa, &dir, DMU_POOL_ROOT_DATASET, sizeof (dir_obj), - 1, &dir_obj)) - return (EIO); - - p = name; - for (;;) { - if (objset_get_dnode(spa, &spa->spa_mos, dir_obj, &dir)) - return (EIO); - dd = (dsl_dir_phys_t *)&dir.dn_bonus; - - while (*p == '/') - p++; - /* Actual loop condition #1. */ - if (*p == '\0') - break; - - q = strchr(p, '/'); - if (q) { - memcpy(element, p, q - p); - element[q - p] = '\0'; - p = q + 1; - } else { - strcpy(element, p); - p += strlen(p); - } - - child_dir_zapobj = dd->dd_child_dir_zapobj; - if (objset_get_dnode(spa, &spa->spa_mos, child_dir_zapobj, &child_dir_zap) != 0) - return (EIO); - - /* Actual loop condition #2. */ - if (zap_lookup(spa, &child_dir_zap, element, sizeof (dir_obj), - 1, &dir_obj) != 0) - return (ENOENT); - } - - *objnum = dd->dd_head_dataset_obj; - return (0); -} - -#ifndef BOOT2 -static int -zfs_list_dataset(const spa_t *spa, uint64_t objnum/*, int pos, char *entry*/) -{ - uint64_t dir_obj, child_dir_zapobj; - dnode_phys_t child_dir_zap, dir, dataset; - dsl_dataset_phys_t *ds; - dsl_dir_phys_t *dd; - - if (objset_get_dnode(spa, &spa->spa_mos, objnum, &dataset)) { - printf("ZFS: can't find dataset %ju\n", (uintmax_t)objnum); - return (EIO); - } - ds = (dsl_dataset_phys_t *) &dataset.dn_bonus; - dir_obj = ds->ds_dir_obj; - - if (objset_get_dnode(spa, &spa->spa_mos, dir_obj, &dir)) { - printf("ZFS: can't find dirobj %ju\n", (uintmax_t)dir_obj); - return (EIO); - } - dd = (dsl_dir_phys_t *)&dir.dn_bonus; - - child_dir_zapobj = dd->dd_child_dir_zapobj; - if (objset_get_dnode(spa, &spa->spa_mos, child_dir_zapobj, &child_dir_zap) != 0) { - printf("ZFS: can't find child zap %ju\n", (uintmax_t)dir_obj); - return (EIO); - } - - return (zap_list(spa, &child_dir_zap) != 0); -} - -int -zfs_callback_dataset(const spa_t *spa, uint64_t objnum, int (*callback)(const char *, uint64_t)) -{ - uint64_t dir_obj, child_dir_zapobj, zap_type; - dnode_phys_t child_dir_zap, dir, dataset; - dsl_dataset_phys_t *ds; - dsl_dir_phys_t *dd; - int err; - - err = objset_get_dnode(spa, &spa->spa_mos, objnum, &dataset); - if (err != 0) { - printf("ZFS: can't find dataset %ju\n", (uintmax_t)objnum); - return (err); - } - ds = (dsl_dataset_phys_t *) &dataset.dn_bonus; - dir_obj = ds->ds_dir_obj; - - err = objset_get_dnode(spa, &spa->spa_mos, dir_obj, &dir); - if (err != 0) { - printf("ZFS: can't find dirobj %ju\n", (uintmax_t)dir_obj); - return (err); - } - dd = (dsl_dir_phys_t *)&dir.dn_bonus; - - child_dir_zapobj = dd->dd_child_dir_zapobj; - err = objset_get_dnode(spa, &spa->spa_mos, child_dir_zapobj, &child_dir_zap); - if (err != 0) { - printf("ZFS: can't find child zap %ju\n", (uintmax_t)dir_obj); - return (err); - } - - err = dnode_read(spa, &child_dir_zap, 0, zap_scratch, child_dir_zap.dn_datablkszsec * 512); - if (err != 0) - return (err); - - zap_type = *(uint64_t *) zap_scratch; - if (zap_type == ZBT_MICRO) - return mzap_list(&child_dir_zap, callback); - else - return fzap_list(spa, &child_dir_zap, callback); -} -#endif - -/* - * Find the object set given the object number of its dataset object - * and return its details in *objset - */ -static int -zfs_mount_dataset(const spa_t *spa, uint64_t objnum, objset_phys_t *objset) -{ - dnode_phys_t dataset; - dsl_dataset_phys_t *ds; - - if (objset_get_dnode(spa, &spa->spa_mos, objnum, &dataset)) { - printf("ZFS: can't find dataset %ju\n", (uintmax_t)objnum); - return (EIO); - } - - ds = (dsl_dataset_phys_t *) &dataset.dn_bonus; - if (zio_read(spa, &ds->ds_bp, objset)) { - printf("ZFS: can't read object set for dataset %ju\n", - (uintmax_t)objnum); - return (EIO); - } - - return (0); -} - -/* - * Find the object set pointed to by the BOOTFS property or the root - * dataset if there is none and return its details in *objset - */ -static int -zfs_get_root(const spa_t *spa, uint64_t *objid) -{ - dnode_phys_t dir, propdir; - uint64_t props, bootfs, root; - - *objid = 0; - - /* - * Start with the MOS directory object. - */ - if (objset_get_dnode(spa, &spa->spa_mos, DMU_POOL_DIRECTORY_OBJECT, &dir)) { - printf("ZFS: can't read MOS object directory\n"); - return (EIO); - } - - /* - * Lookup the pool_props and see if we can find a bootfs. - */ - if (zap_lookup(spa, &dir, DMU_POOL_PROPS, sizeof (props), 1, &props) == 0 - && objset_get_dnode(spa, &spa->spa_mos, props, &propdir) == 0 - && zap_lookup(spa, &propdir, "bootfs", sizeof (bootfs), 1, &bootfs) == 0 - && bootfs != 0) - { - *objid = bootfs; - return (0); - } - /* - * Lookup the root dataset directory - */ - if (zap_lookup(spa, &dir, DMU_POOL_ROOT_DATASET, sizeof (root), 1, &root) - || objset_get_dnode(spa, &spa->spa_mos, root, &dir)) { - printf("ZFS: can't find root dsl_dir\n"); - return (EIO); - } - - /* - * Use the information from the dataset directory's bonus buffer - * to find the dataset object and from that the object set itself. - */ - dsl_dir_phys_t *dd = (dsl_dir_phys_t *) &dir.dn_bonus; - *objid = dd->dd_head_dataset_obj; - return (0); -} - -static int -zfs_mount(const spa_t *spa, uint64_t rootobj, struct zfsmount *mount) -{ - - mount->spa = spa; - - /* - * Find the root object set if not explicitly provided - */ - if (rootobj == 0 && zfs_get_root(spa, &rootobj)) { - printf("ZFS: can't find root filesystem\n"); - return (EIO); - } - - if (zfs_mount_dataset(spa, rootobj, &mount->objset)) { - printf("ZFS: can't open root filesystem\n"); - return (EIO); - } - - mount->rootobj = rootobj; - - return (0); -} - -/* - * callback function for feature name checks. - */ -static int -check_feature(const char *name, uint64_t value) -{ - int i; - - if (value == 0) - return (0); - if (name[0] == '\0') - return (0); - - for (i = 0; features_for_read[i] != NULL; i++) { - if (strcmp(name, features_for_read[i]) == 0) - return (0); - } - printf("ZFS: unsupported feature: %s\n", name); - return (EIO); -} - -/* - * Checks whether the MOS features that are active are supported. - */ -static int -check_mos_features(const spa_t *spa) -{ - dnode_phys_t dir; - uint64_t objnum, zap_type; - size_t size; - int rc; - - if ((rc = objset_get_dnode(spa, &spa->spa_mos, DMU_OT_OBJECT_DIRECTORY, - &dir)) != 0) - return (rc); - if ((rc = zap_lookup(spa, &dir, DMU_POOL_FEATURES_FOR_READ, - sizeof (objnum), 1, &objnum)) != 0) { - /* - * It is older pool without features. As we have already - * tested the label, just return without raising the error. - */ - return (0); - } - - if ((rc = objset_get_dnode(spa, &spa->spa_mos, objnum, &dir)) != 0) - return (rc); - - if (dir.dn_type != DMU_OTN_ZAP_METADATA) - return (EIO); - - size = dir.dn_datablkszsec * 512; - if (dnode_read(spa, &dir, 0, zap_scratch, size)) - return (EIO); - - zap_type = *(uint64_t *) zap_scratch; - if (zap_type == ZBT_MICRO) - rc = mzap_list(&dir, check_feature); - else - rc = fzap_list(spa, &dir, check_feature); - - return (rc); -} - -static int -zfs_spa_init(spa_t *spa) -{ - dnode_phys_t dir; - int rc; - - if (zio_read(spa, &spa->spa_uberblock.ub_rootbp, &spa->spa_mos)) { - printf("ZFS: can't read MOS of pool %s\n", spa->spa_name); - return (EIO); - } - if (spa->spa_mos.os_type != DMU_OST_META) { - printf("ZFS: corrupted MOS of pool %s\n", spa->spa_name); - return (EIO); - } - - if (objset_get_dnode(spa, &spa->spa_mos, DMU_POOL_DIRECTORY_OBJECT, - &dir)) { - printf("ZFS: failed to read pool %s directory object\n", - spa->spa_name); - return (EIO); - } - /* this is allowed to fail, older pools do not have salt */ - rc = zap_lookup(spa, &dir, DMU_POOL_CHECKSUM_SALT, 1, - sizeof (spa->spa_cksum_salt.zcs_bytes), - spa->spa_cksum_salt.zcs_bytes); - - rc = check_mos_features(spa); - if (rc != 0) { - printf("ZFS: pool %s is not supported\n", spa->spa_name); - } - - return (rc); -} - -static int -zfs_dnode_stat(const spa_t *spa, dnode_phys_t *dn, struct stat *sb) -{ - - if (dn->dn_bonustype != DMU_OT_SA) { - znode_phys_t *zp = (znode_phys_t *)dn->dn_bonus; - - sb->st_mode = zp->zp_mode; - sb->st_uid = zp->zp_uid; - sb->st_gid = zp->zp_gid; - sb->st_size = zp->zp_size; - } else { - sa_hdr_phys_t *sahdrp; - int hdrsize; - size_t size = 0; - void *buf = NULL; - - if (dn->dn_bonuslen != 0) - sahdrp = (sa_hdr_phys_t *)DN_BONUS(dn); - else { - if ((dn->dn_flags & DNODE_FLAG_SPILL_BLKPTR) != 0) { - blkptr_t *bp = DN_SPILL_BLKPTR(dn); - int error; - - size = BP_GET_LSIZE(bp); - buf = zfs_alloc(size); - error = zio_read(spa, bp, buf); - if (error != 0) { - zfs_free(buf, size); - return (error); - } - sahdrp = buf; - } else { - return (EIO); - } - } - hdrsize = SA_HDR_SIZE(sahdrp); - sb->st_mode = *(uint64_t *)((char *)sahdrp + hdrsize + - SA_MODE_OFFSET); - sb->st_uid = *(uint64_t *)((char *)sahdrp + hdrsize + - SA_UID_OFFSET); - sb->st_gid = *(uint64_t *)((char *)sahdrp + hdrsize + - SA_GID_OFFSET); - sb->st_size = *(uint64_t *)((char *)sahdrp + hdrsize + - SA_SIZE_OFFSET); - if (buf != NULL) - zfs_free(buf, size); - } - - return (0); -} - -static int -zfs_dnode_readlink(const spa_t *spa, dnode_phys_t *dn, char *path, size_t psize) -{ - int rc = 0; - - if (dn->dn_bonustype == DMU_OT_SA) { - sa_hdr_phys_t *sahdrp = NULL; - size_t size = 0; - void *buf = NULL; - int hdrsize; - char *p; - - if (dn->dn_bonuslen != 0) - sahdrp = (sa_hdr_phys_t *)DN_BONUS(dn); - else { - blkptr_t *bp; - - if ((dn->dn_flags & DNODE_FLAG_SPILL_BLKPTR) == 0) - return (EIO); - bp = DN_SPILL_BLKPTR(dn); - - size = BP_GET_LSIZE(bp); - buf = zfs_alloc(size); - rc = zio_read(spa, bp, buf); - if (rc != 0) { - zfs_free(buf, size); - return (rc); - } - sahdrp = buf; - } - hdrsize = SA_HDR_SIZE(sahdrp); - p = (char *)((uintptr_t)sahdrp + hdrsize + SA_SYMLINK_OFFSET); - memcpy(path, p, psize); - if (buf != NULL) - zfs_free(buf, size); - return (0); - } - /* - * Second test is purely to silence bogus compiler - * warning about accessing past the end of dn_bonus. - */ - if (psize + sizeof(znode_phys_t) <= dn->dn_bonuslen && - sizeof(znode_phys_t) <= sizeof(dn->dn_bonus)) { - memcpy(path, &dn->dn_bonus[sizeof(znode_phys_t)], psize); - } else { - rc = dnode_read(spa, dn, 0, path, psize); - } - return (rc); -} - -struct obj_list { - uint64_t objnum; - STAILQ_ENTRY(obj_list) entry; -}; - -/* - * Lookup a file and return its dnode. - */ -static int -zfs_lookup(const struct zfsmount *mount, const char *upath, dnode_phys_t *dnode) -{ - int rc; - uint64_t objnum; - const spa_t *spa; - dnode_phys_t dn; - const char *p, *q; - char element[256]; - char path[1024]; - int symlinks_followed = 0; - struct stat sb; - struct obj_list *entry, *tentry; - STAILQ_HEAD(, obj_list) on_cache = STAILQ_HEAD_INITIALIZER(on_cache); - - spa = mount->spa; - if (mount->objset.os_type != DMU_OST_ZFS) { - printf("ZFS: unexpected object set type %ju\n", - (uintmax_t)mount->objset.os_type); - return (EIO); - } - - if ((entry = malloc(sizeof(struct obj_list))) == NULL) - return (ENOMEM); - - /* - * Get the root directory dnode. - */ - rc = objset_get_dnode(spa, &mount->objset, MASTER_NODE_OBJ, &dn); - if (rc) { - free(entry); - return (rc); - } - - rc = zap_lookup(spa, &dn, ZFS_ROOT_OBJ, sizeof (objnum), 1, &objnum); - if (rc) { - free(entry); - return (rc); - } - entry->objnum = objnum; - STAILQ_INSERT_HEAD(&on_cache, entry, entry); - - rc = objset_get_dnode(spa, &mount->objset, objnum, &dn); - if (rc != 0) - goto done; - - p = upath; - while (p && *p) { - rc = objset_get_dnode(spa, &mount->objset, objnum, &dn); - if (rc != 0) - goto done; - - while (*p == '/') - p++; - if (*p == '\0') - break; - q = p; - while (*q != '\0' && *q != '/') - q++; - - /* skip dot */ - if (p + 1 == q && p[0] == '.') { - p++; - continue; - } - /* double dot */ - if (p + 2 == q && p[0] == '.' && p[1] == '.') { - p += 2; - if (STAILQ_FIRST(&on_cache) == - STAILQ_LAST(&on_cache, obj_list, entry)) { - rc = ENOENT; - goto done; - } - entry = STAILQ_FIRST(&on_cache); - STAILQ_REMOVE_HEAD(&on_cache, entry); - free(entry); - objnum = (STAILQ_FIRST(&on_cache))->objnum; - continue; - } - if (q - p + 1 > sizeof(element)) { - rc = ENAMETOOLONG; - goto done; - } - memcpy(element, p, q - p); - element[q - p] = 0; - p = q; - - if ((rc = zfs_dnode_stat(spa, &dn, &sb)) != 0) - goto done; - if (!S_ISDIR(sb.st_mode)) { - rc = ENOTDIR; - goto done; - } - - rc = zap_lookup(spa, &dn, element, sizeof (objnum), 1, &objnum); - if (rc) - goto done; - objnum = ZFS_DIRENT_OBJ(objnum); - - if ((entry = malloc(sizeof(struct obj_list))) == NULL) { - rc = ENOMEM; - goto done; - } - entry->objnum = objnum; - STAILQ_INSERT_HEAD(&on_cache, entry, entry); - rc = objset_get_dnode(spa, &mount->objset, objnum, &dn); - if (rc) - goto done; - - /* - * Check for symlink. - */ - rc = zfs_dnode_stat(spa, &dn, &sb); - if (rc) - goto done; - if (S_ISLNK(sb.st_mode)) { - if (symlinks_followed > 10) { - rc = EMLINK; - goto done; - } - symlinks_followed++; - - /* - * Read the link value and copy the tail of our - * current path onto the end. - */ - if (sb.st_size + strlen(p) + 1 > sizeof(path)) { - rc = ENAMETOOLONG; - goto done; - } - strcpy(&path[sb.st_size], p); - - rc = zfs_dnode_readlink(spa, &dn, path, sb.st_size); - if (rc != 0) - goto done; - - /* - * Restart with the new path, starting either at - * the root or at the parent depending whether or - * not the link is relative. - */ - p = path; - if (*p == '/') { - while (STAILQ_FIRST(&on_cache) != - STAILQ_LAST(&on_cache, obj_list, entry)) { - entry = STAILQ_FIRST(&on_cache); - STAILQ_REMOVE_HEAD(&on_cache, entry); - free(entry); - } - } else { - entry = STAILQ_FIRST(&on_cache); - STAILQ_REMOVE_HEAD(&on_cache, entry); - free(entry); - } - objnum = (STAILQ_FIRST(&on_cache))->objnum; - } - } - - *dnode = dn; -done: - STAILQ_FOREACH_SAFE(entry, &on_cache, entry, tentry) - free(entry); - return (rc); -} Property changes on: stable/11/stand/zfs/zfsimpl.c ___________________________________________________________________ Deleted: svn:eol-style ## -1 +0,0 ## -native \ No newline at end of property Deleted: svn:keywords ## -1 +0,0 ## -FreeBSD=%H \ No newline at end of property Deleted: svn:mime-type ## -1 +0,0 ## -text/plain \ No newline at end of property Index: stable/11/stand/zfs/libzfs.h =================================================================== --- stable/11/stand/zfs/libzfs.h (revision 344376) +++ stable/11/stand/zfs/libzfs.h (nonexistent) @@ -1,86 +0,0 @@ -/*- - * Copyright (c) 2012 Andriy Gapon - * All rights reserved. - * - * Redistribution and use in source and binary forms, with or without - * modification, are permitted provided that the following conditions - * are met: - * 1. Redistributions of source code must retain the above copyright - * notice, this list of conditions and the following disclaimer. - * 2. Redistributions in binary form must reproduce the above copyright - * notice, this list of conditions and the following disclaimer in the - * documentation and/or other materials provided with the distribution. - * - * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND - * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE - * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE - * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE - * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL - * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS - * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) - * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT - * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY - * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF - * SUCH DAMAGE. - * - * $FreeBSD$ - */ - -#ifndef _BOOT_LIBZFS_H_ -#define _BOOT_LIBZFS_H_ - -#define ZFS_MAXNAMELEN 256 - -/* - * ZFS fully-qualified device descriptor. - */ -struct zfs_devdesc { - struct devdesc dd; /* Must be first. */ - uint64_t pool_guid; - uint64_t root_guid; -}; - -#ifdef LOADER_GELI_SUPPORT -#include -#endif - -struct zfs_boot_args -{ - uint32_t size; - uint32_t reserved; - uint64_t pool; - uint64_t root; - uint64_t primary_pool; - uint64_t primary_vdev; - union { - char gelipw[256]; - struct { - char notapw; /* - * single null byte to stop keybuf - * being interpreted as a password - */ - uint32_t keybuf_sentinel; -#ifdef LOADER_GELI_SUPPORT - struct keybuf *keybuf; -#else - void *keybuf; -#endif - }; - }; -}; - -int zfs_parsedev(struct zfs_devdesc *dev, const char *devspec, - const char **path); -char *zfs_fmtdev(void *vdev); -int zfs_probe_dev(const char *devname, uint64_t *pool_guid); -int zfs_list(const char *name); -uint64_t ldi_get_size(void *); -void init_zfs_bootenv(const char *currdev); -int zfs_bootenv(const char *name); -int zfs_belist_add(const char *name, uint64_t __unused); -int zfs_set_env(void); - -extern struct devsw zfs_dev; -extern struct fs_ops zfs_fsops; - -#endif /*_BOOT_LIBZFS_H_*/ Property changes on: stable/11/stand/zfs/libzfs.h ___________________________________________________________________ Deleted: svn:eol-style ## -1 +0,0 ## -native \ No newline at end of property Deleted: svn:keywords ## -1 +0,0 ## -FreeBSD=%H \ No newline at end of property Deleted: svn:mime-type ## -1 +0,0 ## -text/plain \ No newline at end of property Index: stable/11/stand/zfs/devicename_stubs.c =================================================================== --- stable/11/stand/zfs/devicename_stubs.c (revision 344376) +++ stable/11/stand/zfs/devicename_stubs.c (nonexistent) @@ -1,47 +0,0 @@ -/*- - * Copyright (c) 2012 Andriy Gapon - * All rights reserved. - * - * Redistribution and use in source and binary forms, with or without - * modification, are permitted provided that the following conditions - * are met: - * 1. Redistributions of source code must retain the above copyright - * notice, this list of conditions and the following disclaimer. - * 2. Redistributions in binary form must reproduce the above copyright - * notice, this list of conditions and the following disclaimer in the - * documentation and/or other materials provided with the distribution. - * - * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND - * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE - * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE - * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE - * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL - * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS - * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) - * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT - * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY - * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF - * SUCH DAMAGE. - */ - -#include -__FBSDID("$FreeBSD$"); - -#include -#include "libzfs.h" - -__attribute__((weak)) -int -zfs_parsedev(struct zfs_devdesc *dev, const char *devspec, const char **path) -{ - return (EINVAL); -} - -__attribute__((weak)) -char * -zfs_fmtdev(void *vdev) -{ - static char buf[128]; - - return (buf); -} Property changes on: stable/11/stand/zfs/devicename_stubs.c ___________________________________________________________________ Deleted: svn:eol-style ## -1 +0,0 ## -native \ No newline at end of property Deleted: svn:keywords ## -1 +0,0 ## -FreeBSD=%H \ No newline at end of property Deleted: svn:mime-type ## -1 +0,0 ## -text/plain \ No newline at end of property Index: stable/11/stand/zfs/Makefile =================================================================== --- stable/11/stand/zfs/Makefile (revision 344376) +++ stable/11/stand/zfs/Makefile (nonexistent) @@ -1,20 +0,0 @@ -# $FreeBSD$ - -.include - -LIB= zfsboot - -.PATH: ${ZFSSRC} -SRCS+= zfs.c skein.c skein_block.c -# Do not unroll skein loops, reduce code size -CFLAGS+= -DSKEIN_LOOP=111 -.PATH: ${SYSDIR}/crypto/skein - -CFLAGS+= -DBOOTPROG=\"zfsloader\" -CFLAGS+= -I${LDRSRC} -CFLAGS+= -I${SYSDIR}/cddl/boot/zfs -CFLAGS+= -I${SYSDIR}/crypto/skein - -CFLAGS+= -Wformat -Wall - -.include Property changes on: stable/11/stand/zfs/Makefile ___________________________________________________________________ Deleted: svn:eol-style ## -1 +0,0 ## -native \ No newline at end of property Deleted: svn:keywords ## -1 +0,0 ## -FreeBSD=%H \ No newline at end of property Deleted: svn:mime-type ## -1 +0,0 ## -text/plain \ No newline at end of property Index: stable/11/stand/Makefile =================================================================== --- stable/11/stand/Makefile (revision 344376) +++ stable/11/stand/Makefile (revision 344377) @@ -1,42 +1,41 @@ # $FreeBSD$ .include # For amd64 we have to build 32 and 64 bit versions of things. For # others we don't. LIB32LIST is a list of libraries, which if # included, need to be built 32-bit as well. .if ${MACHINE_ARCH} == "amd64" -LIB32LIST=libsa ficl liblua zfs +LIB32LIST=libsa ficl liblua .endif S.yes+= libsa S.${MK_FORTH}+= ficl S.${MK_FORTH}+= forth S.${MK_LOADER_LUA}+= liblua S.${MK_LOADER_LUA}+= lua S.${MK_FDT}+= fdt S.${MK_LOADER_OFW}+= ofw -S.${MK_ZFS}+= zfs S.yes+= defaults S.yes+= man .include S.${MK_EFI}+= efi S.${MK_LOADER_UBOOT}+= uboot .if exists(${.CURDIR}/${MACHINE}/.) S.yes+= ${MACHINE} .endif # Build the actual subdir list from S.yes, adding in the 32-bit # variant if necessary. .for _x in ${S.yes} SUBDIR+=${_x} .if defined(LIB32LIST) && ${LIB32LIST:M${_x}} SUBDIR+=${_x}32 .endif .endfor .include Index: stable/11/stand/common/zfs_cmd.c =================================================================== --- stable/11/stand/common/zfs_cmd.c (revision 344376) +++ stable/11/stand/common/zfs_cmd.c (revision 344377) @@ -1,108 +1,108 @@ /*- * Copyright (c) 2018 Warner Losh * All rights reserved. * * Redistribution and use in source and binary forms, with or without * modification, are permitted provided that the following conditions * are met: * 1. Redistributions of source code must retain the above copyright * notice, this list of conditions and the following disclaimer. * 2. Redistributions in binary form must reproduce the above copyright * notice, this list of conditions and the following disclaimer in the * documentation and/or other materials provided with the distribution. * * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF * SUCH DAMAGE. */ #include __FBSDID("$FreeBSD$"); /* * MD bootstrap main() and assorted miscellaneous * commands. */ #include #include #include #include #include "bootstrap.h" #ifdef LOADER_ZFS_SUPPORT -#include "../zfs/libzfs.h" +#include "libzfs.h" #endif COMMAND_SET(lszfs, "lszfs", "list child datasets of a zfs dataset", command_lszfs); static int command_lszfs(int argc, char *argv[]) { int err; if (argc != 2) { command_errmsg = "a single dataset must be supplied"; return (CMD_ERROR); } err = zfs_list(argv[1]); if (err != 0) { command_errmsg = strerror(err); return (CMD_ERROR); } return (CMD_OK); } COMMAND_SET(reloadbe, "reloadbe", "refresh the list of ZFS Boot Environments", command_reloadbe); static int command_reloadbe(int argc, char *argv[]) { int err; char *root; if (argc > 2) { command_errmsg = "wrong number of arguments"; return (CMD_ERROR); } if (argc == 2) { err = zfs_bootenv(argv[1]); } else { root = getenv("zfs_be_root"); if (root == NULL) { /* There does not appear to be a ZFS pool here, exit without error */ return (CMD_OK); } err = zfs_bootenv(root); } if (err != 0) { command_errmsg = strerror(err); return (CMD_ERROR); } return (CMD_OK); } uint64_t ldi_get_size(void *priv) { int fd = (uintptr_t) priv; uint64_t size; ioctl(fd, DIOCGMEDIASIZE, &size); return (size); } Index: stable/11/stand/defs.mk =================================================================== --- stable/11/stand/defs.mk (revision 344376) +++ stable/11/stand/defs.mk (revision 344377) @@ -1,194 +1,194 @@ # $FreeBSD$ .include WARNS?=1 .if !defined(__BOOT_DEFS_MK__) __BOOT_DEFS_MK__=${MFILE} MK_CTF= no MK_SSP= no MK_PROFILE= no MAN= .if !defined(PIC) NO_PIC= INTERNALLIB= .endif BOOTSRC= ${SRCTOP}/stand EFISRC= ${BOOTSRC}/efi EFIINC= ${EFISRC}/include EFIINCMD= ${EFIINC}/${MACHINE} FDTSRC= ${BOOTSRC}/fdt FICLSRC= ${BOOTSRC}/ficl LDRSRC= ${BOOTSRC}/common LIBLUASRC= ${BOOTSRC}/liblua LUASRC= ${SRCTOP}/contrib/lua/src SASRC= ${BOOTSRC}/libsa SYSDIR= ${SRCTOP}/sys UBOOTSRC= ${BOOTSRC}/uboot -ZFSSRC= ${BOOTSRC}/zfs +ZFSSRC= ${SASRC}/zfs BOOTOBJ= ${OBJTOP}/stand # BINDIR is where we install BINDIR?= /boot LIBSA= ${BOOTOBJ}/libsa/libsa.a .if ${MACHINE} == "i386" LIBSA32= ${LIBSA} .else LIBSA32= ${BOOTOBJ}/libsa32/libsa32.a .endif # Standard options: CFLAGS+= -nostdinc .if ${MACHINE_ARCH} == "amd64" && ${DO32:U0} == 1 CFLAGS+= -I${BOOTOBJ}/libsa32 .else CFLAGS+= -I${BOOTOBJ}/libsa .endif CFLAGS+= -I${SASRC} -D_STANDALONE CFLAGS+= -I${SYSDIR} # Spike the floating point interfaces CFLAGS+= -Ddouble=jagged-little-pill -Dfloat=floaty-mcfloatface # GELI Support, with backward compat hooks (mostly) .if defined(HAVE_GELI) .if defined(LOADER_NO_GELI_SUPPORT) MK_LOADER_GELI=no .warning "Please move from LOADER_NO_GELI_SUPPORT to WITHOUT_LOADER_GELI" .endif .if defined(LOADER_GELI_SUPPORT) MK_LOADER_GELI=yes .warning "Please move from LOADER_GELI_SUPPORT to WITH_LOADER_GELI" .endif .if ${MK_LOADER_GELI} == "yes" CFLAGS+= -DLOADER_GELI_SUPPORT CFLAGS+= -I${SASRC}/geli .endif # MK_LOADER_GELI .endif # HAVE_GELI # These should be confined to loader.mk, but can't because uboot/lib # also uses it. It's part of loader, but isn't a loader so we can't # just include loader.mk .if ${LOADER_DISK_SUPPORT:Uyes} == "yes" CFLAGS+= -DLOADER_DISK_SUPPORT .endif # Machine specific flags for all builds here # All PowerPC builds are 32 bit. We have no 64-bit loaders on powerpc # or powerpc64. .if ${MACHINE_ARCH} == "powerpc64" CFLAGS+= -m32 -mcpu=powerpc .endif # For amd64, there's a bit of mixed bag. Some of the tree (i386, lib*32) is # build 32-bit and some 64-bit (lib*, efi). Centralize all the 32-bit magic here # and activate it when DO32 is explicitly defined to be 1. .if ${MACHINE_ARCH} == "amd64" && ${DO32:U0} == 1 CFLAGS+= -m32 # LD_FLAGS is passed directly to ${LD}, not via ${CC}: LD_FLAGS+= -m elf_i386_fbsd AFLAGS+= --32 .endif SSP_CFLAGS= # Add in the no float / no SIMD stuff and announce we're freestanding # aarch64 and riscv don't have -msoft-float, but all others do. riscv # currently has no /boot/loader, but may soon. CFLAGS+= -ffreestanding ${CFLAGS_NO_SIMD} .if ${MACHINE_CPUARCH} == "aarch64" CFLAGS+= -mgeneral-regs-only -fPIC .elif ${MACHINE_CPUARCH} == "riscv" CFLAGS+= -march=rv64imac -mabi=lp64 .else CFLAGS+= -msoft-float .endif .if ${MACHINE_CPUARCH} == "i386" || (${MACHINE_CPUARCH} == "amd64" && ${DO32:U0} == 1) CFLAGS+= -march=i386 CFLAGS.gcc+= -mpreferred-stack-boundary=2 .endif .if ${MACHINE_CPUARCH} == "amd64" && ${DO32:U0} == 0 CFLAGS+= -fPIC -mno-red-zone .endif .if ${MACHINE_CPUARCH} == "arm" # Do not generate movt/movw, because the relocation fixup for them does not # translate to the -Bsymbolic -pie format required by self_reloc() in loader(8). # Also, the fpu is not available in a standalone environment. .if ${COMPILER_VERSION} < 30800 CFLAGS.clang+= -mllvm -arm-use-movt=0 .else CFLAGS.clang+= -mno-movt .endif CFLAGS.clang+= -mfpu=none CFLAGS+= -fPIC .endif # The boot loader build uses dd status=none, where possible, for reproducible # build output (since performance varies from run to run). Trouble is that # option was recently (10.3) added to FreeBSD and is non-standard. Only use it # when this test succeeds rather than require dd to be a bootstrap tool. DD_NOSTATUS!=(dd status=none count=0 2> /dev/null && echo status=none) || true DD=dd ${DD_NOSTATUS} .if ${MACHINE_CPUARCH} == "mips" CFLAGS+= -G0 -fno-pic -mno-abicalls .endif .if ${MK_LOADER_FORCE_LE} != "no" .if ${MACHINE_ARCH} == "powerpc64" CFLAGS+= -mlittle-endian .endif .endif # Make sure we use the machine link we're about to create CFLAGS+=-I. all: ${PROG} .if !defined(NO_OBJ) _ILINKS=machine .if ${MACHINE} != ${MACHINE_CPUARCH} && ${MACHINE} != "arm64" _ILINKS+=${MACHINE_CPUARCH} .endif .if ${MACHINE_CPUARCH} == "i386" || ${MACHINE_CPUARCH} == "amd64" _ILINKS+=x86 .endif CLEANFILES+=${_ILINKS} beforedepend: ${_ILINKS} beforebuild: ${_ILINKS} # Ensure that the links exist without depending on it when it exists which # causes all the modules to be rebuilt when the directory pointed to changes. .for _link in ${_ILINKS} .if !exists(${.OBJDIR}/${_link}) ${OBJS}: ${_link} .endif # _link exists .endfor .NOPATH: ${_ILINKS} ${_ILINKS}: @case ${.TARGET} in \ machine) \ if [ ${DO32:U0} -eq 0 ]; then \ path=${SYSDIR}/${MACHINE}/include ; \ else \ path=${SYSDIR}/${MACHINE:C/amd64/i386/}/include ; \ fi ;; \ *) \ path=${SYSDIR}/${.TARGET:T}/include ;; \ esac ; \ path=`(cd $$path && /bin/pwd)` ; \ ${ECHO} ${.TARGET:T} "->" $$path ; \ ln -fhs $$path ${.TARGET:T} .endif # !NO_OBJ .endif # __BOOT_DEFS_MK__ Index: stable/11/stand/efi/boot1/Makefile =================================================================== --- stable/11/stand/efi/boot1/Makefile (revision 344376) +++ stable/11/stand/efi/boot1/Makefile (revision 344377) @@ -1,123 +1,122 @@ # $FreeBSD$ .include PROG= boot1.sym INTERNALPROG= WARNS?= 6 # We implement a slightly non-standard %S in that it always takes a # CHAR16 that's common in UEFI-land instead of a wchar_t. This only # seems to matter on arm64 where wchar_t defaults to an int instead # of a short. There's no good cast to use here so just ignore the # warnings for now. CWARNFLAGS.boot1.c+= -Wno-format # Disable warnings that are currently incompatible with the zfs boot code CWARNFLAGS.zfs_module.c += -Wno-array-bounds CWARNFLAGS.zfs_module.c += -Wno-cast-align CWARNFLAGS.zfs_module.c += -Wno-cast-qual CWARNFLAGS.zfs_module.c += -Wno-missing-prototypes CWARNFLAGS.zfs_module.c += -Wno-sign-compare CWARNFLAGS.zfs_module.c += -Wno-unused-parameter CWARNFLAGS.zfs_module.c += -Wno-unused-function # architecture-specific loader code SRCS= boot1.c self_reloc.c start.S ufs_module.c .if ${MK_ZFS} != "no" SRCS+= zfs_module.c CFLAGS.zfs_module.c+= -I${ZFSSRC} CFLAGS.zfs_module.c+= -I${SYSDIR}/cddl/boot/zfs CFLAGS.zfs_module.c+= -I${SYSDIR}/crypto/skein CFLAGS+= -DEFI_ZFS_BOOT -LIBZFSBOOT= ${BOOTOBJ}/zfs/libzfsboot.a .endif .if ${COMPILER_TYPE} == "gcc" && ${COMPILER_VERSION} > 40201 CWARNFLAGS.self_reloc.c+= -Wno-error=maybe-uninitialized .endif CFLAGS+= -I${EFIINC} CFLAGS+= -I${EFIINCMD} CFLAGS+= -I${SYSDIR}/contrib/dev/acpica/include CFLAGS+= -DEFI_UFS_BOOT .ifdef(EFI_DEBUG) CFLAGS+= -DEFI_DEBUG .endif # Always add MI sources and REGULAR efi loader bits .PATH: ${EFISRC}/loader/arch/${MACHINE} .PATH: ${EFISRC}/loader .PATH: ${LDRSRC} CFLAGS+= -I${LDRSRC} FILES= boot1.efi boot1.efifat FILESMODE_boot1.efi= ${BINMODE} LDSCRIPT= ${EFISRC}/loader/arch/${MACHINE}/ldscript.${MACHINE} LDFLAGS+= -Wl,-T${LDSCRIPT},-Bsymbolic,-znotext -shared .if ${MACHINE_CPUARCH} == "aarch64" CFLAGS+= -mgeneral-regs-only .endif .if ${MACHINE_CPUARCH} == "amd64" || ${MACHINE_CPUARCH} == "i386" CFLAGS+= -fPIC LDFLAGS+= -Wl,-znocombreloc .endif LIBEFI= ${BOOTOBJ}/efi/libefi/libefi.a # # Add libstand for the runtime functions used by the compiler - for example # __aeabi_* (arm) or __divdi3 (i386). # as well as required string and memory functions for all platforms. # -DPADD+= ${LIBEFI} ${LIBZFSBOOT} ${LIBSA} -LDADD+= ${LIBEFI} ${LIBZFSBOOT} ${LIBSA} +DPADD+= ${LIBEFI} ${LIBSA} +LDADD+= ${LIBEFI} ${LIBSA} DPADD+= ${LDSCRIPT} NM?= nm OBJCOPY?= objcopy .if ${MACHINE_CPUARCH} == "amd64" EFI_TARGET= efi-app-x86_64 .elif ${MACHINE_CPUARCH} == "i386" EFI_TARGET= efi-app-ia32 .else EFI_TARGET= binary .endif # Arbitrarily set the PE/COFF header timestamps to 1 Jan 2016 00:00:00 # for build reproducibility. SOURCE_DATE_EPOCH?=1451606400 boot1.efi: ${PROG} if ${NM} ${.ALLSRC} | grep ' U '; then \ echo "Undefined symbols in ${.ALLSRC}"; \ exit 1; \ fi SOURCE_DATE_EPOCH=${SOURCE_DATE_EPOCH} \ ${OBJCOPY} -j .peheader -j .text -j .sdata -j .data \ -j .dynamic -j .dynsym -j .rel.dyn \ -j .rela.dyn -j .reloc -j .eh_frame \ --output-target=${EFI_TARGET} ${.ALLSRC} ${.TARGET} # The following inserts our objects into a template FAT file system # created by generate-fat.sh .include "Makefile.fat" boot1.efifat: boot1.efi @set -- `ls -l ${.ALLSRC}`; \ x=$$(($$5-${BOOT1_MAXSIZE})); \ if [ $$x -ge 0 ]; then \ echo "boot1 $$x bytes too large; regenerate FAT templates?" >&2 ;\ exit 1; \ fi echo ${.OBJDIR} xz -d -c ${BOOTSRC}/efi/boot1/fat-${MACHINE}.tmpl.xz > ${.TARGET} ${DD} if=${.ALLSRC} of=${.TARGET} seek=${BOOT1_OFFSET} conv=notrunc CLEANFILES+= boot1.efi boot1.efifat .include Index: stable/11/stand/efi/loader/Makefile =================================================================== --- stable/11/stand/efi/loader/Makefile (revision 344376) +++ stable/11/stand/efi/loader/Makefile (revision 344377) @@ -1,127 +1,125 @@ # $FreeBSD$ LOADER_NET_SUPPORT?= yes LOADER_MSDOS_SUPPORT?= yes LOADER_UFS_SUPPORT?= yes LOADER_CD9660_SUPPORT?= no LOADER_EXT2FS_SUPPORT?= no .include PROG= loader.sym INTERNALPROG= WARNS?= 3 # architecture-specific loader code SRCS= autoload.c \ bootinfo.c \ conf.c \ copy.c \ efi_main.c \ framebuffer.c \ main.c \ self_reloc.c \ smbios.c \ vers.c .if ${MK_ZFS} != "no" -LIBZFSBOOT= ${BOOTOBJ}/zfs/libzfsboot.a CFLAGS+= -I${ZFSSRC} CFLAGS+= -DEFI_ZFS_BOOT HAVE_ZFS= yes .endif .if ${COMPILER_TYPE} == "gcc" && ${COMPILER_VERSION} > 40201 CWARNFLAGS.self_reloc.c+= -Wno-error=maybe-uninitialized .endif # We implement a slightly non-standard %S in that it always takes a # CHAR16 that's common in UEFI-land instead of a wchar_t. This only # seems to matter on arm64 where wchar_t defaults to an int instead # of a short. There's no good cast to use here so just ignore the # warnings for now. CWARNFLAGS.main.c+= -Wno-format .PATH: ${.CURDIR}/arch/${MACHINE} # For smbios.c .PATH: ${BOOTSRC}/i386/libi386 .include "${.CURDIR}/arch/${MACHINE}/Makefile.inc" CFLAGS+= -I${.CURDIR} CFLAGS+= -I${.CURDIR}/arch/${MACHINE} CFLAGS+= -I${EFISRC}/include CFLAGS+= -I${EFISRC}/include/${MACHINE} CFLAGS+= -I${SYSDIR}/contrib/dev/acpica/include CFLAGS+= -I${BOOTSRC}/i386/libi386 CFLAGS+= -DNO_PCI -DEFI .if !defined(BOOT_HIDE_SERIAL_NUMBERS) # Export serial numbers, UUID, and asset tag from loader. CFLAGS+= -DSMBIOS_SERIAL_NUMBERS .if defined(BOOT_LITTLE_ENDIAN_UUID) # Use little-endian UUID format as defined in SMBIOS 2.6. CFLAGS+= -DSMBIOS_LITTLE_ENDIAN_UUID .elif defined(BOOT_NETWORK_ENDIAN_UUID) # Use network-endian UUID format for backward compatibility. CFLAGS+= -DSMBIOS_NETWORK_ENDIAN_UUID .endif .endif .if defined(HAVE_FDT) && ${MK_FDT} != "no" .include "${BOOTSRC}/fdt.mk" LIBEFI_FDT= ${BOOTOBJ}/efi/fdt/libefi_fdt.a .endif # Include bcache code. HAVE_BCACHE= yes .if defined(EFI_STAGING_SIZE) CFLAGS+= -DEFI_STAGING_SIZE=${EFI_STAGING_SIZE} .endif # Always add MI sources .include "${BOOTSRC}/loader.mk" FILES+= loader.efi FILESMODE_loader.efi= ${BINMODE} LDSCRIPT= ${.CURDIR}/arch/${MACHINE}/ldscript.${MACHINE} LDFLAGS+= -Wl,-T${LDSCRIPT},-Bsymbolic,-znotext -shared CLEANFILES+= loader.efi NEWVERSWHAT= "EFI loader" ${MACHINE} NM?= nm OBJCOPY?= objcopy .if ${MACHINE_CPUARCH} == "amd64" EFI_TARGET= efi-app-x86_64 .elif ${MACHINE_CPUARCH} == "i386" EFI_TARGET= efi-app-ia32 .else EFI_TARGET= binary .endif # Arbitrarily set the PE/COFF header timestamps to 1 Jan 2016 00:00:00 # for build reproducibility. SOURCE_DATE_EPOCH?=1451606400 loader.efi: ${PROG} if ${NM} ${.ALLSRC} | grep ' U '; then \ echo "Undefined symbols in ${.ALLSRC}"; \ exit 1; \ fi SOURCE_DATE_EPOCH=${SOURCE_DATE_EPOCH} \ ${OBJCOPY} -j .peheader -j .text -j .sdata -j .data \ -j .dynamic -j .dynsym -j .rel.dyn \ -j .rela.dyn -j .reloc -j .eh_frame -j set_Xcommand_set \ -j set_Xficl_compile_set \ --output-target=${EFI_TARGET} ${.ALLSRC} ${.TARGET} LIBEFI= ${BOOTOBJ}/efi/libefi/libefi.a -DPADD= ${LDR_INTERP} ${LIBEFI} ${LIBFDT} ${LIBEFI_FDT} ${LIBZFSBOOT} ${LIBSA} \ - ${LDSCRIPT} -LDADD= ${LDR_INTERP} ${LIBEFI} ${LIBFDT} ${LIBEFI_FDT} ${LIBZFSBOOT} ${LIBSA} +DPADD= ${LDR_INTERP} ${LIBEFI} ${LIBFDT} ${LIBEFI_FDT} ${LIBSA} ${LDSCRIPT} +LDADD= ${LDR_INTERP} ${LIBEFI} ${LIBFDT} ${LIBEFI_FDT} ${LIBSA} .include Index: stable/11/stand/i386/gptzfsboot/Makefile =================================================================== --- stable/11/stand/i386/gptzfsboot/Makefile (revision 344376) +++ stable/11/stand/i386/gptzfsboot/Makefile (revision 344377) @@ -1,85 +1,79 @@ # $FreeBSD$ HAVE_GELI= yes .include .PATH: ${BOOTSRC}/i386/boot2 ${BOOTSRC}/i386/gptboot \ ${BOOTSRC}/i386/zfsboot ${BOOTSRC}/i386/common \ ${SASRC} FILES= gptzfsboot MAN= gptzfsboot.8 NM?= nm BOOT_COMCONSOLE_PORT?= 0x3f8 BOOT_COMCONSOLE_SPEED?= 9600 B2SIOFMT?= 0x3 REL1= 0x700 ORG1= 0x7c00 ORG2= 0x0 CFLAGS+=-DBOOTPROG=\"gptzfsboot\" \ -O1 \ -DGPT -DZFS -DBOOT2 \ -DSIOPRT=${BOOT_COMCONSOLE_PORT} \ -DSIOFMT=${B2SIOFMT} \ -DSIOSPD=${BOOT_COMCONSOLE_SPEED} \ -I${LDRSRC} \ -I${BOOTSRC}/i386/common \ -I${ZFSSRC} \ -I${SYSDIR}/crypto/skein \ -I${SYSDIR}/cddl/boot/zfs \ -I${BOOTSRC}/i386/btx/lib \ -I${BOOTSRC}/i386/boot2 \ -Wall -Waggregate-return -Wbad-function-cast \ -Wmissing-declarations -Wmissing-prototypes -Wnested-externs \ -Wpointer-arith -Wshadow -Wstrict-prototypes -Wwrite-strings \ -Wno-pointer-sign CFLAGS.clang+= -Wno-tentative-definition-incomplete-type NO_WCAST_ALIGN= -.if ${MACHINE} == "amd64" -LIBZFSBOOT=${BOOTOBJ}/zfs32/libzfsboot.a -.else -LIBZFSBOOT=${BOOTOBJ}/zfs/libzfsboot.a -.endif - CFLAGS.gcc+= --param max-inline-insns-single=100 LD_FLAGS+=${LD_FLAGS_BIN} CLEANFILES+= gptzfsboot gptzfsboot: gptldr.bin gptzfsboot.bin ${BTXKERN} btxld -v -E ${ORG2} -f bin -b ${BTXKERN} -l gptldr.bin \ -o ${.TARGET} gptzfsboot.bin CLEANFILES+= gptldr.bin gptldr.out gptldr.o gptldr.bin: gptldr.out ${OBJCOPY} -S -O binary gptldr.out ${.TARGET} gptldr.out: gptldr.o ${LD} ${LD_FLAGS} -e start -Ttext ${ORG1} -o ${.TARGET} gptldr.o CLEANFILES+= gptzfsboot.bin gptzfsboot.out zfsboot.o sio.o cons.o \ drv.o gpt.o ${OPENCRYPTO_XTS} gptzfsboot.bin: gptzfsboot.out ${OBJCOPY} -S -O binary gptzfsboot.out ${.TARGET} gptzfsboot.out: ${BTXCRT} zfsboot.o sio.o gpt.o drv.o cons.o \ ${OPENCRYPTO_XTS} - ${LD} ${LD_FLAGS} -Ttext ${ORG2} -o ${.TARGET} ${.ALLSRC} ${LIBZFSBOOT} ${LIBSA32} + ${LD} ${LD_FLAGS} -Ttext ${ORG2} -o ${.TARGET} ${.ALLSRC} ${LIBSA32} zfsboot.o: ${ZFSSRC}/zfsimpl.c .include # XXX: clang integrated-as doesn't grok .codeNN directives yet CFLAGS.gptldr.S= ${CLANG_NO_IAS} Index: stable/11/stand/i386/libi386/Makefile =================================================================== --- stable/11/stand/i386/libi386/Makefile (revision 344376) +++ stable/11/stand/i386/libi386/Makefile (revision 344377) @@ -1,58 +1,59 @@ # $FreeBSD$ HAVE_GELI= yes .include LIB= i386 SRCS= biosacpi.c bioscd.c biosdisk.c biosmem.c biospnp.c \ biospci.c biossmap.c bootinfo.c bootinfo32.c bootinfo64.c \ comconsole.c devicename.c elf32_freebsd.c \ elf64_freebsd.c multiboot.c multiboot_tramp.S relocater_tramp.S \ i386_copy.c i386_module.c nullconsole.c pxe.c pxetramp.s \ smbios.c time.c vidconsole.c amd64_tramp.S spinconsole.c .PATH: ${ZFSSRC} SRCS+= devicename_stubs.c +CFLAGS+= -I${ZFSSRC} BOOT_COMCONSOLE_PORT?= 0x3f8 CFLAGS+= -DCOMPORT=${BOOT_COMCONSOLE_PORT} BOOT_COMCONSOLE_SPEED?= 9600 CFLAGS+= -DCOMSPEED=${BOOT_COMCONSOLE_SPEED} .ifdef(BOOT_BIOSDISK_DEBUG) # Make the disk code more talkative CFLAGS+= -DDISK_DEBUG .endif .if !defined(BOOT_HIDE_SERIAL_NUMBERS) # Export serial numbers, UUID, and asset tag from loader. CFLAGS+= -DSMBIOS_SERIAL_NUMBERS .if defined(BOOT_LITTLE_ENDIAN_UUID) # Use little-endian UUID format as defined in SMBIOS 2.6. CFLAGS+= -DSMBIOS_LITTLE_ENDIAN_UUID .elif defined(BOOT_NETWORK_ENDIAN_UUID) # Use network-endian UUID format for backward compatibility. CFLAGS+= -DSMBIOS_NETWORK_ENDIAN_UUID .endif .endif # Include simple terminal emulation (cons25-compatible) CFLAGS+= -DTERM_EMU # XXX: make alloca() useable CFLAGS+= -Dalloca=__builtin_alloca CFLAGS+= -I${BOOTSRC}/ficl -I${BOOTSRC}/ficl/i386 \ -I${LDRSRC} -I${BOOTSRC}/i386/common \ -I${SYSDIR}/contrib/dev/acpica/include # Handle FreeBSD specific %b and %D printf format specifiers CFLAGS+= ${FORMAT_EXTENSIONS} .include # XXX: clang integrated-as doesn't grok .codeNN directives yet CFLAGS.amd64_tramp.S= ${CLANG_NO_IAS} CFLAGS.multiboot_tramp.S= ${CLANG_NO_IAS} Index: stable/11/stand/i386/libi386/devicename.c =================================================================== --- stable/11/stand/i386/libi386/devicename.c (revision 344376) +++ stable/11/stand/i386/libi386/devicename.c (revision 344377) @@ -1,205 +1,205 @@ /*- * Copyright (c) 1998 Michael Smith * All rights reserved. * * Redistribution and use in source and binary forms, with or without * modification, are permitted provided that the following conditions * are met: * 1. Redistributions of source code must retain the above copyright * notice, this list of conditions and the following disclaimer. * 2. Redistributions in binary form must reproduce the above copyright * notice, this list of conditions and the following disclaimer in the * documentation and/or other materials provided with the distribution. * * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF * SUCH DAMAGE. */ #include __FBSDID("$FreeBSD$"); #include #include #include "bootstrap.h" #include "disk.h" #include "libi386.h" -#include "../zfs/libzfs.h" +#include "libzfs.h" static int i386_parsedev(struct i386_devdesc **dev, const char *devspec, const char **path); /* * Point (dev) at an allocated device specifier for the device matching the * path in (devspec). If it contains an explicit device specification, * use that. If not, use the default device. */ int i386_getdev(void **vdev, const char *devspec, const char **path) { struct i386_devdesc **dev = (struct i386_devdesc **)vdev; int rv; /* * If it looks like this is just a path and no * device, go with the current device. */ if ((devspec == NULL) || (devspec[0] == '/') || (strchr(devspec, ':') == NULL)) { if (((rv = i386_parsedev(dev, getenv("currdev"), NULL)) == 0) && (path != NULL)) *path = devspec; return(rv); } /* * Try to parse the device name off the beginning of the devspec */ return(i386_parsedev(dev, devspec, path)); } /* * Point (dev) at an allocated device specifier matching the string version * at the beginning of (devspec). Return a pointer to the remaining * text in (path). * * In all cases, the beginning of (devspec) is compared to the names * of known devices in the device switch, and then any following text * is parsed according to the rules applied to the device type. * * For disk-type devices, the syntax is: * * disk[s][]: * */ static int i386_parsedev(struct i386_devdesc **dev, const char *devspec, const char **path) { struct i386_devdesc *idev; struct devsw *dv; int i, unit, err; char *cp; const char *np; /* minimum length check */ if (strlen(devspec) < 2) return(EINVAL); /* look for a device that matches */ for (i = 0, dv = NULL; devsw[i] != NULL; i++) { if (!strncmp(devspec, devsw[i]->dv_name, strlen(devsw[i]->dv_name))) { dv = devsw[i]; break; } } if (dv == NULL) return(ENOENT); idev = malloc(sizeof(struct i386_devdesc)); err = 0; np = (devspec + strlen(dv->dv_name)); switch(dv->dv_type) { case DEVT_NONE: /* XXX what to do here? Do we care? */ break; case DEVT_DISK: err = disk_parsedev((struct disk_devdesc *)idev, np, path); if (err != 0) goto fail; break; case DEVT_CD: case DEVT_NET: unit = 0; if (*np && (*np != ':')) { unit = strtol(np, &cp, 0); /* get unit number if present */ if (cp == np) { err = EUNIT; goto fail; } } else { cp = (char *)np; } if (*cp && (*cp != ':')) { err = EINVAL; goto fail; } idev->dd.d_unit = unit; if (path != NULL) *path = (*cp == 0) ? cp : cp + 1; break; case DEVT_ZFS: err = zfs_parsedev((struct zfs_devdesc *)idev, np, path); if (err != 0) goto fail; break; default: err = EINVAL; goto fail; } idev->dd.d_dev = dv; if (dev == NULL) { free(idev); } else { *dev = idev; } return(0); fail: free(idev); return(err); } char * i386_fmtdev(void *vdev) { struct i386_devdesc *dev = (struct i386_devdesc *)vdev; static char buf[128]; /* XXX device length constant? */ switch(dev->dd.d_dev->dv_type) { case DEVT_NONE: strcpy(buf, "(no device)"); break; case DEVT_CD: case DEVT_NET: sprintf(buf, "%s%d:", dev->dd.d_dev->dv_name, dev->dd.d_unit); break; case DEVT_DISK: return (disk_fmtdev(vdev)); case DEVT_ZFS: return(zfs_fmtdev(vdev)); } return(buf); } /* * Set currdev to suit the value being supplied in (value) */ int i386_setcurrdev(struct env_var *ev, int flags, const void *value) { struct i386_devdesc *ncurr; int rv; if ((rv = i386_parsedev(&ncurr, value, NULL)) != 0) return(rv); free(ncurr); env_setenv(ev->ev_name, flags | EV_NOHOOK, value, NULL, NULL); return(0); } Index: stable/11/stand/i386/loader/Makefile =================================================================== --- stable/11/stand/i386/loader/Makefile (revision 344376) +++ stable/11/stand/i386/loader/Makefile (revision 344377) @@ -1,81 +1,81 @@ # $FreeBSD$ HAVE_GELI= yes LOADER_NET_SUPPORT?= yes LOADER_NFS_SUPPORT?= yes LOADER_TFTP_SUPPORT?= yes LOADER_CD9660_SUPPORT?= yes LOADER_EXT2FS_SUPPORT?= yes LOADER_MSDOS_SUPPORT?= yes LOADER_UFS_SUPPORT?= yes LOADER_GZIP_SUPPORT?= yes LOADER_BZIP2_SUPPORT?= yes .include LOADER?= loader PROG= ${LOADER}.sym INTERNALPROG= NEWVERSWHAT?= "bootstrap loader" x86 VERSION_FILE= ${.CURDIR}/../loader/version .PATH: ${BOOTSRC}/i386/loader # architecture-specific loader code SRCS= main.c conf.c vers.c chain.c # Include bcache code. HAVE_BCACHE= yes # Enable PnP and ISA-PnP code. HAVE_PNP= yes HAVE_ISABUS= yes .if ${MK_LOADER_FIREWIRE} == "yes" CFLAGS+= -DLOADER_FIREWIRE_SUPPORT LIBFIREWIRE= ${BOOTOBJ}/i386/libfirewire/libfirewire.a .endif .if exists(${.CURDIR}/help.i386) HELP_FILES= ${.CURDIR}/help.i386 .endif # Always add MI sources .include "${BOOTSRC}/loader.mk" CLEANFILES+= ${LOADER} ${LOADER}.bin CFLAGS+= -Wall LDFLAGS+= -static -Ttext 0x0 # i386 standalone support library LIBI386= ${BOOTOBJ}/i386/libi386/libi386.a CFLAGS+= -I${BOOTSRC}/i386 # Debug me! #CFLAGS+= -g #LDFLAGS+= -g ${LOADER}: ${LOADER}.bin ${BTXLDR} ${BTXKERN} btxld -v -f aout -e ${LOADER_ADDRESS} -o ${.TARGET} -l ${BTXLDR} \ -b ${BTXKERN} ${LOADER}.bin ${LOADER}.bin: ${LOADER}.sym strip -R .comment -R .note -o ${.TARGET} ${.ALLSRC} FILES+= ${LOADER} # XXX INSTALLFLAGS_loader= -b FILESMODE_${LOADER}= ${BINMODE} -b # XXX crt0.o needs to be first for pxeboot(8) to work OBJS= ${BTXCRT} -DPADD= ${LDR_INTERP32} ${LIBFIREWIRE} ${LIBZFSBOOT} ${LIBI386} ${LIBSA32} -LDADD= ${LDR_INTERP32} ${LIBFIREWIRE} ${LIBZFSBOOT} ${LIBI386} ${LIBSA32} +DPADD= ${LDR_INTERP32} ${LIBFIREWIRE} ${LIBI386} ${LIBSA32} +LDADD= ${LDR_INTERP32} ${LIBFIREWIRE} ${LIBI386} ${LIBSA32} .if ${MACHINE_CPUARCH} == "amd64" CFLAGS+= -DLOADER_PREFER_AMD64 .endif .include Index: stable/11/stand/i386/loader/conf.c =================================================================== --- stable/11/stand/i386/loader/conf.c (revision 344376) +++ stable/11/stand/i386/loader/conf.c (revision 344377) @@ -1,167 +1,167 @@ /*- * Copyright (c) 1998 Michael Smith * All rights reserved. * * Redistribution and use in source and binary forms, with or without * modification, are permitted provided that the following conditions * are met: * 1. Redistributions of source code must retain the above copyright * notice, this list of conditions and the following disclaimer. * 2. Redistributions in binary form must reproduce the above copyright * notice, this list of conditions and the following disclaimer in the * documentation and/or other materials provided with the distribution. * * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF * SUCH DAMAGE. */ #include __FBSDID("$FreeBSD$"); #include #include #include "libi386/libi386.h" #if defined(LOADER_ZFS_SUPPORT) -#include "../zfs/libzfs.h" +#include "libzfs.h" #endif /* * We could use linker sets for some or all of these, but * then we would have to control what ended up linked into * the bootstrap. So it's easier to conditionalise things * here. * * XXX rename these arrays to be consistent and less namespace-hostile * * XXX as libi386 and biosboot merge, some of these can become linker sets. */ #if defined(LOADER_FIREWIRE_SUPPORT) extern struct devsw fwohci; #endif /* Exported for libstand */ struct devsw *devsw[] = { &bioscd, &biosdisk, #if defined(LOADER_NFS_SUPPORT) || defined(LOADER_TFTP_SUPPORT) &pxedisk, #endif #if defined(LOADER_FIREWIRE_SUPPORT) &fwohci, #endif #if defined(LOADER_ZFS_SUPPORT) &zfs_dev, #endif NULL }; struct fs_ops *file_system[] = { #if defined(LOADER_ZFS_SUPPORT) &zfs_fsops, #endif #if defined(LOADER_UFS_SUPPORT) &ufs_fsops, #endif #if defined(LOADER_EXT2FS_SUPPORT) &ext2fs_fsops, #endif #if defined(LOADER_MSDOS_SUPPORT) &dosfs_fsops, #endif #if defined(LOADER_CD9660_SUPPORT) &cd9660_fsops, #endif #if defined(LOADER_NANDFS_SUPPORT) &nandfs_fsops, #endif #ifdef LOADER_NFS_SUPPORT &nfs_fsops, #endif #ifdef LOADER_TFTP_SUPPORT &tftp_fsops, #endif #ifdef LOADER_GZIP_SUPPORT &gzipfs_fsops, #endif #ifdef LOADER_BZIP2_SUPPORT &bzipfs_fsops, #endif #ifdef LOADER_SPLIT_SUPPORT &splitfs_fsops, #endif NULL }; /* Exported for i386 only */ /* * Sort formats so that those that can detect based on arguments * rather than reading the file go first. */ extern struct file_format i386_elf; extern struct file_format i386_elf_obj; extern struct file_format amd64_elf; extern struct file_format amd64_elf_obj; extern struct file_format multiboot; extern struct file_format multiboot_obj; struct file_format *file_formats[] = { &multiboot, &multiboot_obj, #ifdef LOADER_PREFER_AMD64 &amd64_elf, &amd64_elf_obj, #endif &i386_elf, &i386_elf_obj, #ifndef LOADER_PREFER_AMD64 &amd64_elf, &amd64_elf_obj, #endif NULL }; /* * Consoles * * We don't prototype these in libi386.h because they require * data structures from bootstrap.h as well. */ extern struct console vidconsole; extern struct console comconsole; #if defined(LOADER_FIREWIRE_SUPPORT) extern struct console dconsole; #endif extern struct console nullconsole; extern struct console spinconsole; struct console *consoles[] = { &vidconsole, &comconsole, #if defined(LOADER_FIREWIRE_SUPPORT) &dconsole, #endif &nullconsole, &spinconsole, NULL }; extern struct pnphandler isapnphandler; extern struct pnphandler biospnphandler; extern struct pnphandler biospcihandler; struct pnphandler *pnphandlers[] = { &biospnphandler, /* should go first, as it may set isapnp_readport */ &isapnphandler, &biospcihandler, NULL }; Index: stable/11/stand/i386/loader/main.c =================================================================== --- stable/11/stand/i386/loader/main.c (revision 344376) +++ stable/11/stand/i386/loader/main.c (revision 344377) @@ -1,406 +1,406 @@ /*- * Copyright (c) 1998 Michael Smith * All rights reserved. * * Redistribution and use in source and binary forms, with or without * modification, are permitted provided that the following conditions * are met: * 1. Redistributions of source code must retain the above copyright * notice, this list of conditions and the following disclaimer. * 2. Redistributions in binary form must reproduce the above copyright * notice, this list of conditions and the following disclaimer in the * documentation and/or other materials provided with the distribution. * * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF * SUCH DAMAGE. */ #include __FBSDID("$FreeBSD$"); /* * MD bootstrap main() and assorted miscellaneous * commands. */ #include #include #include #include #include #include #include #include #include #include "bootstrap.h" #include "common/bootargs.h" #include "libi386/libi386.h" #include "libi386/smbios.h" #include "btxv86.h" #ifdef LOADER_ZFS_SUPPORT -#include "../zfs/libzfs.h" +#include "libzfs.h" #endif CTASSERT(sizeof(struct bootargs) == BOOTARGS_SIZE); CTASSERT(offsetof(struct bootargs, bootinfo) == BA_BOOTINFO); CTASSERT(offsetof(struct bootargs, bootflags) == BA_BOOTFLAGS); CTASSERT(offsetof(struct bootinfo, bi_size) == BI_SIZE); /* Arguments passed in from the boot1/boot2 loader */ static struct bootargs *kargs; static uint32_t initial_howto; static uint32_t initial_bootdev; static struct bootinfo *initial_bootinfo; struct arch_switch archsw; /* MI/MD interface boundary */ static void extract_currdev(void); static int isa_inb(int port); static void isa_outb(int port, int value); void exit(int code); #ifdef LOADER_GELI_SUPPORT #include "geliboot.h" struct geli_boot_args *gargs; #endif #ifdef LOADER_ZFS_SUPPORT struct zfs_boot_args *zargs; static void i386_zfs_probe(void); #endif /* XXX debugging */ extern char end[]; static void *heap_top; static void *heap_bottom; int main(void) { int i; /* Pick up arguments */ kargs = (void *)__args; initial_howto = kargs->howto; initial_bootdev = kargs->bootdev; initial_bootinfo = kargs->bootinfo ? (struct bootinfo *)PTOV(kargs->bootinfo) : NULL; /* Initialize the v86 register set to a known-good state. */ bzero(&v86, sizeof(v86)); v86.efl = PSL_RESERVED_DEFAULT | PSL_I; /* * Initialise the heap as early as possible. Once this is done, malloc() is usable. */ bios_getmem(); #if defined(LOADER_BZIP2_SUPPORT) || defined(LOADER_FIREWIRE_SUPPORT) || \ defined(LOADER_GPT_SUPPORT) || defined(LOADER_ZFS_SUPPORT) if (high_heap_size > 0) { heap_top = PTOV(high_heap_base + high_heap_size); heap_bottom = PTOV(high_heap_base); if (high_heap_base < memtop_copyin) memtop_copyin = high_heap_base; } else #endif { heap_top = (void *)PTOV(bios_basemem); heap_bottom = (void *)end; } setheap(heap_bottom, heap_top); /* * XXX Chicken-and-egg problem; we want to have console output early, but some * console attributes may depend on reading from eg. the boot device, which we * can't do yet. * * We can use printf() etc. once this is done. * If the previous boot stage has requested a serial console, prefer that. */ bi_setboothowto(initial_howto); if (initial_howto & RB_MULTIPLE) { if (initial_howto & RB_SERIAL) setenv("console", "comconsole vidconsole", 1); else setenv("console", "vidconsole comconsole", 1); } else if (initial_howto & RB_SERIAL) setenv("console", "comconsole", 1); else if (initial_howto & RB_MUTE) setenv("console", "nullconsole", 1); cons_probe(); /* * Initialise the block cache. Set the upper limit. */ bcache_init(32768, 512); /* * Special handling for PXE and CD booting. */ if (kargs->bootinfo == 0) { /* * We only want the PXE disk to try to init itself in the below * walk through devsw if we actually booted off of PXE. */ if (kargs->bootflags & KARGS_FLAGS_PXE) pxe_enable(kargs->pxeinfo ? PTOV(kargs->pxeinfo) : NULL); else if (kargs->bootflags & KARGS_FLAGS_CD) bc_add(initial_bootdev); } archsw.arch_autoload = i386_autoload; archsw.arch_getdev = i386_getdev; archsw.arch_copyin = i386_copyin; archsw.arch_copyout = i386_copyout; archsw.arch_readin = i386_readin; archsw.arch_isainb = isa_inb; archsw.arch_isaoutb = isa_outb; #ifdef LOADER_ZFS_SUPPORT archsw.arch_zfs_probe = i386_zfs_probe; #ifdef LOADER_GELI_SUPPORT if ((kargs->bootflags & KARGS_FLAGS_EXTARG) != 0) { zargs = (struct zfs_boot_args *)(kargs + 1); if (zargs != NULL && zargs->size >= offsetof(struct zfs_boot_args, gelipw)) { if (zargs->size >= offsetof(struct zfs_boot_args, keybuf_sentinel) && zargs->keybuf_sentinel == KEYBUF_SENTINEL) { geli_save_keybuf(zargs->keybuf); } if (zargs->gelipw[0] != '\0') { setenv("kern.geom.eli.passphrase", zargs->gelipw, 1); explicit_bzero(zargs->gelipw, sizeof(zargs->gelipw)); } } } #endif /* LOADER_GELI_SUPPORT */ #else /* !LOADER_ZFS_SUPPORT */ #ifdef LOADER_GELI_SUPPORT if ((kargs->bootflags & KARGS_FLAGS_EXTARG) != 0) { gargs = (struct geli_boot_args *)(kargs + 1); if (gargs != NULL && gargs->size >= offsetof(struct geli_boot_args, gelipw)) { if (gargs->keybuf_sentinel == KEYBUF_SENTINEL) { geli_save_keybuf(gargs->keybuf); } if (gargs->gelipw[0] != '\0') { setenv("kern.geom.eli.passphrase", gargs->gelipw, 1); explicit_bzero(gargs->gelipw, sizeof(gargs->gelipw)); } } } #endif /* LOADER_GELI_SUPPORT */ #endif /* LOADER_ZFS_SUPPORT */ /* * March through the device switch probing for things. */ for (i = 0; devsw[i] != NULL; i++) if (devsw[i]->dv_init != NULL) (devsw[i]->dv_init)(); printf("BIOS %dkB/%dkB available memory\n", bios_basemem / 1024, bios_extmem / 1024); if (initial_bootinfo != NULL) { initial_bootinfo->bi_basemem = bios_basemem / 1024; initial_bootinfo->bi_extmem = bios_extmem / 1024; } /* detect ACPI for future reference */ biosacpi_detect(); /* detect SMBIOS for future reference */ smbios_detect(NULL); /* detect PCI BIOS for future reference */ biospci_detect(); printf("\n%s", bootprog_info); extract_currdev(); /* set $currdev and $loaddev */ setenv("LINES", "24", 1); /* optional */ bios_getsmap(); interact(); /* if we ever get here, it is an error */ return (1); } /* * Set the 'current device' by (if possible) recovering the boot device as * supplied by the initial bootstrap. * * XXX should be extended for netbooting. */ static void extract_currdev(void) { struct i386_devdesc new_currdev; #ifdef LOADER_ZFS_SUPPORT char buf[20]; #endif int biosdev = -1; /* Assume we are booting from a BIOS disk by default */ new_currdev.dd.d_dev = &biosdisk; /* new-style boot loaders such as pxeldr and cdldr */ if (kargs->bootinfo == 0) { if ((kargs->bootflags & KARGS_FLAGS_CD) != 0) { /* we are booting from a CD with cdboot */ new_currdev.dd.d_dev = &bioscd; new_currdev.dd.d_unit = bc_bios2unit(initial_bootdev); } else if ((kargs->bootflags & KARGS_FLAGS_PXE) != 0) { /* we are booting from pxeldr */ new_currdev.dd.d_dev = &pxedisk; new_currdev.dd.d_unit = 0; } else { /* we don't know what our boot device is */ new_currdev.d_kind.biosdisk.slice = -1; new_currdev.d_kind.biosdisk.partition = 0; biosdev = -1; } #ifdef LOADER_ZFS_SUPPORT } else if ((kargs->bootflags & KARGS_FLAGS_ZFS) != 0) { zargs = NULL; /* check for new style extended argument */ if ((kargs->bootflags & KARGS_FLAGS_EXTARG) != 0) zargs = (struct zfs_boot_args *)(kargs + 1); if (zargs != NULL && zargs->size >= offsetof(struct zfs_boot_args, primary_pool)) { /* sufficient data is provided */ new_currdev.d_kind.zfs.pool_guid = zargs->pool; new_currdev.d_kind.zfs.root_guid = zargs->root; if (zargs->size >= sizeof(*zargs) && zargs->primary_vdev != 0) { sprintf(buf, "%llu", zargs->primary_pool); setenv("vfs.zfs.boot.primary_pool", buf, 1); sprintf(buf, "%llu", zargs->primary_vdev); setenv("vfs.zfs.boot.primary_vdev", buf, 1); } } else { /* old style zfsboot block */ new_currdev.d_kind.zfs.pool_guid = kargs->zfspool; new_currdev.d_kind.zfs.root_guid = 0; } new_currdev.dd.d_dev = &zfs_dev; #endif } else if ((initial_bootdev & B_MAGICMASK) != B_DEVMAGIC) { /* The passed-in boot device is bad */ new_currdev.d_kind.biosdisk.slice = -1; new_currdev.d_kind.biosdisk.partition = 0; biosdev = -1; } else { new_currdev.d_kind.biosdisk.slice = B_SLICE(initial_bootdev) - 1; new_currdev.d_kind.biosdisk.partition = B_PARTITION(initial_bootdev); biosdev = initial_bootinfo->bi_bios_dev; /* * If we are booted by an old bootstrap, we have to guess at the BIOS * unit number. We will lose if there is more than one disk type * and we are not booting from the lowest-numbered disk type * (ie. SCSI when IDE also exists). */ if ((biosdev == 0) && (B_TYPE(initial_bootdev) != 2)) /* biosdev doesn't match major */ biosdev = 0x80 + B_UNIT(initial_bootdev); /* assume harddisk */ } /* * If we are booting off of a BIOS disk and we didn't succeed in determining * which one we booted off of, just use disk0: as a reasonable default. */ if ((new_currdev.dd.d_dev->dv_type == biosdisk.dv_type) && ((new_currdev.dd.d_unit = bd_bios2unit(biosdev)) == -1)) { printf("Can't work out which disk we are booting from.\n" "Guessed BIOS device 0x%x not found by probes, defaulting to disk0:\n", biosdev); new_currdev.dd.d_unit = 0; } #ifdef LOADER_ZFS_SUPPORT if (new_currdev.dd.d_dev->dv_type == DEVT_ZFS) init_zfs_bootenv(zfs_fmtdev(&new_currdev)); #endif env_setenv("currdev", EV_VOLATILE, i386_fmtdev(&new_currdev), i386_setcurrdev, env_nounset); env_setenv("loaddev", EV_VOLATILE, i386_fmtdev(&new_currdev), env_noset, env_nounset); } COMMAND_SET(reboot, "reboot", "reboot the system", command_reboot); static int command_reboot(int argc, char *argv[]) { int i; for (i = 0; devsw[i] != NULL; ++i) if (devsw[i]->dv_cleanup != NULL) (devsw[i]->dv_cleanup)(); printf("Rebooting...\n"); delay(1000000); __exit(0); } /* provide this for panic, as it's not in the startup code */ void exit(int code) { __exit(code); } COMMAND_SET(heap, "heap", "show heap usage", command_heap); static int command_heap(int argc, char *argv[]) { mallocstats(); printf("heap base at %p, top at %p, upper limit at %p\n", heap_bottom, sbrk(0), heap_top); return(CMD_OK); } /* ISA bus access functions for PnP. */ static int isa_inb(int port) { return (inb(port)); } static void isa_outb(int port, int value) { outb(port, value); } #ifdef LOADER_ZFS_SUPPORT static void i386_zfs_probe(void) { char devname[32]; int unit; /* * Open all the disks we can find and see if we can reconstruct * ZFS pools from them. */ for (unit = 0; unit < MAXBDDEV; unit++) { if (bd_unit2bios(unit) == -1) break; sprintf(devname, "disk%d:", unit); zfs_probe_dev(devname, NULL); } } #endif Index: stable/11/stand/i386/zfsboot/Makefile =================================================================== --- stable/11/stand/i386/zfsboot/Makefile (revision 344376) +++ stable/11/stand/i386/zfsboot/Makefile (revision 344377) @@ -1,92 +1,87 @@ # $FreeBSD$ HAVE_GELI=yes .include .PATH: ${BOOTSRC}/i386/boot2 ${BOOTSRC}/i386/common ${SASRC} FILES= zfsboot MAN= zfsboot.8 NM?= nm BOOT_COMCONSOLE_PORT?= 0x3f8 BOOT_COMCONSOLE_SPEED?= 9600 B2SIOFMT?= 0x3 REL1= 0x700 ORG1= 0x7c00 ORG2= 0x2000 CFLAGS+=-DBOOTPROG=\"zfsboot\" \ -O1 \ -DZFS -DBOOT2 \ -DSIOPRT=${BOOT_COMCONSOLE_PORT} \ -DSIOFMT=${B2SIOFMT} \ -DSIOSPD=${BOOT_COMCONSOLE_SPEED} \ -I${LDRSRC} \ -I${BOOTSRC}/i386/common \ -I${BOOTSRC}/i386 \ -I${ZFSSRC} \ -I${SYSDIR}/crypto/skein \ -I${SYSDIR}/cddl/boot/zfs \ -I${BOOTSRC}/i386/boot2 \ -Wall -Waggregate-return -Wbad-function-cast -Wno-cast-align \ -Wmissing-declarations -Wmissing-prototypes -Wnested-externs \ -Wpointer-arith -Wshadow -Wstrict-prototypes -Wwrite-strings CFLAGS.gcc+= --param max-inline-insns-single=100 -.if ${MACHINE} == "amd64" -LIBZFSBOOT=${BOOTOBJ}/zfs32/libzfsboot.a -.else -LIBZFSBOOT=${BOOTOBJ}/zfs/libzfsboot.a -.endif LD_FLAGS+=${LD_FLAGS_BIN} CLEANFILES+= zfsboot zfsboot: zfsboot1 zfsboot2 cat zfsboot1 zfsboot2 > zfsboot CLEANFILES+= zfsboot1 zfsldr.out zfsldr.o zfsboot1: zfsldr.out ${OBJCOPY} -S -O binary zfsldr.out ${.TARGET} zfsldr.out: zfsldr.o ${LD} ${LD_FLAGS} -e start -Ttext ${ORG1} -o ${.TARGET} zfsldr.o CLEANFILES+= zfsboot2 zfsboot.ld zfsboot.ldr zfsboot.bin zfsboot.out \ zfsboot.o zfsboot.s zfsboot.s.tmp sio.o cons.o drv.o # We currently allow 256k bytes for zfsboot - in practice it could be # any size up to 3.5Mb but keeping it fixed size simplifies zfsldr. # BOOT2SIZE= 262144 zfsboot2: zfsboot.ld @set -- `ls -l ${.ALLSRC}`; x=$$((${BOOT2SIZE}-$$5)); \ echo "$$x bytes available"; test $$x -ge 0 ${DD} if=${.ALLSRC} of=${.TARGET} obs=${BOOT2SIZE} conv=osync zfsboot.ld: zfsboot.ldr zfsboot.bin ${BTXKERN} btxld -v -E ${ORG2} -f bin -b ${BTXKERN} -l zfsboot.ldr \ -o ${.TARGET} -P 1 zfsboot.bin zfsboot.ldr: cp /dev/null ${.TARGET} zfsboot.bin: zfsboot.out ${OBJCOPY} -S -O binary zfsboot.out ${.TARGET} zfsboot.out: ${BTXCRT} zfsboot.o sio.o drv.o cons.o - ${LD} ${LD_FLAGS} -Ttext ${ORG2} -o ${.TARGET} ${.ALLSRC} ${LIBZFSBOOT} ${LIBSA32} + ${LD} ${LD_FLAGS} -Ttext ${ORG2} -o ${.TARGET} ${.ALLSRC} ${LIBSA32} SRCS= zfsboot.c .include # XXX: clang integrated-as doesn't grok .codeNN directives yet CFLAGS.zfsldr.S= ${CLANG_NO_IAS} Index: stable/11/stand/i386/zfsloader/Makefile =================================================================== --- stable/11/stand/i386/zfsloader/Makefile (revision 344376) +++ stable/11/stand/i386/zfsloader/Makefile (revision 344377) @@ -1,7 +1,8 @@ # $FreeBSD$ LOADER= zfsloader NEWVERSWHAT= "ZFS enabled bootstrap loader" x86 HAVE_ZFS= yes +CFLAGS+= -DBOOTPROG=\"zfsloader\" .include "${.CURDIR}/../loader/Makefile" Index: stable/11/stand/libsa/Makefile =================================================================== --- stable/11/stand/libsa/Makefile (revision 344376) +++ stable/11/stand/libsa/Makefile (revision 344377) @@ -1,154 +1,159 @@ # $FreeBSD$ # Originally from $NetBSD: Makefile,v 1.21 1997/10/26 22:08:38 lukem Exp $ # # Notes: # - We don't use the libc strerror/sys_errlist because the string table is # quite large. # .include LIBSA_CPUARCH?=${MACHINE_CPUARCH} LIBC_SRC= ${SRCTOP}/lib/libc LIB?= sa # standalone components and stuff we have modified locally SRCS+= gzguts.h zutil.h __main.c abort.c assert.c bcd.c environment.c getopt.c gets.c \ globals.c pager.c panic.c printf.c strdup.c strerror.c \ random.c sbrk.c twiddle.c zalloc.c zalloc_malloc.c # private (pruned) versions of libc string functions SRCS+= strcasecmp.c .PATH: ${LIBC_SRC}/net SRCS+= ntoh.c # string functions from libc .PATH: ${LIBC_SRC}/string SRCS+= bcmp.c bcopy.c bzero.c ffs.c fls.c \ memccpy.c memchr.c memcmp.c memcpy.c memmove.c memset.c \ qdivrem.c strcat.c strchr.c strcmp.c strcpy.c stpcpy.c stpncpy.c \ strcspn.c strlcat.c strlcpy.c strlen.c strncat.c strncmp.c strncpy.c \ strnlen.c strpbrk.c strrchr.c strsep.c strspn.c strstr.c strtok.c swab.c # stdlib functions from libc .PATH: ${LIBC_SRC}/stdlib SRCS+= abs.c strtol.c strtoll.c strtoul.c strtoull.c .if ${MACHINE_CPUARCH} == "arm" .PATH: ${LIBC_SRC}/arm/gen # Do not generate movt/movw, because the relocation fixup for them does not # translate to the -Bsymbolic -pie format required by self_reloc() in loader(8). # Also, the fpu is not available in a standalone environment. .if ${COMPILER_VERSION} < 30800 CFLAGS.clang+= -mllvm -arm-use-movt=0 .else CFLAGS.clang+= -mno-movt .endif CFLAGS.clang+= -mfpu=none # Compiler support functions .PATH: ${SRCTOP}/contrib/compiler-rt/lib/builtins/ # __clzsi2 and ctzsi2 for various builtin functions SRCS+= clzsi2.c ctzsi2.c # Divide and modulus functions called by the compiler SRCS+= divmoddi4.c divmodsi4.c divdi3.c divsi3.c moddi3.c modsi3.c SRCS+= udivmoddi4.c udivmodsi4.c udivdi3.c udivsi3.c umoddi3.c umodsi3.c .PATH: ${SRCTOP}/contrib/compiler-rt/lib/builtins/arm/ SRCS+= aeabi_idivmod.S aeabi_ldivmod.S aeabi_uidivmod.S aeabi_uldivmod.S SRCS+= aeabi_memcmp.S aeabi_memcpy.S aeabi_memmove.S aeabi_memset.S .endif .if ${MACHINE_CPUARCH} == "aarch64" || ${MACHINE_CPUARCH} == "riscv" .PATH: ${LIBC_SRC}/${MACHINE_CPUARCH}/gen .endif .if ${MACHINE_CPUARCH} == "powerpc" .PATH: ${LIBC_SRC}/quad SRCS+= ashldi3.c ashrdi3.c SRCS+= syncicache.c .endif # uuid functions from libc .PATH: ${LIBC_SRC}/uuid SRCS+= uuid_create_nil.c uuid_equal.c uuid_from_string.c uuid_is_nil.c uuid_to_string.c # _setjmp/_longjmp .PATH: ${SASRC}/${LIBSA_CPUARCH} SRCS+= _setjmp.S # decompression functionality from libbz2 # NOTE: to actually test this functionality after libbz2 upgrade compile # loader(8) with LOADER_BZIP2_SUPPORT defined .PATH: ${SRCTOP}/contrib/bzip2 CFLAGS+= -DBZ_NO_STDIO -DBZ_NO_COMPRESS SRCS+=bzlib.c crctable.c decompress.c huffman.c randtable.c # decompression functionality from zlib .PATH: ${SRCTOP}/contrib/zlib CFLAGS+=-DHAVE_MEMCPY -I${SRCTOP}/contrib/zlib SRCS+= adler32.c crc32.c SRCS+= infback.c inffast.c inflate.c inftrees.c zutil.c # Create a subset of includes that are safe, as well as adjusting those that aren't # The lists may drive people nuts, but they are explicitly opt-in FAKE_DIRS=xlocale arpa SAFE_INCS=a.out.h assert.h elf.h limits.h nlist.h setjmp.h stddef.h stdbool.h string.h strings.h time.h unistd.h uuid.h STAND_H_INC=ctype.h fcntl.h signal.h stdio.h stdlib.h OTHER_INC=stdarg.h errno.h stdint.h beforedepend: mkdir -p ${FAKE_DIRS}; \ for i in ${SAFE_INCS}; do \ ln -sf ${SRCTOP}/include/$$i $$i; \ done; \ ln -sf ${SYSDIR}/${MACHINE}/include/stdarg.h stdarg.h; \ ln -sf ${SYSDIR}/sys/errno.h errno.h; \ ln -sf ${SYSDIR}/sys/stdint.h stdint.h; \ ln -sf ${SRCTOP}/include/arpa/inet.h arpa/inet.h; \ ln -sf ${SRCTOP}/include/arpa/tftp.h arpa/tftp.h; \ for i in _time.h _strings.h _string.h; do \ [ -f xlocale/$$i ] || cp /dev/null xlocale/$$i; \ done; \ for i in ${STAND_H_INC}; do \ ln -sf ${SASRC}/stand.h $$i; \ done CLEANDIRS+=${FAKE_DIRS} CLEANFILES+= ${SAFE_INCS} ${STAND_H_INC} ${OTHER_INC} # io routines SRCS+= closeall.c dev.c ioctl.c nullfs.c stat.c \ fstat.c close.c lseek.c open.c read.c write.c readdir.c # network routines SRCS+= arp.c ether.c ip.c inet_ntoa.c in_cksum.c net.c udp.c netif.c rpc.c # network info services: SRCS+= bootp.c rarp.c bootparam.c # boot filesystems SRCS+= ufs.c nfs.c cd9660.c tftp.c gzipfs.c bzipfs.c SRCS+= dosfs.c ext2fs.c SRCS+= splitfs.c SRCS+= pkgfs.c .if ${MK_NAND} != "no" SRCS+= nandfs.c .endif CFLAGS.bzipfs.c+= -I${SRCTOP}/contrib/bzip2 # explicit_bzero .PATH: ${SYSDIR}/libkern SRCS+= explicit_bzero.c # Maybe GELI .if ${MK_LOADER_GELI} == "yes" .include "${SASRC}/geli/Makefile.inc" .endif +# Maybe ZFS +.if ${MK_ZFS} == "yes" +.include "${SASRC}/zfs/Makefile.inc" +.endif + .include Index: stable/11/stand/libsa/zfs/Makefile.inc =================================================================== --- stable/11/stand/libsa/zfs/Makefile.inc (nonexistent) +++ stable/11/stand/libsa/zfs/Makefile.inc (revision 344377) @@ -0,0 +1,13 @@ +# $FreeBSD$ + +.PATH: ${ZFSSRC} +SRCS+= zfs.c skein.c skein_block.c +# Do not unroll skein loops, reduce code size +CFLAGS+= -DSKEIN_LOOP=111 +.PATH: ${SYSDIR}/crypto/skein + +CFLAGS+= -I${LDRSRC} +CFLAGS+= -I${SYSDIR}/cddl/boot/zfs +CFLAGS+= -I${SYSDIR}/crypto/skein + +CFLAGS+= -Wformat -Wall Property changes on: stable/11/stand/libsa/zfs/Makefile.inc ___________________________________________________________________ Added: svn:eol-style ## -0,0 +1 ## +native \ No newline at end of property Added: svn:keywords ## -0,0 +1 ## +FreeBSD=%H \ No newline at end of property Added: svn:mime-type ## -0,0 +1 ## +text/plain \ No newline at end of property Index: stable/11/stand/libsa/zfs/devicename_stubs.c =================================================================== --- stable/11/stand/libsa/zfs/devicename_stubs.c (nonexistent) +++ stable/11/stand/libsa/zfs/devicename_stubs.c (revision 344377) @@ -0,0 +1,47 @@ +/*- + * Copyright (c) 2012 Andriy Gapon + * All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * 2. Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * + * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND + * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE + * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE + * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE + * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL + * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS + * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) + * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT + * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY + * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF + * SUCH DAMAGE. + */ + +#include +__FBSDID("$FreeBSD$"); + +#include +#include "libzfs.h" + +__attribute__((weak)) +int +zfs_parsedev(struct zfs_devdesc *dev, const char *devspec, const char **path) +{ + return (EINVAL); +} + +__attribute__((weak)) +char * +zfs_fmtdev(void *vdev) +{ + static char buf[128]; + + return (buf); +} Property changes on: stable/11/stand/libsa/zfs/devicename_stubs.c ___________________________________________________________________ Added: svn:eol-style ## -0,0 +1 ## +native \ No newline at end of property Added: svn:keywords ## -0,0 +1 ## +FreeBSD=%H \ No newline at end of property Added: svn:mime-type ## -0,0 +1 ## +text/plain \ No newline at end of property Index: stable/11/stand/libsa/zfs/libzfs.h =================================================================== --- stable/11/stand/libsa/zfs/libzfs.h (nonexistent) +++ stable/11/stand/libsa/zfs/libzfs.h (revision 344377) @@ -0,0 +1,86 @@ +/*- + * Copyright (c) 2012 Andriy Gapon + * All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * 2. Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * + * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND + * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE + * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE + * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE + * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL + * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS + * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) + * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT + * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY + * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF + * SUCH DAMAGE. + * + * $FreeBSD$ + */ + +#ifndef _BOOT_LIBZFS_H_ +#define _BOOT_LIBZFS_H_ + +#define ZFS_MAXNAMELEN 256 + +/* + * ZFS fully-qualified device descriptor. + */ +struct zfs_devdesc { + struct devdesc dd; /* Must be first. */ + uint64_t pool_guid; + uint64_t root_guid; +}; + +#ifdef LOADER_GELI_SUPPORT +#include +#endif + +struct zfs_boot_args +{ + uint32_t size; + uint32_t reserved; + uint64_t pool; + uint64_t root; + uint64_t primary_pool; + uint64_t primary_vdev; + union { + char gelipw[256]; + struct { + char notapw; /* + * single null byte to stop keybuf + * being interpreted as a password + */ + uint32_t keybuf_sentinel; +#ifdef LOADER_GELI_SUPPORT + struct keybuf *keybuf; +#else + void *keybuf; +#endif + }; + }; +}; + +int zfs_parsedev(struct zfs_devdesc *dev, const char *devspec, + const char **path); +char *zfs_fmtdev(void *vdev); +int zfs_probe_dev(const char *devname, uint64_t *pool_guid); +int zfs_list(const char *name); +uint64_t ldi_get_size(void *); +void init_zfs_bootenv(const char *currdev); +int zfs_bootenv(const char *name); +int zfs_belist_add(const char *name, uint64_t __unused); +int zfs_set_env(void); + +extern struct devsw zfs_dev; +extern struct fs_ops zfs_fsops; + +#endif /*_BOOT_LIBZFS_H_*/ Property changes on: stable/11/stand/libsa/zfs/libzfs.h ___________________________________________________________________ Added: svn:eol-style ## -0,0 +1 ## +native \ No newline at end of property Added: svn:keywords ## -0,0 +1 ## +FreeBSD=%H \ No newline at end of property Added: svn:mime-type ## -0,0 +1 ## +text/plain \ No newline at end of property Index: stable/11/stand/libsa/zfs/zfs.c =================================================================== --- stable/11/stand/libsa/zfs/zfs.c (nonexistent) +++ stable/11/stand/libsa/zfs/zfs.c (revision 344377) @@ -0,0 +1,1002 @@ +/*- + * Copyright (c) 2007 Doug Rabson + * All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * 2. Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * + * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND + * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE + * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE + * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE + * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL + * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS + * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) + * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT + * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY + * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF + * SUCH DAMAGE. + * + * $FreeBSD$ + */ + +#include +__FBSDID("$FreeBSD$"); + +/* + * Stand-alone file reading package. + */ + +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +#include "libzfs.h" + +#include "zfsimpl.c" + +/* Define the range of indexes to be populated with ZFS Boot Environments */ +#define ZFS_BE_FIRST 4 +#define ZFS_BE_LAST 8 + +static int zfs_open(const char *path, struct open_file *f); +static int zfs_close(struct open_file *f); +static int zfs_read(struct open_file *f, void *buf, size_t size, size_t *resid); +static off_t zfs_seek(struct open_file *f, off_t offset, int where); +static int zfs_stat(struct open_file *f, struct stat *sb); +static int zfs_readdir(struct open_file *f, struct dirent *d); + +static void zfs_bootenv_initial(const char *); + +struct devsw zfs_dev; + +struct fs_ops zfs_fsops = { + "zfs", + zfs_open, + zfs_close, + zfs_read, + null_write, + zfs_seek, + zfs_stat, + zfs_readdir +}; + +/* + * In-core open file. + */ +struct file { + off_t f_seekp; /* seek pointer */ + dnode_phys_t f_dnode; + uint64_t f_zap_type; /* zap type for readdir */ + uint64_t f_num_leafs; /* number of fzap leaf blocks */ + zap_leaf_phys_t *f_zap_leaf; /* zap leaf buffer */ +}; + +static int zfs_env_index; +static int zfs_env_count; + +SLIST_HEAD(zfs_be_list, zfs_be_entry) zfs_be_head = SLIST_HEAD_INITIALIZER(zfs_be_head); +struct zfs_be_list *zfs_be_headp; +struct zfs_be_entry { + const char *name; + SLIST_ENTRY(zfs_be_entry) entries; +} *zfs_be, *zfs_be_tmp; + +/* + * Open a file. + */ +static int +zfs_open(const char *upath, struct open_file *f) +{ + struct zfsmount *mount = (struct zfsmount *)f->f_devdata; + struct file *fp; + int rc; + + if (f->f_dev != &zfs_dev) + return (EINVAL); + + /* allocate file system specific data structure */ + fp = malloc(sizeof(struct file)); + bzero(fp, sizeof(struct file)); + f->f_fsdata = (void *)fp; + + rc = zfs_lookup(mount, upath, &fp->f_dnode); + fp->f_seekp = 0; + if (rc) { + f->f_fsdata = NULL; + free(fp); + } + return (rc); +} + +static int +zfs_close(struct open_file *f) +{ + struct file *fp = (struct file *)f->f_fsdata; + + dnode_cache_obj = NULL; + f->f_fsdata = (void *)0; + if (fp == (struct file *)0) + return (0); + + free(fp); + return (0); +} + +/* + * Copy a portion of a file into kernel memory. + * Cross block boundaries when necessary. + */ +static int +zfs_read(struct open_file *f, void *start, size_t size, size_t *resid /* out */) +{ + const spa_t *spa = ((struct zfsmount *)f->f_devdata)->spa; + struct file *fp = (struct file *)f->f_fsdata; + struct stat sb; + size_t n; + int rc; + + rc = zfs_stat(f, &sb); + if (rc) + return (rc); + n = size; + if (fp->f_seekp + n > sb.st_size) + n = sb.st_size - fp->f_seekp; + + rc = dnode_read(spa, &fp->f_dnode, fp->f_seekp, start, n); + if (rc) + return (rc); + + if (0) { + int i; + for (i = 0; i < n; i++) + putchar(((char*) start)[i]); + } + fp->f_seekp += n; + if (resid) + *resid = size - n; + + return (0); +} + +static off_t +zfs_seek(struct open_file *f, off_t offset, int where) +{ + struct file *fp = (struct file *)f->f_fsdata; + + switch (where) { + case SEEK_SET: + fp->f_seekp = offset; + break; + case SEEK_CUR: + fp->f_seekp += offset; + break; + case SEEK_END: + { + struct stat sb; + int error; + + error = zfs_stat(f, &sb); + if (error != 0) { + errno = error; + return (-1); + } + fp->f_seekp = sb.st_size - offset; + break; + } + default: + errno = EINVAL; + return (-1); + } + return (fp->f_seekp); +} + +static int +zfs_stat(struct open_file *f, struct stat *sb) +{ + const spa_t *spa = ((struct zfsmount *)f->f_devdata)->spa; + struct file *fp = (struct file *)f->f_fsdata; + + return (zfs_dnode_stat(spa, &fp->f_dnode, sb)); +} + +static int +zfs_readdir(struct open_file *f, struct dirent *d) +{ + const spa_t *spa = ((struct zfsmount *)f->f_devdata)->spa; + struct file *fp = (struct file *)f->f_fsdata; + mzap_ent_phys_t mze; + struct stat sb; + size_t bsize = fp->f_dnode.dn_datablkszsec << SPA_MINBLOCKSHIFT; + int rc; + + rc = zfs_stat(f, &sb); + if (rc) + return (rc); + if (!S_ISDIR(sb.st_mode)) + return (ENOTDIR); + + /* + * If this is the first read, get the zap type. + */ + if (fp->f_seekp == 0) { + rc = dnode_read(spa, &fp->f_dnode, + 0, &fp->f_zap_type, sizeof(fp->f_zap_type)); + if (rc) + return (rc); + + if (fp->f_zap_type == ZBT_MICRO) { + fp->f_seekp = offsetof(mzap_phys_t, mz_chunk); + } else { + rc = dnode_read(spa, &fp->f_dnode, + offsetof(zap_phys_t, zap_num_leafs), + &fp->f_num_leafs, + sizeof(fp->f_num_leafs)); + if (rc) + return (rc); + + fp->f_seekp = bsize; + fp->f_zap_leaf = (zap_leaf_phys_t *)malloc(bsize); + rc = dnode_read(spa, &fp->f_dnode, + fp->f_seekp, + fp->f_zap_leaf, + bsize); + if (rc) + return (rc); + } + } + + if (fp->f_zap_type == ZBT_MICRO) { + mzap_next: + if (fp->f_seekp >= bsize) + return (ENOENT); + + rc = dnode_read(spa, &fp->f_dnode, + fp->f_seekp, &mze, sizeof(mze)); + if (rc) + return (rc); + fp->f_seekp += sizeof(mze); + + if (!mze.mze_name[0]) + goto mzap_next; + + d->d_fileno = ZFS_DIRENT_OBJ(mze.mze_value); + d->d_type = ZFS_DIRENT_TYPE(mze.mze_value); + strcpy(d->d_name, mze.mze_name); + d->d_namlen = strlen(d->d_name); + return (0); + } else { + zap_leaf_t zl; + zap_leaf_chunk_t *zc, *nc; + int chunk; + size_t namelen; + char *p; + uint64_t value; + + /* + * Initialise this so we can use the ZAP size + * calculating macros. + */ + zl.l_bs = ilog2(bsize); + zl.l_phys = fp->f_zap_leaf; + + /* + * Figure out which chunk we are currently looking at + * and consider seeking to the next leaf. We use the + * low bits of f_seekp as a simple chunk index. + */ + fzap_next: + chunk = fp->f_seekp & (bsize - 1); + if (chunk == ZAP_LEAF_NUMCHUNKS(&zl)) { + fp->f_seekp = rounddown2(fp->f_seekp, bsize) + bsize; + chunk = 0; + + /* + * Check for EOF and read the new leaf. + */ + if (fp->f_seekp >= bsize * fp->f_num_leafs) + return (ENOENT); + + rc = dnode_read(spa, &fp->f_dnode, + fp->f_seekp, + fp->f_zap_leaf, + bsize); + if (rc) + return (rc); + } + + zc = &ZAP_LEAF_CHUNK(&zl, chunk); + fp->f_seekp++; + if (zc->l_entry.le_type != ZAP_CHUNK_ENTRY) + goto fzap_next; + + namelen = zc->l_entry.le_name_numints; + if (namelen > sizeof(d->d_name)) + namelen = sizeof(d->d_name); + + /* + * Paste the name back together. + */ + nc = &ZAP_LEAF_CHUNK(&zl, zc->l_entry.le_name_chunk); + p = d->d_name; + while (namelen > 0) { + int len; + len = namelen; + if (len > ZAP_LEAF_ARRAY_BYTES) + len = ZAP_LEAF_ARRAY_BYTES; + memcpy(p, nc->l_array.la_array, len); + p += len; + namelen -= len; + nc = &ZAP_LEAF_CHUNK(&zl, nc->l_array.la_next); + } + d->d_name[sizeof(d->d_name) - 1] = 0; + + /* + * Assume the first eight bytes of the value are + * a uint64_t. + */ + value = fzap_leaf_value(&zl, zc); + + d->d_fileno = ZFS_DIRENT_OBJ(value); + d->d_type = ZFS_DIRENT_TYPE(value); + d->d_namlen = strlen(d->d_name); + + return (0); + } +} + +static int +vdev_read(vdev_t *vdev, void *priv, off_t offset, void *buf, size_t bytes) +{ + int fd, ret; + size_t res, size, remainder, rb_size, blksz; + unsigned secsz; + off_t off; + char *bouncebuf, *rb_buf; + + fd = (uintptr_t) priv; + bouncebuf = NULL; + + ret = ioctl(fd, DIOCGSECTORSIZE, &secsz); + if (ret != 0) + return (ret); + + off = offset / secsz; + remainder = offset % secsz; + if (lseek(fd, off * secsz, SEEK_SET) == -1) + return (errno); + + rb_buf = buf; + rb_size = bytes; + size = roundup2(bytes + remainder, secsz); + blksz = size; + if (remainder != 0 || size != bytes) { + bouncebuf = zfs_alloc(secsz); + if (bouncebuf == NULL) { + printf("vdev_read: out of memory\n"); + return (ENOMEM); + } + rb_buf = bouncebuf; + blksz = rb_size - remainder; + } + + while (bytes > 0) { + res = read(fd, rb_buf, rb_size); + if (res != rb_size) { + ret = EIO; + goto error; + } + if (bytes < blksz) + blksz = bytes; + if (bouncebuf != NULL) + memcpy(buf, rb_buf + remainder, blksz); + buf = (void *)((uintptr_t)buf + blksz); + bytes -= blksz; + remainder = 0; + blksz = rb_size; + } + + ret = 0; +error: + if (bouncebuf != NULL) + zfs_free(bouncebuf, secsz); + return (ret); +} + +static int +zfs_dev_init(void) +{ + spa_t *spa; + spa_t *next; + spa_t *prev; + + zfs_init(); + if (archsw.arch_zfs_probe == NULL) + return (ENXIO); + archsw.arch_zfs_probe(); + + prev = NULL; + spa = STAILQ_FIRST(&zfs_pools); + while (spa != NULL) { + next = STAILQ_NEXT(spa, spa_link); + if (zfs_spa_init(spa)) { + if (prev == NULL) + STAILQ_REMOVE_HEAD(&zfs_pools, spa_link); + else + STAILQ_REMOVE_AFTER(&zfs_pools, prev, spa_link); + } else + prev = spa; + spa = next; + } + return (0); +} + +struct zfs_probe_args { + int fd; + const char *devname; + uint64_t *pool_guid; + u_int secsz; +}; + +static int +zfs_diskread(void *arg, void *buf, size_t blocks, uint64_t offset) +{ + struct zfs_probe_args *ppa; + + ppa = (struct zfs_probe_args *)arg; + return (vdev_read(NULL, (void *)(uintptr_t)ppa->fd, + offset * ppa->secsz, buf, blocks * ppa->secsz)); +} + +static int +zfs_probe(int fd, uint64_t *pool_guid) +{ + spa_t *spa; + int ret; + + ret = vdev_probe(vdev_read, (void *)(uintptr_t)fd, &spa); + if (ret == 0 && pool_guid != NULL) + *pool_guid = spa->spa_guid; + return (ret); +} + +static int +zfs_probe_partition(void *arg, const char *partname, + const struct ptable_entry *part) +{ + struct zfs_probe_args *ppa, pa; + struct ptable *table; + char devname[32]; + int ret; + + /* Probe only freebsd-zfs and freebsd partitions */ + if (part->type != PART_FREEBSD && + part->type != PART_FREEBSD_ZFS) + return (0); + + ppa = (struct zfs_probe_args *)arg; + strncpy(devname, ppa->devname, strlen(ppa->devname) - 1); + devname[strlen(ppa->devname) - 1] = '\0'; + sprintf(devname, "%s%s:", devname, partname); + pa.fd = open(devname, O_RDONLY); + if (pa.fd == -1) + return (0); + ret = zfs_probe(pa.fd, ppa->pool_guid); + if (ret == 0) + return (0); + /* Do we have BSD label here? */ + if (part->type == PART_FREEBSD) { + pa.devname = devname; + pa.pool_guid = ppa->pool_guid; + pa.secsz = ppa->secsz; + table = ptable_open(&pa, part->end - part->start + 1, + ppa->secsz, zfs_diskread); + if (table != NULL) { + ptable_iterate(table, &pa, zfs_probe_partition); + ptable_close(table); + } + } + close(pa.fd); + return (0); +} + +int +zfs_probe_dev(const char *devname, uint64_t *pool_guid) +{ + struct ptable *table; + struct zfs_probe_args pa; + uint64_t mediasz; + int ret; + + if (pool_guid) + *pool_guid = 0; + pa.fd = open(devname, O_RDONLY); + if (pa.fd == -1) + return (ENXIO); + /* Probe the whole disk */ + ret = zfs_probe(pa.fd, pool_guid); + if (ret == 0) + return (0); + + /* Probe each partition */ + ret = ioctl(pa.fd, DIOCGMEDIASIZE, &mediasz); + if (ret == 0) + ret = ioctl(pa.fd, DIOCGSECTORSIZE, &pa.secsz); + if (ret == 0) { + pa.devname = devname; + pa.pool_guid = pool_guid; + table = ptable_open(&pa, mediasz / pa.secsz, pa.secsz, + zfs_diskread); + if (table != NULL) { + ptable_iterate(table, &pa, zfs_probe_partition); + ptable_close(table); + } + } + close(pa.fd); + if (pool_guid && *pool_guid == 0) + ret = ENXIO; + return (ret); +} + +/* + * Print information about ZFS pools + */ +static int +zfs_dev_print(int verbose) +{ + spa_t *spa; + char line[80]; + int ret = 0; + + if (STAILQ_EMPTY(&zfs_pools)) + return (0); + + printf("%s devices:", zfs_dev.dv_name); + if ((ret = pager_output("\n")) != 0) + return (ret); + + if (verbose) { + return (spa_all_status()); + } + STAILQ_FOREACH(spa, &zfs_pools, spa_link) { + snprintf(line, sizeof(line), " zfs:%s\n", spa->spa_name); + ret = pager_output(line); + if (ret != 0) + break; + } + return (ret); +} + +/* + * Attempt to open the pool described by (dev) for use by (f). + */ +static int +zfs_dev_open(struct open_file *f, ...) +{ + va_list args; + struct zfs_devdesc *dev; + struct zfsmount *mount; + spa_t *spa; + int rv; + + va_start(args, f); + dev = va_arg(args, struct zfs_devdesc *); + va_end(args); + + if (dev->pool_guid == 0) + spa = STAILQ_FIRST(&zfs_pools); + else + spa = spa_find_by_guid(dev->pool_guid); + if (!spa) + return (ENXIO); + mount = malloc(sizeof(*mount)); + rv = zfs_mount(spa, dev->root_guid, mount); + if (rv != 0) { + free(mount); + return (rv); + } + if (mount->objset.os_type != DMU_OST_ZFS) { + printf("Unexpected object set type %ju\n", + (uintmax_t)mount->objset.os_type); + free(mount); + return (EIO); + } + f->f_devdata = mount; + free(dev); + return (0); +} + +static int +zfs_dev_close(struct open_file *f) +{ + + free(f->f_devdata); + f->f_devdata = NULL; + return (0); +} + +static int +zfs_dev_strategy(void *devdata, int rw, daddr_t dblk, size_t size, char *buf, size_t *rsize) +{ + + return (ENOSYS); +} + +struct devsw zfs_dev = { + .dv_name = "zfs", + .dv_type = DEVT_ZFS, + .dv_init = zfs_dev_init, + .dv_strategy = zfs_dev_strategy, + .dv_open = zfs_dev_open, + .dv_close = zfs_dev_close, + .dv_ioctl = noioctl, + .dv_print = zfs_dev_print, + .dv_cleanup = NULL +}; + +int +zfs_parsedev(struct zfs_devdesc *dev, const char *devspec, const char **path) +{ + static char rootname[ZFS_MAXNAMELEN]; + static char poolname[ZFS_MAXNAMELEN]; + spa_t *spa; + const char *end; + const char *np; + const char *sep; + int rv; + + np = devspec; + if (*np != ':') + return (EINVAL); + np++; + end = strrchr(np, ':'); + if (end == NULL) + return (EINVAL); + sep = strchr(np, '/'); + if (sep == NULL || sep >= end) + sep = end; + memcpy(poolname, np, sep - np); + poolname[sep - np] = '\0'; + if (sep < end) { + sep++; + memcpy(rootname, sep, end - sep); + rootname[end - sep] = '\0'; + } + else + rootname[0] = '\0'; + + spa = spa_find_by_name(poolname); + if (!spa) + return (ENXIO); + dev->pool_guid = spa->spa_guid; + rv = zfs_lookup_dataset(spa, rootname, &dev->root_guid); + if (rv != 0) + return (rv); + if (path != NULL) + *path = (*end == '\0') ? end : end + 1; + dev->dd.d_dev = &zfs_dev; + return (0); +} + +char * +zfs_fmtdev(void *vdev) +{ + static char rootname[ZFS_MAXNAMELEN]; + static char buf[2 * ZFS_MAXNAMELEN + 8]; + struct zfs_devdesc *dev = (struct zfs_devdesc *)vdev; + spa_t *spa; + + buf[0] = '\0'; + if (dev->dd.d_dev->dv_type != DEVT_ZFS) + return (buf); + + if (dev->pool_guid == 0) { + spa = STAILQ_FIRST(&zfs_pools); + dev->pool_guid = spa->spa_guid; + } else + spa = spa_find_by_guid(dev->pool_guid); + if (spa == NULL) { + printf("ZFS: can't find pool by guid\n"); + return (buf); + } + if (dev->root_guid == 0 && zfs_get_root(spa, &dev->root_guid)) { + printf("ZFS: can't find root filesystem\n"); + return (buf); + } + if (zfs_rlookup(spa, dev->root_guid, rootname)) { + printf("ZFS: can't find filesystem by guid\n"); + return (buf); + } + + if (rootname[0] == '\0') + sprintf(buf, "%s:%s:", dev->dd.d_dev->dv_name, spa->spa_name); + else + sprintf(buf, "%s:%s/%s:", dev->dd.d_dev->dv_name, spa->spa_name, + rootname); + return (buf); +} + +int +zfs_list(const char *name) +{ + static char poolname[ZFS_MAXNAMELEN]; + uint64_t objid; + spa_t *spa; + const char *dsname; + int len; + int rv; + + len = strlen(name); + dsname = strchr(name, '/'); + if (dsname != NULL) { + len = dsname - name; + dsname++; + } else + dsname = ""; + memcpy(poolname, name, len); + poolname[len] = '\0'; + + spa = spa_find_by_name(poolname); + if (!spa) + return (ENXIO); + rv = zfs_lookup_dataset(spa, dsname, &objid); + if (rv != 0) + return (rv); + + return (zfs_list_dataset(spa, objid)); +} + +void +init_zfs_bootenv(const char *currdev_in) +{ + char *beroot, *currdev; + int currdev_len; + + currdev = NULL; + currdev_len = strlen(currdev_in); + if (currdev_len == 0) + return; + if (strncmp(currdev_in, "zfs:", 4) != 0) + return; + currdev = strdup(currdev_in); + if (currdev == NULL) + return; + /* Remove the trailing : */ + currdev[currdev_len - 1] = '\0'; + setenv("zfs_be_active", currdev, 1); + setenv("zfs_be_currpage", "1", 1); + /* Remove the last element (current bootenv) */ + beroot = strrchr(currdev, '/'); + if (beroot != NULL) + beroot[0] = '\0'; + beroot = strchr(currdev, ':') + 1; + setenv("zfs_be_root", beroot, 1); + zfs_bootenv_initial(beroot); + free(currdev); +} + +static void +zfs_bootenv_initial(const char *name) +{ + char poolname[ZFS_MAXNAMELEN], *dsname; + char envname[32], envval[256]; + uint64_t objid; + spa_t *spa; + int bootenvs_idx, len, rv; + + SLIST_INIT(&zfs_be_head); + zfs_env_count = 0; + len = strlen(name); + dsname = strchr(name, '/'); + if (dsname != NULL) { + len = dsname - name; + dsname++; + } else + dsname = ""; + strlcpy(poolname, name, len + 1); + spa = spa_find_by_name(poolname); + if (spa == NULL) + return; + rv = zfs_lookup_dataset(spa, dsname, &objid); + if (rv != 0) + return; + rv = zfs_callback_dataset(spa, objid, zfs_belist_add); + bootenvs_idx = 0; + /* Populate the initial environment variables */ + SLIST_FOREACH_SAFE(zfs_be, &zfs_be_head, entries, zfs_be_tmp) { + /* Enumerate all bootenvs for general usage */ + snprintf(envname, sizeof(envname), "bootenvs[%d]", bootenvs_idx); + snprintf(envval, sizeof(envval), "zfs:%s/%s", name, zfs_be->name); + rv = setenv(envname, envval, 1); + if (rv != 0) + break; + bootenvs_idx++; + } + snprintf(envval, sizeof(envval), "%d", bootenvs_idx); + setenv("bootenvs_count", envval, 1); + + /* Clean up the SLIST of ZFS BEs */ + while (!SLIST_EMPTY(&zfs_be_head)) { + zfs_be = SLIST_FIRST(&zfs_be_head); + SLIST_REMOVE_HEAD(&zfs_be_head, entries); + free(zfs_be); + } + + return; + +} + +int +zfs_bootenv(const char *name) +{ + static char poolname[ZFS_MAXNAMELEN], *dsname, *root; + char becount[4]; + uint64_t objid; + spa_t *spa; + int len, rv, pages, perpage, currpage; + + if (name == NULL) + return (EINVAL); + if ((root = getenv("zfs_be_root")) == NULL) + return (EINVAL); + + if (strcmp(name, root) != 0) { + if (setenv("zfs_be_root", name, 1) != 0) + return (ENOMEM); + } + + SLIST_INIT(&zfs_be_head); + zfs_env_count = 0; + len = strlen(name); + dsname = strchr(name, '/'); + if (dsname != NULL) { + len = dsname - name; + dsname++; + } else + dsname = ""; + memcpy(poolname, name, len); + poolname[len] = '\0'; + + spa = spa_find_by_name(poolname); + if (!spa) + return (ENXIO); + rv = zfs_lookup_dataset(spa, dsname, &objid); + if (rv != 0) + return (rv); + rv = zfs_callback_dataset(spa, objid, zfs_belist_add); + + /* Calculate and store the number of pages of BEs */ + perpage = (ZFS_BE_LAST - ZFS_BE_FIRST + 1); + pages = (zfs_env_count / perpage) + ((zfs_env_count % perpage) > 0 ? 1 : 0); + snprintf(becount, 4, "%d", pages); + if (setenv("zfs_be_pages", becount, 1) != 0) + return (ENOMEM); + + /* Roll over the page counter if it has exceeded the maximum */ + currpage = strtol(getenv("zfs_be_currpage"), NULL, 10); + if (currpage > pages) { + if (setenv("zfs_be_currpage", "1", 1) != 0) + return (ENOMEM); + } + + /* Populate the menu environment variables */ + zfs_set_env(); + + /* Clean up the SLIST of ZFS BEs */ + while (!SLIST_EMPTY(&zfs_be_head)) { + zfs_be = SLIST_FIRST(&zfs_be_head); + SLIST_REMOVE_HEAD(&zfs_be_head, entries); + free(zfs_be); + } + + return (rv); +} + +int +zfs_belist_add(const char *name, uint64_t value __unused) +{ + + /* Skip special datasets that start with a $ character */ + if (strncmp(name, "$", 1) == 0) { + return (0); + } + /* Add the boot environment to the head of the SLIST */ + zfs_be = malloc(sizeof(struct zfs_be_entry)); + if (zfs_be == NULL) { + return (ENOMEM); + } + zfs_be->name = name; + SLIST_INSERT_HEAD(&zfs_be_head, zfs_be, entries); + zfs_env_count++; + + return (0); +} + +int +zfs_set_env(void) +{ + char envname[32], envval[256]; + char *beroot, *pagenum; + int rv, page, ctr; + + beroot = getenv("zfs_be_root"); + if (beroot == NULL) { + return (1); + } + + pagenum = getenv("zfs_be_currpage"); + if (pagenum != NULL) { + page = strtol(pagenum, NULL, 10); + } else { + page = 1; + } + + ctr = 1; + rv = 0; + zfs_env_index = ZFS_BE_FIRST; + SLIST_FOREACH_SAFE(zfs_be, &zfs_be_head, entries, zfs_be_tmp) { + /* Skip to the requested page number */ + if (ctr <= ((ZFS_BE_LAST - ZFS_BE_FIRST + 1) * (page - 1))) { + ctr++; + continue; + } + + snprintf(envname, sizeof(envname), "bootenvmenu_caption[%d]", zfs_env_index); + snprintf(envval, sizeof(envval), "%s", zfs_be->name); + rv = setenv(envname, envval, 1); + if (rv != 0) { + break; + } + + snprintf(envname, sizeof(envname), "bootenvansi_caption[%d]", zfs_env_index); + rv = setenv(envname, envval, 1); + if (rv != 0){ + break; + } + + snprintf(envname, sizeof(envname), "bootenvmenu_command[%d]", zfs_env_index); + rv = setenv(envname, "set_bootenv", 1); + if (rv != 0){ + break; + } + + snprintf(envname, sizeof(envname), "bootenv_root[%d]", zfs_env_index); + snprintf(envval, sizeof(envval), "zfs:%s/%s", beroot, zfs_be->name); + rv = setenv(envname, envval, 1); + if (rv != 0){ + break; + } + + zfs_env_index++; + if (zfs_env_index > ZFS_BE_LAST) { + break; + } + + } + + for (; zfs_env_index <= ZFS_BE_LAST; zfs_env_index++) { + snprintf(envname, sizeof(envname), "bootenvmenu_caption[%d]", zfs_env_index); + (void)unsetenv(envname); + snprintf(envname, sizeof(envname), "bootenvansi_caption[%d]", zfs_env_index); + (void)unsetenv(envname); + snprintf(envname, sizeof(envname), "bootenvmenu_command[%d]", zfs_env_index); + (void)unsetenv(envname); + snprintf(envname, sizeof(envname), "bootenv_root[%d]", zfs_env_index); + (void)unsetenv(envname); + } + + return (rv); +} Property changes on: stable/11/stand/libsa/zfs/zfs.c ___________________________________________________________________ Added: svn:eol-style ## -0,0 +1 ## +native \ No newline at end of property Added: svn:keywords ## -0,0 +1 ## +FreeBSD=%H \ No newline at end of property Added: svn:mime-type ## -0,0 +1 ## +text/plain \ No newline at end of property Index: stable/11/stand/libsa/zfs/zfsimpl.c =================================================================== --- stable/11/stand/libsa/zfs/zfsimpl.c (nonexistent) +++ stable/11/stand/libsa/zfs/zfsimpl.c (revision 344377) @@ -0,0 +1,2537 @@ +/*- + * Copyright (c) 2007 Doug Rabson + * All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * 2. Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * + * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND + * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE + * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE + * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE + * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL + * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS + * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) + * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT + * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY + * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF + * SUCH DAMAGE. + */ + +#include +__FBSDID("$FreeBSD$"); + +/* + * Stand-alone ZFS file reader. + */ + +#include +#include + +#include "zfsimpl.h" +#include "zfssubr.c" + + +struct zfsmount { + const spa_t *spa; + objset_phys_t objset; + uint64_t rootobj; +}; +static struct zfsmount zfsmount __unused; + +/* + * List of all vdevs, chained through v_alllink. + */ +static vdev_list_t zfs_vdevs; + + /* + * List of ZFS features supported for read + */ +static const char *features_for_read[] = { + "org.illumos:lz4_compress", + "com.delphix:hole_birth", + "com.delphix:extensible_dataset", + "com.delphix:embedded_data", + "org.open-zfs:large_blocks", + "org.illumos:sha512", + "org.illumos:skein", + "org.zfsonlinux:large_dnode", + NULL +}; + +/* + * List of all pools, chained through spa_link. + */ +static spa_list_t zfs_pools; + +static const dnode_phys_t *dnode_cache_obj; +static uint64_t dnode_cache_bn; +static char *dnode_cache_buf; +static char *zap_scratch; +static char *zfs_temp_buf, *zfs_temp_end, *zfs_temp_ptr; + +#define TEMP_SIZE (1024 * 1024) + +static int zio_read(const spa_t *spa, const blkptr_t *bp, void *buf); +static int zfs_get_root(const spa_t *spa, uint64_t *objid); +static int zfs_rlookup(const spa_t *spa, uint64_t objnum, char *result); +static int zap_lookup(const spa_t *spa, const dnode_phys_t *dnode, + const char *name, uint64_t integer_size, uint64_t num_integers, + void *value); + +static void +zfs_init(void) +{ + STAILQ_INIT(&zfs_vdevs); + STAILQ_INIT(&zfs_pools); + + zfs_temp_buf = malloc(TEMP_SIZE); + zfs_temp_end = zfs_temp_buf + TEMP_SIZE; + zfs_temp_ptr = zfs_temp_buf; + dnode_cache_buf = malloc(SPA_MAXBLOCKSIZE); + zap_scratch = malloc(SPA_MAXBLOCKSIZE); + + zfs_init_crc(); +} + +static void * +zfs_alloc(size_t size) +{ + char *ptr; + + if (zfs_temp_ptr + size > zfs_temp_end) { + printf("ZFS: out of temporary buffer space\n"); + for (;;) ; + } + ptr = zfs_temp_ptr; + zfs_temp_ptr += size; + + return (ptr); +} + +static void +zfs_free(void *ptr, size_t size) +{ + + zfs_temp_ptr -= size; + if (zfs_temp_ptr != ptr) { + printf("ZFS: zfs_alloc()/zfs_free() mismatch\n"); + for (;;) ; + } +} + +static int +xdr_int(const unsigned char **xdr, int *ip) +{ + *ip = ((*xdr)[0] << 24) + | ((*xdr)[1] << 16) + | ((*xdr)[2] << 8) + | ((*xdr)[3] << 0); + (*xdr) += 4; + return (0); +} + +static int +xdr_u_int(const unsigned char **xdr, u_int *ip) +{ + *ip = ((*xdr)[0] << 24) + | ((*xdr)[1] << 16) + | ((*xdr)[2] << 8) + | ((*xdr)[3] << 0); + (*xdr) += 4; + return (0); +} + +static int +xdr_uint64_t(const unsigned char **xdr, uint64_t *lp) +{ + u_int hi, lo; + + xdr_u_int(xdr, &hi); + xdr_u_int(xdr, &lo); + *lp = (((uint64_t) hi) << 32) | lo; + return (0); +} + +static int +nvlist_find(const unsigned char *nvlist, const char *name, int type, + int* elementsp, void *valuep) +{ + const unsigned char *p, *pair; + int junk; + int encoded_size, decoded_size; + + p = nvlist; + xdr_int(&p, &junk); + xdr_int(&p, &junk); + + pair = p; + xdr_int(&p, &encoded_size); + xdr_int(&p, &decoded_size); + while (encoded_size && decoded_size) { + int namelen, pairtype, elements; + const char *pairname; + + xdr_int(&p, &namelen); + pairname = (const char*) p; + p += roundup(namelen, 4); + xdr_int(&p, &pairtype); + + if (!memcmp(name, pairname, namelen) && type == pairtype) { + xdr_int(&p, &elements); + if (elementsp) + *elementsp = elements; + if (type == DATA_TYPE_UINT64) { + xdr_uint64_t(&p, (uint64_t *) valuep); + return (0); + } else if (type == DATA_TYPE_STRING) { + int len; + xdr_int(&p, &len); + (*(const char**) valuep) = (const char*) p; + return (0); + } else if (type == DATA_TYPE_NVLIST + || type == DATA_TYPE_NVLIST_ARRAY) { + (*(const unsigned char**) valuep) = + (const unsigned char*) p; + return (0); + } else { + return (EIO); + } + } else { + /* + * Not the pair we are looking for, skip to the next one. + */ + p = pair + encoded_size; + } + + pair = p; + xdr_int(&p, &encoded_size); + xdr_int(&p, &decoded_size); + } + + return (EIO); +} + +static int +nvlist_check_features_for_read(const unsigned char *nvlist) +{ + const unsigned char *p, *pair; + int junk; + int encoded_size, decoded_size; + int rc; + + rc = 0; + + p = nvlist; + xdr_int(&p, &junk); + xdr_int(&p, &junk); + + pair = p; + xdr_int(&p, &encoded_size); + xdr_int(&p, &decoded_size); + while (encoded_size && decoded_size) { + int namelen, pairtype; + const char *pairname; + int i, found; + + found = 0; + + xdr_int(&p, &namelen); + pairname = (const char*) p; + p += roundup(namelen, 4); + xdr_int(&p, &pairtype); + + for (i = 0; features_for_read[i] != NULL; i++) { + if (!memcmp(pairname, features_for_read[i], namelen)) { + found = 1; + break; + } + } + + if (!found) { + printf("ZFS: unsupported feature: %s\n", pairname); + rc = EIO; + } + + p = pair + encoded_size; + + pair = p; + xdr_int(&p, &encoded_size); + xdr_int(&p, &decoded_size); + } + + return (rc); +} + +/* + * Return the next nvlist in an nvlist array. + */ +static const unsigned char * +nvlist_next(const unsigned char *nvlist) +{ + const unsigned char *p, *pair; + int junk; + int encoded_size, decoded_size; + + p = nvlist; + xdr_int(&p, &junk); + xdr_int(&p, &junk); + + pair = p; + xdr_int(&p, &encoded_size); + xdr_int(&p, &decoded_size); + while (encoded_size && decoded_size) { + p = pair + encoded_size; + + pair = p; + xdr_int(&p, &encoded_size); + xdr_int(&p, &decoded_size); + } + + return p; +} + +#ifdef TEST + +static const unsigned char * +nvlist_print(const unsigned char *nvlist, unsigned int indent) +{ + static const char* typenames[] = { + "DATA_TYPE_UNKNOWN", + "DATA_TYPE_BOOLEAN", + "DATA_TYPE_BYTE", + "DATA_TYPE_INT16", + "DATA_TYPE_UINT16", + "DATA_TYPE_INT32", + "DATA_TYPE_UINT32", + "DATA_TYPE_INT64", + "DATA_TYPE_UINT64", + "DATA_TYPE_STRING", + "DATA_TYPE_BYTE_ARRAY", + "DATA_TYPE_INT16_ARRAY", + "DATA_TYPE_UINT16_ARRAY", + "DATA_TYPE_INT32_ARRAY", + "DATA_TYPE_UINT32_ARRAY", + "DATA_TYPE_INT64_ARRAY", + "DATA_TYPE_UINT64_ARRAY", + "DATA_TYPE_STRING_ARRAY", + "DATA_TYPE_HRTIME", + "DATA_TYPE_NVLIST", + "DATA_TYPE_NVLIST_ARRAY", + "DATA_TYPE_BOOLEAN_VALUE", + "DATA_TYPE_INT8", + "DATA_TYPE_UINT8", + "DATA_TYPE_BOOLEAN_ARRAY", + "DATA_TYPE_INT8_ARRAY", + "DATA_TYPE_UINT8_ARRAY" + }; + + unsigned int i, j; + const unsigned char *p, *pair; + int junk; + int encoded_size, decoded_size; + + p = nvlist; + xdr_int(&p, &junk); + xdr_int(&p, &junk); + + pair = p; + xdr_int(&p, &encoded_size); + xdr_int(&p, &decoded_size); + while (encoded_size && decoded_size) { + int namelen, pairtype, elements; + const char *pairname; + + xdr_int(&p, &namelen); + pairname = (const char*) p; + p += roundup(namelen, 4); + xdr_int(&p, &pairtype); + + for (i = 0; i < indent; i++) + printf(" "); + printf("%s %s", typenames[pairtype], pairname); + + xdr_int(&p, &elements); + switch (pairtype) { + case DATA_TYPE_UINT64: { + uint64_t val; + xdr_uint64_t(&p, &val); + printf(" = 0x%jx\n", (uintmax_t)val); + break; + } + + case DATA_TYPE_STRING: { + int len; + xdr_int(&p, &len); + printf(" = \"%s\"\n", p); + break; + } + + case DATA_TYPE_NVLIST: + printf("\n"); + nvlist_print(p, indent + 1); + break; + + case DATA_TYPE_NVLIST_ARRAY: + for (j = 0; j < elements; j++) { + printf("[%d]\n", j); + p = nvlist_print(p, indent + 1); + if (j != elements - 1) { + for (i = 0; i < indent; i++) + printf(" "); + printf("%s %s", typenames[pairtype], pairname); + } + } + break; + + default: + printf("\n"); + } + + p = pair + encoded_size; + + pair = p; + xdr_int(&p, &encoded_size); + xdr_int(&p, &decoded_size); + } + + return p; +} + +#endif + +static int +vdev_read_phys(vdev_t *vdev, const blkptr_t *bp, void *buf, + off_t offset, size_t size) +{ + size_t psize; + int rc; + + if (!vdev->v_phys_read) + return (EIO); + + if (bp) { + psize = BP_GET_PSIZE(bp); + } else { + psize = size; + } + + /*printf("ZFS: reading %zu bytes at 0x%jx to %p\n", psize, (uintmax_t)offset, buf);*/ + rc = vdev->v_phys_read(vdev, vdev->v_read_priv, offset, buf, psize); + if (rc) + return (rc); + if (bp && zio_checksum_verify(vdev->spa, bp, buf)) + return (EIO); + + return (0); +} + +static int +vdev_disk_read(vdev_t *vdev, const blkptr_t *bp, void *buf, + off_t offset, size_t bytes) +{ + + return (vdev_read_phys(vdev, bp, buf, + offset + VDEV_LABEL_START_SIZE, bytes)); +} + + +static int +vdev_mirror_read(vdev_t *vdev, const blkptr_t *bp, void *buf, + off_t offset, size_t bytes) +{ + vdev_t *kid; + int rc; + + rc = EIO; + STAILQ_FOREACH(kid, &vdev->v_children, v_childlink) { + if (kid->v_state != VDEV_STATE_HEALTHY) + continue; + rc = kid->v_read(kid, bp, buf, offset, bytes); + if (!rc) + return (0); + } + + return (rc); +} + +static int +vdev_replacing_read(vdev_t *vdev, const blkptr_t *bp, void *buf, + off_t offset, size_t bytes) +{ + vdev_t *kid; + + /* + * Here we should have two kids: + * First one which is the one we are replacing and we can trust + * only this one to have valid data, but it might not be present. + * Second one is that one we are replacing with. It is most likely + * healthy, but we can't trust it has needed data, so we won't use it. + */ + kid = STAILQ_FIRST(&vdev->v_children); + if (kid == NULL) + return (EIO); + if (kid->v_state != VDEV_STATE_HEALTHY) + return (EIO); + return (kid->v_read(kid, bp, buf, offset, bytes)); +} + +static vdev_t * +vdev_find(uint64_t guid) +{ + vdev_t *vdev; + + STAILQ_FOREACH(vdev, &zfs_vdevs, v_alllink) + if (vdev->v_guid == guid) + return (vdev); + + return (0); +} + +static vdev_t * +vdev_create(uint64_t guid, vdev_read_t *_read) +{ + vdev_t *vdev; + + vdev = malloc(sizeof(vdev_t)); + memset(vdev, 0, sizeof(vdev_t)); + STAILQ_INIT(&vdev->v_children); + vdev->v_guid = guid; + vdev->v_state = VDEV_STATE_OFFLINE; + vdev->v_read = _read; + vdev->v_phys_read = 0; + vdev->v_read_priv = 0; + STAILQ_INSERT_TAIL(&zfs_vdevs, vdev, v_alllink); + + return (vdev); +} + +static int +vdev_init_from_nvlist(const unsigned char *nvlist, vdev_t *pvdev, + vdev_t **vdevp, int is_newer) +{ + int rc; + uint64_t guid, id, ashift, nparity; + const char *type; + const char *path; + vdev_t *vdev, *kid; + const unsigned char *kids; + int nkids, i, is_new; + uint64_t is_offline, is_faulted, is_degraded, is_removed, isnt_present; + + if (nvlist_find(nvlist, ZPOOL_CONFIG_GUID, DATA_TYPE_UINT64, + NULL, &guid) + || nvlist_find(nvlist, ZPOOL_CONFIG_ID, DATA_TYPE_UINT64, NULL, &id) + || nvlist_find(nvlist, ZPOOL_CONFIG_TYPE, DATA_TYPE_STRING, + NULL, &type)) { + printf("ZFS: can't find vdev details\n"); + return (ENOENT); + } + + if (strcmp(type, VDEV_TYPE_MIRROR) + && strcmp(type, VDEV_TYPE_DISK) +#ifdef ZFS_TEST + && strcmp(type, VDEV_TYPE_FILE) +#endif + && strcmp(type, VDEV_TYPE_RAIDZ) + && strcmp(type, VDEV_TYPE_REPLACING)) { + printf("ZFS: can only boot from disk, mirror, raidz1, raidz2 and raidz3 vdevs\n"); + return (EIO); + } + + is_offline = is_removed = is_faulted = is_degraded = isnt_present = 0; + + nvlist_find(nvlist, ZPOOL_CONFIG_OFFLINE, DATA_TYPE_UINT64, NULL, + &is_offline); + nvlist_find(nvlist, ZPOOL_CONFIG_REMOVED, DATA_TYPE_UINT64, NULL, + &is_removed); + nvlist_find(nvlist, ZPOOL_CONFIG_FAULTED, DATA_TYPE_UINT64, NULL, + &is_faulted); + nvlist_find(nvlist, ZPOOL_CONFIG_DEGRADED, DATA_TYPE_UINT64, NULL, + &is_degraded); + nvlist_find(nvlist, ZPOOL_CONFIG_NOT_PRESENT, DATA_TYPE_UINT64, NULL, + &isnt_present); + + vdev = vdev_find(guid); + if (!vdev) { + is_new = 1; + + if (!strcmp(type, VDEV_TYPE_MIRROR)) + vdev = vdev_create(guid, vdev_mirror_read); + else if (!strcmp(type, VDEV_TYPE_RAIDZ)) + vdev = vdev_create(guid, vdev_raidz_read); + else if (!strcmp(type, VDEV_TYPE_REPLACING)) + vdev = vdev_create(guid, vdev_replacing_read); + else + vdev = vdev_create(guid, vdev_disk_read); + + vdev->v_id = id; + vdev->v_top = pvdev != NULL ? pvdev : vdev; + if (nvlist_find(nvlist, ZPOOL_CONFIG_ASHIFT, + DATA_TYPE_UINT64, NULL, &ashift) == 0) { + vdev->v_ashift = ashift; + } else { + vdev->v_ashift = 0; + } + if (nvlist_find(nvlist, ZPOOL_CONFIG_NPARITY, + DATA_TYPE_UINT64, NULL, &nparity) == 0) { + vdev->v_nparity = nparity; + } else { + vdev->v_nparity = 0; + } + if (nvlist_find(nvlist, ZPOOL_CONFIG_PATH, + DATA_TYPE_STRING, NULL, &path) == 0) { + if (strncmp(path, "/dev/", 5) == 0) + path += 5; + vdev->v_name = strdup(path); + } else { + if (!strcmp(type, "raidz")) { + if (vdev->v_nparity == 1) + vdev->v_name = "raidz1"; + else if (vdev->v_nparity == 2) + vdev->v_name = "raidz2"; + else if (vdev->v_nparity == 3) + vdev->v_name = "raidz3"; + else { + printf("ZFS: can only boot from disk, mirror, raidz1, raidz2 and raidz3 vdevs\n"); + return (EIO); + } + } else { + vdev->v_name = strdup(type); + } + } + } else { + is_new = 0; + } + + if (is_new || is_newer) { + /* + * This is either new vdev or we've already seen this vdev, + * but from an older vdev label, so let's refresh its state + * from the newer label. + */ + if (is_offline) + vdev->v_state = VDEV_STATE_OFFLINE; + else if (is_removed) + vdev->v_state = VDEV_STATE_REMOVED; + else if (is_faulted) + vdev->v_state = VDEV_STATE_FAULTED; + else if (is_degraded) + vdev->v_state = VDEV_STATE_DEGRADED; + else if (isnt_present) + vdev->v_state = VDEV_STATE_CANT_OPEN; + } + + rc = nvlist_find(nvlist, ZPOOL_CONFIG_CHILDREN, DATA_TYPE_NVLIST_ARRAY, + &nkids, &kids); + /* + * Its ok if we don't have any kids. + */ + if (rc == 0) { + vdev->v_nchildren = nkids; + for (i = 0; i < nkids; i++) { + rc = vdev_init_from_nvlist(kids, vdev, &kid, is_newer); + if (rc) + return (rc); + if (is_new) + STAILQ_INSERT_TAIL(&vdev->v_children, kid, + v_childlink); + kids = nvlist_next(kids); + } + } else { + vdev->v_nchildren = 0; + } + + if (vdevp) + *vdevp = vdev; + return (0); +} + +static void +vdev_set_state(vdev_t *vdev) +{ + vdev_t *kid; + int good_kids; + int bad_kids; + + /* + * A mirror or raidz is healthy if all its kids are healthy. A + * mirror is degraded if any of its kids is healthy; a raidz + * is degraded if at most nparity kids are offline. + */ + if (STAILQ_FIRST(&vdev->v_children)) { + good_kids = 0; + bad_kids = 0; + STAILQ_FOREACH(kid, &vdev->v_children, v_childlink) { + if (kid->v_state == VDEV_STATE_HEALTHY) + good_kids++; + else + bad_kids++; + } + if (bad_kids == 0) { + vdev->v_state = VDEV_STATE_HEALTHY; + } else { + if (vdev->v_read == vdev_mirror_read) { + if (good_kids) { + vdev->v_state = VDEV_STATE_DEGRADED; + } else { + vdev->v_state = VDEV_STATE_OFFLINE; + } + } else if (vdev->v_read == vdev_raidz_read) { + if (bad_kids > vdev->v_nparity) { + vdev->v_state = VDEV_STATE_OFFLINE; + } else { + vdev->v_state = VDEV_STATE_DEGRADED; + } + } + } + } +} + +static spa_t * +spa_find_by_guid(uint64_t guid) +{ + spa_t *spa; + + STAILQ_FOREACH(spa, &zfs_pools, spa_link) + if (spa->spa_guid == guid) + return (spa); + + return (0); +} + +static spa_t * +spa_find_by_name(const char *name) +{ + spa_t *spa; + + STAILQ_FOREACH(spa, &zfs_pools, spa_link) + if (!strcmp(spa->spa_name, name)) + return (spa); + + return (0); +} + +#ifdef BOOT2 +static spa_t * +spa_get_primary(void) +{ + + return (STAILQ_FIRST(&zfs_pools)); +} + +static vdev_t * +spa_get_primary_vdev(const spa_t *spa) +{ + vdev_t *vdev; + vdev_t *kid; + + if (spa == NULL) + spa = spa_get_primary(); + if (spa == NULL) + return (NULL); + vdev = STAILQ_FIRST(&spa->spa_vdevs); + if (vdev == NULL) + return (NULL); + for (kid = STAILQ_FIRST(&vdev->v_children); kid != NULL; + kid = STAILQ_FIRST(&vdev->v_children)) + vdev = kid; + return (vdev); +} +#endif + +static spa_t * +spa_create(uint64_t guid, const char *name) +{ + spa_t *spa; + + if ((spa = malloc(sizeof(spa_t))) == NULL) + return (NULL); + memset(spa, 0, sizeof(spa_t)); + if ((spa->spa_name = strdup(name)) == NULL) { + free(spa); + return (NULL); + } + STAILQ_INIT(&spa->spa_vdevs); + spa->spa_guid = guid; + STAILQ_INSERT_TAIL(&zfs_pools, spa, spa_link); + + return (spa); +} + +static const char * +state_name(vdev_state_t state) +{ + static const char* names[] = { + "UNKNOWN", + "CLOSED", + "OFFLINE", + "REMOVED", + "CANT_OPEN", + "FAULTED", + "DEGRADED", + "ONLINE" + }; + return names[state]; +} + +#ifdef BOOT2 + +#define pager_printf printf + +#else + +static int +pager_printf(const char *fmt, ...) +{ + char line[80]; + va_list args; + + va_start(args, fmt); + vsprintf(line, fmt, args); + va_end(args); + + return (pager_output(line)); +} + +#endif + +#define STATUS_FORMAT " %s %s\n" + +static int +print_state(int indent, const char *name, vdev_state_t state) +{ + char buf[512]; + int i; + + buf[0] = 0; + for (i = 0; i < indent; i++) + strcat(buf, " "); + strcat(buf, name); + + return (pager_printf(STATUS_FORMAT, buf, state_name(state))); +} + +static int +vdev_status(vdev_t *vdev, int indent) +{ + vdev_t *kid; + int ret; + ret = print_state(indent, vdev->v_name, vdev->v_state); + if (ret != 0) + return (ret); + + STAILQ_FOREACH(kid, &vdev->v_children, v_childlink) { + ret = vdev_status(kid, indent + 1); + if (ret != 0) + return (ret); + } + return (ret); +} + +static int +spa_status(spa_t *spa) +{ + static char bootfs[ZFS_MAXNAMELEN]; + uint64_t rootid; + vdev_t *vdev; + int good_kids, bad_kids, degraded_kids, ret; + vdev_state_t state; + + ret = pager_printf(" pool: %s\n", spa->spa_name); + if (ret != 0) + return (ret); + + if (zfs_get_root(spa, &rootid) == 0 && + zfs_rlookup(spa, rootid, bootfs) == 0) { + if (bootfs[0] == '\0') + ret = pager_printf("bootfs: %s\n", spa->spa_name); + else + ret = pager_printf("bootfs: %s/%s\n", spa->spa_name, + bootfs); + if (ret != 0) + return (ret); + } + ret = pager_printf("config:\n\n"); + if (ret != 0) + return (ret); + ret = pager_printf(STATUS_FORMAT, "NAME", "STATE"); + if (ret != 0) + return (ret); + + good_kids = 0; + degraded_kids = 0; + bad_kids = 0; + STAILQ_FOREACH(vdev, &spa->spa_vdevs, v_childlink) { + if (vdev->v_state == VDEV_STATE_HEALTHY) + good_kids++; + else if (vdev->v_state == VDEV_STATE_DEGRADED) + degraded_kids++; + else + bad_kids++; + } + + state = VDEV_STATE_CLOSED; + if (good_kids > 0 && (degraded_kids + bad_kids) == 0) + state = VDEV_STATE_HEALTHY; + else if ((good_kids + degraded_kids) > 0) + state = VDEV_STATE_DEGRADED; + + ret = print_state(0, spa->spa_name, state); + if (ret != 0) + return (ret); + STAILQ_FOREACH(vdev, &spa->spa_vdevs, v_childlink) { + ret = vdev_status(vdev, 1); + if (ret != 0) + return (ret); + } + return (ret); +} + +static int +spa_all_status(void) +{ + spa_t *spa; + int first = 1, ret = 0; + + STAILQ_FOREACH(spa, &zfs_pools, spa_link) { + if (!first) { + ret = pager_printf("\n"); + if (ret != 0) + return (ret); + } + first = 0; + ret = spa_status(spa); + if (ret != 0) + return (ret); + } + return (ret); +} + +static uint64_t +vdev_label_offset(uint64_t psize, int l, uint64_t offset) +{ + uint64_t label_offset; + + if (l < VDEV_LABELS / 2) + label_offset = 0; + else + label_offset = psize - VDEV_LABELS * sizeof (vdev_label_t); + + return (offset + l * sizeof (vdev_label_t) + label_offset); +} + +static int +vdev_probe(vdev_phys_read_t *_read, void *read_priv, spa_t **spap) +{ + vdev_t vtmp; + vdev_phys_t *vdev_label = (vdev_phys_t *) zap_scratch; + vdev_phys_t *tmp_label; + spa_t *spa; + vdev_t *vdev, *top_vdev, *pool_vdev; + off_t off; + blkptr_t bp; + const unsigned char *nvlist = NULL; + uint64_t val; + uint64_t guid; + uint64_t best_txg = 0; + uint64_t pool_txg, pool_guid; + uint64_t psize; + const char *pool_name; + const unsigned char *vdevs; + const unsigned char *features; + int i, l, rc, is_newer; + char *upbuf; + const struct uberblock *up; + + /* + * Load the vdev label and figure out which + * uberblock is most current. + */ + memset(&vtmp, 0, sizeof(vtmp)); + vtmp.v_phys_read = _read; + vtmp.v_read_priv = read_priv; + psize = P2ALIGN(ldi_get_size(read_priv), + (uint64_t)sizeof (vdev_label_t)); + + /* Test for minimum pool size. */ + if (psize < SPA_MINDEVSIZE) + return (EIO); + + tmp_label = zfs_alloc(sizeof(vdev_phys_t)); + + for (l = 0; l < VDEV_LABELS; l++) { + off = vdev_label_offset(psize, l, + offsetof(vdev_label_t, vl_vdev_phys)); + + BP_ZERO(&bp); + BP_SET_LSIZE(&bp, sizeof(vdev_phys_t)); + BP_SET_PSIZE(&bp, sizeof(vdev_phys_t)); + BP_SET_CHECKSUM(&bp, ZIO_CHECKSUM_LABEL); + BP_SET_COMPRESS(&bp, ZIO_COMPRESS_OFF); + DVA_SET_OFFSET(BP_IDENTITY(&bp), off); + ZIO_SET_CHECKSUM(&bp.blk_cksum, off, 0, 0, 0); + + if (vdev_read_phys(&vtmp, &bp, tmp_label, off, 0)) + continue; + + if (tmp_label->vp_nvlist[0] != NV_ENCODE_XDR) + continue; + + nvlist = (const unsigned char *) tmp_label->vp_nvlist + 4; + if (nvlist_find(nvlist, ZPOOL_CONFIG_POOL_TXG, + DATA_TYPE_UINT64, NULL, &pool_txg) != 0) + continue; + + if (best_txg <= pool_txg) { + best_txg = pool_txg; + memcpy(vdev_label, tmp_label, sizeof (vdev_phys_t)); + } + } + + zfs_free(tmp_label, sizeof (vdev_phys_t)); + + if (best_txg == 0) + return (EIO); + + if (vdev_label->vp_nvlist[0] != NV_ENCODE_XDR) + return (EIO); + + nvlist = (const unsigned char *) vdev_label->vp_nvlist + 4; + + if (nvlist_find(nvlist, ZPOOL_CONFIG_VERSION, DATA_TYPE_UINT64, + NULL, &val) != 0) { + return (EIO); + } + + if (!SPA_VERSION_IS_SUPPORTED(val)) { + printf("ZFS: unsupported ZFS version %u (should be %u)\n", + (unsigned) val, (unsigned) SPA_VERSION); + return (EIO); + } + + /* Check ZFS features for read */ + if (nvlist_find(nvlist, ZPOOL_CONFIG_FEATURES_FOR_READ, + DATA_TYPE_NVLIST, NULL, &features) == 0 && + nvlist_check_features_for_read(features) != 0) { + return (EIO); + } + + if (nvlist_find(nvlist, ZPOOL_CONFIG_POOL_STATE, DATA_TYPE_UINT64, + NULL, &val) != 0) { + return (EIO); + } + + if (val == POOL_STATE_DESTROYED) { + /* We don't boot only from destroyed pools. */ + return (EIO); + } + + if (nvlist_find(nvlist, ZPOOL_CONFIG_POOL_TXG, DATA_TYPE_UINT64, + NULL, &pool_txg) != 0 || + nvlist_find(nvlist, ZPOOL_CONFIG_POOL_GUID, DATA_TYPE_UINT64, + NULL, &pool_guid) != 0 || + nvlist_find(nvlist, ZPOOL_CONFIG_POOL_NAME, DATA_TYPE_STRING, + NULL, &pool_name) != 0) { + /* + * Cache and spare devices end up here - just ignore + * them. + */ + /*printf("ZFS: can't find pool details\n");*/ + return (EIO); + } + + if (nvlist_find(nvlist, ZPOOL_CONFIG_IS_LOG, DATA_TYPE_UINT64, + NULL, &val) == 0 && val != 0) { + return (EIO); + } + + /* + * Create the pool if this is the first time we've seen it. + */ + spa = spa_find_by_guid(pool_guid); + if (spa == NULL) { + spa = spa_create(pool_guid, pool_name); + if (spa == NULL) + return (ENOMEM); + } + if (pool_txg > spa->spa_txg) { + spa->spa_txg = pool_txg; + is_newer = 1; + } else { + is_newer = 0; + } + + /* + * Get the vdev tree and create our in-core copy of it. + * If we already have a vdev with this guid, this must + * be some kind of alias (overlapping slices, dangerously dedicated + * disks etc). + */ + if (nvlist_find(nvlist, ZPOOL_CONFIG_GUID, DATA_TYPE_UINT64, + NULL, &guid) != 0) { + return (EIO); + } + vdev = vdev_find(guid); + if (vdev && vdev->v_phys_read) /* Has this vdev already been inited? */ + return (EIO); + + if (nvlist_find(nvlist, ZPOOL_CONFIG_VDEV_TREE, DATA_TYPE_NVLIST, + NULL, &vdevs)) { + return (EIO); + } + + rc = vdev_init_from_nvlist(vdevs, NULL, &top_vdev, is_newer); + if (rc != 0) + return (rc); + + /* + * Add the toplevel vdev to the pool if its not already there. + */ + STAILQ_FOREACH(pool_vdev, &spa->spa_vdevs, v_childlink) + if (top_vdev == pool_vdev) + break; + if (!pool_vdev && top_vdev) { + top_vdev->spa = spa; + STAILQ_INSERT_TAIL(&spa->spa_vdevs, top_vdev, v_childlink); + } + + /* + * We should already have created an incomplete vdev for this + * vdev. Find it and initialise it with our read proc. + */ + vdev = vdev_find(guid); + if (vdev) { + vdev->v_phys_read = _read; + vdev->v_read_priv = read_priv; + vdev->v_state = VDEV_STATE_HEALTHY; + } else { + printf("ZFS: inconsistent nvlist contents\n"); + return (EIO); + } + + /* + * Re-evaluate top-level vdev state. + */ + vdev_set_state(top_vdev); + + /* + * Ok, we are happy with the pool so far. Lets find + * the best uberblock and then we can actually access + * the contents of the pool. + */ + upbuf = zfs_alloc(VDEV_UBERBLOCK_SIZE(vdev)); + up = (const struct uberblock *)upbuf; + for (l = 0; l < VDEV_LABELS; l++) { + for (i = 0; i < VDEV_UBERBLOCK_COUNT(vdev); i++) { + off = vdev_label_offset(psize, l, + VDEV_UBERBLOCK_OFFSET(vdev, i)); + BP_ZERO(&bp); + DVA_SET_OFFSET(&bp.blk_dva[0], off); + BP_SET_LSIZE(&bp, VDEV_UBERBLOCK_SIZE(vdev)); + BP_SET_PSIZE(&bp, VDEV_UBERBLOCK_SIZE(vdev)); + BP_SET_CHECKSUM(&bp, ZIO_CHECKSUM_LABEL); + BP_SET_COMPRESS(&bp, ZIO_COMPRESS_OFF); + ZIO_SET_CHECKSUM(&bp.blk_cksum, off, 0, 0, 0); + + if (vdev_read_phys(vdev, &bp, upbuf, off, 0)) + continue; + + if (up->ub_magic != UBERBLOCK_MAGIC) + continue; + if (up->ub_txg < spa->spa_txg) + continue; + if (up->ub_txg > spa->spa_uberblock.ub_txg || + (up->ub_txg == spa->spa_uberblock.ub_txg && + up->ub_timestamp > + spa->spa_uberblock.ub_timestamp)) { + spa->spa_uberblock = *up; + } + } + } + zfs_free(upbuf, VDEV_UBERBLOCK_SIZE(vdev)); + + vdev->spa = spa; + if (spap != NULL) + *spap = spa; + return (0); +} + +static int +ilog2(int n) +{ + int v; + + for (v = 0; v < 32; v++) + if (n == (1 << v)) + return v; + return -1; +} + +static int +zio_read_gang(const spa_t *spa, const blkptr_t *bp, void *buf) +{ + blkptr_t gbh_bp; + zio_gbh_phys_t zio_gb; + char *pbuf; + int i; + + /* Artificial BP for gang block header. */ + gbh_bp = *bp; + BP_SET_PSIZE(&gbh_bp, SPA_GANGBLOCKSIZE); + BP_SET_LSIZE(&gbh_bp, SPA_GANGBLOCKSIZE); + BP_SET_CHECKSUM(&gbh_bp, ZIO_CHECKSUM_GANG_HEADER); + BP_SET_COMPRESS(&gbh_bp, ZIO_COMPRESS_OFF); + for (i = 0; i < SPA_DVAS_PER_BP; i++) + DVA_SET_GANG(&gbh_bp.blk_dva[i], 0); + + /* Read gang header block using the artificial BP. */ + if (zio_read(spa, &gbh_bp, &zio_gb)) + return (EIO); + + pbuf = buf; + for (i = 0; i < SPA_GBH_NBLKPTRS; i++) { + blkptr_t *gbp = &zio_gb.zg_blkptr[i]; + + if (BP_IS_HOLE(gbp)) + continue; + if (zio_read(spa, gbp, pbuf)) + return (EIO); + pbuf += BP_GET_PSIZE(gbp); + } + + if (zio_checksum_verify(spa, bp, buf)) + return (EIO); + return (0); +} + +static int +zio_read(const spa_t *spa, const blkptr_t *bp, void *buf) +{ + int cpfunc = BP_GET_COMPRESS(bp); + uint64_t align, size; + void *pbuf; + int i, error; + + /* + * Process data embedded in block pointer + */ + if (BP_IS_EMBEDDED(bp)) { + ASSERT(BPE_GET_ETYPE(bp) == BP_EMBEDDED_TYPE_DATA); + + size = BPE_GET_PSIZE(bp); + ASSERT(size <= BPE_PAYLOAD_SIZE); + + if (cpfunc != ZIO_COMPRESS_OFF) + pbuf = zfs_alloc(size); + else + pbuf = buf; + + decode_embedded_bp_compressed(bp, pbuf); + error = 0; + + if (cpfunc != ZIO_COMPRESS_OFF) { + error = zio_decompress_data(cpfunc, pbuf, + size, buf, BP_GET_LSIZE(bp)); + zfs_free(pbuf, size); + } + if (error != 0) + printf("ZFS: i/o error - unable to decompress block pointer data, error %d\n", + error); + return (error); + } + + error = EIO; + + for (i = 0; i < SPA_DVAS_PER_BP; i++) { + const dva_t *dva = &bp->blk_dva[i]; + vdev_t *vdev; + int vdevid; + off_t offset; + + if (!dva->dva_word[0] && !dva->dva_word[1]) + continue; + + vdevid = DVA_GET_VDEV(dva); + offset = DVA_GET_OFFSET(dva); + STAILQ_FOREACH(vdev, &spa->spa_vdevs, v_childlink) { + if (vdev->v_id == vdevid) + break; + } + if (!vdev || !vdev->v_read) + continue; + + size = BP_GET_PSIZE(bp); + if (vdev->v_read == vdev_raidz_read) { + align = 1ULL << vdev->v_top->v_ashift; + if (P2PHASE(size, align) != 0) + size = P2ROUNDUP(size, align); + } + if (size != BP_GET_PSIZE(bp) || cpfunc != ZIO_COMPRESS_OFF) + pbuf = zfs_alloc(size); + else + pbuf = buf; + + if (DVA_GET_GANG(dva)) + error = zio_read_gang(spa, bp, pbuf); + else + error = vdev->v_read(vdev, bp, pbuf, offset, size); + if (error == 0) { + if (cpfunc != ZIO_COMPRESS_OFF) + error = zio_decompress_data(cpfunc, pbuf, + BP_GET_PSIZE(bp), buf, BP_GET_LSIZE(bp)); + else if (size != BP_GET_PSIZE(bp)) + bcopy(pbuf, buf, BP_GET_PSIZE(bp)); + } + if (buf != pbuf) + zfs_free(pbuf, size); + if (error == 0) + break; + } + if (error != 0) + printf("ZFS: i/o error - all block copies unavailable\n"); + return (error); +} + +static int +dnode_read(const spa_t *spa, const dnode_phys_t *dnode, off_t offset, void *buf, size_t buflen) +{ + int ibshift = dnode->dn_indblkshift - SPA_BLKPTRSHIFT; + int bsize = dnode->dn_datablkszsec << SPA_MINBLOCKSHIFT; + int nlevels = dnode->dn_nlevels; + int i, rc; + + if (bsize > SPA_MAXBLOCKSIZE) { + printf("ZFS: I/O error - blocks larger than %llu are not " + "supported\n", SPA_MAXBLOCKSIZE); + return (EIO); + } + + /* + * Note: bsize may not be a power of two here so we need to do an + * actual divide rather than a bitshift. + */ + while (buflen > 0) { + uint64_t bn = offset / bsize; + int boff = offset % bsize; + int ibn; + const blkptr_t *indbp; + blkptr_t bp; + + if (bn > dnode->dn_maxblkid) + return (EIO); + + if (dnode == dnode_cache_obj && bn == dnode_cache_bn) + goto cached; + + indbp = dnode->dn_blkptr; + for (i = 0; i < nlevels; i++) { + /* + * Copy the bp from the indirect array so that + * we can re-use the scratch buffer for multi-level + * objects. + */ + ibn = bn >> ((nlevels - i - 1) * ibshift); + ibn &= ((1 << ibshift) - 1); + bp = indbp[ibn]; + if (BP_IS_HOLE(&bp)) { + memset(dnode_cache_buf, 0, bsize); + break; + } + rc = zio_read(spa, &bp, dnode_cache_buf); + if (rc) + return (rc); + indbp = (const blkptr_t *) dnode_cache_buf; + } + dnode_cache_obj = dnode; + dnode_cache_bn = bn; + cached: + + /* + * The buffer contains our data block. Copy what we + * need from it and loop. + */ + i = bsize - boff; + if (i > buflen) i = buflen; + memcpy(buf, &dnode_cache_buf[boff], i); + buf = ((char*) buf) + i; + offset += i; + buflen -= i; + } + + return (0); +} + +/* + * Lookup a value in a microzap directory. Assumes that the zap + * scratch buffer contains the directory contents. + */ +static int +mzap_lookup(const dnode_phys_t *dnode, const char *name, uint64_t *value) +{ + const mzap_phys_t *mz; + const mzap_ent_phys_t *mze; + size_t size; + int chunks, i; + + /* + * Microzap objects use exactly one block. Read the whole + * thing. + */ + size = dnode->dn_datablkszsec * 512; + + mz = (const mzap_phys_t *) zap_scratch; + chunks = size / MZAP_ENT_LEN - 1; + + for (i = 0; i < chunks; i++) { + mze = &mz->mz_chunk[i]; + if (!strcmp(mze->mze_name, name)) { + *value = mze->mze_value; + return (0); + } + } + + return (ENOENT); +} + +/* + * Compare a name with a zap leaf entry. Return non-zero if the name + * matches. + */ +static int +fzap_name_equal(const zap_leaf_t *zl, const zap_leaf_chunk_t *zc, const char *name) +{ + size_t namelen; + const zap_leaf_chunk_t *nc; + const char *p; + + namelen = zc->l_entry.le_name_numints; + + nc = &ZAP_LEAF_CHUNK(zl, zc->l_entry.le_name_chunk); + p = name; + while (namelen > 0) { + size_t len; + len = namelen; + if (len > ZAP_LEAF_ARRAY_BYTES) + len = ZAP_LEAF_ARRAY_BYTES; + if (memcmp(p, nc->l_array.la_array, len)) + return (0); + p += len; + namelen -= len; + nc = &ZAP_LEAF_CHUNK(zl, nc->l_array.la_next); + } + + return 1; +} + +/* + * Extract a uint64_t value from a zap leaf entry. + */ +static uint64_t +fzap_leaf_value(const zap_leaf_t *zl, const zap_leaf_chunk_t *zc) +{ + const zap_leaf_chunk_t *vc; + int i; + uint64_t value; + const uint8_t *p; + + vc = &ZAP_LEAF_CHUNK(zl, zc->l_entry.le_value_chunk); + for (i = 0, value = 0, p = vc->l_array.la_array; i < 8; i++) { + value = (value << 8) | p[i]; + } + + return value; +} + +static void +stv(int len, void *addr, uint64_t value) +{ + switch (len) { + case 1: + *(uint8_t *)addr = value; + return; + case 2: + *(uint16_t *)addr = value; + return; + case 4: + *(uint32_t *)addr = value; + return; + case 8: + *(uint64_t *)addr = value; + return; + } +} + +/* + * Extract a array from a zap leaf entry. + */ +static void +fzap_leaf_array(const zap_leaf_t *zl, const zap_leaf_chunk_t *zc, + uint64_t integer_size, uint64_t num_integers, void *buf) +{ + uint64_t array_int_len = zc->l_entry.le_value_intlen; + uint64_t value = 0; + uint64_t *u64 = buf; + char *p = buf; + int len = MIN(zc->l_entry.le_value_numints, num_integers); + int chunk = zc->l_entry.le_value_chunk; + int byten = 0; + + if (integer_size == 8 && len == 1) { + *u64 = fzap_leaf_value(zl, zc); + return; + } + + while (len > 0) { + struct zap_leaf_array *la = &ZAP_LEAF_CHUNK(zl, chunk).l_array; + int i; + + ASSERT3U(chunk, <, ZAP_LEAF_NUMCHUNKS(zl)); + for (i = 0; i < ZAP_LEAF_ARRAY_BYTES && len > 0; i++) { + value = (value << 8) | la->la_array[i]; + byten++; + if (byten == array_int_len) { + stv(integer_size, p, value); + byten = 0; + len--; + if (len == 0) + return; + p += integer_size; + } + } + chunk = la->la_next; + } +} + +/* + * Lookup a value in a fatzap directory. Assumes that the zap scratch + * buffer contains the directory header. + */ +static int +fzap_lookup(const spa_t *spa, const dnode_phys_t *dnode, const char *name, + uint64_t integer_size, uint64_t num_integers, void *value) +{ + int bsize = dnode->dn_datablkszsec << SPA_MINBLOCKSHIFT; + zap_phys_t zh = *(zap_phys_t *) zap_scratch; + fat_zap_t z; + uint64_t *ptrtbl; + uint64_t hash; + int rc; + + if (zh.zap_magic != ZAP_MAGIC) + return (EIO); + + z.zap_block_shift = ilog2(bsize); + z.zap_phys = (zap_phys_t *) zap_scratch; + + /* + * Figure out where the pointer table is and read it in if necessary. + */ + if (zh.zap_ptrtbl.zt_blk) { + rc = dnode_read(spa, dnode, zh.zap_ptrtbl.zt_blk * bsize, + zap_scratch, bsize); + if (rc) + return (rc); + ptrtbl = (uint64_t *) zap_scratch; + } else { + ptrtbl = &ZAP_EMBEDDED_PTRTBL_ENT(&z, 0); + } + + hash = zap_hash(zh.zap_salt, name); + + zap_leaf_t zl; + zl.l_bs = z.zap_block_shift; + + off_t off = ptrtbl[hash >> (64 - zh.zap_ptrtbl.zt_shift)] << zl.l_bs; + zap_leaf_chunk_t *zc; + + rc = dnode_read(spa, dnode, off, zap_scratch, bsize); + if (rc) + return (rc); + + zl.l_phys = (zap_leaf_phys_t *) zap_scratch; + + /* + * Make sure this chunk matches our hash. + */ + if (zl.l_phys->l_hdr.lh_prefix_len > 0 + && zl.l_phys->l_hdr.lh_prefix + != hash >> (64 - zl.l_phys->l_hdr.lh_prefix_len)) + return (ENOENT); + + /* + * Hash within the chunk to find our entry. + */ + int shift = (64 - ZAP_LEAF_HASH_SHIFT(&zl) - zl.l_phys->l_hdr.lh_prefix_len); + int h = (hash >> shift) & ((1 << ZAP_LEAF_HASH_SHIFT(&zl)) - 1); + h = zl.l_phys->l_hash[h]; + if (h == 0xffff) + return (ENOENT); + zc = &ZAP_LEAF_CHUNK(&zl, h); + while (zc->l_entry.le_hash != hash) { + if (zc->l_entry.le_next == 0xffff) { + zc = NULL; + break; + } + zc = &ZAP_LEAF_CHUNK(&zl, zc->l_entry.le_next); + } + if (fzap_name_equal(&zl, zc, name)) { + if (zc->l_entry.le_value_intlen * zc->l_entry.le_value_numints > + integer_size * num_integers) + return (E2BIG); + fzap_leaf_array(&zl, zc, integer_size, num_integers, value); + return (0); + } + + return (ENOENT); +} + +/* + * Lookup a name in a zap object and return its value as a uint64_t. + */ +static int +zap_lookup(const spa_t *spa, const dnode_phys_t *dnode, const char *name, + uint64_t integer_size, uint64_t num_integers, void *value) +{ + int rc; + uint64_t zap_type; + size_t size = dnode->dn_datablkszsec << SPA_MINBLOCKSHIFT; + + rc = dnode_read(spa, dnode, 0, zap_scratch, size); + if (rc) + return (rc); + + zap_type = *(uint64_t *) zap_scratch; + if (zap_type == ZBT_MICRO) + return mzap_lookup(dnode, name, value); + else if (zap_type == ZBT_HEADER) { + return fzap_lookup(spa, dnode, name, integer_size, + num_integers, value); + } + printf("ZFS: invalid zap_type=%d\n", (int)zap_type); + return (EIO); +} + +/* + * List a microzap directory. Assumes that the zap scratch buffer contains + * the directory contents. + */ +static int +mzap_list(const dnode_phys_t *dnode, int (*callback)(const char *, uint64_t)) +{ + const mzap_phys_t *mz; + const mzap_ent_phys_t *mze; + size_t size; + int chunks, i, rc; + + /* + * Microzap objects use exactly one block. Read the whole + * thing. + */ + size = dnode->dn_datablkszsec * 512; + mz = (const mzap_phys_t *) zap_scratch; + chunks = size / MZAP_ENT_LEN - 1; + + for (i = 0; i < chunks; i++) { + mze = &mz->mz_chunk[i]; + if (mze->mze_name[0]) { + rc = callback(mze->mze_name, mze->mze_value); + if (rc != 0) + return (rc); + } + } + + return (0); +} + +/* + * List a fatzap directory. Assumes that the zap scratch buffer contains + * the directory header. + */ +static int +fzap_list(const spa_t *spa, const dnode_phys_t *dnode, int (*callback)(const char *, uint64_t)) +{ + int bsize = dnode->dn_datablkszsec << SPA_MINBLOCKSHIFT; + zap_phys_t zh = *(zap_phys_t *) zap_scratch; + fat_zap_t z; + int i, j, rc; + + if (zh.zap_magic != ZAP_MAGIC) + return (EIO); + + z.zap_block_shift = ilog2(bsize); + z.zap_phys = (zap_phys_t *) zap_scratch; + + /* + * This assumes that the leaf blocks start at block 1. The + * documentation isn't exactly clear on this. + */ + zap_leaf_t zl; + zl.l_bs = z.zap_block_shift; + for (i = 0; i < zh.zap_num_leafs; i++) { + off_t off = (i + 1) << zl.l_bs; + char name[256], *p; + uint64_t value; + + if (dnode_read(spa, dnode, off, zap_scratch, bsize)) + return (EIO); + + zl.l_phys = (zap_leaf_phys_t *) zap_scratch; + + for (j = 0; j < ZAP_LEAF_NUMCHUNKS(&zl); j++) { + zap_leaf_chunk_t *zc, *nc; + int namelen; + + zc = &ZAP_LEAF_CHUNK(&zl, j); + if (zc->l_entry.le_type != ZAP_CHUNK_ENTRY) + continue; + namelen = zc->l_entry.le_name_numints; + if (namelen > sizeof(name)) + namelen = sizeof(name); + + /* + * Paste the name back together. + */ + nc = &ZAP_LEAF_CHUNK(&zl, zc->l_entry.le_name_chunk); + p = name; + while (namelen > 0) { + int len; + len = namelen; + if (len > ZAP_LEAF_ARRAY_BYTES) + len = ZAP_LEAF_ARRAY_BYTES; + memcpy(p, nc->l_array.la_array, len); + p += len; + namelen -= len; + nc = &ZAP_LEAF_CHUNK(&zl, nc->l_array.la_next); + } + + /* + * Assume the first eight bytes of the value are + * a uint64_t. + */ + value = fzap_leaf_value(&zl, zc); + + //printf("%s 0x%jx\n", name, (uintmax_t)value); + rc = callback((const char *)name, value); + if (rc != 0) + return (rc); + } + } + + return (0); +} + +static int zfs_printf(const char *name, uint64_t value __unused) +{ + + printf("%s\n", name); + + return (0); +} + +/* + * List a zap directory. + */ +static int +zap_list(const spa_t *spa, const dnode_phys_t *dnode) +{ + uint64_t zap_type; + size_t size = dnode->dn_datablkszsec * 512; + + if (dnode_read(spa, dnode, 0, zap_scratch, size)) + return (EIO); + + zap_type = *(uint64_t *) zap_scratch; + if (zap_type == ZBT_MICRO) + return mzap_list(dnode, zfs_printf); + else + return fzap_list(spa, dnode, zfs_printf); +} + +static int +objset_get_dnode(const spa_t *spa, const objset_phys_t *os, uint64_t objnum, dnode_phys_t *dnode) +{ + off_t offset; + + offset = objnum * sizeof(dnode_phys_t); + return dnode_read(spa, &os->os_meta_dnode, offset, + dnode, sizeof(dnode_phys_t)); +} + +static int +mzap_rlookup(const spa_t *spa, const dnode_phys_t *dnode, char *name, uint64_t value) +{ + const mzap_phys_t *mz; + const mzap_ent_phys_t *mze; + size_t size; + int chunks, i; + + /* + * Microzap objects use exactly one block. Read the whole + * thing. + */ + size = dnode->dn_datablkszsec * 512; + + mz = (const mzap_phys_t *) zap_scratch; + chunks = size / MZAP_ENT_LEN - 1; + + for (i = 0; i < chunks; i++) { + mze = &mz->mz_chunk[i]; + if (value == mze->mze_value) { + strcpy(name, mze->mze_name); + return (0); + } + } + + return (ENOENT); +} + +static void +fzap_name_copy(const zap_leaf_t *zl, const zap_leaf_chunk_t *zc, char *name) +{ + size_t namelen; + const zap_leaf_chunk_t *nc; + char *p; + + namelen = zc->l_entry.le_name_numints; + + nc = &ZAP_LEAF_CHUNK(zl, zc->l_entry.le_name_chunk); + p = name; + while (namelen > 0) { + size_t len; + len = namelen; + if (len > ZAP_LEAF_ARRAY_BYTES) + len = ZAP_LEAF_ARRAY_BYTES; + memcpy(p, nc->l_array.la_array, len); + p += len; + namelen -= len; + nc = &ZAP_LEAF_CHUNK(zl, nc->l_array.la_next); + } + + *p = '\0'; +} + +static int +fzap_rlookup(const spa_t *spa, const dnode_phys_t *dnode, char *name, uint64_t value) +{ + int bsize = dnode->dn_datablkszsec << SPA_MINBLOCKSHIFT; + zap_phys_t zh = *(zap_phys_t *) zap_scratch; + fat_zap_t z; + int i, j; + + if (zh.zap_magic != ZAP_MAGIC) + return (EIO); + + z.zap_block_shift = ilog2(bsize); + z.zap_phys = (zap_phys_t *) zap_scratch; + + /* + * This assumes that the leaf blocks start at block 1. The + * documentation isn't exactly clear on this. + */ + zap_leaf_t zl; + zl.l_bs = z.zap_block_shift; + for (i = 0; i < zh.zap_num_leafs; i++) { + off_t off = (i + 1) << zl.l_bs; + + if (dnode_read(spa, dnode, off, zap_scratch, bsize)) + return (EIO); + + zl.l_phys = (zap_leaf_phys_t *) zap_scratch; + + for (j = 0; j < ZAP_LEAF_NUMCHUNKS(&zl); j++) { + zap_leaf_chunk_t *zc; + + zc = &ZAP_LEAF_CHUNK(&zl, j); + if (zc->l_entry.le_type != ZAP_CHUNK_ENTRY) + continue; + if (zc->l_entry.le_value_intlen != 8 || + zc->l_entry.le_value_numints != 1) + continue; + + if (fzap_leaf_value(&zl, zc) == value) { + fzap_name_copy(&zl, zc, name); + return (0); + } + } + } + + return (ENOENT); +} + +static int +zap_rlookup(const spa_t *spa, const dnode_phys_t *dnode, char *name, uint64_t value) +{ + int rc; + uint64_t zap_type; + size_t size = dnode->dn_datablkszsec * 512; + + rc = dnode_read(spa, dnode, 0, zap_scratch, size); + if (rc) + return (rc); + + zap_type = *(uint64_t *) zap_scratch; + if (zap_type == ZBT_MICRO) + return mzap_rlookup(spa, dnode, name, value); + else + return fzap_rlookup(spa, dnode, name, value); +} + +static int +zfs_rlookup(const spa_t *spa, uint64_t objnum, char *result) +{ + char name[256]; + char component[256]; + uint64_t dir_obj, parent_obj, child_dir_zapobj; + dnode_phys_t child_dir_zap, dataset, dir, parent; + dsl_dir_phys_t *dd; + dsl_dataset_phys_t *ds; + char *p; + int len; + + p = &name[sizeof(name) - 1]; + *p = '\0'; + + if (objset_get_dnode(spa, &spa->spa_mos, objnum, &dataset)) { + printf("ZFS: can't find dataset %ju\n", (uintmax_t)objnum); + return (EIO); + } + ds = (dsl_dataset_phys_t *)&dataset.dn_bonus; + dir_obj = ds->ds_dir_obj; + + for (;;) { + if (objset_get_dnode(spa, &spa->spa_mos, dir_obj, &dir) != 0) + return (EIO); + dd = (dsl_dir_phys_t *)&dir.dn_bonus; + + /* Actual loop condition. */ + parent_obj = dd->dd_parent_obj; + if (parent_obj == 0) + break; + + if (objset_get_dnode(spa, &spa->spa_mos, parent_obj, &parent) != 0) + return (EIO); + dd = (dsl_dir_phys_t *)&parent.dn_bonus; + child_dir_zapobj = dd->dd_child_dir_zapobj; + if (objset_get_dnode(spa, &spa->spa_mos, child_dir_zapobj, &child_dir_zap) != 0) + return (EIO); + if (zap_rlookup(spa, &child_dir_zap, component, dir_obj) != 0) + return (EIO); + + len = strlen(component); + p -= len; + memcpy(p, component, len); + --p; + *p = '/'; + + /* Actual loop iteration. */ + dir_obj = parent_obj; + } + + if (*p != '\0') + ++p; + strcpy(result, p); + + return (0); +} + +static int +zfs_lookup_dataset(const spa_t *spa, const char *name, uint64_t *objnum) +{ + char element[256]; + uint64_t dir_obj, child_dir_zapobj; + dnode_phys_t child_dir_zap, dir; + dsl_dir_phys_t *dd; + const char *p, *q; + + if (objset_get_dnode(spa, &spa->spa_mos, DMU_POOL_DIRECTORY_OBJECT, &dir)) + return (EIO); + if (zap_lookup(spa, &dir, DMU_POOL_ROOT_DATASET, sizeof (dir_obj), + 1, &dir_obj)) + return (EIO); + + p = name; + for (;;) { + if (objset_get_dnode(spa, &spa->spa_mos, dir_obj, &dir)) + return (EIO); + dd = (dsl_dir_phys_t *)&dir.dn_bonus; + + while (*p == '/') + p++; + /* Actual loop condition #1. */ + if (*p == '\0') + break; + + q = strchr(p, '/'); + if (q) { + memcpy(element, p, q - p); + element[q - p] = '\0'; + p = q + 1; + } else { + strcpy(element, p); + p += strlen(p); + } + + child_dir_zapobj = dd->dd_child_dir_zapobj; + if (objset_get_dnode(spa, &spa->spa_mos, child_dir_zapobj, &child_dir_zap) != 0) + return (EIO); + + /* Actual loop condition #2. */ + if (zap_lookup(spa, &child_dir_zap, element, sizeof (dir_obj), + 1, &dir_obj) != 0) + return (ENOENT); + } + + *objnum = dd->dd_head_dataset_obj; + return (0); +} + +#ifndef BOOT2 +static int +zfs_list_dataset(const spa_t *spa, uint64_t objnum/*, int pos, char *entry*/) +{ + uint64_t dir_obj, child_dir_zapobj; + dnode_phys_t child_dir_zap, dir, dataset; + dsl_dataset_phys_t *ds; + dsl_dir_phys_t *dd; + + if (objset_get_dnode(spa, &spa->spa_mos, objnum, &dataset)) { + printf("ZFS: can't find dataset %ju\n", (uintmax_t)objnum); + return (EIO); + } + ds = (dsl_dataset_phys_t *) &dataset.dn_bonus; + dir_obj = ds->ds_dir_obj; + + if (objset_get_dnode(spa, &spa->spa_mos, dir_obj, &dir)) { + printf("ZFS: can't find dirobj %ju\n", (uintmax_t)dir_obj); + return (EIO); + } + dd = (dsl_dir_phys_t *)&dir.dn_bonus; + + child_dir_zapobj = dd->dd_child_dir_zapobj; + if (objset_get_dnode(spa, &spa->spa_mos, child_dir_zapobj, &child_dir_zap) != 0) { + printf("ZFS: can't find child zap %ju\n", (uintmax_t)dir_obj); + return (EIO); + } + + return (zap_list(spa, &child_dir_zap) != 0); +} + +int +zfs_callback_dataset(const spa_t *spa, uint64_t objnum, int (*callback)(const char *, uint64_t)) +{ + uint64_t dir_obj, child_dir_zapobj, zap_type; + dnode_phys_t child_dir_zap, dir, dataset; + dsl_dataset_phys_t *ds; + dsl_dir_phys_t *dd; + int err; + + err = objset_get_dnode(spa, &spa->spa_mos, objnum, &dataset); + if (err != 0) { + printf("ZFS: can't find dataset %ju\n", (uintmax_t)objnum); + return (err); + } + ds = (dsl_dataset_phys_t *) &dataset.dn_bonus; + dir_obj = ds->ds_dir_obj; + + err = objset_get_dnode(spa, &spa->spa_mos, dir_obj, &dir); + if (err != 0) { + printf("ZFS: can't find dirobj %ju\n", (uintmax_t)dir_obj); + return (err); + } + dd = (dsl_dir_phys_t *)&dir.dn_bonus; + + child_dir_zapobj = dd->dd_child_dir_zapobj; + err = objset_get_dnode(spa, &spa->spa_mos, child_dir_zapobj, &child_dir_zap); + if (err != 0) { + printf("ZFS: can't find child zap %ju\n", (uintmax_t)dir_obj); + return (err); + } + + err = dnode_read(spa, &child_dir_zap, 0, zap_scratch, child_dir_zap.dn_datablkszsec * 512); + if (err != 0) + return (err); + + zap_type = *(uint64_t *) zap_scratch; + if (zap_type == ZBT_MICRO) + return mzap_list(&child_dir_zap, callback); + else + return fzap_list(spa, &child_dir_zap, callback); +} +#endif + +/* + * Find the object set given the object number of its dataset object + * and return its details in *objset + */ +static int +zfs_mount_dataset(const spa_t *spa, uint64_t objnum, objset_phys_t *objset) +{ + dnode_phys_t dataset; + dsl_dataset_phys_t *ds; + + if (objset_get_dnode(spa, &spa->spa_mos, objnum, &dataset)) { + printf("ZFS: can't find dataset %ju\n", (uintmax_t)objnum); + return (EIO); + } + + ds = (dsl_dataset_phys_t *) &dataset.dn_bonus; + if (zio_read(spa, &ds->ds_bp, objset)) { + printf("ZFS: can't read object set for dataset %ju\n", + (uintmax_t)objnum); + return (EIO); + } + + return (0); +} + +/* + * Find the object set pointed to by the BOOTFS property or the root + * dataset if there is none and return its details in *objset + */ +static int +zfs_get_root(const spa_t *spa, uint64_t *objid) +{ + dnode_phys_t dir, propdir; + uint64_t props, bootfs, root; + + *objid = 0; + + /* + * Start with the MOS directory object. + */ + if (objset_get_dnode(spa, &spa->spa_mos, DMU_POOL_DIRECTORY_OBJECT, &dir)) { + printf("ZFS: can't read MOS object directory\n"); + return (EIO); + } + + /* + * Lookup the pool_props and see if we can find a bootfs. + */ + if (zap_lookup(spa, &dir, DMU_POOL_PROPS, sizeof (props), 1, &props) == 0 + && objset_get_dnode(spa, &spa->spa_mos, props, &propdir) == 0 + && zap_lookup(spa, &propdir, "bootfs", sizeof (bootfs), 1, &bootfs) == 0 + && bootfs != 0) + { + *objid = bootfs; + return (0); + } + /* + * Lookup the root dataset directory + */ + if (zap_lookup(spa, &dir, DMU_POOL_ROOT_DATASET, sizeof (root), 1, &root) + || objset_get_dnode(spa, &spa->spa_mos, root, &dir)) { + printf("ZFS: can't find root dsl_dir\n"); + return (EIO); + } + + /* + * Use the information from the dataset directory's bonus buffer + * to find the dataset object and from that the object set itself. + */ + dsl_dir_phys_t *dd = (dsl_dir_phys_t *) &dir.dn_bonus; + *objid = dd->dd_head_dataset_obj; + return (0); +} + +static int +zfs_mount(const spa_t *spa, uint64_t rootobj, struct zfsmount *mount) +{ + + mount->spa = spa; + + /* + * Find the root object set if not explicitly provided + */ + if (rootobj == 0 && zfs_get_root(spa, &rootobj)) { + printf("ZFS: can't find root filesystem\n"); + return (EIO); + } + + if (zfs_mount_dataset(spa, rootobj, &mount->objset)) { + printf("ZFS: can't open root filesystem\n"); + return (EIO); + } + + mount->rootobj = rootobj; + + return (0); +} + +/* + * callback function for feature name checks. + */ +static int +check_feature(const char *name, uint64_t value) +{ + int i; + + if (value == 0) + return (0); + if (name[0] == '\0') + return (0); + + for (i = 0; features_for_read[i] != NULL; i++) { + if (strcmp(name, features_for_read[i]) == 0) + return (0); + } + printf("ZFS: unsupported feature: %s\n", name); + return (EIO); +} + +/* + * Checks whether the MOS features that are active are supported. + */ +static int +check_mos_features(const spa_t *spa) +{ + dnode_phys_t dir; + uint64_t objnum, zap_type; + size_t size; + int rc; + + if ((rc = objset_get_dnode(spa, &spa->spa_mos, DMU_OT_OBJECT_DIRECTORY, + &dir)) != 0) + return (rc); + if ((rc = zap_lookup(spa, &dir, DMU_POOL_FEATURES_FOR_READ, + sizeof (objnum), 1, &objnum)) != 0) { + /* + * It is older pool without features. As we have already + * tested the label, just return without raising the error. + */ + return (0); + } + + if ((rc = objset_get_dnode(spa, &spa->spa_mos, objnum, &dir)) != 0) + return (rc); + + if (dir.dn_type != DMU_OTN_ZAP_METADATA) + return (EIO); + + size = dir.dn_datablkszsec * 512; + if (dnode_read(spa, &dir, 0, zap_scratch, size)) + return (EIO); + + zap_type = *(uint64_t *) zap_scratch; + if (zap_type == ZBT_MICRO) + rc = mzap_list(&dir, check_feature); + else + rc = fzap_list(spa, &dir, check_feature); + + return (rc); +} + +static int +zfs_spa_init(spa_t *spa) +{ + dnode_phys_t dir; + int rc; + + if (zio_read(spa, &spa->spa_uberblock.ub_rootbp, &spa->spa_mos)) { + printf("ZFS: can't read MOS of pool %s\n", spa->spa_name); + return (EIO); + } + if (spa->spa_mos.os_type != DMU_OST_META) { + printf("ZFS: corrupted MOS of pool %s\n", spa->spa_name); + return (EIO); + } + + if (objset_get_dnode(spa, &spa->spa_mos, DMU_POOL_DIRECTORY_OBJECT, + &dir)) { + printf("ZFS: failed to read pool %s directory object\n", + spa->spa_name); + return (EIO); + } + /* this is allowed to fail, older pools do not have salt */ + rc = zap_lookup(spa, &dir, DMU_POOL_CHECKSUM_SALT, 1, + sizeof (spa->spa_cksum_salt.zcs_bytes), + spa->spa_cksum_salt.zcs_bytes); + + rc = check_mos_features(spa); + if (rc != 0) { + printf("ZFS: pool %s is not supported\n", spa->spa_name); + } + + return (rc); +} + +static int +zfs_dnode_stat(const spa_t *spa, dnode_phys_t *dn, struct stat *sb) +{ + + if (dn->dn_bonustype != DMU_OT_SA) { + znode_phys_t *zp = (znode_phys_t *)dn->dn_bonus; + + sb->st_mode = zp->zp_mode; + sb->st_uid = zp->zp_uid; + sb->st_gid = zp->zp_gid; + sb->st_size = zp->zp_size; + } else { + sa_hdr_phys_t *sahdrp; + int hdrsize; + size_t size = 0; + void *buf = NULL; + + if (dn->dn_bonuslen != 0) + sahdrp = (sa_hdr_phys_t *)DN_BONUS(dn); + else { + if ((dn->dn_flags & DNODE_FLAG_SPILL_BLKPTR) != 0) { + blkptr_t *bp = DN_SPILL_BLKPTR(dn); + int error; + + size = BP_GET_LSIZE(bp); + buf = zfs_alloc(size); + error = zio_read(spa, bp, buf); + if (error != 0) { + zfs_free(buf, size); + return (error); + } + sahdrp = buf; + } else { + return (EIO); + } + } + hdrsize = SA_HDR_SIZE(sahdrp); + sb->st_mode = *(uint64_t *)((char *)sahdrp + hdrsize + + SA_MODE_OFFSET); + sb->st_uid = *(uint64_t *)((char *)sahdrp + hdrsize + + SA_UID_OFFSET); + sb->st_gid = *(uint64_t *)((char *)sahdrp + hdrsize + + SA_GID_OFFSET); + sb->st_size = *(uint64_t *)((char *)sahdrp + hdrsize + + SA_SIZE_OFFSET); + if (buf != NULL) + zfs_free(buf, size); + } + + return (0); +} + +static int +zfs_dnode_readlink(const spa_t *spa, dnode_phys_t *dn, char *path, size_t psize) +{ + int rc = 0; + + if (dn->dn_bonustype == DMU_OT_SA) { + sa_hdr_phys_t *sahdrp = NULL; + size_t size = 0; + void *buf = NULL; + int hdrsize; + char *p; + + if (dn->dn_bonuslen != 0) + sahdrp = (sa_hdr_phys_t *)DN_BONUS(dn); + else { + blkptr_t *bp; + + if ((dn->dn_flags & DNODE_FLAG_SPILL_BLKPTR) == 0) + return (EIO); + bp = DN_SPILL_BLKPTR(dn); + + size = BP_GET_LSIZE(bp); + buf = zfs_alloc(size); + rc = zio_read(spa, bp, buf); + if (rc != 0) { + zfs_free(buf, size); + return (rc); + } + sahdrp = buf; + } + hdrsize = SA_HDR_SIZE(sahdrp); + p = (char *)((uintptr_t)sahdrp + hdrsize + SA_SYMLINK_OFFSET); + memcpy(path, p, psize); + if (buf != NULL) + zfs_free(buf, size); + return (0); + } + /* + * Second test is purely to silence bogus compiler + * warning about accessing past the end of dn_bonus. + */ + if (psize + sizeof(znode_phys_t) <= dn->dn_bonuslen && + sizeof(znode_phys_t) <= sizeof(dn->dn_bonus)) { + memcpy(path, &dn->dn_bonus[sizeof(znode_phys_t)], psize); + } else { + rc = dnode_read(spa, dn, 0, path, psize); + } + return (rc); +} + +struct obj_list { + uint64_t objnum; + STAILQ_ENTRY(obj_list) entry; +}; + +/* + * Lookup a file and return its dnode. + */ +static int +zfs_lookup(const struct zfsmount *mount, const char *upath, dnode_phys_t *dnode) +{ + int rc; + uint64_t objnum; + const spa_t *spa; + dnode_phys_t dn; + const char *p, *q; + char element[256]; + char path[1024]; + int symlinks_followed = 0; + struct stat sb; + struct obj_list *entry, *tentry; + STAILQ_HEAD(, obj_list) on_cache = STAILQ_HEAD_INITIALIZER(on_cache); + + spa = mount->spa; + if (mount->objset.os_type != DMU_OST_ZFS) { + printf("ZFS: unexpected object set type %ju\n", + (uintmax_t)mount->objset.os_type); + return (EIO); + } + + if ((entry = malloc(sizeof(struct obj_list))) == NULL) + return (ENOMEM); + + /* + * Get the root directory dnode. + */ + rc = objset_get_dnode(spa, &mount->objset, MASTER_NODE_OBJ, &dn); + if (rc) { + free(entry); + return (rc); + } + + rc = zap_lookup(spa, &dn, ZFS_ROOT_OBJ, sizeof (objnum), 1, &objnum); + if (rc) { + free(entry); + return (rc); + } + entry->objnum = objnum; + STAILQ_INSERT_HEAD(&on_cache, entry, entry); + + rc = objset_get_dnode(spa, &mount->objset, objnum, &dn); + if (rc != 0) + goto done; + + p = upath; + while (p && *p) { + rc = objset_get_dnode(spa, &mount->objset, objnum, &dn); + if (rc != 0) + goto done; + + while (*p == '/') + p++; + if (*p == '\0') + break; + q = p; + while (*q != '\0' && *q != '/') + q++; + + /* skip dot */ + if (p + 1 == q && p[0] == '.') { + p++; + continue; + } + /* double dot */ + if (p + 2 == q && p[0] == '.' && p[1] == '.') { + p += 2; + if (STAILQ_FIRST(&on_cache) == + STAILQ_LAST(&on_cache, obj_list, entry)) { + rc = ENOENT; + goto done; + } + entry = STAILQ_FIRST(&on_cache); + STAILQ_REMOVE_HEAD(&on_cache, entry); + free(entry); + objnum = (STAILQ_FIRST(&on_cache))->objnum; + continue; + } + if (q - p + 1 > sizeof(element)) { + rc = ENAMETOOLONG; + goto done; + } + memcpy(element, p, q - p); + element[q - p] = 0; + p = q; + + if ((rc = zfs_dnode_stat(spa, &dn, &sb)) != 0) + goto done; + if (!S_ISDIR(sb.st_mode)) { + rc = ENOTDIR; + goto done; + } + + rc = zap_lookup(spa, &dn, element, sizeof (objnum), 1, &objnum); + if (rc) + goto done; + objnum = ZFS_DIRENT_OBJ(objnum); + + if ((entry = malloc(sizeof(struct obj_list))) == NULL) { + rc = ENOMEM; + goto done; + } + entry->objnum = objnum; + STAILQ_INSERT_HEAD(&on_cache, entry, entry); + rc = objset_get_dnode(spa, &mount->objset, objnum, &dn); + if (rc) + goto done; + + /* + * Check for symlink. + */ + rc = zfs_dnode_stat(spa, &dn, &sb); + if (rc) + goto done; + if (S_ISLNK(sb.st_mode)) { + if (symlinks_followed > 10) { + rc = EMLINK; + goto done; + } + symlinks_followed++; + + /* + * Read the link value and copy the tail of our + * current path onto the end. + */ + if (sb.st_size + strlen(p) + 1 > sizeof(path)) { + rc = ENAMETOOLONG; + goto done; + } + strcpy(&path[sb.st_size], p); + + rc = zfs_dnode_readlink(spa, &dn, path, sb.st_size); + if (rc != 0) + goto done; + + /* + * Restart with the new path, starting either at + * the root or at the parent depending whether or + * not the link is relative. + */ + p = path; + if (*p == '/') { + while (STAILQ_FIRST(&on_cache) != + STAILQ_LAST(&on_cache, obj_list, entry)) { + entry = STAILQ_FIRST(&on_cache); + STAILQ_REMOVE_HEAD(&on_cache, entry); + free(entry); + } + } else { + entry = STAILQ_FIRST(&on_cache); + STAILQ_REMOVE_HEAD(&on_cache, entry); + free(entry); + } + objnum = (STAILQ_FIRST(&on_cache))->objnum; + } + } + + *dnode = dn; +done: + STAILQ_FOREACH_SAFE(entry, &on_cache, entry, tentry) + free(entry); + return (rc); +} Property changes on: stable/11/stand/libsa/zfs/zfsimpl.c ___________________________________________________________________ Added: svn:eol-style ## -0,0 +1 ## +native \ No newline at end of property Added: svn:keywords ## -0,0 +1 ## +FreeBSD=%H \ No newline at end of property Added: svn:mime-type ## -0,0 +1 ## +text/plain \ No newline at end of property Index: stable/11/stand/loader.mk =================================================================== --- stable/11/stand/loader.mk (revision 344376) +++ stable/11/stand/loader.mk (revision 344377) @@ -1,174 +1,167 @@ # $FreeBSD$ .PATH: ${LDRSRC} ${BOOTSRC}/libsa CFLAGS+=-I${LDRSRC} SRCS+= boot.c commands.c console.c devopen.c interp.c SRCS+= interp_backslash.c interp_parse.c ls.c misc.c SRCS+= module.c .if ${MACHINE} == "i386" || ${MACHINE_CPUARCH} == "amd64" SRCS+= load_elf32.c load_elf32_obj.c reloc_elf32.c SRCS+= load_elf64.c load_elf64_obj.c reloc_elf64.c .elif ${MACHINE} == "pc98" SRCS+= load_elf32.c load_elf32_obj.c reloc_elf32.c .elif ${MACHINE_CPUARCH} == "aarch64" SRCS+= load_elf64.c reloc_elf64.c .elif ${MACHINE_CPUARCH} == "arm" SRCS+= load_elf32.c reloc_elf32.c .elif ${MACHINE_CPUARCH} == "powerpc" SRCS+= load_elf32.c reloc_elf32.c SRCS+= load_elf64.c reloc_elf64.c SRCS+= metadata.c .elif ${MACHINE_CPUARCH} == "sparc64" SRCS+= load_elf64.c reloc_elf64.c SRCS+= metadata.c .elif ${MACHINE_ARCH:Mmips64*} != "" SRCS+= load_elf64.c reloc_elf64.c SRCS+= metadata.c .elif ${MACHINE} == "mips" SRCS+= load_elf32.c reloc_elf32.c SRCS+= metadata.c .endif .if ${LOADER_DISK_SUPPORT:Uyes} == "yes" SRCS+= disk.c part.c .endif .if ${LOADER_NET_SUPPORT:Uno} == "yes" SRCS+= dev_net.c .endif .if defined(HAVE_BCACHE) SRCS+= bcache.c .endif .if defined(MD_IMAGE_SIZE) CFLAGS+= -DMD_IMAGE_SIZE=${MD_IMAGE_SIZE} SRCS+= md.c .else CLEANFILES+= md.o .endif # Machine-independant ISA PnP .if defined(HAVE_ISABUS) SRCS+= isapnp.c .endif .if defined(HAVE_PNP) SRCS+= pnp.c .endif # Forth interpreter .if ${MK_FORTH} != "no" SRCS+= interp_forth.c .include "${BOOTSRC}/ficl.mk" LDR_INTERP= ${LIBFICL} LDR_INTERP32= ${LIBFICL32} .elif ${MK_LOADER_LUA} != "no" SRCS+= interp_lua.c .include "${BOOTSRC}/lua.mk" LDR_INTERP= ${LIBLUA} LDR_INTERP32= ${LIBLUA32} .else SRCS+= interp_simple.c .endif .if defined(BOOT_PROMPT_123) CFLAGS+= -DBOOT_PROMPT_123 .endif .if defined(LOADER_INSTALL_SUPPORT) SRCS+= install.c .endif # Filesystem support .if ${LOADER_CD9660_SUPPORT:Uno} == "yes" CFLAGS+= -DLOADER_CD9660_SUPPORT .endif .if ${LOADER_EXT2FS_SUPPORT:Uno} == "yes" CFLAGS+= -DLOADER_EXT2FS_SUPPORT .endif .if ${LOADER_MSDOS_SUPPORT:Uno} == "yes" CFLAGS+= -DLOADER_MSDOS_SUPPORT .endif .if ${LOADER_NANDFS_SUPPORT:U${MK_NAND}} == "yes" CFLAGS+= -DLOADER_NANDFS_SUPPORT .endif .if ${LOADER_UFS_SUPPORT:Uyes} == "yes" CFLAGS+= -DLOADER_UFS_SUPPORT .endif # Compression .if ${LOADER_GZIP_SUPPORT:Uno} == "yes" CFLAGS+= -DLOADER_GZIP_SUPPORT .endif .if ${LOADER_BZIP2_SUPPORT:Uno} == "yes" CFLAGS+= -DLOADER_BZIP2_SUPPORT .endif # Network related things .if ${LOADER_NET_SUPPORT:Uno} == "yes" CFLAGS+= -DLOADER_NET_SUPPORT .endif .if ${LOADER_NFS_SUPPORT:Uno} == "yes" CFLAGS+= -DLOADER_NFS_SUPPORT .endif .if ${LOADER_TFTP_SUPPORT:Uno} == "yes" CFLAGS+= -DLOADER_TFTP_SUPPORT .endif # Partition support .if ${LOADER_GPT_SUPPORT:Uyes} == "yes" CFLAGS+= -DLOADER_GPT_SUPPORT .endif .if ${LOADER_MBR_SUPPORT:Uyes} == "yes" CFLAGS+= -DLOADER_MBR_SUPPORT .endif .if defined(HAVE_ZFS) CFLAGS+= -DLOADER_ZFS_SUPPORT CFLAGS+= -I${ZFSSRC} CFLAGS+= -I${SYSDIR}/cddl/boot/zfs SRCS+= zfs_cmd.c -.if ${MACHINE_CPUARCH} == "amd64" && ${DO32:U0} == 1 -# Have to override to use 32-bit version of zfs library... -# kinda lame to select that there XXX -LIBZFSBOOT= ${BOOTOBJ}/zfs32/libzfsboot.a -.else -LIBZFSBOOT= ${BOOTOBJ}/zfs/libzfsboot.a -.endif .endif LIBFICL= ${BOOTOBJ}/ficl/libficl.a .if ${MACHINE} == "i386" LIBFICL32= ${LIBFICL} .else LIBFICL32= ${BOOTOBJ}/ficl32/libficl.a .endif LIBLUA= ${BOOTOBJ}/liblua/liblua.a .if ${MACHINE} == "i386" LIBLUA32= ${LIBLUA} .else LIBLUA32= ${BOOTOBJ}/liblua32/liblua.a .endif CLEANFILES+= vers.c VERSION_FILE?= ${.CURDIR}/version .if ${MK_REPRODUCIBLE_BUILD} != no REPRO_FLAG= -r .endif vers.c: ${LDRSRC}/newvers.sh ${VERSION_FILE} sh ${LDRSRC}/newvers.sh ${REPRO_FLAG} ${VERSION_FILE} \ ${NEWVERSWHAT} .if !empty(HELP_FILES) HELP_FILES+= ${LDRSRC}/help.common CLEANFILES+= loader.help FILES+= loader.help loader.help: ${HELP_FILES} cat ${HELP_FILES} | awk -f ${LDRSRC}/merge_help.awk > ${.TARGET} .endif Index: stable/11/stand/ofw/libofw/Makefile =================================================================== --- stable/11/stand/ofw/libofw/Makefile (revision 344376) +++ stable/11/stand/ofw/libofw/Makefile (revision 344377) @@ -1,21 +1,22 @@ # $FreeBSD$ .include LIB= ofw SRCS= devicename.c ofw_console.c ofw_copy.c ofw_disk.c \ ofw_memory.c ofw_module.c ofw_net.c ofw_reboot.c \ ofw_time.c openfirm.c .PATH: ${ZFSSRC} SRCS+= devicename_stubs.c +CFLAGS+= -I${ZFSSRC} # Pick up the bootstrap header for some interface items CFLAGS+= -I${LDRSRC} .ifdef(BOOT_DISK_DEBUG) # Make the disk code more talkative CFLAGS+= -DDISK_DEBUG .endif .include Index: stable/11/stand/ofw/libofw/devicename.c =================================================================== --- stable/11/stand/ofw/libofw/devicename.c (revision 344376) +++ stable/11/stand/ofw/libofw/devicename.c (revision 344377) @@ -1,146 +1,146 @@ /*- * Copyright (c) 1998 Michael Smith * All rights reserved. * * Redistribution and use in source and binary forms, with or without * modification, are permitted provided that the following conditions * are met: * 1. Redistributions of source code must retain the above copyright * notice, this list of conditions and the following disclaimer. * 2. Redistributions in binary form must reproduce the above copyright * notice, this list of conditions and the following disclaimer in the * documentation and/or other materials provided with the distribution. * * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF * SUCH DAMAGE. */ #include __FBSDID("$FreeBSD$"); #include #include "bootstrap.h" #include "libofw.h" -#include "../zfs/libzfs.h" +#include "libzfs.h" static int ofw_parsedev(struct ofw_devdesc **, const char *, const char **); /* * Point (dev) at an allocated device specifier for the device matching the * path in (devspec). If it contains an explicit device specification, * use that. If not, use the default device. */ int ofw_getdev(void **vdev, const char *devspec, const char **path) { struct ofw_devdesc **dev = (struct ofw_devdesc **)vdev; int rv; /* * If it looks like this is just a path and no * device, go with the current device. */ if ((devspec == NULL) || ((strchr(devspec, '@') == NULL) && (strchr(devspec, ':') == NULL))) { if (((rv = ofw_parsedev(dev, getenv("currdev"), NULL)) == 0) && (path != NULL)) *path = devspec; return(rv); } /* * Try to parse the device name off the beginning of the devspec */ return(ofw_parsedev(dev, devspec, path)); } /* * Point (dev) at an allocated device specifier matching the string version * at the beginning of (devspec). Return a pointer to the remaining * text in (path). */ static int ofw_parsedev(struct ofw_devdesc **dev, const char *devspec, const char **path) { struct ofw_devdesc *idev; struct devsw *dv; phandle_t handle; const char *p; const char *s; char *ep; char name[256]; char type[64]; int err; int len; int i; for (p = s = devspec; *s != '\0'; p = s) { if ((s = strchr(p + 1, '/')) == NULL) s = strchr(p, '\0'); len = s - devspec; bcopy(devspec, name, len); name[len] = '\0'; if ((handle = OF_finddevice(name)) == -1) { bcopy(name, type, len); type[len] = '\0'; } else if (OF_getprop(handle, "device_type", type, sizeof(type)) == -1) continue; for (i = 0; (dv = devsw[i]) != NULL; i++) { if (strncmp(dv->dv_name, type, strlen(dv->dv_name)) == 0) goto found; } } return(ENOENT); found: if (path != NULL) *path = s; idev = malloc(sizeof(struct ofw_devdesc)); if (idev == NULL) { printf("ofw_parsedev: malloc failed\n"); return ENOMEM; } strcpy(idev->d_path, name); idev->dd.d_dev = dv; if (dv->dv_type == DEVT_ZFS) { p = devspec + strlen(dv->dv_name); err = zfs_parsedev((struct zfs_devdesc *)idev, p, path); if (err != 0) { free(idev); return (err); } } if (dev == NULL) { free(idev); } else { *dev = idev; } return(0); } int ofw_setcurrdev(struct env_var *ev, int flags, const void *value) { struct ofw_devdesc *ncurr; int rv; if ((rv = ofw_parsedev(&ncurr, value, NULL)) != 0) return rv; free(ncurr); env_setenv(ev->ev_name, flags | EV_NOHOOK, value, NULL, NULL); return 0; } Index: stable/11/stand/pc98/libpc98/Makefile =================================================================== --- stable/11/stand/pc98/libpc98/Makefile (revision 344376) +++ stable/11/stand/pc98/libpc98/Makefile (revision 344377) @@ -1,44 +1,45 @@ # $FreeBSD$ # .include LIB= pc98 .PATH: ${BOOTSRC}/i386/libi386 SRCS= bioscd.c biosdisk.c biosmem.c biospnp.c \ biospci.c biossmap.c bootinfo.c bootinfo32.c \ comconsole.c devicename.c elf32_freebsd.c \ i386_copy.c i386_module.c nullconsole.c pc98_sys.c pxe.c pxetramp.s \ time.c vidconsole.c -.PATH: ${BOOTSRC}/zfs +.PATH: ${ZFSSRC} SRCS+= devicename_stubs.c +CFLAGS+= -I${ZFSSRC} BOOT_COMCONSOLE_PORT?= 0x238 CFLAGS+= -DCOMPORT=${BOOT_COMCONSOLE_PORT} BOOT_COMCONSOLE_SPEED?= 9600 CFLAGS+= -DCOMSPEED=${BOOT_COMCONSOLE_SPEED} .ifdef(BOOT_BIOSDISK_DEBUG) # Make the disk code more talkative CFLAGS+= -DDISK_DEBUG .endif # Include simple terminal emulation (cons25-compatible) CFLAGS+= -DTERM_EMU # XXX: make alloca() useable CFLAGS+= -Dalloca=__builtin_alloca CFLAGS+= -I${BOOTSRC}/ficl -I${BOOTSRC}/ficl/i386 \ -I${LDRSRC} -I${BOOTSRC}/common \ -I${BOOTSRC}/pc98/btx/lib \ -I${BOOTSRC}/i386/libi386 \ -I${SYSDIR} # Handle FreeBSD specific %b and %D printf format specifiers CFLAGS+= ${FORMAT_EXTENSIONS} .include Index: stable/11/stand/sparc64/loader/Makefile =================================================================== --- stable/11/stand/sparc64/loader/Makefile (revision 344376) +++ stable/11/stand/sparc64/loader/Makefile (revision 344377) @@ -1,50 +1,50 @@ # $FreeBSD$ LOADER_DISK_SUPPORT?= yes LOADER_UFS_SUPPORT?= yes LOADER_CD9660_SUPPORT?= yes LOADER_EXT2FS_SUPPORT?= no LOADER_MSDOS_SUPPORT?= no LOADER_NET_SUPPORT?= yes LOADER_NFS_SUPPORT?= yes LOADER_TFTP_SUPPORT?= yes LOADER_GZIP_SUPPORT?= yes LOADER_BZIP2_SUPPORT?= no LOADER_DEBUG?= no .include PROG?= loader NEWVERSWHAT?= "bootstrap loader" sparc64 VERSION_FILE= ${.CURDIR}/../loader/version INSTALLFLAGS= -b .if ${MK_ZFS} != "no" HAVE_ZFS= yes .endif # Architecture-specific loader code .PATH: ${BOOTSRC}/sparc64/loader SRCS= locore.S main.c vers.c .if ${LOADER_DEBUG} == "yes" CFLAGS+= -DLOADER_DEBUG .endif .if exists(${.CURDIR}/help.sparc64) HELP_FILES= ${.CURDIR}/help.sparc64 .endif # Always add MI sources .include "${BOOTSRC}/loader.mk" LDFLAGS+= -static # Open Firmware standalone support library LIBOFW= ${BOOTOBJ}/ofw/libofw/libofw.a CFLAGS+= -I${BOOTSRC}/ofw/libofw/ -DPADD= ${LDR_INTERP} ${LIBZFSBOOT} ${LIBOFW} ${LIBSA} -LDADD= ${LDR_INTERP} ${LIBZFSBOOT} ${LIBOFW} ${LIBSA} +DPADD= ${LDR_INTERP} ${LIBOFW} ${LIBSA} +LDADD= ${LDR_INTERP} ${LIBOFW} ${LIBSA} .include Index: stable/11/stand/sparc64/loader/main.c =================================================================== --- stable/11/stand/sparc64/loader/main.c (revision 344376) +++ stable/11/stand/sparc64/loader/main.c (revision 344377) @@ -1,986 +1,986 @@ /*- * Initial implementation: * Copyright (c) 2001 Robert Drehmel * All rights reserved. * * As long as the above copyright statement and this notice remain * unchanged, you can do what ever you want with this file. */ /*- * Copyright (c) 2008 - 2012 Marius Strobl * All rights reserved. * * Redistribution and use in source and binary forms, with or without * modification, are permitted provided that the following conditions * are met: * 1. Redistributions of source code must retain the above copyright * notice, this list of conditions and the following disclaimer. * 2. Redistributions in binary form must reproduce the above copyright * notice, this list of conditions and the following disclaimer in the * documentation and/or other materials provided with the distribution. * * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF * SUCH DAMAGE. */ #include __FBSDID("$FreeBSD$"); /* * FreeBSD/sparc64 kernel loader - machine dependent part * * - implements copyin and readin functions that map kernel * pages on demand. The machine independent code does not * know the size of the kernel early enough to pre-enter * TTEs and install just one 4MB mapping seemed to limiting * to me. */ #include #include #include #include #include #include #ifdef LOADER_ZFS_SUPPORT #include -#include "../zfs/libzfs.h" +#include "libzfs.h" #endif #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include "bootstrap.h" #include "libofw.h" #include "dev_net.h" enum { HEAPVA = 0x800000, HEAPSZ = 0x3000000, LOADSZ = 0x1000000 /* for kernel and modules */ }; /* At least Sun Fire V1280 require page sized allocations to be claimed. */ CTASSERT(HEAPSZ % PAGE_SIZE == 0); static struct mmu_ops { void (*tlb_init)(void); int (*mmu_mapin)(vm_offset_t va, vm_size_t len); } *mmu_ops; typedef void kernel_entry_t(vm_offset_t mdp, u_long o1, u_long o2, u_long o3, void *openfirmware); static inline u_long dtlb_get_data_sun4u(u_int, u_int); static int dtlb_enter_sun4u(u_int, u_long data, vm_offset_t); static vm_offset_t dtlb_va_to_pa_sun4u(vm_offset_t); static inline u_long itlb_get_data_sun4u(u_int, u_int); static int itlb_enter_sun4u(u_int, u_long data, vm_offset_t); static vm_offset_t itlb_va_to_pa_sun4u(vm_offset_t); static void itlb_relocate_locked0_sun4u(void); static int sparc64_autoload(void); static ssize_t sparc64_readin(const int, vm_offset_t, const size_t); static ssize_t sparc64_copyin(const void *, vm_offset_t, size_t); static vm_offset_t claim_virt(vm_offset_t, size_t, int); static vm_offset_t alloc_phys(size_t, int); static int map_phys(int, size_t, vm_offset_t, vm_offset_t); static void release_phys(vm_offset_t, u_int); static int __elfN(exec)(struct preloaded_file *); static int mmu_mapin_sun4u(vm_offset_t, vm_size_t); static vm_offset_t init_heap(void); static phandle_t find_bsp_sun4u(phandle_t, uint32_t); const char *cpu_cpuid_prop_sun4u(void); uint32_t cpu_get_mid_sun4u(void); static void tlb_init_sun4u(void); #ifdef LOADER_DEBUG typedef uint64_t tte_t; static void pmap_print_tlb_sun4u(void); static void pmap_print_tte_sun4u(tte_t, tte_t); #endif static struct mmu_ops mmu_ops_sun4u = { tlb_init_sun4u, mmu_mapin_sun4u }; /* sun4u */ struct tlb_entry *dtlb_store; struct tlb_entry *itlb_store; u_int dtlb_slot; u_int itlb_slot; static int cpu_impl; static u_int dtlb_slot_max; static u_int itlb_slot_max; static u_int tlb_locked; static vm_offset_t curkva = 0; static vm_offset_t heapva; static char bootpath[64]; static phandle_t root; #ifdef LOADER_ZFS_SUPPORT static struct zfs_devdesc zfs_currdev; #endif /* * Machine dependent structures that the machine independent * loader part uses. */ struct devsw *devsw[] = { #ifdef LOADER_DISK_SUPPORT &ofwdisk, #endif #ifdef LOADER_NET_SUPPORT &netdev, #endif #ifdef LOADER_ZFS_SUPPORT &zfs_dev, #endif NULL }; struct arch_switch archsw; static struct file_format sparc64_elf = { __elfN(loadfile), __elfN(exec) }; struct file_format *file_formats[] = { &sparc64_elf, NULL }; struct fs_ops *file_system[] = { #ifdef LOADER_ZFS_SUPPORT &zfs_fsops, #endif #ifdef LOADER_UFS_SUPPORT &ufs_fsops, #endif #ifdef LOADER_CD9660_SUPPORT &cd9660_fsops, #endif #ifdef LOADER_ZIP_SUPPORT &zipfs_fsops, #endif #ifdef LOADER_GZIP_SUPPORT &gzipfs_fsops, #endif #ifdef LOADER_BZIP2_SUPPORT &bzipfs_fsops, #endif #ifdef LOADER_NFS_SUPPORT &nfs_fsops, #endif #ifdef LOADER_TFTP_SUPPORT &tftp_fsops, #endif NULL }; struct netif_driver *netif_drivers[] = { #ifdef LOADER_NET_SUPPORT &ofwnet, #endif NULL }; extern struct console ofwconsole; struct console *consoles[] = { &ofwconsole, NULL }; #ifdef LOADER_DEBUG static int watch_phys_set_mask(vm_offset_t pa, u_long mask) { u_long lsucr; stxa(AA_DMMU_PWPR, ASI_DMMU, pa & (((2UL << 38) - 1) << 3)); lsucr = ldxa(0, ASI_LSU_CTL_REG); lsucr = ((lsucr | LSU_PW) & ~LSU_PM_MASK) | (mask << LSU_PM_SHIFT); stxa(0, ASI_LSU_CTL_REG, lsucr); return (0); } static int watch_phys_set(vm_offset_t pa, int sz) { u_long off; off = (u_long)pa & 7; /* Test for misaligned watch points. */ if (off + sz > 8) return (-1); return (watch_phys_set_mask(pa, ((1 << sz) - 1) << off)); } static int watch_virt_set_mask(vm_offset_t va, u_long mask) { u_long lsucr; stxa(AA_DMMU_VWPR, ASI_DMMU, va & (((2UL << 41) - 1) << 3)); lsucr = ldxa(0, ASI_LSU_CTL_REG); lsucr = ((lsucr | LSU_VW) & ~LSU_VM_MASK) | (mask << LSU_VM_SHIFT); stxa(0, ASI_LSU_CTL_REG, lsucr); return (0); } static int watch_virt_set(vm_offset_t va, int sz) { u_long off; off = (u_long)va & 7; /* Test for misaligned watch points. */ if (off + sz > 8) return (-1); return (watch_virt_set_mask(va, ((1 << sz) - 1) << off)); } #endif /* * archsw functions */ static int sparc64_autoload(void) { return (0); } static ssize_t sparc64_readin(const int fd, vm_offset_t va, const size_t len) { mmu_ops->mmu_mapin(va, len); return (read(fd, (void *)va, len)); } static ssize_t sparc64_copyin(const void *src, vm_offset_t dest, size_t len) { mmu_ops->mmu_mapin(dest, len); memcpy((void *)dest, src, len); return (len); } /* * other MD functions */ static vm_offset_t claim_virt(vm_offset_t virt, size_t size, int align) { vm_offset_t mva; if (OF_call_method("claim", mmu, 3, 1, virt, size, align, &mva) == -1) return ((vm_offset_t)-1); return (mva); } static vm_offset_t alloc_phys(size_t size, int align) { cell_t phys_hi, phys_low; if (OF_call_method("claim", memory, 2, 2, size, align, &phys_low, &phys_hi) == -1) return ((vm_offset_t)-1); return ((vm_offset_t)phys_hi << 32 | phys_low); } static int map_phys(int mode, size_t size, vm_offset_t virt, vm_offset_t phys) { return (OF_call_method("map", mmu, 5, 0, (uint32_t)phys, (uint32_t)(phys >> 32), virt, size, mode)); } static void release_phys(vm_offset_t phys, u_int size) { (void)OF_call_method("release", memory, 3, 0, (uint32_t)phys, (uint32_t)(phys >> 32), size); } static int __elfN(exec)(struct preloaded_file *fp) { struct file_metadata *fmp; vm_offset_t mdp; Elf_Addr entry; Elf_Ehdr *e; int error; if ((fmp = file_findmetadata(fp, MODINFOMD_ELFHDR)) == 0) return (EFTYPE); e = (Elf_Ehdr *)&fmp->md_data; if ((error = md_load64(fp->f_args, &mdp, NULL)) != 0) return (error); printf("jumping to kernel entry at %#lx.\n", e->e_entry); #ifdef LOADER_DEBUG pmap_print_tlb_sun4u(); #endif dev_cleanup(); entry = e->e_entry; OF_release((void *)heapva, HEAPSZ); ((kernel_entry_t *)entry)(mdp, 0, 0, 0, openfirmware); panic("%s: exec returned", __func__); } static inline u_long dtlb_get_data_sun4u(u_int tlb, u_int slot) { u_long data, pstate; slot = TLB_DAR_SLOT(tlb, slot); /* * We read ASI_DTLB_DATA_ACCESS_REG twice back-to-back in order to * work around errata of USIII and beyond. */ pstate = rdpr(pstate); wrpr(pstate, pstate & ~PSTATE_IE, 0); (void)ldxa(slot, ASI_DTLB_DATA_ACCESS_REG); data = ldxa(slot, ASI_DTLB_DATA_ACCESS_REG); wrpr(pstate, pstate, 0); return (data); } static inline u_long itlb_get_data_sun4u(u_int tlb, u_int slot) { u_long data, pstate; slot = TLB_DAR_SLOT(tlb, slot); /* * We read ASI_DTLB_DATA_ACCESS_REG twice back-to-back in order to * work around errata of USIII and beyond. */ pstate = rdpr(pstate); wrpr(pstate, pstate & ~PSTATE_IE, 0); (void)ldxa(slot, ASI_ITLB_DATA_ACCESS_REG); data = ldxa(slot, ASI_ITLB_DATA_ACCESS_REG); wrpr(pstate, pstate, 0); return (data); } static vm_offset_t dtlb_va_to_pa_sun4u(vm_offset_t va) { u_long pstate, reg; u_int i, tlb; pstate = rdpr(pstate); wrpr(pstate, pstate & ~PSTATE_IE, 0); for (i = 0; i < dtlb_slot_max; i++) { reg = ldxa(TLB_DAR_SLOT(tlb_locked, i), ASI_DTLB_TAG_READ_REG); if (TLB_TAR_VA(reg) != va) continue; reg = dtlb_get_data_sun4u(tlb_locked, i); wrpr(pstate, pstate, 0); reg >>= TD_PA_SHIFT; if (cpu_impl == CPU_IMPL_SPARC64V || cpu_impl >= CPU_IMPL_ULTRASPARCIII) return (reg & TD_PA_CH_MASK); return (reg & TD_PA_SF_MASK); } wrpr(pstate, pstate, 0); return (-1); } static vm_offset_t itlb_va_to_pa_sun4u(vm_offset_t va) { u_long pstate, reg; int i; pstate = rdpr(pstate); wrpr(pstate, pstate & ~PSTATE_IE, 0); for (i = 0; i < itlb_slot_max; i++) { reg = ldxa(TLB_DAR_SLOT(tlb_locked, i), ASI_ITLB_TAG_READ_REG); if (TLB_TAR_VA(reg) != va) continue; reg = itlb_get_data_sun4u(tlb_locked, i); wrpr(pstate, pstate, 0); reg >>= TD_PA_SHIFT; if (cpu_impl == CPU_IMPL_SPARC64V || cpu_impl >= CPU_IMPL_ULTRASPARCIII) return (reg & TD_PA_CH_MASK); return (reg & TD_PA_SF_MASK); } wrpr(pstate, pstate, 0); return (-1); } static int dtlb_enter_sun4u(u_int index, u_long data, vm_offset_t virt) { return (OF_call_method("SUNW,dtlb-load", mmu, 3, 0, index, data, virt)); } static int itlb_enter_sun4u(u_int index, u_long data, vm_offset_t virt) { if (cpu_impl == CPU_IMPL_ULTRASPARCIIIp && index == 0 && (data & TD_L) != 0) panic("%s: won't enter locked TLB entry at index 0 on USIII+", __func__); return (OF_call_method("SUNW,itlb-load", mmu, 3, 0, index, data, virt)); } static void itlb_relocate_locked0_sun4u(void) { u_long data, pstate, tag; int i; if (cpu_impl != CPU_IMPL_ULTRASPARCIIIp) return; pstate = rdpr(pstate); wrpr(pstate, pstate & ~PSTATE_IE, 0); data = itlb_get_data_sun4u(tlb_locked, 0); if ((data & (TD_V | TD_L)) != (TD_V | TD_L)) { wrpr(pstate, pstate, 0); return; } /* Flush the mapping of slot 0. */ tag = ldxa(TLB_DAR_SLOT(tlb_locked, 0), ASI_ITLB_TAG_READ_REG); stxa(TLB_DEMAP_VA(TLB_TAR_VA(tag)) | TLB_DEMAP_PRIMARY | TLB_DEMAP_PAGE, ASI_IMMU_DEMAP, 0); flush(0); /* The USIII-family ignores the address. */ /* * Search a replacement slot != 0 and enter the data and tag * that formerly were in slot 0. */ for (i = 1; i < itlb_slot_max; i++) { if ((itlb_get_data_sun4u(tlb_locked, i) & TD_V) != 0) continue; stxa(AA_IMMU_TAR, ASI_IMMU, tag); stxa(TLB_DAR_SLOT(tlb_locked, i), ASI_ITLB_DATA_ACCESS_REG, data); flush(0); /* The USIII-family ignores the address. */ break; } wrpr(pstate, pstate, 0); if (i == itlb_slot_max) panic("%s: could not find a replacement slot", __func__); } static int mmu_mapin_sun4u(vm_offset_t va, vm_size_t len) { vm_offset_t pa, mva; u_long data; u_int index; if (va + len > curkva) curkva = va + len; pa = (vm_offset_t)-1; len += va & PAGE_MASK_4M; va &= ~PAGE_MASK_4M; while (len) { if (dtlb_va_to_pa_sun4u(va) == (vm_offset_t)-1 || itlb_va_to_pa_sun4u(va) == (vm_offset_t)-1) { /* Allocate a physical page, claim the virtual area. */ if (pa == (vm_offset_t)-1) { pa = alloc_phys(PAGE_SIZE_4M, PAGE_SIZE_4M); if (pa == (vm_offset_t)-1) panic("%s: out of memory", __func__); mva = claim_virt(va, PAGE_SIZE_4M, 0); if (mva != va) panic("%s: can't claim virtual page " "(wanted %#lx, got %#lx)", __func__, va, mva); /* * The mappings may have changed, be paranoid. */ continue; } /* * Actually, we can only allocate two pages less at * most (depending on the kernel TSB size). */ if (dtlb_slot >= dtlb_slot_max) panic("%s: out of dtlb_slots", __func__); if (itlb_slot >= itlb_slot_max) panic("%s: out of itlb_slots", __func__); data = TD_V | TD_4M | TD_PA(pa) | TD_L | TD_CP | TD_CV | TD_P | TD_W; dtlb_store[dtlb_slot].te_pa = pa; dtlb_store[dtlb_slot].te_va = va; index = dtlb_slot_max - dtlb_slot - 1; if (dtlb_enter_sun4u(index, data, va) < 0) panic("%s: can't enter dTLB slot %d data " "%#lx va %#lx", __func__, index, data, va); dtlb_slot++; itlb_store[itlb_slot].te_pa = pa; itlb_store[itlb_slot].te_va = va; index = itlb_slot_max - itlb_slot - 1; if (itlb_enter_sun4u(index, data, va) < 0) panic("%s: can't enter iTLB slot %d data " "%#lx va %#lxd", __func__, index, data, va); itlb_slot++; pa = (vm_offset_t)-1; } len -= len > PAGE_SIZE_4M ? PAGE_SIZE_4M : len; va += PAGE_SIZE_4M; } if (pa != (vm_offset_t)-1) release_phys(pa, PAGE_SIZE_4M); return (0); } static vm_offset_t init_heap(void) { /* There is no need for continuous physical heap memory. */ heapva = (vm_offset_t)OF_claim((void *)HEAPVA, HEAPSZ, 32); return (heapva); } static phandle_t find_bsp_sun4u(phandle_t node, uint32_t bspid) { char type[sizeof("cpu")]; phandle_t child; uint32_t cpuid; for (; node > 0; node = OF_peer(node)) { child = OF_child(node); if (child > 0) { child = find_bsp_sun4u(child, bspid); if (child > 0) return (child); } else { if (OF_getprop(node, "device_type", type, sizeof(type)) <= 0) continue; if (strcmp(type, "cpu") != 0) continue; if (OF_getprop(node, cpu_cpuid_prop_sun4u(), &cpuid, sizeof(cpuid)) <= 0) continue; if (cpuid == bspid) return (node); } } return (0); } const char * cpu_cpuid_prop_sun4u(void) { switch (cpu_impl) { case CPU_IMPL_SPARC64: case CPU_IMPL_SPARC64V: case CPU_IMPL_ULTRASPARCI: case CPU_IMPL_ULTRASPARCII: case CPU_IMPL_ULTRASPARCIIi: case CPU_IMPL_ULTRASPARCIIe: return ("upa-portid"); case CPU_IMPL_ULTRASPARCIII: case CPU_IMPL_ULTRASPARCIIIp: case CPU_IMPL_ULTRASPARCIIIi: case CPU_IMPL_ULTRASPARCIIIip: return ("portid"); case CPU_IMPL_ULTRASPARCIV: case CPU_IMPL_ULTRASPARCIVp: return ("cpuid"); default: return (""); } } uint32_t cpu_get_mid_sun4u(void) { switch (cpu_impl) { case CPU_IMPL_SPARC64: case CPU_IMPL_SPARC64V: case CPU_IMPL_ULTRASPARCI: case CPU_IMPL_ULTRASPARCII: case CPU_IMPL_ULTRASPARCIIi: case CPU_IMPL_ULTRASPARCIIe: return (UPA_CR_GET_MID(ldxa(0, ASI_UPA_CONFIG_REG))); case CPU_IMPL_ULTRASPARCIII: case CPU_IMPL_ULTRASPARCIIIp: return (FIREPLANE_CR_GET_AID(ldxa(AA_FIREPLANE_CONFIG, ASI_FIREPLANE_CONFIG_REG))); case CPU_IMPL_ULTRASPARCIIIi: case CPU_IMPL_ULTRASPARCIIIip: return (JBUS_CR_GET_JID(ldxa(0, ASI_JBUS_CONFIG_REG))); case CPU_IMPL_ULTRASPARCIV: case CPU_IMPL_ULTRASPARCIVp: return (INTR_ID_GET_ID(ldxa(AA_INTR_ID, ASI_INTR_ID))); default: return (0); } } static void tlb_init_sun4u(void) { phandle_t bsp; cpu_impl = VER_IMPL(rdpr(ver)); switch (cpu_impl) { case CPU_IMPL_SPARC64: case CPU_IMPL_ULTRASPARCI: case CPU_IMPL_ULTRASPARCII: case CPU_IMPL_ULTRASPARCIIi: case CPU_IMPL_ULTRASPARCIIe: tlb_locked = TLB_DAR_T32; break; case CPU_IMPL_ULTRASPARCIII: case CPU_IMPL_ULTRASPARCIIIp: case CPU_IMPL_ULTRASPARCIIIi: case CPU_IMPL_ULTRASPARCIIIip: case CPU_IMPL_ULTRASPARCIV: case CPU_IMPL_ULTRASPARCIVp: tlb_locked = TLB_DAR_T16; break; case CPU_IMPL_SPARC64V: tlb_locked = TLB_DAR_FTLB; break; } bsp = find_bsp_sun4u(OF_child(root), cpu_get_mid_sun4u()); if (bsp == 0) panic("%s: no node for bootcpu?!?!", __func__); if (OF_getprop(bsp, "#dtlb-entries", &dtlb_slot_max, sizeof(dtlb_slot_max)) == -1 || OF_getprop(bsp, "#itlb-entries", &itlb_slot_max, sizeof(itlb_slot_max)) == -1) panic("%s: can't get TLB slot max.", __func__); if (cpu_impl == CPU_IMPL_ULTRASPARCIIIp) { #ifdef LOADER_DEBUG printf("pre fixup:\n"); pmap_print_tlb_sun4u(); #endif /* * Relocate the locked entry in it16 slot 0 (if existent) * as part of working around Cheetah+ erratum 34. */ itlb_relocate_locked0_sun4u(); #ifdef LOADER_DEBUG printf("post fixup:\n"); pmap_print_tlb_sun4u(); #endif } dtlb_store = malloc(dtlb_slot_max * sizeof(*dtlb_store)); itlb_store = malloc(itlb_slot_max * sizeof(*itlb_store)); if (dtlb_store == NULL || itlb_store == NULL) panic("%s: can't allocate TLB store", __func__); } #ifdef LOADER_ZFS_SUPPORT static void sparc64_zfs_probe(void) { struct vtoc8 vtoc; char alias[64], devname[sizeof(alias) + sizeof(":x") - 1]; char type[sizeof("device_type")]; char *bdev, *dev, *odev; uint64_t guid, *guidp; int fd, len, part; phandle_t aliases, options; guid = 0; /* * Get the GUIDs of the ZFS pools on any additional disks listed in * the boot-device environment variable. */ if ((aliases = OF_finddevice("/aliases")) == -1) goto out; options = OF_finddevice("/options"); len = OF_getproplen(options, "boot-device"); if (len <= 0) goto out; bdev = odev = malloc(len + 1); if (bdev == NULL) goto out; if (OF_getprop(options, "boot-device", bdev, len) <= 0) goto out; bdev[len] = '\0'; while ((dev = strsep(&bdev, " ")) != NULL) { if (*dev == '\0') continue; strcpy(alias, dev); (void)OF_getprop(aliases, dev, alias, sizeof(alias)); if (OF_getprop(OF_finddevice(alias), "device_type", type, sizeof(type)) == -1) continue; if (strcmp(type, "block") != 0) continue; /* Find freebsd-zfs slices in the VTOC. */ fd = open(alias, O_RDONLY); if (fd == -1) continue; lseek(fd, 0, SEEK_SET); if (read(fd, &vtoc, sizeof(vtoc)) != sizeof(vtoc)) { close(fd); continue; } close(fd); for (part = 0; part < 8; part++) { if (part == 2 || vtoc.part[part].tag != VTOC_TAG_FREEBSD_ZFS) continue; (void)sprintf(devname, "%s:%c", alias, part + 'a'); /* Get the GUID of the ZFS pool on the boot device. */ if (strcmp(devname, bootpath) == 0) guidp = &guid; else guidp = NULL; if (zfs_probe_dev(devname, guidp) == ENXIO) break; } } free(odev); out: if (guid != 0) { zfs_currdev.pool_guid = guid; zfs_currdev.root_guid = 0; zfs_currdev.dd.d_dev = &zfs_dev; } } #endif /* LOADER_ZFS_SUPPORT */ int main(int (*openfirm)(void *)) { char compatible[32]; struct devsw **dp; /* * Tell the Open Firmware functions where they find the OFW gate. */ OF_init(openfirm); archsw.arch_getdev = ofw_getdev; archsw.arch_copyin = sparc64_copyin; archsw.arch_copyout = ofw_copyout; archsw.arch_readin = sparc64_readin; archsw.arch_autoload = sparc64_autoload; #ifdef LOADER_ZFS_SUPPORT archsw.arch_zfs_probe = sparc64_zfs_probe; #endif if (init_heap() == (vm_offset_t)-1) OF_exit(); setheap((void *)heapva, (void *)(heapva + HEAPSZ)); /* * Probe for a console. */ cons_probe(); if ((root = OF_peer(0)) == -1) panic("%s: can't get root phandle", __func__); OF_getprop(root, "compatible", compatible, sizeof(compatible)); mmu_ops = &mmu_ops_sun4u; mmu_ops->tlb_init(); /* * Set up the current device. */ OF_getprop(chosen, "bootpath", bootpath, sizeof(bootpath)); /* * Initialize devices. */ for (dp = devsw; *dp != NULL; dp++) if ((*dp)->dv_init != 0) (*dp)->dv_init(); #ifdef LOADER_ZFS_SUPPORT if (zfs_currdev.pool_guid != 0) { (void)strncpy(bootpath, zfs_fmtdev(&zfs_currdev), sizeof(bootpath) - 1); bootpath[sizeof(bootpath) - 1] = '\0'; } else #endif /* * Sun compatible bootable CD-ROMs have a disk label placed before * the ISO 9660 data, with the actual file system being in the first * partition, while the other partitions contain pseudo disk labels * with embedded boot blocks for different architectures, which may * be followed by UFS file systems. * The firmware will set the boot path to the partition it boots from * ('f' in the sun4u/sun4v case), but we want the kernel to be loaded * from the ISO 9660 file system ('a'), so the boot path needs to be * altered. */ if (bootpath[strlen(bootpath) - 2] == ':' && bootpath[strlen(bootpath) - 1] == 'f') bootpath[strlen(bootpath) - 1] = 'a'; env_setenv("currdev", EV_VOLATILE, bootpath, ofw_setcurrdev, env_nounset); env_setenv("loaddev", EV_VOLATILE, bootpath, env_noset, env_nounset); printf("\n%s", bootprog_info); printf("bootpath=\"%s\"\n", bootpath); /* Give control to the machine independent loader code. */ interact(); return (1); } COMMAND_SET(heap, "heap", "show heap usage", command_heap); static int command_heap(int argc, char *argv[]) { mallocstats(); printf("heap base at %p, top at %p, upper limit at %p\n", heapva, sbrk(0), heapva + HEAPSZ); return(CMD_OK); } COMMAND_SET(reboot, "reboot", "reboot the system", command_reboot); static int command_reboot(int argc, char *argv[]) { int i; for (i = 0; devsw[i] != NULL; ++i) if (devsw[i]->dv_cleanup != NULL) (devsw[i]->dv_cleanup)(); printf("Rebooting...\n"); OF_exit(); } /* provide this for panic, as it's not in the startup code */ void exit(int code) { OF_exit(); } #ifdef LOADER_DEBUG static const char *const page_sizes[] = { " 8k", " 64k", "512k", " 4m" }; static void pmap_print_tte_sun4u(tte_t tag, tte_t tte) { printf("%s %s ", page_sizes[(tte >> TD_SIZE_SHIFT) & TD_SIZE_MASK], tag & TD_G ? "G" : " "); printf(tte & TD_W ? "W " : " "); printf(tte & TD_P ? "\e[33mP\e[0m " : " "); printf(tte & TD_E ? "E " : " "); printf(tte & TD_CV ? "CV " : " "); printf(tte & TD_CP ? "CP " : " "); printf(tte & TD_L ? "\e[32mL\e[0m " : " "); printf(tte & TD_IE ? "IE " : " "); printf(tte & TD_NFO ? "NFO " : " "); printf("pa=0x%lx va=0x%lx ctx=%ld\n", TD_PA(tte), TLB_TAR_VA(tag), TLB_TAR_CTX(tag)); } static void pmap_print_tlb_sun4u(void) { tte_t tag, tte; u_long pstate; int i; pstate = rdpr(pstate); for (i = 0; i < itlb_slot_max; i++) { wrpr(pstate, pstate & ~PSTATE_IE, 0); tte = itlb_get_data_sun4u(tlb_locked, i); wrpr(pstate, pstate, 0); if (!(tte & TD_V)) continue; tag = ldxa(TLB_DAR_SLOT(tlb_locked, i), ASI_ITLB_TAG_READ_REG); printf("iTLB-%2u: ", i); pmap_print_tte_sun4u(tag, tte); } for (i = 0; i < dtlb_slot_max; i++) { wrpr(pstate, pstate & ~PSTATE_IE, 0); tte = dtlb_get_data_sun4u(tlb_locked, i); wrpr(pstate, pstate, 0); if (!(tte & TD_V)) continue; tag = ldxa(TLB_DAR_SLOT(tlb_locked, i), ASI_DTLB_TAG_READ_REG); printf("dTLB-%2u: ", i); pmap_print_tte_sun4u(tag, tte); } } #endif Index: stable/11/stand/sparc64/zfsloader/Makefile =================================================================== --- stable/11/stand/sparc64/zfsloader/Makefile (revision 344376) +++ stable/11/stand/sparc64/zfsloader/Makefile (revision 344377) @@ -1,7 +1,8 @@ # $FreeBSD$ PROG= zfsloader NEWVERSWHAT= "ZFS enabled bootstrap loader" sparc64 HAVE_ZFS= yes +CFLAGS+= -DBOOTPROG=\"zfsloader\" .include "${.CURDIR}/../loader/Makefile" Index: stable/11/stand/userboot/userboot/Makefile =================================================================== --- stable/11/stand/userboot/userboot/Makefile (revision 344376) +++ stable/11/stand/userboot/userboot/Makefile (revision 344377) @@ -1,54 +1,53 @@ # $FreeBSD$ LOADER_MSDOS_SUPPORT?= yes LOADER_UFS_SUPPORT?= yes LOADER_CD9660_SUPPORT?= no LOADER_EXT2FS_SUPPORT?= no PIC=yes .include SHLIB_NAME= userboot.so STRIP= LIBDIR= /boot SRCS= autoload.c SRCS+= bcache.c SRCS+= biossmap.c SRCS+= bootinfo.c SRCS+= bootinfo32.c SRCS+= bootinfo64.c SRCS+= conf.c SRCS+= console.c SRCS+= copy.c SRCS+= devicename.c SRCS+= elf32_freebsd.c SRCS+= elf64_freebsd.c SRCS+= host.c SRCS+= main.c SRCS+= userboot_cons.c SRCS+= userboot_disk.c SRCS+= vers.c CFLAGS+= -Wall CFLAGS+= -I${BOOTSRC}/userboot CWARNFLAGS.main.c += -Wno-implicit-function-declaration LDFLAGS+= -nostdlib -Wl,-Bsymbolic NEWVERSWHAT= "User boot" ${MACHINE_CPUARCH} .if ${MK_ZFS} != "no" CFLAGS+= -DUSERBOOT_ZFS_SUPPORT -LIBZFSBOOT= ${BOOTOBJ}/zfs/libzfsboot.a HAVE_ZFS=yes .endif # Always add MI sources .include "${BOOTSRC}/loader.mk" CFLAGS+= -I. -DPADD+= ${LDR_INTERP} ${LIBZFSBOOT} ${LIBSA} -LDADD+= ${LDR_INTERP} ${LIBZFSBOOT} ${LIBSA} +DPADD+= ${LDR_INTERP} ${LIBSA} +LDADD+= ${LDR_INTERP} ${LIBSA} .include Index: stable/11/stand/userboot/userboot/conf.c =================================================================== --- stable/11/stand/userboot/userboot/conf.c (revision 344376) +++ stable/11/stand/userboot/userboot/conf.c (revision 344377) @@ -1,107 +1,107 @@ /*- * Copyright (c) 1997 * Matthias Drochner. All rights reserved. * * Redistribution and use in source and binary forms, with or without * modification, are permitted provided that the following conditions * are met: * 1. Redistributions of source code must retain the above copyright * notice, this list of conditions and the following disclaimer. * 2. Redistributions in binary form must reproduce the above copyright * notice, this list of conditions and the following disclaimer in the * documentation and/or other materials provided with the distribution. * 3. All advertising materials mentioning features or use of this software * must display the following acknowledgement: * This product includes software developed for the NetBSD Project * by Matthias Drochner. * 4. The name of the author may not be used to endorse or promote products * derived from this software without specific prior written permission. * * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. * IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT, * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. * * $NetBSD: conf.c,v 1.2 1997/03/22 09:03:29 thorpej Exp $ */ #include __FBSDID("$FreeBSD$"); #include #include "libuserboot.h" #if defined(USERBOOT_ZFS_SUPPORT) -#include "../zfs/libzfs.h" +#include "libzfs.h" #endif /* * We could use linker sets for some or all of these, but * then we would have to control what ended up linked into * the bootstrap. So it's easier to conditionalise things * here. * * XXX rename these arrays to be consistent and less namespace-hostile */ /* Exported for libstand */ struct devsw *devsw[] = { &host_dev, &userboot_disk, #if defined(USERBOOT_ZFS_SUPPORT) &zfs_dev, #endif NULL }; struct fs_ops *file_system[] = { &host_fsops, &ufs_fsops, &cd9660_fsops, #if defined(USERBOOT_ZFS_SUPPORT) &zfs_fsops, #endif &gzipfs_fsops, &bzipfs_fsops, NULL }; /* Exported for i386 only */ /* * Sort formats so that those that can detect based on arguments * rather than reading the file go first. */ extern struct file_format i386_elf; extern struct file_format i386_elf_obj; extern struct file_format amd64_elf; extern struct file_format amd64_elf_obj; struct file_format *file_formats[] = { &i386_elf, &i386_elf_obj, &amd64_elf, &amd64_elf_obj, NULL }; /* * Consoles * * We don't prototype these in libuserboot.h because they require * data structures from bootstrap.h as well. */ extern struct console userboot_console; extern struct console userboot_comconsole; struct console *consoles[] = { &userboot_console, &userboot_comconsole, NULL }; Index: stable/11/stand/userboot/userboot/devicename.c =================================================================== --- stable/11/stand/userboot/userboot/devicename.c (revision 344376) +++ stable/11/stand/userboot/userboot/devicename.c (revision 344377) @@ -1,223 +1,223 @@ /*- * Copyright (c) 1998 Michael Smith * All rights reserved. * * Redistribution and use in source and binary forms, with or without * modification, are permitted provided that the following conditions * are met: * 1. Redistributions of source code must retain the above copyright * notice, this list of conditions and the following disclaimer. * 2. Redistributions in binary form must reproduce the above copyright * notice, this list of conditions and the following disclaimer in the * documentation and/or other materials provided with the distribution. * * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF * SUCH DAMAGE. */ #include __FBSDID("$FreeBSD$"); #include #include #include "bootstrap.h" #include "disk.h" #include "libuserboot.h" #if defined(USERBOOT_ZFS_SUPPORT) -#include "../zfs/libzfs.h" +#include "libzfs.h" #endif static int userboot_parsedev(struct disk_devdesc **dev, const char *devspec, const char **path); /* * Point (dev) at an allocated device specifier for the device matching the * path in (devspec). If it contains an explicit device specification, * use that. If not, use the default device. */ int userboot_getdev(void **vdev, const char *devspec, const char **path) { struct disk_devdesc **dev = (struct disk_devdesc **)vdev; int rv; /* * If it looks like this is just a path and no * device, go with the current device. */ if ((devspec == NULL) || (devspec[0] == '/') || (strchr(devspec, ':') == NULL)) { if (((rv = userboot_parsedev(dev, getenv("currdev"), NULL)) == 0) && (path != NULL)) *path = devspec; return(rv); } /* * Try to parse the device name off the beginning of the devspec */ return(userboot_parsedev(dev, devspec, path)); } /* * Point (dev) at an allocated device specifier matching the string version * at the beginning of (devspec). Return a pointer to the remaining * text in (path). * * In all cases, the beginning of (devspec) is compared to the names * of known devices in the device switch, and then any following text * is parsed according to the rules applied to the device type. * * For disk-type devices, the syntax is: * * disk[s][]: * */ static int userboot_parsedev(struct disk_devdesc **dev, const char *devspec, const char **path) { struct disk_devdesc *idev; struct devsw *dv; int i, unit, err; const char *cp; const char *np; /* minimum length check */ if (strlen(devspec) < 2) return(EINVAL); /* look for a device that matches */ for (i = 0, dv = NULL; devsw[i] != NULL; i++) { if (!strncmp(devspec, devsw[i]->dv_name, strlen(devsw[i]->dv_name))) { dv = devsw[i]; break; } } if (dv == NULL) return(ENOENT); idev = malloc(sizeof(struct disk_devdesc)); err = 0; np = (devspec + strlen(dv->dv_name)); switch(dv->dv_type) { case DEVT_NONE: /* XXX what to do here? Do we care? */ break; case DEVT_DISK: err = disk_parsedev(idev, np, path); if (err != 0) goto fail; break; case DEVT_CD: case DEVT_NET: unit = 0; if (*np && (*np != ':')) { unit = strtol(np, (char **)&cp, 0); /* get unit number if present */ if (cp == np) { err = EUNIT; goto fail; } } else { cp = np; } if (*cp && (*cp != ':')) { err = EINVAL; goto fail; } idev->dd.d_unit = unit; if (path != NULL) *path = (*cp == 0) ? cp : cp + 1; break; case DEVT_ZFS: #if defined(USERBOOT_ZFS_SUPPORT) err = zfs_parsedev((struct zfs_devdesc *)idev, np, path); if (err != 0) goto fail; break; #else /* FALLTHROUGH */ #endif default: err = EINVAL; goto fail; } idev->dd.d_dev = dv; if (dev == NULL) { free(idev); } else { *dev = idev; } return(0); fail: free(idev); return(err); } char * userboot_fmtdev(void *vdev) { struct devdesc *dev = (struct devdesc *)vdev; static char buf[128]; /* XXX device length constant? */ switch(dev->d_dev->dv_type) { case DEVT_NONE: strcpy(buf, "(no device)"); break; case DEVT_CD: sprintf(buf, "%s%d:", dev->d_dev->dv_name, dev->d_unit); break; case DEVT_DISK: return (disk_fmtdev(vdev)); case DEVT_NET: sprintf(buf, "%s%d:", dev->d_dev->dv_name, dev->d_unit); break; case DEVT_ZFS: #if defined(USERBOOT_ZFS_SUPPORT) return (zfs_fmtdev(vdev)); #else sprintf(buf, "%s%d:", dev->d_dev->dv_name, dev->d_unit); #endif break; } return(buf); } /* * Set currdev to suit the value being supplied in (value) */ int userboot_setcurrdev(struct env_var *ev, int flags, const void *value) { struct disk_devdesc *ncurr; int rv; if ((rv = userboot_parsedev(&ncurr, value, NULL)) != 0) return(rv); free(ncurr); env_setenv(ev->ev_name, flags | EV_NOHOOK, value, NULL, NULL); return(0); } Index: stable/11/stand/userboot/userboot/main.c =================================================================== --- stable/11/stand/userboot/userboot/main.c (revision 344376) +++ stable/11/stand/userboot/userboot/main.c (revision 344377) @@ -1,238 +1,238 @@ /*- * Copyright (c) 1998 Michael Smith * Copyright (c) 1998,2000 Doug Rabson * All rights reserved. * * Redistribution and use in source and binary forms, with or without * modification, are permitted provided that the following conditions * are met: * 1. Redistributions of source code must retain the above copyright * notice, this list of conditions and the following disclaimer. * 2. Redistributions in binary form must reproduce the above copyright * notice, this list of conditions and the following disclaimer in the * documentation and/or other materials provided with the distribution. * * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF * SUCH DAMAGE. */ #include __FBSDID("$FreeBSD$"); #include #include #include #include #include "bootstrap.h" #include "disk.h" #include "libuserboot.h" #if defined(USERBOOT_ZFS_SUPPORT) -#include "../zfs/libzfs.h" +#include "libzfs.h" static void userboot_zfs_probe(void); static int userboot_zfs_found; #endif /* Minimum version required */ #define USERBOOT_VERSION USERBOOT_VERSION_3 #define MALLOCSZ (64*1024*1024) struct loader_callbacks *callbacks; void *callbacks_arg; static jmp_buf jb; struct arch_switch archsw; /* MI/MD interface boundary */ static void extract_currdev(void); void delay(int usec) { CALLBACK(delay, usec); } void exit(int v) { CALLBACK(exit, v); longjmp(jb, 1); } void loader_main(struct loader_callbacks *cb, void *arg, int version, int ndisks) { static char mallocbuf[MALLOCSZ]; char *var; int i; if (version < USERBOOT_VERSION) abort(); callbacks = cb; callbacks_arg = arg; userboot_disk_maxunit = ndisks; /* * initialise the heap as early as possible. Once this is done, * alloc() is usable. */ setheap((void *)mallocbuf, (void *)(mallocbuf + sizeof(mallocbuf))); /* * Hook up the console */ cons_probe(); printf("\n%s", bootprog_info); #if 0 printf("Memory: %ld k\n", memsize() / 1024); #endif setenv("LINES", "24", 1); /* optional */ /* * Set custom environment variables */ i = 0; while (1) { var = CALLBACK(getenv, i++); if (var == NULL) break; putenv(var); } archsw.arch_autoload = userboot_autoload; archsw.arch_getdev = userboot_getdev; archsw.arch_copyin = userboot_copyin; archsw.arch_copyout = userboot_copyout; archsw.arch_readin = userboot_readin; #if defined(USERBOOT_ZFS_SUPPORT) archsw.arch_zfs_probe = userboot_zfs_probe; #endif /* * Initialise the block cache. Set the upper limit. */ bcache_init(32768, 512); /* * March through the device switch probing for things. */ for (i = 0; devsw[i] != NULL; i++) if (devsw[i]->dv_init != NULL) (devsw[i]->dv_init)(); extract_currdev(); if (setjmp(jb)) return; interact(); /* doesn't return */ exit(0); } /* * Set the 'current device' by (if possible) recovering the boot device as * supplied by the initial bootstrap. */ static void extract_currdev(void) { struct disk_devdesc dev; struct devdesc *dd; #if defined(USERBOOT_ZFS_SUPPORT) struct zfs_devdesc zdev; if (userboot_zfs_found) { /* Leave the pool/root guid's unassigned */ bzero(&zdev, sizeof(zdev)); zdev.dd.d_dev = &zfs_dev; init_zfs_bootenv(zfs_fmtdev(&zdev)); dd = &zdev.dd; } else #endif if (userboot_disk_maxunit > 0) { dev.dd.d_dev = &userboot_disk; dev.dd.d_unit = 0; dev.d_slice = 0; dev.d_partition = 0; /* * If we cannot auto-detect the partition type then * access the disk as a raw device. */ if (dev.dd.d_dev->dv_open(NULL, &dev)) { dev.d_slice = -1; dev.d_partition = -1; } dd = &dev.dd; } else { dev.dd.d_dev = &host_dev; dev.dd.d_unit = 0; dd = &dev.dd; } env_setenv("currdev", EV_VOLATILE, userboot_fmtdev(dd), userboot_setcurrdev, env_nounset); env_setenv("loaddev", EV_VOLATILE, userboot_fmtdev(dd), env_noset, env_nounset); } #if defined(USERBOOT_ZFS_SUPPORT) static void userboot_zfs_probe(void) { char devname[32]; uint64_t pool_guid; int unit; /* * Open all the disks we can find and see if we can reconstruct * ZFS pools from them. Record if any were found. */ for (unit = 0; unit < userboot_disk_maxunit; unit++) { sprintf(devname, "disk%d:", unit); pool_guid = 0; zfs_probe_dev(devname, &pool_guid); if (pool_guid != 0) userboot_zfs_found = 1; } } #endif COMMAND_SET(quit, "quit", "exit the loader", command_quit); static int command_quit(int argc, char *argv[]) { exit(USERBOOT_EXIT_QUIT); return (CMD_OK); } COMMAND_SET(reboot, "reboot", "reboot the system", command_reboot); static int command_reboot(int argc, char *argv[]) { exit(USERBOOT_EXIT_REBOOT); return (CMD_OK); } Index: stable/11 =================================================================== --- stable/11 (revision 344376) +++ stable/11 (revision 344377) Property changes on: stable/11 ___________________________________________________________________ Modified: svn:mergeinfo ## -0,0 +0,1 ## Merged /head:r336084-336085,336118