Rebase to OpenSolaris b103, in the process we are removing any code which did not originate from the OpenSolaris source. These changes will be reintroduced in topic branches for easier tracking

This commit is contained in:
Brian Behlendorf
2008-12-03 12:09:06 -08:00
parent b6097ae55a
commit b128c09fbe
339 changed files with 15459 additions and 60397 deletions
+23 -9
View File
@@ -27,8 +27,6 @@
#ifndef _LIBZFS_H
#define _LIBZFS_H
#pragma ident "@(#)libzfs.h 1.51 08/04/01 SMI"
#include <assert.h>
#include <libnvpair.h>
#include <sys/param.h>
@@ -115,6 +113,8 @@ enum {
EZFS_BADCACHE, /* bad cache file */
EZFS_ISL2CACHE, /* device is for the level 2 ARC */
EZFS_VDEVNOTSUP, /* unsupported vdev type */
EZFS_NOTSUP, /* ops not supported on this dataset */
EZFS_ACTIVE_SPARE, /* pool has active shared spare devices */
EZFS_UNKNOWN
};
@@ -185,6 +185,7 @@ extern void zpool_close(zpool_handle_t *);
extern const char *zpool_get_name(zpool_handle_t *);
extern int zpool_get_state(zpool_handle_t *);
extern char *zpool_state_to_name(vdev_state_t, vdev_aux_t);
extern void zpool_free_handles(libzfs_handle_t *);
/*
* Iterate over all active pools in the system.
@@ -196,7 +197,7 @@ extern int zpool_iter(libzfs_handle_t *, zpool_iter_f, void *);
* Functions to create and destroy pools
*/
extern int zpool_create(libzfs_handle_t *, const char *, nvlist_t *,
nvlist_t *);
nvlist_t *, nvlist_t *);
extern int zpool_destroy(zpool_handle_t *);
extern int zpool_add(zpool_handle_t *, nvlist_t *);
@@ -219,7 +220,7 @@ extern int zpool_vdev_degrade(zpool_handle_t *, uint64_t);
extern int zpool_vdev_clear(zpool_handle_t *, uint64_t);
extern nvlist_t *zpool_find_vdev(zpool_handle_t *, const char *, boolean_t *,
boolean_t *);
boolean_t *, boolean_t *);
extern int zpool_label_disk(libzfs_handle_t *, zpool_handle_t *, char *);
/*
@@ -253,8 +254,11 @@ typedef enum {
ZPOOL_STATUS_FAILING_DEV, /* device experiencing errors */
ZPOOL_STATUS_VERSION_NEWER, /* newer on-disk version */
ZPOOL_STATUS_HOSTID_MISMATCH, /* last accessed by another system */
ZPOOL_STATUS_IO_FAILURE_WAIT, /* failed I/O, failmode 'wait' */
ZPOOL_STATUS_IO_FAILURE_CONTINUE, /* failed I/O, failmode 'continue' */
ZPOOL_STATUS_FAULTED_DEV_R, /* faulted device with replicas */
ZPOOL_STATUS_FAULTED_DEV_NR, /* faulted device with no replicas */
ZPOOL_STATUS_BAD_LOG, /* cannot read log chain(s) */
/*
* The following are not faults per se, but still an error possibly
@@ -284,18 +288,23 @@ extern int zpool_get_errlog(zpool_handle_t *, nvlist_t **);
/*
* Import and export functions
*/
extern int zpool_export(zpool_handle_t *);
extern int zpool_export(zpool_handle_t *, boolean_t);
extern int zpool_import(libzfs_handle_t *, nvlist_t *, const char *,
char *altroot);
extern int zpool_import_props(libzfs_handle_t *, nvlist_t *, const char *,
nvlist_t *);
nvlist_t *, boolean_t);
/*
* Search for pools to import
*/
extern nvlist_t *zpool_find_import(libzfs_handle_t *, int, char **, boolean_t);
extern nvlist_t *zpool_find_import(libzfs_handle_t *, int, char **);
extern nvlist_t *zpool_find_import_cached(libzfs_handle_t *, const char *,
boolean_t);
char *, uint64_t);
extern nvlist_t *zpool_find_import_byname(libzfs_handle_t *, int, char **,
char *);
extern nvlist_t *zpool_find_import_byguid(libzfs_handle_t *, int, char **,
uint64_t);
extern nvlist_t *zpool_find_import_activeok(libzfs_handle_t *, int, char **);
/*
* Miscellaneous pool functions
@@ -311,6 +320,7 @@ extern int zpool_stage_history(libzfs_handle_t *, const char *);
extern void zpool_obj_to_path(zpool_handle_t *, uint64_t, uint64_t, char *,
size_t len);
extern int zfs_ioctl(libzfs_handle_t *, int, struct zfs_cmd *);
extern int zpool_get_physpath(zpool_handle_t *, char *);
/*
* Basic handle manipulations. These functions do not create or destroy the
* underlying datasets, only the references to them.
@@ -319,6 +329,7 @@ extern zfs_handle_t *zfs_open(libzfs_handle_t *, const char *, int);
extern void zfs_close(zfs_handle_t *);
extern zfs_type_t zfs_get_type(const zfs_handle_t *);
extern const char *zfs_get_name(const zfs_handle_t *);
extern zpool_handle_t *zfs_get_pool_handle(const zfs_handle_t *);
/*
* Property management functions. Some functions are shared with the kernel,
@@ -333,6 +344,9 @@ extern uint64_t zfs_prop_default_numeric(zfs_prop_t);
extern const char *zfs_prop_column_name(zfs_prop_t);
extern boolean_t zfs_prop_align_right(zfs_prop_t);
extern nvlist_t *zfs_valid_proplist(libzfs_handle_t *, zfs_type_t,
nvlist_t *, uint64_t, zfs_handle_t *, const char *);
extern const char *zfs_prop_to_name(zfs_prop_t);
extern int zfs_prop_set(zfs_handle_t *, const char *, const char *);
extern int zfs_prop_get(zfs_handle_t *, zfs_prop_t, char *, size_t,
@@ -418,7 +432,7 @@ extern int zfs_create_ancestors(libzfs_handle_t *, const char *);
extern int zfs_destroy(zfs_handle_t *);
extern int zfs_destroy_snaps(zfs_handle_t *, char *);
extern int zfs_clone(zfs_handle_t *, const char *, nvlist_t *);
extern int zfs_snapshot(libzfs_handle_t *, const char *, boolean_t);
extern int zfs_snapshot(libzfs_handle_t *, const char *, boolean_t, nvlist_t *);
extern int zfs_rollback(zfs_handle_t *, zfs_handle_t *, boolean_t);
extern int zfs_rename(zfs_handle_t *, const char *, boolean_t);
extern int zfs_send(zfs_handle_t *, const char *, const char *,
+11 -4
View File
@@ -27,8 +27,6 @@
#ifndef _LIBFS_IMPL_H
#define _LIBFS_IMPL_H
#pragma ident "@(#)libzfs_impl.h 1.27 08/04/14 SMI"
#include <sys/dmu.h>
#include <sys/fs/zfs.h>
#include <sys/zfs_ioctl.h>
@@ -54,6 +52,7 @@ struct libzfs_handle {
int libzfs_fd;
FILE *libzfs_mnttab;
FILE *libzfs_sharetab;
zpool_handle_t *libzfs_pool_handles;
uu_avl_pool_t *libzfs_ns_avlpool;
uu_avl_t *libzfs_ns_avl;
uint64_t libzfs_ns_gen;
@@ -69,6 +68,7 @@ struct libzfs_handle {
struct zfs_handle {
libzfs_handle_t *zfs_hdl;
zpool_handle_t *zpool_hdl;
char zfs_name[ZFS_MAXNAMELEN];
zfs_type_t zfs_type; /* type including snapshot */
zfs_type_t zfs_head_type; /* type excluding snapshot */
@@ -77,7 +77,6 @@ struct zfs_handle {
nvlist_t *zfs_user_props;
boolean_t zfs_mntcheck;
char *zfs_mntopts;
char zfs_root[MAXPATHLEN];
};
/*
@@ -88,6 +87,7 @@ struct zfs_handle {
struct zpool_handle {
libzfs_handle_t *zpool_hdl;
zpool_handle_t *zpool_next;
char zpool_name[ZPOOL_MAXNAMELEN];
int zpool_state;
size_t zpool_config_size;
@@ -136,6 +136,13 @@ int zprop_parse_value(libzfs_handle_t *, nvpair_t *, int, zfs_type_t,
int zprop_expand_list(libzfs_handle_t *hdl, zprop_list_t **plp,
zfs_type_t type);
/*
* Use this changelist_gather() flag to force attempting mounts
* on each change node regardless of whether or not it is currently
* mounted.
*/
#define CL_GATHER_MOUNT_ALWAYS 1
typedef struct prop_changelist prop_changelist_t;
int zcmd_alloc_dst_nvlist(libzfs_handle_t *, zfs_cmd_t *, size_t);
@@ -150,7 +157,7 @@ int changelist_postfix(prop_changelist_t *);
void changelist_rename(prop_changelist_t *, const char *, const char *);
void changelist_remove(prop_changelist_t *, const char *);
void changelist_free(prop_changelist_t *);
prop_changelist_t *changelist_gather(zfs_handle_t *, zfs_prop_t, int);
prop_changelist_t *changelist_gather(zfs_handle_t *, zfs_prop_t, int, int);
int changelist_unshare(prop_changelist_t *, zfs_share_proto_t *);
int changelist_haszonedchild(prop_changelist_t *);
+11 -8
View File
@@ -26,8 +26,6 @@
* Portions Copyright 2007 Ramprakash Jelari
*/
#pragma ident "@(#)libzfs_changelist.c 1.23 08/03/04 SMI"
#include <libintl.h>
#include <libuutil.h>
#include <stddef.h>
@@ -80,7 +78,8 @@ struct prop_changelist {
boolean_t cl_waslegacy;
boolean_t cl_allchildren;
boolean_t cl_alldependents;
int cl_flags;
int cl_mflags; /* Mount flags */
int cl_gflags; /* Gather request flags */
boolean_t cl_haszonedchild;
boolean_t cl_sorted;
};
@@ -149,7 +148,7 @@ changelist_prefix(prop_changelist_t *clp)
switch (clp->cl_prop) {
case ZFS_PROP_MOUNTPOINT:
if (zfs_unmount(cn->cn_handle, NULL,
clp->cl_flags) != 0) {
clp->cl_mflags) != 0) {
ret = -1;
cn->cn_needpost = B_FALSE;
}
@@ -480,7 +479,8 @@ change_one(zfs_handle_t *zhp, void *data)
}
cn->cn_handle = zhp;
cn->cn_mounted = zfs_is_mounted(zhp, NULL);
cn->cn_mounted = (clp->cl_gflags & CL_GATHER_MOUNT_ALWAYS) ||
zfs_is_mounted(zhp, NULL);
cn->cn_shared = zfs_is_shared(zhp);
cn->cn_zoned = zfs_prop_get_int(zhp, ZFS_PROP_ZONED);
cn->cn_needpost = B_TRUE;
@@ -556,7 +556,8 @@ compare_mountpoints(const void *a, const void *b, void *unused)
* mark whether it was shared beforehand.
*/
prop_changelist_t *
changelist_gather(zfs_handle_t *zhp, zfs_prop_t prop, int flags)
changelist_gather(zfs_handle_t *zhp, zfs_prop_t prop, int gather_flags,
int mnt_flags)
{
prop_changelist_t *clp;
prop_changenode_t *cn;
@@ -592,7 +593,8 @@ changelist_gather(zfs_handle_t *zhp, zfs_prop_t prop, int flags)
clp->cl_list = uu_list_create(clp->cl_pool, NULL,
clp->cl_sorted ? UU_LIST_SORTED : 0);
clp->cl_flags = flags;
clp->cl_gflags = gather_flags;
clp->cl_mflags = mnt_flags;
if (clp->cl_list == NULL) {
assert(uu_error() == UU_ERROR_NO_MEMORY);
@@ -673,7 +675,8 @@ changelist_gather(zfs_handle_t *zhp, zfs_prop_t prop, int flags)
}
cn->cn_handle = temp;
cn->cn_mounted = zfs_is_mounted(temp, NULL);
cn->cn_mounted = (clp->cl_gflags & CL_GATHER_MOUNT_ALWAYS) ||
zfs_is_mounted(temp, NULL);
cn->cn_shared = zfs_is_shared(temp);
cn->cn_zoned = zfs_prop_get_int(zhp, ZFS_PROP_ZONED);
cn->cn_needpost = B_TRUE;
+1 -1
View File
@@ -23,7 +23,7 @@
* Use is subject to license terms.
*/
#pragma ident "@(#)libzfs_config.c 1.9 07/04/19 SMI"
#pragma ident "%Z%%M% %I% %E% SMI"
/*
* The pool configuration repository is stored in /etc/zfs/zpool.cache as a
+156 -58
View File
@@ -24,8 +24,6 @@
* Use is subject to license terms.
*/
#pragma ident "@(#)libzfs_dataset.c 1.79 08/04/01 SMI"
#include <assert.h>
#include <ctype.h>
#include <errno.h>
@@ -254,6 +252,69 @@ process_user_props(zfs_handle_t *zhp, nvlist_t *props)
return (nvl);
}
static zpool_handle_t *
zpool_add_handle(zfs_handle_t *zhp, const char *pool_name)
{
libzfs_handle_t *hdl = zhp->zfs_hdl;
zpool_handle_t *zph;
if ((zph = zpool_open_canfail(hdl, pool_name)) != NULL) {
if (hdl->libzfs_pool_handles != NULL)
zph->zpool_next = hdl->libzfs_pool_handles;
hdl->libzfs_pool_handles = zph;
}
return (zph);
}
static zpool_handle_t *
zpool_find_handle(zfs_handle_t *zhp, const char *pool_name, int len)
{
libzfs_handle_t *hdl = zhp->zfs_hdl;
zpool_handle_t *zph = hdl->libzfs_pool_handles;
while ((zph != NULL) &&
(strncmp(pool_name, zpool_get_name(zph), len) != 0))
zph = zph->zpool_next;
return (zph);
}
/*
* Returns a handle to the pool that contains the provided dataset.
* If a handle to that pool already exists then that handle is returned.
* Otherwise, a new handle is created and added to the list of handles.
*/
static zpool_handle_t *
zpool_handle(zfs_handle_t *zhp)
{
char *pool_name;
int len;
zpool_handle_t *zph;
len = strcspn(zhp->zfs_name, "/@") + 1;
pool_name = zfs_alloc(zhp->zfs_hdl, len);
(void) strlcpy(pool_name, zhp->zfs_name, len);
zph = zpool_find_handle(zhp, pool_name, len);
if (zph == NULL)
zph = zpool_add_handle(zhp, pool_name);
free(pool_name);
return (zph);
}
void
zpool_free_handles(libzfs_handle_t *hdl)
{
zpool_handle_t *next, *zph = hdl->libzfs_pool_handles;
while (zph != NULL) {
next = zph->zpool_next;
zpool_close(zph);
zph = next;
}
hdl->libzfs_pool_handles = NULL;
}
/*
* Utility function to gather stats (objset and zpl) for the given object.
*/
@@ -283,8 +344,6 @@ get_stats(zfs_handle_t *zhp)
zhp->zfs_dmustats = zc.zc_objset_stats; /* structure assignment */
(void) strlcpy(zhp->zfs_root, zc.zc_value, sizeof (zhp->zfs_root));
if (zcmd_read_dst_nvlist(hdl, &zc, &allprops) != 0) {
zcmd_free_nvlists(&zc);
return (-1);
@@ -409,6 +468,7 @@ top:
abort(); /* we should never see any other types */
zhp->zfs_hdl->libzfs_log_str = logstr;
zhp->zpool_hdl = zpool_handle(zhp);
return (zhp);
}
@@ -470,27 +530,13 @@ zfs_close(zfs_handle_t *zhp)
int
zfs_spa_version(zfs_handle_t *zhp, int *spa_version)
{
char *pool_name;
zpool_handle_t *zpool_handle;
char *p;
zpool_handle_t *zpool_handle = zhp->zpool_hdl;
pool_name = zfs_alloc(zhp->zfs_hdl, MAXPATHLEN);
if (zfs_prop_get(zhp, ZFS_PROP_NAME, pool_name,
MAXPATHLEN, NULL, NULL, 0, B_FALSE) != 0) {
free(pool_name);
return (-1);
}
if (p = strchr(pool_name, '/'))
*p = '\0';
zpool_handle = zpool_open(zhp->zfs_hdl, pool_name);
free(pool_name);
if (zpool_handle == NULL)
return (-1);
*spa_version = zpool_get_prop_int(zpool_handle,
ZPOOL_PROP_VERSION, NULL);
zpool_close(zpool_handle);
return (0);
}
@@ -518,8 +564,8 @@ zfs_which_resv_prop(zfs_handle_t *zhp, zfs_prop_t *resv_prop)
* parses any numeric properties (index, boolean, etc) if they are specified as
* strings.
*/
static nvlist_t *
zfs_validate_properties(libzfs_handle_t *hdl, zfs_type_t type, nvlist_t *nvl,
nvlist_t *
zfs_valid_proplist(libzfs_handle_t *hdl, zfs_type_t type, nvlist_t *nvl,
uint64_t zoned, zfs_handle_t *zhp, const char *errbuf)
{
nvpair_t *elem;
@@ -530,13 +576,6 @@ zfs_validate_properties(libzfs_handle_t *hdl, zfs_type_t type, nvlist_t *nvl,
int chosen_normal = -1;
int chosen_utf = -1;
if (type == ZFS_TYPE_SNAPSHOT) {
zfs_error_aux(hdl, dgettext(TEXT_DOMAIN,
"snapshot properties cannot be modified"));
(void) zfs_error(hdl, EZFS_PROPTYPE, errbuf);
return (NULL);
}
if (nvlist_alloc(&ret, NV_UNIQUE_NAME, 0) != 0) {
(void) no_memory(hdl);
return (NULL);
@@ -584,6 +623,13 @@ zfs_validate_properties(libzfs_handle_t *hdl, zfs_type_t type, nvlist_t *nvl,
continue;
}
if (type == ZFS_TYPE_SNAPSHOT) {
zfs_error_aux(hdl, dgettext(TEXT_DOMAIN,
"this property can not be modified for snapshots"));
(void) zfs_error(hdl, EZFS_PROPTYPE, errbuf);
goto error;
}
if (!zfs_prop_valid_for_type(prop, type)) {
zfs_error_aux(hdl,
dgettext(TEXT_DOMAIN, "'%s' does not "
@@ -1722,7 +1768,8 @@ zfs_prop_set(zfs_handle_t *zhp, const char *propname, const char *propval)
libzfs_handle_t *hdl = zhp->zfs_hdl;
nvlist_t *nvl = NULL, *realprops;
zfs_prop_t prop;
int do_prefix = 1;
boolean_t do_prefix;
uint64_t idx;
(void) snprintf(errbuf, sizeof (errbuf),
dgettext(TEXT_DOMAIN, "cannot set property for '%s'"),
@@ -1734,7 +1781,7 @@ zfs_prop_set(zfs_handle_t *zhp, const char *propname, const char *propval)
goto error;
}
if ((realprops = zfs_validate_properties(hdl, zhp->zfs_type, nvl,
if ((realprops = zfs_valid_proplist(hdl, zhp->zfs_type, nvl,
zfs_prop_get_int(zhp, ZFS_PROP_ZONED), zhp, errbuf)) == NULL)
goto error;
@@ -1743,7 +1790,7 @@ zfs_prop_set(zfs_handle_t *zhp, const char *propname, const char *propval)
prop = zfs_name_to_prop(propname);
if ((cl = changelist_gather(zhp, prop, 0)) == NULL)
if ((cl = changelist_gather(zhp, prop, 0, 0)) == NULL)
goto error;
if (prop == ZFS_PROP_MOUNTPOINT && changelist_haszonedchild(cl)) {
@@ -1754,13 +1801,16 @@ zfs_prop_set(zfs_handle_t *zhp, const char *propname, const char *propval)
goto error;
}
/* do not unmount dataset if canmount is being set to noauto */
if (prop == ZFS_PROP_CANMOUNT && *propval == ZFS_CANMOUNT_NOAUTO)
do_prefix = 0;
/*
* If the dataset's canmount property is being set to noauto,
* then we want to prevent unmounting & remounting it.
*/
do_prefix = !((prop == ZFS_PROP_CANMOUNT) &&
(zprop_string_to_index(prop, propval, &idx,
ZFS_TYPE_DATASET) == 0) && (idx == ZFS_CANMOUNT_NOAUTO));
if (do_prefix && (ret = changelist_prefix(cl)) != 0)
goto error;
goto error;
/*
* Execute the corresponding ioctl() to set this property.
@@ -1820,6 +1870,17 @@ zfs_prop_set(zfs_handle_t *zhp, const char *propname, const char *propval)
(void) zfs_error(hdl, EZFS_BADVERSION, errbuf);
break;
case ERANGE:
if (prop == ZFS_PROP_COMPRESSION) {
(void) zfs_error_aux(hdl, dgettext(TEXT_DOMAIN,
"property setting is not allowed on "
"bootable datasets"));
(void) zfs_error(hdl, EZFS_NOTSUP, errbuf);
} else {
(void) zfs_standard_error(hdl, errno, errbuf);
}
break;
case EOVERFLOW:
/*
* This platform can't address a volume this big.
@@ -1922,7 +1983,7 @@ zfs_prop_inherit(zfs_handle_t *zhp, const char *propname)
/*
* Determine datasets which will be affected by this change, if any.
*/
if ((cl = changelist_gather(zhp, prop, 0)) == NULL)
if ((cl = changelist_gather(zhp, prop, 0, 0)) == NULL)
return (-1);
if (prop == ZFS_PROP_MOUNTPOINT && changelist_haszonedchild(cl)) {
@@ -2168,6 +2229,15 @@ get_numeric_property(zfs_handle_t *zhp, zfs_prop_t prop, zprop_source_t *src,
case PROP_TYPE_NUMBER:
case PROP_TYPE_INDEX:
*val = getprop_uint64(zhp, prop, source);
/*
* If we tried to use a defalut value for a
* readonly property, it means that it was not
* present; return an error.
*/
if (zfs_prop_readonly(prop) &&
*source && (*source)[0] == '\0') {
return (-1);
}
break;
case PROP_TYPE_STRING:
@@ -2221,7 +2291,6 @@ zfs_prop_get(zfs_handle_t *zhp, zfs_prop_t prop, char *propbuf, size_t proplen,
char *source = NULL;
uint64_t val;
char *str;
const char *root;
const char *strval;
/*
@@ -2257,25 +2326,42 @@ zfs_prop_get(zfs_handle_t *zhp, zfs_prop_t prop, char *propbuf, size_t proplen,
* Getting the precise mountpoint can be tricky.
*
* - for 'none' or 'legacy', return those values.
* - for default mountpoints, construct it as /zfs/<dataset>
* - for inherited mountpoints, we want to take everything
* after our ancestor and append it to the inherited value.
*
* If the pool has an alternate root, we want to prepend that
* root to any values we return.
*/
root = zhp->zfs_root;
str = getprop_string(zhp, prop, &source);
if (str[0] == '\0') {
(void) snprintf(propbuf, proplen, "%s/zfs/%s",
root, zhp->zfs_name);
} else if (str[0] == '/') {
if (str[0] == '/') {
char buf[MAXPATHLEN];
char *root = buf;
const char *relpath = zhp->zfs_name + strlen(source);
if (relpath[0] == '/')
relpath++;
if (str[1] == '\0')
if ((zpool_get_prop(zhp->zpool_hdl,
ZPOOL_PROP_ALTROOT, buf, MAXPATHLEN, NULL)) ||
(strcmp(root, "-") == 0))
root[0] = '\0';
/*
* Special case an alternate root of '/'. This will
* avoid having multiple leading slashes in the
* mountpoint path.
*/
if (strcmp(root, "/") == 0)
root++;
/*
* If the mountpoint is '/' then skip over this
* if we are obtaining either an alternate root or
* an inherited mountpoint.
*/
if (str[1] == '\0' && (root[0] != '\0' ||
relpath[0] != '\0'))
str++;
if (relpath[0] == '\0')
@@ -2859,7 +2945,7 @@ zfs_create(libzfs_handle_t *hdl, const char *path, zfs_type_t type,
else
zc.zc_objset_type = DMU_OST_ZFS;
if (props && (props = zfs_validate_properties(hdl, type, props,
if (props && (props = zfs_valid_proplist(hdl, type, props,
zoned, NULL, errbuf)) == 0)
return (-1);
@@ -3142,8 +3228,8 @@ zfs_clone(zfs_handle_t *zhp, const char *target, nvlist_t *props)
}
if (props) {
if ((props = zfs_validate_properties(hdl, type, props,
zoned, zhp, errbuf)) == NULL)
if ((props = zfs_valid_proplist(hdl, type, props, zoned,
zhp, errbuf)) == NULL)
return (-1);
if (zcmd_write_src_nvlist(hdl, &zc, props) != 0) {
@@ -3375,10 +3461,11 @@ zfs_create_link_cb(zfs_handle_t *zhp, void *arg)
* Takes a snapshot of the given dataset.
*/
int
zfs_snapshot(libzfs_handle_t *hdl, const char *path, boolean_t recursive)
zfs_snapshot(libzfs_handle_t *hdl, const char *path, boolean_t recursive,
nvlist_t *props)
{
const char *delim;
char *parent;
char parent[ZFS_MAXNAMELEN];
zfs_handle_t *zhp;
zfs_cmd_t zc = { 0 };
int ret;
@@ -3391,16 +3478,27 @@ zfs_snapshot(libzfs_handle_t *hdl, const char *path, boolean_t recursive)
if (!zfs_validate_name(hdl, path, ZFS_TYPE_SNAPSHOT, B_TRUE))
return (zfs_error(hdl, EZFS_INVALIDNAME, errbuf));
if (props) {
if ((props = zfs_valid_proplist(hdl, ZFS_TYPE_SNAPSHOT,
props, B_FALSE, NULL, errbuf)) == NULL)
return (-1);
if (zcmd_write_src_nvlist(hdl, &zc, props) != 0) {
nvlist_free(props);
return (-1);
}
nvlist_free(props);
}
/* make sure the parent exists and is of the appropriate type */
delim = strchr(path, '@');
if ((parent = zfs_alloc(hdl, delim - path + 1)) == NULL)
return (-1);
(void) strncpy(parent, path, delim - path);
parent[delim - path] = '\0';
if ((zhp = zfs_open(hdl, parent, ZFS_TYPE_FILESYSTEM |
ZFS_TYPE_VOLUME)) == NULL) {
free(parent);
zcmd_free_nvlists(&zc);
return (-1);
}
@@ -3413,6 +3511,8 @@ zfs_snapshot(libzfs_handle_t *hdl, const char *path, boolean_t recursive)
zc.zc_cookie = recursive;
ret = zfs_ioctl(zhp->zfs_hdl, ZFS_IOC_SNAPSHOT, &zc);
zcmd_free_nvlists(&zc);
/*
* if it was recursive, the one that actually failed will be in
* zc.zc_name.
@@ -3435,7 +3535,6 @@ zfs_snapshot(libzfs_handle_t *hdl, const char *path, boolean_t recursive)
dgettext(TEXT_DOMAIN,
"Volume successfully snapshotted, but device links "
"were not created"));
free(parent);
zfs_close(zhp);
return (-1);
}
@@ -3444,7 +3543,6 @@ zfs_snapshot(libzfs_handle_t *hdl, const char *path, boolean_t recursive)
if (ret != 0)
(void) zfs_standard_error(hdl, errno, errbuf);
free(parent);
zfs_close(zhp);
return (ret);
@@ -3490,7 +3588,7 @@ rollback_destroy(zfs_handle_t *zhp, void *data)
/* We must destroy this clone; first unmount it */
prop_changelist_t *clp;
clp = changelist_gather(zhp, ZFS_PROP_NAME,
clp = changelist_gather(zhp, ZFS_PROP_NAME, 0,
cbp->cb_force ? MS_FORCE: 0);
if (clp == NULL || changelist_prefix(clp) != 0) {
cbp->cb_error = B_TRUE;
@@ -3766,7 +3864,7 @@ zfs_rename(zfs_handle_t *zhp, const char *target, boolean_t recursive)
goto error;
}
} else {
if ((cl = changelist_gather(zhp, ZFS_PROP_NAME, 0)) == NULL)
if ((cl = changelist_gather(zhp, ZFS_PROP_NAME, 0, 0)) == NULL)
return (-1);
if (changelist_haszonedchild(cl)) {
@@ -3918,7 +4016,7 @@ zvol_create_link_common(libzfs_handle_t *hdl, const char *dataset, int ifexists)
if ((dhdl = di_devlink_init(ZFS_DRIVER,
DI_MAKE_LINK)) == NULL) {
zfs_error_aux(hdl, strerror(errno));
(void) zfs_standard_error_fmt(hdl, EZFS_DEVLINKS,
(void) zfs_error_fmt(hdl, errno,
dgettext(TEXT_DOMAIN, "cannot create device links "
"for '%s'"), dataset);
(void) ioctl(hdl->libzfs_fd, ZFS_IOC_REMOVE_MINOR, &zc);
+1 -1
View File
@@ -23,7 +23,7 @@
* Use is subject to license terms.
*/
#pragma ident "@(#)libzfs_graph.c 1.8 08/02/27 SMI"
#pragma ident "%Z%%M% %I% %E% SMI"
/*
* Iterate over all children of the current object. This includes the normal
+102 -41
View File
@@ -23,7 +23,7 @@
* Use is subject to license terms.
*/
#pragma ident "@(#)libzfs_import.c 1.24 08/04/08 SMI"
#pragma ident "%Z%%M% %I% %E% SMI"
/*
* Pool import support functions.
@@ -429,6 +429,7 @@ get_configs(libzfs_handle_t *hdl, pool_list_t *pl, boolean_t active_ok)
boolean_t isactive;
uint64_t hostid;
nvlist_t *nvl;
boolean_t found_one = B_FALSE;
if (nvlist_alloc(&ret, 0, 0) != 0)
goto nomem;
@@ -689,10 +690,16 @@ add_pool:
if (nvlist_add_nvlist(ret, name, config) != 0)
goto nomem;
found_one = B_TRUE;
nvlist_free(config);
config = NULL;
}
if (!found_one) {
nvlist_free(ret);
ret = NULL;
}
return (ret);
nomem:
@@ -740,7 +747,7 @@ zpool_read_label(int fd, nvlist_t **config)
return (-1);
for (l = 0; l < VDEV_LABELS; l++) {
if (pread(fd, label, sizeof (vdev_label_t),
if (pread64(fd, label, sizeof (vdev_label_t),
label_offset(size, l)) != sizeof (vdev_label_t))
continue;
@@ -774,10 +781,12 @@ zpool_read_label(int fd, nvlist_t **config)
* Given a list of directories to search, find all pools stored on disk. This
* includes partial pools which are not available to import. If no args are
* given (argc is 0), then the default directory (/dev/dsk) is searched.
* poolname or guid (but not both) are provided by the caller when trying
* to import a specific pool.
*/
nvlist_t *
zpool_find_import(libzfs_handle_t *hdl, int argc, char **argv,
boolean_t active_ok)
static nvlist_t *
zpool_find_import_impl(libzfs_handle_t *hdl, int argc, char **argv,
boolean_t active_ok, char *poolname, uint64_t guid)
{
int i;
DIR *dirp = NULL;
@@ -795,6 +804,8 @@ zpool_find_import(libzfs_handle_t *hdl, int argc, char **argv,
config_entry_t *ce, *cenext;
name_entry_t *ne, *nenext;
verify(poolname == NULL || guid == 0);
if (argc == 0) {
argc = 1;
argv = &default_dir;
@@ -873,6 +884,28 @@ zpool_find_import(libzfs_handle_t *hdl, int argc, char **argv,
(void) close(fd);
if (config != NULL) {
boolean_t matched = B_TRUE;
if (poolname != NULL) {
char *pname;
matched = nvlist_lookup_string(config,
ZPOOL_CONFIG_POOL_NAME,
&pname) == 0 &&
strcmp(poolname, pname) == 0;
} else if (guid != 0) {
uint64_t this_guid;
matched = nvlist_lookup_uint64(config,
ZPOOL_CONFIG_POOL_GUID,
&this_guid) == 0 &&
guid == this_guid;
}
if (!matched) {
nvlist_free(config);
config = NULL;
continue;
}
/* use the non-raw path for the config */
(void) strlcpy(end, name, pathleft);
if (add_config(hdl, &pools, path, config) != 0)
@@ -915,12 +948,40 @@ error:
return (ret);
}
nvlist_t *
zpool_find_import(libzfs_handle_t *hdl, int argc, char **argv)
{
return (zpool_find_import_impl(hdl, argc, argv, B_FALSE, NULL, 0));
}
nvlist_t *
zpool_find_import_byname(libzfs_handle_t *hdl, int argc, char **argv,
char *pool)
{
return (zpool_find_import_impl(hdl, argc, argv, B_FALSE, pool, 0));
}
nvlist_t *
zpool_find_import_byguid(libzfs_handle_t *hdl, int argc, char **argv,
uint64_t guid)
{
return (zpool_find_import_impl(hdl, argc, argv, B_FALSE, NULL, guid));
}
nvlist_t *
zpool_find_import_activeok(libzfs_handle_t *hdl, int argc, char **argv)
{
return (zpool_find_import_impl(hdl, argc, argv, B_TRUE, NULL, 0));
}
/*
* Given a cache file, return the contents as a list of importable pools.
* poolname or guid (but not both) are provided by the caller when trying
* to import a specific pool.
*/
nvlist_t *
zpool_find_import_cached(libzfs_handle_t *hdl, const char *cachefile,
boolean_t active_ok)
char *poolname, uint64_t guid)
{
char *buf;
int fd;
@@ -929,9 +990,11 @@ zpool_find_import_cached(libzfs_handle_t *hdl, const char *cachefile,
nvlist_t *pools;
nvpair_t *elem;
char *name;
uint64_t guid;
uint64_t this_guid;
boolean_t active;
verify(poolname == NULL || guid == 0);
if ((fd = open(cachefile, O_RDONLY)) < 0) {
zfs_error_aux(hdl, "%s", strerror(errno));
(void) zfs_error(hdl, EZFS_BADCACHE,
@@ -989,43 +1052,41 @@ zpool_find_import_cached(libzfs_handle_t *hdl, const char *cachefile,
verify(nvlist_lookup_string(src, ZPOOL_CONFIG_POOL_NAME,
&name) == 0);
if (poolname != NULL && strcmp(poolname, name) != 0)
continue;
verify(nvlist_lookup_uint64(src, ZPOOL_CONFIG_POOL_GUID,
&guid) == 0);
if (!active_ok) {
if (pool_active(hdl, name, guid, &active) != 0) {
nvlist_free(raw);
nvlist_free(pools);
return (NULL);
}
if (active)
&this_guid) == 0);
if (guid != 0) {
verify(nvlist_lookup_uint64(src, ZPOOL_CONFIG_POOL_GUID,
&this_guid) == 0);
if (guid != this_guid)
continue;
if ((dst = refresh_config(hdl, src)) == NULL) {
nvlist_free(raw);
nvlist_free(pools);
return (NULL);
}
if (nvlist_add_nvlist(pools, nvpair_name(elem), dst)
!= 0) {
(void) no_memory(hdl);
nvlist_free(dst);
nvlist_free(raw);
nvlist_free(pools);
return (NULL);
}
nvlist_free(dst);
} else {
if (nvlist_add_nvlist(pools, nvpair_name(elem), src)
!= 0) {
(void) no_memory(hdl);
nvlist_free(raw);
nvlist_free(pools);
return (NULL);
}
}
if (pool_active(hdl, name, this_guid, &active) != 0) {
nvlist_free(raw);
nvlist_free(pools);
return (NULL);
}
if (active)
continue;
if ((dst = refresh_config(hdl, src)) == NULL) {
nvlist_free(raw);
nvlist_free(pools);
return (NULL);
}
if (nvlist_add_nvlist(pools, nvpair_name(elem), dst) != 0) {
(void) no_memory(hdl);
nvlist_free(dst);
nvlist_free(raw);
nvlist_free(pools);
return (NULL);
}
nvlist_free(dst);
}
nvlist_free(raw);
+2 -4
View File
@@ -24,8 +24,6 @@
* Use is subject to license terms.
*/
#pragma ident "@(#)libzfs_mount.c 1.25 08/03/04 SMI"
/*
* Routines to manage ZFS mounts. We separate all the nasty routines that have
* to deal with the OS. The following functions are the main entry points --
@@ -440,7 +438,7 @@ zfs_unmountall(zfs_handle_t *zhp, int flags)
prop_changelist_t *clp;
int ret;
clp = changelist_gather(zhp, ZFS_PROP_MOUNTPOINT, flags);
clp = changelist_gather(zhp, ZFS_PROP_MOUNTPOINT, 0, flags);
if (clp == NULL)
return (-1);
@@ -945,7 +943,7 @@ zfs_unshareall_proto(zfs_handle_t *zhp, zfs_share_proto_t *proto)
prop_changelist_t *clp;
int ret;
clp = changelist_gather(zhp, ZFS_PROP_SHARENFS, 0);
clp = changelist_gather(zhp, ZFS_PROP_SHARENFS, 0, 0);
if (clp == NULL)
return (-1);
+373 -81
View File
@@ -24,8 +24,6 @@
* Use is subject to license terms.
*/
#pragma ident "@(#)libzfs_pool.c 1.44 08/04/11 SMI"
#include <alloca.h>
#include <assert.h>
#include <ctype.h>
@@ -38,6 +36,7 @@
#include <stdlib.h>
#include <strings.h>
#include <unistd.h>
#include <zone.h>
#include <sys/efi_partition.h>
#include <sys/vtoc.h>
#include <sys/zfs_ioctl.h>
@@ -48,6 +47,13 @@
#include "zfs_prop.h"
#include "libzfs_impl.h"
static int read_efi_label(nvlist_t *config, diskaddr_t *sb);
#if defined(__i386) || defined(__amd64)
#define BOOTCMD "installgrub(1M)"
#else
#define BOOTCMD "installboot(1M)"
#endif
/*
* ====================================================================
@@ -135,8 +141,21 @@ zpool_get_prop_int(zpool_handle_t *zhp, zpool_prop_t prop, zprop_source_t *src)
uint64_t value;
zprop_source_t source;
if (zhp->zpool_props == NULL && zpool_get_all_props(zhp))
if (zhp->zpool_props == NULL && zpool_get_all_props(zhp)) {
/*
* zpool_get_all_props() has most likely failed because
* the pool is faulted, but if all we need is the top level
* vdev's guid then get it from the zhp config nvlist.
*/
if ((prop == ZPOOL_PROP_GUID) &&
(nvlist_lookup_nvlist(zhp->zpool_config,
ZPOOL_CONFIG_VDEV_TREE, &nv) == 0) &&
(nvlist_lookup_uint64(nv, ZPOOL_CONFIG_GUID, &value)
== 0)) {
return (value);
}
return (zpool_prop_default_numeric(prop));
}
nvl = zhp->zpool_props;
if (nvlist_lookup_nvlist(nvl, zpool_prop_to_name(prop), &nv) == 0) {
@@ -167,7 +186,7 @@ zpool_state_to_name(vdev_state_t state, vdev_aux_t aux)
case VDEV_STATE_REMOVED:
return (gettext("REMOVED"));
case VDEV_STATE_CANT_OPEN:
if (aux == VDEV_AUX_CORRUPT_DATA)
if (aux == VDEV_AUX_CORRUPT_DATA || aux == VDEV_AUX_BAD_LOG)
return (gettext("FAULTED"));
else
return (gettext("UNAVAIL"));
@@ -273,7 +292,7 @@ bootfs_name_valid(const char *pool, char *bootfs)
{
int len = strlen(pool);
if (!zfs_name_valid(bootfs, ZFS_TYPE_FILESYSTEM))
if (!zfs_name_valid(bootfs, ZFS_TYPE_FILESYSTEM|ZFS_TYPE_SNAPSHOT))
return (B_FALSE);
if (strncmp(pool, bootfs, len) == 0 &&
@@ -283,13 +302,45 @@ bootfs_name_valid(const char *pool, char *bootfs)
return (B_FALSE);
}
/*
* Inspect the configuration to determine if any of the devices contain
* an EFI label.
*/
static boolean_t
pool_uses_efi(nvlist_t *config)
{
nvlist_t **child;
uint_t c, children;
if (nvlist_lookup_nvlist_array(config, ZPOOL_CONFIG_CHILDREN,
&child, &children) != 0)
return (read_efi_label(config, NULL) >= 0);
for (c = 0; c < children; c++) {
if (pool_uses_efi(child[c]))
return (B_TRUE);
}
return (B_FALSE);
}
static boolean_t
pool_is_bootable(zpool_handle_t *zhp)
{
char bootfs[ZPOOL_MAXNAMELEN];
return (zpool_get_prop(zhp, ZPOOL_PROP_BOOTFS, bootfs,
sizeof (bootfs), NULL) == 0 && strncmp(bootfs, "-",
sizeof (bootfs)) != 0);
}
/*
* Given an nvlist of zpool properties to be set, validate that they are
* correct, and parse any numeric properties (index, boolean, etc) if they are
* specified as strings.
*/
static nvlist_t *
zpool_validate_properties(libzfs_handle_t *hdl, const char *poolname,
zpool_valid_proplist(libzfs_handle_t *hdl, const char *poolname,
nvlist_t *props, uint64_t version, boolean_t create_or_import, char *errbuf)
{
nvpair_t *elem;
@@ -299,6 +350,8 @@ zpool_validate_properties(libzfs_handle_t *hdl, const char *poolname,
uint64_t intval;
char *slash;
struct stat64 statbuf;
zpool_handle_t *zhp;
nvlist_t *nvroot;
if (nvlist_alloc(&retprops, NV_UNIQUE_NAME, 0) != 0) {
(void) no_memory(hdl);
@@ -372,6 +425,29 @@ zpool_validate_properties(libzfs_handle_t *hdl, const char *poolname,
(void) zfs_error(hdl, EZFS_INVALIDNAME, errbuf);
goto error;
}
if ((zhp = zpool_open_canfail(hdl, poolname)) == NULL) {
zfs_error_aux(hdl, dgettext(TEXT_DOMAIN,
"could not open pool '%s'"), poolname);
(void) zfs_error(hdl, EZFS_OPENFAILED, errbuf);
goto error;
}
verify(nvlist_lookup_nvlist(zpool_get_config(zhp, NULL),
ZPOOL_CONFIG_VDEV_TREE, &nvroot) == 0);
/*
* bootfs property cannot be set on a disk which has
* been EFI labeled.
*/
if (pool_uses_efi(nvroot)) {
zfs_error_aux(hdl, dgettext(TEXT_DOMAIN,
"property '%s' not supported on "
"EFI labeled devices"), propname);
(void) zfs_error(hdl, EZFS_POOL_NOTSUP, errbuf);
zpool_close(zhp);
goto error;
}
zpool_close(zhp);
break;
case ZPOOL_PROP_ALTROOT:
@@ -468,7 +544,7 @@ zpool_set_prop(zpool_handle_t *zhp, const char *propname, const char *propval)
}
version = zpool_get_prop_int(zhp, ZPOOL_PROP_VERSION, NULL);
if ((realprops = zpool_validate_properties(zhp->zpool_hdl,
if ((realprops = zpool_valid_proplist(zhp->zpool_hdl,
zhp->zpool_name, nvl, version, B_FALSE, errbuf)) == NULL) {
nvlist_free(nvl);
return (-1);
@@ -751,11 +827,14 @@ zpool_get_state(zpool_handle_t *zhp)
*/
int
zpool_create(libzfs_handle_t *hdl, const char *pool, nvlist_t *nvroot,
nvlist_t *props)
nvlist_t *props, nvlist_t *fsprops)
{
zfs_cmd_t zc = { 0 };
nvlist_t *zc_fsprops = NULL;
nvlist_t *zc_props = NULL;
char msg[1024];
char *altroot;
int ret = -1;
(void) snprintf(msg, sizeof (msg), dgettext(TEXT_DOMAIN,
"cannot create '%s'"), pool);
@@ -766,21 +845,45 @@ zpool_create(libzfs_handle_t *hdl, const char *pool, nvlist_t *nvroot,
if (zcmd_write_conf_nvlist(hdl, &zc, nvroot) != 0)
return (-1);
if (props && (props = zpool_validate_properties(hdl, pool, props,
SPA_VERSION_1, B_TRUE, msg)) == NULL)
return (-1);
if (props && zcmd_write_src_nvlist(hdl, &zc, props) != 0) {
nvlist_free(props);
return (-1);
if (props) {
if ((zc_props = zpool_valid_proplist(hdl, pool, props,
SPA_VERSION_1, B_TRUE, msg)) == NULL) {
goto create_failed;
}
}
if (fsprops) {
uint64_t zoned;
char *zonestr;
zoned = ((nvlist_lookup_string(fsprops,
zfs_prop_to_name(ZFS_PROP_ZONED), &zonestr) == 0) &&
strcmp(zonestr, "on") == 0);
if ((zc_fsprops = zfs_valid_proplist(hdl,
ZFS_TYPE_FILESYSTEM, fsprops, zoned, NULL, msg)) == NULL) {
goto create_failed;
}
if (!zc_props &&
(nvlist_alloc(&zc_props, NV_UNIQUE_NAME, 0) != 0)) {
goto create_failed;
}
if (nvlist_add_nvlist(zc_props,
ZPOOL_ROOTFS_PROPS, zc_fsprops) != 0) {
goto create_failed;
}
}
if (zc_props && zcmd_write_src_nvlist(hdl, &zc, zc_props) != 0)
goto create_failed;
(void) strlcpy(zc.zc_name, pool, sizeof (zc.zc_name));
if (zfs_ioctl(hdl, ZFS_IOC_POOL_CREATE, &zc) != 0) {
if ((ret = zfs_ioctl(hdl, ZFS_IOC_POOL_CREATE, &zc)) != 0) {
zcmd_free_nvlists(&zc);
nvlist_free(props);
nvlist_free(zc_props);
nvlist_free(zc_fsprops);
switch (errno) {
case EBUSY:
@@ -842,9 +945,11 @@ zpool_create(libzfs_handle_t *hdl, const char *pool, nvlist_t *nvroot,
zfs_close(zhp);
}
create_failed:
zcmd_free_nvlists(&zc);
nvlist_free(props);
return (0);
nvlist_free(zc_props);
nvlist_free(zc_fsprops);
return (ret);
}
/*
@@ -920,6 +1025,24 @@ zpool_add(zpool_handle_t *zhp, nvlist_t *nvroot)
return (zfs_error(hdl, EZFS_BADVERSION, msg));
}
if (pool_is_bootable(zhp) && nvlist_lookup_nvlist_array(nvroot,
ZPOOL_CONFIG_SPARES, &spares, &nspares) == 0) {
uint64_t s;
for (s = 0; s < nspares; s++) {
char *path;
if (nvlist_lookup_string(spares[s], ZPOOL_CONFIG_PATH,
&path) == 0 && pool_uses_efi(spares[s])) {
zfs_error_aux(hdl, dgettext(TEXT_DOMAIN,
"device '%s' contains an EFI label and "
"cannot be used on root pools."),
zpool_vdev_name(hdl, NULL, spares[s]));
return (zfs_error(hdl, EZFS_POOL_NOTSUP, msg));
}
}
}
if (zpool_get_prop_int(zhp, ZPOOL_PROP_VERSION, NULL) <
SPA_VERSION_L2CACHE &&
nvlist_lookup_nvlist_array(nvroot, ZPOOL_CONFIG_L2CACHE,
@@ -1004,19 +1127,36 @@ zpool_add(zpool_handle_t *zhp, nvlist_t *nvroot)
* mounted datasets in the pool.
*/
int
zpool_export(zpool_handle_t *zhp)
zpool_export(zpool_handle_t *zhp, boolean_t force)
{
zfs_cmd_t zc = { 0 };
char msg[1024];
if (zpool_remove_zvol_links(zhp) != 0)
return (-1);
(void) strlcpy(zc.zc_name, zhp->zpool_name, sizeof (zc.zc_name));
(void) snprintf(msg, sizeof (msg), dgettext(TEXT_DOMAIN,
"cannot export '%s'"), zhp->zpool_name);
(void) strlcpy(zc.zc_name, zhp->zpool_name, sizeof (zc.zc_name));
zc.zc_cookie = force;
if (zfs_ioctl(zhp->zpool_hdl, ZFS_IOC_POOL_EXPORT, &zc) != 0) {
switch (errno) {
case EXDEV:
zfs_error_aux(zhp->zpool_hdl, dgettext(TEXT_DOMAIN,
"use '-f' to override the following errors:\n"
"'%s' has an active shared spare which could be"
" used by other pools once '%s' is exported."),
zhp->zpool_name, zhp->zpool_name);
return (zfs_error(zhp->zpool_hdl, EZFS_ACTIVE_SPARE,
msg));
default:
return (zpool_standard_error_fmt(zhp->zpool_hdl, errno,
msg));
}
}
if (zfs_ioctl(zhp->zpool_hdl, ZFS_IOC_POOL_EXPORT, &zc) != 0)
return (zpool_standard_error_fmt(zhp->zpool_hdl, errno,
dgettext(TEXT_DOMAIN, "cannot export '%s'"),
zhp->zpool_name));
return (0);
}
@@ -1050,7 +1190,7 @@ zpool_import(libzfs_handle_t *hdl, nvlist_t *config, const char *newname,
}
}
ret = zpool_import_props(hdl, config, newname, props);
ret = zpool_import_props(hdl, config, newname, props, B_FALSE);
if (props)
nvlist_free(props);
return (ret);
@@ -1064,7 +1204,7 @@ zpool_import(libzfs_handle_t *hdl, nvlist_t *config, const char *newname,
*/
int
zpool_import_props(libzfs_handle_t *hdl, nvlist_t *config, const char *newname,
nvlist_t *props)
nvlist_t *props, boolean_t importfaulted)
{
zfs_cmd_t zc = { 0 };
char *thename;
@@ -1094,7 +1234,7 @@ zpool_import_props(libzfs_handle_t *hdl, nvlist_t *config, const char *newname,
verify(nvlist_lookup_uint64(config, ZPOOL_CONFIG_VERSION,
&version) == 0);
if ((props = zpool_validate_properties(hdl, origname,
if ((props = zpool_valid_proplist(hdl, origname,
props, version, B_TRUE, errbuf)) == NULL) {
return (-1);
} else if (zcmd_write_src_nvlist(hdl, &zc, props) != 0) {
@@ -1113,6 +1253,7 @@ zpool_import_props(libzfs_handle_t *hdl, nvlist_t *config, const char *newname,
return (-1);
}
zc.zc_cookie = (uint64_t)importfaulted;
ret = 0;
if (zfs_ioctl(hdl, ZFS_IOC_POOL_IMPORT, &zc) != 0) {
char desc[1024];
@@ -1194,7 +1335,7 @@ zpool_scrub(zpool_handle_t *zhp, pool_scrub_type_t type)
*/
static nvlist_t *
vdev_to_nvlist_iter(nvlist_t *nv, const char *search, uint64_t guid,
boolean_t *avail_spare, boolean_t *l2cache)
boolean_t *avail_spare, boolean_t *l2cache, boolean_t *log)
{
uint_t c, children;
nvlist_t **child;
@@ -1202,6 +1343,7 @@ vdev_to_nvlist_iter(nvlist_t *nv, const char *search, uint64_t guid,
char *path;
uint64_t wholedisk = 0;
nvlist_t *ret;
uint64_t is_log;
verify(nvlist_lookup_uint64(nv, ZPOOL_CONFIG_GUID, &theguid) == 0);
@@ -1234,16 +1376,30 @@ vdev_to_nvlist_iter(nvlist_t *nv, const char *search, uint64_t guid,
&child, &children) != 0)
return (NULL);
for (c = 0; c < children; c++)
for (c = 0; c < children; c++) {
if ((ret = vdev_to_nvlist_iter(child[c], search, guid,
avail_spare, l2cache)) != NULL)
avail_spare, l2cache, NULL)) != NULL) {
/*
* The 'is_log' value is only set for the toplevel
* vdev, not the leaf vdevs. So we always lookup the
* log device from the root of the vdev tree (where
* 'log' is non-NULL).
*/
if (log != NULL &&
nvlist_lookup_uint64(child[c],
ZPOOL_CONFIG_IS_LOG, &is_log) == 0 &&
is_log) {
*log = B_TRUE;
}
return (ret);
}
}
if (nvlist_lookup_nvlist_array(nv, ZPOOL_CONFIG_SPARES,
&child, &children) == 0) {
for (c = 0; c < children; c++) {
if ((ret = vdev_to_nvlist_iter(child[c], search, guid,
avail_spare, l2cache)) != NULL) {
avail_spare, l2cache, NULL)) != NULL) {
*avail_spare = B_TRUE;
return (ret);
}
@@ -1254,7 +1410,7 @@ vdev_to_nvlist_iter(nvlist_t *nv, const char *search, uint64_t guid,
&child, &children) == 0) {
for (c = 0; c < children; c++) {
if ((ret = vdev_to_nvlist_iter(child[c], search, guid,
avail_spare, l2cache)) != NULL) {
avail_spare, l2cache, NULL)) != NULL) {
*l2cache = B_TRUE;
return (ret);
}
@@ -1266,7 +1422,7 @@ vdev_to_nvlist_iter(nvlist_t *nv, const char *search, uint64_t guid,
nvlist_t *
zpool_find_vdev(zpool_handle_t *zhp, const char *path, boolean_t *avail_spare,
boolean_t *l2cache)
boolean_t *l2cache, boolean_t *log)
{
char buf[MAXPATHLEN];
const char *search;
@@ -1289,8 +1445,98 @@ zpool_find_vdev(zpool_handle_t *zhp, const char *path, boolean_t *avail_spare,
*avail_spare = B_FALSE;
*l2cache = B_FALSE;
if (log != NULL)
*log = B_FALSE;
return (vdev_to_nvlist_iter(nvroot, search, guid, avail_spare,
l2cache));
l2cache, log));
}
static int
vdev_online(nvlist_t *nv)
{
uint64_t ival;
if (nvlist_lookup_uint64(nv, ZPOOL_CONFIG_OFFLINE, &ival) == 0 ||
nvlist_lookup_uint64(nv, ZPOOL_CONFIG_FAULTED, &ival) == 0 ||
nvlist_lookup_uint64(nv, ZPOOL_CONFIG_REMOVED, &ival) == 0)
return (0);
return (1);
}
/*
* Get phys_path for a root pool
* Return 0 on success; non-zeron on failure.
*/
int
zpool_get_physpath(zpool_handle_t *zhp, char *physpath)
{
nvlist_t *vdev_root;
nvlist_t **child;
uint_t count;
int i;
/*
* Make sure this is a root pool, as phys_path doesn't mean
* anything to a non-root pool.
*/
if (!pool_is_bootable(zhp))
return (-1);
verify(nvlist_lookup_nvlist(zhp->zpool_config,
ZPOOL_CONFIG_VDEV_TREE, &vdev_root) == 0);
if (nvlist_lookup_nvlist_array(vdev_root, ZPOOL_CONFIG_CHILDREN,
&child, &count) != 0)
return (-2);
for (i = 0; i < count; i++) {
nvlist_t **child2;
uint_t count2;
char *type;
char *tmppath;
int j;
if (nvlist_lookup_string(child[i], ZPOOL_CONFIG_TYPE, &type)
!= 0)
return (-3);
if (strcmp(type, VDEV_TYPE_DISK) == 0) {
if (!vdev_online(child[i]))
return (-8);
verify(nvlist_lookup_string(child[i],
ZPOOL_CONFIG_PHYS_PATH, &tmppath) == 0);
(void) strncpy(physpath, tmppath, strlen(tmppath));
} else if (strcmp(type, VDEV_TYPE_MIRROR) == 0) {
if (nvlist_lookup_nvlist_array(child[i],
ZPOOL_CONFIG_CHILDREN, &child2, &count2) != 0)
return (-4);
for (j = 0; j < count2; j++) {
if (!vdev_online(child2[j]))
return (-8);
if (nvlist_lookup_string(child2[j],
ZPOOL_CONFIG_PHYS_PATH, &tmppath) != 0)
return (-5);
if ((strlen(physpath) + strlen(tmppath)) >
MAXNAMELEN)
return (-6);
if (strlen(physpath) == 0) {
(void) strncpy(physpath, tmppath,
strlen(tmppath));
} else {
(void) strcat(physpath, " ");
(void) strcat(physpath, tmppath);
}
}
} else {
return (-7);
}
}
return (0);
}
/*
@@ -1339,7 +1585,8 @@ zpool_vdev_online(zpool_handle_t *zhp, const char *path, int flags,
dgettext(TEXT_DOMAIN, "cannot online %s"), path);
(void) strlcpy(zc.zc_name, zhp->zpool_name, sizeof (zc.zc_name));
if ((tgt = zpool_find_vdev(zhp, path, &avail_spare, &l2cache)) == NULL)
if ((tgt = zpool_find_vdev(zhp, path, &avail_spare, &l2cache,
NULL)) == NULL)
return (zfs_error(hdl, EZFS_NODEVICE, msg));
verify(nvlist_lookup_uint64(tgt, ZPOOL_CONFIG_GUID, &zc.zc_guid) == 0);
@@ -1348,14 +1595,9 @@ zpool_vdev_online(zpool_handle_t *zhp, const char *path, int flags,
is_guid_type(zhp, zc.zc_guid, ZPOOL_CONFIG_SPARES) == B_TRUE)
return (zfs_error(hdl, EZFS_ISSPARE, msg));
if (l2cache ||
is_guid_type(zhp, zc.zc_guid, ZPOOL_CONFIG_L2CACHE) == B_TRUE)
return (zfs_error(hdl, EZFS_ISL2CACHE, msg));
zc.zc_cookie = VDEV_STATE_ONLINE;
zc.zc_obj = flags;
if (zfs_ioctl(zhp->zpool_hdl, ZFS_IOC_VDEV_SET_STATE, &zc) != 0)
return (zpool_standard_error(hdl, errno, msg));
@@ -1379,7 +1621,8 @@ zpool_vdev_offline(zpool_handle_t *zhp, const char *path, boolean_t istmp)
dgettext(TEXT_DOMAIN, "cannot offline %s"), path);
(void) strlcpy(zc.zc_name, zhp->zpool_name, sizeof (zc.zc_name));
if ((tgt = zpool_find_vdev(zhp, path, &avail_spare, &l2cache)) == NULL)
if ((tgt = zpool_find_vdev(zhp, path, &avail_spare, &l2cache,
NULL)) == NULL)
return (zfs_error(hdl, EZFS_NODEVICE, msg));
verify(nvlist_lookup_uint64(tgt, ZPOOL_CONFIG_GUID, &zc.zc_guid) == 0);
@@ -1388,10 +1631,6 @@ zpool_vdev_offline(zpool_handle_t *zhp, const char *path, boolean_t istmp)
is_guid_type(zhp, zc.zc_guid, ZPOOL_CONFIG_SPARES) == B_TRUE)
return (zfs_error(hdl, EZFS_ISSPARE, msg));
if (l2cache ||
is_guid_type(zhp, zc.zc_guid, ZPOOL_CONFIG_L2CACHE) == B_TRUE)
return (zfs_error(hdl, EZFS_ISL2CACHE, msg));
zc.zc_cookie = VDEV_STATE_OFFLINE;
zc.zc_obj = istmp ? ZFS_OFFLINE_TEMPORARY : 0;
@@ -1508,13 +1747,14 @@ zpool_vdev_attach(zpool_handle_t *zhp,
char msg[1024];
int ret;
nvlist_t *tgt;
boolean_t avail_spare, l2cache;
uint64_t val, is_log;
char *path;
boolean_t avail_spare, l2cache, islog;
uint64_t val;
char *path, *newname;
nvlist_t **child;
uint_t children;
nvlist_t *config_root;
libzfs_handle_t *hdl = zhp->zpool_hdl;
boolean_t rootpool = pool_is_bootable(zhp);
if (replacing)
(void) snprintf(msg, sizeof (msg), dgettext(TEXT_DOMAIN,
@@ -1523,8 +1763,19 @@ zpool_vdev_attach(zpool_handle_t *zhp,
(void) snprintf(msg, sizeof (msg), dgettext(TEXT_DOMAIN,
"cannot attach %s to %s"), new_disk, old_disk);
/*
* If this is a root pool, make sure that we're not attaching an
* EFI labeled device.
*/
if (rootpool && pool_uses_efi(nvroot)) {
zfs_error_aux(hdl, dgettext(TEXT_DOMAIN,
"EFI labeled devices are not supported on root pools."));
return (zfs_error(hdl, EZFS_POOL_NOTSUP, msg));
}
(void) strlcpy(zc.zc_name, zhp->zpool_name, sizeof (zc.zc_name));
if ((tgt = zpool_find_vdev(zhp, old_disk, &avail_spare, &l2cache)) == 0)
if ((tgt = zpool_find_vdev(zhp, old_disk, &avail_spare, &l2cache,
&islog)) == 0)
return (zfs_error(hdl, EZFS_NODEVICE, msg));
if (avail_spare)
@@ -1546,17 +1797,21 @@ zpool_vdev_attach(zpool_handle_t *zhp,
verify(nvlist_lookup_nvlist(zpool_get_config(zhp, NULL),
ZPOOL_CONFIG_VDEV_TREE, &config_root) == 0);
if ((newname = zpool_vdev_name(NULL, NULL, child[0])) == NULL)
return (-1);
/*
* If the target is a hot spare that has been swapped in, we can only
* replace it with another hot spare.
*/
if (replacing &&
nvlist_lookup_uint64(tgt, ZPOOL_CONFIG_IS_SPARE, &val) == 0 &&
nvlist_lookup_string(child[0], ZPOOL_CONFIG_PATH, &path) == 0 &&
(zpool_find_vdev(zhp, path, &avail_spare, &l2cache) == NULL ||
!avail_spare) && is_replacing_spare(config_root, tgt, 1)) {
(zpool_find_vdev(zhp, newname, &avail_spare, &l2cache,
NULL) == NULL || !avail_spare) &&
is_replacing_spare(config_root, tgt, 1)) {
zfs_error_aux(hdl, dgettext(TEXT_DOMAIN,
"can only be replaced by another hot spare"));
free(newname);
return (zfs_error(hdl, EZFS_BADTARGET, msg));
}
@@ -1566,13 +1821,17 @@ zpool_vdev_attach(zpool_handle_t *zhp,
*/
if (replacing &&
nvlist_lookup_string(child[0], ZPOOL_CONFIG_PATH, &path) == 0 &&
zpool_find_vdev(zhp, path, &avail_spare, &l2cache) != NULL &&
avail_spare && is_replacing_spare(config_root, tgt, 0)) {
zpool_find_vdev(zhp, newname, &avail_spare,
&l2cache, NULL) != NULL && avail_spare &&
is_replacing_spare(config_root, tgt, 0)) {
zfs_error_aux(hdl, dgettext(TEXT_DOMAIN,
"device has already been replaced with a spare"));
free(newname);
return (zfs_error(hdl, EZFS_BADTARGET, msg));
}
free(newname);
if (zcmd_write_conf_nvlist(hdl, &zc, nvroot) != 0)
return (-1);
@@ -1580,8 +1839,19 @@ zpool_vdev_attach(zpool_handle_t *zhp,
zcmd_free_nvlists(&zc);
if (ret == 0)
if (ret == 0) {
if (rootpool) {
/*
* XXX - This should be removed once we can
* automatically install the bootblocks on the
* newly attached disk.
*/
(void) fprintf(stderr, dgettext(TEXT_DOMAIN, "Please "
"be sure to invoke %s to make '%s' bootable.\n"),
BOOTCMD, new_disk);
}
return (0);
}
switch (errno) {
case ENOTSUP:
@@ -1589,10 +1859,7 @@ zpool_vdev_attach(zpool_handle_t *zhp,
* Can't attach to or replace this type of vdev.
*/
if (replacing) {
is_log = B_FALSE;
(void) nvlist_lookup_uint64(tgt, ZPOOL_CONFIG_IS_LOG,
&is_log);
if (is_log)
if (islog)
zfs_error_aux(hdl, dgettext(TEXT_DOMAIN,
"cannot replace a log with a spare"));
else
@@ -1669,7 +1936,8 @@ zpool_vdev_detach(zpool_handle_t *zhp, const char *path)
dgettext(TEXT_DOMAIN, "cannot detach %s"), path);
(void) strlcpy(zc.zc_name, zhp->zpool_name, sizeof (zc.zc_name));
if ((tgt = zpool_find_vdev(zhp, path, &avail_spare, &l2cache)) == 0)
if ((tgt = zpool_find_vdev(zhp, path, &avail_spare, &l2cache,
NULL)) == 0)
return (zfs_error(hdl, EZFS_NODEVICE, msg));
if (avail_spare)
@@ -1725,7 +1993,8 @@ zpool_vdev_remove(zpool_handle_t *zhp, const char *path)
dgettext(TEXT_DOMAIN, "cannot remove %s"), path);
(void) strlcpy(zc.zc_name, zhp->zpool_name, sizeof (zc.zc_name));
if ((tgt = zpool_find_vdev(zhp, path, &avail_spare, &l2cache)) == 0)
if ((tgt = zpool_find_vdev(zhp, path, &avail_spare, &l2cache,
NULL)) == 0)
return (zfs_error(hdl, EZFS_NODEVICE, msg));
if (!avail_spare && !l2cache) {
@@ -1767,7 +2036,7 @@ zpool_clear(zpool_handle_t *zhp, const char *path)
(void) strlcpy(zc.zc_name, zhp->zpool_name, sizeof (zc.zc_name));
if (path) {
if ((tgt = zpool_find_vdev(zhp, path, &avail_spare,
&l2cache)) == 0)
&l2cache, NULL)) == 0)
return (zfs_error(hdl, EZFS_NODEVICE, msg));
/*
@@ -2503,6 +2772,38 @@ zpool_obj_to_path(zpool_handle_t *zhp, uint64_t dsobj, uint64_t obj,
*/
#define NEW_START_BLOCK 256
/*
* Read the EFI label from the config, if a label does not exist then
* pass back the error to the caller. If the caller has passed a non-NULL
* diskaddr argument then we set it to the starting address of the EFI
* partition.
*/
static int
read_efi_label(nvlist_t *config, diskaddr_t *sb)
{
char *path;
int fd;
char diskname[MAXPATHLEN];
int err = -1;
if (nvlist_lookup_string(config, ZPOOL_CONFIG_PATH, &path) != 0)
return (err);
(void) snprintf(diskname, sizeof (diskname), "%s%s", RDISK_ROOT,
strrchr(path, '/'));
if ((fd = open(diskname, O_RDONLY|O_NDELAY)) >= 0) {
struct dk_gpt *vtoc;
if ((err = efi_alloc_and_read(fd, &vtoc)) >= 0) {
if (sb != NULL)
*sb = vtoc->efi_parts[0].p_start;
efi_free(vtoc);
}
(void) close(fd);
}
return (err);
}
/*
* determine where a partition starts on a disk in the current
* configuration
@@ -2512,10 +2813,7 @@ find_start_block(nvlist_t *config)
{
nvlist_t **child;
uint_t c, children;
char *path;
diskaddr_t sb = MAXOFFSET_T;
int fd;
char diskname[MAXPATHLEN];
uint64_t wholedisk;
if (nvlist_lookup_nvlist_array(config,
@@ -2525,21 +2823,8 @@ find_start_block(nvlist_t *config)
&wholedisk) != 0 || !wholedisk) {
return (MAXOFFSET_T);
}
if (nvlist_lookup_string(config,
ZPOOL_CONFIG_PATH, &path) != 0) {
return (MAXOFFSET_T);
}
(void) snprintf(diskname, sizeof (diskname), "%s%s",
RDISK_ROOT, strrchr(path, '/'));
if ((fd = open(diskname, O_RDONLY|O_NDELAY)) >= 0) {
struct dk_gpt *vtoc;
if (efi_alloc_and_read(fd, &vtoc) >= 0) {
sb = vtoc->efi_parts[0].p_start;
efi_free(vtoc);
}
(void) close(fd);
}
if (read_efi_label(config, &sb) < 0)
sb = MAXOFFSET_T;
return (sb);
}
@@ -2574,6 +2859,13 @@ zpool_label_disk(libzfs_handle_t *hdl, zpool_handle_t *zhp, char *name)
if (zhp) {
nvlist_t *nvroot;
if (pool_is_bootable(zhp)) {
zfs_error_aux(hdl, dgettext(TEXT_DOMAIN,
"EFI labeled devices are not supported on root "
"pools."));
return (zfs_error(hdl, EZFS_POOL_NOTSUP, errbuf));
}
verify(nvlist_lookup_nvlist(zhp->zpool_config,
ZPOOL_CONFIG_VDEV_TREE, &nvroot) == 0);
+120 -25
View File
@@ -24,8 +24,6 @@
* Use is subject to license terms.
*/
#pragma ident "@(#)libzfs_sendrecv.c 1.7 08/04/23 SMI"
#include <assert.h>
#include <ctype.h>
#include <errno.h>
@@ -51,6 +49,9 @@
#include <fletcher.c> /* XXX */
static int zfs_receive_impl(libzfs_handle_t *, const char *, recvflags_t,
int, avl_tree_t *, char **);
/*
* Routines for dealing with the AVL tree of fs-nvlists
*/
@@ -166,6 +167,7 @@ typedef struct send_data {
uint64_t parent_fromsnap_guid;
nvlist_t *parent_snaps;
nvlist_t *fss;
nvlist_t *snapprops;
const char *fromsnap;
const char *tosnap;
@@ -182,6 +184,7 @@ typedef struct send_data {
*
* "props" -> { name -> value (only if set here) }
* "snaps" -> { name (lastname) -> number (guid) }
* "snapprops" -> { name (lastname) -> { name -> value } }
*
* "origin" -> number (guid) (if clone)
* "sent" -> boolean (not on-disk)
@@ -192,12 +195,15 @@ typedef struct send_data {
*/
} send_data_t;
static void send_iterate_prop(zfs_handle_t *zhp, nvlist_t *nv);
static int
send_iterate_snap(zfs_handle_t *zhp, void *arg)
{
send_data_t *sd = arg;
uint64_t guid = zhp->zfs_dmustats.dds_guid;
char *snapname;
nvlist_t *nv;
snapname = strrchr(zhp->zfs_name, '@')+1;
@@ -212,6 +218,11 @@ send_iterate_snap(zfs_handle_t *zhp, void *arg)
sd->parent_fromsnap_guid = guid;
}
VERIFY(0 == nvlist_alloc(&nv, NV_UNIQUE_NAME, 0));
send_iterate_prop(zhp, nv);
VERIFY(0 == nvlist_add_nvlist(sd->snapprops, snapname, nv));
nvlist_free(nv);
zfs_close(zhp);
return (0);
}
@@ -235,6 +246,8 @@ send_iterate_prop(zfs_handle_t *zhp, nvlist_t *nv)
uint64_t value;
verify(nvlist_lookup_uint64(propnv,
ZPROP_VALUE, &value) == 0);
if (zhp->zfs_type == ZFS_TYPE_SNAPSHOT)
continue;
} else {
char *source;
if (nvlist_lookup_string(propnv,
@@ -292,9 +305,12 @@ send_iterate_fs(zfs_handle_t *zhp, void *arg)
/* iterate over snaps, and set sd->parent_fromsnap_guid */
sd->parent_fromsnap_guid = 0;
VERIFY(0 == nvlist_alloc(&sd->parent_snaps, NV_UNIQUE_NAME, 0));
VERIFY(0 == nvlist_alloc(&sd->snapprops, NV_UNIQUE_NAME, 0));
(void) zfs_iter_snapshots(zhp, send_iterate_snap, sd);
VERIFY(0 == nvlist_add_nvlist(nvfs, "snaps", sd->parent_snaps));
VERIFY(0 == nvlist_add_nvlist(nvfs, "snapprops", sd->snapprops));
nvlist_free(sd->parent_snaps);
nvlist_free(sd->snapprops);
/* add this fs to nvlist */
(void) snprintf(guidstring, sizeof (guidstring),
@@ -867,7 +883,8 @@ recv_rename(libzfs_handle_t *hdl, const char *name, const char *tryname,
zhp = zfs_open(hdl, name, ZFS_TYPE_DATASET);
if (zhp == NULL)
return (-1);
clp = changelist_gather(zhp, ZFS_PROP_NAME, flags.force ? MS_FORCE : 0);
clp = changelist_gather(zhp, ZFS_PROP_NAME, 0,
flags.force ? MS_FORCE : 0);
zfs_close(zhp);
if (clp == NULL)
return (-1);
@@ -938,7 +955,8 @@ recv_destroy(libzfs_handle_t *hdl, const char *name, int baselen,
zhp = zfs_open(hdl, name, ZFS_TYPE_DATASET);
if (zhp == NULL)
return (-1);
clp = changelist_gather(zhp, ZFS_PROP_NAME, flags.force ? MS_FORCE : 0);
clp = changelist_gather(zhp, ZFS_PROP_NAME, 0,
flags.force ? MS_FORCE : 0);
zfs_close(zhp);
if (clp == NULL)
return (-1);
@@ -1180,7 +1198,7 @@ again:
snapelem; snapelem = nextsnapelem) {
uint64_t thisguid;
char *stream_snapname;
nvlist_t *found;
nvlist_t *found, *props;
nextsnapelem = nvlist_next_nvpair(snaps, snapelem);
@@ -1209,6 +1227,22 @@ again:
stream_nvfs = found;
if (0 == nvlist_lookup_nvlist(stream_nvfs, "snapprops",
&props) && 0 == nvlist_lookup_nvlist(props,
stream_snapname, &props)) {
zfs_cmd_t zc = { 0 };
zc.zc_cookie = B_TRUE; /* clear current props */
(void) snprintf(zc.zc_name, sizeof (zc.zc_name),
"%s@%s", fsname, nvpair_name(snapelem));
if (zcmd_write_src_nvlist(hdl, &zc,
props) == 0) {
(void) zfs_ioctl(hdl,
ZFS_IOC_SET_PROP, &zc);
zcmd_free_nvlists(&zc);
}
}
/* check for different snapname */
if (strcmp(nvpair_name(snapelem),
stream_snapname) != 0) {
@@ -1314,7 +1348,8 @@ again:
static int
zfs_receive_package(libzfs_handle_t *hdl, int fd, const char *destname,
recvflags_t flags, dmu_replay_record_t *drr, zio_cksum_t *zc)
recvflags_t flags, dmu_replay_record_t *drr, zio_cksum_t *zc,
char **top_zfs)
{
nvlist_t *stream_nv = NULL;
avl_tree_t *stream_avl = NULL;
@@ -1426,7 +1461,8 @@ zfs_receive_package(libzfs_handle_t *hdl, int fd, const char *destname,
* zfs_receive_one() will take care of it (ie,
* recv_skip() and return 0).
*/
error = zfs_receive(hdl, destname, flags, fd, stream_avl);
error = zfs_receive_impl(hdl, destname, flags, fd,
stream_avl, top_zfs);
if (error == ENODATA) {
error = 0;
break;
@@ -1492,7 +1528,7 @@ recv_skip(libzfs_handle_t *hdl, int fd, boolean_t byteswap)
case DRR_WRITE:
if (byteswap) {
drr->drr_u.drr_write.drr_length =
BSWAP_32(drr->drr_u.drr_write.drr_length);
BSWAP_64(drr->drr_u.drr_write.drr_length);
}
(void) recv_read(hdl, fd, buf,
drr->drr_u.drr_write.drr_length, B_FALSE, NULL);
@@ -1517,7 +1553,8 @@ recv_skip(libzfs_handle_t *hdl, int fd, boolean_t byteswap)
static int
zfs_receive_one(libzfs_handle_t *hdl, int infd, const char *tosnap,
recvflags_t flags, dmu_replay_record_t *drr,
dmu_replay_record_t *drr_noswap, avl_tree_t *stream_avl)
dmu_replay_record_t *drr_noswap, avl_tree_t *stream_avl,
char **top_zfs)
{
zfs_cmd_t zc = { 0 };
time_t begin_time;
@@ -1530,6 +1567,7 @@ zfs_receive_one(libzfs_handle_t *hdl, int infd, const char *tosnap,
boolean_t stream_wantsnewfs;
uint64_t parent_snapguid = 0;
prop_changelist_t *clp = NULL;
nvlist_t *snapprops_nvlist = NULL;
begin_time = time(NULL);
@@ -1537,7 +1575,9 @@ zfs_receive_one(libzfs_handle_t *hdl, int infd, const char *tosnap,
"cannot receive"));
if (stream_avl != NULL) {
nvlist_t *fs = fsavl_find(stream_avl, drrb->drr_toguid, NULL);
char *snapname;
nvlist_t *fs = fsavl_find(stream_avl, drrb->drr_toguid,
&snapname);
nvlist_t *props;
int ret;
@@ -1555,6 +1595,11 @@ zfs_receive_one(libzfs_handle_t *hdl, int infd, const char *tosnap,
if (err)
nvlist_free(props);
if (0 == nvlist_lookup_nvlist(fs, "snapprops", &props)) {
VERIFY(0 == nvlist_lookup_nvlist(props,
snapname, &snapprops_nvlist));
}
if (ret != 0)
return (-1);
}
@@ -1720,7 +1765,7 @@ zfs_receive_one(libzfs_handle_t *hdl, int infd, const char *tosnap,
if (!flags.dryrun && zhp->zfs_type == ZFS_TYPE_FILESYSTEM &&
stream_wantsnewfs) {
/* We can't do online recv in this case */
clp = changelist_gather(zhp, ZFS_PROP_NAME, 0);
clp = changelist_gather(zhp, ZFS_PROP_NAME, 0, 0);
if (clp == NULL) {
zcmd_free_nvlists(&zc);
return (-1);
@@ -1787,6 +1832,18 @@ zfs_receive_one(libzfs_handle_t *hdl, int infd, const char *tosnap,
err = ioctl_err = zfs_ioctl(hdl, ZFS_IOC_RECV, &zc);
ioctl_errno = errno;
zcmd_free_nvlists(&zc);
if (err == 0 && snapprops_nvlist) {
zfs_cmd_t zc2 = { 0 };
(void) strcpy(zc2.zc_name, zc.zc_value);
if (zcmd_write_src_nvlist(hdl, &zc2, snapprops_nvlist) == 0) {
(void) zfs_ioctl(hdl, ZFS_IOC_SET_PROP, &zc2);
zcmd_free_nvlists(&zc2);
}
}
if (err && (ioctl_errno == ENOENT || ioctl_errno == ENODEV)) {
/*
* It may be that this snapshot already exists,
@@ -1822,7 +1879,6 @@ zfs_receive_one(libzfs_handle_t *hdl, int infd, const char *tosnap,
*cp = '@';
}
zcmd_free_nvlists(&zc);
if (ioctl_err != 0) {
switch (ioctl_errno) {
@@ -1881,18 +1937,24 @@ zfs_receive_one(libzfs_handle_t *hdl, int infd, const char *tosnap,
*cp = '\0';
h = zfs_open(hdl, zc.zc_value,
ZFS_TYPE_FILESYSTEM | ZFS_TYPE_VOLUME);
*cp = '@';
if (h != NULL) {
if (h->zfs_type == ZFS_TYPE_VOLUME) {
*cp = '@';
err = zvol_create_link(hdl, h->zfs_name);
if (err == 0 && ioctl_err == 0)
err = zvol_create_link(hdl,
zc.zc_value);
} else if (newfs) {
err = zfs_mount(h, NULL, 0);
/*
* Track the first/top of hierarchy fs,
* for mounting and sharing later.
*/
if (top_zfs && *top_zfs == NULL)
*top_zfs = zfs_strdup(hdl, zc.zc_value);
}
zfs_close(h);
}
*cp = '@';
}
if (clp) {
@@ -1920,15 +1982,9 @@ zfs_receive_one(libzfs_handle_t *hdl, int infd, const char *tosnap,
return (0);
}
/*
* Restores a backup of tosnap from the file descriptor specified by infd.
* Return 0 on total success, -2 if some things couldn't be
* destroyed/renamed/promoted, -1 if some things couldn't be received.
* (-1 will override -2).
*/
int
zfs_receive(libzfs_handle_t *hdl, const char *tosnap, recvflags_t flags,
int infd, avl_tree_t *stream_avl)
static int
zfs_receive_impl(libzfs_handle_t *hdl, const char *tosnap, recvflags_t flags,
int infd, avl_tree_t *stream_avl, char **top_zfs)
{
int err;
dmu_replay_record_t drr, drr_noswap;
@@ -1994,10 +2050,10 @@ zfs_receive(libzfs_handle_t *hdl, const char *tosnap, recvflags_t flags,
if (drrb->drr_version == DMU_BACKUP_STREAM_VERSION) {
return (zfs_receive_one(hdl, infd, tosnap, flags,
&drr, &drr_noswap, stream_avl));
&drr, &drr_noswap, stream_avl, top_zfs));
} else if (drrb->drr_version == DMU_BACKUP_HEADER_VERSION) {
return (zfs_receive_package(hdl, infd, tosnap, flags,
&drr, &zcksum));
&drr, &zcksum, top_zfs));
} else {
zfs_error_aux(hdl, dgettext(TEXT_DOMAIN,
"stream is unsupported version %llu"),
@@ -2005,3 +2061,42 @@ zfs_receive(libzfs_handle_t *hdl, const char *tosnap, recvflags_t flags,
return (zfs_error(hdl, EZFS_BADSTREAM, errbuf));
}
}
/*
* Restores a backup of tosnap from the file descriptor specified by infd.
* Return 0 on total success, -2 if some things couldn't be
* destroyed/renamed/promoted, -1 if some things couldn't be received.
* (-1 will override -2).
*/
int
zfs_receive(libzfs_handle_t *hdl, const char *tosnap, recvflags_t flags,
int infd, avl_tree_t *stream_avl)
{
char *top_zfs = NULL;
int err;
err = zfs_receive_impl(hdl, tosnap, flags, infd, stream_avl, &top_zfs);
if (err == 0 && top_zfs) {
zfs_handle_t *zhp;
prop_changelist_t *clp;
zhp = zfs_open(hdl, top_zfs, ZFS_TYPE_FILESYSTEM);
if (zhp != NULL) {
clp = changelist_gather(zhp, ZFS_PROP_MOUNTPOINT,
CL_GATHER_MOUNT_ALWAYS, 0);
zfs_close(zhp);
if (clp != NULL) {
/* mount and share received datasets */
err = changelist_postfix(clp);
changelist_free(clp);
}
}
if (zhp == NULL || clp == NULL || err)
err = -1;
}
if (top_zfs)
free(top_zfs);
return (err);
}
+24 -4
View File
@@ -19,12 +19,10 @@
* CDDL HEADER END
*/
/*
* Copyright 2007 Sun Microsystems, Inc. All rights reserved.
* Copyright 2008 Sun Microsystems, Inc. All rights reserved.
* Use is subject to license terms.
*/
#pragma ident "@(#)libzfs_status.c 1.7 07/06/29 SMI"
/*
* This file contains the functions which analyze the status of a pool. This
* include both the status of an active pool, as well as the status exported
@@ -62,7 +60,10 @@ static char *zfs_msgid_table[] = {
"ZFS-8000-8A",
"ZFS-8000-9P",
"ZFS-8000-A5",
"ZFS-8000-EY"
"ZFS-8000-EY",
"ZFS-8000-HC",
"ZFS-8000-JQ",
"ZFS-8000-K4",
};
#define NMSGID (sizeof (zfs_msgid_table) / sizeof (zfs_msgid_table[0]))
@@ -169,6 +170,7 @@ check_status(nvlist_t *config, boolean_t isimport)
uint64_t nerr;
uint64_t version;
uint64_t stateval;
uint64_t suspended;
uint64_t hostid = 0;
verify(nvlist_lookup_uint64(config, ZPOOL_CONFIG_VERSION,
@@ -202,6 +204,24 @@ check_status(nvlist_t *config, boolean_t isimport)
vs->vs_aux == VDEV_AUX_BAD_GUID_SUM)
return (ZPOOL_STATUS_BAD_GUID_SUM);
/*
* Check whether the pool has suspended due to failed I/O.
*/
if (nvlist_lookup_uint64(config, ZPOOL_CONFIG_SUSPENDED,
&suspended) == 0) {
if (suspended == ZIO_FAILURE_MODE_CONTINUE)
return (ZPOOL_STATUS_IO_FAILURE_CONTINUE);
return (ZPOOL_STATUS_IO_FAILURE_WAIT);
}
/*
* Could not read a log.
*/
if (vs->vs_state == VDEV_STATE_CANT_OPEN &&
vs->vs_aux == VDEV_AUX_BAD_LOG) {
return (ZPOOL_STATUS_BAD_LOG);
}
/*
* Bad devices in non-replicated config.
*/
+86 -52
View File
@@ -23,8 +23,6 @@
* Use is subject to license terms.
*/
#pragma ident "@(#)libzfs_util.c 1.29 08/04/01 SMI"
/*
* Internal utility routines for the ZFS library.
*/
@@ -206,6 +204,12 @@ libzfs_error_description(libzfs_handle_t *hdl)
case EZFS_VDEVNOTSUP:
return (dgettext(TEXT_DOMAIN, "vdev specification is not "
"supported"));
case EZFS_NOTSUP:
return (dgettext(TEXT_DOMAIN, "operation not supported "
"on this dataset"));
case EZFS_ACTIVE_SPARE:
return (dgettext(TEXT_DOMAIN, "pool has active shared spare "
"device"));
case EZFS_UNKNOWN:
return (dgettext(TEXT_DOMAIN, "unknown error"));
default:
@@ -408,7 +412,7 @@ zpool_standard_error_fmt(libzfs_handle_t *hdl, int error, const char *fmt, ...)
case EBUSY:
zfs_error_aux(hdl, dgettext(TEXT_DOMAIN, "pool is busy"));
zfs_verror(hdl, EZFS_EXISTS, fmt, ap);
zfs_verror(hdl, EZFS_BUSY, fmt, ap);
break;
case ENXIO:
@@ -587,6 +591,7 @@ libzfs_fini(libzfs_handle_t *hdl)
zfs_uninit_libshare(hdl);
if (hdl->libzfs_log_str)
(void) free(hdl->libzfs_log_str);
zpool_free_handles(hdl);
namespace_clear(hdl);
free(hdl);
}
@@ -603,6 +608,12 @@ zfs_get_handle(zfs_handle_t *zhp)
return (zhp->zfs_hdl);
}
zpool_handle_t *
zfs_get_pool_handle(const zfs_handle_t *zhp)
{
return (zhp->zpool_hdl);
}
/*
* Given a name, determine whether or not it's a valid path
* (starts with '/' or "./"). If so, walk the mnttab trying
@@ -1173,6 +1184,51 @@ error:
return (-1);
}
static int
addlist(libzfs_handle_t *hdl, char *propname, zprop_list_t **listp,
zfs_type_t type)
{
int prop;
zprop_list_t *entry;
prop = zprop_name_to_prop(propname, type);
if (prop != ZPROP_INVAL && !zprop_valid_for_type(prop, type))
prop = ZPROP_INVAL;
/*
* When no property table entry can be found, return failure if
* this is a pool property or if this isn't a user-defined
* dataset property,
*/
if (prop == ZPROP_INVAL && (type == ZFS_TYPE_POOL ||
!zfs_prop_user(propname))) {
zfs_error_aux(hdl, dgettext(TEXT_DOMAIN,
"invalid property '%s'"), propname);
return (zfs_error(hdl, EZFS_BADPROP,
dgettext(TEXT_DOMAIN, "bad property list")));
}
if ((entry = zfs_alloc(hdl, sizeof (zprop_list_t))) == NULL)
return (-1);
entry->pl_prop = prop;
if (prop == ZPROP_INVAL) {
if ((entry->pl_user_prop = zfs_strdup(hdl, propname)) == NULL) {
free(entry);
return (-1);
}
entry->pl_width = strlen(propname);
} else {
entry->pl_width = zprop_width(prop, &entry->pl_fixed,
type);
}
*listp = entry;
return (0);
}
/*
* Given a comma-separated list of properties, construct a property list
* containing both user-defined and native properties. This function will
@@ -1183,15 +1239,7 @@ int
zprop_get_list(libzfs_handle_t *hdl, char *props, zprop_list_t **listp,
zfs_type_t type)
{
size_t len;
char *s, *p;
char c;
int prop;
zprop_list_t *entry;
zprop_list_t **last;
*listp = NULL;
last = listp;
/*
* If 'all' is specified, return a NULL list.
@@ -1213,13 +1261,16 @@ zprop_get_list(libzfs_handle_t *hdl, char *props, zprop_list_t **listp,
* It would be nice to use getsubopt() here, but the inclusion of column
* aliases makes this more effort than it's worth.
*/
s = props;
while (*s != '\0') {
if ((p = strchr(s, ',')) == NULL) {
len = strlen(s);
p = s + len;
while (*props != '\0') {
size_t len;
char *p;
char c;
if ((p = strchr(props, ',')) == NULL) {
len = strlen(props);
p = props + len;
} else {
len = p - s;
len = p - props;
}
/*
@@ -1235,48 +1286,31 @@ zprop_get_list(libzfs_handle_t *hdl, char *props, zprop_list_t **listp,
/*
* Check all regular property names.
*/
c = s[len];
s[len] = '\0';
prop = zprop_name_to_prop(s, type);
c = props[len];
props[len] = '\0';
if (prop != ZPROP_INVAL && !zprop_valid_for_type(prop, type))
prop = ZPROP_INVAL;
if (strcmp(props, "space") == 0) {
static char *spaceprops[] = {
"name", "avail", "used", "usedbysnapshots",
"usedbydataset", "usedbyrefreservation",
"usedbychildren", NULL
};
int i;
/*
* When no property table entry can be found, return failure if
* this is a pool property or if this isn't a user-defined
* dataset property,
*/
if (prop == ZPROP_INVAL && (type == ZFS_TYPE_POOL ||
!zfs_prop_user(s))) {
zfs_error_aux(hdl, dgettext(TEXT_DOMAIN,
"invalid property '%s'"), s);
return (zfs_error(hdl, EZFS_BADPROP,
dgettext(TEXT_DOMAIN, "bad property list")));
}
if ((entry = zfs_alloc(hdl, sizeof (zprop_list_t))) == NULL)
return (-1);
entry->pl_prop = prop;
if (prop == ZPROP_INVAL) {
if ((entry->pl_user_prop = zfs_strdup(hdl, s))
== NULL) {
free(entry);
return (-1);
for (i = 0; spaceprops[i]; i++) {
if (addlist(hdl, spaceprops[i], listp, type))
return (-1);
listp = &(*listp)->pl_next;
}
entry->pl_width = strlen(s);
} else {
entry->pl_width = zprop_width(prop, &entry->pl_fixed,
type);
if (addlist(hdl, props, listp, type))
return (-1);
listp = &(*listp)->pl_next;
}
*last = entry;
last = &entry->pl_next;
s = p;
props = p;
if (c == ',')
s++;
props++;
}
return (0);