aboutsummaryrefslogtreecommitdiff
path: root/stand/libsa/zfs/zfs.c
diff options
context:
space:
mode:
Diffstat (limited to 'stand/libsa/zfs/zfs.c')
-rw-r--r--stand/libsa/zfs/zfs.c201
1 files changed, 90 insertions, 111 deletions
diff --git a/stand/libsa/zfs/zfs.c b/stand/libsa/zfs/zfs.c
index 633ef3b18784..70a102f6425d 100644
--- a/stand/libsa/zfs/zfs.c
+++ b/stand/libsa/zfs/zfs.c
@@ -22,13 +22,8 @@
* 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 <sys/cdefs.h>
-__FBSDID("$FreeBSD$");
-
/*
* Stand-alone file reading package.
*/
@@ -66,6 +61,9 @@ static void zfs_bootenv_initial(const char *envname, spa_t *spa,
static void zfs_checkpoints_initial(spa_t *spa, const char *name,
const char *dsname);
+static int zfs_parsedev(struct devdesc **idev, const char *devspec,
+ const char **path);
+
struct devsw zfs_dev;
struct fs_ops zfs_fsops = {
@@ -108,7 +106,8 @@ struct zfs_be_entry {
static int
zfs_open(const char *upath, struct open_file *f)
{
- struct zfsmount *mount = (struct zfsmount *)f->f_devdata;
+ struct devdesc *dev = f->f_devdata;
+ struct zfsmount *mount = dev->d_opendata;
struct file *fp;
int rc;
@@ -149,7 +148,8 @@ zfs_close(struct open_file *f)
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 devdesc *dev = f->f_devdata;
+ const spa_t *spa = ((struct zfsmount *)dev->d_opendata)->spa;
struct file *fp = (struct file *)f->f_fsdata;
struct stat sb;
size_t n;
@@ -213,7 +213,8 @@ zfs_seek(struct open_file *f, off_t offset, int where)
static int
zfs_stat(struct open_file *f, struct stat *sb)
{
- const spa_t *spa = ((struct zfsmount *)f->f_devdata)->spa;
+ struct devdesc *dev = f->f_devdata;
+ const spa_t *spa = ((struct zfsmount *)dev->d_opendata)->spa;
struct file *fp = (struct file *)f->f_fsdata;
return (zfs_dnode_stat(spa, &fp->f_dnode, sb));
@@ -222,7 +223,8 @@ zfs_stat(struct open_file *f, struct stat *sb)
static int
zfs_readdir(struct open_file *f, struct dirent *d)
{
- const spa_t *spa = ((struct zfsmount *)f->f_devdata)->spa;
+ struct devdesc *dev = f->f_devdata;
+ const spa_t *spa = ((struct zfsmount *)dev->d_opendata)->spa;
struct file *fp = (struct file *)f->f_fsdata;
mzap_ent_phys_t mze;
struct stat sb;
@@ -366,59 +368,77 @@ zfs_readdir(struct open_file *f, struct dirent *d)
}
}
+static spa_t *
+spa_find_by_dev(struct zfs_devdesc *dev)
+{
+
+ if (dev->dd.d_dev->dv_type != DEVT_ZFS)
+ return (NULL);
+
+ if (dev->pool_guid == 0)
+ return (STAILQ_FIRST(&zfs_pools));
+
+ return (spa_find_by_guid(dev->pool_guid));
+}
+
/*
* if path is NULL, create mount structure, but do not add it to list.
*/
static int
zfs_mount(const char *dev, const char *path, void **data)
{
- struct zfs_devdesc *zfsdev;
+ struct zfs_devdesc *zfsdev = NULL;
spa_t *spa;
- struct zfsmount *mnt;
+ struct zfsmount *mnt = NULL;
int rv;
errno = 0;
- zfsdev = malloc(sizeof(*zfsdev));
- if (zfsdev == NULL)
- return (errno);
-
- rv = zfs_parsedev(zfsdev, dev + 3, NULL);
+ rv = zfs_parsedev((struct devdesc **)&zfsdev, dev, NULL);
if (rv != 0) {
- free(zfsdev);
return (rv);
}
spa = spa_find_by_dev(zfsdev);
- if (spa == NULL)
- return (ENXIO);
+ if (spa == NULL) {
+ rv = ENXIO;
+ goto err;
+ }
mnt = calloc(1, sizeof(*mnt));
- if (mnt != NULL && path != NULL)
+ if (mnt == NULL) {
+ rv = ENOMEM;
+ goto err;
+ }
+
+ if (mnt->path != NULL) {
mnt->path = strdup(path);
- rv = errno;
+ if (mnt->path == NULL) {
+ rv = ENOMEM;
+ goto err;
+ }
+ }
- if (mnt != NULL)
- rv = zfs_mount_impl(spa, zfsdev->root_guid, mnt);
- free(zfsdev);
+ rv = zfs_mount_impl(spa, zfsdev->root_guid, mnt);
- if (rv == 0 && mnt != NULL && mnt->objset.os_type != DMU_OST_ZFS) {
+ if (rv == 0 && mnt->objset.os_type != DMU_OST_ZFS) {
printf("Unexpected object set type %ju\n",
(uintmax_t)mnt->objset.os_type);
rv = EIO;
}
-
+err:
if (rv != 0) {
if (mnt != NULL)
free(mnt->path);
free(mnt);
+ free(zfsdev);
return (rv);
}
- if (mnt != NULL) {
- *data = mnt;
- if (path != NULL)
- STAILQ_INSERT_TAIL(&zfsmount, mnt, next);
- }
+ *data = mnt;
+ if (path != NULL)
+ STAILQ_INSERT_TAIL(&zfsmount, mnt, next);
+
+ free(zfsdev);
return (rv);
}
@@ -773,35 +793,12 @@ zfs_probe_partition(void *arg, const char *partname,
int
zfs_get_bootenv(void *vdev, nvlist_t **benvp)
{
- struct zfs_devdesc *dev = (struct zfs_devdesc *)vdev;
- nvlist_t *benv = NULL;
- vdev_t *vd;
spa_t *spa;
- if (dev->dd.d_dev->dv_type != DEVT_ZFS)
- return (ENOTSUP);
-
- if ((spa = spa_find_by_dev(dev)) == NULL)
+ if ((spa = spa_find_by_dev((struct zfs_devdesc *)vdev)) == NULL)
return (ENXIO);
- if (spa->spa_bootenv == NULL) {
- STAILQ_FOREACH(vd, &spa->spa_root_vdev->v_children,
- v_childlink) {
- benv = vdev_read_bootenv(vd);
-
- if (benv != NULL)
- break;
- }
- spa->spa_bootenv = benv;
- } else {
- benv = spa->spa_bootenv;
- }
-
- if (benv == NULL)
- return (ENOENT);
-
- *benvp = benv;
- return (0);
+ return (zfs_get_bootenv_spa(spa, benvp));
}
/*
@@ -810,22 +807,12 @@ zfs_get_bootenv(void *vdev, nvlist_t **benvp)
int
zfs_set_bootenv(void *vdev, nvlist_t *benv)
{
- struct zfs_devdesc *dev = (struct zfs_devdesc *)vdev;
spa_t *spa;
- vdev_t *vd;
- if (dev->dd.d_dev->dv_type != DEVT_ZFS)
- return (ENOTSUP);
-
- if ((spa = spa_find_by_dev(dev)) == NULL)
+ if ((spa = spa_find_by_dev((struct zfs_devdesc *)vdev)) == NULL)
return (ENXIO);
- STAILQ_FOREACH(vd, &spa->spa_root_vdev->v_children, v_childlink) {
- vdev_write_bootenv(vd, benv);
- }
-
- spa->spa_bootenv = benv;
- return (0);
+ return (zfs_set_bootenv_spa(spa, benv));
}
/*
@@ -835,27 +822,12 @@ zfs_set_bootenv(void *vdev, nvlist_t *benv)
int
zfs_get_bootonce(void *vdev, const char *key, char *buf, size_t size)
{
- nvlist_t *benv;
- char *result = NULL;
- int result_size, rv;
-
- if ((rv = zfs_get_bootenv(vdev, &benv)) != 0)
- return (rv);
+ spa_t *spa;
- if ((rv = nvlist_find(benv, key, DATA_TYPE_STRING, NULL,
- &result, &result_size)) == 0) {
- if (result_size == 0) {
- /* ignore empty string */
- rv = ENOENT;
- } else {
- size = MIN((size_t)result_size + 1, size);
- strlcpy(buf, result, size);
- }
- (void) nvlist_remove(benv, key, DATA_TYPE_STRING);
- (void) zfs_set_bootenv(vdev, benv);
- }
+ if ((spa = spa_find_by_dev((struct zfs_devdesc *)vdev)) == NULL)
+ return (ENXIO);
- return (rv);
+ return (zfs_get_bootonce_spa(spa, key, buf, size));
}
/*
@@ -1292,8 +1264,12 @@ zfs_nvstore_unset_impl(void *vdev, const char *name, bool unset_env)
rv = zfs_set_bootenv(vdev, spa->spa_bootenv);
}
- if (unset_env)
- env_discard(env_getenv(name));
+ if (unset_env) {
+ struct env_var *ev = env_getenv(name);
+
+ if (ev != NULL)
+ env_discard(ev);
+ }
return (rv);
}
@@ -1490,7 +1466,7 @@ zfs_attach_nvstore(void *vdev)
}
int
-zfs_probe_dev(const char *devname, uint64_t *pool_guid)
+zfs_probe_dev(const char *devname, uint64_t *pool_guid, bool parts_too)
{
struct ptable *table;
struct zfs_probe_args pa;
@@ -1506,6 +1482,8 @@ zfs_probe_dev(const char *devname, uint64_t *pool_guid)
ret = zfs_probe(pa.fd, pool_guid);
if (ret == 0)
return (0);
+ if (!parts_too)
+ return (ENXIO);
/* Probe each partition */
ret = ioctl(pa.fd, DIOCGMEDIASIZE, &mediasz);
@@ -1583,11 +1561,10 @@ zfs_dev_open(struct open_file *f, ...)
rv = 0;
/* This device is not set as currdev, mount us private copy. */
if (mount == NULL)
- rv = zfs_mount(zfs_fmtdev(dev), NULL, (void **)&mount);
+ rv = zfs_mount(devformat(&dev->dd), NULL, (void **)&mount);
if (rv == 0) {
- f->f_devdata = mount;
- free(dev);
+ dev->dd.d_opendata = mount;
}
return (rv);
}
@@ -1595,25 +1572,18 @@ zfs_dev_open(struct open_file *f, ...)
static int
zfs_dev_close(struct open_file *f)
{
+ struct devdesc *dev;
struct zfsmount *mnt, *mount;
- mnt = f->f_devdata;
+ dev = f->f_devdata;
+ mnt = dev->d_opendata;
STAILQ_FOREACH(mount, &zfsmount, next) {
if (mnt->spa->spa_guid == mount->spa->spa_guid)
break;
}
- /*
- * devclose() will free f->f_devdata, but since we do have
- * pointer to zfsmount structure in f->f_devdata, and
- * zfs_unmount() will also free the zfsmount structure,
- * we will get double free. To prevent double free,
- * we must set f_devdata to NULL there.
- */
- if (mount != NULL)
- f->f_devdata = NULL;
-
+ /* XXX */
return (0);
}
@@ -1633,11 +1603,13 @@ struct devsw zfs_dev = {
.dv_close = zfs_dev_close,
.dv_ioctl = noioctl,
.dv_print = zfs_dev_print,
- .dv_cleanup = NULL
+ .dv_cleanup = nullsys,
+ .dv_fmtdev = zfs_fmtdev,
+ .dv_parsedev = zfs_parsedev,
};
-int
-zfs_parsedev(struct zfs_devdesc *dev, const char *devspec, const char **path)
+static int
+zfs_parsedev(struct devdesc **idev, const char *devspec, const char **path)
{
static char rootname[ZFS_MAXNAMELEN];
static char poolname[ZFS_MAXNAMELEN];
@@ -1646,8 +1618,9 @@ zfs_parsedev(struct zfs_devdesc *dev, const char *devspec, const char **path)
const char *np;
const char *sep;
int rv;
+ struct zfs_devdesc *dev;
- np = devspec;
+ np = devspec + 3; /* Skip the leading 'zfs' */
if (*np != ':')
return (EINVAL);
np++;
@@ -1670,18 +1643,24 @@ zfs_parsedev(struct zfs_devdesc *dev, const char *devspec, const char **path)
spa = spa_find_by_name(poolname);
if (!spa)
return (ENXIO);
+ dev = malloc(sizeof(*dev));
+ if (dev == NULL)
+ return (ENOMEM);
dev->pool_guid = spa->spa_guid;
rv = zfs_lookup_dataset(spa, rootname, &dev->root_guid);
- if (rv != 0)
+ if (rv != 0) {
+ free(dev);
return (rv);
+ }
if (path != NULL)
*path = (*end == '\0') ? end : end + 1;
dev->dd.d_dev = &zfs_dev;
+ *idev = &dev->dd;
return (0);
}
char *
-zfs_fmtdev(void *vdev)
+zfs_fmtdev(struct devdesc *vdev)
{
static char rootname[ZFS_MAXNAMELEN];
static char buf[2 * ZFS_MAXNAMELEN + 8];
@@ -1689,7 +1668,7 @@ zfs_fmtdev(void *vdev)
spa_t *spa;
buf[0] = '\0';
- if (dev->dd.d_dev->dv_type != DEVT_ZFS)
+ if (vdev->d_dev->dv_type != DEVT_ZFS)
return (buf);
/* Do we have any pools? */