Update vendor-sys/illumos/dist to illumos-gate 13752:9f5f6c52ba19
(zfs part) Obtained from: ssh://anonhg@hg.illumos.org/illumos-gate
This commit is contained in:
parent
4eca1cfa73
commit
5b5bfb7422
@ -57,6 +57,7 @@
|
|||||||
#include <sys/arc.h>
|
#include <sys/arc.h>
|
||||||
#include <sys/ddt.h>
|
#include <sys/ddt.h>
|
||||||
#include <sys/zfeature.h>
|
#include <sys/zfeature.h>
|
||||||
|
#include <zfs_comutil.h>
|
||||||
#undef ZFS_MAXNAMELEN
|
#undef ZFS_MAXNAMELEN
|
||||||
#undef verify
|
#undef verify
|
||||||
#include <libzfs.h>
|
#include <libzfs.h>
|
||||||
@ -204,6 +205,27 @@ dump_packed_nvlist(objset_t *os, uint64_t object, void *data, size_t size)
|
|||||||
nvlist_free(nv);
|
nvlist_free(nv);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/* ARGSUSED */
|
||||||
|
static void
|
||||||
|
dump_history_offsets(objset_t *os, uint64_t object, void *data, size_t size)
|
||||||
|
{
|
||||||
|
spa_history_phys_t *shp = data;
|
||||||
|
|
||||||
|
if (shp == NULL)
|
||||||
|
return;
|
||||||
|
|
||||||
|
(void) printf("\t\tpool_create_len = %llu\n",
|
||||||
|
(u_longlong_t)shp->sh_pool_create_len);
|
||||||
|
(void) printf("\t\tphys_max_off = %llu\n",
|
||||||
|
(u_longlong_t)shp->sh_phys_max_off);
|
||||||
|
(void) printf("\t\tbof = %llu\n",
|
||||||
|
(u_longlong_t)shp->sh_bof);
|
||||||
|
(void) printf("\t\teof = %llu\n",
|
||||||
|
(u_longlong_t)shp->sh_eof);
|
||||||
|
(void) printf("\t\trecords_lost = %llu\n",
|
||||||
|
(u_longlong_t)shp->sh_records_lost);
|
||||||
|
}
|
||||||
|
|
||||||
static void
|
static void
|
||||||
zdb_nicenum(uint64_t num, char *buf)
|
zdb_nicenum(uint64_t num, char *buf)
|
||||||
{
|
{
|
||||||
@ -853,21 +875,22 @@ dump_history(spa_t *spa)
|
|||||||
for (int i = 0; i < num; i++) {
|
for (int i = 0; i < num; i++) {
|
||||||
uint64_t time, txg, ievent;
|
uint64_t time, txg, ievent;
|
||||||
char *cmd, *intstr;
|
char *cmd, *intstr;
|
||||||
|
boolean_t printed = B_FALSE;
|
||||||
|
|
||||||
if (nvlist_lookup_uint64(events[i], ZPOOL_HIST_TIME,
|
if (nvlist_lookup_uint64(events[i], ZPOOL_HIST_TIME,
|
||||||
&time) != 0)
|
&time) != 0)
|
||||||
continue;
|
goto next;
|
||||||
if (nvlist_lookup_string(events[i], ZPOOL_HIST_CMD,
|
if (nvlist_lookup_string(events[i], ZPOOL_HIST_CMD,
|
||||||
&cmd) != 0) {
|
&cmd) != 0) {
|
||||||
if (nvlist_lookup_uint64(events[i],
|
if (nvlist_lookup_uint64(events[i],
|
||||||
ZPOOL_HIST_INT_EVENT, &ievent) != 0)
|
ZPOOL_HIST_INT_EVENT, &ievent) != 0)
|
||||||
continue;
|
goto next;
|
||||||
verify(nvlist_lookup_uint64(events[i],
|
verify(nvlist_lookup_uint64(events[i],
|
||||||
ZPOOL_HIST_TXG, &txg) == 0);
|
ZPOOL_HIST_TXG, &txg) == 0);
|
||||||
verify(nvlist_lookup_string(events[i],
|
verify(nvlist_lookup_string(events[i],
|
||||||
ZPOOL_HIST_INT_STR, &intstr) == 0);
|
ZPOOL_HIST_INT_STR, &intstr) == 0);
|
||||||
if (ievent >= LOG_END)
|
if (ievent >= ZFS_NUM_LEGACY_HISTORY_EVENTS)
|
||||||
continue;
|
goto next;
|
||||||
|
|
||||||
(void) snprintf(internalstr,
|
(void) snprintf(internalstr,
|
||||||
sizeof (internalstr),
|
sizeof (internalstr),
|
||||||
@ -880,6 +903,14 @@ dump_history(spa_t *spa)
|
|||||||
(void) localtime_r(&tsec, &t);
|
(void) localtime_r(&tsec, &t);
|
||||||
(void) strftime(tbuf, sizeof (tbuf), "%F.%T", &t);
|
(void) strftime(tbuf, sizeof (tbuf), "%F.%T", &t);
|
||||||
(void) printf("%s %s\n", tbuf, cmd);
|
(void) printf("%s %s\n", tbuf, cmd);
|
||||||
|
printed = B_TRUE;
|
||||||
|
|
||||||
|
next:
|
||||||
|
if (dump_opt['h'] > 1) {
|
||||||
|
if (!printed)
|
||||||
|
(void) printf("unrecognized record:\n");
|
||||||
|
dump_nvlist(events[i], 2);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -1456,7 +1487,7 @@ static object_viewer_t *object_viewer[DMU_OT_NUMTYPES + 1] = {
|
|||||||
dump_zap, /* other ZAP */
|
dump_zap, /* other ZAP */
|
||||||
dump_zap, /* persistent error log */
|
dump_zap, /* persistent error log */
|
||||||
dump_uint8, /* SPA history */
|
dump_uint8, /* SPA history */
|
||||||
dump_uint64, /* SPA history offsets */
|
dump_history_offsets, /* SPA history offsets */
|
||||||
dump_zap, /* Pool properties */
|
dump_zap, /* Pool properties */
|
||||||
dump_zap, /* DSL permissions */
|
dump_zap, /* DSL permissions */
|
||||||
dump_acl, /* ZFS ACL */
|
dump_acl, /* ZFS ACL */
|
||||||
|
@ -56,6 +56,7 @@
|
|||||||
#include <time.h>
|
#include <time.h>
|
||||||
|
|
||||||
#include <libzfs.h>
|
#include <libzfs.h>
|
||||||
|
#include <libzfs_core.h>
|
||||||
#include <zfs_prop.h>
|
#include <zfs_prop.h>
|
||||||
#include <zfs_deleg.h>
|
#include <zfs_deleg.h>
|
||||||
#include <libuutil.h>
|
#include <libuutil.h>
|
||||||
@ -70,6 +71,7 @@ libzfs_handle_t *g_zfs;
|
|||||||
|
|
||||||
static FILE *mnttab_file;
|
static FILE *mnttab_file;
|
||||||
static char history_str[HIS_MAX_RECORD_LEN];
|
static char history_str[HIS_MAX_RECORD_LEN];
|
||||||
|
static boolean_t log_history = B_TRUE;
|
||||||
|
|
||||||
static int zfs_do_clone(int argc, char **argv);
|
static int zfs_do_clone(int argc, char **argv);
|
||||||
static int zfs_do_create(int argc, char **argv);
|
static int zfs_do_create(int argc, char **argv);
|
||||||
@ -259,7 +261,7 @@ get_usage(zfs_help_t idx)
|
|||||||
return (gettext("\tshare <-a | filesystem>\n"));
|
return (gettext("\tshare <-a | filesystem>\n"));
|
||||||
case HELP_SNAPSHOT:
|
case HELP_SNAPSHOT:
|
||||||
return (gettext("\tsnapshot [-r] [-o property=value] ... "
|
return (gettext("\tsnapshot [-r] [-o property=value] ... "
|
||||||
"<filesystem@snapname|volume@snapname>\n"));
|
"<filesystem@snapname|volume@snapname> ...\n"));
|
||||||
case HELP_UNMOUNT:
|
case HELP_UNMOUNT:
|
||||||
return (gettext("\tunmount [-f] "
|
return (gettext("\tunmount [-f] "
|
||||||
"<-a | filesystem|mountpoint>\n"));
|
"<-a | filesystem|mountpoint>\n"));
|
||||||
@ -888,9 +890,9 @@ typedef struct destroy_cbdata {
|
|||||||
nvlist_t *cb_nvl;
|
nvlist_t *cb_nvl;
|
||||||
|
|
||||||
/* first snap in contiguous run */
|
/* first snap in contiguous run */
|
||||||
zfs_handle_t *cb_firstsnap;
|
char *cb_firstsnap;
|
||||||
/* previous snap in contiguous run */
|
/* previous snap in contiguous run */
|
||||||
zfs_handle_t *cb_prevsnap;
|
char *cb_prevsnap;
|
||||||
int64_t cb_snapused;
|
int64_t cb_snapused;
|
||||||
char *cb_snapspec;
|
char *cb_snapspec;
|
||||||
} destroy_cbdata_t;
|
} destroy_cbdata_t;
|
||||||
@ -1004,11 +1006,13 @@ destroy_print_cb(zfs_handle_t *zhp, void *arg)
|
|||||||
|
|
||||||
if (nvlist_exists(cb->cb_nvl, name)) {
|
if (nvlist_exists(cb->cb_nvl, name)) {
|
||||||
if (cb->cb_firstsnap == NULL)
|
if (cb->cb_firstsnap == NULL)
|
||||||
cb->cb_firstsnap = zfs_handle_dup(zhp);
|
cb->cb_firstsnap = strdup(name);
|
||||||
if (cb->cb_prevsnap != NULL)
|
if (cb->cb_prevsnap != NULL)
|
||||||
zfs_close(cb->cb_prevsnap);
|
free(cb->cb_prevsnap);
|
||||||
/* this snap continues the current range */
|
/* this snap continues the current range */
|
||||||
cb->cb_prevsnap = zfs_handle_dup(zhp);
|
cb->cb_prevsnap = strdup(name);
|
||||||
|
if (cb->cb_firstsnap == NULL || cb->cb_prevsnap == NULL)
|
||||||
|
nomem();
|
||||||
if (cb->cb_verbose) {
|
if (cb->cb_verbose) {
|
||||||
if (cb->cb_parsable) {
|
if (cb->cb_parsable) {
|
||||||
(void) printf("destroy\t%s\n", name);
|
(void) printf("destroy\t%s\n", name);
|
||||||
@ -1023,12 +1027,12 @@ destroy_print_cb(zfs_handle_t *zhp, void *arg)
|
|||||||
} else if (cb->cb_firstsnap != NULL) {
|
} else if (cb->cb_firstsnap != NULL) {
|
||||||
/* end of this range */
|
/* end of this range */
|
||||||
uint64_t used = 0;
|
uint64_t used = 0;
|
||||||
err = zfs_get_snapused_int(cb->cb_firstsnap,
|
err = lzc_snaprange_space(cb->cb_firstsnap,
|
||||||
cb->cb_prevsnap, &used);
|
cb->cb_prevsnap, &used);
|
||||||
cb->cb_snapused += used;
|
cb->cb_snapused += used;
|
||||||
zfs_close(cb->cb_firstsnap);
|
free(cb->cb_firstsnap);
|
||||||
cb->cb_firstsnap = NULL;
|
cb->cb_firstsnap = NULL;
|
||||||
zfs_close(cb->cb_prevsnap);
|
free(cb->cb_prevsnap);
|
||||||
cb->cb_prevsnap = NULL;
|
cb->cb_prevsnap = NULL;
|
||||||
}
|
}
|
||||||
zfs_close(zhp);
|
zfs_close(zhp);
|
||||||
@ -1045,13 +1049,13 @@ destroy_print_snapshots(zfs_handle_t *fs_zhp, destroy_cbdata_t *cb)
|
|||||||
if (cb->cb_firstsnap != NULL) {
|
if (cb->cb_firstsnap != NULL) {
|
||||||
uint64_t used = 0;
|
uint64_t used = 0;
|
||||||
if (err == 0) {
|
if (err == 0) {
|
||||||
err = zfs_get_snapused_int(cb->cb_firstsnap,
|
err = lzc_snaprange_space(cb->cb_firstsnap,
|
||||||
cb->cb_prevsnap, &used);
|
cb->cb_prevsnap, &used);
|
||||||
}
|
}
|
||||||
cb->cb_snapused += used;
|
cb->cb_snapused += used;
|
||||||
zfs_close(cb->cb_firstsnap);
|
free(cb->cb_firstsnap);
|
||||||
cb->cb_firstsnap = NULL;
|
cb->cb_firstsnap = NULL;
|
||||||
zfs_close(cb->cb_prevsnap);
|
free(cb->cb_prevsnap);
|
||||||
cb->cb_prevsnap = NULL;
|
cb->cb_prevsnap = NULL;
|
||||||
}
|
}
|
||||||
return (err);
|
return (err);
|
||||||
@ -1064,7 +1068,7 @@ snapshot_to_nvl_cb(zfs_handle_t *zhp, void *arg)
|
|||||||
int err = 0;
|
int err = 0;
|
||||||
|
|
||||||
/* Check for clones. */
|
/* Check for clones. */
|
||||||
if (!cb->cb_doclones) {
|
if (!cb->cb_doclones && !cb->cb_defer_destroy) {
|
||||||
cb->cb_target = zhp;
|
cb->cb_target = zhp;
|
||||||
cb->cb_first = B_TRUE;
|
cb->cb_first = B_TRUE;
|
||||||
err = zfs_iter_dependents(zhp, B_TRUE,
|
err = zfs_iter_dependents(zhp, B_TRUE,
|
||||||
@ -1904,9 +1908,11 @@ upgrade_set_callback(zfs_handle_t *zhp, void *data)
|
|||||||
/*
|
/*
|
||||||
* If they did "zfs upgrade -a", then we could
|
* If they did "zfs upgrade -a", then we could
|
||||||
* be doing ioctls to different pools. We need
|
* be doing ioctls to different pools. We need
|
||||||
* to log this history once to each pool.
|
* to log this history once to each pool, and bypass
|
||||||
|
* the normal history logging that happens in main().
|
||||||
*/
|
*/
|
||||||
verify(zpool_stage_history(g_zfs, history_str) == 0);
|
(void) zpool_log_history(g_zfs, history_str);
|
||||||
|
log_history = B_FALSE;
|
||||||
}
|
}
|
||||||
if (zfs_prop_set(zhp, "version", verstr) == 0)
|
if (zfs_prop_set(zhp, "version", verstr) == 0)
|
||||||
cb->cb_numupgraded++;
|
cb->cb_numupgraded++;
|
||||||
@ -3424,6 +3430,32 @@ zfs_do_set(int argc, char **argv)
|
|||||||
return (ret);
|
return (ret);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
typedef struct snap_cbdata {
|
||||||
|
nvlist_t *sd_nvl;
|
||||||
|
boolean_t sd_recursive;
|
||||||
|
const char *sd_snapname;
|
||||||
|
} snap_cbdata_t;
|
||||||
|
|
||||||
|
static int
|
||||||
|
zfs_snapshot_cb(zfs_handle_t *zhp, void *arg)
|
||||||
|
{
|
||||||
|
snap_cbdata_t *sd = arg;
|
||||||
|
char *name;
|
||||||
|
int rv = 0;
|
||||||
|
int error;
|
||||||
|
|
||||||
|
error = asprintf(&name, "%s@%s", zfs_get_name(zhp), sd->sd_snapname);
|
||||||
|
if (error == -1)
|
||||||
|
nomem();
|
||||||
|
fnvlist_add_boolean(sd->sd_nvl, name);
|
||||||
|
free(name);
|
||||||
|
|
||||||
|
if (sd->sd_recursive)
|
||||||
|
rv = zfs_iter_filesystems(zhp, zfs_snapshot_cb, sd);
|
||||||
|
zfs_close(zhp);
|
||||||
|
return (rv);
|
||||||
|
}
|
||||||
|
|
||||||
/*
|
/*
|
||||||
* zfs snapshot [-r] [-o prop=value] ... <fs@snap>
|
* zfs snapshot [-r] [-o prop=value] ... <fs@snap>
|
||||||
*
|
*
|
||||||
@ -3433,13 +3465,16 @@ zfs_do_set(int argc, char **argv)
|
|||||||
static int
|
static int
|
||||||
zfs_do_snapshot(int argc, char **argv)
|
zfs_do_snapshot(int argc, char **argv)
|
||||||
{
|
{
|
||||||
boolean_t recursive = B_FALSE;
|
|
||||||
int ret = 0;
|
int ret = 0;
|
||||||
char c;
|
char c;
|
||||||
nvlist_t *props;
|
nvlist_t *props;
|
||||||
|
snap_cbdata_t sd = { 0 };
|
||||||
|
boolean_t multiple_snaps = B_FALSE;
|
||||||
|
|
||||||
if (nvlist_alloc(&props, NV_UNIQUE_NAME, 0) != 0)
|
if (nvlist_alloc(&props, NV_UNIQUE_NAME, 0) != 0)
|
||||||
nomem();
|
nomem();
|
||||||
|
if (nvlist_alloc(&sd.sd_nvl, NV_UNIQUE_NAME, 0) != 0)
|
||||||
|
nomem();
|
||||||
|
|
||||||
/* check options */
|
/* check options */
|
||||||
while ((c = getopt(argc, argv, "ro:")) != -1) {
|
while ((c = getopt(argc, argv, "ro:")) != -1) {
|
||||||
@ -3449,7 +3484,8 @@ zfs_do_snapshot(int argc, char **argv)
|
|||||||
return (1);
|
return (1);
|
||||||
break;
|
break;
|
||||||
case 'r':
|
case 'r':
|
||||||
recursive = B_TRUE;
|
sd.sd_recursive = B_TRUE;
|
||||||
|
multiple_snaps = B_TRUE;
|
||||||
break;
|
break;
|
||||||
case '?':
|
case '?':
|
||||||
(void) fprintf(stderr, gettext("invalid option '%c'\n"),
|
(void) fprintf(stderr, gettext("invalid option '%c'\n"),
|
||||||
@ -3466,18 +3502,35 @@ zfs_do_snapshot(int argc, char **argv)
|
|||||||
(void) fprintf(stderr, gettext("missing snapshot argument\n"));
|
(void) fprintf(stderr, gettext("missing snapshot argument\n"));
|
||||||
goto usage;
|
goto usage;
|
||||||
}
|
}
|
||||||
if (argc > 1) {
|
|
||||||
(void) fprintf(stderr, gettext("too many arguments\n"));
|
if (argc > 1)
|
||||||
goto usage;
|
multiple_snaps = B_TRUE;
|
||||||
|
for (; argc > 0; argc--, argv++) {
|
||||||
|
char *atp;
|
||||||
|
zfs_handle_t *zhp;
|
||||||
|
|
||||||
|
atp = strchr(argv[0], '@');
|
||||||
|
if (atp == NULL)
|
||||||
|
goto usage;
|
||||||
|
*atp = '\0';
|
||||||
|
sd.sd_snapname = atp + 1;
|
||||||
|
zhp = zfs_open(g_zfs, argv[0],
|
||||||
|
ZFS_TYPE_FILESYSTEM | ZFS_TYPE_VOLUME);
|
||||||
|
if (zhp == NULL)
|
||||||
|
goto usage;
|
||||||
|
if (zfs_snapshot_cb(zhp, &sd) != 0)
|
||||||
|
goto usage;
|
||||||
}
|
}
|
||||||
|
|
||||||
ret = zfs_snapshot(g_zfs, argv[0], recursive, props);
|
ret = zfs_snapshot_nvl(g_zfs, sd.sd_nvl, props);
|
||||||
|
nvlist_free(sd.sd_nvl);
|
||||||
nvlist_free(props);
|
nvlist_free(props);
|
||||||
if (ret && recursive)
|
if (ret != 0 && multiple_snaps)
|
||||||
(void) fprintf(stderr, gettext("no snapshots were created\n"));
|
(void) fprintf(stderr, gettext("no snapshots were created\n"));
|
||||||
return (ret != 0);
|
return (ret != 0);
|
||||||
|
|
||||||
usage:
|
usage:
|
||||||
|
nvlist_free(sd.sd_nvl);
|
||||||
nvlist_free(props);
|
nvlist_free(props);
|
||||||
usage(B_FALSE);
|
usage(B_FALSE);
|
||||||
return (-1);
|
return (-1);
|
||||||
@ -6479,8 +6532,7 @@ main(int argc, char **argv)
|
|||||||
return (1);
|
return (1);
|
||||||
}
|
}
|
||||||
|
|
||||||
zpool_set_history_str("zfs", argc, argv, history_str);
|
zfs_save_arguments(argc, argv, history_str, sizeof (history_str));
|
||||||
verify(zpool_stage_history(g_zfs, history_str) == 0);
|
|
||||||
|
|
||||||
libzfs_print_on_error(g_zfs, B_TRUE);
|
libzfs_print_on_error(g_zfs, B_TRUE);
|
||||||
|
|
||||||
@ -6549,6 +6601,9 @@ main(int argc, char **argv)
|
|||||||
|
|
||||||
(void) fclose(mnttab_file);
|
(void) fclose(mnttab_file);
|
||||||
|
|
||||||
|
if (ret == 0 && log_history)
|
||||||
|
(void) zpool_log_history(g_zfs, history_str);
|
||||||
|
|
||||||
libzfs_fini(g_zfs);
|
libzfs_fini(g_zfs);
|
||||||
|
|
||||||
/*
|
/*
|
||||||
|
@ -279,6 +279,9 @@ feature_enable_sync(void *arg1, void *arg2, dmu_tx_t *tx)
|
|||||||
zfeature_info_t *feature = arg2;
|
zfeature_info_t *feature = arg2;
|
||||||
|
|
||||||
spa_feature_enable(spa, feature, tx);
|
spa_feature_enable(spa, feature, tx);
|
||||||
|
spa_history_log_internal(spa, "zhack enable feature", tx,
|
||||||
|
"name=%s can_readonly=%u",
|
||||||
|
feature->fi_guid, feature->fi_can_readonly);
|
||||||
}
|
}
|
||||||
|
|
||||||
static void
|
static void
|
||||||
@ -356,6 +359,8 @@ feature_incr_sync(void *arg1, void *arg2, dmu_tx_t *tx)
|
|||||||
zfeature_info_t *feature = arg2;
|
zfeature_info_t *feature = arg2;
|
||||||
|
|
||||||
spa_feature_incr(spa, feature, tx);
|
spa_feature_incr(spa, feature, tx);
|
||||||
|
spa_history_log_internal(spa, "zhack feature incr", tx,
|
||||||
|
"name=%s", feature->fi_guid);
|
||||||
}
|
}
|
||||||
|
|
||||||
static void
|
static void
|
||||||
@ -365,6 +370,8 @@ feature_decr_sync(void *arg1, void *arg2, dmu_tx_t *tx)
|
|||||||
zfeature_info_t *feature = arg2;
|
zfeature_info_t *feature = arg2;
|
||||||
|
|
||||||
spa_feature_decr(spa, feature, tx);
|
spa_feature_decr(spa, feature, tx);
|
||||||
|
spa_history_log_internal(spa, "zhack feature decr", tx,
|
||||||
|
"name=%s", feature->fi_guid);
|
||||||
}
|
}
|
||||||
|
|
||||||
static void
|
static void
|
||||||
|
@ -185,9 +185,9 @@ static zpool_command_t command_table[] = {
|
|||||||
|
|
||||||
#define NCOMMAND (sizeof (command_table) / sizeof (command_table[0]))
|
#define NCOMMAND (sizeof (command_table) / sizeof (command_table[0]))
|
||||||
|
|
||||||
zpool_command_t *current_command;
|
static zpool_command_t *current_command;
|
||||||
static char history_str[HIS_MAX_RECORD_LEN];
|
static char history_str[HIS_MAX_RECORD_LEN];
|
||||||
|
static boolean_t log_history = B_TRUE;
|
||||||
static uint_t timestamp_fmt = NODATE;
|
static uint_t timestamp_fmt = NODATE;
|
||||||
|
|
||||||
static const char *
|
static const char *
|
||||||
@ -935,7 +935,10 @@ zpool_do_destroy(int argc, char **argv)
|
|||||||
return (1);
|
return (1);
|
||||||
}
|
}
|
||||||
|
|
||||||
ret = (zpool_destroy(zhp) != 0);
|
/* The history must be logged as part of the export */
|
||||||
|
log_history = B_FALSE;
|
||||||
|
|
||||||
|
ret = (zpool_destroy(zhp, history_str) != 0);
|
||||||
|
|
||||||
zpool_close(zhp);
|
zpool_close(zhp);
|
||||||
|
|
||||||
@ -999,10 +1002,13 @@ zpool_do_export(int argc, char **argv)
|
|||||||
continue;
|
continue;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/* The history must be logged as part of the export */
|
||||||
|
log_history = B_FALSE;
|
||||||
|
|
||||||
if (hardforce) {
|
if (hardforce) {
|
||||||
if (zpool_export_force(zhp) != 0)
|
if (zpool_export_force(zhp, history_str) != 0)
|
||||||
ret = 1;
|
ret = 1;
|
||||||
} else if (zpool_export(zhp, force) != 0) {
|
} else if (zpool_export(zhp, force, history_str) != 0) {
|
||||||
ret = 1;
|
ret = 1;
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -4269,6 +4275,14 @@ upgrade_cb(zpool_handle_t *zhp, void *arg)
|
|||||||
(void) printf(gettext("Successfully upgraded "
|
(void) printf(gettext("Successfully upgraded "
|
||||||
"'%s'\n\n"), zpool_get_name(zhp));
|
"'%s'\n\n"), zpool_get_name(zhp));
|
||||||
}
|
}
|
||||||
|
/*
|
||||||
|
* If they did "zpool upgrade -a", then we could
|
||||||
|
* be doing ioctls to different pools. We need
|
||||||
|
* to log this history once to each pool, and bypass
|
||||||
|
* the normal history logging that happens in main().
|
||||||
|
*/
|
||||||
|
(void) zpool_log_history(g_zfs, history_str);
|
||||||
|
log_history = B_FALSE;
|
||||||
}
|
}
|
||||||
} else if (cbp->cb_newer && !SPA_VERSION_IS_SUPPORTED(version)) {
|
} else if (cbp->cb_newer && !SPA_VERSION_IS_SUPPORTED(version)) {
|
||||||
assert(!cbp->cb_all);
|
assert(!cbp->cb_all);
|
||||||
@ -4491,8 +4505,8 @@ zpool_do_upgrade(int argc, char **argv)
|
|||||||
|
|
||||||
typedef struct hist_cbdata {
|
typedef struct hist_cbdata {
|
||||||
boolean_t first;
|
boolean_t first;
|
||||||
int longfmt;
|
boolean_t longfmt;
|
||||||
int internal;
|
boolean_t internal;
|
||||||
} hist_cbdata_t;
|
} hist_cbdata_t;
|
||||||
|
|
||||||
/*
|
/*
|
||||||
@ -4504,21 +4518,8 @@ get_history_one(zpool_handle_t *zhp, void *data)
|
|||||||
nvlist_t *nvhis;
|
nvlist_t *nvhis;
|
||||||
nvlist_t **records;
|
nvlist_t **records;
|
||||||
uint_t numrecords;
|
uint_t numrecords;
|
||||||
char *cmdstr;
|
|
||||||
char *pathstr;
|
|
||||||
uint64_t dst_time;
|
|
||||||
time_t tsec;
|
|
||||||
struct tm t;
|
|
||||||
char tbuf[30];
|
|
||||||
int ret, i;
|
int ret, i;
|
||||||
uint64_t who;
|
|
||||||
struct passwd *pwd;
|
|
||||||
char *hostname;
|
|
||||||
char *zonename;
|
|
||||||
char internalstr[MAXPATHLEN];
|
|
||||||
hist_cbdata_t *cb = (hist_cbdata_t *)data;
|
hist_cbdata_t *cb = (hist_cbdata_t *)data;
|
||||||
uint64_t txg;
|
|
||||||
uint64_t ievent;
|
|
||||||
|
|
||||||
cb->first = B_FALSE;
|
cb->first = B_FALSE;
|
||||||
|
|
||||||
@ -4530,64 +4531,94 @@ get_history_one(zpool_handle_t *zhp, void *data)
|
|||||||
verify(nvlist_lookup_nvlist_array(nvhis, ZPOOL_HIST_RECORD,
|
verify(nvlist_lookup_nvlist_array(nvhis, ZPOOL_HIST_RECORD,
|
||||||
&records, &numrecords) == 0);
|
&records, &numrecords) == 0);
|
||||||
for (i = 0; i < numrecords; i++) {
|
for (i = 0; i < numrecords; i++) {
|
||||||
if (nvlist_lookup_uint64(records[i], ZPOOL_HIST_TIME,
|
nvlist_t *rec = records[i];
|
||||||
&dst_time) != 0)
|
char tbuf[30] = "";
|
||||||
continue;
|
|
||||||
|
|
||||||
/* is it an internal event or a standard event? */
|
if (nvlist_exists(rec, ZPOOL_HIST_TIME)) {
|
||||||
if (nvlist_lookup_string(records[i], ZPOOL_HIST_CMD,
|
time_t tsec;
|
||||||
&cmdstr) != 0) {
|
struct tm t;
|
||||||
if (cb->internal == 0)
|
|
||||||
continue;
|
|
||||||
|
|
||||||
if (nvlist_lookup_uint64(records[i],
|
tsec = fnvlist_lookup_uint64(records[i],
|
||||||
ZPOOL_HIST_INT_EVENT, &ievent) != 0)
|
ZPOOL_HIST_TIME);
|
||||||
continue;
|
(void) localtime_r(&tsec, &t);
|
||||||
verify(nvlist_lookup_uint64(records[i],
|
(void) strftime(tbuf, sizeof (tbuf), "%F.%T", &t);
|
||||||
ZPOOL_HIST_TXG, &txg) == 0);
|
}
|
||||||
verify(nvlist_lookup_string(records[i],
|
|
||||||
ZPOOL_HIST_INT_STR, &pathstr) == 0);
|
if (nvlist_exists(rec, ZPOOL_HIST_CMD)) {
|
||||||
if (ievent >= LOG_END)
|
(void) printf("%s %s", tbuf,
|
||||||
continue;
|
fnvlist_lookup_string(rec, ZPOOL_HIST_CMD));
|
||||||
(void) snprintf(internalstr,
|
} else if (nvlist_exists(rec, ZPOOL_HIST_INT_EVENT)) {
|
||||||
sizeof (internalstr),
|
int ievent =
|
||||||
"[internal %s txg:%lld] %s",
|
fnvlist_lookup_uint64(rec, ZPOOL_HIST_INT_EVENT);
|
||||||
zfs_history_event_names[ievent], txg,
|
if (!cb->internal)
|
||||||
pathstr);
|
continue;
|
||||||
cmdstr = internalstr;
|
if (ievent >= ZFS_NUM_LEGACY_HISTORY_EVENTS) {
|
||||||
|
(void) printf("%s unrecognized record:\n",
|
||||||
|
tbuf);
|
||||||
|
dump_nvlist(rec, 4);
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
(void) printf("%s [internal %s txg:%lld] %s", tbuf,
|
||||||
|
zfs_history_event_names[ievent],
|
||||||
|
fnvlist_lookup_uint64(rec, ZPOOL_HIST_TXG),
|
||||||
|
fnvlist_lookup_string(rec, ZPOOL_HIST_INT_STR));
|
||||||
|
} else if (nvlist_exists(rec, ZPOOL_HIST_INT_NAME)) {
|
||||||
|
if (!cb->internal)
|
||||||
|
continue;
|
||||||
|
(void) printf("%s [txg:%lld] %s", tbuf,
|
||||||
|
fnvlist_lookup_uint64(rec, ZPOOL_HIST_TXG),
|
||||||
|
fnvlist_lookup_string(rec, ZPOOL_HIST_INT_NAME));
|
||||||
|
if (nvlist_exists(rec, ZPOOL_HIST_DSNAME)) {
|
||||||
|
(void) printf(" %s (%llu)",
|
||||||
|
fnvlist_lookup_string(rec,
|
||||||
|
ZPOOL_HIST_DSNAME),
|
||||||
|
fnvlist_lookup_uint64(rec,
|
||||||
|
ZPOOL_HIST_DSID));
|
||||||
|
}
|
||||||
|
(void) printf(" %s", fnvlist_lookup_string(rec,
|
||||||
|
ZPOOL_HIST_INT_STR));
|
||||||
|
} else if (nvlist_exists(rec, ZPOOL_HIST_IOCTL)) {
|
||||||
|
if (!cb->internal)
|
||||||
|
continue;
|
||||||
|
(void) printf("%s ioctl %s\n", tbuf,
|
||||||
|
fnvlist_lookup_string(rec, ZPOOL_HIST_IOCTL));
|
||||||
|
if (nvlist_exists(rec, ZPOOL_HIST_INPUT_NVL)) {
|
||||||
|
(void) printf(" input:\n");
|
||||||
|
dump_nvlist(fnvlist_lookup_nvlist(rec,
|
||||||
|
ZPOOL_HIST_INPUT_NVL), 8);
|
||||||
|
}
|
||||||
|
if (nvlist_exists(rec, ZPOOL_HIST_OUTPUT_NVL)) {
|
||||||
|
(void) printf(" output:\n");
|
||||||
|
dump_nvlist(fnvlist_lookup_nvlist(rec,
|
||||||
|
ZPOOL_HIST_OUTPUT_NVL), 8);
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
if (!cb->internal)
|
||||||
|
continue;
|
||||||
|
(void) printf("%s unrecognized record:\n", tbuf);
|
||||||
|
dump_nvlist(rec, 4);
|
||||||
}
|
}
|
||||||
tsec = dst_time;
|
|
||||||
(void) localtime_r(&tsec, &t);
|
|
||||||
(void) strftime(tbuf, sizeof (tbuf), "%F.%T", &t);
|
|
||||||
(void) printf("%s %s", tbuf, cmdstr);
|
|
||||||
|
|
||||||
if (!cb->longfmt) {
|
if (!cb->longfmt) {
|
||||||
(void) printf("\n");
|
(void) printf("\n");
|
||||||
continue;
|
continue;
|
||||||
}
|
}
|
||||||
(void) printf(" [");
|
(void) printf(" [");
|
||||||
if (nvlist_lookup_uint64(records[i],
|
if (nvlist_exists(rec, ZPOOL_HIST_WHO)) {
|
||||||
ZPOOL_HIST_WHO, &who) == 0) {
|
uid_t who = fnvlist_lookup_uint64(rec, ZPOOL_HIST_WHO);
|
||||||
pwd = getpwuid((uid_t)who);
|
struct passwd *pwd = getpwuid(who);
|
||||||
if (pwd)
|
(void) printf("user %d ", (int)who);
|
||||||
(void) printf("user %s on",
|
if (pwd != NULL)
|
||||||
pwd->pw_name);
|
(void) printf("(%s) ", pwd->pw_name);
|
||||||
else
|
|
||||||
(void) printf("user %d on",
|
|
||||||
(int)who);
|
|
||||||
} else {
|
|
||||||
(void) printf(gettext("no info]\n"));
|
|
||||||
continue;
|
|
||||||
}
|
}
|
||||||
if (nvlist_lookup_string(records[i],
|
if (nvlist_exists(rec, ZPOOL_HIST_HOST)) {
|
||||||
ZPOOL_HIST_HOST, &hostname) == 0) {
|
(void) printf("on %s",
|
||||||
(void) printf(" %s", hostname);
|
fnvlist_lookup_string(rec, ZPOOL_HIST_HOST));
|
||||||
}
|
}
|
||||||
if (nvlist_lookup_string(records[i],
|
if (nvlist_exists(rec, ZPOOL_HIST_ZONE)) {
|
||||||
ZPOOL_HIST_ZONE, &zonename) == 0) {
|
(void) printf(":%s",
|
||||||
(void) printf(":%s", zonename);
|
fnvlist_lookup_string(rec, ZPOOL_HIST_ZONE));
|
||||||
}
|
}
|
||||||
|
|
||||||
(void) printf("]");
|
(void) printf("]");
|
||||||
(void) printf("\n");
|
(void) printf("\n");
|
||||||
}
|
}
|
||||||
@ -4602,8 +4633,6 @@ get_history_one(zpool_handle_t *zhp, void *data)
|
|||||||
*
|
*
|
||||||
* Displays the history of commands that modified pools.
|
* Displays the history of commands that modified pools.
|
||||||
*/
|
*/
|
||||||
|
|
||||||
|
|
||||||
int
|
int
|
||||||
zpool_do_history(int argc, char **argv)
|
zpool_do_history(int argc, char **argv)
|
||||||
{
|
{
|
||||||
@ -4616,10 +4645,10 @@ zpool_do_history(int argc, char **argv)
|
|||||||
while ((c = getopt(argc, argv, "li")) != -1) {
|
while ((c = getopt(argc, argv, "li")) != -1) {
|
||||||
switch (c) {
|
switch (c) {
|
||||||
case 'l':
|
case 'l':
|
||||||
cbdata.longfmt = 1;
|
cbdata.longfmt = B_TRUE;
|
||||||
break;
|
break;
|
||||||
case 'i':
|
case 'i':
|
||||||
cbdata.internal = 1;
|
cbdata.internal = B_TRUE;
|
||||||
break;
|
break;
|
||||||
case '?':
|
case '?':
|
||||||
(void) fprintf(stderr, gettext("invalid option '%c'\n"),
|
(void) fprintf(stderr, gettext("invalid option '%c'\n"),
|
||||||
@ -4844,8 +4873,7 @@ main(int argc, char **argv)
|
|||||||
if (strcmp(cmdname, "-?") == 0)
|
if (strcmp(cmdname, "-?") == 0)
|
||||||
usage(B_TRUE);
|
usage(B_TRUE);
|
||||||
|
|
||||||
zpool_set_history_str("zpool", argc, argv, history_str);
|
zfs_save_arguments(argc, argv, history_str, sizeof (history_str));
|
||||||
verify(zpool_stage_history(g_zfs, history_str) == 0);
|
|
||||||
|
|
||||||
/*
|
/*
|
||||||
* Run the appropriate command.
|
* Run the appropriate command.
|
||||||
@ -4872,6 +4900,9 @@ main(int argc, char **argv)
|
|||||||
usage(B_FALSE);
|
usage(B_FALSE);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
if (ret == 0 && log_history)
|
||||||
|
(void) zpool_log_history(g_zfs, history_str);
|
||||||
|
|
||||||
libzfs_fini(g_zfs);
|
libzfs_fini(g_zfs);
|
||||||
|
|
||||||
/*
|
/*
|
||||||
|
@ -2252,7 +2252,7 @@ ztest_spa_create_destroy(ztest_ds_t *zd, uint64_t id)
|
|||||||
*/
|
*/
|
||||||
nvroot = make_vdev_root("/dev/bogus", NULL, 0, 0, 0, 0, 0, 1);
|
nvroot = make_vdev_root("/dev/bogus", NULL, 0, 0, 0, 0, 0, 1);
|
||||||
VERIFY3U(ENOENT, ==,
|
VERIFY3U(ENOENT, ==,
|
||||||
spa_create("ztest_bad_file", nvroot, NULL, NULL, NULL));
|
spa_create("ztest_bad_file", nvroot, NULL, NULL));
|
||||||
nvlist_free(nvroot);
|
nvlist_free(nvroot);
|
||||||
|
|
||||||
/*
|
/*
|
||||||
@ -2260,7 +2260,7 @@ ztest_spa_create_destroy(ztest_ds_t *zd, uint64_t id)
|
|||||||
*/
|
*/
|
||||||
nvroot = make_vdev_root("/dev/bogus", NULL, 0, 0, 0, 0, 2, 1);
|
nvroot = make_vdev_root("/dev/bogus", NULL, 0, 0, 0, 0, 2, 1);
|
||||||
VERIFY3U(ENOENT, ==,
|
VERIFY3U(ENOENT, ==,
|
||||||
spa_create("ztest_bad_mirror", nvroot, NULL, NULL, NULL));
|
spa_create("ztest_bad_mirror", nvroot, NULL, NULL));
|
||||||
nvlist_free(nvroot);
|
nvlist_free(nvroot);
|
||||||
|
|
||||||
/*
|
/*
|
||||||
@ -2269,7 +2269,7 @@ ztest_spa_create_destroy(ztest_ds_t *zd, uint64_t id)
|
|||||||
*/
|
*/
|
||||||
(void) rw_rdlock(&ztest_name_lock);
|
(void) rw_rdlock(&ztest_name_lock);
|
||||||
nvroot = make_vdev_root("/dev/bogus", NULL, 0, 0, 0, 0, 0, 1);
|
nvroot = make_vdev_root("/dev/bogus", NULL, 0, 0, 0, 0, 0, 1);
|
||||||
VERIFY3U(EEXIST, ==, spa_create(zo->zo_pool, nvroot, NULL, NULL, NULL));
|
VERIFY3U(EEXIST, ==, spa_create(zo->zo_pool, nvroot, NULL, NULL));
|
||||||
nvlist_free(nvroot);
|
nvlist_free(nvroot);
|
||||||
VERIFY3U(0, ==, spa_open(zo->zo_pool, &spa, FTAG));
|
VERIFY3U(0, ==, spa_open(zo->zo_pool, &spa, FTAG));
|
||||||
VERIFY3U(EBUSY, ==, spa_destroy(zo->zo_pool));
|
VERIFY3U(EBUSY, ==, spa_destroy(zo->zo_pool));
|
||||||
@ -3056,8 +3056,7 @@ ztest_snapshot_create(char *osname, uint64_t id)
|
|||||||
(void) snprintf(snapname, MAXNAMELEN, "%s@%llu", osname,
|
(void) snprintf(snapname, MAXNAMELEN, "%s@%llu", osname,
|
||||||
(u_longlong_t)id);
|
(u_longlong_t)id);
|
||||||
|
|
||||||
error = dmu_objset_snapshot(osname, strchr(snapname, '@') + 1,
|
error = dmu_objset_snapshot_one(osname, strchr(snapname, '@') + 1);
|
||||||
NULL, NULL, B_FALSE, B_FALSE, -1);
|
|
||||||
if (error == ENOSPC) {
|
if (error == ENOSPC) {
|
||||||
ztest_record_enospc(FTAG);
|
ztest_record_enospc(FTAG);
|
||||||
return (B_FALSE);
|
return (B_FALSE);
|
||||||
@ -3257,8 +3256,7 @@ ztest_dsl_dataset_promote_busy(ztest_ds_t *zd, uint64_t id)
|
|||||||
(void) snprintf(clone2name, MAXNAMELEN, "%s/c2_%llu", osname, id);
|
(void) snprintf(clone2name, MAXNAMELEN, "%s/c2_%llu", osname, id);
|
||||||
(void) snprintf(snap3name, MAXNAMELEN, "%s@s3_%llu", clone1name, id);
|
(void) snprintf(snap3name, MAXNAMELEN, "%s@s3_%llu", clone1name, id);
|
||||||
|
|
||||||
error = dmu_objset_snapshot(osname, strchr(snap1name, '@')+1,
|
error = dmu_objset_snapshot_one(osname, strchr(snap1name, '@') + 1);
|
||||||
NULL, NULL, B_FALSE, B_FALSE, -1);
|
|
||||||
if (error && error != EEXIST) {
|
if (error && error != EEXIST) {
|
||||||
if (error == ENOSPC) {
|
if (error == ENOSPC) {
|
||||||
ztest_record_enospc(FTAG);
|
ztest_record_enospc(FTAG);
|
||||||
@ -3281,8 +3279,7 @@ ztest_dsl_dataset_promote_busy(ztest_ds_t *zd, uint64_t id)
|
|||||||
fatal(0, "dmu_objset_create(%s) = %d", clone1name, error);
|
fatal(0, "dmu_objset_create(%s) = %d", clone1name, error);
|
||||||
}
|
}
|
||||||
|
|
||||||
error = dmu_objset_snapshot(clone1name, strchr(snap2name, '@')+1,
|
error = dmu_objset_snapshot_one(clone1name, strchr(snap2name, '@') + 1);
|
||||||
NULL, NULL, B_FALSE, B_FALSE, -1);
|
|
||||||
if (error && error != EEXIST) {
|
if (error && error != EEXIST) {
|
||||||
if (error == ENOSPC) {
|
if (error == ENOSPC) {
|
||||||
ztest_record_enospc(FTAG);
|
ztest_record_enospc(FTAG);
|
||||||
@ -3291,8 +3288,7 @@ ztest_dsl_dataset_promote_busy(ztest_ds_t *zd, uint64_t id)
|
|||||||
fatal(0, "dmu_open_snapshot(%s) = %d", snap2name, error);
|
fatal(0, "dmu_open_snapshot(%s) = %d", snap2name, error);
|
||||||
}
|
}
|
||||||
|
|
||||||
error = dmu_objset_snapshot(clone1name, strchr(snap3name, '@')+1,
|
error = dmu_objset_snapshot_one(clone1name, strchr(snap3name, '@') + 1);
|
||||||
NULL, NULL, B_FALSE, B_FALSE, -1);
|
|
||||||
if (error && error != EEXIST) {
|
if (error && error != EEXIST) {
|
||||||
if (error == ENOSPC) {
|
if (error == ENOSPC) {
|
||||||
ztest_record_enospc(FTAG);
|
ztest_record_enospc(FTAG);
|
||||||
@ -4480,8 +4476,7 @@ ztest_dmu_snapshot_hold(ztest_ds_t *zd, uint64_t id)
|
|||||||
* Create snapshot, clone it, mark snap for deferred destroy,
|
* Create snapshot, clone it, mark snap for deferred destroy,
|
||||||
* destroy clone, verify snap was also destroyed.
|
* destroy clone, verify snap was also destroyed.
|
||||||
*/
|
*/
|
||||||
error = dmu_objset_snapshot(osname, snapname, NULL, NULL, FALSE,
|
error = dmu_objset_snapshot_one(osname, snapname);
|
||||||
FALSE, -1);
|
|
||||||
if (error) {
|
if (error) {
|
||||||
if (error == ENOSPC) {
|
if (error == ENOSPC) {
|
||||||
ztest_record_enospc("dmu_objset_snapshot");
|
ztest_record_enospc("dmu_objset_snapshot");
|
||||||
@ -4523,8 +4518,7 @@ ztest_dmu_snapshot_hold(ztest_ds_t *zd, uint64_t id)
|
|||||||
* destroy a held snapshot, mark for deferred destroy,
|
* destroy a held snapshot, mark for deferred destroy,
|
||||||
* release hold, verify snapshot was destroyed.
|
* release hold, verify snapshot was destroyed.
|
||||||
*/
|
*/
|
||||||
error = dmu_objset_snapshot(osname, snapname, NULL, NULL, FALSE,
|
error = dmu_objset_snapshot_one(osname, snapname);
|
||||||
FALSE, -1);
|
|
||||||
if (error) {
|
if (error) {
|
||||||
if (error == ENOSPC) {
|
if (error == ENOSPC) {
|
||||||
ztest_record_enospc("dmu_objset_snapshot");
|
ztest_record_enospc("dmu_objset_snapshot");
|
||||||
@ -5612,8 +5606,7 @@ ztest_init(ztest_shared_t *zs)
|
|||||||
spa_feature_table[i].fi_uname);
|
spa_feature_table[i].fi_uname);
|
||||||
VERIFY3U(0, ==, nvlist_add_uint64(props, buf, 0));
|
VERIFY3U(0, ==, nvlist_add_uint64(props, buf, 0));
|
||||||
}
|
}
|
||||||
VERIFY3U(0, ==, spa_create(ztest_opts.zo_pool, nvroot, props,
|
VERIFY3U(0, ==, spa_create(ztest_opts.zo_pool, nvroot, props, NULL));
|
||||||
NULL, NULL));
|
|
||||||
nvlist_free(nvroot);
|
nvlist_free(nvroot);
|
||||||
|
|
||||||
VERIFY3U(0, ==, spa_open(ztest_opts.zo_pool, &spa, FTAG));
|
VERIFY3U(0, ==, spa_open(ztest_opts.zo_pool, &spa, FTAG));
|
||||||
|
@ -54,7 +54,8 @@ extern "C" {
|
|||||||
/*
|
/*
|
||||||
* libzfs errors
|
* libzfs errors
|
||||||
*/
|
*/
|
||||||
enum {
|
typedef enum zfs_error {
|
||||||
|
EZFS_SUCCESS = 0, /* no error -- success */
|
||||||
EZFS_NOMEM = 2000, /* out of memory */
|
EZFS_NOMEM = 2000, /* out of memory */
|
||||||
EZFS_BADPROP, /* invalid property value */
|
EZFS_BADPROP, /* invalid property value */
|
||||||
EZFS_PROPREADONLY, /* cannot set readonly property */
|
EZFS_PROPREADONLY, /* cannot set readonly property */
|
||||||
@ -126,7 +127,7 @@ enum {
|
|||||||
EZFS_DIFFDATA, /* bad zfs diff data */
|
EZFS_DIFFDATA, /* bad zfs diff data */
|
||||||
EZFS_POOLREADONLY, /* pool is in read-only mode */
|
EZFS_POOLREADONLY, /* pool is in read-only mode */
|
||||||
EZFS_UNKNOWN
|
EZFS_UNKNOWN
|
||||||
};
|
} zfs_error_t;
|
||||||
|
|
||||||
/*
|
/*
|
||||||
* The following data structures are all part
|
* The following data structures are all part
|
||||||
@ -182,6 +183,9 @@ extern libzfs_handle_t *zfs_get_handle(zfs_handle_t *);
|
|||||||
|
|
||||||
extern void libzfs_print_on_error(libzfs_handle_t *, boolean_t);
|
extern void libzfs_print_on_error(libzfs_handle_t *, boolean_t);
|
||||||
|
|
||||||
|
extern void zfs_save_arguments(int argc, char **, char *, int);
|
||||||
|
extern int zpool_log_history(libzfs_handle_t *, const char *);
|
||||||
|
|
||||||
extern int libzfs_errno(libzfs_handle_t *);
|
extern int libzfs_errno(libzfs_handle_t *);
|
||||||
extern const char *libzfs_error_action(libzfs_handle_t *);
|
extern const char *libzfs_error_action(libzfs_handle_t *);
|
||||||
extern const char *libzfs_error_description(libzfs_handle_t *);
|
extern const char *libzfs_error_description(libzfs_handle_t *);
|
||||||
@ -216,7 +220,7 @@ extern int zpool_iter(libzfs_handle_t *, zpool_iter_f, void *);
|
|||||||
*/
|
*/
|
||||||
extern int zpool_create(libzfs_handle_t *, const char *, nvlist_t *,
|
extern int zpool_create(libzfs_handle_t *, const char *, nvlist_t *,
|
||||||
nvlist_t *, nvlist_t *);
|
nvlist_t *, nvlist_t *);
|
||||||
extern int zpool_destroy(zpool_handle_t *);
|
extern int zpool_destroy(zpool_handle_t *, const char *);
|
||||||
extern int zpool_add(zpool_handle_t *, nvlist_t *);
|
extern int zpool_add(zpool_handle_t *, nvlist_t *);
|
||||||
|
|
||||||
typedef struct splitflags {
|
typedef struct splitflags {
|
||||||
@ -338,8 +342,8 @@ extern int zpool_get_errlog(zpool_handle_t *, nvlist_t **);
|
|||||||
/*
|
/*
|
||||||
* Import and export functions
|
* Import and export functions
|
||||||
*/
|
*/
|
||||||
extern int zpool_export(zpool_handle_t *, boolean_t);
|
extern int zpool_export(zpool_handle_t *, boolean_t, const char *);
|
||||||
extern int zpool_export_force(zpool_handle_t *);
|
extern int zpool_export_force(zpool_handle_t *, const char *);
|
||||||
extern int zpool_import(libzfs_handle_t *, nvlist_t *, const char *,
|
extern int zpool_import(libzfs_handle_t *, nvlist_t *, const char *,
|
||||||
char *altroot);
|
char *altroot);
|
||||||
extern int zpool_import_props(libzfs_handle_t *, nvlist_t *, const char *,
|
extern int zpool_import_props(libzfs_handle_t *, nvlist_t *, const char *,
|
||||||
@ -373,7 +377,7 @@ extern nvlist_t *zpool_find_import_cached(libzfs_handle_t *, const char *,
|
|||||||
*/
|
*/
|
||||||
struct zfs_cmd;
|
struct zfs_cmd;
|
||||||
|
|
||||||
extern const char *zfs_history_event_names[LOG_END];
|
extern const char *zfs_history_event_names[];
|
||||||
|
|
||||||
extern char *zpool_vdev_name(libzfs_handle_t *, zpool_handle_t *, nvlist_t *,
|
extern char *zpool_vdev_name(libzfs_handle_t *, zpool_handle_t *, nvlist_t *,
|
||||||
boolean_t verbose);
|
boolean_t verbose);
|
||||||
@ -381,9 +385,6 @@ extern int zpool_upgrade(zpool_handle_t *, uint64_t);
|
|||||||
extern int zpool_get_history(zpool_handle_t *, nvlist_t **);
|
extern int zpool_get_history(zpool_handle_t *, nvlist_t **);
|
||||||
extern int zpool_history_unpack(char *, uint64_t, uint64_t *,
|
extern int zpool_history_unpack(char *, uint64_t, uint64_t *,
|
||||||
nvlist_t ***, uint_t *);
|
nvlist_t ***, uint_t *);
|
||||||
extern void zpool_set_history_str(const char *subcommand, int argc,
|
|
||||||
char **argv, char *history_str);
|
|
||||||
extern int zpool_stage_history(libzfs_handle_t *, const char *);
|
|
||||||
extern void zpool_obj_to_path(zpool_handle_t *, uint64_t, uint64_t, char *,
|
extern void zpool_obj_to_path(zpool_handle_t *, uint64_t, uint64_t, char *,
|
||||||
size_t len);
|
size_t len);
|
||||||
extern int zfs_ioctl(libzfs_handle_t *, int, struct zfs_cmd *);
|
extern int zfs_ioctl(libzfs_handle_t *, int, struct zfs_cmd *);
|
||||||
@ -436,8 +437,6 @@ extern int zfs_prop_get_written(zfs_handle_t *zhp, const char *propname,
|
|||||||
char *propbuf, int proplen, boolean_t literal);
|
char *propbuf, int proplen, boolean_t literal);
|
||||||
extern int zfs_prop_get_feature(zfs_handle_t *zhp, const char *propname,
|
extern int zfs_prop_get_feature(zfs_handle_t *zhp, const char *propname,
|
||||||
char *buf, size_t len);
|
char *buf, size_t len);
|
||||||
extern int zfs_get_snapused_int(zfs_handle_t *firstsnap, zfs_handle_t *lastsnap,
|
|
||||||
uint64_t *usedp);
|
|
||||||
extern uint64_t zfs_prop_get_int(zfs_handle_t *, zfs_prop_t);
|
extern uint64_t zfs_prop_get_int(zfs_handle_t *, zfs_prop_t);
|
||||||
extern int zfs_prop_inherit(zfs_handle_t *, const char *, boolean_t);
|
extern int zfs_prop_inherit(zfs_handle_t *, const char *, boolean_t);
|
||||||
extern const char *zfs_prop_values(zfs_prop_t);
|
extern const char *zfs_prop_values(zfs_prop_t);
|
||||||
@ -553,6 +552,8 @@ extern int zfs_destroy_snaps(zfs_handle_t *, char *, boolean_t);
|
|||||||
extern int zfs_destroy_snaps_nvl(zfs_handle_t *, nvlist_t *, boolean_t);
|
extern int zfs_destroy_snaps_nvl(zfs_handle_t *, nvlist_t *, boolean_t);
|
||||||
extern int zfs_clone(zfs_handle_t *, const char *, nvlist_t *);
|
extern int zfs_clone(zfs_handle_t *, const char *, nvlist_t *);
|
||||||
extern int zfs_snapshot(libzfs_handle_t *, const char *, boolean_t, nvlist_t *);
|
extern int zfs_snapshot(libzfs_handle_t *, const char *, boolean_t, nvlist_t *);
|
||||||
|
extern int zfs_snapshot_nvl(libzfs_handle_t *hdl, nvlist_t *snaps,
|
||||||
|
nvlist_t *props);
|
||||||
extern int zfs_rollback(zfs_handle_t *, zfs_handle_t *, boolean_t);
|
extern int zfs_rollback(zfs_handle_t *, zfs_handle_t *, boolean_t);
|
||||||
extern int zfs_rename(zfs_handle_t *, const char *, boolean_t, boolean_t);
|
extern int zfs_rename(zfs_handle_t *, const char *, boolean_t, boolean_t);
|
||||||
|
|
||||||
|
@ -336,6 +336,48 @@ zpool_refresh_stats(zpool_handle_t *zhp, boolean_t *missing)
|
|||||||
return (0);
|
return (0);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/*
|
||||||
|
* If the __ZFS_POOL_RESTRICT environment variable is set we only iterate over
|
||||||
|
* pools it lists.
|
||||||
|
*
|
||||||
|
* This is an undocumented feature for use during testing only.
|
||||||
|
*
|
||||||
|
* This function returns B_TRUE if the pool should be skipped
|
||||||
|
* during iteration.
|
||||||
|
*/
|
||||||
|
static boolean_t
|
||||||
|
check_restricted(const char *poolname)
|
||||||
|
{
|
||||||
|
static boolean_t initialized = B_FALSE;
|
||||||
|
static char *restricted = NULL;
|
||||||
|
|
||||||
|
const char *cur, *end;
|
||||||
|
int len, namelen;
|
||||||
|
|
||||||
|
if (!initialized) {
|
||||||
|
initialized = B_TRUE;
|
||||||
|
restricted = getenv("__ZFS_POOL_RESTRICT");
|
||||||
|
}
|
||||||
|
|
||||||
|
if (NULL == restricted)
|
||||||
|
return (B_FALSE);
|
||||||
|
|
||||||
|
cur = restricted;
|
||||||
|
namelen = strlen(poolname);
|
||||||
|
do {
|
||||||
|
end = strchr(cur, ' ');
|
||||||
|
len = (NULL == end) ? strlen(cur) : (end - cur);
|
||||||
|
|
||||||
|
if (len == namelen && 0 == strncmp(cur, poolname, len)) {
|
||||||
|
return (B_FALSE);
|
||||||
|
}
|
||||||
|
|
||||||
|
cur += (len + 1);
|
||||||
|
} while (NULL != end);
|
||||||
|
|
||||||
|
return (B_TRUE);
|
||||||
|
}
|
||||||
|
|
||||||
/*
|
/*
|
||||||
* Iterate over all pools in the system.
|
* Iterate over all pools in the system.
|
||||||
*/
|
*/
|
||||||
@ -359,6 +401,9 @@ zpool_iter(libzfs_handle_t *hdl, zpool_iter_f func, void *data)
|
|||||||
for (cn = uu_avl_first(hdl->libzfs_ns_avl); cn != NULL;
|
for (cn = uu_avl_first(hdl->libzfs_ns_avl); cn != NULL;
|
||||||
cn = uu_avl_next(hdl->libzfs_ns_avl, cn)) {
|
cn = uu_avl_next(hdl->libzfs_ns_avl, cn)) {
|
||||||
|
|
||||||
|
if (check_restricted(cn->cn_name))
|
||||||
|
continue;
|
||||||
|
|
||||||
if (zpool_open_silent(hdl, cn->cn_name, &zhp) != 0) {
|
if (zpool_open_silent(hdl, cn->cn_name, &zhp) != 0) {
|
||||||
hdl->libzfs_pool_iter--;
|
hdl->libzfs_pool_iter--;
|
||||||
return (-1);
|
return (-1);
|
||||||
@ -394,6 +439,9 @@ zfs_iter_root(libzfs_handle_t *hdl, zfs_iter_f func, void *data)
|
|||||||
for (cn = uu_avl_first(hdl->libzfs_ns_avl); cn != NULL;
|
for (cn = uu_avl_first(hdl->libzfs_ns_avl); cn != NULL;
|
||||||
cn = uu_avl_next(hdl->libzfs_ns_avl, cn)) {
|
cn = uu_avl_next(hdl->libzfs_ns_avl, cn)) {
|
||||||
|
|
||||||
|
if (check_restricted(cn->cn_name))
|
||||||
|
continue;
|
||||||
|
|
||||||
if ((zhp = make_dataset_handle(hdl, cn->cn_name)) == NULL)
|
if ((zhp = make_dataset_handle(hdl, cn->cn_name)) == NULL)
|
||||||
continue;
|
continue;
|
||||||
|
|
||||||
|
@ -1407,8 +1407,7 @@ zfs_prop_set(zfs_handle_t *zhp, const char *propname, const char *propval)
|
|||||||
libzfs_handle_t *hdl = zhp->zfs_hdl;
|
libzfs_handle_t *hdl = zhp->zfs_hdl;
|
||||||
nvlist_t *nvl = NULL, *realprops;
|
nvlist_t *nvl = NULL, *realprops;
|
||||||
zfs_prop_t prop;
|
zfs_prop_t prop;
|
||||||
boolean_t do_prefix;
|
boolean_t do_prefix = B_TRUE;
|
||||||
uint64_t idx;
|
|
||||||
int added_resv;
|
int added_resv;
|
||||||
|
|
||||||
(void) snprintf(errbuf, sizeof (errbuf),
|
(void) snprintf(errbuf, sizeof (errbuf),
|
||||||
@ -1447,12 +1446,17 @@ zfs_prop_set(zfs_handle_t *zhp, const char *propname, const char *propval)
|
|||||||
}
|
}
|
||||||
|
|
||||||
/*
|
/*
|
||||||
* If the dataset's canmount property is being set to noauto,
|
* We don't want to unmount & remount the dataset when changing
|
||||||
* then we want to prevent unmounting & remounting it.
|
* its canmount property to 'on' or 'noauto'. We only use
|
||||||
|
* the changelist logic to unmount when setting canmount=off.
|
||||||
*/
|
*/
|
||||||
do_prefix = !((prop == ZFS_PROP_CANMOUNT) &&
|
if (prop == ZFS_PROP_CANMOUNT) {
|
||||||
(zprop_string_to_index(prop, propval, &idx,
|
uint64_t idx;
|
||||||
ZFS_TYPE_DATASET) == 0) && (idx == ZFS_CANMOUNT_NOAUTO));
|
int err = zprop_string_to_index(prop, propval, &idx,
|
||||||
|
ZFS_TYPE_DATASET);
|
||||||
|
if (err == 0 && idx != ZFS_CANMOUNT_OFF)
|
||||||
|
do_prefix = B_FALSE;
|
||||||
|
}
|
||||||
|
|
||||||
if (do_prefix && (ret = changelist_prefix(cl)) != 0)
|
if (do_prefix && (ret = changelist_prefix(cl)) != 0)
|
||||||
goto error;
|
goto error;
|
||||||
@ -2641,25 +2645,6 @@ zfs_prop_get_written(zfs_handle_t *zhp, const char *propname,
|
|||||||
return (0);
|
return (0);
|
||||||
}
|
}
|
||||||
|
|
||||||
int
|
|
||||||
zfs_get_snapused_int(zfs_handle_t *firstsnap, zfs_handle_t *lastsnap,
|
|
||||||
uint64_t *usedp)
|
|
||||||
{
|
|
||||||
int err;
|
|
||||||
zfs_cmd_t zc = { 0 };
|
|
||||||
|
|
||||||
(void) strlcpy(zc.zc_name, lastsnap->zfs_name, sizeof (zc.zc_name));
|
|
||||||
(void) strlcpy(zc.zc_value, firstsnap->zfs_name, sizeof (zc.zc_value));
|
|
||||||
|
|
||||||
err = ioctl(lastsnap->zfs_hdl->libzfs_fd, ZFS_IOC_SPACE_SNAPS, &zc);
|
|
||||||
if (err)
|
|
||||||
return (err);
|
|
||||||
|
|
||||||
*usedp = zc.zc_cookie;
|
|
||||||
|
|
||||||
return (0);
|
|
||||||
}
|
|
||||||
|
|
||||||
/*
|
/*
|
||||||
* Returns the name of the given zfs handle.
|
* Returns the name of the given zfs handle.
|
||||||
*/
|
*/
|
||||||
@ -2860,7 +2845,6 @@ create_parents(libzfs_handle_t *hdl, char *target, int prefixlen)
|
|||||||
*/
|
*/
|
||||||
for (cp = target + prefixlen + 1;
|
for (cp = target + prefixlen + 1;
|
||||||
cp = strchr(cp, '/'); *cp = '/', cp++) {
|
cp = strchr(cp, '/'); *cp = '/', cp++) {
|
||||||
char *logstr;
|
|
||||||
|
|
||||||
*cp = '\0';
|
*cp = '\0';
|
||||||
|
|
||||||
@ -2871,16 +2855,12 @@ create_parents(libzfs_handle_t *hdl, char *target, int prefixlen)
|
|||||||
continue;
|
continue;
|
||||||
}
|
}
|
||||||
|
|
||||||
logstr = hdl->libzfs_log_str;
|
|
||||||
hdl->libzfs_log_str = NULL;
|
|
||||||
if (zfs_create(hdl, target, ZFS_TYPE_FILESYSTEM,
|
if (zfs_create(hdl, target, ZFS_TYPE_FILESYSTEM,
|
||||||
NULL) != 0) {
|
NULL) != 0) {
|
||||||
hdl->libzfs_log_str = logstr;
|
|
||||||
opname = dgettext(TEXT_DOMAIN, "create");
|
opname = dgettext(TEXT_DOMAIN, "create");
|
||||||
goto ancestorerr;
|
goto ancestorerr;
|
||||||
}
|
}
|
||||||
|
|
||||||
hdl->libzfs_log_str = logstr;
|
|
||||||
h = zfs_open(hdl, target, ZFS_TYPE_FILESYSTEM);
|
h = zfs_open(hdl, target, ZFS_TYPE_FILESYSTEM);
|
||||||
if (h == NULL) {
|
if (h == NULL) {
|
||||||
opname = dgettext(TEXT_DOMAIN, "open");
|
opname = dgettext(TEXT_DOMAIN, "open");
|
||||||
@ -2938,12 +2918,12 @@ int
|
|||||||
zfs_create(libzfs_handle_t *hdl, const char *path, zfs_type_t type,
|
zfs_create(libzfs_handle_t *hdl, const char *path, zfs_type_t type,
|
||||||
nvlist_t *props)
|
nvlist_t *props)
|
||||||
{
|
{
|
||||||
zfs_cmd_t zc = { 0 };
|
|
||||||
int ret;
|
int ret;
|
||||||
uint64_t size = 0;
|
uint64_t size = 0;
|
||||||
uint64_t blocksize = zfs_prop_default_numeric(ZFS_PROP_VOLBLOCKSIZE);
|
uint64_t blocksize = zfs_prop_default_numeric(ZFS_PROP_VOLBLOCKSIZE);
|
||||||
char errbuf[1024];
|
char errbuf[1024];
|
||||||
uint64_t zoned;
|
uint64_t zoned;
|
||||||
|
dmu_objset_type_t ost;
|
||||||
|
|
||||||
(void) snprintf(errbuf, sizeof (errbuf), dgettext(TEXT_DOMAIN,
|
(void) snprintf(errbuf, sizeof (errbuf), dgettext(TEXT_DOMAIN,
|
||||||
"cannot create '%s'"), path);
|
"cannot create '%s'"), path);
|
||||||
@ -2963,17 +2943,16 @@ zfs_create(libzfs_handle_t *hdl, const char *path, zfs_type_t type,
|
|||||||
* will return ENOENT, not EEXIST. To prevent this from happening, we
|
* will return ENOENT, not EEXIST. To prevent this from happening, we
|
||||||
* first try to see if the dataset exists.
|
* first try to see if the dataset exists.
|
||||||
*/
|
*/
|
||||||
(void) strlcpy(zc.zc_name, path, sizeof (zc.zc_name));
|
if (zfs_dataset_exists(hdl, path, ZFS_TYPE_DATASET)) {
|
||||||
if (zfs_dataset_exists(hdl, zc.zc_name, ZFS_TYPE_DATASET)) {
|
|
||||||
zfs_error_aux(hdl, dgettext(TEXT_DOMAIN,
|
zfs_error_aux(hdl, dgettext(TEXT_DOMAIN,
|
||||||
"dataset already exists"));
|
"dataset already exists"));
|
||||||
return (zfs_error(hdl, EZFS_EXISTS, errbuf));
|
return (zfs_error(hdl, EZFS_EXISTS, errbuf));
|
||||||
}
|
}
|
||||||
|
|
||||||
if (type == ZFS_TYPE_VOLUME)
|
if (type == ZFS_TYPE_VOLUME)
|
||||||
zc.zc_objset_type = DMU_OST_ZVOL;
|
ost = DMU_OST_ZVOL;
|
||||||
else
|
else
|
||||||
zc.zc_objset_type = DMU_OST_ZFS;
|
ost = DMU_OST_ZFS;
|
||||||
|
|
||||||
if (props && (props = zfs_valid_proplist(hdl, type, props,
|
if (props && (props = zfs_valid_proplist(hdl, type, props,
|
||||||
zoned, NULL, errbuf)) == 0)
|
zoned, NULL, errbuf)) == 0)
|
||||||
@ -3025,14 +3004,9 @@ zfs_create(libzfs_handle_t *hdl, const char *path, zfs_type_t type,
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
if (props && zcmd_write_src_nvlist(hdl, &zc, props) != 0)
|
|
||||||
return (-1);
|
|
||||||
nvlist_free(props);
|
|
||||||
|
|
||||||
/* create the dataset */
|
/* create the dataset */
|
||||||
ret = zfs_ioctl(hdl, ZFS_IOC_CREATE, &zc);
|
ret = lzc_create(path, ost, props);
|
||||||
|
nvlist_free(props);
|
||||||
zcmd_free_nvlists(&zc);
|
|
||||||
|
|
||||||
/* check for failure */
|
/* check for failure */
|
||||||
if (ret != 0) {
|
if (ret != 0) {
|
||||||
@ -3084,7 +3058,8 @@ zfs_create(libzfs_handle_t *hdl, const char *path, zfs_type_t type,
|
|||||||
|
|
||||||
/*
|
/*
|
||||||
* Destroys the given dataset. The caller must make sure that the filesystem
|
* Destroys the given dataset. The caller must make sure that the filesystem
|
||||||
* isn't mounted, and that there are no active dependents.
|
* isn't mounted, and that there are no active dependents. If the file system
|
||||||
|
* does not exist this function does nothing.
|
||||||
*/
|
*/
|
||||||
int
|
int
|
||||||
zfs_destroy(zfs_handle_t *zhp, boolean_t defer)
|
zfs_destroy(zfs_handle_t *zhp, boolean_t defer)
|
||||||
@ -3100,7 +3075,8 @@ zfs_destroy(zfs_handle_t *zhp, boolean_t defer)
|
|||||||
}
|
}
|
||||||
|
|
||||||
zc.zc_defer_destroy = defer;
|
zc.zc_defer_destroy = defer;
|
||||||
if (zfs_ioctl(zhp->zfs_hdl, ZFS_IOC_DESTROY, &zc) != 0) {
|
if (zfs_ioctl(zhp->zfs_hdl, ZFS_IOC_DESTROY, &zc) != 0 &&
|
||||||
|
errno != ENOENT) {
|
||||||
return (zfs_standard_error_fmt(zhp->zfs_hdl, errno,
|
return (zfs_standard_error_fmt(zhp->zfs_hdl, errno,
|
||||||
dgettext(TEXT_DOMAIN, "cannot destroy '%s'"),
|
dgettext(TEXT_DOMAIN, "cannot destroy '%s'"),
|
||||||
zhp->zfs_name));
|
zhp->zfs_name));
|
||||||
@ -3170,33 +3146,35 @@ int
|
|||||||
zfs_destroy_snaps_nvl(zfs_handle_t *zhp, nvlist_t *snaps, boolean_t defer)
|
zfs_destroy_snaps_nvl(zfs_handle_t *zhp, nvlist_t *snaps, boolean_t defer)
|
||||||
{
|
{
|
||||||
int ret;
|
int ret;
|
||||||
zfs_cmd_t zc = { 0 };
|
nvlist_t *errlist;
|
||||||
|
|
||||||
(void) strlcpy(zc.zc_name, zhp->zfs_name, sizeof (zc.zc_name));
|
ret = lzc_destroy_snaps(snaps, defer, &errlist);
|
||||||
if (zcmd_write_src_nvlist(zhp->zfs_hdl, &zc, snaps) != 0)
|
|
||||||
return (-1);
|
|
||||||
zc.zc_defer_destroy = defer;
|
|
||||||
|
|
||||||
ret = zfs_ioctl(zhp->zfs_hdl, ZFS_IOC_DESTROY_SNAPS_NVL, &zc);
|
|
||||||
if (ret != 0) {
|
if (ret != 0) {
|
||||||
char errbuf[1024];
|
for (nvpair_t *pair = nvlist_next_nvpair(errlist, NULL);
|
||||||
|
pair != NULL; pair = nvlist_next_nvpair(errlist, pair)) {
|
||||||
|
char errbuf[1024];
|
||||||
|
(void) snprintf(errbuf, sizeof (errbuf),
|
||||||
|
dgettext(TEXT_DOMAIN, "cannot destroy snapshot %s"),
|
||||||
|
nvpair_name(pair));
|
||||||
|
|
||||||
(void) snprintf(errbuf, sizeof (errbuf), dgettext(TEXT_DOMAIN,
|
switch (fnvpair_value_int32(pair)) {
|
||||||
"cannot destroy snapshots in %s"), zc.zc_name);
|
case EEXIST:
|
||||||
|
zfs_error_aux(zhp->zfs_hdl,
|
||||||
switch (errno) {
|
dgettext(TEXT_DOMAIN,
|
||||||
case EEXIST:
|
"snapshot is cloned"));
|
||||||
zfs_error_aux(zhp->zfs_hdl, dgettext(TEXT_DOMAIN,
|
ret = zfs_error(zhp->zfs_hdl, EZFS_EXISTS,
|
||||||
"snapshot is cloned"));
|
errbuf);
|
||||||
return (zfs_error(zhp->zfs_hdl, EZFS_EXISTS, errbuf));
|
break;
|
||||||
|
default:
|
||||||
default:
|
ret = zfs_standard_error(zhp->zfs_hdl, errno,
|
||||||
return (zfs_standard_error(zhp->zfs_hdl, errno,
|
errbuf);
|
||||||
errbuf));
|
break;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
return (0);
|
return (ret);
|
||||||
}
|
}
|
||||||
|
|
||||||
/*
|
/*
|
||||||
@ -3205,12 +3183,10 @@ zfs_destroy_snaps_nvl(zfs_handle_t *zhp, nvlist_t *snaps, boolean_t defer)
|
|||||||
int
|
int
|
||||||
zfs_clone(zfs_handle_t *zhp, const char *target, nvlist_t *props)
|
zfs_clone(zfs_handle_t *zhp, const char *target, nvlist_t *props)
|
||||||
{
|
{
|
||||||
zfs_cmd_t zc = { 0 };
|
|
||||||
char parent[ZFS_MAXNAMELEN];
|
char parent[ZFS_MAXNAMELEN];
|
||||||
int ret;
|
int ret;
|
||||||
char errbuf[1024];
|
char errbuf[1024];
|
||||||
libzfs_handle_t *hdl = zhp->zfs_hdl;
|
libzfs_handle_t *hdl = zhp->zfs_hdl;
|
||||||
zfs_type_t type;
|
|
||||||
uint64_t zoned;
|
uint64_t zoned;
|
||||||
|
|
||||||
assert(zhp->zfs_type == ZFS_TYPE_SNAPSHOT);
|
assert(zhp->zfs_type == ZFS_TYPE_SNAPSHOT);
|
||||||
@ -3229,32 +3205,21 @@ zfs_clone(zfs_handle_t *zhp, const char *target, nvlist_t *props)
|
|||||||
(void) parent_name(target, parent, sizeof (parent));
|
(void) parent_name(target, parent, sizeof (parent));
|
||||||
|
|
||||||
/* do the clone */
|
/* do the clone */
|
||||||
if (ZFS_IS_VOLUME(zhp)) {
|
|
||||||
zc.zc_objset_type = DMU_OST_ZVOL;
|
|
||||||
type = ZFS_TYPE_VOLUME;
|
|
||||||
} else {
|
|
||||||
zc.zc_objset_type = DMU_OST_ZFS;
|
|
||||||
type = ZFS_TYPE_FILESYSTEM;
|
|
||||||
}
|
|
||||||
|
|
||||||
if (props) {
|
if (props) {
|
||||||
|
zfs_type_t type;
|
||||||
|
if (ZFS_IS_VOLUME(zhp)) {
|
||||||
|
type = ZFS_TYPE_VOLUME;
|
||||||
|
} else {
|
||||||
|
type = ZFS_TYPE_FILESYSTEM;
|
||||||
|
}
|
||||||
if ((props = zfs_valid_proplist(hdl, type, props, zoned,
|
if ((props = zfs_valid_proplist(hdl, type, props, zoned,
|
||||||
zhp, errbuf)) == NULL)
|
zhp, errbuf)) == NULL)
|
||||||
return (-1);
|
return (-1);
|
||||||
|
|
||||||
if (zcmd_write_src_nvlist(hdl, &zc, props) != 0) {
|
|
||||||
nvlist_free(props);
|
|
||||||
return (-1);
|
|
||||||
}
|
|
||||||
|
|
||||||
nvlist_free(props);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
(void) strlcpy(zc.zc_name, target, sizeof (zc.zc_name));
|
ret = lzc_clone(target, zhp->zfs_name, props);
|
||||||
(void) strlcpy(zc.zc_value, zhp->zfs_name, sizeof (zc.zc_value));
|
nvlist_free(props);
|
||||||
ret = zfs_ioctl(zhp->zfs_hdl, ZFS_IOC_CREATE, &zc);
|
|
||||||
|
|
||||||
zcmd_free_nvlists(&zc);
|
|
||||||
|
|
||||||
if (ret != 0) {
|
if (ret != 0) {
|
||||||
switch (errno) {
|
switch (errno) {
|
||||||
@ -3339,74 +3304,134 @@ zfs_promote(zfs_handle_t *zhp)
|
|||||||
return (ret);
|
return (ret);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
typedef struct snapdata {
|
||||||
|
nvlist_t *sd_nvl;
|
||||||
|
const char *sd_snapname;
|
||||||
|
} snapdata_t;
|
||||||
|
|
||||||
|
static int
|
||||||
|
zfs_snapshot_cb(zfs_handle_t *zhp, void *arg)
|
||||||
|
{
|
||||||
|
snapdata_t *sd = arg;
|
||||||
|
char name[ZFS_MAXNAMELEN];
|
||||||
|
int rv = 0;
|
||||||
|
|
||||||
|
(void) snprintf(name, sizeof (name),
|
||||||
|
"%s@%s", zfs_get_name(zhp), sd->sd_snapname);
|
||||||
|
|
||||||
|
fnvlist_add_boolean(sd->sd_nvl, name);
|
||||||
|
|
||||||
|
rv = zfs_iter_filesystems(zhp, zfs_snapshot_cb, sd);
|
||||||
|
zfs_close(zhp);
|
||||||
|
return (rv);
|
||||||
|
}
|
||||||
|
|
||||||
/*
|
/*
|
||||||
* Takes a snapshot of the given dataset.
|
* Creates snapshots. The keys in the snaps nvlist are the snapshots to be
|
||||||
|
* created.
|
||||||
*/
|
*/
|
||||||
|
int
|
||||||
|
zfs_snapshot_nvl(libzfs_handle_t *hdl, nvlist_t *snaps, nvlist_t *props)
|
||||||
|
{
|
||||||
|
int ret;
|
||||||
|
char errbuf[1024];
|
||||||
|
nvpair_t *elem;
|
||||||
|
nvlist_t *errors;
|
||||||
|
|
||||||
|
(void) snprintf(errbuf, sizeof (errbuf), dgettext(TEXT_DOMAIN,
|
||||||
|
"cannot create snapshots "));
|
||||||
|
|
||||||
|
elem = NULL;
|
||||||
|
while ((elem = nvlist_next_nvpair(snaps, elem)) != NULL) {
|
||||||
|
const char *snapname = nvpair_name(elem);
|
||||||
|
|
||||||
|
/* validate the target name */
|
||||||
|
if (!zfs_validate_name(hdl, snapname, ZFS_TYPE_SNAPSHOT,
|
||||||
|
B_TRUE)) {
|
||||||
|
(void) snprintf(errbuf, sizeof (errbuf),
|
||||||
|
dgettext(TEXT_DOMAIN,
|
||||||
|
"cannot create snapshot '%s'"), snapname);
|
||||||
|
return (zfs_error(hdl, EZFS_INVALIDNAME, errbuf));
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
if (props != NULL &&
|
||||||
|
(props = zfs_valid_proplist(hdl, ZFS_TYPE_SNAPSHOT,
|
||||||
|
props, B_FALSE, NULL, errbuf)) == NULL) {
|
||||||
|
return (-1);
|
||||||
|
}
|
||||||
|
|
||||||
|
ret = lzc_snapshot(snaps, props, &errors);
|
||||||
|
|
||||||
|
if (ret != 0) {
|
||||||
|
boolean_t printed = B_FALSE;
|
||||||
|
for (elem = nvlist_next_nvpair(errors, NULL);
|
||||||
|
elem != NULL;
|
||||||
|
elem = nvlist_next_nvpair(errors, elem)) {
|
||||||
|
(void) snprintf(errbuf, sizeof (errbuf),
|
||||||
|
dgettext(TEXT_DOMAIN,
|
||||||
|
"cannot create snapshot '%s'"), nvpair_name(elem));
|
||||||
|
(void) zfs_standard_error(hdl,
|
||||||
|
fnvpair_value_int32(elem), errbuf);
|
||||||
|
printed = B_TRUE;
|
||||||
|
}
|
||||||
|
if (!printed) {
|
||||||
|
switch (ret) {
|
||||||
|
case EXDEV:
|
||||||
|
zfs_error_aux(hdl, dgettext(TEXT_DOMAIN,
|
||||||
|
"multiple snapshots of same "
|
||||||
|
"fs not allowed"));
|
||||||
|
(void) zfs_error(hdl, EZFS_EXISTS, errbuf);
|
||||||
|
|
||||||
|
break;
|
||||||
|
default:
|
||||||
|
(void) zfs_standard_error(hdl, ret, errbuf);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
nvlist_free(props);
|
||||||
|
nvlist_free(errors);
|
||||||
|
return (ret);
|
||||||
|
}
|
||||||
|
|
||||||
int
|
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)
|
nvlist_t *props)
|
||||||
{
|
{
|
||||||
const char *delim;
|
|
||||||
char parent[ZFS_MAXNAMELEN];
|
|
||||||
zfs_handle_t *zhp;
|
|
||||||
zfs_cmd_t zc = { 0 };
|
|
||||||
int ret;
|
int ret;
|
||||||
|
snapdata_t sd = { 0 };
|
||||||
|
char fsname[ZFS_MAXNAMELEN];
|
||||||
|
char *cp;
|
||||||
|
zfs_handle_t *zhp;
|
||||||
char errbuf[1024];
|
char errbuf[1024];
|
||||||
|
|
||||||
(void) snprintf(errbuf, sizeof (errbuf), dgettext(TEXT_DOMAIN,
|
(void) snprintf(errbuf, sizeof (errbuf), dgettext(TEXT_DOMAIN,
|
||||||
"cannot snapshot '%s'"), path);
|
"cannot snapshot %s"), path);
|
||||||
|
|
||||||
/* validate the target name */
|
|
||||||
if (!zfs_validate_name(hdl, path, ZFS_TYPE_SNAPSHOT, B_TRUE))
|
if (!zfs_validate_name(hdl, path, ZFS_TYPE_SNAPSHOT, B_TRUE))
|
||||||
return (zfs_error(hdl, EZFS_INVALIDNAME, errbuf));
|
return (zfs_error(hdl, EZFS_INVALIDNAME, errbuf));
|
||||||
|
|
||||||
if (props) {
|
(void) strlcpy(fsname, path, sizeof (fsname));
|
||||||
if ((props = zfs_valid_proplist(hdl, ZFS_TYPE_SNAPSHOT,
|
cp = strchr(fsname, '@');
|
||||||
props, B_FALSE, NULL, errbuf)) == NULL)
|
*cp = '\0';
|
||||||
return (-1);
|
sd.sd_snapname = cp + 1;
|
||||||
|
|
||||||
if (zcmd_write_src_nvlist(hdl, &zc, props) != 0) {
|
if ((zhp = zfs_open(hdl, fsname, ZFS_TYPE_FILESYSTEM |
|
||||||
nvlist_free(props);
|
|
||||||
return (-1);
|
|
||||||
}
|
|
||||||
|
|
||||||
nvlist_free(props);
|
|
||||||
}
|
|
||||||
|
|
||||||
/* make sure the parent exists and is of the appropriate type */
|
|
||||||
delim = strchr(path, '@');
|
|
||||||
(void) strncpy(parent, path, delim - path);
|
|
||||||
parent[delim - path] = '\0';
|
|
||||||
|
|
||||||
if ((zhp = zfs_open(hdl, parent, ZFS_TYPE_FILESYSTEM |
|
|
||||||
ZFS_TYPE_VOLUME)) == NULL) {
|
ZFS_TYPE_VOLUME)) == NULL) {
|
||||||
zcmd_free_nvlists(&zc);
|
|
||||||
return (-1);
|
return (-1);
|
||||||
}
|
}
|
||||||
|
|
||||||
(void) strlcpy(zc.zc_name, zhp->zfs_name, sizeof (zc.zc_name));
|
verify(nvlist_alloc(&sd.sd_nvl, NV_UNIQUE_NAME, 0) == 0);
|
||||||
(void) strlcpy(zc.zc_value, delim+1, sizeof (zc.zc_value));
|
if (recursive) {
|
||||||
if (ZFS_IS_VOLUME(zhp))
|
(void) zfs_snapshot_cb(zfs_handle_dup(zhp), &sd);
|
||||||
zc.zc_objset_type = DMU_OST_ZVOL;
|
} else {
|
||||||
else
|
fnvlist_add_boolean(sd.sd_nvl, path);
|
||||||
zc.zc_objset_type = DMU_OST_ZFS;
|
|
||||||
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.
|
|
||||||
*/
|
|
||||||
if (ret != 0) {
|
|
||||||
(void) snprintf(errbuf, sizeof (errbuf), dgettext(TEXT_DOMAIN,
|
|
||||||
"cannot create snapshot '%s@%s'"), zc.zc_name, zc.zc_value);
|
|
||||||
(void) zfs_standard_error(hdl, errno, errbuf);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
|
ret = zfs_snapshot_nvl(hdl, sd.sd_nvl, props);
|
||||||
|
nvlist_free(sd.sd_nvl);
|
||||||
zfs_close(zhp);
|
zfs_close(zhp);
|
||||||
|
|
||||||
return (ret);
|
return (ret);
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -3434,17 +3459,13 @@ rollback_destroy(zfs_handle_t *zhp, void *data)
|
|||||||
zfs_get_type(zhp) == ZFS_TYPE_SNAPSHOT &&
|
zfs_get_type(zhp) == ZFS_TYPE_SNAPSHOT &&
|
||||||
zfs_prop_get_int(zhp, ZFS_PROP_CREATETXG) >
|
zfs_prop_get_int(zhp, ZFS_PROP_CREATETXG) >
|
||||||
cbp->cb_create) {
|
cbp->cb_create) {
|
||||||
char *logstr;
|
|
||||||
|
|
||||||
cbp->cb_dependent = B_TRUE;
|
cbp->cb_dependent = B_TRUE;
|
||||||
cbp->cb_error |= zfs_iter_dependents(zhp, B_FALSE,
|
cbp->cb_error |= zfs_iter_dependents(zhp, B_FALSE,
|
||||||
rollback_destroy, cbp);
|
rollback_destroy, cbp);
|
||||||
cbp->cb_dependent = B_FALSE;
|
cbp->cb_dependent = B_FALSE;
|
||||||
|
|
||||||
logstr = zhp->zfs_hdl->libzfs_log_str;
|
|
||||||
zhp->zfs_hdl->libzfs_log_str = NULL;
|
|
||||||
cbp->cb_error |= zfs_destroy(zhp, B_FALSE);
|
cbp->cb_error |= zfs_destroy(zhp, B_FALSE);
|
||||||
zhp->zfs_hdl->libzfs_log_str = logstr;
|
|
||||||
}
|
}
|
||||||
} else {
|
} else {
|
||||||
/* We must destroy this clone; first unmount it */
|
/* We must destroy this clone; first unmount it */
|
||||||
|
@ -21,11 +21,11 @@
|
|||||||
|
|
||||||
/*
|
/*
|
||||||
* Copyright (c) 2005, 2010, Oracle and/or its affiliates. All rights reserved.
|
* Copyright (c) 2005, 2010, Oracle and/or its affiliates. All rights reserved.
|
||||||
* Copyright (c) 2011 by Delphix. All rights reserved.
|
* Copyright (c) 2012 by Delphix. All rights reserved.
|
||||||
*/
|
*/
|
||||||
|
|
||||||
#ifndef _LIBFS_IMPL_H
|
#ifndef _LIBZFS_IMPL_H
|
||||||
#define _LIBFS_IMPL_H
|
#define _LIBZFS_IMPL_H
|
||||||
|
|
||||||
#include <sys/dmu.h>
|
#include <sys/dmu.h>
|
||||||
#include <sys/fs/zfs.h>
|
#include <sys/fs/zfs.h>
|
||||||
@ -36,6 +36,7 @@
|
|||||||
#include <libuutil.h>
|
#include <libuutil.h>
|
||||||
#include <libzfs.h>
|
#include <libzfs.h>
|
||||||
#include <libshare.h>
|
#include <libshare.h>
|
||||||
|
#include <libzfs_core.h>
|
||||||
|
|
||||||
#include <fm/libtopo.h>
|
#include <fm/libtopo.h>
|
||||||
|
|
||||||
@ -67,7 +68,6 @@ struct libzfs_handle {
|
|||||||
int libzfs_desc_active;
|
int libzfs_desc_active;
|
||||||
char libzfs_action[1024];
|
char libzfs_action[1024];
|
||||||
char libzfs_desc[1024];
|
char libzfs_desc[1024];
|
||||||
char *libzfs_log_str;
|
|
||||||
int libzfs_printerr;
|
int libzfs_printerr;
|
||||||
int libzfs_storeerr; /* stuff error messages into buffer */
|
int libzfs_storeerr; /* stuff error messages into buffer */
|
||||||
void *libzfs_sharehdl; /* libshare handle */
|
void *libzfs_sharehdl; /* libshare handle */
|
||||||
@ -213,4 +213,4 @@ extern void libzfs_fru_clear(libzfs_handle_t *, boolean_t);
|
|||||||
}
|
}
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
#endif /* _LIBFS_IMPL_H */
|
#endif /* _LIBZFS_IMPL_H */
|
||||||
|
@ -22,7 +22,7 @@
|
|||||||
/*
|
/*
|
||||||
* Copyright (c) 2005, 2010, Oracle and/or its affiliates. All rights reserved.
|
* Copyright (c) 2005, 2010, Oracle and/or its affiliates. All rights reserved.
|
||||||
* Copyright 2010 Nexenta Systems, Inc. All rights reserved.
|
* Copyright 2010 Nexenta Systems, Inc. All rights reserved.
|
||||||
* Copyright (c) 2011 by Delphix. All rights reserved.
|
* Copyright (c) 2012 by Delphix. All rights reserved.
|
||||||
*/
|
*/
|
||||||
|
|
||||||
#include <stdio.h>
|
#include <stdio.h>
|
||||||
@ -301,12 +301,11 @@ int
|
|||||||
zfs_iter_snapspec(zfs_handle_t *fs_zhp, const char *spec_orig,
|
zfs_iter_snapspec(zfs_handle_t *fs_zhp, const char *spec_orig,
|
||||||
zfs_iter_f func, void *arg)
|
zfs_iter_f func, void *arg)
|
||||||
{
|
{
|
||||||
char buf[ZFS_MAXNAMELEN];
|
char *buf, *comma_separated, *cp;
|
||||||
char *comma_separated, *cp;
|
|
||||||
int err = 0;
|
int err = 0;
|
||||||
int ret = 0;
|
int ret = 0;
|
||||||
|
|
||||||
(void) strlcpy(buf, spec_orig, sizeof (buf));
|
buf = zfs_strdup(fs_zhp->zfs_hdl, spec_orig);
|
||||||
cp = buf;
|
cp = buf;
|
||||||
|
|
||||||
while ((comma_separated = strsep(&cp, ",")) != NULL) {
|
while ((comma_separated = strsep(&cp, ",")) != NULL) {
|
||||||
@ -364,6 +363,7 @@ zfs_iter_snapspec(zfs_handle_t *fs_zhp, const char *spec_orig,
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
free(buf);
|
||||||
return (ret);
|
return (ret);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -34,6 +34,7 @@
|
|||||||
#include <stdlib.h>
|
#include <stdlib.h>
|
||||||
#include <strings.h>
|
#include <strings.h>
|
||||||
#include <unistd.h>
|
#include <unistd.h>
|
||||||
|
#include <libgen.h>
|
||||||
#include <sys/efi_partition.h>
|
#include <sys/efi_partition.h>
|
||||||
#include <sys/vtoc.h>
|
#include <sys/vtoc.h>
|
||||||
#include <sys/zfs_ioctl.h>
|
#include <sys/zfs_ioctl.h>
|
||||||
@ -1205,7 +1206,7 @@ zpool_create(libzfs_handle_t *hdl, const char *pool, nvlist_t *nvroot,
|
|||||||
* datasets left in the pool.
|
* datasets left in the pool.
|
||||||
*/
|
*/
|
||||||
int
|
int
|
||||||
zpool_destroy(zpool_handle_t *zhp)
|
zpool_destroy(zpool_handle_t *zhp, const char *log_str)
|
||||||
{
|
{
|
||||||
zfs_cmd_t zc = { 0 };
|
zfs_cmd_t zc = { 0 };
|
||||||
zfs_handle_t *zfp = NULL;
|
zfs_handle_t *zfp = NULL;
|
||||||
@ -1217,6 +1218,7 @@ zpool_destroy(zpool_handle_t *zhp)
|
|||||||
return (-1);
|
return (-1);
|
||||||
|
|
||||||
(void) strlcpy(zc.zc_name, zhp->zpool_name, sizeof (zc.zc_name));
|
(void) strlcpy(zc.zc_name, zhp->zpool_name, sizeof (zc.zc_name));
|
||||||
|
zc.zc_history = (uint64_t)(uintptr_t)log_str;
|
||||||
|
|
||||||
if (zfs_ioctl(hdl, ZFS_IOC_POOL_DESTROY, &zc) != 0) {
|
if (zfs_ioctl(hdl, ZFS_IOC_POOL_DESTROY, &zc) != 0) {
|
||||||
(void) snprintf(msg, sizeof (msg), dgettext(TEXT_DOMAIN,
|
(void) snprintf(msg, sizeof (msg), dgettext(TEXT_DOMAIN,
|
||||||
@ -1371,8 +1373,9 @@ zpool_add(zpool_handle_t *zhp, nvlist_t *nvroot)
|
|||||||
* Exports the pool from the system. The caller must ensure that there are no
|
* Exports the pool from the system. The caller must ensure that there are no
|
||||||
* mounted datasets in the pool.
|
* mounted datasets in the pool.
|
||||||
*/
|
*/
|
||||||
int
|
static int
|
||||||
zpool_export_common(zpool_handle_t *zhp, boolean_t force, boolean_t hardforce)
|
zpool_export_common(zpool_handle_t *zhp, boolean_t force, boolean_t hardforce,
|
||||||
|
const char *log_str)
|
||||||
{
|
{
|
||||||
zfs_cmd_t zc = { 0 };
|
zfs_cmd_t zc = { 0 };
|
||||||
char msg[1024];
|
char msg[1024];
|
||||||
@ -1383,6 +1386,7 @@ zpool_export_common(zpool_handle_t *zhp, boolean_t force, boolean_t hardforce)
|
|||||||
(void) strlcpy(zc.zc_name, zhp->zpool_name, sizeof (zc.zc_name));
|
(void) strlcpy(zc.zc_name, zhp->zpool_name, sizeof (zc.zc_name));
|
||||||
zc.zc_cookie = force;
|
zc.zc_cookie = force;
|
||||||
zc.zc_guid = hardforce;
|
zc.zc_guid = hardforce;
|
||||||
|
zc.zc_history = (uint64_t)(uintptr_t)log_str;
|
||||||
|
|
||||||
if (zfs_ioctl(zhp->zpool_hdl, ZFS_IOC_POOL_EXPORT, &zc) != 0) {
|
if (zfs_ioctl(zhp->zpool_hdl, ZFS_IOC_POOL_EXPORT, &zc) != 0) {
|
||||||
switch (errno) {
|
switch (errno) {
|
||||||
@ -1404,15 +1408,15 @@ zpool_export_common(zpool_handle_t *zhp, boolean_t force, boolean_t hardforce)
|
|||||||
}
|
}
|
||||||
|
|
||||||
int
|
int
|
||||||
zpool_export(zpool_handle_t *zhp, boolean_t force)
|
zpool_export(zpool_handle_t *zhp, boolean_t force, const char *log_str)
|
||||||
{
|
{
|
||||||
return (zpool_export_common(zhp, force, B_FALSE));
|
return (zpool_export_common(zhp, force, B_FALSE, log_str));
|
||||||
}
|
}
|
||||||
|
|
||||||
int
|
int
|
||||||
zpool_export_force(zpool_handle_t *zhp)
|
zpool_export_force(zpool_handle_t *zhp, const char *log_str)
|
||||||
{
|
{
|
||||||
return (zpool_export_common(zhp, B_TRUE, B_TRUE));
|
return (zpool_export_common(zhp, B_TRUE, B_TRUE, log_str));
|
||||||
}
|
}
|
||||||
|
|
||||||
static void
|
static void
|
||||||
@ -3574,40 +3578,30 @@ zpool_upgrade(zpool_handle_t *zhp, uint64_t new_version)
|
|||||||
}
|
}
|
||||||
|
|
||||||
void
|
void
|
||||||
zpool_set_history_str(const char *subcommand, int argc, char **argv,
|
zfs_save_arguments(int argc, char **argv, char *string, int len)
|
||||||
char *history_str)
|
|
||||||
{
|
{
|
||||||
int i;
|
(void) strlcpy(string, basename(argv[0]), len);
|
||||||
|
for (int i = 1; i < argc; i++) {
|
||||||
(void) strlcpy(history_str, subcommand, HIS_MAX_RECORD_LEN);
|
(void) strlcat(string, " ", len);
|
||||||
for (i = 1; i < argc; i++) {
|
(void) strlcat(string, argv[i], len);
|
||||||
if (strlen(history_str) + 1 + strlen(argv[i]) >
|
|
||||||
HIS_MAX_RECORD_LEN)
|
|
||||||
break;
|
|
||||||
(void) strlcat(history_str, " ", HIS_MAX_RECORD_LEN);
|
|
||||||
(void) strlcat(history_str, argv[i], HIS_MAX_RECORD_LEN);
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
/*
|
|
||||||
* Stage command history for logging.
|
|
||||||
*/
|
|
||||||
int
|
int
|
||||||
zpool_stage_history(libzfs_handle_t *hdl, const char *history_str)
|
zpool_log_history(libzfs_handle_t *hdl, const char *message)
|
||||||
{
|
{
|
||||||
if (history_str == NULL)
|
zfs_cmd_t zc = { 0 };
|
||||||
return (EINVAL);
|
nvlist_t *args;
|
||||||
|
int err;
|
||||||
|
|
||||||
if (strlen(history_str) > HIS_MAX_RECORD_LEN)
|
args = fnvlist_alloc();
|
||||||
return (EINVAL);
|
fnvlist_add_string(args, "message", message);
|
||||||
|
err = zcmd_write_src_nvlist(hdl, &zc, args);
|
||||||
if (hdl->libzfs_log_str != NULL)
|
if (err == 0)
|
||||||
free(hdl->libzfs_log_str);
|
err = ioctl(hdl->libzfs_fd, ZFS_IOC_LOG_HISTORY, &zc);
|
||||||
|
nvlist_free(args);
|
||||||
if ((hdl->libzfs_log_str = strdup(history_str)) == NULL)
|
zcmd_free_nvlists(&zc);
|
||||||
return (no_memory(hdl));
|
return (err);
|
||||||
|
|
||||||
return (0);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
/*
|
/*
|
||||||
|
@ -21,7 +21,7 @@
|
|||||||
|
|
||||||
/*
|
/*
|
||||||
* Copyright (c) 2005, 2010, Oracle and/or its affiliates. All rights reserved.
|
* Copyright (c) 2005, 2010, Oracle and/or its affiliates. All rights reserved.
|
||||||
* Copyright (c) 2011 by Delphix. All rights reserved.
|
* Copyright (c) 2012 by Delphix. All rights reserved.
|
||||||
* Copyright (c) 2012, Joyent, Inc. All rights reserved.
|
* Copyright (c) 2012, Joyent, Inc. All rights reserved.
|
||||||
*/
|
*/
|
||||||
|
|
||||||
@ -1381,7 +1381,6 @@ zfs_send(zfs_handle_t *zhp, const char *fromsnap, const char *tosnap,
|
|||||||
avl_tree_t *fsavl = NULL;
|
avl_tree_t *fsavl = NULL;
|
||||||
static uint64_t holdseq;
|
static uint64_t holdseq;
|
||||||
int spa_version;
|
int spa_version;
|
||||||
boolean_t holdsnaps = B_FALSE;
|
|
||||||
pthread_t tid;
|
pthread_t tid;
|
||||||
int pipefd[2];
|
int pipefd[2];
|
||||||
dedup_arg_t dda = { 0 };
|
dedup_arg_t dda = { 0 };
|
||||||
@ -1404,11 +1403,6 @@ zfs_send(zfs_handle_t *zhp, const char *fromsnap, const char *tosnap,
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
if (!flags->dryrun && zfs_spa_version(zhp, &spa_version) == 0 &&
|
|
||||||
spa_version >= SPA_VERSION_USERREFS &&
|
|
||||||
(flags->doall || flags->replicate))
|
|
||||||
holdsnaps = B_TRUE;
|
|
||||||
|
|
||||||
if (flags->dedup && !flags->dryrun) {
|
if (flags->dedup && !flags->dryrun) {
|
||||||
featureflags |= (DMU_BACKUP_FEATURE_DEDUP |
|
featureflags |= (DMU_BACKUP_FEATURE_DEDUP |
|
||||||
DMU_BACKUP_FEATURE_DEDUPPROPS);
|
DMU_BACKUP_FEATURE_DEDUPPROPS);
|
||||||
@ -1530,7 +1524,18 @@ zfs_send(zfs_handle_t *zhp, const char *fromsnap, const char *tosnap,
|
|||||||
sdd.filter_cb_arg = cb_arg;
|
sdd.filter_cb_arg = cb_arg;
|
||||||
if (debugnvp)
|
if (debugnvp)
|
||||||
sdd.debugnv = *debugnvp;
|
sdd.debugnv = *debugnvp;
|
||||||
if (holdsnaps || flags->progress) {
|
|
||||||
|
/*
|
||||||
|
* Some flags require that we place user holds on the datasets that are
|
||||||
|
* being sent so they don't get destroyed during the send. We can skip
|
||||||
|
* this step if the pool is imported read-only since the datasets cannot
|
||||||
|
* be destroyed.
|
||||||
|
*/
|
||||||
|
if (!flags->dryrun && !zpool_get_prop_int(zfs_get_pool_handle(zhp),
|
||||||
|
ZPOOL_PROP_READONLY, NULL) &&
|
||||||
|
zfs_spa_version(zhp, &spa_version) == 0 &&
|
||||||
|
spa_version >= SPA_VERSION_USERREFS &&
|
||||||
|
(flags->doall || flags->replicate)) {
|
||||||
++holdseq;
|
++holdseq;
|
||||||
(void) snprintf(sdd.holdtag, sizeof (sdd.holdtag),
|
(void) snprintf(sdd.holdtag, sizeof (sdd.holdtag),
|
||||||
".send-%d-%llu", getpid(), (u_longlong_t)holdseq);
|
".send-%d-%llu", getpid(), (u_longlong_t)holdseq);
|
||||||
|
@ -43,6 +43,7 @@
|
|||||||
#include <sys/types.h>
|
#include <sys/types.h>
|
||||||
|
|
||||||
#include <libzfs.h>
|
#include <libzfs.h>
|
||||||
|
#include <libzfs_core.h>
|
||||||
|
|
||||||
#include "libzfs_impl.h"
|
#include "libzfs_impl.h"
|
||||||
#include "zfs_prop.h"
|
#include "zfs_prop.h"
|
||||||
@ -630,6 +631,14 @@ libzfs_init(void)
|
|||||||
|
|
||||||
hdl->libzfs_sharetab = fopen("/etc/dfs/sharetab", "r");
|
hdl->libzfs_sharetab = fopen("/etc/dfs/sharetab", "r");
|
||||||
|
|
||||||
|
if (libzfs_core_init() != 0) {
|
||||||
|
(void) close(hdl->libzfs_fd);
|
||||||
|
(void) fclose(hdl->libzfs_mnttab);
|
||||||
|
(void) fclose(hdl->libzfs_sharetab);
|
||||||
|
free(hdl);
|
||||||
|
return (NULL);
|
||||||
|
}
|
||||||
|
|
||||||
zfs_prop_init();
|
zfs_prop_init();
|
||||||
zpool_prop_init();
|
zpool_prop_init();
|
||||||
zpool_feature_init();
|
zpool_feature_init();
|
||||||
@ -647,12 +656,11 @@ libzfs_fini(libzfs_handle_t *hdl)
|
|||||||
if (hdl->libzfs_sharetab)
|
if (hdl->libzfs_sharetab)
|
||||||
(void) fclose(hdl->libzfs_sharetab);
|
(void) fclose(hdl->libzfs_sharetab);
|
||||||
zfs_uninit_libshare(hdl);
|
zfs_uninit_libshare(hdl);
|
||||||
if (hdl->libzfs_log_str)
|
|
||||||
(void) free(hdl->libzfs_log_str);
|
|
||||||
zpool_free_handles(hdl);
|
zpool_free_handles(hdl);
|
||||||
libzfs_fru_clear(hdl, B_TRUE);
|
libzfs_fru_clear(hdl, B_TRUE);
|
||||||
namespace_clear(hdl);
|
namespace_clear(hdl);
|
||||||
libzfs_mnttab_fini(hdl);
|
libzfs_mnttab_fini(hdl);
|
||||||
|
libzfs_core_fini();
|
||||||
free(hdl);
|
free(hdl);
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -814,17 +822,7 @@ zcmd_read_dst_nvlist(libzfs_handle_t *hdl, zfs_cmd_t *zc, nvlist_t **nvlp)
|
|||||||
int
|
int
|
||||||
zfs_ioctl(libzfs_handle_t *hdl, int request, zfs_cmd_t *zc)
|
zfs_ioctl(libzfs_handle_t *hdl, int request, zfs_cmd_t *zc)
|
||||||
{
|
{
|
||||||
int error;
|
return (ioctl(hdl->libzfs_fd, request, zc));
|
||||||
|
|
||||||
zc->zc_history = (uint64_t)(uintptr_t)hdl->libzfs_log_str;
|
|
||||||
error = ioctl(hdl->libzfs_fd, request, zc);
|
|
||||||
if (hdl->libzfs_log_str) {
|
|
||||||
free(hdl->libzfs_log_str);
|
|
||||||
hdl->libzfs_log_str = NULL;
|
|
||||||
}
|
|
||||||
zc->zc_history = 0;
|
|
||||||
|
|
||||||
return (error);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
/*
|
/*
|
||||||
|
477
lib/libzfs_core/common/libzfs_core.c
Normal file
477
lib/libzfs_core/common/libzfs_core.c
Normal file
@ -0,0 +1,477 @@
|
|||||||
|
/*
|
||||||
|
* CDDL HEADER START
|
||||||
|
*
|
||||||
|
* The contents of this file are subject to the terms of the
|
||||||
|
* Common Development and Distribution License (the "License").
|
||||||
|
* You may not use this file except in compliance with the License.
|
||||||
|
*
|
||||||
|
* You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE
|
||||||
|
* or http://www.opensolaris.org/os/licensing.
|
||||||
|
* See the License for the specific language governing permissions
|
||||||
|
* and limitations under the License.
|
||||||
|
*
|
||||||
|
* When distributing Covered Code, include this CDDL HEADER in each
|
||||||
|
* file and include the License file at usr/src/OPENSOLARIS.LICENSE.
|
||||||
|
* If applicable, add the following below this CDDL HEADER, with the
|
||||||
|
* fields enclosed by brackets "[]" replaced with your own identifying
|
||||||
|
* information: Portions Copyright [yyyy] [name of copyright owner]
|
||||||
|
*
|
||||||
|
* CDDL HEADER END
|
||||||
|
*/
|
||||||
|
|
||||||
|
/*
|
||||||
|
* Copyright (c) 2012 by Delphix. All rights reserved.
|
||||||
|
*/
|
||||||
|
|
||||||
|
/*
|
||||||
|
* LibZFS_Core (lzc) is intended to replace most functionality in libzfs.
|
||||||
|
* It has the following characteristics:
|
||||||
|
*
|
||||||
|
* - Thread Safe. libzfs_core is accessible concurrently from multiple
|
||||||
|
* threads. This is accomplished primarily by avoiding global data
|
||||||
|
* (e.g. caching). Since it's thread-safe, there is no reason for a
|
||||||
|
* process to have multiple libzfs "instances". Therefore, we store
|
||||||
|
* our few pieces of data (e.g. the file descriptor) in global
|
||||||
|
* variables. The fd is reference-counted so that the libzfs_core
|
||||||
|
* library can be "initialized" multiple times (e.g. by different
|
||||||
|
* consumers within the same process).
|
||||||
|
*
|
||||||
|
* - Committed Interface. The libzfs_core interface will be committed,
|
||||||
|
* therefore consumers can compile against it and be confident that
|
||||||
|
* their code will continue to work on future releases of this code.
|
||||||
|
* Currently, the interface is Evolving (not Committed), but we intend
|
||||||
|
* to commit to it once it is more complete and we determine that it
|
||||||
|
* meets the needs of all consumers.
|
||||||
|
*
|
||||||
|
* - Programatic Error Handling. libzfs_core communicates errors with
|
||||||
|
* defined error numbers, and doesn't print anything to stdout/stderr.
|
||||||
|
*
|
||||||
|
* - Thin Layer. libzfs_core is a thin layer, marshaling arguments
|
||||||
|
* to/from the kernel ioctls. There is generally a 1:1 correspondence
|
||||||
|
* between libzfs_core functions and ioctls to /dev/zfs.
|
||||||
|
*
|
||||||
|
* - Clear Atomicity. Because libzfs_core functions are generally 1:1
|
||||||
|
* with kernel ioctls, and kernel ioctls are general atomic, each
|
||||||
|
* libzfs_core function is atomic. For example, creating multiple
|
||||||
|
* snapshots with a single call to lzc_snapshot() is atomic -- it
|
||||||
|
* can't fail with only some of the requested snapshots created, even
|
||||||
|
* in the event of power loss or system crash.
|
||||||
|
*
|
||||||
|
* - Continued libzfs Support. Some higher-level operations (e.g.
|
||||||
|
* support for "zfs send -R") are too complicated to fit the scope of
|
||||||
|
* libzfs_core. This functionality will continue to live in libzfs.
|
||||||
|
* Where appropriate, libzfs will use the underlying atomic operations
|
||||||
|
* of libzfs_core. For example, libzfs may implement "zfs send -R |
|
||||||
|
* zfs receive" by using individual "send one snapshot", rename,
|
||||||
|
* destroy, and "receive one snapshot" operations in libzfs_core.
|
||||||
|
* /sbin/zfs and /zbin/zpool will link with both libzfs and
|
||||||
|
* libzfs_core. Other consumers should aim to use only libzfs_core,
|
||||||
|
* since that will be the supported, stable interface going forwards.
|
||||||
|
*/
|
||||||
|
|
||||||
|
#include <libzfs_core.h>
|
||||||
|
#include <ctype.h>
|
||||||
|
#include <unistd.h>
|
||||||
|
#include <stdlib.h>
|
||||||
|
#include <string.h>
|
||||||
|
#include <errno.h>
|
||||||
|
#include <fcntl.h>
|
||||||
|
#include <pthread.h>
|
||||||
|
#include <sys/nvpair.h>
|
||||||
|
#include <sys/param.h>
|
||||||
|
#include <sys/types.h>
|
||||||
|
#include <sys/stat.h>
|
||||||
|
#include <sys/zfs_ioctl.h>
|
||||||
|
|
||||||
|
static int g_fd;
|
||||||
|
static pthread_mutex_t g_lock = PTHREAD_MUTEX_INITIALIZER;
|
||||||
|
static int g_refcount;
|
||||||
|
|
||||||
|
int
|
||||||
|
libzfs_core_init(void)
|
||||||
|
{
|
||||||
|
(void) pthread_mutex_lock(&g_lock);
|
||||||
|
if (g_refcount == 0) {
|
||||||
|
g_fd = open("/dev/zfs", O_RDWR);
|
||||||
|
if (g_fd < 0) {
|
||||||
|
(void) pthread_mutex_unlock(&g_lock);
|
||||||
|
return (errno);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
g_refcount++;
|
||||||
|
(void) pthread_mutex_unlock(&g_lock);
|
||||||
|
return (0);
|
||||||
|
}
|
||||||
|
|
||||||
|
void
|
||||||
|
libzfs_core_fini(void)
|
||||||
|
{
|
||||||
|
(void) pthread_mutex_lock(&g_lock);
|
||||||
|
ASSERT3S(g_refcount, >, 0);
|
||||||
|
g_refcount--;
|
||||||
|
if (g_refcount == 0)
|
||||||
|
(void) close(g_fd);
|
||||||
|
(void) pthread_mutex_unlock(&g_lock);
|
||||||
|
}
|
||||||
|
|
||||||
|
static int
|
||||||
|
lzc_ioctl(zfs_ioc_t ioc, const char *name,
|
||||||
|
nvlist_t *source, nvlist_t **resultp)
|
||||||
|
{
|
||||||
|
zfs_cmd_t zc = { 0 };
|
||||||
|
int error = 0;
|
||||||
|
char *packed;
|
||||||
|
size_t size;
|
||||||
|
|
||||||
|
ASSERT3S(g_refcount, >, 0);
|
||||||
|
|
||||||
|
(void) strlcpy(zc.zc_name, name, sizeof (zc.zc_name));
|
||||||
|
|
||||||
|
packed = fnvlist_pack(source, &size);
|
||||||
|
zc.zc_nvlist_src = (uint64_t)(uintptr_t)packed;
|
||||||
|
zc.zc_nvlist_src_size = size;
|
||||||
|
|
||||||
|
if (resultp != NULL) {
|
||||||
|
zc.zc_nvlist_dst_size = MAX(size * 2, 128 * 1024);
|
||||||
|
zc.zc_nvlist_dst = (uint64_t)(uintptr_t)
|
||||||
|
malloc(zc.zc_nvlist_dst_size);
|
||||||
|
if (zc.zc_nvlist_dst == NULL) {
|
||||||
|
error = ENOMEM;
|
||||||
|
goto out;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
while (ioctl(g_fd, ioc, &zc) != 0) {
|
||||||
|
if (errno == ENOMEM && resultp != NULL) {
|
||||||
|
free((void *)(uintptr_t)zc.zc_nvlist_dst);
|
||||||
|
zc.zc_nvlist_dst_size *= 2;
|
||||||
|
zc.zc_nvlist_dst = (uint64_t)(uintptr_t)
|
||||||
|
malloc(zc.zc_nvlist_dst_size);
|
||||||
|
if (zc.zc_nvlist_dst == NULL) {
|
||||||
|
error = ENOMEM;
|
||||||
|
goto out;
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
error = errno;
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
if (zc.zc_nvlist_dst_filled) {
|
||||||
|
*resultp = fnvlist_unpack((void *)(uintptr_t)zc.zc_nvlist_dst,
|
||||||
|
zc.zc_nvlist_dst_size);
|
||||||
|
} else if (resultp != NULL) {
|
||||||
|
*resultp = NULL;
|
||||||
|
}
|
||||||
|
|
||||||
|
out:
|
||||||
|
fnvlist_pack_free(packed, size);
|
||||||
|
free((void *)(uintptr_t)zc.zc_nvlist_dst);
|
||||||
|
return (error);
|
||||||
|
}
|
||||||
|
|
||||||
|
int
|
||||||
|
lzc_create(const char *fsname, dmu_objset_type_t type, nvlist_t *props)
|
||||||
|
{
|
||||||
|
int error;
|
||||||
|
nvlist_t *args = fnvlist_alloc();
|
||||||
|
fnvlist_add_int32(args, "type", type);
|
||||||
|
if (props != NULL)
|
||||||
|
fnvlist_add_nvlist(args, "props", props);
|
||||||
|
error = lzc_ioctl(ZFS_IOC_CREATE, fsname, args, NULL);
|
||||||
|
nvlist_free(args);
|
||||||
|
return (error);
|
||||||
|
}
|
||||||
|
|
||||||
|
int
|
||||||
|
lzc_clone(const char *fsname, const char *origin,
|
||||||
|
nvlist_t *props)
|
||||||
|
{
|
||||||
|
int error;
|
||||||
|
nvlist_t *args = fnvlist_alloc();
|
||||||
|
fnvlist_add_string(args, "origin", origin);
|
||||||
|
if (props != NULL)
|
||||||
|
fnvlist_add_nvlist(args, "props", props);
|
||||||
|
error = lzc_ioctl(ZFS_IOC_CLONE, fsname, args, NULL);
|
||||||
|
nvlist_free(args);
|
||||||
|
return (error);
|
||||||
|
}
|
||||||
|
|
||||||
|
/*
|
||||||
|
* Creates snapshots.
|
||||||
|
*
|
||||||
|
* The keys in the snaps nvlist are the snapshots to be created.
|
||||||
|
* They must all be in the same pool.
|
||||||
|
*
|
||||||
|
* The props nvlist is properties to set. Currently only user properties
|
||||||
|
* are supported. { user:prop_name -> string value }
|
||||||
|
*
|
||||||
|
* The returned results nvlist will have an entry for each snapshot that failed.
|
||||||
|
* The value will be the (int32) error code.
|
||||||
|
*
|
||||||
|
* The return value will be 0 if all snapshots were created, otherwise it will
|
||||||
|
* be the errno of a (undetermined) snapshot that failed.
|
||||||
|
*/
|
||||||
|
int
|
||||||
|
lzc_snapshot(nvlist_t *snaps, nvlist_t *props, nvlist_t **errlist)
|
||||||
|
{
|
||||||
|
nvpair_t *elem;
|
||||||
|
nvlist_t *args;
|
||||||
|
int error;
|
||||||
|
char pool[MAXNAMELEN];
|
||||||
|
|
||||||
|
*errlist = NULL;
|
||||||
|
|
||||||
|
/* determine the pool name */
|
||||||
|
elem = nvlist_next_nvpair(snaps, NULL);
|
||||||
|
if (elem == NULL)
|
||||||
|
return (0);
|
||||||
|
(void) strlcpy(pool, nvpair_name(elem), sizeof (pool));
|
||||||
|
pool[strcspn(pool, "/@")] = '\0';
|
||||||
|
|
||||||
|
args = fnvlist_alloc();
|
||||||
|
fnvlist_add_nvlist(args, "snaps", snaps);
|
||||||
|
if (props != NULL)
|
||||||
|
fnvlist_add_nvlist(args, "props", props);
|
||||||
|
|
||||||
|
error = lzc_ioctl(ZFS_IOC_SNAPSHOT, pool, args, errlist);
|
||||||
|
nvlist_free(args);
|
||||||
|
|
||||||
|
return (error);
|
||||||
|
}
|
||||||
|
|
||||||
|
/*
|
||||||
|
* Destroys snapshots.
|
||||||
|
*
|
||||||
|
* The keys in the snaps nvlist are the snapshots to be destroyed.
|
||||||
|
* They must all be in the same pool.
|
||||||
|
*
|
||||||
|
* Snapshots that do not exist will be silently ignored.
|
||||||
|
*
|
||||||
|
* If 'defer' is not set, and a snapshot has user holds or clones, the
|
||||||
|
* destroy operation will fail and none of the snapshots will be
|
||||||
|
* destroyed.
|
||||||
|
*
|
||||||
|
* If 'defer' is set, and a snapshot has user holds or clones, it will be
|
||||||
|
* marked for deferred destruction, and will be destroyed when the last hold
|
||||||
|
* or clone is removed/destroyed.
|
||||||
|
*
|
||||||
|
* The return value will be 0 if all snapshots were destroyed (or marked for
|
||||||
|
* later destruction if 'defer' is set) or didn't exist to begin with.
|
||||||
|
*
|
||||||
|
* Otherwise the return value will be the errno of a (undetermined) snapshot
|
||||||
|
* that failed, no snapshots will be destroyed, and the errlist will have an
|
||||||
|
* entry for each snapshot that failed. The value in the errlist will be
|
||||||
|
* the (int32) error code.
|
||||||
|
*/
|
||||||
|
int
|
||||||
|
lzc_destroy_snaps(nvlist_t *snaps, boolean_t defer, nvlist_t **errlist)
|
||||||
|
{
|
||||||
|
nvpair_t *elem;
|
||||||
|
nvlist_t *args;
|
||||||
|
int error;
|
||||||
|
char pool[MAXNAMELEN];
|
||||||
|
|
||||||
|
/* determine the pool name */
|
||||||
|
elem = nvlist_next_nvpair(snaps, NULL);
|
||||||
|
if (elem == NULL)
|
||||||
|
return (0);
|
||||||
|
(void) strlcpy(pool, nvpair_name(elem), sizeof (pool));
|
||||||
|
pool[strcspn(pool, "/@")] = '\0';
|
||||||
|
|
||||||
|
args = fnvlist_alloc();
|
||||||
|
fnvlist_add_nvlist(args, "snaps", snaps);
|
||||||
|
if (defer)
|
||||||
|
fnvlist_add_boolean(args, "defer");
|
||||||
|
|
||||||
|
error = lzc_ioctl(ZFS_IOC_DESTROY_SNAPS, pool, args, errlist);
|
||||||
|
nvlist_free(args);
|
||||||
|
|
||||||
|
return (error);
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
int
|
||||||
|
lzc_snaprange_space(const char *firstsnap, const char *lastsnap,
|
||||||
|
uint64_t *usedp)
|
||||||
|
{
|
||||||
|
nvlist_t *args;
|
||||||
|
nvlist_t *result;
|
||||||
|
int err;
|
||||||
|
char fs[MAXNAMELEN];
|
||||||
|
char *atp;
|
||||||
|
|
||||||
|
/* determine the fs name */
|
||||||
|
(void) strlcpy(fs, firstsnap, sizeof (fs));
|
||||||
|
atp = strchr(fs, '@');
|
||||||
|
if (atp == NULL)
|
||||||
|
return (EINVAL);
|
||||||
|
*atp = '\0';
|
||||||
|
|
||||||
|
args = fnvlist_alloc();
|
||||||
|
fnvlist_add_string(args, "firstsnap", firstsnap);
|
||||||
|
|
||||||
|
err = lzc_ioctl(ZFS_IOC_SPACE_SNAPS, lastsnap, args, &result);
|
||||||
|
nvlist_free(args);
|
||||||
|
if (err == 0)
|
||||||
|
*usedp = fnvlist_lookup_uint64(result, "used");
|
||||||
|
fnvlist_free(result);
|
||||||
|
|
||||||
|
return (err);
|
||||||
|
}
|
||||||
|
|
||||||
|
boolean_t
|
||||||
|
lzc_exists(const char *dataset)
|
||||||
|
{
|
||||||
|
/*
|
||||||
|
* The objset_stats ioctl is still legacy, so we need to construct our
|
||||||
|
* own zfs_cmd_t rather than using zfsc_ioctl().
|
||||||
|
*/
|
||||||
|
zfs_cmd_t zc = { 0 };
|
||||||
|
|
||||||
|
(void) strlcpy(zc.zc_name, dataset, sizeof (zc.zc_name));
|
||||||
|
return (ioctl(g_fd, ZFS_IOC_OBJSET_STATS, &zc) == 0);
|
||||||
|
}
|
||||||
|
|
||||||
|
/*
|
||||||
|
* If fromsnap is NULL, a full (non-incremental) stream will be sent.
|
||||||
|
*/
|
||||||
|
int
|
||||||
|
lzc_send(const char *snapname, const char *fromsnap, int fd)
|
||||||
|
{
|
||||||
|
nvlist_t *args;
|
||||||
|
int err;
|
||||||
|
|
||||||
|
args = fnvlist_alloc();
|
||||||
|
fnvlist_add_int32(args, "fd", fd);
|
||||||
|
if (fromsnap != NULL)
|
||||||
|
fnvlist_add_string(args, "fromsnap", fromsnap);
|
||||||
|
err = lzc_ioctl(ZFS_IOC_SEND_NEW, snapname, args, NULL);
|
||||||
|
nvlist_free(args);
|
||||||
|
return (err);
|
||||||
|
}
|
||||||
|
|
||||||
|
/*
|
||||||
|
* If fromsnap is NULL, a full (non-incremental) stream will be estimated.
|
||||||
|
*/
|
||||||
|
int
|
||||||
|
lzc_send_space(const char *snapname, const char *fromsnap, uint64_t *spacep)
|
||||||
|
{
|
||||||
|
nvlist_t *args;
|
||||||
|
nvlist_t *result;
|
||||||
|
int err;
|
||||||
|
|
||||||
|
args = fnvlist_alloc();
|
||||||
|
if (fromsnap != NULL)
|
||||||
|
fnvlist_add_string(args, "fromsnap", fromsnap);
|
||||||
|
err = lzc_ioctl(ZFS_IOC_SEND_SPACE, snapname, args, &result);
|
||||||
|
nvlist_free(args);
|
||||||
|
if (err == 0)
|
||||||
|
*spacep = fnvlist_lookup_uint64(result, "space");
|
||||||
|
nvlist_free(result);
|
||||||
|
return (err);
|
||||||
|
}
|
||||||
|
|
||||||
|
static int
|
||||||
|
recv_read(int fd, void *buf, int ilen)
|
||||||
|
{
|
||||||
|
char *cp = buf;
|
||||||
|
int rv;
|
||||||
|
int len = ilen;
|
||||||
|
|
||||||
|
do {
|
||||||
|
rv = read(fd, cp, len);
|
||||||
|
cp += rv;
|
||||||
|
len -= rv;
|
||||||
|
} while (rv > 0);
|
||||||
|
|
||||||
|
if (rv < 0 || len != 0)
|
||||||
|
return (EIO);
|
||||||
|
|
||||||
|
return (0);
|
||||||
|
}
|
||||||
|
|
||||||
|
/*
|
||||||
|
* The simplest receive case: receive from the specified fd, creating the
|
||||||
|
* specified snapshot. Apply the specified properties a "received" properties
|
||||||
|
* (which can be overridden by locally-set properties). If the stream is a
|
||||||
|
* clone, its origin snapshot must be specified by 'origin'. The 'force'
|
||||||
|
* flag will cause the target filesystem to be rolled back or destroyed if
|
||||||
|
* necessary to receive.
|
||||||
|
*
|
||||||
|
* Return 0 on success or an errno on failure.
|
||||||
|
*
|
||||||
|
* Note: this interface does not work on dedup'd streams
|
||||||
|
* (those with DMU_BACKUP_FEATURE_DEDUP).
|
||||||
|
*/
|
||||||
|
int
|
||||||
|
lzc_receive(const char *snapname, nvlist_t *props, const char *origin,
|
||||||
|
boolean_t force, int fd)
|
||||||
|
{
|
||||||
|
/*
|
||||||
|
* The receive ioctl is still legacy, so we need to construct our own
|
||||||
|
* zfs_cmd_t rather than using zfsc_ioctl().
|
||||||
|
*/
|
||||||
|
zfs_cmd_t zc = { 0 };
|
||||||
|
char *atp;
|
||||||
|
char *packed = NULL;
|
||||||
|
size_t size;
|
||||||
|
dmu_replay_record_t drr;
|
||||||
|
int error;
|
||||||
|
|
||||||
|
ASSERT3S(g_refcount, >, 0);
|
||||||
|
|
||||||
|
/* zc_name is name of containing filesystem */
|
||||||
|
(void) strlcpy(zc.zc_name, snapname, sizeof (zc.zc_name));
|
||||||
|
atp = strchr(zc.zc_name, '@');
|
||||||
|
if (atp == NULL)
|
||||||
|
return (EINVAL);
|
||||||
|
*atp = '\0';
|
||||||
|
|
||||||
|
/* if the fs does not exist, try its parent. */
|
||||||
|
if (!lzc_exists(zc.zc_name)) {
|
||||||
|
char *slashp = strrchr(zc.zc_name, '/');
|
||||||
|
if (slashp == NULL)
|
||||||
|
return (ENOENT);
|
||||||
|
*slashp = '\0';
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
/* zc_value is full name of the snapshot to create */
|
||||||
|
(void) strlcpy(zc.zc_value, snapname, sizeof (zc.zc_value));
|
||||||
|
|
||||||
|
if (props != NULL) {
|
||||||
|
/* zc_nvlist_src is props to set */
|
||||||
|
packed = fnvlist_pack(props, &size);
|
||||||
|
zc.zc_nvlist_src = (uint64_t)(uintptr_t)packed;
|
||||||
|
zc.zc_nvlist_src_size = size;
|
||||||
|
}
|
||||||
|
|
||||||
|
/* zc_string is name of clone origin (if DRR_FLAG_CLONE) */
|
||||||
|
if (origin != NULL)
|
||||||
|
(void) strlcpy(zc.zc_string, origin, sizeof (zc.zc_string));
|
||||||
|
|
||||||
|
/* zc_begin_record is non-byteswapped BEGIN record */
|
||||||
|
error = recv_read(fd, &drr, sizeof (drr));
|
||||||
|
if (error != 0)
|
||||||
|
goto out;
|
||||||
|
zc.zc_begin_record = drr.drr_u.drr_begin;
|
||||||
|
|
||||||
|
/* zc_cookie is fd to read from */
|
||||||
|
zc.zc_cookie = fd;
|
||||||
|
|
||||||
|
/* zc guid is force flag */
|
||||||
|
zc.zc_guid = force;
|
||||||
|
|
||||||
|
/* zc_cleanup_fd is unused */
|
||||||
|
zc.zc_cleanup_fd = -1;
|
||||||
|
|
||||||
|
error = ioctl(g_fd, ZFS_IOC_RECV, &zc);
|
||||||
|
if (error != 0)
|
||||||
|
error = errno;
|
||||||
|
|
||||||
|
out:
|
||||||
|
if (packed != NULL)
|
||||||
|
fnvlist_pack_free(packed, size);
|
||||||
|
free((void*)(uintptr_t)zc.zc_nvlist_dst);
|
||||||
|
return (error);
|
||||||
|
}
|
62
lib/libzfs_core/common/libzfs_core.h
Normal file
62
lib/libzfs_core/common/libzfs_core.h
Normal file
@ -0,0 +1,62 @@
|
|||||||
|
/*
|
||||||
|
* CDDL HEADER START
|
||||||
|
*
|
||||||
|
* The contents of this file are subject to the terms of the
|
||||||
|
* Common Development and Distribution License (the "License").
|
||||||
|
* You may not use this file except in compliance with the License.
|
||||||
|
*
|
||||||
|
* You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE
|
||||||
|
* or http://www.opensolaris.org/os/licensing.
|
||||||
|
* See the License for the specific language governing permissions
|
||||||
|
* and limitations under the License.
|
||||||
|
*
|
||||||
|
* When distributing Covered Code, include this CDDL HEADER in each
|
||||||
|
* file and include the License file at usr/src/OPENSOLARIS.LICENSE.
|
||||||
|
* If applicable, add the following below this CDDL HEADER, with the
|
||||||
|
* fields enclosed by brackets "[]" replaced with your own identifying
|
||||||
|
* information: Portions Copyright [yyyy] [name of copyright owner]
|
||||||
|
*
|
||||||
|
* CDDL HEADER END
|
||||||
|
*/
|
||||||
|
|
||||||
|
/*
|
||||||
|
* Copyright (c) 2012 by Delphix. All rights reserved.
|
||||||
|
*/
|
||||||
|
|
||||||
|
#ifndef _LIBZFS_CORE_H
|
||||||
|
#define _LIBZFS_CORE_H
|
||||||
|
|
||||||
|
#include <libnvpair.h>
|
||||||
|
#include <sys/param.h>
|
||||||
|
#include <sys/types.h>
|
||||||
|
#include <sys/fs/zfs.h>
|
||||||
|
|
||||||
|
#ifdef __cplusplus
|
||||||
|
extern "C" {
|
||||||
|
#endif
|
||||||
|
|
||||||
|
int libzfs_core_init(void);
|
||||||
|
void libzfs_core_fini(void);
|
||||||
|
|
||||||
|
int lzc_snapshot(nvlist_t *snaps, nvlist_t *props, nvlist_t **errlist);
|
||||||
|
int lzc_create(const char *fsname, dmu_objset_type_t type, nvlist_t *props);
|
||||||
|
int lzc_clone(const char *fsname, const char *origin, nvlist_t *props);
|
||||||
|
int lzc_destroy_snaps(nvlist_t *snaps, boolean_t defer, nvlist_t **errlist);
|
||||||
|
|
||||||
|
int lzc_snaprange_space(const char *firstsnap, const char *lastsnap,
|
||||||
|
uint64_t *usedp);
|
||||||
|
|
||||||
|
int lzc_send(const char *snapname, const char *fromsnap, int fd);
|
||||||
|
int lzc_receive(const char *snapname, nvlist_t *props, const char *origin,
|
||||||
|
boolean_t force, int fd);
|
||||||
|
int lzc_send_space(const char *snapname, const char *fromsnap,
|
||||||
|
uint64_t *result);
|
||||||
|
|
||||||
|
boolean_t lzc_exists(const char *dataset);
|
||||||
|
|
||||||
|
|
||||||
|
#ifdef __cplusplus
|
||||||
|
}
|
||||||
|
#endif
|
||||||
|
|
||||||
|
#endif /* _LIBZFS_CORE_H */
|
@ -871,6 +871,12 @@ crgetuid(cred_t *cr)
|
|||||||
return (0);
|
return (0);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
uid_t
|
||||||
|
crgetruid(cred_t *cr)
|
||||||
|
{
|
||||||
|
return (0);
|
||||||
|
}
|
||||||
|
|
||||||
gid_t
|
gid_t
|
||||||
crgetgid(cred_t *cr)
|
crgetgid(cred_t *cr)
|
||||||
{
|
{
|
||||||
|
@ -286,6 +286,7 @@ extern void rw_exit(krwlock_t *rwlp);
|
|||||||
#define rw_downgrade(rwlp) do { } while (0)
|
#define rw_downgrade(rwlp) do { } while (0)
|
||||||
|
|
||||||
extern uid_t crgetuid(cred_t *cr);
|
extern uid_t crgetuid(cred_t *cr);
|
||||||
|
extern uid_t crgetruid(cred_t *cr);
|
||||||
extern gid_t crgetgid(cred_t *cr);
|
extern gid_t crgetgid(cred_t *cr);
|
||||||
extern int crgetngroups(cred_t *cr);
|
extern int crgetngroups(cred_t *cr);
|
||||||
extern gid_t *crgetgroups(cred_t *cr);
|
extern gid_t *crgetgroups(cred_t *cr);
|
||||||
|
@ -39,7 +39,7 @@ zfs \- configures ZFS file systems
|
|||||||
.LP
|
.LP
|
||||||
.nf
|
.nf
|
||||||
\fBzfs\fR \fBsnapshot\fR [\fB-r\fR] [\fB-o\fR \fIproperty\fR=\fIvalue\fR]...
|
\fBzfs\fR \fBsnapshot\fR [\fB-r\fR] [\fB-o\fR \fIproperty\fR=\fIvalue\fR]...
|
||||||
\fIfilesystem@snapname\fR|\fIvolume@snapname\fR
|
\fIfilesystem@snapname\fR|\fIvolume@snapname\fR...
|
||||||
.fi
|
.fi
|
||||||
|
|
||||||
.LP
|
.LP
|
||||||
@ -1837,13 +1837,14 @@ behavior for mounted file systems in use.
|
|||||||
.ne 2
|
.ne 2
|
||||||
.na
|
.na
|
||||||
\fB\fBzfs snapshot\fR [\fB-r\fR] [\fB-o\fR \fIproperty\fR=\fIvalue\fR] ...
|
\fB\fBzfs snapshot\fR [\fB-r\fR] [\fB-o\fR \fIproperty\fR=\fIvalue\fR] ...
|
||||||
\fIfilesystem@snapname\fR|\fIvolume@snapname\fR\fR
|
\fIfilesystem@snapname\fR|\fIvolume@snapname\fR\fR...
|
||||||
.ad
|
.ad
|
||||||
.sp .6
|
.sp .6
|
||||||
.RS 4n
|
.RS 4n
|
||||||
Creates a snapshot with the given name. All previous modifications by
|
Creates snapshots with the given names. All previous modifications by
|
||||||
successful system calls to the file system are part of the snapshot. See the
|
successful system calls to the file system are part of the snapshots.
|
||||||
"Snapshots" section for details.
|
Snapshots are taken atomically, so that all snapshots correspond to the same
|
||||||
|
moment in time. See the "Snapshots" section for details.
|
||||||
.sp
|
.sp
|
||||||
.ne 2
|
.ne 2
|
||||||
.na
|
.na
|
||||||
@ -1851,9 +1852,7 @@ successful system calls to the file system are part of the snapshot. See the
|
|||||||
.ad
|
.ad
|
||||||
.sp .6
|
.sp .6
|
||||||
.RS 4n
|
.RS 4n
|
||||||
Recursively create snapshots of all descendent datasets. Snapshots are taken
|
Recursively create snapshots of all descendent datasets
|
||||||
atomically, so that all recursive snapshots correspond to the same moment in
|
|
||||||
time.
|
|
||||||
.RE
|
.RE
|
||||||
|
|
||||||
.sp
|
.sp
|
||||||
|
Loading…
Reference in New Issue
Block a user