diff options
Diffstat (limited to 'lib')
35 files changed, 1454 insertions, 4307 deletions
diff --git a/lib/libctf/common/ctf_lib.c b/lib/libctf/common/ctf_lib.c index 1c5c3f1d5f7e..6e599540a4f6 100644 --- a/lib/libctf/common/ctf_lib.c +++ b/lib/libctf/common/ctf_lib.c @@ -24,6 +24,8 @@ * Use is subject to license terms. */ +#pragma ident "%Z%%M% %I% %E% SMI" + #include <sys/types.h> #include <sys/stat.h> #include <sys/mman.h> @@ -35,9 +37,9 @@ #include <gelf.h> #ifdef _LP64 -static const char *_libctf_zlib = "/usr/lib/64/libz.so.1"; +static const char *_libctf_zlib = "/usr/lib/64/libz.so"; #else -static const char *_libctf_zlib = "/usr/lib/libz.so.1"; +static const char *_libctf_zlib = "/usr/lib/libz.so"; #endif static struct { diff --git a/lib/libdtrace/common/dt_aggregate.c b/lib/libdtrace/common/dt_aggregate.c index bb766f71c466..2e66250b88d7 100644 --- a/lib/libdtrace/common/dt_aggregate.c +++ b/lib/libdtrace/common/dt_aggregate.c @@ -24,9 +24,7 @@ * Use is subject to license terms. */ -/* - * Copyright (c) 2011, Joyent, Inc. All rights reserved. - */ +#pragma ident "%Z%%M% %I% %E% SMI" #include <stdlib.h> #include <strings.h> @@ -206,83 +204,6 @@ dt_aggregate_lquantizedcmp(int64_t *lhs, int64_t *rhs) return (0); } -static void -dt_aggregate_llquantize(int64_t *existing, int64_t *new, size_t size) -{ - int i; - - for (i = 1; i < size / sizeof (int64_t); i++) - existing[i] = existing[i] + new[i]; -} - -static long double -dt_aggregate_llquantizedsum(int64_t *llquanta) -{ - int64_t arg = *llquanta++; - uint16_t factor = DTRACE_LLQUANTIZE_FACTOR(arg); - uint16_t low = DTRACE_LLQUANTIZE_LOW(arg); - uint16_t high = DTRACE_LLQUANTIZE_HIGH(arg); - uint16_t nsteps = DTRACE_LLQUANTIZE_NSTEP(arg); - int bin = 0, order; - int64_t value = 1, next, step; - long double total; - - assert(nsteps >= factor); - assert(nsteps % factor == 0); - - for (order = 0; order < low; order++) - value *= factor; - - total = (long double)llquanta[bin++] * (long double)(value - 1); - - next = value * factor; - step = next > nsteps ? next / nsteps : 1; - - while (order <= high) { - assert(value < next); - total += (long double)llquanta[bin++] * (long double)(value); - - if ((value += step) != next) - continue; - - next = value * factor; - step = next > nsteps ? next / nsteps : 1; - order++; - } - - return (total + (long double)llquanta[bin] * (long double)value); -} - -static int -dt_aggregate_llquantizedcmp(int64_t *lhs, int64_t *rhs) -{ - long double lsum = dt_aggregate_llquantizedsum(lhs); - long double rsum = dt_aggregate_llquantizedsum(rhs); - int64_t lzero, rzero; - - if (lsum < rsum) - return (DT_LESSTHAN); - - if (lsum > rsum) - return (DT_GREATERTHAN); - - /* - * If they're both equal, then we will compare based on the weights at - * zero. If the weights at zero are equal, then this will be judged a - * tie and will be resolved based on the key comparison. - */ - lzero = lhs[1]; - rzero = rhs[1]; - - if (lzero < rzero) - return (DT_LESSTHAN); - - if (lzero > rzero) - return (DT_GREATERTHAN); - - return (0); -} - static int dt_aggregate_quantizedcmp(int64_t *lhs, int64_t *rhs) { @@ -661,10 +582,6 @@ hashnext: h->dtahe_aggregate = dt_aggregate_lquantize; break; - case DTRACEAGG_LLQUANTIZE: - h->dtahe_aggregate = dt_aggregate_llquantize; - break; - case DTRACEAGG_COUNT: case DTRACEAGG_SUM: case DTRACEAGG_AVG: @@ -932,10 +849,6 @@ dt_aggregate_valcmp(const void *lhs, const void *rhs) rval = dt_aggregate_lquantizedcmp(laddr, raddr); break; - case DTRACEAGG_LLQUANTIZE: - rval = dt_aggregate_llquantizedcmp(laddr, raddr); - break; - case DTRACEAGG_COUNT: case DTRACEAGG_SUM: case DTRACEAGG_MIN: diff --git a/lib/libdtrace/common/dt_cc.c b/lib/libdtrace/common/dt_cc.c index 8b8bcf475cba..24a386bbde95 100644 --- a/lib/libdtrace/common/dt_cc.c +++ b/lib/libdtrace/common/dt_cc.c @@ -21,8 +21,6 @@ /* * Copyright (c) 2003, 2010, Oracle and/or its affiliates. All rights reserved. - * Copyright (c) 2011, Joyent Inc. All rights reserved. - * Copyright (c) 2011 by Delphix. All rights reserved. */ /* @@ -84,7 +82,6 @@ #include <sys/types.h> #include <sys/wait.h> -#include <sys/sysmacros.h> #include <assert.h> #include <strings.h> @@ -679,59 +676,13 @@ dt_action_trace(dtrace_hdl_t *dtp, dt_node_t *dnp, dtrace_stmtdesc_t *sdp) ap->dtad_kind = DTRACEACT_DIFEXPR; } -/* - * The print() action behaves identically to trace(), except that it stores the - * CTF type of the argument (if present) within the DOF for the DIFEXPR action. - * To do this, we set the 'dtsd_strdata' to point to the fully-qualified CTF - * type ID for the result of the DIF action. We use the ID instead of the name - * to handles complex types like arrays and function pointers that can't be - * resolved by ctf_type_lookup(). This is later processed by - * dtrace_dof_create() and turned into a reference into the string table so - * that we can get the type information when we process the data after the - * fact. - */ -static void -dt_action_print(dtrace_hdl_t *dtp, dt_node_t *dnp, dtrace_stmtdesc_t *sdp) -{ - dtrace_actdesc_t *ap = dt_stmt_action(dtp, sdp); - dt_node_t *dret; - size_t len; - dt_module_t *dmp; - - if (dt_node_is_void(dnp->dn_args)) { - dnerror(dnp->dn_args, D_PRINT_VOID, - "print( ) may not be applied to a void expression\n"); - } - - if (dt_node_is_dynamic(dnp->dn_args)) { - dnerror(dnp->dn_args, D_PRINT_DYN, - "print( ) may not be applied to a dynamic expression\n"); - } - - dt_cg(yypcb, dnp->dn_args); - - dret = yypcb->pcb_dret; - dmp = dt_module_lookup_by_ctf(dtp, dret->dn_ctfp); - - len = snprintf(NULL, 0, "%s`%d", dmp->dm_name, dret->dn_type) + 1; - sdp->dtsd_strdata = dt_alloc(dtp, len); - if (sdp->dtsd_strdata == NULL) - longjmp(yypcb->pcb_jmpbuf, EDT_NOMEM); - (void) snprintf(sdp->dtsd_strdata, len, "%s`%d", dmp->dm_name, - dret->dn_type); - - ap->dtad_difo = dt_as(yypcb); - ap->dtad_kind = DTRACEACT_DIFEXPR; -} - static void dt_action_tracemem(dtrace_hdl_t *dtp, dt_node_t *dnp, dtrace_stmtdesc_t *sdp) { dtrace_actdesc_t *ap = dt_stmt_action(dtp, sdp); dt_node_t *addr = dnp->dn_args; - dt_node_t *max = dnp->dn_args->dn_list; - dt_node_t *size; + dt_node_t *size = dnp->dn_args->dn_list; char n[DT_TYPE_NAMELEN]; @@ -743,37 +694,17 @@ dt_action_tracemem(dtrace_hdl_t *dtp, dt_node_t *dnp, dtrace_stmtdesc_t *sdp) dt_node_type_name(addr, n, sizeof (n))); } - if (dt_node_is_posconst(max) == 0) { - dnerror(max, D_TRACEMEM_SIZE, "tracemem( ) argument #2 must " + if (dt_node_is_posconst(size) == 0) { + dnerror(size, D_TRACEMEM_SIZE, "tracemem( ) argument #2 must " "be a non-zero positive integral constant expression\n"); } - if ((size = max->dn_list) != NULL) { - if (size->dn_list != NULL) { - dnerror(size, D_TRACEMEM_ARGS, "tracemem ( ) prototype " - "mismatch: expected at most 3 args\n"); - } - - if (!dt_node_is_scalar(size)) { - dnerror(size, D_TRACEMEM_DYNSIZE, "tracemem ( ) " - "dynamic size (argument #3) must be of " - "scalar type\n"); - } - - dt_cg(yypcb, size); - ap->dtad_difo = dt_as(yypcb); - ap->dtad_difo->dtdo_rtype = dt_int_rtype; - ap->dtad_kind = DTRACEACT_TRACEMEM_DYNSIZE; - - ap = dt_stmt_action(dtp, sdp); - } - dt_cg(yypcb, addr); ap->dtad_difo = dt_as(yypcb); - ap->dtad_kind = DTRACEACT_TRACEMEM; + ap->dtad_kind = DTRACEACT_DIFEXPR; ap->dtad_difo->dtdo_rtype.dtdt_flags |= DIF_TF_BYREF; - ap->dtad_difo->dtdo_rtype.dtdt_size = max->dn_value; + ap->dtad_difo->dtdo_rtype.dtdt_size = size->dn_value; } static void @@ -1103,9 +1034,6 @@ dt_compile_fun(dtrace_hdl_t *dtp, dt_node_t *dnp, dtrace_stmtdesc_t *sdp) case DT_ACT_TRACE: dt_action_trace(dtp, dnp->dn_expr, sdp); break; - case DT_ACT_PRINT: - dt_action_print(dtp, dnp->dn_expr, sdp); - break; case DT_ACT_TRACEMEM: dt_action_tracemem(dtp, dnp->dn_expr, sdp); break; @@ -1363,145 +1291,6 @@ dt_compile_agg(dtrace_hdl_t *dtp, dt_node_t *dnp, dtrace_stmtdesc_t *sdp) argmax = 5; } - if (fid->di_id == DTRACEAGG_LLQUANTIZE) { - /* - * For log/linear quantizations, we have between one and five - * arguments in addition to the expression: - * - * arg1 => Factor - * arg2 => Low magnitude - * arg3 => High magnitude - * arg4 => Number of steps per magnitude - * arg5 => Quantization increment value (defaults to 1) - */ - dt_node_t *llarg = dnp->dn_aggfun->dn_args->dn_list; - uint64_t oarg, order, v; - dt_idsig_t *isp; - int i; - - struct { - char *str; /* string identifier */ - int badtype; /* error on bad type */ - int badval; /* error on bad value */ - int mismatch; /* error on bad match */ - int shift; /* shift value */ - uint16_t value; /* value itself */ - } args[] = { - { "factor", D_LLQUANT_FACTORTYPE, - D_LLQUANT_FACTORVAL, D_LLQUANT_FACTORMATCH, - DTRACE_LLQUANTIZE_FACTORSHIFT }, - { "low magnitude", D_LLQUANT_LOWTYPE, - D_LLQUANT_LOWVAL, D_LLQUANT_LOWMATCH, - DTRACE_LLQUANTIZE_LOWSHIFT }, - { "high magnitude", D_LLQUANT_HIGHTYPE, - D_LLQUANT_HIGHVAL, D_LLQUANT_HIGHMATCH, - DTRACE_LLQUANTIZE_HIGHSHIFT }, - { "linear steps per magnitude", D_LLQUANT_NSTEPTYPE, - D_LLQUANT_NSTEPVAL, D_LLQUANT_NSTEPMATCH, - DTRACE_LLQUANTIZE_NSTEPSHIFT }, - { NULL } - }; - - assert(arg == 0); - - for (i = 0; args[i].str != NULL; i++) { - if (llarg->dn_kind != DT_NODE_INT) { - dnerror(llarg, args[i].badtype, "llquantize( ) " - "argument #%d (%s) must be an " - "integer constant\n", i + 1, args[i].str); - } - - if ((uint64_t)llarg->dn_value > UINT16_MAX) { - dnerror(llarg, args[i].badval, "llquantize( ) " - "argument #%d (%s) must be an unsigned " - "16-bit quantity\n", i + 1, args[i].str); - } - - args[i].value = (uint16_t)llarg->dn_value; - - assert(!(arg & (UINT16_MAX << args[i].shift))); - arg |= ((uint64_t)args[i].value << args[i].shift); - llarg = llarg->dn_list; - } - - assert(arg != 0); - - if (args[0].value < 2) { - dnerror(dnp, D_LLQUANT_FACTORSMALL, "llquantize( ) " - "factor (argument #1) must be two or more\n"); - } - - if (args[1].value >= args[2].value) { - dnerror(dnp, D_LLQUANT_MAGRANGE, "llquantize( ) " - "high magnitude (argument #3) must be greater " - "than low magnitude (argument #2)\n"); - } - - if (args[3].value < args[0].value) { - dnerror(dnp, D_LLQUANT_FACTORNSTEPS, "llquantize( ) " - "factor (argument #1) must be less than or " - "equal to the number of linear steps per " - "magnitude (argument #4)\n"); - } - - for (v = args[0].value; v < args[3].value; v *= args[0].value) - continue; - - if ((args[3].value % args[0].value) || (v % args[3].value)) { - dnerror(dnp, D_LLQUANT_FACTOREVEN, "llquantize( ) " - "factor (argument #1) must evenly divide the " - "number of steps per magnitude (argument #4), " - "and the number of steps per magnitude must evenly " - "divide a power of the factor\n"); - } - - for (i = 0, order = 1; i < args[2].value; i++) { - if (order * args[0].value > order) { - order *= args[0].value; - continue; - } - - dnerror(dnp, D_LLQUANT_MAGTOOBIG, "llquantize( ) " - "factor (%d) raised to power of high magnitude " - "(%d) overflows 64-bits\n", args[0].value, - args[2].value); - } - - isp = (dt_idsig_t *)aid->di_data; - - if (isp->dis_auxinfo == 0) { - /* - * This is the first time we've seen an llquantize() - * for this aggregation; we'll store our argument - * as the auxiliary signature information. - */ - isp->dis_auxinfo = arg; - } else if ((oarg = isp->dis_auxinfo) != arg) { - /* - * If we have seen this llquantize() before and the - * argument doesn't match the original argument, pick - * the original argument apart to concisely report the - * mismatch. - */ - int expected = 0, found = 0; - - for (i = 0; expected == found; i++) { - assert(args[i].str != NULL); - - expected = (oarg >> args[i].shift) & UINT16_MAX; - found = (arg >> args[i].shift) & UINT16_MAX; - } - - dnerror(dnp, args[i - 1].mismatch, "llquantize( ) " - "%s (argument #%d) doesn't match previous " - "declaration: expected %d, found %d\n", - args[i - 1].str, i, expected, found); - } - - incr = llarg; - argmax = 6; - } - if (fid->di_id == DTRACEAGG_QUANTIZE) { incr = dnp->dn_aggfun->dn_args->dn_list; argmax = 2; @@ -2124,23 +1913,25 @@ dt_lib_depend_free(dtrace_hdl_t *dtp) } } + /* - * Open all the .d library files found in the specified directory and - * compile each one of them. We silently ignore any missing directories and - * other files found therein. We only fail (and thereby fail dt_load_libs()) if - * we fail to compile a library and the error is something other than #pragma D - * depends_on. Dependency errors are silently ignored to permit a library - * directory to contain libraries which may not be accessible depending on our - * privileges. + * Open all of the .d library files found in the specified directory and + * compile each one in topological order to cache its inlines and translators, + * etc. We silently ignore any missing directories and other files found + * therein. We only fail (and thereby fail dt_load_libs()) if we fail to + * compile a library and the error is something other than #pragma D depends_on. + * Dependency errors are silently ignored to permit a library directory to + * contain libraries which may not be accessible depending on our privileges. */ static int dt_load_libs_dir(dtrace_hdl_t *dtp, const char *path) { struct dirent *dp; - const char *p, *end; + const char *p; DIR *dirp; char fname[PATH_MAX]; + dtrace_prog_t *pgp; FILE *fp; void *rv; dt_lib_depend_t *dld; @@ -2164,28 +1955,9 @@ dt_load_libs_dir(dtrace_hdl_t *dtp, const char *path) continue; } - /* - * Skip files whose name match an already processed library - */ - for (dld = dt_list_next(&dtp->dt_lib_dep); dld != NULL; - dld = dt_list_next(dld)) { - end = strrchr(dld->dtld_library, '/'); - /* dt_lib_depend_add ensures this */ - assert(end != NULL); - if (strcmp(end + 1, dp->d_name) == 0) - break; - } - - if (dld != NULL) { - dt_dprintf("skipping library %s, already processed " - "library with the same name: %s", dp->d_name, - dld->dtld_library); - continue; - } - dtp->dt_filetag = fname; if (dt_lib_depend_add(dtp, &dtp->dt_lib_dep, fname) != 0) - return (-1); /* preserve dt_errno */ + goto err; rv = dt_compile(dtp, DT_CTX_DPROG, DTRACE_PROBESPEC_NAME, NULL, @@ -2194,7 +1966,7 @@ dt_load_libs_dir(dtrace_hdl_t *dtp, const char *path) if (rv != NULL && dtp->dt_errno && (dtp->dt_errno != EDT_COMPILER || dtp->dt_errtag != dt_errtag(D_PRAGMA_DEPEND))) - return (-1); /* preserve dt_errno */ + goto err; if (dtp->dt_errno) dt_dprintf("error parsing library %s: %s\n", @@ -2205,27 +1977,6 @@ dt_load_libs_dir(dtrace_hdl_t *dtp, const char *path) } (void) closedir(dirp); - - return (0); -} - -/* - * Perform a topological sorting of all the libraries found across the entire - * dt_lib_path. Once sorted, compile each one in topological order to cache its - * inlines and translators, etc. We silently ignore any missing directories and - * other files found therein. We only fail (and thereby fail dt_load_libs()) if - * we fail to compile a library and the error is something other than #pragma D - * depends_on. Dependency errors are silently ignored to permit a library - * directory to contain libraries which may not be accessible depending on our - * privileges. - */ -static int -dt_load_libs_sort(dtrace_hdl_t *dtp) -{ - dtrace_prog_t *pgp; - FILE *fp; - dt_lib_depend_t *dld; - /* * Finish building the graph containing the library dependencies * and perform a topological sort to generate an ordered list @@ -2286,14 +2037,7 @@ dt_load_libs(dtrace_hdl_t *dtp) dtp->dt_cflags |= DTRACE_C_NOLIBS; - /* - * /usr/lib/dtrace is always at the head of the list. The rest of the - * list is specified in the precedence order the user requested. Process - * everything other than the head first. DTRACE_C_NOLIBS has already - * been spcified so dt_vopen will ensure that there is always one entry - * in dt_lib_path. - */ - for (dirp = dt_list_next(dt_list_next(&dtp->dt_lib_path)); + for (dirp = dt_list_next(&dtp->dt_lib_path); dirp != NULL; dirp = dt_list_next(dirp)) { if (dt_load_libs_dir(dtp, dirp->dir_path) != 0) { dtp->dt_cflags &= ~DTRACE_C_NOLIBS; @@ -2301,16 +2045,6 @@ dt_load_libs(dtrace_hdl_t *dtp) } } - /* Handle /usr/lib/dtrace */ - dirp = dt_list_next(&dtp->dt_lib_path); - if (dt_load_libs_dir(dtp, dirp->dir_path) != 0) { - dtp->dt_cflags &= ~DTRACE_C_NOLIBS; - return (-1); /* errno is set for us */ - } - - if (dt_load_libs_sort(dtp) < 0) - return (-1); /* errno is set for us */ - return (0); } diff --git a/lib/libdtrace/common/dt_consume.c b/lib/libdtrace/common/dt_consume.c index d3a554c1c6b7..564189a000ad 100644 --- a/lib/libdtrace/common/dt_consume.c +++ b/lib/libdtrace/common/dt_consume.c @@ -23,11 +23,6 @@ * Use is subject to license terms. */ -/* - * Copyright (c) 2011, Joyent, Inc. All rights reserved. - * Copyright (c) 2011 by Delphix. All rights reserved. - */ - #include <stdlib.h> #include <strings.h> #include <errno.h> @@ -686,121 +681,6 @@ dt_print_lquantize(dtrace_hdl_t *dtp, FILE *fp, const void *addr, return (0); } -int -dt_print_llquantize(dtrace_hdl_t *dtp, FILE *fp, const void *addr, - size_t size, uint64_t normal) -{ - int i, first_bin, last_bin, bin = 1, order, levels; - uint16_t factor, low, high, nsteps; - const int64_t *data = addr; - int64_t value = 1, next, step; - char positives = 0, negatives = 0; - long double total = 0; - uint64_t arg; - char c[32]; - - if (size < sizeof (uint64_t)) - return (dt_set_errno(dtp, EDT_DMISMATCH)); - - arg = *data++; - size -= sizeof (uint64_t); - - factor = DTRACE_LLQUANTIZE_FACTOR(arg); - low = DTRACE_LLQUANTIZE_LOW(arg); - high = DTRACE_LLQUANTIZE_HIGH(arg); - nsteps = DTRACE_LLQUANTIZE_NSTEP(arg); - - /* - * We don't expect to be handed invalid llquantize() parameters here, - * but sanity check them (to a degree) nonetheless. - */ - if (size > INT32_MAX || factor < 2 || low >= high || - nsteps == 0 || factor > nsteps) - return (dt_set_errno(dtp, EDT_DMISMATCH)); - - levels = (int)size / sizeof (uint64_t); - - first_bin = 0; - last_bin = levels - 1; - - while (first_bin < levels && data[first_bin] == 0) - first_bin++; - - if (first_bin == levels) { - first_bin = 0; - last_bin = 1; - } else { - if (first_bin > 0) - first_bin--; - - while (last_bin > 0 && data[last_bin] == 0) - last_bin--; - - if (last_bin < levels - 1) - last_bin++; - } - - for (i = first_bin; i <= last_bin; i++) { - positives |= (data[i] > 0); - negatives |= (data[i] < 0); - total += dt_fabsl((long double)data[i]); - } - - if (dt_printf(dtp, fp, "\n%16s %41s %-9s\n", "value", - "------------- Distribution -------------", "count") < 0) - return (-1); - - for (order = 0; order < low; order++) - value *= factor; - - next = value * factor; - step = next > nsteps ? next / nsteps : 1; - - if (first_bin == 0) { - (void) snprintf(c, sizeof (c), "< %lld", value); - - if (dt_printf(dtp, fp, "%16s ", c) < 0) - return (-1); - - if (dt_print_quantline(dtp, fp, data[0], normal, - total, positives, negatives) < 0) - return (-1); - } - - while (order <= high) { - if (bin >= first_bin && bin <= last_bin) { - if (dt_printf(dtp, fp, "%16lld ", (long long)value) < 0) - return (-1); - - if (dt_print_quantline(dtp, fp, data[bin], - normal, total, positives, negatives) < 0) - return (-1); - } - - assert(value < next); - bin++; - - if ((value += step) != next) - continue; - - next = value * factor; - step = next > nsteps ? next / nsteps : 1; - order++; - } - - if (last_bin < bin) - return (0); - - assert(last_bin == bin); - (void) snprintf(c, sizeof (c), ">= %lld", value); - - if (dt_printf(dtp, fp, "%16s ", c) < 0) - return (-1); - - return (dt_print_quantline(dtp, fp, data[bin], normal, - total, positives, negatives)); -} - /*ARGSUSED*/ static int dt_print_average(dtrace_hdl_t *dtp, FILE *fp, caddr_t addr, @@ -828,7 +708,7 @@ dt_print_stddev(dtrace_hdl_t *dtp, FILE *fp, caddr_t addr, /*ARGSUSED*/ int dt_print_bytes(dtrace_hdl_t *dtp, FILE *fp, caddr_t addr, - size_t nbytes, int width, int quiet, int forceraw) + size_t nbytes, int width, int quiet) { /* * If the byte stream is a series of printable characters, followed by @@ -841,9 +721,6 @@ dt_print_bytes(dtrace_hdl_t *dtp, FILE *fp, caddr_t addr, if (nbytes == 0) return (0); - if (forceraw) - goto raw; - if (dtp->dt_options[DTRACEOPT_RAWBYTES] != DTRACEOPT_UNSET) goto raw; @@ -1520,9 +1397,6 @@ dt_print_datum(dtrace_hdl_t *dtp, FILE *fp, dtrace_recdesc_t *rec, case DTRACEAGG_LQUANTIZE: return (dt_print_lquantize(dtp, fp, addr, size, normal)); - case DTRACEAGG_LLQUANTIZE: - return (dt_print_llquantize(dtp, fp, addr, size, normal)); - case DTRACEAGG_AVG: return (dt_print_average(dtp, fp, addr, size, normal)); @@ -1554,7 +1428,7 @@ dt_print_datum(dtrace_hdl_t *dtp, FILE *fp, dtrace_recdesc_t *rec, (uint32_t)normal); break; default: - err = dt_print_bytes(dtp, fp, addr, size, 50, 0, 0); + err = dt_print_bytes(dtp, fp, addr, size, 50, 0); break; } @@ -1709,7 +1583,6 @@ dt_consume_cpu(dtrace_hdl_t *dtp, FILE *fp, int cpu, dtrace_bufdesc_t *buf, int quiet = (dtp->dt_options[DTRACEOPT_QUIET] != DTRACEOPT_UNSET); int rval, i, n; dtrace_epid_t last = DTRACE_EPIDNONE; - uint64_t tracememsize = 0; dtrace_probedata_t data; uint64_t drops; caddr_t addr; @@ -1878,13 +1751,6 @@ again: } } - if (act == DTRACEACT_TRACEMEM_DYNSIZE && - rec->dtrd_size == sizeof (uint64_t)) { - /* LINTED - alignment */ - tracememsize = *((unsigned long long *)addr); - continue; - } - rval = (*rfunc)(&data, rec, arg); if (rval == DTRACE_CONSUME_NEXT) @@ -1976,35 +1842,6 @@ again: goto nextrec; } - /* - * If this is a DIF expression, and the record has a - * format set, this indicates we have a CTF type name - * associated with the data and we should try to print - * it out by type. - */ - if (act == DTRACEACT_DIFEXPR) { - const char *strdata = dt_strdata_lookup(dtp, - rec->dtrd_format); - if (strdata != NULL) { - n = dtrace_print(dtp, fp, strdata, - addr, rec->dtrd_size); - - /* - * dtrace_print() will return -1 on - * error, or return the number of bytes - * consumed. It will return 0 if the - * type couldn't be determined, and we - * should fall through to the normal - * trace method. - */ - if (n < 0) - return (-1); - - if (n > 0) - goto nextrec; - } - } - nofmt: if (act == DTRACEACT_PRINTA) { dt_print_aggdata_t pd; @@ -2073,23 +1910,6 @@ nofmt: goto nextrec; } - if (act == DTRACEACT_TRACEMEM) { - if (tracememsize == 0 || - tracememsize > rec->dtrd_size) { - tracememsize = rec->dtrd_size; - } - - n = dt_print_bytes(dtp, fp, addr, - tracememsize, 33, quiet, 1); - - tracememsize = 0; - - if (n < 0) - return (-1); - - goto nextrec; - } - switch (rec->dtrd_size) { case sizeof (uint64_t): n = dt_printf(dtp, fp, @@ -2113,7 +1933,7 @@ nofmt: break; default: n = dt_print_bytes(dtp, fp, addr, - rec->dtrd_size, 33, quiet, 0); + rec->dtrd_size, 33, quiet); break; } diff --git a/lib/libdtrace/common/dt_dof.c b/lib/libdtrace/common/dt_dof.c index 04c4c89cdbdb..a7eb8e4d239f 100644 --- a/lib/libdtrace/common/dt_dof.c +++ b/lib/libdtrace/common/dt_dof.c @@ -21,7 +21,6 @@ /* * Copyright (c) 2003, 2010, Oracle and/or its affiliates. All rights reserved. - * Copyright (c) 2011 by Delphix. All rights reserved. */ #include <sys/types.h> @@ -755,23 +754,16 @@ dtrace_dof_create(dtrace_hdl_t *dtp, dtrace_prog_t *pgp, uint_t flags) dofa[i].dofa_difo = DOF_SECIDX_NONE; /* - * If the first action in a statement has string data, - * add the string to the global string table. This can - * be due either to a printf() format string - * (dtsd_fmtdata) or a print() type string - * (dtsd_strdata). + * If the first action in a statement has format data, + * add the format string to the global string table. */ if (sdp != NULL && ap == sdp->dtsd_action) { if (sdp->dtsd_fmtdata != NULL) { (void) dtrace_printf_format(dtp, sdp->dtsd_fmtdata, fmt, maxfmt + 1); strndx = dof_add_string(ddo, fmt); - } else if (sdp->dtsd_strdata != NULL) { - strndx = dof_add_string(ddo, - sdp->dtsd_strdata); - } else { + } else strndx = 0; /* use dtad_arg instead */ - } if ((next = dt_list_next(next)) != NULL) sdp = next->ds_desc; diff --git a/lib/libdtrace/common/dt_errtags.h b/lib/libdtrace/common/dt_errtags.h index 473e2addc789..9e32dfdf2492 100644 --- a/lib/libdtrace/common/dt_errtags.h +++ b/lib/libdtrace/common/dt_errtags.h @@ -24,14 +24,11 @@ * Use is subject to license terms. */ -/* - * Copyright (c) 2011, Joyent, Inc. All rights reserved. - * Copyright (c) 2011 by Delphix. All rights reserved. - */ - #ifndef _DT_ERRTAGS_H #define _DT_ERRTAGS_H +#pragma ident "%Z%%M% %I% %E% SMI" + #ifdef __cplusplus extern "C" { #endif @@ -190,12 +187,8 @@ typedef enum { D_PRINTA_AGGPROTO, /* printa() aggregation mismatch */ D_TRACE_VOID, /* trace() argument has void type */ D_TRACE_DYN, /* trace() argument has dynamic type */ - D_PRINT_VOID, /* print() argument has void type */ - D_PRINT_DYN, /* print() argument has dynamic type */ D_TRACEMEM_ADDR, /* tracemem() address bad type */ D_TRACEMEM_SIZE, /* tracemem() size bad type */ - D_TRACEMEM_ARGS, /* tracemem() illegal number of args */ - D_TRACEMEM_DYNSIZE, /* tracemem() dynamic size bad type */ D_STACK_PROTO, /* stack() prototype mismatch */ D_STACK_SIZE, /* stack() size argument bad type */ D_USTACK_FRAMES, /* ustack() frames arg bad type */ @@ -242,24 +235,7 @@ typedef enum { D_FREOPEN_INVALID, /* frename() filename is invalid */ D_LQUANT_MATCHBASE, /* lquantize() mismatch on base */ D_LQUANT_MATCHLIM, /* lquantize() mismatch on limit */ - D_LQUANT_MATCHSTEP, /* lquantize() mismatch on step */ - D_LLQUANT_FACTORTYPE, /* llquantize() bad magnitude type */ - D_LLQUANT_FACTORVAL, /* llquantize() bad magnitude value */ - D_LLQUANT_FACTORMATCH, /* llquantize() mismatch on magnitude */ - D_LLQUANT_LOWTYPE, /* llquantize() bad low mag type */ - D_LLQUANT_LOWVAL, /* llquantize() bad low mag value */ - D_LLQUANT_LOWMATCH, /* llquantize() mismatch on low mag */ - D_LLQUANT_HIGHTYPE, /* llquantize() bad high mag type */ - D_LLQUANT_HIGHVAL, /* llquantize() bad high mag value */ - D_LLQUANT_HIGHMATCH, /* llquantize() mismatch on high mag */ - D_LLQUANT_NSTEPTYPE, /* llquantize() bad # steps type */ - D_LLQUANT_NSTEPVAL, /* llquantize() bad # steps value */ - D_LLQUANT_NSTEPMATCH, /* llquantize() mismatch on # steps */ - D_LLQUANT_MAGRANGE, /* llquantize() bad magnitude range */ - D_LLQUANT_FACTORNSTEPS, /* llquantize() # steps < factor */ - D_LLQUANT_FACTOREVEN, /* llquantize() bad # steps/factor */ - D_LLQUANT_FACTORSMALL, /* llquantize() magnitude too small */ - D_LLQUANT_MAGTOOBIG /* llquantize() high mag too large */ + D_LQUANT_MATCHSTEP /* lquantize() mismatch on step */ } dt_errtag_t; extern const char *dt_errtag(dt_errtag_t); diff --git a/lib/libdtrace/common/dt_impl.h b/lib/libdtrace/common/dt_impl.h index b06fd6477d7a..1937ce06474d 100644 --- a/lib/libdtrace/common/dt_impl.h +++ b/lib/libdtrace/common/dt_impl.h @@ -24,11 +24,6 @@ * Use is subject to license terms. */ -/* - * Copyright (c) 2011, Joyent, Inc. All rights reserved. - * Copyright (c) 2011 by Delphix. All rights reserved. - */ - #ifndef _DT_IMPL_H #define _DT_IMPL_H @@ -241,8 +236,6 @@ struct dtrace_hdl { dtrace_aggdesc_t **dt_aggdesc; /* aggregation descriptions */ int dt_maxformat; /* max format ID */ void **dt_formats; /* pointer to format array */ - int dt_maxstrdata; /* max strdata ID */ - char **dt_strdata; /* pointer to strdata array */ dt_aggregate_t dt_aggregate; /* aggregate */ dtrace_bufdesc_t dt_buf; /* staging buffer */ struct dt_pfdict *dt_pfdict; /* dictionary of printf conversions */ @@ -420,7 +413,6 @@ struct dtrace_hdl { #define DT_ACT_UMOD DT_ACT(26) /* umod() action */ #define DT_ACT_UADDR DT_ACT(27) /* uaddr() action */ #define DT_ACT_SETOPT DT_ACT(28) /* setopt() action */ -#define DT_ACT_PRINT DT_ACT(29) /* print() action */ /* * Sentinel to tell freopen() to restore the saved stdout. This must not @@ -604,15 +596,10 @@ extern void dt_aggid_destroy(dtrace_hdl_t *); extern void *dt_format_lookup(dtrace_hdl_t *, int); extern void dt_format_destroy(dtrace_hdl_t *); -extern const char *dt_strdata_lookup(dtrace_hdl_t *, int); -extern void dt_strdata_destroy(dtrace_hdl_t *); - extern int dt_print_quantize(dtrace_hdl_t *, FILE *, const void *, size_t, uint64_t); extern int dt_print_lquantize(dtrace_hdl_t *, FILE *, const void *, size_t, uint64_t); -extern int dt_print_llquantize(dtrace_hdl_t *, FILE *, - const void *, size_t, uint64_t); extern int dt_print_agg(const dtrace_aggdata_t *, void *); extern int dt_handle(dtrace_hdl_t *, dtrace_probedata_t *); diff --git a/lib/libdtrace/common/dt_map.c b/lib/libdtrace/common/dt_map.c index 8a3ce817e4d7..15361862de8f 100644 --- a/lib/libdtrace/common/dt_map.c +++ b/lib/libdtrace/common/dt_map.c @@ -23,9 +23,7 @@ * Use is subject to license terms. */ -/* - * Copyright (c) 2011 by Delphix. All rights reserved. - */ +#pragma ident "%Z%%M% %I% %E% SMI" #include <stdlib.h> #include <strings.h> @@ -37,81 +35,10 @@ #include <dt_printf.h> static int -dt_strdata_add(dtrace_hdl_t *dtp, dtrace_recdesc_t *rec, void ***data, int *max) -{ - int maxformat; - dtrace_fmtdesc_t fmt; - void *result; - - if (rec->dtrd_format == 0) - return (0); - - if (rec->dtrd_format <= *max && - (*data)[rec->dtrd_format - 1] != NULL) { - return (0); - } - - bzero(&fmt, sizeof (fmt)); - fmt.dtfd_format = rec->dtrd_format; - fmt.dtfd_string = NULL; - fmt.dtfd_length = 0; - - if (dt_ioctl(dtp, DTRACEIOC_FORMAT, &fmt) == -1) - return (dt_set_errno(dtp, errno)); - - if ((fmt.dtfd_string = dt_alloc(dtp, fmt.dtfd_length)) == NULL) - return (dt_set_errno(dtp, EDT_NOMEM)); - - if (dt_ioctl(dtp, DTRACEIOC_FORMAT, &fmt) == -1) { - free(fmt.dtfd_string); - return (dt_set_errno(dtp, errno)); - } - - while (rec->dtrd_format > (maxformat = *max)) { - int new_max = maxformat ? (maxformat << 1) : 1; - size_t nsize = new_max * sizeof (void *); - size_t osize = maxformat * sizeof (void *); - void **new_data = dt_zalloc(dtp, nsize); - - if (new_data == NULL) { - dt_free(dtp, fmt.dtfd_string); - return (dt_set_errno(dtp, EDT_NOMEM)); - } - - bcopy(*data, new_data, osize); - free(*data); - - *data = new_data; - *max = new_max; - } - - switch (rec->dtrd_action) { - case DTRACEACT_DIFEXPR: - result = fmt.dtfd_string; - break; - case DTRACEACT_PRINTA: - result = dtrace_printa_create(dtp, fmt.dtfd_string); - dt_free(dtp, fmt.dtfd_string); - break; - default: - result = dtrace_printf_create(dtp, fmt.dtfd_string); - dt_free(dtp, fmt.dtfd_string); - break; - } - - if (result == NULL) - return (-1); - - (*data)[rec->dtrd_format - 1] = result; - - return (0); -} - -static int dt_epid_add(dtrace_hdl_t *dtp, dtrace_epid_t id) { dtrace_id_t max; - int rval, i; + int rval, i, maxformat; dtrace_eprobedesc_t *enabled, *nenabled; dtrace_probedesc_t *probe; @@ -197,23 +124,71 @@ dt_epid_add(dtrace_hdl_t *dtp, dtrace_epid_t id) } for (i = 0; i < enabled->dtepd_nrecs; i++) { + dtrace_fmtdesc_t fmt; dtrace_recdesc_t *rec = &enabled->dtepd_rec[i]; - if (DTRACEACT_ISPRINTFLIKE(rec->dtrd_action)) { - if (dt_strdata_add(dtp, rec, &dtp->dt_formats, - &dtp->dt_maxformat) != 0) { - rval = -1; - goto err; - } - } else if (rec->dtrd_action == DTRACEACT_DIFEXPR) { - if (dt_strdata_add(dtp, rec, - (void ***)&dtp->dt_strdata, - &dtp->dt_maxstrdata) != 0) { - rval = -1; + if (!DTRACEACT_ISPRINTFLIKE(rec->dtrd_action)) + continue; + + if (rec->dtrd_format == 0) + continue; + + if (rec->dtrd_format <= dtp->dt_maxformat && + dtp->dt_formats[rec->dtrd_format - 1] != NULL) + continue; + + bzero(&fmt, sizeof (fmt)); + fmt.dtfd_format = rec->dtrd_format; + fmt.dtfd_string = NULL; + fmt.dtfd_length = 0; + + if (dt_ioctl(dtp, DTRACEIOC_FORMAT, &fmt) == -1) { + rval = dt_set_errno(dtp, errno); + goto err; + } + + if ((fmt.dtfd_string = malloc(fmt.dtfd_length)) == NULL) { + rval = dt_set_errno(dtp, EDT_NOMEM); + goto err; + } + + if (dt_ioctl(dtp, DTRACEIOC_FORMAT, &fmt) == -1) { + rval = dt_set_errno(dtp, errno); + free(fmt.dtfd_string); + goto err; + } + + while (rec->dtrd_format > (maxformat = dtp->dt_maxformat)) { + int new_max = maxformat ? (maxformat << 1) : 1; + size_t nsize = new_max * sizeof (void *); + size_t osize = maxformat * sizeof (void *); + void **new_formats = malloc(nsize); + + if (new_formats == NULL) { + rval = dt_set_errno(dtp, EDT_NOMEM); + free(fmt.dtfd_string); goto err; } + + bzero(new_formats, nsize); + bcopy(dtp->dt_formats, new_formats, osize); + free(dtp->dt_formats); + + dtp->dt_formats = new_formats; + dtp->dt_maxformat = new_max; } + dtp->dt_formats[rec->dtrd_format - 1] = + rec->dtrd_action == DTRACEACT_PRINTA ? + dtrace_printa_create(dtp, fmt.dtfd_string) : + dtrace_printf_create(dtp, fmt.dtfd_string); + + free(fmt.dtfd_string); + + if (dtp->dt_formats[rec->dtrd_format - 1] == NULL) { + rval = -1; /* dt_errno is set for us */ + goto err; + } } dtp->dt_pdesc[id] = probe; @@ -449,28 +424,3 @@ dt_aggid_destroy(dtrace_hdl_t *dtp) dtp->dt_aggdesc = NULL; dtp->dt_maxagg = 0; } - -const char * -dt_strdata_lookup(dtrace_hdl_t *dtp, int idx) -{ - if (idx == 0 || idx > dtp->dt_maxstrdata) - return (NULL); - - if (dtp->dt_strdata == NULL) - return (NULL); - - return (dtp->dt_strdata[idx - 1]); -} - -void -dt_strdata_destroy(dtrace_hdl_t *dtp) -{ - int i; - - for (i = 0; i < dtp->dt_maxstrdata; i++) { - free(dtp->dt_strdata[i]); - } - - free(dtp->dt_strdata); - dtp->dt_strdata = NULL; -} diff --git a/lib/libdtrace/common/dt_open.c b/lib/libdtrace/common/dt_open.c index 502a9d42ad73..2b9cd7c414da 100644 --- a/lib/libdtrace/common/dt_open.c +++ b/lib/libdtrace/common/dt_open.c @@ -21,8 +21,6 @@ /* * Copyright (c) 2003, 2010, Oracle and/or its affiliates. All rights reserved. - * Copyright (c) 2011, Joyent, Inc. All rights reserved. - * Copyright (c) 2011 by Delphix. All rights reserved. */ #include <sys/types.h> @@ -105,13 +103,8 @@ #define DT_VERS_1_6_1 DT_VERSION_NUMBER(1, 6, 1) #define DT_VERS_1_6_2 DT_VERSION_NUMBER(1, 6, 2) #define DT_VERS_1_6_3 DT_VERSION_NUMBER(1, 6, 3) -#define DT_VERS_1_7 DT_VERSION_NUMBER(1, 7, 0) -#define DT_VERS_1_7_1 DT_VERSION_NUMBER(1, 7, 1) -#define DT_VERS_1_8 DT_VERSION_NUMBER(1, 8, 0) -#define DT_VERS_1_8_1 DT_VERSION_NUMBER(1, 8, 1) -#define DT_VERS_1_9 DT_VERSION_NUMBER(1, 9, 0) -#define DT_VERS_LATEST DT_VERS_1_9 -#define DT_VERS_STRING "Sun D 1.9" +#define DT_VERS_LATEST DT_VERS_1_6_3 +#define DT_VERS_STRING "Sun D 1.6.3" const dt_version_t _dtrace_versions[] = { DT_VERS_1_0, /* D API 1.0.0 (PSARC 2001/466) Solaris 10 FCS */ @@ -127,11 +120,6 @@ const dt_version_t _dtrace_versions[] = { DT_VERS_1_6_1, /* D API 1.6.1 */ DT_VERS_1_6_2, /* D API 1.6.2 */ DT_VERS_1_6_3, /* D API 1.6.3 */ - DT_VERS_1_7, /* D API 1.7 */ - DT_VERS_1_7_1, /* D API 1.7.1 */ - DT_VERS_1_8, /* D API 1.8 */ - DT_VERS_1_8_1, /* D API 1.8.1 */ - DT_VERS_1_9, /* D API 1.9 */ 0 }; @@ -262,10 +250,7 @@ static const dt_ident_t _dtrace_globals[] = { { "jstack", DT_IDENT_ACTFUNC, 0, DT_ACT_JSTACK, DT_ATTR_STABCMN, DT_VERS_1_0, &dt_idops_func, "stack(...)" }, { "lltostr", DT_IDENT_FUNC, 0, DIF_SUBR_LLTOSTR, DT_ATTR_STABCMN, DT_VERS_1_0, - &dt_idops_func, "string(int64_t, [int])" }, -{ "llquantize", DT_IDENT_AGGFUNC, 0, DTRACEAGG_LLQUANTIZE, DT_ATTR_STABCMN, - DT_VERS_1_7, &dt_idops_func, - "void(@, int32_t, int32_t, int32_t, int32_t, ...)" }, + &dt_idops_func, "string(int64_t)" }, { "lquantize", DT_IDENT_AGGFUNC, 0, DTRACEAGG_LQUANTIZE, DT_ATTR_STABCMN, DT_VERS_1_0, &dt_idops_func, "void(@, int32_t, int32_t, ...)" }, @@ -307,8 +292,6 @@ static const dt_ident_t _dtrace_globals[] = { &dt_idops_type, "pid_t" }, { "ppid", DT_IDENT_SCALAR, 0, DIF_VAR_PPID, DT_ATTR_STABCMN, DT_VERS_1_0, &dt_idops_type, "pid_t" }, -{ "print", DT_IDENT_ACTFUNC, 0, DT_ACT_PRINT, DT_ATTR_STABCMN, DT_VERS_1_9, - &dt_idops_func, "void(@)" }, { "printa", DT_IDENT_ACTFUNC, 0, DT_ACT_PRINTA, DT_ATTR_STABCMN, DT_VERS_1_0, &dt_idops_func, "void(@, ...)" }, { "printf", DT_IDENT_ACTFUNC, 0, DT_ACT_PRINTF, DT_ATTR_STABCMN, DT_VERS_1_0, @@ -388,15 +371,11 @@ static const dt_ident_t _dtrace_globals[] = { { "timestamp", DT_IDENT_SCALAR, 0, DIF_VAR_TIMESTAMP, DT_ATTR_STABCMN, DT_VERS_1_0, &dt_idops_type, "uint64_t" }, -{ "tolower", DT_IDENT_FUNC, 0, DIF_SUBR_TOLOWER, DT_ATTR_STABCMN, DT_VERS_1_8, - &dt_idops_func, "string(const char *)" }, -{ "toupper", DT_IDENT_FUNC, 0, DIF_SUBR_TOUPPER, DT_ATTR_STABCMN, DT_VERS_1_8, - &dt_idops_func, "string(const char *)" }, { "trace", DT_IDENT_ACTFUNC, 0, DT_ACT_TRACE, DT_ATTR_STABCMN, DT_VERS_1_0, &dt_idops_func, "void(@)" }, { "tracemem", DT_IDENT_ACTFUNC, 0, DT_ACT_TRACEMEM, DT_ATTR_STABCMN, DT_VERS_1_0, - &dt_idops_func, "void(@, size_t, ...)" }, + &dt_idops_func, "void(@, size_t)" }, { "trunc", DT_IDENT_ACTFUNC, 0, DT_ACT_TRUNC, DT_ATTR_STABCMN, DT_VERS_1_0, &dt_idops_func, "void(...)" }, { "uaddr", DT_IDENT_ACTFUNC, 0, DT_ACT_UADDR, DT_ATTR_STABCMN, @@ -418,8 +397,6 @@ static const dt_ident_t _dtrace_globals[] = { &dt_idops_type, "uint32_t" }, { "usym", DT_IDENT_ACTFUNC, 0, DT_ACT_USYM, DT_ATTR_STABCMN, DT_VERS_1_2, &dt_idops_func, "_usymaddr(uintptr_t)" }, -{ "vmregs", DT_IDENT_ARRAY, 0, DIF_VAR_VMREGS, DT_ATTR_STABCMN, DT_VERS_1_7, - &dt_idops_regs, NULL }, { "vtimestamp", DT_IDENT_SCALAR, 0, DIF_VAR_VTIMESTAMP, DT_ATTR_STABCMN, DT_VERS_1_0, &dt_idops_type, "uint64_t" }, @@ -1362,7 +1339,6 @@ dtrace_close(dtrace_hdl_t *dtp) dt_epid_destroy(dtp); dt_aggid_destroy(dtp); dt_format_destroy(dtp); - dt_strdata_destroy(dtp); dt_buffered_destroy(dtp); dt_aggregate_destroy(dtp); free(dtp->dt_buf.dtbd_data); diff --git a/lib/libdtrace/common/dt_options.c b/lib/libdtrace/common/dt_options.c index 426f8cb73c7a..5353bfae528d 100644 --- a/lib/libdtrace/common/dt_options.c +++ b/lib/libdtrace/common/dt_options.c @@ -24,6 +24,8 @@ * Use is subject to license terms. */ +#pragma ident "%Z%%M% %I% %E% SMI" + #include <sys/resource.h> #include <sys/mman.h> #include <sys/types.h> @@ -835,6 +837,30 @@ dt_options_load(dtrace_hdl_t *dtp) return (0); } +/*ARGSUSED*/ +static int +dt_opt_preallocate(dtrace_hdl_t *dtp, const char *arg, uintptr_t option) +{ + dtrace_optval_t size; + void *p; + + if (arg == NULL || dt_optval_parse(arg, &size) != 0) + return (dt_set_errno(dtp, EDT_BADOPTVAL)); + + if (size > SIZE_MAX) + size = SIZE_MAX; + + if ((p = dt_zalloc(dtp, size)) == NULL) { + do { + size /= 2; + } while ((p = dt_zalloc(dtp, size)) == NULL); + } + + dt_free(dtp, p); + + return (0); +} + typedef struct dt_option { const char *o_name; int (*o_func)(dtrace_hdl_t *, const char *, uintptr_t); @@ -873,6 +899,7 @@ static const dt_option_t _dtrace_ctoptions[] = { { "linktype", dt_opt_linktype }, { "nolibs", dt_opt_cflags, DTRACE_C_NOLIBS }, { "pgmax", dt_opt_pgmax }, + { "preallocate", dt_opt_preallocate }, { "pspec", dt_opt_cflags, DTRACE_C_PSPEC }, { "stdc", dt_opt_stdc }, { "strip", dt_opt_dflags, DTRACE_D_STRIP }, diff --git a/lib/libdtrace/common/dt_parser.c b/lib/libdtrace/common/dt_parser.c index 05715894a7df..6ad30a9ac52a 100644 --- a/lib/libdtrace/common/dt_parser.c +++ b/lib/libdtrace/common/dt_parser.c @@ -21,7 +21,6 @@ /* * Copyright (c) 2003, 2010, Oracle and/or its affiliates. All rights reserved. - * Copyright (c) 2011, Joyent Inc. All rights reserved. */ /* @@ -720,19 +719,12 @@ dt_node_type_name(const dt_node_t *dnp, char *buf, size_t len) size_t dt_node_type_size(const dt_node_t *dnp) { - ctf_id_t base; - if (dnp->dn_kind == DT_NODE_STRING) return (strlen(dnp->dn_string) + 1); if (dt_node_is_dynamic(dnp) && dnp->dn_ident != NULL) return (dt_ident_size(dnp->dn_ident)); - base = ctf_type_resolve(dnp->dn_ctfp, dnp->dn_type); - - if (ctf_type_kind(dnp->dn_ctfp, base) == CTF_K_FORWARD) - return (0); - return (ctf_type_size(dnp->dn_ctfp, dnp->dn_type)); } diff --git a/lib/libdtrace/common/dt_pragma.c b/lib/libdtrace/common/dt_pragma.c index 9fae5ac42c40..9cb3c3b8d615 100644 --- a/lib/libdtrace/common/dt_pragma.c +++ b/lib/libdtrace/common/dt_pragma.c @@ -21,19 +21,14 @@ /* * Copyright (c) 2003, 2010, Oracle and/or its affiliates. All rights reserved. - * Copyright (c) 2011, Joyent Inc. All rights reserved. */ #include <assert.h> #include <strings.h> #include <alloca.h> -#include <fcntl.h> #include <stdlib.h> #include <stdio.h> -#include <sys/types.h> -#include <sys/stat.h> - #include <dt_parser.h> #include <dt_impl.h> #include <dt_provider.h> @@ -201,29 +196,6 @@ dt_pragma_binding(const char *prname, dt_node_t *dnp) dtp->dt_globals->dh_defer = &dt_pragma_apply; } -static void -dt_pragma_depends_finddep(dtrace_hdl_t *dtp, const char *lname, char *lib, - size_t len) -{ - dt_dirpath_t *dirp; - struct stat sbuf; - int found = 0; - - for (dirp = dt_list_next(&dtp->dt_lib_path); dirp != NULL; - dirp = dt_list_next(dirp)) { - (void) snprintf(lib, len, "%s/%s", dirp->dir_path, lname); - - if (stat(lib, &sbuf) == 0) { - found = 1; - break; - } - } - - if (!found) - xyerror(D_PRAGMA_DEPEND, - "failed to find dependency in libpath: %s", lname); -} - /* * The #pragma depends_on directive can be used to express a dependency on a * module, provider or library which if not present will cause processing to @@ -253,13 +225,16 @@ dt_pragma_depends(const char *prname, dt_node_t *cnp) if (yypcb->pcb_cflags & DTRACE_C_CTL) { assert(dtp->dt_filetag != NULL); - dt_pragma_depends_finddep(dtp, nnp->dn_string, lib, - sizeof (lib)); - + /* + * We have the file we are working on in dtp->dt_filetag + * so find that node and add the dependency in. + */ dld = dt_lib_depend_lookup(&dtp->dt_lib_dep, dtp->dt_filetag); assert(dld != NULL); + (void) snprintf(lib, sizeof (lib), "%s%s", + dld->dtld_libpath, nnp->dn_string); if ((dt_lib_depend_add(dtp, &dld->dtld_dependencies, lib)) != 0) { xyerror(D_PRAGMA_DEPEND, @@ -281,8 +256,8 @@ dt_pragma_depends(const char *prname, dt_node_t *cnp) dtp->dt_filetag); assert(dld != NULL); - dt_pragma_depends_finddep(dtp, nnp->dn_string, lib, - sizeof (lib)); + (void) snprintf(lib, sizeof (lib), "%s%s", + dld->dtld_libpath, nnp->dn_string); dld = dt_lib_depend_lookup(&dtp->dt_lib_dep_sorted, lib); assert(dld != NULL); diff --git a/lib/libdtrace/common/dt_print.c b/lib/libdtrace/common/dt_print.c deleted file mode 100644 index 261fc8ced4d5..000000000000 --- a/lib/libdtrace/common/dt_print.c +++ /dev/null @@ -1,648 +0,0 @@ -/* - * 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 2009 Sun Microsystems, Inc. All rights reserved. - * Use is subject to license terms. - */ -/* - * Copyright (c) 2011 by Delphix. All rights reserved. - */ - -/* - * DTrace print() action - * - * This file contains the post-processing logic for the print() action. The - * print action behaves identically to trace() in that it generates a - * DTRACEACT_DIFEXPR action, but the action argument field refers to a CTF type - * string stored in the DOF string table (similar to printf formats). We - * take the result of the trace action and post-process it in the fashion of - * MDB's ::print dcmd. - * - * This implementation differs from MDB's in the following ways: - * - * - We do not expose any options or flags. The behavior of print() is - * equivalent to "::print -tn". - * - * - MDB will display "holes" in structures (unused padding between - * members). - * - * - When printing arrays of structures, MDB will leave a trailing ',' - * after the last element. - * - * - MDB will print time_t types as date and time. - * - * - MDB will detect when an enum is actually the OR of several flags, - * and print it out with the constituent flags separated. - * - * - For large arrays, MDB will print the first few members and then - * print a "..." continuation line. - * - * - MDB will break and wrap arrays at 80 columns. - * - * - MDB prints out floats and doubles by hand, as it must run in kmdb - * context. We're able to leverage the printf() format strings, - * but the result is a slightly different format. - */ - -#include <sys/sysmacros.h> -#include <strings.h> -#include <stdlib.h> -#include <alloca.h> -#include <assert.h> -#include <ctype.h> -#include <errno.h> -#include <limits.h> -#include <sys/socket.h> -#include <netdb.h> -#include <netinet/in.h> -#include <arpa/inet.h> -#include <arpa/nameser.h> - -#include <dt_module.h> -#include <dt_printf.h> -#include <dt_string.h> -#include <dt_impl.h> - -/* determines whether the given integer CTF encoding is a character */ -#define CTF_IS_CHAR(e) \ - (((e).cte_format & (CTF_INT_CHAR | CTF_INT_SIGNED)) == \ - (CTF_INT_CHAR | CTF_INT_SIGNED) && (e).cte_bits == NBBY) -/* determines whether the given CTF kind is a struct or union */ -#define CTF_IS_STRUCTLIKE(k) \ - ((k) == CTF_K_STRUCT || (k) == CTF_K_UNION) - -/* - * Print structure passed down recursively through printing algorithm. - */ -typedef struct dt_printarg { - caddr_t pa_addr; /* base address of trace data */ - ctf_file_t *pa_ctfp; /* CTF container */ - int pa_depth; /* member depth */ - int pa_nest; /* nested array depth */ - FILE *pa_file; /* output file */ -} dt_printarg_t; - -static int dt_print_member(const char *, ctf_id_t, ulong_t, int, void *); - -/* - * Safe version of ctf_type_name() that will fall back to just "<ctfid>" if it - * can't resolve the type. - */ -static void -dt_print_type_name(ctf_file_t *ctfp, ctf_id_t id, char *buf, size_t buflen) -{ - if (ctf_type_name(ctfp, id, buf, buflen) == NULL) - (void) snprintf(buf, buflen, "<%ld>", id); -} - -/* - * Print any necessary trailing braces for structures or unions. We don't get - * invoked when a struct or union ends, so we infer the need to print braces - * based on the depth the last time we printed something and the new depth. - */ -static void -dt_print_trailing_braces(dt_printarg_t *pap, int depth) -{ - int d; - - for (d = pap->pa_depth; d > depth; d--) { - (void) fprintf(pap->pa_file, "%*s}%s", - (d + pap->pa_nest - 1) * 4, "", - d == depth + 1 ? "" : "\n"); - } -} - -/* - * Print the appropriate amount of indentation given the current depth and - * array nesting. - */ -static void -dt_print_indent(dt_printarg_t *pap) -{ - (void) fprintf(pap->pa_file, "%*s", - (pap->pa_depth + pap->pa_nest) * 4, ""); -} - -/* - * Print a bitfield. It's worth noting that the D compiler support for - * bitfields is currently broken; printing "D`user_desc_t" (pulled in by the - * various D provider files) will produce incorrect results compared to - * "genunix`user_desc_t". - */ -static void -print_bitfield(dt_printarg_t *pap, ulong_t off, ctf_encoding_t *ep) -{ - FILE *fp = pap->pa_file; - caddr_t addr = pap->pa_addr + off / NBBY; - uint64_t mask = (1ULL << ep->cte_bits) - 1; - uint64_t value = 0; - size_t size = (ep->cte_bits + (NBBY - 1)) / NBBY; - uint8_t *buf = (uint8_t *)&value; - uint8_t shift; - - /* - * On big-endian machines, we need to adjust the buf pointer to refer - * to the lowest 'size' bytes in 'value', and we need to shift based on - * the offset from the end of the data, not the offset of the start. - */ -#ifdef _BIG_ENDIAN - buf += sizeof (value) - size; - off += ep->cte_bits; -#endif - bcopy(addr, buf, size); - shift = off % NBBY; - - /* - * Offsets are counted from opposite ends on little- and - * big-endian machines. - */ -#ifdef _BIG_ENDIAN - shift = NBBY - shift; -#endif - - /* - * If the bits we want do not begin on a byte boundary, shift the data - * right so that the value is in the lowest 'cte_bits' of 'value'. - */ - if (off % NBBY != 0) - value >>= shift; - value &= mask; - - (void) fprintf(fp, "%#llx", (u_longlong_t)value); -} - -/* - * Dump the contents of memory as a fixed-size integer in hex. - */ -static void -dt_print_hex(FILE *fp, caddr_t addr, size_t size) -{ - switch (size) { - case sizeof (uint8_t): - (void) fprintf(fp, "%#x", *(uint8_t *)addr); - break; - case sizeof (uint16_t): - /* LINTED - alignment */ - (void) fprintf(fp, "%#x", *(uint16_t *)addr); - break; - case sizeof (uint32_t): - /* LINTED - alignment */ - (void) fprintf(fp, "%#x", *(uint32_t *)addr); - break; - case sizeof (uint64_t): - (void) fprintf(fp, "%#llx", - /* LINTED - alignment */ - (unsigned long long)*(uint64_t *)addr); - break; - default: - (void) fprintf(fp, "<invalid size %u>", (uint_t)size); - } -} - -/* - * Print an integer type. Before dumping the contents via dt_print_hex(), we - * first check the encoding to see if it's part of a bitfield or a character. - */ -static void -dt_print_int(ctf_id_t base, ulong_t off, dt_printarg_t *pap) -{ - FILE *fp = pap->pa_file; - ctf_file_t *ctfp = pap->pa_ctfp; - ctf_encoding_t e; - size_t size; - caddr_t addr = pap->pa_addr + off / NBBY; - - if (ctf_type_encoding(ctfp, base, &e) == CTF_ERR) { - (void) fprintf(fp, "<unknown encoding>"); - return; - } - - /* - * This comes from MDB - it's not clear under what circumstances this - * would be found. - */ - if (e.cte_format & CTF_INT_VARARGS) { - (void) fprintf(fp, "..."); - return; - } - - /* - * We print this as a bitfield if the bit encoding indicates it's not - * an even power of two byte size, or is larger than 8 bytes. - */ - size = e.cte_bits / NBBY; - if (size > 8 || (e.cte_bits % NBBY) != 0 || (size & (size - 1)) != 0) { - print_bitfield(pap, off, &e); - return; - } - - /* - * If this is a character, print it out as such. - */ - if (CTF_IS_CHAR(e)) { - char c = *(char *)addr; - if (isprint(c)) - (void) fprintf(fp, "'%c'", c); - else if (c == 0) - (void) fprintf(fp, "'\\0'"); - else - (void) fprintf(fp, "'\\%03o'", c); - return; - } - - dt_print_hex(fp, addr, size); -} - -/* - * Print a floating point (float, double, long double) value. - */ -/* ARGSUSED */ -static void -dt_print_float(ctf_id_t base, ulong_t off, dt_printarg_t *pap) -{ - FILE *fp = pap->pa_file; - ctf_file_t *ctfp = pap->pa_ctfp; - ctf_encoding_t e; - caddr_t addr = pap->pa_addr + off / NBBY; - - if (ctf_type_encoding(ctfp, base, &e) == 0) { - if (e.cte_format == CTF_FP_SINGLE && - e.cte_bits == sizeof (float) * NBBY) { - /* LINTED - alignment */ - (void) fprintf(fp, "%+.7e", *((float *)addr)); - } else if (e.cte_format == CTF_FP_DOUBLE && - e.cte_bits == sizeof (double) * NBBY) { - /* LINTED - alignment */ - (void) fprintf(fp, "%+.7e", *((double *)addr)); - } else if (e.cte_format == CTF_FP_LDOUBLE && - e.cte_bits == sizeof (long double) * NBBY) { - /* LINTED - alignment */ - (void) fprintf(fp, "%+.16LE", *((long double *)addr)); - } else { - (void) fprintf(fp, "<unknown encoding>"); - } - } -} - -/* - * A pointer is printed as a fixed-size integer. This is used both for - * pointers and functions. - */ -static void -dt_print_ptr(ctf_id_t base, ulong_t off, dt_printarg_t *pap) -{ - FILE *fp = pap->pa_file; - ctf_file_t *ctfp = pap->pa_ctfp; - caddr_t addr = pap->pa_addr + off / NBBY; - size_t size = ctf_type_size(ctfp, base); - - dt_print_hex(fp, addr, size); -} - -/* - * Print out an array. This is somewhat complex, as we must manually visit - * each member, and recursively invoke ctf_type_visit() for each member. If - * the members are non-structs, then we print them out directly: - * - * [ 0x14, 0x2e, 0 ] - * - * If they are structs, then we print out the necessary leading and trailing - * braces, to end up with: - * - * [ - * type { - * ... - * }, - * type { - * ... - * } - * ] - * - * We also use a heuristic to detect whether the array looks like a character - * array. If the encoding indicates it's a character, and we have all - * printable characters followed by a null byte, then we display it as a - * string: - * - * [ "string" ] - */ -static void -dt_print_array(ctf_id_t base, ulong_t off, dt_printarg_t *pap) -{ - FILE *fp = pap->pa_file; - ctf_file_t *ctfp = pap->pa_ctfp; - caddr_t addr = pap->pa_addr + off / NBBY; - ctf_arinfo_t car; - ssize_t eltsize; - ctf_encoding_t e; - int i; - boolean_t isstring; - int kind; - ctf_id_t rtype; - - if (ctf_array_info(ctfp, base, &car) == CTF_ERR) { - (void) fprintf(fp, "0x%p", (void *)addr); - return; - } - - if ((eltsize = ctf_type_size(ctfp, car.ctr_contents)) < 0 || - (rtype = ctf_type_resolve(ctfp, car.ctr_contents)) == CTF_ERR || - (kind = ctf_type_kind(ctfp, rtype)) == CTF_ERR) { - (void) fprintf(fp, "<invalid type %lu>", car.ctr_contents); - return; - } - - /* see if this looks like a string */ - isstring = B_FALSE; - if (kind == CTF_K_INTEGER && - ctf_type_encoding(ctfp, rtype, &e) != CTF_ERR && CTF_IS_CHAR(e)) { - char c; - for (i = 0; i < car.ctr_nelems; i++) { - c = *((char *)addr + eltsize * i); - if (!isprint(c) || c == '\0') - break; - } - - if (i != car.ctr_nelems && c == '\0') - isstring = B_TRUE; - } - - /* - * As a slight aesthetic optimization, if we are a top-level type, then - * don't bother printing out the brackets. This lets print("foo") look - * like: - * - * string "foo" - * - * As D will internally represent this as a char[256] array. - */ - if (!isstring || pap->pa_depth != 0) - (void) fprintf(fp, "[ "); - - if (isstring) - (void) fprintf(fp, "\""); - - for (i = 0; i < car.ctr_nelems; i++) { - if (isstring) { - char c = *((char *)addr + eltsize * i); - if (c == '\0') - break; - (void) fprintf(fp, "%c", c); - } else { - /* - * Recursively invoke ctf_type_visit() on each member. - * We setup a new printarg struct with 'pa_nest' set to - * indicate that we are within a nested array. - */ - dt_printarg_t pa = *pap; - pa.pa_nest += pap->pa_depth + 1; - pa.pa_depth = 0; - pa.pa_addr = addr + eltsize * i; - (void) ctf_type_visit(ctfp, car.ctr_contents, - dt_print_member, &pa); - - dt_print_trailing_braces(&pa, 0); - if (i != car.ctr_nelems - 1) - (void) fprintf(fp, ", "); - else if (CTF_IS_STRUCTLIKE(kind)) - (void) fprintf(fp, "\n"); - } - } - - if (isstring) - (void) fprintf(fp, "\""); - - if (!isstring || pap->pa_depth != 0) { - if (CTF_IS_STRUCTLIKE(kind)) - dt_print_indent(pap); - else - (void) fprintf(fp, " "); - (void) fprintf(fp, "]"); - } -} - -/* - * This isued by both structs and unions to print the leading brace. - */ -/* ARGSUSED */ -static void -dt_print_structlike(ctf_id_t id, ulong_t off, dt_printarg_t *pap) -{ - (void) fprintf(pap->pa_file, "{"); -} - -/* - * For enums, we try to print the enum name, and fall back to the value if it - * can't be determined. We do not do any fancy flag processing like mdb. - */ -/* ARGSUSED */ -static void -dt_print_enum(ctf_id_t base, ulong_t off, dt_printarg_t *pap) -{ - FILE *fp = pap->pa_file; - ctf_file_t *ctfp = pap->pa_ctfp; - const char *ename; - int value = 0; - - if ((ename = ctf_enum_name(ctfp, base, value)) != NULL) - (void) fprintf(fp, "%s", ename); - else - (void) fprintf(fp, "%d", value); -} - -/* - * Forward declaration. There's not much to do here without the complete - * type information, so just print out this fact and drive on. - */ -/* ARGSUSED */ -static void -dt_print_tag(ctf_id_t base, ulong_t off, dt_printarg_t *pap) -{ - (void) fprintf(pap->pa_file, "<forward decl>"); -} - -typedef void dt_printarg_f(ctf_id_t, ulong_t, dt_printarg_t *); - -static dt_printarg_f *const dt_printfuncs[] = { - dt_print_int, /* CTF_K_INTEGER */ - dt_print_float, /* CTF_K_FLOAT */ - dt_print_ptr, /* CTF_K_POINTER */ - dt_print_array, /* CTF_K_ARRAY */ - dt_print_ptr, /* CTF_K_FUNCTION */ - dt_print_structlike, /* CTF_K_STRUCT */ - dt_print_structlike, /* CTF_K_UNION */ - dt_print_enum, /* CTF_K_ENUM */ - dt_print_tag /* CTF_K_FORWARD */ -}; - -/* - * Print one member of a structure. This callback is invoked from - * ctf_type_visit() recursively. - */ -static int -dt_print_member(const char *name, ctf_id_t id, ulong_t off, int depth, - void *data) -{ - char type[DT_TYPE_NAMELEN]; - int kind; - dt_printarg_t *pap = data; - FILE *fp = pap->pa_file; - ctf_file_t *ctfp = pap->pa_ctfp; - boolean_t arraymember; - boolean_t brief; - ctf_encoding_t e; - ctf_id_t rtype; - - dt_print_trailing_braces(pap, depth); - /* - * dt_print_trailing_braces() doesn't include the trailing newline; add - * it here if necessary. - */ - if (depth < pap->pa_depth) - (void) fprintf(fp, "\n"); - pap->pa_depth = depth; - - if ((rtype = ctf_type_resolve(ctfp, id)) == CTF_ERR || - (kind = ctf_type_kind(ctfp, rtype)) == CTF_ERR || - kind < CTF_K_INTEGER || kind > CTF_K_FORWARD) { - dt_print_indent(pap); - (void) fprintf(fp, "%s = <invalid type %lu>", name, id); - return (0); - } - - dt_print_type_name(ctfp, id, type, sizeof (type)); - - arraymember = (pap->pa_nest != 0 && depth == 0); - brief = (arraymember && !CTF_IS_STRUCTLIKE(kind)); - - if (!brief) { - /* - * If this is a direct array member and a struct (otherwise - * brief would be true), then print a trailing newline, as the - * array printing code doesn't include it because it might be a - * simple type. - */ - if (arraymember) - (void) fprintf(fp, "\n"); - dt_print_indent(pap); - - /* always print the type */ - (void) fprintf(fp, "%s", type); - if (name[0] != '\0') { - /* - * For aesthetics, we don't include a space between the - * type name and member name if the type is a pointer. - * This will give us "void *foo =" instead of "void * - * foo =". Unions also have the odd behavior that the - * type name is returned as "union ", with a trailing - * space, so we also avoid printing a space if the type - * name already ends with a space. - */ - if (type[strlen(type) - 1] != '*' && - type[strlen(type) -1] != ' ') { - (void) fprintf(fp, " "); - } - (void) fprintf(fp, "%s", name); - - /* - * If this looks like a bitfield, or is an integer not - * aligned on a byte boundary, print the number of - * bits after the name. - */ - if (kind == CTF_K_INTEGER && - ctf_type_encoding(ctfp, id, &e) == 0) { - ulong_t bits = e.cte_bits; - ulong_t size = bits / NBBY; - - if (bits % NBBY != 0 || - off % NBBY != 0 || - size > 8 || - size != ctf_type_size(ctfp, id)) { - (void) fprintf(fp, " :%lu", bits); - } - } - - (void) fprintf(fp, " ="); - } - (void) fprintf(fp, " "); - } - - dt_printfuncs[kind - 1](rtype, off, pap); - - /* direct simple array members are not separated by newlines */ - if (!brief) - (void) fprintf(fp, "\n"); - - return (0); -} - -/* - * Main print function invoked by dt_consume_cpu(). - */ -int -dtrace_print(dtrace_hdl_t *dtp, FILE *fp, const char *typename, - caddr_t addr, size_t len) -{ - const char *s; - char *object; - dt_printarg_t pa; - ctf_id_t id; - dt_module_t *dmp; - - /* - * Split the fully-qualified type ID (module`id). This should - * always be the format, but if for some reason we don't find the - * expected value, return 0 to fall back to the generic trace() - * behavior. - */ - for (s = typename; *s != '\0' && *s != '`'; s++) - ; - - if (*s != '`') - return (0); - - object = alloca(s - typename + 1); - bcopy(typename, object, s - typename); - object[s - typename] = '\0'; - id = atoi(s + 1); - - /* - * Try to get the CTF kind for this id. If something has gone horribly - * wrong and we can't resolve the ID, bail out and let trace() do the - * work. - */ - dmp = dt_module_lookup_by_name(dtp, object); - if (dmp == NULL || ctf_type_kind(dt_module_getctf(dtp, dmp), - id) == CTF_ERR) { - return (0); - } - - /* setup the print structure and kick off the main print routine */ - pa.pa_addr = addr; - pa.pa_ctfp = dt_module_getctf(dtp, dmp); - pa.pa_nest = 0; - pa.pa_depth = 0; - pa.pa_file = fp; - (void) ctf_type_visit(pa.pa_ctfp, id, dt_print_member, &pa); - - dt_print_trailing_braces(&pa, 0); - - return (len); -} diff --git a/lib/libdtrace/common/dt_printf.c b/lib/libdtrace/common/dt_printf.c index eabc42338bcc..52904789bc7e 100644 --- a/lib/libdtrace/common/dt_printf.c +++ b/lib/libdtrace/common/dt_printf.c @@ -21,7 +21,6 @@ /* * Copyright (c) 2003, 2010, Oracle and/or its affiliates. All rights reserved. - * Copyright (c) 2011, Joyent, Inc. All rights reserved. */ #include <sys/sysmacros.h> @@ -1301,14 +1300,6 @@ pfprint_lquantize(dtrace_hdl_t *dtp, FILE *fp, const char *format, return (dt_print_lquantize(dtp, fp, addr, size, normal)); } -/*ARGSUSED*/ -static int -pfprint_llquantize(dtrace_hdl_t *dtp, FILE *fp, const char *format, - const dt_pfargd_t *pfd, const void *addr, size_t size, uint64_t normal) -{ - return (dt_print_llquantize(dtp, fp, addr, size, normal)); -} - static int dt_printf_format(dtrace_hdl_t *dtp, FILE *fp, const dt_pfargv_t *pfv, const dtrace_recdesc_t *recs, uint_t nrecs, const void *buf, @@ -1494,9 +1485,6 @@ dt_printf_format(dtrace_hdl_t *dtp, FILE *fp, const dt_pfargv_t *pfv, case DTRACEAGG_LQUANTIZE: func = pfprint_lquantize; break; - case DTRACEAGG_LLQUANTIZE: - func = pfprint_llquantize; - break; case DTRACEACT_MOD: func = pfprint_mod; break; diff --git a/lib/libdtrace/common/dt_program.c b/lib/libdtrace/common/dt_program.c index 7d725bd0af86..19f377de26ac 100644 --- a/lib/libdtrace/common/dt_program.c +++ b/lib/libdtrace/common/dt_program.c @@ -21,7 +21,6 @@ /* * Copyright (c) 2003, 2010, Oracle and/or its affiliates. All rights reserved. - * Copyright (c) 2011 by Delphix. All rights reserved. */ #include <unistd.h> @@ -348,7 +347,6 @@ dtrace_stmt_destroy(dtrace_hdl_t *dtp, dtrace_stmtdesc_t *sdp) if (sdp->dtsd_fmtdata != NULL) dt_printf_destroy(sdp->dtsd_fmtdata); - dt_free(dtp, sdp->dtsd_strdata); dt_ecbdesc_release(dtp, sdp->dtsd_ecbdesc); dt_free(dtp, sdp); diff --git a/lib/libdtrace/common/dtrace.h b/lib/libdtrace/common/dtrace.h index 87df1ca4402a..1c041207c0ae 100644 --- a/lib/libdtrace/common/dtrace.h +++ b/lib/libdtrace/common/dtrace.h @@ -24,13 +24,11 @@ * Use is subject to license terms. */ -/* - * Copyright (c) 2011, Joyent, Inc. All rights reserved. - */ - #ifndef _DTRACE_H #define _DTRACE_H +#pragma ident "%Z%%M% %I% %E% SMI" + #include <sys/dtrace.h> #include <stdarg.h> #include <stdio.h> @@ -150,7 +148,6 @@ typedef struct dtrace_stmtdesc { dtrace_actdesc_t *dtsd_action_last; /* last action in action list */ void *dtsd_aggdata; /* aggregation data */ void *dtsd_fmtdata; /* type-specific output data */ - void *dtsd_strdata; /* type-specific string data */ void (*dtsd_callback)(); /* callback function for EPID */ void *dtsd_data; /* callback data pointer */ dtrace_attribute_t dtsd_descattr; /* probedesc attributes */ @@ -243,18 +240,6 @@ extern int dtrace_freopen(dtrace_hdl_t *, FILE *, void *, const void *, size_t); /* - * Type-specific output printing - * - * The print() action will associate a string data record that is actually the - * fully-qualified type name of the data traced by the DIFEXPR action. This is - * stored in the same 'format' record from the kernel, but we know by virtue of - * the fact that the action is still DIFEXPR that it is actually a reference to - * plain string data. - */ -extern int dtrace_print(dtrace_hdl_t *, FILE *, const char *, - caddr_t, size_t); - -/* * DTrace Work Interface */ typedef enum { diff --git a/lib/libdtrace/i386/regs.d.in b/lib/libdtrace/i386/regs.d.in index d18c5f7ff1fb..3328f33515b0 100644 --- a/lib/libdtrace/i386/regs.d.in +++ b/lib/libdtrace/i386/regs.d.in @@ -23,9 +23,8 @@ * Copyright 2004 Sun Microsystems, Inc. All rights reserved. * Use is subject to license terms. */ -/* - * Copyright 2011 Joyent, Inc. All rights reserved. - */ + +#pragma ident "%Z%%M% %I% %E% SMI" inline int R_GS = @GS@; #pragma D binding "1.0" R_GS @@ -116,149 +115,3 @@ inline int R_R14 = @REG_R14@; inline int R_R15 = @REG_R15@; #pragma D binding "1.0" R_R15 -enum vmregs_vmx { - VMX_VIRTUAL_PROCESSOR_ID = 0x00000000, - VMX_GUEST_ES_SELECTOR = 0x00000800, - VMX_GUEST_CS_SELECTOR = 0x00000802, - VMX_GUEST_SS_SELECTOR = 0x00000804, - VMX_GUEST_DS_SELECTOR = 0x00000806, - VMX_GUEST_FS_SELECTOR = 0x00000808, - VMX_GUEST_GS_SELECTOR = 0x0000080a, - VMX_GUEST_LDTR_SELECTOR = 0x0000080c, - VMX_GUEST_TR_SELECTOR = 0x0000080e, - VMX_HOST_ES_SELECTOR = 0x00000c00, - VMX_HOST_CS_SELECTOR = 0x00000c02, - VMX_HOST_SS_SELECTOR = 0x00000c04, - VMX_HOST_DS_SELECTOR = 0x00000c06, - VMX_HOST_FS_SELECTOR = 0x00000c08, - VMX_HOST_GS_SELECTOR = 0x00000c0a, - VMX_HOST_TR_SELECTOR = 0x00000c0c, - VMX_IO_BITMAP_A = 0x00002000, - VMX_IO_BITMAP_A_HIGH = 0x00002001, - VMX_IO_BITMAP_B = 0x00002002, - VMX_IO_BITMAP_B_HIGH = 0x00002003, - VMX_MSR_BITMAP = 0x00002004, - VMX_MSR_BITMAP_HIGH = 0x00002005, - VMX_VM_EXIT_MSR_STORE_ADDR = 0x00002006, - VMX_VM_EXIT_MSR_STORE_ADDR_HIGH = 0x00002007, - VMX_VM_EXIT_MSR_LOAD_ADDR = 0x00002008, - VMX_VM_EXIT_MSR_LOAD_ADDR_HIGH = 0x00002009, - VMX_VM_ENTRY_MSR_LOAD_ADDR = 0x0000200a, - VMX_VM_ENTRY_MSR_LOAD_ADDR_HIGH = 0x0000200b, - VMX_TSC_OFFSET = 0x00002010, - VMX_TSC_OFFSET_HIGH = 0x00002011, - VMX_VIRTUAL_APIC_PAGE_ADDR = 0x00002012, - VMX_VIRTUAL_APIC_PAGE_ADDR_HIGH = 0x00002013, - VMX_APIC_ACCESS_ADDR = 0x00002014, - VMX_APIC_ACCESS_ADDR_HIGH = 0x00002015, - VMX_EPT_POINTER = 0x0000201a, - VMX_EPT_POINTER_HIGH = 0x0000201b, - VMX_GUEST_PHYSICAL_ADDRESS = 0x00002400, - VMX_GUEST_PHYSICAL_ADDRESS_HIGH = 0x00002401, - VMX_VMCS_LINK_POINTER = 0x00002800, - VMX_VMCS_LINK_POINTER_HIGH = 0x00002801, - VMX_GUEST_IA32_DEBUGCTL = 0x00002802, - VMX_GUEST_IA32_DEBUGCTL_HIGH = 0x00002803, - VMX_GUEST_IA32_PAT = 0x00002804, - VMX_GUEST_IA32_PAT_HIGH = 0x00002805, - VMX_GUEST_PDPTR0 = 0x0000280a, - VMX_GUEST_PDPTR0_HIGH = 0x0000280b, - VMX_GUEST_PDPTR1 = 0x0000280c, - VMX_GUEST_PDPTR1_HIGH = 0x0000280d, - VMX_GUEST_PDPTR2 = 0x0000280e, - VMX_GUEST_PDPTR2_HIGH = 0x0000280f, - VMX_GUEST_PDPTR3 = 0x00002810, - VMX_GUEST_PDPTR3_HIGH = 0x00002811, - VMX_HOST_IA32_PAT = 0x00002c00, - VMX_HOST_IA32_PAT_HIGH = 0x00002c01, - VMX_PIN_BASED_VM_EXEC_CONTROL = 0x00004000, - VMX_CPU_BASED_VM_EXEC_CONTROL = 0x00004002, - VMX_EXCEPTION_BITMAP = 0x00004004, - VMX_PAGE_FAULT_ERROR_CODE_MASK = 0x00004006, - VMX_PAGE_FAULT_ERROR_CODE_MATCH = 0x00004008, - VMX_CR3_TARGET_COUNT = 0x0000400a, - VMX_VM_EXIT_CONTROLS = 0x0000400c, - VMX_VM_EXIT_MSR_STORE_COUNT = 0x0000400e, - VMX_VM_EXIT_MSR_LOAD_COUNT = 0x00004010, - VMX_VM_ENTRY_CONTROLS = 0x00004012, - VMX_VM_ENTRY_MSR_LOAD_COUNT = 0x00004014, - VMX_VM_ENTRY_INTR_INFO_FIELD = 0x00004016, - VMX_VM_ENTRY_EXCEPTION_ERROR_CODE = 0x00004018, - VMX_VM_ENTRY_INSTRUCTION_LEN = 0x0000401a, - VMX_TPR_THRESHOLD = 0x0000401c, - VMX_SECONDARY_VM_EXEC_CONTROL = 0x0000401e, - VMX_PLE_GAP = 0x00004020, - VMX_PLE_WINDOW = 0x00004022, - VMX_VM_INSTRUCTION_ERROR = 0x00004400, - VMX_VM_EXIT_REASON = 0x00004402, - VMX_VM_EXIT_INTR_INFO = 0x00004404, - VMX_VM_EXIT_INTR_ERROR_CODE = 0x00004406, - VMX_IDT_VECTORING_INFO_FIELD = 0x00004408, - VMX_IDT_VECTORING_ERROR_CODE = 0x0000440a, - VMX_VM_EXIT_INSTRUCTION_LEN = 0x0000440c, - VMX_VMX_INSTRUCTION_INFO = 0x0000440e, - VMX_GUEST_ES_LIMIT = 0x00004800, - VMX_GUEST_CS_LIMIT = 0x00004802, - VMX_GUEST_SS_LIMIT = 0x00004804, - VMX_GUEST_DS_LIMIT = 0x00004806, - VMX_GUEST_FS_LIMIT = 0x00004808, - VMX_GUEST_GS_LIMIT = 0x0000480a, - VMX_GUEST_LDTR_LIMIT = 0x0000480c, - VMX_GUEST_TR_LIMIT = 0x0000480e, - VMX_GUEST_GDTR_LIMIT = 0x00004810, - VMX_GUEST_IDTR_LIMIT = 0x00004812, - VMX_GUEST_ES_AR_BYTES = 0x00004814, - VMX_GUEST_CS_AR_BYTES = 0x00004816, - VMX_GUEST_SS_AR_BYTES = 0x00004818, - VMX_GUEST_DS_AR_BYTES = 0x0000481a, - VMX_GUEST_FS_AR_BYTES = 0x0000481c, - VMX_GUEST_GS_AR_BYTES = 0x0000481e, - VMX_GUEST_LDTR_AR_BYTES = 0x00004820, - VMX_GUEST_TR_AR_BYTES = 0x00004822, - VMX_GUEST_INTERRUPTIBILITY_INFO = 0x00004824, - VMX_GUEST_ACTIVITY_STATE = 0X00004826, - VMX_GUEST_SYSENTER_CS = 0x0000482A, - VMX_HOST_IA32_SYSENTER_CS = 0x00004c00, - VMX_CR0_GUEST_HOST_MASK = 0x00006000, - VMX_CR4_GUEST_HOST_MASK = 0x00006002, - VMX_CR0_READ_SHADOW = 0x00006004, - VMX_CR4_READ_SHADOW = 0x00006006, - VMX_CR3_TARGET_VALUE0 = 0x00006008, - VMX_CR3_TARGET_VALUE1 = 0x0000600a, - VMX_CR3_TARGET_VALUE2 = 0x0000600c, - VMX_CR3_TARGET_VALUE3 = 0x0000600e, - VMX_EXIT_QUALIFICATION = 0x00006400, - VMX_GUEST_LINEAR_ADDRESS = 0x0000640a, - VMX_GUEST_CR0 = 0x00006800, - VMX_GUEST_CR3 = 0x00006802, - VMX_GUEST_CR4 = 0x00006804, - VMX_GUEST_ES_BASE = 0x00006806, - VMX_GUEST_CS_BASE = 0x00006808, - VMX_GUEST_SS_BASE = 0x0000680a, - VMX_GUEST_DS_BASE = 0x0000680c, - VMX_GUEST_FS_BASE = 0x0000680e, - VMX_GUEST_GS_BASE = 0x00006810, - VMX_GUEST_LDTR_BASE = 0x00006812, - VMX_GUEST_TR_BASE = 0x00006814, - VMX_GUEST_GDTR_BASE = 0x00006816, - VMX_GUEST_IDTR_BASE = 0x00006818, - VMX_GUEST_DR7 = 0x0000681a, - VMX_GUEST_RSP = 0x0000681c, - VMX_GUEST_RIP = 0x0000681e, - VMX_GUEST_RFLAGS = 0x00006820, - VMX_GUEST_PENDING_DBG_EXCEPTIONS = 0x00006822, - VMX_GUEST_SYSENTER_ESP = 0x00006824, - VMX_GUEST_SYSENTER_EIP = 0x00006826, - VMX_HOST_CR0 = 0x00006c00, - VMX_HOST_CR3 = 0x00006c02, - VMX_HOST_CR4 = 0x00006c04, - VMX_HOST_FS_BASE = 0x00006c06, - VMX_HOST_GS_BASE = 0x00006c08, - VMX_HOST_TR_BASE = 0x00006c0a, - VMX_HOST_GDTR_BASE = 0x00006c0c, - VMX_HOST_IDTR_BASE = 0x00006c0e, - VMX_HOST_IA32_SYSENTER_ESP = 0x00006c10, - VMX_HOST_IA32_SYSENTER_EIP = 0x00006c12, - VMX_HOST_RSP = 0x00006c14, - VMX_HOST_RIP = 0x00006c16 -}; diff --git a/lib/libnvpair/libnvpair.c b/lib/libnvpair/libnvpair.c index c2e5a1b46dad..16bce483bee5 100644 --- a/lib/libnvpair/libnvpair.c +++ b/lib/libnvpair/libnvpair.c @@ -20,7 +20,6 @@ */ /* * Copyright (c) 2000, 2010, Oracle and/or its affiliates. All rights reserved. - * Copyright (c) 2012 by Delphix. All rights reserved. */ #include <unistd.h> @@ -804,10 +803,6 @@ dump_nvlist(nvlist_t *list, int indent) while ((elem = nvlist_next_nvpair(list, elem)) != NULL) { switch (nvpair_type(elem)) { - case DATA_TYPE_BOOLEAN: - (void) printf("%*s%s\n", indent, "", nvpair_name(elem)); - break; - case DATA_TYPE_BOOLEAN_VALUE: (void) nvpair_value_boolean_value(elem, &bool_value); (void) printf("%*s%s: %s\n", indent, "", diff --git a/lib/libuutil/common/uu_list.c b/lib/libuutil/common/uu_list.c index 93795e5289b2..35c7ba800103 100644 --- a/lib/libuutil/common/uu_list.c +++ b/lib/libuutil/common/uu_list.c @@ -18,14 +18,13 @@ * * CDDL HEADER END */ - /* * Copyright 2008 Sun Microsystems, Inc. All rights reserved. * Use is subject to license terms. - * - * Copyright 2011 Jason King. All rights reserved. */ +#pragma ident "%Z%%M% %I% %E% SMI" + #include "libuutil_common.h" #include <stdlib.h> @@ -319,8 +318,6 @@ uu_list_find(uu_list_t *lp, void *elem, void *private, uu_list_index_t *out) uu_compare_fn_t *func = lp->ul_pool->ulp_cmp; uu_list_node_impl_t *np; - uu_set_error(UU_ERROR_NONE); - if (func == NULL) { if (out != NULL) *out = 0; diff --git a/lib/libzfs/common/libzfs.h b/lib/libzfs/common/libzfs.h index 56ebf530daf5..ea34cc9efa31 100644 --- a/lib/libzfs/common/libzfs.h +++ b/lib/libzfs/common/libzfs.h @@ -21,9 +21,6 @@ /* * Copyright (c) 2005, 2010, Oracle and/or its affiliates. All rights reserved. - * Copyright 2011 Nexenta Systems, Inc. All rights reserved. - * Copyright (c) 2012 by Delphix. All rights reserved. - * Copyright (c) 2012, Joyent, Inc. All rights reserved. */ #ifndef _LIBZFS_H @@ -54,8 +51,7 @@ extern "C" { /* * libzfs errors */ -typedef enum zfs_error { - EZFS_SUCCESS = 0, /* no error -- success */ +enum { EZFS_NOMEM = 2000, /* out of memory */ EZFS_BADPROP, /* invalid property value */ EZFS_PROPREADONLY, /* cannot set readonly property */ @@ -127,7 +123,7 @@ typedef enum zfs_error { EZFS_DIFFDATA, /* bad zfs diff data */ EZFS_POOLREADONLY, /* pool is in read-only mode */ EZFS_UNKNOWN -} zfs_error_t; +}; /* * The following data structures are all part @@ -183,9 +179,6 @@ extern libzfs_handle_t *zfs_get_handle(zfs_handle_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 const char *libzfs_error_action(libzfs_handle_t *); extern const char *libzfs_error_description(libzfs_handle_t *); @@ -220,7 +213,7 @@ extern int zpool_iter(libzfs_handle_t *, zpool_iter_f, void *); */ extern int zpool_create(libzfs_handle_t *, const char *, nvlist_t *, nvlist_t *, nvlist_t *); -extern int zpool_destroy(zpool_handle_t *, const char *); +extern int zpool_destroy(zpool_handle_t *); extern int zpool_add(zpool_handle_t *, nvlist_t *); typedef struct splitflags { @@ -236,8 +229,6 @@ typedef struct splitflags { */ extern int zpool_scan(zpool_handle_t *, pool_scan_func_t); extern int zpool_clear(zpool_handle_t *, const char *, nvlist_t *); -extern int zpool_reguid(zpool_handle_t *); -extern int zpool_reopen(zpool_handle_t *); extern int zpool_vdev_online(zpool_handle_t *, const char *, int, vdev_state_t *); @@ -295,15 +286,6 @@ typedef enum { ZPOOL_STATUS_BAD_LOG, /* cannot read log chain(s) */ /* - * If the pool has unsupported features but can still be opened in - * read-only mode, its status is ZPOOL_STATUS_UNSUP_FEAT_WRITE. If the - * pool has unsupported features but cannot be opened at all, its - * status is ZPOOL_STATUS_UNSUP_FEAT_READ. - */ - ZPOOL_STATUS_UNSUP_FEAT_READ, /* unsupported features for read */ - ZPOOL_STATUS_UNSUP_FEAT_WRITE, /* unsupported features for write */ - - /* * These faults have no corresponding message ID. At the time we are * checking the status, the original reason for the FMA fault (I/O or * checksum errors) has been lost. @@ -335,20 +317,18 @@ extern void zpool_dump_ddt(const ddt_stat_t *dds, const ddt_histogram_t *ddh); * Statistics and configuration functions. */ extern nvlist_t *zpool_get_config(zpool_handle_t *, nvlist_t **); -extern nvlist_t *zpool_get_features(zpool_handle_t *); extern int zpool_refresh_stats(zpool_handle_t *, boolean_t *); extern int zpool_get_errlog(zpool_handle_t *, nvlist_t **); /* * Import and export functions */ -extern int zpool_export(zpool_handle_t *, boolean_t, const char *); -extern int zpool_export_force(zpool_handle_t *, const char *); +extern int zpool_export(zpool_handle_t *, boolean_t); +extern int zpool_export_force(zpool_handle_t *); extern int zpool_import(libzfs_handle_t *, nvlist_t *, const char *, char *altroot); extern int zpool_import_props(libzfs_handle_t *, nvlist_t *, const char *, nvlist_t *, int); -extern void zpool_print_unsup_feat(nvlist_t *config); /* * Search for pools to import @@ -377,7 +357,7 @@ extern nvlist_t *zpool_find_import_cached(libzfs_handle_t *, const char *, */ struct zfs_cmd; -extern const char *zfs_history_event_names[]; +extern const char *zfs_history_event_names[LOG_END]; extern char *zpool_vdev_name(libzfs_handle_t *, zpool_handle_t *, nvlist_t *, boolean_t verbose); @@ -385,6 +365,9 @@ extern int zpool_upgrade(zpool_handle_t *, uint64_t); extern int zpool_get_history(zpool_handle_t *, nvlist_t **); extern int zpool_history_unpack(char *, uint64_t, uint64_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 *, size_t len); extern int zfs_ioctl(libzfs_handle_t *, int, struct zfs_cmd *); @@ -397,7 +380,6 @@ extern void zpool_explain_recover(libzfs_handle_t *, const char *, int, * underlying datasets, only the references to them. */ extern zfs_handle_t *zfs_open(libzfs_handle_t *, const char *, int); -extern zfs_handle_t *zfs_handle_dup(zfs_handle_t *); extern void zfs_close(zfs_handle_t *); extern zfs_type_t zfs_get_type(const zfs_handle_t *); extern const char *zfs_get_name(const zfs_handle_t *); @@ -431,20 +413,12 @@ extern int zfs_prop_get_userquota_int(zfs_handle_t *zhp, const char *propname, uint64_t *propvalue); extern int zfs_prop_get_userquota(zfs_handle_t *zhp, const char *propname, char *propbuf, int proplen, boolean_t literal); -extern int zfs_prop_get_written_int(zfs_handle_t *zhp, const char *propname, - uint64_t *propvalue); -extern int zfs_prop_get_written(zfs_handle_t *zhp, const char *propname, - char *propbuf, int proplen, boolean_t literal); -extern int zfs_prop_get_feature(zfs_handle_t *zhp, const char *propname, - char *buf, size_t len); 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 const char *zfs_prop_values(zfs_prop_t); extern int zfs_prop_is_string(zfs_prop_t prop); extern nvlist_t *zfs_get_user_props(zfs_handle_t *); extern nvlist_t *zfs_get_recvd_props(zfs_handle_t *); -extern nvlist_t *zfs_get_clones_nvl(zfs_handle_t *); - typedef struct zprop_list { int pl_prop; @@ -462,19 +436,10 @@ extern void zfs_prune_proplist(zfs_handle_t *, uint8_t *); #define ZFS_MOUNTPOINT_NONE "none" #define ZFS_MOUNTPOINT_LEGACY "legacy" -#define ZFS_FEATURE_DISABLED "disabled" -#define ZFS_FEATURE_ENABLED "enabled" -#define ZFS_FEATURE_ACTIVE "active" - -#define ZFS_UNSUPPORTED_INACTIVE "inactive" -#define ZFS_UNSUPPORTED_READONLY "readonly" - /* * zpool property management */ extern int zpool_expand_proplist(zpool_handle_t *, zprop_list_t **); -extern int zpool_prop_get_feature(zpool_handle_t *, const char *, char *, - size_t); extern const char *zpool_prop_default_string(zpool_prop_t); extern uint64_t zpool_prop_default_numeric(zpool_prop_t); extern const char *zpool_prop_column_name(zpool_prop_t); @@ -528,7 +493,6 @@ extern int zfs_iter_dependents(zfs_handle_t *, boolean_t, zfs_iter_f, void *); extern int zfs_iter_filesystems(zfs_handle_t *, zfs_iter_f, void *); extern int zfs_iter_snapshots(zfs_handle_t *, zfs_iter_f, void *); extern int zfs_iter_snapshots_sorted(zfs_handle_t *, zfs_iter_f, void *); -extern int zfs_iter_snapspec(zfs_handle_t *, const char *, zfs_iter_f, void *); typedef struct get_all_cb { zfs_handle_t **cb_handles; @@ -549,94 +513,79 @@ extern int zfs_create(libzfs_handle_t *, const char *, zfs_type_t, extern int zfs_create_ancestors(libzfs_handle_t *, const char *); extern int zfs_destroy(zfs_handle_t *, boolean_t); 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_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_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_rename(zfs_handle_t *, const char *, boolean_t, boolean_t); +extern int zfs_rename(zfs_handle_t *, const char *, boolean_t); typedef struct sendflags { /* print informational messages (ie, -v was specified) */ - boolean_t verbose; + int verbose : 1; /* recursive send (ie, -R) */ - boolean_t replicate; + int replicate : 1; /* for incrementals, do all intermediate snapshots */ - boolean_t doall; + int doall : 1; /* (ie, -I) */ /* if dataset is a clone, do incremental from its origin */ - boolean_t fromorigin; + int fromorigin : 1; /* do deduplication */ - boolean_t dedup; + int dedup : 1; /* send properties (ie, -p) */ - boolean_t props; - - /* do not send (no-op, ie. -n) */ - boolean_t dryrun; - - /* parsable verbose output (ie. -P) */ - boolean_t parsable; - - /* show progress (ie. -v) */ - boolean_t progress; + int props : 1; } sendflags_t; typedef boolean_t (snapfilter_cb_t)(zfs_handle_t *, void *); -extern int zfs_send(zfs_handle_t *, const char *, const char *, - sendflags_t *, int, snapfilter_cb_t, void *, nvlist_t **); +extern int zfs_send(zfs_handle_t *zhp, const char *fromsnap, const char *tosnap, + sendflags_t flags, int outfd, snapfilter_cb_t filter_func, + void *cb_arg, nvlist_t **debugnvp); extern int zfs_promote(zfs_handle_t *); extern int zfs_hold(zfs_handle_t *, const char *, const char *, boolean_t, boolean_t, boolean_t, int, uint64_t, uint64_t); extern int zfs_release(zfs_handle_t *, const char *, const char *, boolean_t); -extern int zfs_get_holds(zfs_handle_t *, nvlist_t **); extern uint64_t zvol_volsize_to_reservation(uint64_t, nvlist_t *); typedef int (*zfs_userspace_cb_t)(void *arg, const char *domain, uid_t rid, uint64_t space); -extern int zfs_userspace(zfs_handle_t *, zfs_userquota_prop_t, - zfs_userspace_cb_t, void *); - -extern int zfs_get_fsacl(zfs_handle_t *, nvlist_t **); -extern int zfs_set_fsacl(zfs_handle_t *, boolean_t, nvlist_t *); +extern int zfs_userspace(zfs_handle_t *zhp, zfs_userquota_prop_t type, + zfs_userspace_cb_t func, void *arg); typedef struct recvflags { /* print informational messages (ie, -v was specified) */ - boolean_t verbose; + int verbose : 1; /* the destination is a prefix, not the exact fs (ie, -d) */ - boolean_t isprefix; + int isprefix : 1; /* * Only the tail of the sent snapshot path is appended to the * destination to determine the received snapshot name (ie, -e). */ - boolean_t istail; + int istail : 1; /* do not actually do the recv, just check if it would work (ie, -n) */ - boolean_t dryrun; + int dryrun : 1; /* rollback/destroy filesystems as necessary (eg, -F) */ - boolean_t force; + int force : 1; /* set "canmount=off" on all modified filesystems */ - boolean_t canmountoff; + int canmountoff : 1; /* byteswap flag is used internally; callers need not specify */ - boolean_t byteswap; + int byteswap : 1; /* do not mount file systems as they are extracted (private) */ - boolean_t nomount; + int nomount : 1; } recvflags_t; -extern int zfs_receive(libzfs_handle_t *, const char *, recvflags_t *, +extern int zfs_receive(libzfs_handle_t *, const char *, recvflags_t, int, avl_tree_t *); typedef enum diff_flags { diff --git a/lib/libzfs/common/libzfs_config.c b/lib/libzfs/common/libzfs_config.c index d5ba20fde0cf..dc27238c9cf3 100644 --- a/lib/libzfs/common/libzfs_config.c +++ b/lib/libzfs/common/libzfs_config.c @@ -18,17 +18,12 @@ * * CDDL HEADER END */ - /* * Copyright 2009 Sun Microsystems, Inc. All rights reserved. * Use is subject to license terms. */ /* - * Copyright (c) 2012 by Delphix. All rights reserved. - */ - -/* * The pool configuration repository is stored in /etc/zfs/zpool.cache as a * single packed nvlist. While it would be nice to just read in this * file from userland, this wouldn't work from a local zone. So we have to have @@ -223,36 +218,6 @@ zpool_get_config(zpool_handle_t *zhp, nvlist_t **oldconfig) } /* - * Retrieves a list of enabled features and their refcounts and caches it in - * the pool handle. - */ -nvlist_t * -zpool_get_features(zpool_handle_t *zhp) -{ - nvlist_t *config, *features; - - config = zpool_get_config(zhp, NULL); - - if (config == NULL || !nvlist_exists(config, - ZPOOL_CONFIG_FEATURE_STATS)) { - int error; - boolean_t missing = B_FALSE; - - error = zpool_refresh_stats(zhp, &missing); - - if (error != 0 || missing) - return (NULL); - - config = zpool_get_config(zhp, NULL); - } - - verify(nvlist_lookup_nvlist(config, ZPOOL_CONFIG_FEATURE_STATS, - &features) == 0); - - return (features); -} - -/* * Refresh the vdev statistics associated with the given pool. This is used in * iostat to show configuration changes and determine the delta from the last * time the function was called. This function can fail, in case the pool has @@ -337,48 +302,6 @@ zpool_refresh_stats(zpool_handle_t *zhp, boolean_t *missing) } /* - * 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. */ int @@ -401,9 +324,6 @@ zpool_iter(libzfs_handle_t *hdl, zpool_iter_f func, void *data) for (cn = uu_avl_first(hdl->libzfs_ns_avl); cn != NULL; 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) { hdl->libzfs_pool_iter--; return (-1); @@ -439,9 +359,6 @@ zfs_iter_root(libzfs_handle_t *hdl, zfs_iter_f func, void *data) for (cn = uu_avl_first(hdl->libzfs_ns_avl); cn != NULL; 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) continue; diff --git a/lib/libzfs/common/libzfs_dataset.c b/lib/libzfs/common/libzfs_dataset.c index cc2603cf890b..b7c1360db4b7 100644 --- a/lib/libzfs/common/libzfs_dataset.c +++ b/lib/libzfs/common/libzfs_dataset.c @@ -21,9 +21,6 @@ /* * Copyright (c) 2005, 2010, Oracle and/or its affiliates. All rights reserved. - * Copyright 2010 Nexenta Systems, Inc. All rights reserved. - * Copyright (c) 2012 by Delphix. All rights reserved. - * Copyright (c) 2012 DEY Storage Systems, Inc. All rights reserved. */ #include <ctype.h> @@ -135,7 +132,6 @@ zfs_validate_name(libzfs_handle_t *hdl, const char *path, int type, namecheck_err_t why; char what; - (void) zfs_prop_get_table(); if (dataset_namecheck(path, &why, &what) != 0) { if (hdl != NULL) { switch (why) { @@ -497,7 +493,7 @@ make_dataset_handle(libzfs_handle_t *hdl, const char *path) return (zhp); } -zfs_handle_t * +static zfs_handle_t * make_dataset_handle_zc(libzfs_handle_t *hdl, zfs_cmd_t *zc) { zfs_handle_t *zhp = calloc(sizeof (zfs_handle_t), 1); @@ -514,53 +510,6 @@ make_dataset_handle_zc(libzfs_handle_t *hdl, zfs_cmd_t *zc) return (zhp); } -zfs_handle_t * -zfs_handle_dup(zfs_handle_t *zhp_orig) -{ - zfs_handle_t *zhp = calloc(sizeof (zfs_handle_t), 1); - - if (zhp == NULL) - return (NULL); - - zhp->zfs_hdl = zhp_orig->zfs_hdl; - zhp->zpool_hdl = zhp_orig->zpool_hdl; - (void) strlcpy(zhp->zfs_name, zhp_orig->zfs_name, - sizeof (zhp->zfs_name)); - zhp->zfs_type = zhp_orig->zfs_type; - zhp->zfs_head_type = zhp_orig->zfs_head_type; - zhp->zfs_dmustats = zhp_orig->zfs_dmustats; - if (zhp_orig->zfs_props != NULL) { - if (nvlist_dup(zhp_orig->zfs_props, &zhp->zfs_props, 0) != 0) { - (void) no_memory(zhp->zfs_hdl); - zfs_close(zhp); - return (NULL); - } - } - if (zhp_orig->zfs_user_props != NULL) { - if (nvlist_dup(zhp_orig->zfs_user_props, - &zhp->zfs_user_props, 0) != 0) { - (void) no_memory(zhp->zfs_hdl); - zfs_close(zhp); - return (NULL); - } - } - if (zhp_orig->zfs_recvd_props != NULL) { - if (nvlist_dup(zhp_orig->zfs_recvd_props, - &zhp->zfs_recvd_props, 0)) { - (void) no_memory(zhp->zfs_hdl); - zfs_close(zhp); - return (NULL); - } - } - zhp->zfs_mntcheck = zhp_orig->zfs_mntcheck; - if (zhp_orig->zfs_mntopts != NULL) { - zhp->zfs_mntopts = zfs_strdup(zhp_orig->zfs_hdl, - zhp_orig->zfs_mntopts); - } - zhp->zfs_props_table = zhp_orig->zfs_props_table; - return (zhp); -} - /* * Opens the given snapshot, filesystem, or volume. The 'types' * argument is a mask of acceptable types. The function will print an @@ -924,12 +873,6 @@ zfs_valid_proplist(libzfs_handle_t *hdl, zfs_type_t type, nvlist_t *nvl, goto error; } continue; - } else if (prop == ZPROP_INVAL && zfs_prop_written(propname)) { - zfs_error_aux(hdl, dgettext(TEXT_DOMAIN, - "'%s' is readonly"), - propname); - (void) zfs_error(hdl, EZFS_PROPREADONLY, errbuf); - goto error; } if (prop == ZPROP_INVAL) { @@ -1407,7 +1350,8 @@ zfs_prop_set(zfs_handle_t *zhp, const char *propname, const char *propval) libzfs_handle_t *hdl = zhp->zfs_hdl; nvlist_t *nvl = NULL, *realprops; zfs_prop_t prop; - boolean_t do_prefix = B_TRUE; + boolean_t do_prefix; + uint64_t idx; int added_resv; (void) snprintf(errbuf, sizeof (errbuf), @@ -1446,17 +1390,12 @@ zfs_prop_set(zfs_handle_t *zhp, const char *propname, const char *propval) } /* - * We don't want to unmount & remount the dataset when changing - * its canmount property to 'on' or 'noauto'. We only use - * the changelist logic to unmount when setting canmount=off. + * If the dataset's canmount property is being set to noauto, + * then we want to prevent unmounting & remounting it. */ - if (prop == ZFS_PROP_CANMOUNT) { - uint64_t idx; - int err = zprop_string_to_index(prop, propval, &idx, - ZFS_TYPE_DATASET); - if (err == 0 && idx != ZFS_CANMOUNT_OFF) - do_prefix = B_FALSE; - } + do_prefix = !((prop == ZFS_PROP_CANMOUNT) && + (zprop_string_to_index(prop, propval, &idx, + ZFS_TYPE_DATASET) == 0) && (idx == ZFS_CANMOUNT_NOAUTO)); if (do_prefix && (ret = changelist_prefix(cl)) != 0) goto error; @@ -1907,6 +1846,8 @@ zfs_prop_get_recvd(zfs_handle_t *zhp, const char *propname, char *propbuf, err = zfs_prop_get(zhp, prop, propbuf, proplen, NULL, NULL, 0, literal); zfs_unset_recvd_props_mode(zhp, &cookie); + } else if (zfs_prop_userquota(propname)) { + return (-1); } else { nvlist_t *propval; char *recvdval; @@ -1921,120 +1862,6 @@ zfs_prop_get_recvd(zfs_handle_t *zhp, const char *propname, char *propbuf, return (err == 0 ? 0 : -1); } -static int -get_clones_string(zfs_handle_t *zhp, char *propbuf, size_t proplen) -{ - nvlist_t *value; - nvpair_t *pair; - - value = zfs_get_clones_nvl(zhp); - if (value == NULL) - return (-1); - - propbuf[0] = '\0'; - for (pair = nvlist_next_nvpair(value, NULL); pair != NULL; - pair = nvlist_next_nvpair(value, pair)) { - if (propbuf[0] != '\0') - (void) strlcat(propbuf, ",", proplen); - (void) strlcat(propbuf, nvpair_name(pair), proplen); - } - - return (0); -} - -struct get_clones_arg { - uint64_t numclones; - nvlist_t *value; - const char *origin; - char buf[ZFS_MAXNAMELEN]; -}; - -int -get_clones_cb(zfs_handle_t *zhp, void *arg) -{ - struct get_clones_arg *gca = arg; - - if (gca->numclones == 0) { - zfs_close(zhp); - return (0); - } - - if (zfs_prop_get(zhp, ZFS_PROP_ORIGIN, gca->buf, sizeof (gca->buf), - NULL, NULL, 0, B_TRUE) != 0) - goto out; - if (strcmp(gca->buf, gca->origin) == 0) { - if (nvlist_add_boolean(gca->value, zfs_get_name(zhp)) != 0) { - zfs_close(zhp); - return (no_memory(zhp->zfs_hdl)); - } - gca->numclones--; - } - -out: - (void) zfs_iter_children(zhp, get_clones_cb, gca); - zfs_close(zhp); - return (0); -} - -nvlist_t * -zfs_get_clones_nvl(zfs_handle_t *zhp) -{ - nvlist_t *nv, *value; - - if (nvlist_lookup_nvlist(zhp->zfs_props, - zfs_prop_to_name(ZFS_PROP_CLONES), &nv) != 0) { - struct get_clones_arg gca; - - /* - * if this is a snapshot, then the kernel wasn't able - * to get the clones. Do it by slowly iterating. - */ - if (zhp->zfs_type != ZFS_TYPE_SNAPSHOT) - return (NULL); - if (nvlist_alloc(&nv, NV_UNIQUE_NAME, 0) != 0) - return (NULL); - if (nvlist_alloc(&value, NV_UNIQUE_NAME, 0) != 0) { - nvlist_free(nv); - return (NULL); - } - - gca.numclones = zfs_prop_get_int(zhp, ZFS_PROP_NUMCLONES); - gca.value = value; - gca.origin = zhp->zfs_name; - - if (gca.numclones != 0) { - zfs_handle_t *root; - char pool[ZFS_MAXNAMELEN]; - char *cp = pool; - - /* get the pool name */ - (void) strlcpy(pool, zhp->zfs_name, sizeof (pool)); - (void) strsep(&cp, "/@"); - root = zfs_open(zhp->zfs_hdl, pool, - ZFS_TYPE_FILESYSTEM); - - (void) get_clones_cb(root, &gca); - } - - if (gca.numclones != 0 || - nvlist_add_nvlist(nv, ZPROP_VALUE, value) != 0 || - nvlist_add_nvlist(zhp->zfs_props, - zfs_prop_to_name(ZFS_PROP_CLONES), nv) != 0) { - nvlist_free(nv); - nvlist_free(value); - return (NULL); - } - nvlist_free(nv); - nvlist_free(value); - verify(0 == nvlist_lookup_nvlist(zhp->zfs_props, - zfs_prop_to_name(ZFS_PROP_CLONES), &nv)); - } - - verify(nvlist_lookup_nvlist(nv, ZPROP_VALUE, &value) == 0); - - return (value); -} - /* * Retrieve a property from the given object. If 'literal' is specified, then * numbers are left as exact values. Otherwise, numbers are converted to a @@ -2163,11 +1990,6 @@ zfs_prop_get(zfs_handle_t *zhp, zfs_prop_t prop, char *propbuf, size_t proplen, return (-1); break; - case ZFS_PROP_CLONES: - if (get_clones_string(zhp, propbuf, proplen) != 0) - return (-1); - break; - case ZFS_PROP_QUOTA: case ZFS_PROP_REFQUOTA: case ZFS_PROP_RESERVATION: @@ -2196,7 +2018,6 @@ zfs_prop_get(zfs_handle_t *zhp, zfs_prop_t prop, char *propbuf, size_t proplen, } break; - case ZFS_PROP_REFRATIO: case ZFS_PROP_COMPRESSRATIO: if (get_numeric_property(zhp, prop, src, &source, &val) != 0) return (-1); @@ -2285,17 +2106,6 @@ zfs_prop_get(zfs_handle_t *zhp, zfs_prop_t prop, char *propbuf, size_t proplen, } break; - case ZFS_PROP_GUID: - /* - * GUIDs are stored as numbers, but they are identifiers. - * We don't want them to be pretty printed, because pretty - * printing mangles the ID into a truncated and useless value. - */ - if (get_numeric_property(zhp, prop, src, &source, &val) != 0) - return (-1); - (void) snprintf(propbuf, proplen, "%llu", (u_longlong_t)val); - break; - default: switch (zfs_prop_get_type(prop)) { case PROP_TYPE_NUMBER: @@ -2539,7 +2349,7 @@ zfs_prop_get_userquota_common(zfs_handle_t *zhp, const char *propname, int err; zfs_cmd_t zc = { 0 }; - (void) strlcpy(zc.zc_name, zhp->zfs_name, sizeof (zc.zc_name)); + (void) strncpy(zc.zc_name, zhp->zfs_name, sizeof (zc.zc_name)); err = userquota_propname_decode(propname, zfs_prop_get_int(zhp, ZFS_PROP_ZONED), @@ -2591,76 +2401,144 @@ zfs_prop_get_userquota(zfs_handle_t *zhp, const char *propname, return (0); } -int -zfs_prop_get_written_int(zfs_handle_t *zhp, const char *propname, - uint64_t *propvalue) +/* + * Returns the name of the given zfs handle. + */ +const char * +zfs_get_name(const zfs_handle_t *zhp) { - int err; - zfs_cmd_t zc = { 0 }; - const char *snapname; + return (zhp->zfs_name); +} - (void) strlcpy(zc.zc_name, zhp->zfs_name, sizeof (zc.zc_name)); +/* + * Returns the type of the given zfs handle. + */ +zfs_type_t +zfs_get_type(const zfs_handle_t *zhp) +{ + return (zhp->zfs_type); +} - snapname = strchr(propname, '@') + 1; - if (strchr(snapname, '@')) { - (void) strlcpy(zc.zc_value, snapname, sizeof (zc.zc_value)); - } else { - /* snapname is the short name, append it to zhp's fsname */ - char *cp; - - (void) strlcpy(zc.zc_value, zhp->zfs_name, - sizeof (zc.zc_value)); - cp = strchr(zc.zc_value, '@'); - if (cp != NULL) - *cp = '\0'; - (void) strlcat(zc.zc_value, "@", sizeof (zc.zc_value)); - (void) strlcat(zc.zc_value, snapname, sizeof (zc.zc_value)); - } +static int +zfs_do_list_ioctl(zfs_handle_t *zhp, int arg, zfs_cmd_t *zc) +{ + int rc; + uint64_t orig_cookie; - err = ioctl(zhp->zfs_hdl->libzfs_fd, ZFS_IOC_SPACE_WRITTEN, &zc); - if (err) - return (err); + orig_cookie = zc->zc_cookie; +top: + (void) strlcpy(zc->zc_name, zhp->zfs_name, sizeof (zc->zc_name)); + rc = ioctl(zhp->zfs_hdl->libzfs_fd, arg, zc); - *propvalue = zc.zc_cookie; - return (0); + if (rc == -1) { + switch (errno) { + case ENOMEM: + /* expand nvlist memory and try again */ + if (zcmd_expand_dst_nvlist(zhp->zfs_hdl, zc) != 0) { + zcmd_free_nvlists(zc); + return (-1); + } + zc->zc_cookie = orig_cookie; + goto top; + /* + * An errno value of ESRCH indicates normal completion. + * If ENOENT is returned, then the underlying dataset + * has been removed since we obtained the handle. + */ + case ESRCH: + case ENOENT: + rc = 1; + break; + default: + rc = zfs_standard_error(zhp->zfs_hdl, errno, + dgettext(TEXT_DOMAIN, + "cannot iterate filesystems")); + break; + } + } + return (rc); } +/* + * Iterate over all child filesystems + */ int -zfs_prop_get_written(zfs_handle_t *zhp, const char *propname, - char *propbuf, int proplen, boolean_t literal) +zfs_iter_filesystems(zfs_handle_t *zhp, zfs_iter_f func, void *data) { - int err; - uint64_t propvalue; + zfs_cmd_t zc = { 0 }; + zfs_handle_t *nzhp; + int ret; - err = zfs_prop_get_written_int(zhp, propname, &propvalue); + if (zhp->zfs_type != ZFS_TYPE_FILESYSTEM) + return (0); - if (err) - return (err); + if (zcmd_alloc_dst_nvlist(zhp->zfs_hdl, &zc, 0) != 0) + return (-1); - if (literal) { - (void) snprintf(propbuf, proplen, "%llu", propvalue); - } else { - zfs_nicenum(propvalue, propbuf, proplen); + while ((ret = zfs_do_list_ioctl(zhp, ZFS_IOC_DATASET_LIST_NEXT, + &zc)) == 0) { + /* + * Silently ignore errors, as the only plausible explanation is + * that the pool has since been removed. + */ + if ((nzhp = make_dataset_handle_zc(zhp->zfs_hdl, + &zc)) == NULL) { + continue; + } + + if ((ret = func(nzhp, data)) != 0) { + zcmd_free_nvlists(&zc); + return (ret); + } } - return (0); + zcmd_free_nvlists(&zc); + return ((ret < 0) ? ret : 0); } /* - * Returns the name of the given zfs handle. + * Iterate over all snapshots */ -const char * -zfs_get_name(const zfs_handle_t *zhp) +int +zfs_iter_snapshots(zfs_handle_t *zhp, zfs_iter_f func, void *data) { - return (zhp->zfs_name); + zfs_cmd_t zc = { 0 }; + zfs_handle_t *nzhp; + int ret; + + if (zhp->zfs_type == ZFS_TYPE_SNAPSHOT) + return (0); + + if (zcmd_alloc_dst_nvlist(zhp->zfs_hdl, &zc, 0) != 0) + return (-1); + while ((ret = zfs_do_list_ioctl(zhp, ZFS_IOC_SNAPSHOT_LIST_NEXT, + &zc)) == 0) { + + if ((nzhp = make_dataset_handle_zc(zhp->zfs_hdl, + &zc)) == NULL) { + continue; + } + + if ((ret = func(nzhp, data)) != 0) { + zcmd_free_nvlists(&zc); + return (ret); + } + } + zcmd_free_nvlists(&zc); + return ((ret < 0) ? ret : 0); } /* - * Returns the type of the given zfs handle. + * Iterate over all children, snapshots and filesystems */ -zfs_type_t -zfs_get_type(const zfs_handle_t *zhp) +int +zfs_iter_children(zfs_handle_t *zhp, zfs_iter_f func, void *data) { - return (zhp->zfs_type); + int ret; + + if ((ret = zfs_iter_filesystems(zhp, func, data)) != 0) + return (ret); + + return (zfs_iter_snapshots(zhp, func, data)); } /* @@ -2686,19 +2564,18 @@ is_descendant(const char *ds1, const char *ds2) /* * Given a complete name, return just the portion that refers to the parent. - * Will return -1 if there is no parent (path is just the name of the - * pool). + * Can return NULL if this is a pool. */ static int parent_name(const char *path, char *buf, size_t buflen) { - char *slashp; - - (void) strlcpy(buf, path, buflen); + char *loc; - if ((slashp = strrchr(buf, '/')) == NULL) + if ((loc = strrchr(path, '/')) == NULL) return (-1); - *slashp = '\0'; + + (void) strncpy(buf, path, MIN(buflen, loc - path)); + buf[loc - path] = '\0'; return (0); } @@ -2845,6 +2722,7 @@ create_parents(libzfs_handle_t *hdl, char *target, int prefixlen) */ for (cp = target + prefixlen + 1; cp = strchr(cp, '/'); *cp = '/', cp++) { + char *logstr; *cp = '\0'; @@ -2855,12 +2733,16 @@ create_parents(libzfs_handle_t *hdl, char *target, int prefixlen) continue; } + logstr = hdl->libzfs_log_str; + hdl->libzfs_log_str = NULL; if (zfs_create(hdl, target, ZFS_TYPE_FILESYSTEM, NULL) != 0) { + hdl->libzfs_log_str = logstr; opname = dgettext(TEXT_DOMAIN, "create"); goto ancestorerr; } + hdl->libzfs_log_str = logstr; h = zfs_open(hdl, target, ZFS_TYPE_FILESYSTEM); if (h == NULL) { opname = dgettext(TEXT_DOMAIN, "open"); @@ -2918,12 +2800,12 @@ int zfs_create(libzfs_handle_t *hdl, const char *path, zfs_type_t type, nvlist_t *props) { + zfs_cmd_t zc = { 0 }; int ret; uint64_t size = 0; uint64_t blocksize = zfs_prop_default_numeric(ZFS_PROP_VOLBLOCKSIZE); char errbuf[1024]; uint64_t zoned; - dmu_objset_type_t ost; (void) snprintf(errbuf, sizeof (errbuf), dgettext(TEXT_DOMAIN, "cannot create '%s'"), path); @@ -2943,16 +2825,17 @@ zfs_create(libzfs_handle_t *hdl, const char *path, zfs_type_t type, * will return ENOENT, not EEXIST. To prevent this from happening, we * first try to see if the dataset exists. */ - if (zfs_dataset_exists(hdl, path, ZFS_TYPE_DATASET)) { + (void) strlcpy(zc.zc_name, path, sizeof (zc.zc_name)); + if (zfs_dataset_exists(hdl, zc.zc_name, ZFS_TYPE_DATASET)) { zfs_error_aux(hdl, dgettext(TEXT_DOMAIN, "dataset already exists")); return (zfs_error(hdl, EZFS_EXISTS, errbuf)); } if (type == ZFS_TYPE_VOLUME) - ost = DMU_OST_ZVOL; + zc.zc_objset_type = DMU_OST_ZVOL; else - ost = DMU_OST_ZFS; + zc.zc_objset_type = DMU_OST_ZFS; if (props && (props = zfs_valid_proplist(hdl, type, props, zoned, NULL, errbuf)) == 0) @@ -3004,10 +2887,15 @@ zfs_create(libzfs_handle_t *hdl, const char *path, zfs_type_t type, } } - /* create the dataset */ - ret = lzc_create(path, ost, props); + if (props && zcmd_write_src_nvlist(hdl, &zc, props) != 0) + return (-1); nvlist_free(props); + /* create the dataset */ + ret = zfs_ioctl(hdl, ZFS_IOC_CREATE, &zc); + + zcmd_free_nvlists(&zc); + /* check for failure */ if (ret != 0) { char parent[ZFS_MAXNAMELEN]; @@ -3058,8 +2946,7 @@ 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 - * isn't mounted, and that there are no active dependents. If the file system - * does not exist this function does nothing. + * isn't mounted, and that there are no active dependents. */ int zfs_destroy(zfs_handle_t *zhp, boolean_t defer) @@ -3075,8 +2962,7 @@ zfs_destroy(zfs_handle_t *zhp, boolean_t defer) } zc.zc_defer_destroy = defer; - if (zfs_ioctl(zhp->zfs_hdl, ZFS_IOC_DESTROY, &zc) != 0 && - errno != ENOENT) { + if (zfs_ioctl(zhp->zfs_hdl, ZFS_IOC_DESTROY, &zc) != 0) { return (zfs_standard_error_fmt(zhp->zfs_hdl, errno, dgettext(TEXT_DOMAIN, "cannot destroy '%s'"), zhp->zfs_name)); @@ -3088,8 +2974,9 @@ zfs_destroy(zfs_handle_t *zhp, boolean_t defer) } struct destroydata { - nvlist_t *nvl; - const char *snapname; + char *snapname; + boolean_t gotone; + boolean_t closezhp; }; static int @@ -3098,19 +2985,24 @@ zfs_check_snap_cb(zfs_handle_t *zhp, void *arg) struct destroydata *dd = arg; zfs_handle_t *szhp; char name[ZFS_MAXNAMELEN]; + boolean_t closezhp = dd->closezhp; int rv = 0; - (void) snprintf(name, sizeof (name), - "%s@%s", zhp->zfs_name, dd->snapname); + (void) strlcpy(name, zhp->zfs_name, sizeof (name)); + (void) strlcat(name, "@", sizeof (name)); + (void) strlcat(name, dd->snapname, sizeof (name)); szhp = make_dataset_handle(zhp->zfs_hdl, name); if (szhp) { - verify(nvlist_add_boolean(dd->nvl, name) == 0); + dd->gotone = B_TRUE; zfs_close(szhp); } - rv = zfs_iter_filesystems(zhp, zfs_check_snap_cb, dd); - zfs_close(zhp); + dd->closezhp = B_TRUE; + if (!dd->gotone) + rv = zfs_iter_filesystems(zhp, zfs_check_snap_cb, arg); + if (closezhp) + zfs_close(zhp); return (rv); } @@ -3120,61 +3012,43 @@ zfs_check_snap_cb(zfs_handle_t *zhp, void *arg) int zfs_destroy_snaps(zfs_handle_t *zhp, char *snapname, boolean_t defer) { + zfs_cmd_t zc = { 0 }; int ret; struct destroydata dd = { 0 }; dd.snapname = snapname; - verify(nvlist_alloc(&dd.nvl, NV_UNIQUE_NAME, 0) == 0); - (void) zfs_check_snap_cb(zfs_handle_dup(zhp), &dd); + (void) zfs_check_snap_cb(zhp, &dd); - if (nvlist_next_nvpair(dd.nvl, NULL) == NULL) { - ret = zfs_standard_error_fmt(zhp->zfs_hdl, ENOENT, + if (!dd.gotone) { + return (zfs_standard_error_fmt(zhp->zfs_hdl, ENOENT, dgettext(TEXT_DOMAIN, "cannot destroy '%s@%s'"), - zhp->zfs_name, snapname); - } else { - ret = zfs_destroy_snaps_nvl(zhp, dd.nvl, defer); + zhp->zfs_name, snapname)); } - nvlist_free(dd.nvl); - return (ret); -} -/* - * Destroys all the snapshots named in the nvlist. They must be underneath - * the zhp (either snapshots of it, or snapshots of its descendants). - */ -int -zfs_destroy_snaps_nvl(zfs_handle_t *zhp, nvlist_t *snaps, boolean_t defer) -{ - int ret; - nvlist_t *errlist; - - ret = lzc_destroy_snaps(snaps, defer, &errlist); + (void) strlcpy(zc.zc_name, zhp->zfs_name, sizeof (zc.zc_name)); + (void) strlcpy(zc.zc_value, snapname, sizeof (zc.zc_value)); + zc.zc_defer_destroy = defer; + ret = zfs_ioctl(zhp->zfs_hdl, ZFS_IOC_DESTROY_SNAPS, &zc); if (ret != 0) { - 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)); - - switch (fnvpair_value_int32(pair)) { - case EEXIST: - zfs_error_aux(zhp->zfs_hdl, - dgettext(TEXT_DOMAIN, - "snapshot is cloned")); - ret = zfs_error(zhp->zfs_hdl, EZFS_EXISTS, - errbuf); - break; - default: - ret = zfs_standard_error(zhp->zfs_hdl, errno, - errbuf); - break; - } + char errbuf[1024]; + + (void) snprintf(errbuf, sizeof (errbuf), dgettext(TEXT_DOMAIN, + "cannot destroy '%s@%s'"), zc.zc_name, snapname); + + switch (errno) { + case EEXIST: + zfs_error_aux(zhp->zfs_hdl, dgettext(TEXT_DOMAIN, + "snapshot is cloned")); + return (zfs_error(zhp->zfs_hdl, EZFS_EXISTS, errbuf)); + + default: + return (zfs_standard_error(zhp->zfs_hdl, errno, + errbuf)); } } - return (ret); + return (0); } /* @@ -3183,10 +3057,12 @@ zfs_destroy_snaps_nvl(zfs_handle_t *zhp, nvlist_t *snaps, boolean_t defer) int zfs_clone(zfs_handle_t *zhp, const char *target, nvlist_t *props) { + zfs_cmd_t zc = { 0 }; char parent[ZFS_MAXNAMELEN]; int ret; char errbuf[1024]; libzfs_handle_t *hdl = zhp->zfs_hdl; + zfs_type_t type; uint64_t zoned; assert(zhp->zfs_type == ZFS_TYPE_SNAPSHOT); @@ -3194,7 +3070,7 @@ zfs_clone(zfs_handle_t *zhp, const char *target, nvlist_t *props) (void) snprintf(errbuf, sizeof (errbuf), dgettext(TEXT_DOMAIN, "cannot create '%s'"), target); - /* validate the target/clone name */ + /* validate the target name */ if (!zfs_validate_name(hdl, target, ZFS_TYPE_FILESYSTEM, B_TRUE)) return (zfs_error(hdl, EZFS_INVALIDNAME, errbuf)); @@ -3205,21 +3081,32 @@ zfs_clone(zfs_handle_t *zhp, const char *target, nvlist_t *props) (void) parent_name(target, parent, sizeof (parent)); /* 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) { - 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, zhp, errbuf)) == NULL) return (-1); + + if (zcmd_write_src_nvlist(hdl, &zc, props) != 0) { + nvlist_free(props); + return (-1); + } + + nvlist_free(props); } - ret = lzc_clone(target, zhp->zfs_name, props); - nvlist_free(props); + (void) strlcpy(zc.zc_name, target, sizeof (zc.zc_name)); + (void) strlcpy(zc.zc_value, zhp->zfs_name, sizeof (zc.zc_value)); + ret = zfs_ioctl(zhp->zfs_hdl, ZFS_IOC_CREATE, &zc); + + zcmd_free_nvlists(&zc); if (ret != 0) { switch (errno) { @@ -3304,134 +3191,74 @@ zfs_promote(zfs_handle_t *zhp) 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); -} - /* - * Creates snapshots. The keys in the snaps nvlist are the snapshots to be - * created. + * Takes a snapshot of the given dataset. */ int -zfs_snapshot_nvl(libzfs_handle_t *hdl, nvlist_t *snaps, nvlist_t *props) +zfs_snapshot(libzfs_handle_t *hdl, const char *path, boolean_t recursive, + nvlist_t *props) { + const char *delim; + char parent[ZFS_MAXNAMELEN]; + zfs_handle_t *zhp; + zfs_cmd_t zc = { 0 }; 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); + "cannot snapshot '%s'"), path); - /* 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); - } + /* validate the target name */ + if (!zfs_validate_name(hdl, path, ZFS_TYPE_SNAPSHOT, B_TRUE)) + return (zfs_error(hdl, EZFS_INVALIDNAME, errbuf)); - ret = lzc_snapshot(snaps, props, &errors); + if (props) { + if ((props = zfs_valid_proplist(hdl, ZFS_TYPE_SNAPSHOT, + props, B_FALSE, NULL, errbuf)) == NULL) + return (-1); - 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 (zcmd_write_src_nvlist(hdl, &zc, props) != 0) { + nvlist_free(props); + return (-1); } - 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(props); - nvlist_free(errors); - return (ret); -} - -int -zfs_snapshot(libzfs_handle_t *hdl, const char *path, boolean_t recursive, - nvlist_t *props) -{ - int ret; - snapdata_t sd = { 0 }; - char fsname[ZFS_MAXNAMELEN]; - char *cp; - zfs_handle_t *zhp; - char errbuf[1024]; - - (void) snprintf(errbuf, sizeof (errbuf), dgettext(TEXT_DOMAIN, - "cannot snapshot %s"), path); - - if (!zfs_validate_name(hdl, path, ZFS_TYPE_SNAPSHOT, B_TRUE)) - return (zfs_error(hdl, EZFS_INVALIDNAME, errbuf)); - - (void) strlcpy(fsname, path, sizeof (fsname)); - cp = strchr(fsname, '@'); - *cp = '\0'; - sd.sd_snapname = cp + 1; + /* 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, fsname, ZFS_TYPE_FILESYSTEM | + if ((zhp = zfs_open(hdl, parent, ZFS_TYPE_FILESYSTEM | ZFS_TYPE_VOLUME)) == NULL) { + zcmd_free_nvlists(&zc); return (-1); } - verify(nvlist_alloc(&sd.sd_nvl, NV_UNIQUE_NAME, 0) == 0); - if (recursive) { - (void) zfs_snapshot_cb(zfs_handle_dup(zhp), &sd); - } else { - fnvlist_add_boolean(sd.sd_nvl, path); + (void) strlcpy(zc.zc_name, zhp->zfs_name, sizeof (zc.zc_name)); + (void) strlcpy(zc.zc_value, delim+1, sizeof (zc.zc_value)); + if (ZFS_IS_VOLUME(zhp)) + zc.zc_objset_type = DMU_OST_ZVOL; + else + 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); + return (ret); } @@ -3459,13 +3286,17 @@ rollback_destroy(zfs_handle_t *zhp, void *data) zfs_get_type(zhp) == ZFS_TYPE_SNAPSHOT && zfs_prop_get_int(zhp, ZFS_PROP_CREATETXG) > cbp->cb_create) { + char *logstr; cbp->cb_dependent = B_TRUE; cbp->cb_error |= zfs_iter_dependents(zhp, B_FALSE, rollback_destroy, cbp); 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); + zhp->zfs_hdl->libzfs_log_str = logstr; } } else { /* We must destroy this clone; first unmount it */ @@ -3576,11 +3407,46 @@ zfs_rollback(zfs_handle_t *zhp, zfs_handle_t *snap, boolean_t force) } /* + * Iterate over all dependents for a given dataset. This includes both + * hierarchical dependents (children) and data dependents (snapshots and + * clones). The bulk of the processing occurs in get_dependents() in + * libzfs_graph.c. + */ +int +zfs_iter_dependents(zfs_handle_t *zhp, boolean_t allowrecursion, + zfs_iter_f func, void *data) +{ + char **dependents; + size_t count; + int i; + zfs_handle_t *child; + int ret = 0; + + if (get_dependents(zhp->zfs_hdl, allowrecursion, zhp->zfs_name, + &dependents, &count) != 0) + return (-1); + + for (i = 0; i < count; i++) { + if ((child = make_dataset_handle(zhp->zfs_hdl, + dependents[i])) == NULL) + continue; + + if ((ret = func(child, data)) != 0) + break; + } + + for (i = 0; i < count; i++) + free(dependents[i]); + free(dependents); + + return (ret); +} + +/* * Renames the given dataset. */ int -zfs_rename(zfs_handle_t *zhp, const char *target, boolean_t recursive, - boolean_t force_unmount) +zfs_rename(zfs_handle_t *zhp, const char *target, boolean_t recursive) { int ret; zfs_cmd_t zc = { 0 }; @@ -3692,8 +3558,7 @@ zfs_rename(zfs_handle_t *zhp, const char *target, boolean_t recursive, } } else { - if ((cl = changelist_gather(zhp, ZFS_PROP_NAME, 0, - force_unmount ? MS_FORCE : 0)) == NULL) + if ((cl = changelist_gather(zhp, ZFS_PROP_NAME, 0, 0)) == NULL) return (-1); if (changelist_haszonedchild(cl)) { @@ -4026,7 +3891,7 @@ zfs_userspace(zfs_handle_t *zhp, zfs_userquota_prop_t type, int error; zfs_useracct_t buf[100]; - (void) strlcpy(zc.zc_name, zhp->zfs_name, sizeof (zc.zc_name)); + (void) strncpy(zc.zc_name, zhp->zfs_name, sizeof (zc.zc_name)); zc.zc_objset_type = type; zc.zc_nvlist_dst = (uintptr_t)buf; @@ -4154,193 +4019,6 @@ zfs_release(zfs_handle_t *zhp, const char *snapname, const char *tag, return (0); } -int -zfs_get_fsacl(zfs_handle_t *zhp, nvlist_t **nvl) -{ - zfs_cmd_t zc = { 0 }; - libzfs_handle_t *hdl = zhp->zfs_hdl; - int nvsz = 2048; - void *nvbuf; - int err = 0; - char errbuf[ZFS_MAXNAMELEN+32]; - - assert(zhp->zfs_type == ZFS_TYPE_VOLUME || - zhp->zfs_type == ZFS_TYPE_FILESYSTEM); - -tryagain: - - nvbuf = malloc(nvsz); - if (nvbuf == NULL) { - err = (zfs_error(hdl, EZFS_NOMEM, strerror(errno))); - goto out; - } - - zc.zc_nvlist_dst_size = nvsz; - zc.zc_nvlist_dst = (uintptr_t)nvbuf; - - (void) strlcpy(zc.zc_name, zhp->zfs_name, ZFS_MAXNAMELEN); - - if (ioctl(hdl->libzfs_fd, ZFS_IOC_GET_FSACL, &zc) != 0) { - (void) snprintf(errbuf, sizeof (errbuf), - dgettext(TEXT_DOMAIN, "cannot get permissions on '%s'"), - zc.zc_name); - switch (errno) { - case ENOMEM: - free(nvbuf); - nvsz = zc.zc_nvlist_dst_size; - goto tryagain; - - case ENOTSUP: - zfs_error_aux(hdl, dgettext(TEXT_DOMAIN, - "pool must be upgraded")); - err = zfs_error(hdl, EZFS_BADVERSION, errbuf); - break; - case EINVAL: - err = zfs_error(hdl, EZFS_BADTYPE, errbuf); - break; - case ENOENT: - err = zfs_error(hdl, EZFS_NOENT, errbuf); - break; - default: - err = zfs_standard_error_fmt(hdl, errno, errbuf); - break; - } - } else { - /* success */ - int rc = nvlist_unpack(nvbuf, zc.zc_nvlist_dst_size, nvl, 0); - if (rc) { - (void) snprintf(errbuf, sizeof (errbuf), dgettext( - TEXT_DOMAIN, "cannot get permissions on '%s'"), - zc.zc_name); - err = zfs_standard_error_fmt(hdl, rc, errbuf); - } - } - - free(nvbuf); -out: - return (err); -} - -int -zfs_set_fsacl(zfs_handle_t *zhp, boolean_t un, nvlist_t *nvl) -{ - zfs_cmd_t zc = { 0 }; - libzfs_handle_t *hdl = zhp->zfs_hdl; - char *nvbuf; - char errbuf[ZFS_MAXNAMELEN+32]; - size_t nvsz; - int err; - - assert(zhp->zfs_type == ZFS_TYPE_VOLUME || - zhp->zfs_type == ZFS_TYPE_FILESYSTEM); - - err = nvlist_size(nvl, &nvsz, NV_ENCODE_NATIVE); - assert(err == 0); - - nvbuf = malloc(nvsz); - - err = nvlist_pack(nvl, &nvbuf, &nvsz, NV_ENCODE_NATIVE, 0); - assert(err == 0); - - zc.zc_nvlist_src_size = nvsz; - zc.zc_nvlist_src = (uintptr_t)nvbuf; - zc.zc_perm_action = un; - - (void) strlcpy(zc.zc_name, zhp->zfs_name, sizeof (zc.zc_name)); - - if (zfs_ioctl(hdl, ZFS_IOC_SET_FSACL, &zc) != 0) { - (void) snprintf(errbuf, sizeof (errbuf), - dgettext(TEXT_DOMAIN, "cannot set permissions on '%s'"), - zc.zc_name); - switch (errno) { - case ENOTSUP: - zfs_error_aux(hdl, dgettext(TEXT_DOMAIN, - "pool must be upgraded")); - err = zfs_error(hdl, EZFS_BADVERSION, errbuf); - break; - case EINVAL: - err = zfs_error(hdl, EZFS_BADTYPE, errbuf); - break; - case ENOENT: - err = zfs_error(hdl, EZFS_NOENT, errbuf); - break; - default: - err = zfs_standard_error_fmt(hdl, errno, errbuf); - break; - } - } - - free(nvbuf); - - return (err); -} - -int -zfs_get_holds(zfs_handle_t *zhp, nvlist_t **nvl) -{ - zfs_cmd_t zc = { 0 }; - libzfs_handle_t *hdl = zhp->zfs_hdl; - int nvsz = 2048; - void *nvbuf; - int err = 0; - char errbuf[ZFS_MAXNAMELEN+32]; - - assert(zhp->zfs_type == ZFS_TYPE_SNAPSHOT); - -tryagain: - - nvbuf = malloc(nvsz); - if (nvbuf == NULL) { - err = (zfs_error(hdl, EZFS_NOMEM, strerror(errno))); - goto out; - } - - zc.zc_nvlist_dst_size = nvsz; - zc.zc_nvlist_dst = (uintptr_t)nvbuf; - - (void) strlcpy(zc.zc_name, zhp->zfs_name, ZFS_MAXNAMELEN); - - if (zfs_ioctl(hdl, ZFS_IOC_GET_HOLDS, &zc) != 0) { - (void) snprintf(errbuf, sizeof (errbuf), - dgettext(TEXT_DOMAIN, "cannot get holds for '%s'"), - zc.zc_name); - switch (errno) { - case ENOMEM: - free(nvbuf); - nvsz = zc.zc_nvlist_dst_size; - goto tryagain; - - case ENOTSUP: - zfs_error_aux(hdl, dgettext(TEXT_DOMAIN, - "pool must be upgraded")); - err = zfs_error(hdl, EZFS_BADVERSION, errbuf); - break; - case EINVAL: - err = zfs_error(hdl, EZFS_BADTYPE, errbuf); - break; - case ENOENT: - err = zfs_error(hdl, EZFS_NOENT, errbuf); - break; - default: - err = zfs_standard_error_fmt(hdl, errno, errbuf); - break; - } - } else { - /* success */ - int rc = nvlist_unpack(nvbuf, zc.zc_nvlist_dst_size, nvl, 0); - if (rc) { - (void) snprintf(errbuf, sizeof (errbuf), - dgettext(TEXT_DOMAIN, "cannot get holds for '%s'"), - zc.zc_name); - err = zfs_standard_error_fmt(hdl, rc, errbuf); - } - } - - free(nvbuf); -out: - return (err); -} - uint64_t zvol_volsize_to_reservation(uint64_t volsize, nvlist_t *props) { diff --git a/lib/libzfs/common/libzfs_graph.c b/lib/libzfs/common/libzfs_graph.c new file mode 100644 index 000000000000..bc21c51ae26c --- /dev/null +++ b/lib/libzfs/common/libzfs_graph.c @@ -0,0 +1,653 @@ +/* + * 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 2009 Sun Microsystems, Inc. All rights reserved. + * Use is subject to license terms. + */ + +/* + * Iterate over all children of the current object. This includes the normal + * dataset hierarchy, but also arbitrary hierarchies due to clones. We want to + * walk all datasets in the pool, and construct a directed graph of the form: + * + * home + * | + * +----+----+ + * | | + * v v ws + * bar baz | + * | | + * v v + * @yesterday ----> foo + * + * In order to construct this graph, we have to walk every dataset in the pool, + * because the clone parent is stored as a property of the child, not the + * parent. The parent only keeps track of the number of clones. + * + * In the normal case (without clones) this would be rather expensive. To avoid + * unnecessary computation, we first try a walk of the subtree hierarchy + * starting from the initial node. At each dataset, we construct a node in the + * graph and an edge leading from its parent. If we don't see any snapshots + * with a non-zero clone count, then we are finished. + * + * If we do find a cloned snapshot, then we finish the walk of the current + * subtree, but indicate that we need to do a complete walk. We then perform a + * global walk of all datasets, avoiding the subtree we already processed. + * + * At the end of this, we'll end up with a directed graph of all relevant (and + * possible some irrelevant) datasets in the system. We need to both find our + * limiting subgraph and determine a safe ordering in which to destroy the + * datasets. We do a topological ordering of our graph starting at our target + * dataset, and then walk the results in reverse. + * + * It's possible for the graph to have cycles if, for example, the user renames + * a clone to be the parent of its origin snapshot. The user can request to + * generate an error in this case, or ignore the cycle and continue. + * + * When removing datasets, we want to destroy the snapshots in chronological + * order (because this is the most efficient method). In order to accomplish + * this, we store the creation transaction group with each vertex and keep each + * vertex's edges sorted according to this value. The topological sort will + * automatically walk the snapshots in the correct order. + */ + +#include <assert.h> +#include <libintl.h> +#include <stdio.h> +#include <stdlib.h> +#include <string.h> +#include <strings.h> +#include <unistd.h> + +#include <libzfs.h> + +#include "libzfs_impl.h" +#include "zfs_namecheck.h" + +#define MIN_EDGECOUNT 4 + +/* + * Vertex structure. Indexed by dataset name, this structure maintains a list + * of edges to other vertices. + */ +struct zfs_edge; +typedef struct zfs_vertex { + char zv_dataset[ZFS_MAXNAMELEN]; + struct zfs_vertex *zv_next; + int zv_visited; + uint64_t zv_txg; + struct zfs_edge **zv_edges; + int zv_edgecount; + int zv_edgealloc; +} zfs_vertex_t; + +enum { + VISIT_SEEN = 1, + VISIT_SORT_PRE, + VISIT_SORT_POST +}; + +/* + * Edge structure. Simply maintains a pointer to the destination vertex. There + * is no need to store the source vertex, since we only use edges in the context + * of the source vertex. + */ +typedef struct zfs_edge { + zfs_vertex_t *ze_dest; + struct zfs_edge *ze_next; +} zfs_edge_t; + +#define ZFS_GRAPH_SIZE 1027 /* this could be dynamic some day */ + +/* + * Graph structure. Vertices are maintained in a hash indexed by dataset name. + */ +typedef struct zfs_graph { + zfs_vertex_t **zg_hash; + size_t zg_size; + size_t zg_nvertex; + const char *zg_root; + int zg_clone_count; +} zfs_graph_t; + +/* + * Allocate a new edge pointing to the target vertex. + */ +static zfs_edge_t * +zfs_edge_create(libzfs_handle_t *hdl, zfs_vertex_t *dest) +{ + zfs_edge_t *zep = zfs_alloc(hdl, sizeof (zfs_edge_t)); + + if (zep == NULL) + return (NULL); + + zep->ze_dest = dest; + + return (zep); +} + +/* + * Destroy an edge. + */ +static void +zfs_edge_destroy(zfs_edge_t *zep) +{ + free(zep); +} + +/* + * Allocate a new vertex with the given name. + */ +static zfs_vertex_t * +zfs_vertex_create(libzfs_handle_t *hdl, const char *dataset) +{ + zfs_vertex_t *zvp = zfs_alloc(hdl, sizeof (zfs_vertex_t)); + + if (zvp == NULL) + return (NULL); + + assert(strlen(dataset) < ZFS_MAXNAMELEN); + + (void) strlcpy(zvp->zv_dataset, dataset, sizeof (zvp->zv_dataset)); + + if ((zvp->zv_edges = zfs_alloc(hdl, + MIN_EDGECOUNT * sizeof (void *))) == NULL) { + free(zvp); + return (NULL); + } + + zvp->zv_edgealloc = MIN_EDGECOUNT; + + return (zvp); +} + +/* + * Destroy a vertex. Frees up any associated edges. + */ +static void +zfs_vertex_destroy(zfs_vertex_t *zvp) +{ + int i; + + for (i = 0; i < zvp->zv_edgecount; i++) + zfs_edge_destroy(zvp->zv_edges[i]); + + free(zvp->zv_edges); + free(zvp); +} + +/* + * Given a vertex, add an edge to the destination vertex. + */ +static int +zfs_vertex_add_edge(libzfs_handle_t *hdl, zfs_vertex_t *zvp, + zfs_vertex_t *dest) +{ + zfs_edge_t *zep = zfs_edge_create(hdl, dest); + + if (zep == NULL) + return (-1); + + if (zvp->zv_edgecount == zvp->zv_edgealloc) { + void *ptr; + + if ((ptr = zfs_realloc(hdl, zvp->zv_edges, + zvp->zv_edgealloc * sizeof (void *), + zvp->zv_edgealloc * 2 * sizeof (void *))) == NULL) + return (-1); + + zvp->zv_edges = ptr; + zvp->zv_edgealloc *= 2; + } + + zvp->zv_edges[zvp->zv_edgecount++] = zep; + + return (0); +} + +static int +zfs_edge_compare(const void *a, const void *b) +{ + const zfs_edge_t *ea = *((zfs_edge_t **)a); + const zfs_edge_t *eb = *((zfs_edge_t **)b); + + if (ea->ze_dest->zv_txg < eb->ze_dest->zv_txg) + return (-1); + if (ea->ze_dest->zv_txg > eb->ze_dest->zv_txg) + return (1); + return (0); +} + +/* + * Sort the given vertex edges according to the creation txg of each vertex. + */ +static void +zfs_vertex_sort_edges(zfs_vertex_t *zvp) +{ + if (zvp->zv_edgecount == 0) + return; + + qsort(zvp->zv_edges, zvp->zv_edgecount, sizeof (void *), + zfs_edge_compare); +} + +/* + * Construct a new graph object. We allow the size to be specified as a + * parameter so in the future we can size the hash according to the number of + * datasets in the pool. + */ +static zfs_graph_t * +zfs_graph_create(libzfs_handle_t *hdl, const char *dataset, size_t size) +{ + zfs_graph_t *zgp = zfs_alloc(hdl, sizeof (zfs_graph_t)); + + if (zgp == NULL) + return (NULL); + + zgp->zg_size = size; + if ((zgp->zg_hash = zfs_alloc(hdl, + size * sizeof (zfs_vertex_t *))) == NULL) { + free(zgp); + return (NULL); + } + + zgp->zg_root = dataset; + zgp->zg_clone_count = 0; + + return (zgp); +} + +/* + * Destroy a graph object. We have to iterate over all the hash chains, + * destroying each vertex in the process. + */ +static void +zfs_graph_destroy(zfs_graph_t *zgp) +{ + int i; + zfs_vertex_t *current, *next; + + for (i = 0; i < zgp->zg_size; i++) { + current = zgp->zg_hash[i]; + while (current != NULL) { + next = current->zv_next; + zfs_vertex_destroy(current); + current = next; + } + } + + free(zgp->zg_hash); + free(zgp); +} + +/* + * Graph hash function. Classic bernstein k=33 hash function, taken from + * usr/src/cmd/sgs/tools/common/strhash.c + */ +static size_t +zfs_graph_hash(zfs_graph_t *zgp, const char *str) +{ + size_t hash = 5381; + int c; + + while ((c = *str++) != 0) + hash = ((hash << 5) + hash) + c; /* hash * 33 + c */ + + return (hash % zgp->zg_size); +} + +/* + * Given a dataset name, finds the associated vertex, creating it if necessary. + */ +static zfs_vertex_t * +zfs_graph_lookup(libzfs_handle_t *hdl, zfs_graph_t *zgp, const char *dataset, + uint64_t txg) +{ + size_t idx = zfs_graph_hash(zgp, dataset); + zfs_vertex_t *zvp; + + for (zvp = zgp->zg_hash[idx]; zvp != NULL; zvp = zvp->zv_next) { + if (strcmp(zvp->zv_dataset, dataset) == 0) { + if (zvp->zv_txg == 0) + zvp->zv_txg = txg; + return (zvp); + } + } + + if ((zvp = zfs_vertex_create(hdl, dataset)) == NULL) + return (NULL); + + zvp->zv_next = zgp->zg_hash[idx]; + zvp->zv_txg = txg; + zgp->zg_hash[idx] = zvp; + zgp->zg_nvertex++; + + return (zvp); +} + +/* + * Given two dataset names, create an edge between them. For the source vertex, + * mark 'zv_visited' to indicate that we have seen this vertex, and not simply + * created it as a destination of another edge. If 'dest' is NULL, then this + * is an individual vertex (i.e. the starting vertex), so don't add an edge. + */ +static int +zfs_graph_add(libzfs_handle_t *hdl, zfs_graph_t *zgp, const char *source, + const char *dest, uint64_t txg) +{ + zfs_vertex_t *svp, *dvp; + + if ((svp = zfs_graph_lookup(hdl, zgp, source, 0)) == NULL) + return (-1); + svp->zv_visited = VISIT_SEEN; + if (dest != NULL) { + dvp = zfs_graph_lookup(hdl, zgp, dest, txg); + if (dvp == NULL) + return (-1); + if (zfs_vertex_add_edge(hdl, svp, dvp) != 0) + return (-1); + } + + return (0); +} + +/* + * Iterate over all children of the given dataset, adding any vertices + * as necessary. Returns -1 if there was an error, or 0 otherwise. + * This is a simple recursive algorithm - the ZFS namespace typically + * is very flat. We manually invoke the necessary ioctl() calls to + * avoid the overhead and additional semantics of zfs_open(). + */ +static int +iterate_children(libzfs_handle_t *hdl, zfs_graph_t *zgp, const char *dataset) +{ + zfs_cmd_t zc = { 0 }; + zfs_vertex_t *zvp; + + /* + * Look up the source vertex, and avoid it if we've seen it before. + */ + zvp = zfs_graph_lookup(hdl, zgp, dataset, 0); + if (zvp == NULL) + return (-1); + if (zvp->zv_visited == VISIT_SEEN) + return (0); + + /* + * Iterate over all children + */ + for ((void) strlcpy(zc.zc_name, dataset, sizeof (zc.zc_name)); + ioctl(hdl->libzfs_fd, ZFS_IOC_DATASET_LIST_NEXT, &zc) == 0; + (void) strlcpy(zc.zc_name, dataset, sizeof (zc.zc_name))) { + /* + * Get statistics for this dataset, to determine the type of the + * dataset and clone statistics. If this fails, the dataset has + * since been removed, and we're pretty much screwed anyway. + */ + zc.zc_objset_stats.dds_origin[0] = '\0'; + if (ioctl(hdl->libzfs_fd, ZFS_IOC_OBJSET_STATS, &zc) != 0) + continue; + + if (zc.zc_objset_stats.dds_origin[0] != '\0') { + if (zfs_graph_add(hdl, zgp, + zc.zc_objset_stats.dds_origin, zc.zc_name, + zc.zc_objset_stats.dds_creation_txg) != 0) + return (-1); + /* + * Count origins only if they are contained in the graph + */ + if (isa_child_of(zc.zc_objset_stats.dds_origin, + zgp->zg_root)) + zgp->zg_clone_count--; + } + + /* + * Add an edge between the parent and the child. + */ + if (zfs_graph_add(hdl, zgp, dataset, zc.zc_name, + zc.zc_objset_stats.dds_creation_txg) != 0) + return (-1); + + /* + * Recursively visit child + */ + if (iterate_children(hdl, zgp, zc.zc_name)) + return (-1); + } + + /* + * Now iterate over all snapshots. + */ + bzero(&zc, sizeof (zc)); + + for ((void) strlcpy(zc.zc_name, dataset, sizeof (zc.zc_name)); + ioctl(hdl->libzfs_fd, ZFS_IOC_SNAPSHOT_LIST_NEXT, &zc) == 0; + (void) strlcpy(zc.zc_name, dataset, sizeof (zc.zc_name))) { + + /* + * Get statistics for this dataset, to determine the type of the + * dataset and clone statistics. If this fails, the dataset has + * since been removed, and we're pretty much screwed anyway. + */ + if (ioctl(hdl->libzfs_fd, ZFS_IOC_OBJSET_STATS, &zc) != 0) + continue; + + /* + * Add an edge between the parent and the child. + */ + if (zfs_graph_add(hdl, zgp, dataset, zc.zc_name, + zc.zc_objset_stats.dds_creation_txg) != 0) + return (-1); + + zgp->zg_clone_count += zc.zc_objset_stats.dds_num_clones; + } + + zvp->zv_visited = VISIT_SEEN; + + return (0); +} + +/* + * Returns false if there are no snapshots with dependent clones in this + * subtree or if all of those clones are also in this subtree. Returns + * true if there is an error or there are external dependents. + */ +static boolean_t +external_dependents(libzfs_handle_t *hdl, zfs_graph_t *zgp, const char *dataset) +{ + zfs_cmd_t zc = { 0 }; + + /* + * Check whether this dataset is a clone or has clones since + * iterate_children() only checks the children. + */ + (void) strlcpy(zc.zc_name, dataset, sizeof (zc.zc_name)); + if (ioctl(hdl->libzfs_fd, ZFS_IOC_OBJSET_STATS, &zc) != 0) + return (B_TRUE); + + if (zc.zc_objset_stats.dds_origin[0] != '\0') { + if (zfs_graph_add(hdl, zgp, + zc.zc_objset_stats.dds_origin, zc.zc_name, + zc.zc_objset_stats.dds_creation_txg) != 0) + return (B_TRUE); + if (isa_child_of(zc.zc_objset_stats.dds_origin, dataset)) + zgp->zg_clone_count--; + } + + if ((zc.zc_objset_stats.dds_num_clones) || + iterate_children(hdl, zgp, dataset)) + return (B_TRUE); + + return (zgp->zg_clone_count != 0); +} + +/* + * Construct a complete graph of all necessary vertices. First, iterate over + * only our object's children. If no cloned snapshots are found, or all of + * the cloned snapshots are in this subtree then return a graph of the subtree. + * Otherwise, start at the root of the pool and iterate over all datasets. + */ +static zfs_graph_t * +construct_graph(libzfs_handle_t *hdl, const char *dataset) +{ + zfs_graph_t *zgp = zfs_graph_create(hdl, dataset, ZFS_GRAPH_SIZE); + int ret = 0; + + if (zgp == NULL) + return (zgp); + + if ((strchr(dataset, '/') == NULL) || + (external_dependents(hdl, zgp, dataset))) { + /* + * Determine pool name and try again. + */ + int len = strcspn(dataset, "/@") + 1; + char *pool = zfs_alloc(hdl, len); + + if (pool == NULL) { + zfs_graph_destroy(zgp); + return (NULL); + } + (void) strlcpy(pool, dataset, len); + + if (iterate_children(hdl, zgp, pool) == -1 || + zfs_graph_add(hdl, zgp, pool, NULL, 0) != 0) { + free(pool); + zfs_graph_destroy(zgp); + return (NULL); + } + free(pool); + } + + if (ret == -1 || zfs_graph_add(hdl, zgp, dataset, NULL, 0) != 0) { + zfs_graph_destroy(zgp); + return (NULL); + } + + return (zgp); +} + +/* + * Given a graph, do a recursive topological sort into the given array. This is + * really just a depth first search, so that the deepest nodes appear first. + * hijack the 'zv_visited' marker to avoid visiting the same vertex twice. + */ +static int +topo_sort(libzfs_handle_t *hdl, boolean_t allowrecursion, char **result, + size_t *idx, zfs_vertex_t *zgv) +{ + int i; + + if (zgv->zv_visited == VISIT_SORT_PRE && !allowrecursion) { + /* + * If we've already seen this vertex as part of our depth-first + * search, then we have a cyclic dependency, and we must return + * an error. + */ + zfs_error_aux(hdl, dgettext(TEXT_DOMAIN, + "recursive dependency at '%s'"), + zgv->zv_dataset); + return (zfs_error(hdl, EZFS_RECURSIVE, + dgettext(TEXT_DOMAIN, + "cannot determine dependent datasets"))); + } else if (zgv->zv_visited >= VISIT_SORT_PRE) { + /* + * If we've already processed this as part of the topological + * sort, then don't bother doing so again. + */ + return (0); + } + + zgv->zv_visited = VISIT_SORT_PRE; + + /* avoid doing a search if we don't have to */ + zfs_vertex_sort_edges(zgv); + for (i = 0; i < zgv->zv_edgecount; i++) { + if (topo_sort(hdl, allowrecursion, result, idx, + zgv->zv_edges[i]->ze_dest) != 0) + return (-1); + } + + /* we may have visited this in the course of the above */ + if (zgv->zv_visited == VISIT_SORT_POST) + return (0); + + if ((result[*idx] = zfs_alloc(hdl, + strlen(zgv->zv_dataset) + 1)) == NULL) + return (-1); + + (void) strcpy(result[*idx], zgv->zv_dataset); + *idx += 1; + zgv->zv_visited = VISIT_SORT_POST; + return (0); +} + +/* + * The only public interface for this file. Do the dirty work of constructing a + * child list for the given object. Construct the graph, do the toplogical + * sort, and then return the array of strings to the caller. + * + * The 'allowrecursion' parameter controls behavior when cycles are found. If + * it is set, the the cycle is ignored and the results returned as if the cycle + * did not exist. If it is not set, then the routine will generate an error if + * a cycle is found. + */ +int +get_dependents(libzfs_handle_t *hdl, boolean_t allowrecursion, + const char *dataset, char ***result, size_t *count) +{ + zfs_graph_t *zgp; + zfs_vertex_t *zvp; + + if ((zgp = construct_graph(hdl, dataset)) == NULL) + return (-1); + + if ((*result = zfs_alloc(hdl, + zgp->zg_nvertex * sizeof (char *))) == NULL) { + zfs_graph_destroy(zgp); + return (-1); + } + + if ((zvp = zfs_graph_lookup(hdl, zgp, dataset, 0)) == NULL) { + free(*result); + zfs_graph_destroy(zgp); + return (-1); + } + + *count = 0; + if (topo_sort(hdl, allowrecursion, *result, count, zvp) != 0) { + free(*result); + zfs_graph_destroy(zgp); + return (-1); + } + + /* + * Get rid of the last entry, which is our starting vertex and not + * strictly a dependent. + */ + assert(*count > 0); + free((*result)[*count - 1]); + (*count)--; + + zfs_graph_destroy(zgp); + + return (0); +} diff --git a/lib/libzfs/common/libzfs_impl.h b/lib/libzfs/common/libzfs_impl.h index 576b2af5d2c2..c9b09a205024 100644 --- a/lib/libzfs/common/libzfs_impl.h +++ b/lib/libzfs/common/libzfs_impl.h @@ -21,11 +21,10 @@ /* * Copyright (c) 2005, 2010, Oracle and/or its affiliates. All rights reserved. - * Copyright (c) 2012 by Delphix. All rights reserved. */ -#ifndef _LIBZFS_IMPL_H -#define _LIBZFS_IMPL_H +#ifndef _LIBFS_IMPL_H +#define _LIBFS_IMPL_H #include <sys/dmu.h> #include <sys/fs/zfs.h> @@ -36,7 +35,6 @@ #include <libuutil.h> #include <libzfs.h> #include <libshare.h> -#include <libzfs_core.h> #include <fm/libtopo.h> @@ -68,6 +66,7 @@ struct libzfs_handle { int libzfs_desc_active; char libzfs_action[1024]; char libzfs_desc[1024]; + char *libzfs_log_str; int libzfs_printerr; int libzfs_storeerr; /* stuff error messages into buffer */ void *libzfs_sharehdl; /* libshare handle */ @@ -116,7 +115,7 @@ struct zpool_handle { diskaddr_t zpool_start_block; }; -typedef enum { +typedef enum { PROTO_NFS = 0, PROTO_SMB = 1, PROTO_END = 2 @@ -148,7 +147,6 @@ int zpool_standard_error_fmt(libzfs_handle_t *, int, const char *, ...); int get_dependents(libzfs_handle_t *, boolean_t, const char *, char ***, size_t *); -zfs_handle_t *make_dataset_handle_zc(libzfs_handle_t *, zfs_cmd_t *); int zprop_parse_value(libzfs_handle_t *, nvpair_t *, int, zfs_type_t, @@ -213,4 +211,4 @@ extern void libzfs_fru_clear(libzfs_handle_t *, boolean_t); } #endif -#endif /* _LIBZFS_IMPL_H */ +#endif /* _LIBFS_IMPL_H */ diff --git a/lib/libzfs/common/libzfs_import.c b/lib/libzfs/common/libzfs_import.c index 414aa2f747b1..e1370350fd52 100644 --- a/lib/libzfs/common/libzfs_import.c +++ b/lib/libzfs/common/libzfs_import.c @@ -20,8 +20,6 @@ */ /* * Copyright (c) 2005, 2010, Oracle and/or its affiliates. All rights reserved. - * Copyright 2011 Nexenta Systems, Inc. All rights reserved. - * Copyright (c) 2011 by Delphix. All rights reserved. */ /* @@ -439,7 +437,7 @@ get_configs(libzfs_handle_t *hdl, pool_list_t *pl, boolean_t active_ok) uint_t i, nspares, nl2cache; boolean_t config_seen; uint64_t best_txg; - char *name, *hostname, *comment; + char *name, *hostname; uint64_t version, guid; uint_t children = 0; nvlist_t **child = NULL; @@ -528,7 +526,6 @@ get_configs(libzfs_handle_t *hdl, pool_list_t *pl, boolean_t active_ok) * version * pool guid * name - * comment (if available) * pool state * hostid (if available) * hostname (if available) @@ -550,24 +547,11 @@ get_configs(libzfs_handle_t *hdl, pool_list_t *pl, boolean_t active_ok) if (nvlist_add_string(config, ZPOOL_CONFIG_POOL_NAME, name) != 0) goto nomem; - - /* - * COMMENT is optional, don't bail if it's not - * there, instead, set it to NULL. - */ - if (nvlist_lookup_string(tmp, - ZPOOL_CONFIG_COMMENT, &comment) != 0) - comment = NULL; - else if (nvlist_add_string(config, - ZPOOL_CONFIG_COMMENT, comment) != 0) - goto nomem; - verify(nvlist_lookup_uint64(tmp, ZPOOL_CONFIG_POOL_STATE, &state) == 0); if (nvlist_add_uint64(config, ZPOOL_CONFIG_POOL_STATE, state) != 0) goto nomem; - hostid = 0; if (nvlist_lookup_uint64(tmp, ZPOOL_CONFIG_HOSTID, &hostid) == 0) { diff --git a/lib/libzfs/common/libzfs_iter.c b/lib/libzfs/common/libzfs_iter.c deleted file mode 100644 index be5767f542d6..000000000000 --- a/lib/libzfs/common/libzfs_iter.c +++ /dev/null @@ -1,462 +0,0 @@ -/* - * 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) 2005, 2010, Oracle and/or its affiliates. All rights reserved. - * Copyright 2010 Nexenta Systems, Inc. All rights reserved. - * Copyright (c) 2012 by Delphix. All rights reserved. - */ - -#include <stdio.h> -#include <stdlib.h> -#include <strings.h> -#include <unistd.h> -#include <stddef.h> -#include <libintl.h> -#include <libzfs.h> - -#include "libzfs_impl.h" - -int -zfs_iter_clones(zfs_handle_t *zhp, zfs_iter_f func, void *data) -{ - nvlist_t *nvl = zfs_get_clones_nvl(zhp); - nvpair_t *pair; - - if (nvl == NULL) - return (0); - - for (pair = nvlist_next_nvpair(nvl, NULL); pair != NULL; - pair = nvlist_next_nvpair(nvl, pair)) { - zfs_handle_t *clone = zfs_open(zhp->zfs_hdl, nvpair_name(pair), - ZFS_TYPE_FILESYSTEM | ZFS_TYPE_VOLUME); - if (clone != NULL) { - int err = func(clone, data); - if (err != 0) - return (err); - } - } - return (0); -} - -static int -zfs_do_list_ioctl(zfs_handle_t *zhp, int arg, zfs_cmd_t *zc) -{ - int rc; - uint64_t orig_cookie; - - orig_cookie = zc->zc_cookie; -top: - (void) strlcpy(zc->zc_name, zhp->zfs_name, sizeof (zc->zc_name)); - rc = ioctl(zhp->zfs_hdl->libzfs_fd, arg, zc); - - if (rc == -1) { - switch (errno) { - case ENOMEM: - /* expand nvlist memory and try again */ - if (zcmd_expand_dst_nvlist(zhp->zfs_hdl, zc) != 0) { - zcmd_free_nvlists(zc); - return (-1); - } - zc->zc_cookie = orig_cookie; - goto top; - /* - * An errno value of ESRCH indicates normal completion. - * If ENOENT is returned, then the underlying dataset - * has been removed since we obtained the handle. - */ - case ESRCH: - case ENOENT: - rc = 1; - break; - default: - rc = zfs_standard_error(zhp->zfs_hdl, errno, - dgettext(TEXT_DOMAIN, - "cannot iterate filesystems")); - break; - } - } - return (rc); -} - -/* - * Iterate over all child filesystems - */ -int -zfs_iter_filesystems(zfs_handle_t *zhp, zfs_iter_f func, void *data) -{ - zfs_cmd_t zc = { 0 }; - zfs_handle_t *nzhp; - int ret; - - if (zhp->zfs_type != ZFS_TYPE_FILESYSTEM) - return (0); - - if (zcmd_alloc_dst_nvlist(zhp->zfs_hdl, &zc, 0) != 0) - return (-1); - - while ((ret = zfs_do_list_ioctl(zhp, ZFS_IOC_DATASET_LIST_NEXT, - &zc)) == 0) { - /* - * Silently ignore errors, as the only plausible explanation is - * that the pool has since been removed. - */ - if ((nzhp = make_dataset_handle_zc(zhp->zfs_hdl, - &zc)) == NULL) { - continue; - } - - if ((ret = func(nzhp, data)) != 0) { - zcmd_free_nvlists(&zc); - return (ret); - } - } - zcmd_free_nvlists(&zc); - return ((ret < 0) ? ret : 0); -} - -/* - * Iterate over all snapshots - */ -int -zfs_iter_snapshots(zfs_handle_t *zhp, zfs_iter_f func, void *data) -{ - zfs_cmd_t zc = { 0 }; - zfs_handle_t *nzhp; - int ret; - - if (zhp->zfs_type == ZFS_TYPE_SNAPSHOT) - return (0); - - if (zcmd_alloc_dst_nvlist(zhp->zfs_hdl, &zc, 0) != 0) - return (-1); - while ((ret = zfs_do_list_ioctl(zhp, ZFS_IOC_SNAPSHOT_LIST_NEXT, - &zc)) == 0) { - - if ((nzhp = make_dataset_handle_zc(zhp->zfs_hdl, - &zc)) == NULL) { - continue; - } - - if ((ret = func(nzhp, data)) != 0) { - zcmd_free_nvlists(&zc); - return (ret); - } - } - zcmd_free_nvlists(&zc); - return ((ret < 0) ? ret : 0); -} - -/* - * Routines for dealing with the sorted snapshot functionality - */ -typedef struct zfs_node { - zfs_handle_t *zn_handle; - avl_node_t zn_avlnode; -} zfs_node_t; - -static int -zfs_sort_snaps(zfs_handle_t *zhp, void *data) -{ - avl_tree_t *avl = data; - zfs_node_t *node; - zfs_node_t search; - - search.zn_handle = zhp; - node = avl_find(avl, &search, NULL); - if (node) { - /* - * If this snapshot was renamed while we were creating the - * AVL tree, it's possible that we already inserted it under - * its old name. Remove the old handle before adding the new - * one. - */ - zfs_close(node->zn_handle); - avl_remove(avl, node); - free(node); - } - - node = zfs_alloc(zhp->zfs_hdl, sizeof (zfs_node_t)); - node->zn_handle = zhp; - avl_add(avl, node); - - return (0); -} - -static int -zfs_snapshot_compare(const void *larg, const void *rarg) -{ - zfs_handle_t *l = ((zfs_node_t *)larg)->zn_handle; - zfs_handle_t *r = ((zfs_node_t *)rarg)->zn_handle; - uint64_t lcreate, rcreate; - - /* - * Sort them according to creation time. We use the hidden - * CREATETXG property to get an absolute ordering of snapshots. - */ - lcreate = zfs_prop_get_int(l, ZFS_PROP_CREATETXG); - rcreate = zfs_prop_get_int(r, ZFS_PROP_CREATETXG); - - if (lcreate < rcreate) - return (-1); - else if (lcreate > rcreate) - return (+1); - else - return (0); -} - -int -zfs_iter_snapshots_sorted(zfs_handle_t *zhp, zfs_iter_f callback, void *data) -{ - int ret = 0; - zfs_node_t *node; - avl_tree_t avl; - void *cookie = NULL; - - avl_create(&avl, zfs_snapshot_compare, - sizeof (zfs_node_t), offsetof(zfs_node_t, zn_avlnode)); - - ret = zfs_iter_snapshots(zhp, zfs_sort_snaps, &avl); - - for (node = avl_first(&avl); node != NULL; node = AVL_NEXT(&avl, node)) - ret |= callback(node->zn_handle, data); - - while ((node = avl_destroy_nodes(&avl, &cookie)) != NULL) - free(node); - - avl_destroy(&avl); - - return (ret); -} - -typedef struct { - char *ssa_first; - char *ssa_last; - boolean_t ssa_seenfirst; - boolean_t ssa_seenlast; - zfs_iter_f ssa_func; - void *ssa_arg; -} snapspec_arg_t; - -static int -snapspec_cb(zfs_handle_t *zhp, void *arg) { - snapspec_arg_t *ssa = arg; - char *shortsnapname; - int err = 0; - - if (ssa->ssa_seenlast) - return (0); - shortsnapname = zfs_strdup(zhp->zfs_hdl, - strchr(zfs_get_name(zhp), '@') + 1); - - if (!ssa->ssa_seenfirst && strcmp(shortsnapname, ssa->ssa_first) == 0) - ssa->ssa_seenfirst = B_TRUE; - - if (ssa->ssa_seenfirst) { - err = ssa->ssa_func(zhp, ssa->ssa_arg); - } else { - zfs_close(zhp); - } - - if (strcmp(shortsnapname, ssa->ssa_last) == 0) - ssa->ssa_seenlast = B_TRUE; - free(shortsnapname); - - return (err); -} - -/* - * spec is a string like "A,B%C,D" - * - * <snaps>, where <snaps> can be: - * <snap> (single snapshot) - * <snap>%<snap> (range of snapshots, inclusive) - * %<snap> (range of snapshots, starting with earliest) - * <snap>% (range of snapshots, ending with last) - * % (all snapshots) - * <snaps>[,...] (comma separated list of the above) - * - * If a snapshot can not be opened, continue trying to open the others, but - * return ENOENT at the end. - */ -int -zfs_iter_snapspec(zfs_handle_t *fs_zhp, const char *spec_orig, - zfs_iter_f func, void *arg) -{ - char *buf, *comma_separated, *cp; - int err = 0; - int ret = 0; - - buf = zfs_strdup(fs_zhp->zfs_hdl, spec_orig); - cp = buf; - - while ((comma_separated = strsep(&cp, ",")) != NULL) { - char *pct = strchr(comma_separated, '%'); - if (pct != NULL) { - snapspec_arg_t ssa = { 0 }; - ssa.ssa_func = func; - ssa.ssa_arg = arg; - - if (pct == comma_separated) - ssa.ssa_seenfirst = B_TRUE; - else - ssa.ssa_first = comma_separated; - *pct = '\0'; - ssa.ssa_last = pct + 1; - - /* - * If there is a lastname specified, make sure it - * exists. - */ - if (ssa.ssa_last[0] != '\0') { - char snapname[ZFS_MAXNAMELEN]; - (void) snprintf(snapname, sizeof (snapname), - "%s@%s", zfs_get_name(fs_zhp), - ssa.ssa_last); - if (!zfs_dataset_exists(fs_zhp->zfs_hdl, - snapname, ZFS_TYPE_SNAPSHOT)) { - ret = ENOENT; - continue; - } - } - - err = zfs_iter_snapshots_sorted(fs_zhp, - snapspec_cb, &ssa); - if (ret == 0) - ret = err; - if (ret == 0 && (!ssa.ssa_seenfirst || - (ssa.ssa_last[0] != '\0' && !ssa.ssa_seenlast))) { - ret = ENOENT; - } - } else { - char snapname[ZFS_MAXNAMELEN]; - zfs_handle_t *snap_zhp; - (void) snprintf(snapname, sizeof (snapname), "%s@%s", - zfs_get_name(fs_zhp), comma_separated); - snap_zhp = make_dataset_handle(fs_zhp->zfs_hdl, - snapname); - if (snap_zhp == NULL) { - ret = ENOENT; - continue; - } - err = func(snap_zhp, arg); - if (ret == 0) - ret = err; - } - } - - free(buf); - return (ret); -} - -/* - * Iterate over all children, snapshots and filesystems - */ -int -zfs_iter_children(zfs_handle_t *zhp, zfs_iter_f func, void *data) -{ - int ret; - - if ((ret = zfs_iter_filesystems(zhp, func, data)) != 0) - return (ret); - - return (zfs_iter_snapshots(zhp, func, data)); -} - - -typedef struct iter_stack_frame { - struct iter_stack_frame *next; - zfs_handle_t *zhp; -} iter_stack_frame_t; - -typedef struct iter_dependents_arg { - boolean_t first; - boolean_t allowrecursion; - iter_stack_frame_t *stack; - zfs_iter_f func; - void *data; -} iter_dependents_arg_t; - -static int -iter_dependents_cb(zfs_handle_t *zhp, void *arg) -{ - iter_dependents_arg_t *ida = arg; - int err; - boolean_t first = ida->first; - ida->first = B_FALSE; - - if (zhp->zfs_type == ZFS_TYPE_SNAPSHOT) { - err = zfs_iter_clones(zhp, iter_dependents_cb, ida); - } else { - iter_stack_frame_t isf; - iter_stack_frame_t *f; - - /* - * check if there is a cycle by seeing if this fs is already - * on the stack. - */ - for (f = ida->stack; f != NULL; f = f->next) { - if (f->zhp->zfs_dmustats.dds_guid == - zhp->zfs_dmustats.dds_guid) { - if (ida->allowrecursion) { - zfs_close(zhp); - return (0); - } else { - zfs_error_aux(zhp->zfs_hdl, - dgettext(TEXT_DOMAIN, - "recursive dependency at '%s'"), - zfs_get_name(zhp)); - err = zfs_error(zhp->zfs_hdl, - EZFS_RECURSIVE, - dgettext(TEXT_DOMAIN, - "cannot determine dependent " - "datasets")); - zfs_close(zhp); - return (err); - } - } - } - - isf.zhp = zhp; - isf.next = ida->stack; - ida->stack = &isf; - err = zfs_iter_filesystems(zhp, iter_dependents_cb, ida); - if (err == 0) - err = zfs_iter_snapshots(zhp, iter_dependents_cb, ida); - ida->stack = isf.next; - } - if (!first && err == 0) - err = ida->func(zhp, ida->data); - return (err); -} - -int -zfs_iter_dependents(zfs_handle_t *zhp, boolean_t allowrecursion, - zfs_iter_f func, void *data) -{ - iter_dependents_arg_t ida; - ida.allowrecursion = allowrecursion; - ida.stack = NULL; - ida.func = func; - ida.data = data; - ida.first = B_TRUE; - return (iter_dependents_cb(zfs_handle_dup(zhp), &ida)); -} diff --git a/lib/libzfs/common/libzfs_pool.c b/lib/libzfs/common/libzfs_pool.c index 1c6fb371e3bc..7df7e910ddc5 100644 --- a/lib/libzfs/common/libzfs_pool.c +++ b/lib/libzfs/common/libzfs_pool.c @@ -21,8 +21,6 @@ /* * Copyright (c) 2005, 2010, Oracle and/or its affiliates. All rights reserved. - * Copyright 2011 Nexenta Systems, Inc. All rights reserved. - * Copyright (c) 2012 by Delphix. All rights reserved. */ #include <ctype.h> @@ -34,7 +32,6 @@ #include <stdlib.h> #include <strings.h> #include <unistd.h> -#include <libgen.h> #include <sys/efi_partition.h> #include <sys/vtoc.h> #include <sys/zfs_ioctl.h> @@ -44,7 +41,6 @@ #include "zfs_prop.h" #include "libzfs_impl.h" #include "zfs_comutil.h" -#include "zfeature_common.h" static int read_efi_label(nvlist_t *config, diskaddr_t *sb); @@ -237,7 +233,6 @@ zpool_get_prop(zpool_handle_t *zhp, zpool_prop_t prop, char *buf, size_t len, case ZPOOL_PROP_ALTROOT: case ZPOOL_PROP_CACHEFILE: - case ZPOOL_PROP_COMMENT: if (zhp->zpool_props != NULL || zpool_get_all_props(zhp) == 0) { (void) strlcpy(buf, @@ -275,8 +270,6 @@ zpool_get_prop(zpool_handle_t *zhp, zpool_prop_t prop, char *buf, size_t len, case ZPOOL_PROP_SIZE: case ZPOOL_PROP_ALLOCATED: case ZPOOL_PROP_FREE: - case ZPOOL_PROP_FREEING: - case ZPOOL_PROP_EXPANDSZ: (void) zfs_nicenum(intval, buf, len); break; @@ -301,12 +294,6 @@ zpool_get_prop(zpool_handle_t *zhp, zpool_prop_t prop, char *buf, size_t len, (void) strlcpy(buf, zpool_state_to_name(intval, vs->vs_aux), len); break; - case ZPOOL_PROP_VERSION: - if (intval >= SPA_VERSION_FEATURES) { - (void) snprintf(buf, len, "-"); - break; - } - /* FALLTHROUGH */ default: (void) snprintf(buf, len, "%llu", intval); } @@ -370,8 +357,8 @@ pool_uses_efi(nvlist_t *config) return (B_FALSE); } -boolean_t -zpool_is_bootable(zpool_handle_t *zhp) +static boolean_t +pool_is_bootable(zpool_handle_t *zhp) { char bootfs[ZPOOL_MAXNAMELEN]; @@ -395,7 +382,7 @@ zpool_valid_proplist(libzfs_handle_t *hdl, const char *poolname, zpool_prop_t prop; char *strval; uint64_t intval; - char *slash, *check; + char *slash; struct stat64 statbuf; zpool_handle_t *zhp; nvlist_t *nvroot; @@ -409,48 +396,10 @@ zpool_valid_proplist(libzfs_handle_t *hdl, const char *poolname, while ((elem = nvlist_next_nvpair(props, elem)) != NULL) { const char *propname = nvpair_name(elem); - prop = zpool_name_to_prop(propname); - if (prop == ZPROP_INVAL && zpool_prop_feature(propname)) { - int err; - zfeature_info_t *feature; - char *fname = strchr(propname, '@') + 1; - - err = zfeature_lookup_name(fname, &feature); - if (err != 0) { - ASSERT3U(err, ==, ENOENT); - zfs_error_aux(hdl, dgettext(TEXT_DOMAIN, - "invalid feature '%s'"), fname); - (void) zfs_error(hdl, EZFS_BADPROP, errbuf); - goto error; - } - - if (nvpair_type(elem) != DATA_TYPE_STRING) { - zfs_error_aux(hdl, dgettext(TEXT_DOMAIN, - "'%s' must be a string"), propname); - (void) zfs_error(hdl, EZFS_BADPROP, errbuf); - goto error; - } - - (void) nvpair_value_string(elem, &strval); - if (strcmp(strval, ZFS_FEATURE_ENABLED) != 0) { - zfs_error_aux(hdl, dgettext(TEXT_DOMAIN, - "property '%s' can only be set to " - "'enabled'"), propname); - (void) zfs_error(hdl, EZFS_BADPROP, errbuf); - goto error; - } - - if (nvlist_add_uint64(retprops, propname, 0) != 0) { - (void) no_memory(hdl); - goto error; - } - continue; - } - /* * Make sure this property is valid and applies to this type. */ - if (prop == ZPROP_INVAL) { + if ((prop = zpool_name_to_prop(propname)) == ZPROP_INVAL) { zfs_error_aux(hdl, dgettext(TEXT_DOMAIN, "invalid property '%s'"), propname); (void) zfs_error(hdl, EZFS_BADPROP, errbuf); @@ -473,8 +422,7 @@ zpool_valid_proplist(libzfs_handle_t *hdl, const char *poolname, */ switch (prop) { case ZPOOL_PROP_VERSION: - if (intval < version || - !SPA_VERSION_IS_SUPPORTED(intval)) { + if (intval < version || intval > SPA_VERSION) { zfs_error_aux(hdl, dgettext(TEXT_DOMAIN, "property '%s' number %d is invalid."), propname, intval); @@ -593,26 +541,6 @@ zpool_valid_proplist(libzfs_handle_t *hdl, const char *poolname, *slash = '/'; break; - case ZPOOL_PROP_COMMENT: - for (check = strval; *check != '\0'; check++) { - if (!isprint(*check)) { - zfs_error_aux(hdl, - dgettext(TEXT_DOMAIN, - "comment may only have printable " - "characters")); - (void) zfs_error(hdl, EZFS_BADPROP, - errbuf); - goto error; - } - } - if (strlen(strval) > ZPROP_MAX_COMMENT) { - zfs_error_aux(hdl, dgettext(TEXT_DOMAIN, - "comment must not exceed %d characters"), - ZPROP_MAX_COMMENT); - (void) zfs_error(hdl, EZFS_BADPROP, errbuf); - goto error; - } - break; case ZPOOL_PROP_READONLY: if (!flags.import) { zfs_error_aux(hdl, dgettext(TEXT_DOMAIN, @@ -696,77 +624,10 @@ zpool_expand_proplist(zpool_handle_t *zhp, zprop_list_t **plp) libzfs_handle_t *hdl = zhp->zpool_hdl; zprop_list_t *entry; char buf[ZFS_MAXPROPLEN]; - nvlist_t *features = NULL; - zprop_list_t **last; - boolean_t firstexpand = (NULL == *plp); if (zprop_expand_list(hdl, plp, ZFS_TYPE_POOL) != 0) return (-1); - last = plp; - while (*last != NULL) - last = &(*last)->pl_next; - - if ((*plp)->pl_all) - features = zpool_get_features(zhp); - - if ((*plp)->pl_all && firstexpand) { - for (int i = 0; i < SPA_FEATURES; i++) { - zprop_list_t *entry = zfs_alloc(hdl, - sizeof (zprop_list_t)); - entry->pl_prop = ZPROP_INVAL; - entry->pl_user_prop = zfs_asprintf(hdl, "feature@%s", - spa_feature_table[i].fi_uname); - entry->pl_width = strlen(entry->pl_user_prop); - entry->pl_all = B_TRUE; - - *last = entry; - last = &entry->pl_next; - } - } - - /* add any unsupported features */ - for (nvpair_t *nvp = nvlist_next_nvpair(features, NULL); - nvp != NULL; nvp = nvlist_next_nvpair(features, nvp)) { - char *propname; - boolean_t found; - zprop_list_t *entry; - - if (zfeature_is_supported(nvpair_name(nvp))) - continue; - - propname = zfs_asprintf(hdl, "unsupported@%s", - nvpair_name(nvp)); - - /* - * Before adding the property to the list make sure that no - * other pool already added the same property. - */ - found = B_FALSE; - entry = *plp; - while (entry != NULL) { - if (entry->pl_user_prop != NULL && - strcmp(propname, entry->pl_user_prop) == 0) { - found = B_TRUE; - break; - } - entry = entry->pl_next; - } - if (found) { - free(propname); - continue; - } - - entry = zfs_alloc(hdl, sizeof (zprop_list_t)); - entry->pl_prop = ZPROP_INVAL; - entry->pl_user_prop = propname; - entry->pl_width = strlen(entry->pl_user_prop); - entry->pl_all = B_TRUE; - - *last = entry; - last = &entry->pl_next; - } - for (entry = *plp; entry != NULL; entry = entry->pl_next) { if (entry->pl_fixed) @@ -783,66 +644,6 @@ zpool_expand_proplist(zpool_handle_t *zhp, zprop_list_t **plp) return (0); } -/* - * Get the state for the given feature on the given ZFS pool. - */ -int -zpool_prop_get_feature(zpool_handle_t *zhp, const char *propname, char *buf, - size_t len) -{ - uint64_t refcount; - boolean_t found = B_FALSE; - nvlist_t *features = zpool_get_features(zhp); - boolean_t supported; - const char *feature = strchr(propname, '@') + 1; - - supported = zpool_prop_feature(propname); - ASSERT(supported || zfs_prop_unsupported(propname)); - - /* - * Convert from feature name to feature guid. This conversion is - * unecessary for unsupported@... properties because they already - * use guids. - */ - if (supported) { - int ret; - zfeature_info_t *fi; - - ret = zfeature_lookup_name(feature, &fi); - if (ret != 0) { - (void) strlcpy(buf, "-", len); - return (ENOTSUP); - } - feature = fi->fi_guid; - } - - if (nvlist_lookup_uint64(features, feature, &refcount) == 0) - found = B_TRUE; - - if (supported) { - if (!found) { - (void) strlcpy(buf, ZFS_FEATURE_DISABLED, len); - } else { - if (refcount == 0) - (void) strlcpy(buf, ZFS_FEATURE_ENABLED, len); - else - (void) strlcpy(buf, ZFS_FEATURE_ACTIVE, len); - } - } else { - if (found) { - if (refcount == 0) { - (void) strcpy(buf, ZFS_UNSUPPORTED_INACTIVE); - } else { - (void) strcpy(buf, ZFS_UNSUPPORTED_READONLY); - } - } else { - (void) strlcpy(buf, "-", len); - return (ENOTSUP); - } - } - - return (0); -} /* * Don't start the slice at the default block of 34; many storage @@ -1206,7 +1007,7 @@ create_failed: * datasets left in the pool. */ int -zpool_destroy(zpool_handle_t *zhp, const char *log_str) +zpool_destroy(zpool_handle_t *zhp) { zfs_cmd_t zc = { 0 }; zfs_handle_t *zfp = NULL; @@ -1218,7 +1019,6 @@ zpool_destroy(zpool_handle_t *zhp, const char *log_str) return (-1); (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) { (void) snprintf(msg, sizeof (msg), dgettext(TEXT_DOMAIN, @@ -1271,7 +1071,7 @@ zpool_add(zpool_handle_t *zhp, nvlist_t *nvroot) return (zfs_error(hdl, EZFS_BADVERSION, msg)); } - if (zpool_is_bootable(zhp) && nvlist_lookup_nvlist_array(nvroot, + if (pool_is_bootable(zhp) && nvlist_lookup_nvlist_array(nvroot, ZPOOL_CONFIG_SPARES, &spares, &nspares) == 0) { uint64_t s; @@ -1373,9 +1173,8 @@ zpool_add(zpool_handle_t *zhp, nvlist_t *nvroot) * Exports the pool from the system. The caller must ensure that there are no * mounted datasets in the pool. */ -static int -zpool_export_common(zpool_handle_t *zhp, boolean_t force, boolean_t hardforce, - const char *log_str) +int +zpool_export_common(zpool_handle_t *zhp, boolean_t force, boolean_t hardforce) { zfs_cmd_t zc = { 0 }; char msg[1024]; @@ -1386,7 +1185,6 @@ 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)); zc.zc_cookie = force; 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) { switch (errno) { @@ -1408,15 +1206,15 @@ zpool_export_common(zpool_handle_t *zhp, boolean_t force, boolean_t hardforce, } int -zpool_export(zpool_handle_t *zhp, boolean_t force, const char *log_str) +zpool_export(zpool_handle_t *zhp, boolean_t force) { - return (zpool_export_common(zhp, force, B_FALSE, log_str)); + return (zpool_export_common(zhp, force, B_FALSE)); } int -zpool_export_force(zpool_handle_t *zhp, const char *log_str) +zpool_export_force(zpool_handle_t *zhp) { - return (zpool_export_common(zhp, B_TRUE, B_TRUE, log_str)); + return (zpool_export_common(zhp, B_TRUE, B_TRUE)); } static void @@ -1432,10 +1230,8 @@ zpool_rewind_exclaim(libzfs_handle_t *hdl, const char *name, boolean_t dryrun, if (!hdl->libzfs_printerr || config == NULL) return; - if (nvlist_lookup_nvlist(config, ZPOOL_CONFIG_LOAD_INFO, &nv) != 0 || - nvlist_lookup_nvlist(nv, ZPOOL_CONFIG_REWIND_INFO, &nv) != 0) { + if (nvlist_lookup_nvlist(config, ZPOOL_CONFIG_LOAD_INFO, &nv) != 0) return; - } if (nvlist_lookup_uint64(nv, ZPOOL_CONFIG_LOAD_TIME, &rewindto) != 0) return; @@ -1491,7 +1287,6 @@ zpool_explain_recover(libzfs_handle_t *hdl, const char *name, int reason, /* All attempted rewinds failed if ZPOOL_CONFIG_LOAD_TIME missing */ if (nvlist_lookup_nvlist(config, ZPOOL_CONFIG_LOAD_INFO, &nv) != 0 || - nvlist_lookup_nvlist(nv, ZPOOL_CONFIG_REWIND_INFO, &nv) != 0 || nvlist_lookup_uint64(nv, ZPOOL_CONFIG_LOAD_TIME, &rewindto) != 0) goto no_info; @@ -1614,30 +1409,6 @@ print_vdev_tree(libzfs_handle_t *hdl, const char *name, nvlist_t *nv, } } -void -zpool_print_unsup_feat(nvlist_t *config) -{ - nvlist_t *nvinfo, *unsup_feat; - - verify(nvlist_lookup_nvlist(config, ZPOOL_CONFIG_LOAD_INFO, &nvinfo) == - 0); - verify(nvlist_lookup_nvlist(nvinfo, ZPOOL_CONFIG_UNSUP_FEAT, - &unsup_feat) == 0); - - for (nvpair_t *nvp = nvlist_next_nvpair(unsup_feat, NULL); nvp != NULL; - nvp = nvlist_next_nvpair(unsup_feat, nvp)) { - char *desc; - - verify(nvpair_type(nvp) == DATA_TYPE_STRING); - verify(nvpair_value_string(nvp, &desc) == 0); - - if (strlen(desc) > 0) - (void) printf("\t%s (%s)\n", nvpair_name(nvp), desc); - else - (void) printf("\t%s\n", nvpair_name(nvp)); - } -} - /* * Import the given pool using the known configuration and a list of * properties to be set. The configuration should have come from @@ -1744,22 +1515,6 @@ zpool_import_props(libzfs_handle_t *hdl, nvlist_t *config, const char *newname, switch (error) { case ENOTSUP: - if (nv != NULL && nvlist_lookup_nvlist(nv, - ZPOOL_CONFIG_LOAD_INFO, &nvinfo) == 0 && - nvlist_exists(nvinfo, ZPOOL_CONFIG_UNSUP_FEAT)) { - (void) printf(dgettext(TEXT_DOMAIN, "This " - "pool uses the following feature(s) not " - "supported by this system:\n")); - zpool_print_unsup_feat(nv); - if (nvlist_exists(nvinfo, - ZPOOL_CONFIG_CAN_RDONLY)) { - (void) printf(dgettext(TEXT_DOMAIN, - "All unsupported features are only " - "required for writing to the pool." - "\nThe pool can be imported using " - "'-o readonly=on'.\n")); - } - } /* * Unsupported version. */ @@ -2600,7 +2355,7 @@ zpool_vdev_attach(zpool_handle_t *zhp, uint_t children; nvlist_t *config_root; libzfs_handle_t *hdl = zhp->zpool_hdl; - boolean_t rootpool = zpool_is_bootable(zhp); + boolean_t rootpool = pool_is_bootable(zhp); if (replacing) (void) snprintf(msg, sizeof (msg), dgettext(TEXT_DOMAIN, @@ -3212,46 +2967,6 @@ zpool_vdev_clear(zpool_handle_t *zhp, uint64_t guid) } /* - * Change the GUID for a pool. - */ -int -zpool_reguid(zpool_handle_t *zhp) -{ - char msg[1024]; - libzfs_handle_t *hdl = zhp->zpool_hdl; - zfs_cmd_t zc = { 0 }; - - (void) snprintf(msg, sizeof (msg), - dgettext(TEXT_DOMAIN, "cannot reguid '%s'"), zhp->zpool_name); - - (void) strlcpy(zc.zc_name, zhp->zpool_name, sizeof (zc.zc_name)); - if (zfs_ioctl(hdl, ZFS_IOC_POOL_REGUID, &zc) == 0) - return (0); - - return (zpool_standard_error(hdl, errno, msg)); -} - -/* - * Reopen the pool. - */ -int -zpool_reopen(zpool_handle_t *zhp) -{ - zfs_cmd_t zc = { 0 }; - char msg[1024]; - libzfs_handle_t *hdl = zhp->zpool_hdl; - - (void) snprintf(msg, sizeof (msg), - dgettext(TEXT_DOMAIN, "cannot reopen '%s'"), - zhp->zpool_name); - - (void) strlcpy(zc.zc_name, zhp->zpool_name, sizeof (zc.zc_name)); - if (zfs_ioctl(hdl, ZFS_IOC_POOL_REOPEN, &zc) == 0) - return (0); - return (zpool_standard_error(hdl, errno, msg)); -} - -/* * Convert from a devid string to a path. */ static char * @@ -3578,30 +3293,40 @@ zpool_upgrade(zpool_handle_t *zhp, uint64_t new_version) } void -zfs_save_arguments(int argc, char **argv, char *string, int len) +zpool_set_history_str(const char *subcommand, int argc, char **argv, + char *history_str) { - (void) strlcpy(string, basename(argv[0]), len); - for (int i = 1; i < argc; i++) { - (void) strlcat(string, " ", len); - (void) strlcat(string, argv[i], len); + int i; + + (void) strlcpy(history_str, subcommand, HIS_MAX_RECORD_LEN); + for (i = 1; i < argc; i++) { + 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 -zpool_log_history(libzfs_handle_t *hdl, const char *message) +zpool_stage_history(libzfs_handle_t *hdl, const char *history_str) { - zfs_cmd_t zc = { 0 }; - nvlist_t *args; - int err; - - args = fnvlist_alloc(); - fnvlist_add_string(args, "message", message); - err = zcmd_write_src_nvlist(hdl, &zc, args); - if (err == 0) - err = ioctl(hdl->libzfs_fd, ZFS_IOC_LOG_HISTORY, &zc); - nvlist_free(args); - zcmd_free_nvlists(&zc); - return (err); + if (history_str == NULL) + return (EINVAL); + + if (strlen(history_str) > HIS_MAX_RECORD_LEN) + return (EINVAL); + + if (hdl->libzfs_log_str != NULL) + free(hdl->libzfs_log_str); + + if ((hdl->libzfs_log_str = strdup(history_str)) == NULL) + return (no_memory(hdl)); + + return (0); } /* @@ -3874,7 +3599,7 @@ zpool_label_disk(libzfs_handle_t *hdl, zpool_handle_t *zhp, char *name) if (zhp) { nvlist_t *nvroot; - if (zpool_is_bootable(zhp)) { + if (pool_is_bootable(zhp)) { zfs_error_aux(hdl, dgettext(TEXT_DOMAIN, "EFI labeled devices are not supported on root " "pools.")); diff --git a/lib/libzfs/common/libzfs_sendrecv.c b/lib/libzfs/common/libzfs_sendrecv.c index ee6e64319e40..3093ab974d06 100644 --- a/lib/libzfs/common/libzfs_sendrecv.c +++ b/lib/libzfs/common/libzfs_sendrecv.c @@ -21,8 +21,6 @@ /* * Copyright (c) 2005, 2010, Oracle and/or its affiliates. All rights reserved. - * Copyright (c) 2012 by Delphix. All rights reserved. - * Copyright (c) 2012, Joyent, Inc. All rights reserved. */ #include <assert.h> @@ -38,7 +36,6 @@ #include <sys/mount.h> #include <pthread.h> #include <umem.h> -#include <time.h> #include <libzfs.h> @@ -53,7 +50,7 @@ /* in libzfs_dataset.c */ extern void zfs_setprop_error(libzfs_handle_t *, zfs_prop_t, int, char *); -static int zfs_receive_impl(libzfs_handle_t *, const char *, recvflags_t *, +static int zfs_receive_impl(libzfs_handle_t *, const char *, recvflags_t, int, const char *, nvlist_t *, avl_tree_t *, char **, int, uint64_t *); static const zio_cksum_t zero_cksum = { 0 }; @@ -64,12 +61,6 @@ typedef struct dedup_arg { libzfs_handle_t *dedup_hdl; } dedup_arg_t; -typedef struct progress_arg { - zfs_handle_t *pa_zhp; - int pa_fd; - boolean_t pa_parsable; -} progress_arg_t; - typedef struct dataref { uint64_t ref_guid; uint64_t ref_object; @@ -780,6 +771,88 @@ gather_nvlist(libzfs_handle_t *hdl, const char *fsname, const char *fromsnap, } /* + * Routines for dealing with the sorted snapshot functionality + */ +typedef struct zfs_node { + zfs_handle_t *zn_handle; + avl_node_t zn_avlnode; +} zfs_node_t; + +static int +zfs_sort_snaps(zfs_handle_t *zhp, void *data) +{ + avl_tree_t *avl = data; + zfs_node_t *node; + zfs_node_t search; + + search.zn_handle = zhp; + node = avl_find(avl, &search, NULL); + if (node) { + /* + * If this snapshot was renamed while we were creating the + * AVL tree, it's possible that we already inserted it under + * its old name. Remove the old handle before adding the new + * one. + */ + zfs_close(node->zn_handle); + avl_remove(avl, node); + free(node); + } + + node = zfs_alloc(zhp->zfs_hdl, sizeof (zfs_node_t)); + node->zn_handle = zhp; + avl_add(avl, node); + + return (0); +} + +static int +zfs_snapshot_compare(const void *larg, const void *rarg) +{ + zfs_handle_t *l = ((zfs_node_t *)larg)->zn_handle; + zfs_handle_t *r = ((zfs_node_t *)rarg)->zn_handle; + uint64_t lcreate, rcreate; + + /* + * Sort them according to creation time. We use the hidden + * CREATETXG property to get an absolute ordering of snapshots. + */ + lcreate = zfs_prop_get_int(l, ZFS_PROP_CREATETXG); + rcreate = zfs_prop_get_int(r, ZFS_PROP_CREATETXG); + + if (lcreate < rcreate) + return (-1); + else if (lcreate > rcreate) + return (+1); + else + return (0); +} + +int +zfs_iter_snapshots_sorted(zfs_handle_t *zhp, zfs_iter_f callback, void *data) +{ + int ret = 0; + zfs_node_t *node; + avl_tree_t avl; + void *cookie = NULL; + + avl_create(&avl, zfs_snapshot_compare, + sizeof (zfs_node_t), offsetof(zfs_node_t, zn_avlnode)); + + ret = zfs_iter_snapshots(zhp, zfs_sort_snaps, &avl); + + for (node = avl_first(&avl); node != NULL; node = AVL_NEXT(&avl, node)) + ret |= callback(node->zn_handle, data); + + while ((node = avl_destroy_nodes(&avl, &cookie)) != NULL) + free(node); + + avl_destroy(&avl); + + return (ret); +} + +/* * Routines specific to "zfs send" */ typedef struct send_dump_data { @@ -789,7 +862,7 @@ typedef struct send_dump_data { char prevsnap[ZFS_MAXNAMELEN]; uint64_t prevsnap_obj; boolean_t seenfrom, seento, replicate, doall, fromorigin; - boolean_t verbose, dryrun, parsable, progress; + boolean_t verbose; int outfd; boolean_t err; nvlist_t *fss; @@ -799,69 +872,8 @@ typedef struct send_dump_data { nvlist_t *debugnv; char holdtag[ZFS_MAXNAMELEN]; int cleanup_fd; - uint64_t size; } send_dump_data_t; -static int -estimate_ioctl(zfs_handle_t *zhp, uint64_t fromsnap_obj, - boolean_t fromorigin, uint64_t *sizep) -{ - zfs_cmd_t zc = { 0 }; - libzfs_handle_t *hdl = zhp->zfs_hdl; - - assert(zhp->zfs_type == ZFS_TYPE_SNAPSHOT); - assert(fromsnap_obj == 0 || !fromorigin); - - (void) strlcpy(zc.zc_name, zhp->zfs_name, sizeof (zc.zc_name)); - zc.zc_obj = fromorigin; - zc.zc_sendobj = zfs_prop_get_int(zhp, ZFS_PROP_OBJSETID); - zc.zc_fromobj = fromsnap_obj; - zc.zc_guid = 1; /* estimate flag */ - - if (zfs_ioctl(zhp->zfs_hdl, ZFS_IOC_SEND, &zc) != 0) { - char errbuf[1024]; - (void) snprintf(errbuf, sizeof (errbuf), dgettext(TEXT_DOMAIN, - "warning: cannot estimate space for '%s'"), zhp->zfs_name); - - switch (errno) { - case EXDEV: - zfs_error_aux(hdl, dgettext(TEXT_DOMAIN, - "not an earlier snapshot from the same fs")); - return (zfs_error(hdl, EZFS_CROSSTARGET, errbuf)); - - case ENOENT: - if (zfs_dataset_exists(hdl, zc.zc_name, - ZFS_TYPE_SNAPSHOT)) { - zfs_error_aux(hdl, dgettext(TEXT_DOMAIN, - "incremental source (@%s) does not exist"), - zc.zc_value); - } - return (zfs_error(hdl, EZFS_NOENT, errbuf)); - - case EDQUOT: - case EFBIG: - case EIO: - case ENOLINK: - case ENOSPC: - case ENOSTR: - case ENXIO: - case EPIPE: - case ERANGE: - case EFAULT: - case EROFS: - zfs_error_aux(hdl, strerror(errno)); - return (zfs_error(hdl, EZFS_BADBACKUP, errbuf)); - - default: - return (zfs_standard_error(hdl, errno, errbuf)); - } - } - - *sizep = zc.zc_objset_type; - - return (0); -} - /* * Dumps a backup of the given snapshot (incremental from fromsnap if it's not * NULL) to the file descriptor specified by outfd. @@ -889,7 +901,7 @@ dump_ioctl(zfs_handle_t *zhp, const char *fromsnap, uint64_t fromsnap_obj, "fromsnap", fromsnap)); } - if (zfs_ioctl(zhp->zfs_hdl, ZFS_IOC_SEND, &zc) != 0) { + if (ioctl(zhp->zfs_hdl->libzfs_fd, ZFS_IOC_SEND, &zc) != 0) { char errbuf[1024]; (void) snprintf(errbuf, sizeof (errbuf), dgettext(TEXT_DOMAIN, "warning: cannot send '%s'"), zhp->zfs_name); @@ -902,6 +914,7 @@ dump_ioctl(zfs_handle_t *zhp, const char *fromsnap, uint64_t fromsnap_obj, nvlist_free(thisdbg); switch (errno) { + case EXDEV: zfs_error_aux(hdl, dgettext(TEXT_DOMAIN, "not an earlier snapshot from the same fs")); @@ -951,9 +964,6 @@ hold_for_send(zfs_handle_t *zhp, send_dump_data_t *sdd) assert(zhp->zfs_type == ZFS_TYPE_SNAPSHOT); - if (sdd->dryrun) - return (0); - /* * zfs_send() only opens a cleanup_fd for sends that need it, * e.g. replication and doall. @@ -981,63 +991,13 @@ hold_for_send(zfs_handle_t *zhp, send_dump_data_t *sdd) return (error); } -static void * -send_progress_thread(void *arg) -{ - progress_arg_t *pa = arg; - - zfs_cmd_t zc = { 0 }; - zfs_handle_t *zhp = pa->pa_zhp; - libzfs_handle_t *hdl = zhp->zfs_hdl; - unsigned long long bytes; - char buf[16]; - - time_t t; - struct tm *tm; - - assert(zhp->zfs_type == ZFS_TYPE_SNAPSHOT); - (void) strlcpy(zc.zc_name, zhp->zfs_name, sizeof (zc.zc_name)); - - if (!pa->pa_parsable) - (void) fprintf(stderr, "TIME SENT SNAPSHOT\n"); - - /* - * Print the progress from ZFS_IOC_SEND_PROGRESS every second. - */ - for (;;) { - (void) sleep(1); - - zc.zc_cookie = pa->pa_fd; - if (zfs_ioctl(hdl, ZFS_IOC_SEND_PROGRESS, &zc) != 0) - return ((void *)-1); - - (void) time(&t); - tm = localtime(&t); - bytes = zc.zc_cookie; - - if (pa->pa_parsable) { - (void) fprintf(stderr, "%02d:%02d:%02d\t%llu\t%s\n", - tm->tm_hour, tm->tm_min, tm->tm_sec, - bytes, zhp->zfs_name); - } else { - zfs_nicenum(bytes, buf, sizeof (buf)); - (void) fprintf(stderr, "%02d:%02d:%02d %5s %s\n", - tm->tm_hour, tm->tm_min, tm->tm_sec, - buf, zhp->zfs_name); - } - } -} - static int dump_snapshot(zfs_handle_t *zhp, void *arg) { send_dump_data_t *sdd = arg; - progress_arg_t pa = { 0 }; - pthread_t tid; - char *thissnap; int err; - boolean_t isfromsnap, istosnap, fromorigin; + boolean_t isfromsnap, istosnap; boolean_t exclude = B_FALSE; thissnap = strchr(zhp->zfs_name, '@') + 1; @@ -1114,68 +1074,15 @@ dump_snapshot(zfs_handle_t *zhp, void *arg) return (err); } - fromorigin = sdd->prevsnap[0] == '\0' && - (sdd->fromorigin || sdd->replicate); - + /* send it */ if (sdd->verbose) { - uint64_t size; - err = estimate_ioctl(zhp, sdd->prevsnap_obj, - fromorigin, &size); - - if (sdd->parsable) { - if (sdd->prevsnap[0] != '\0') { - (void) fprintf(stderr, "incremental\t%s\t%s", - sdd->prevsnap, zhp->zfs_name); - } else { - (void) fprintf(stderr, "full\t%s", - zhp->zfs_name); - } - } else { - (void) fprintf(stderr, dgettext(TEXT_DOMAIN, - "send from @%s to %s"), - sdd->prevsnap, zhp->zfs_name); - } - if (err == 0) { - if (sdd->parsable) { - (void) fprintf(stderr, "\t%llu\n", - (longlong_t)size); - } else { - char buf[16]; - zfs_nicenum(size, buf, sizeof (buf)); - (void) fprintf(stderr, dgettext(TEXT_DOMAIN, - " estimated size is %s\n"), buf); - } - sdd->size += size; - } else { - (void) fprintf(stderr, "\n"); - } + (void) fprintf(stderr, "sending from @%s to %s\n", + sdd->prevsnap, zhp->zfs_name); } - if (!sdd->dryrun) { - /* - * If progress reporting is requested, spawn a new thread to - * poll ZFS_IOC_SEND_PROGRESS at a regular interval. - */ - if (sdd->progress) { - pa.pa_zhp = zhp; - pa.pa_fd = sdd->outfd; - pa.pa_parsable = sdd->parsable; - - if (err = pthread_create(&tid, NULL, - send_progress_thread, &pa)) { - zfs_close(zhp); - return (err); - } - } - - err = dump_ioctl(zhp, sdd->prevsnap, sdd->prevsnap_obj, - fromorigin, sdd->outfd, sdd->debugnv); - - if (sdd->progress) { - (void) pthread_cancel(tid); - (void) pthread_join(tid, NULL); - } - } + err = dump_ioctl(zhp, sdd->prevsnap, sdd->prevsnap_obj, + sdd->prevsnap[0] == '\0' && (sdd->fromorigin || sdd->replicate), + sdd->outfd, sdd->debugnv); (void) strcpy(sdd->prevsnap, thissnap); sdd->prevsnap_obj = zfs_prop_get_int(zhp, ZFS_PROP_OBJSETID); @@ -1194,8 +1101,8 @@ dump_filesystem(zfs_handle_t *zhp, void *arg) (void) snprintf(zc.zc_name, sizeof (zc.zc_name), "%s@%s", zhp->zfs_name, sdd->tosnap); if (ioctl(zhp->zfs_hdl->libzfs_fd, ZFS_IOC_OBJSET_STATS, &zc) != 0) { - (void) fprintf(stderr, dgettext(TEXT_DOMAIN, - "WARNING: could not send %s@%s: does not exist\n"), + (void) fprintf(stderr, "WARNING: " + "could not send %s@%s: does not exist\n", zhp->zfs_name, sdd->tosnap); sdd->err = B_TRUE; return (0); @@ -1224,24 +1131,23 @@ dump_filesystem(zfs_handle_t *zhp, void *arg) rv = zfs_iter_snapshots_sorted(zhp, dump_snapshot, arg); if (!sdd->seenfrom) { - (void) fprintf(stderr, dgettext(TEXT_DOMAIN, + (void) fprintf(stderr, "WARNING: could not send %s@%s:\n" - "incremental source (%s@%s) does not exist\n"), + "incremental source (%s@%s) does not exist\n", zhp->zfs_name, sdd->tosnap, zhp->zfs_name, sdd->fromsnap); sdd->err = B_TRUE; } else if (!sdd->seento) { if (sdd->fromsnap) { - (void) fprintf(stderr, dgettext(TEXT_DOMAIN, + (void) fprintf(stderr, "WARNING: could not send %s@%s:\n" "incremental source (%s@%s) " - "is not earlier than it\n"), + "is not earlier than it\n", zhp->zfs_name, sdd->tosnap, zhp->zfs_name, sdd->fromsnap); } else { - (void) fprintf(stderr, dgettext(TEXT_DOMAIN, - "WARNING: " - "could not send %s@%s: does not exist\n"), + (void) fprintf(stderr, "WARNING: " + "could not send %s@%s: does not exist\n", zhp->zfs_name, sdd->tosnap); } sdd->err = B_TRUE; @@ -1287,12 +1193,11 @@ again: needagain = progress = B_FALSE; for (fspair = nvlist_next_nvpair(sdd->fss, NULL); fspair; fspair = nvlist_next_nvpair(sdd->fss, fspair)) { - nvlist_t *fslist, *parent_nv; + nvlist_t *fslist; char *fsname; zfs_handle_t *zhp; int err; uint64_t origin_guid = 0; - uint64_t parent_guid = 0; VERIFY(nvpair_value_nvlist(fspair, &fslist) == 0); if (nvlist_lookup_boolean(fslist, "sent") == 0) @@ -1300,23 +1205,13 @@ again: VERIFY(nvlist_lookup_string(fslist, "name", &fsname) == 0); (void) nvlist_lookup_uint64(fslist, "origin", &origin_guid); - (void) nvlist_lookup_uint64(fslist, "parentfromsnap", - &parent_guid); - - if (parent_guid != 0) { - parent_nv = fsavl_find(sdd->fsavl, parent_guid, NULL); - if (!nvlist_exists(parent_nv, "sent")) { - /* parent has not been sent; skip this one */ - needagain = B_TRUE; - continue; - } - } if (origin_guid != 0) { nvlist_t *origin_nv = fsavl_find(sdd->fsavl, origin_guid, NULL); if (origin_nv != NULL && - !nvlist_exists(origin_nv, "sent")) { + nvlist_lookup_boolean(origin_nv, + "sent") == ENOENT) { /* * origin has not been sent yet; * skip this clone. @@ -1340,16 +1235,6 @@ again: assert(progress); goto again; } - - /* clean out the sent flags in case we reuse this fss */ - for (fspair = nvlist_next_nvpair(sdd->fss, NULL); fspair; - fspair = nvlist_next_nvpair(sdd->fss, fspair)) { - nvlist_t *fslist; - - VERIFY(nvpair_value_nvlist(fspair, &fslist) == 0); - (void) nvlist_remove_all(fslist, "sent"); - } - return (0); } @@ -1371,16 +1256,17 @@ again: */ int zfs_send(zfs_handle_t *zhp, const char *fromsnap, const char *tosnap, - sendflags_t *flags, int outfd, snapfilter_cb_t filter_func, + sendflags_t flags, int outfd, snapfilter_cb_t filter_func, void *cb_arg, nvlist_t **debugnvp) { char errbuf[1024]; send_dump_data_t sdd = { 0 }; - int err = 0; + int err; nvlist_t *fss = NULL; avl_tree_t *fsavl = NULL; static uint64_t holdseq; int spa_version; + boolean_t holdsnaps = B_FALSE; pthread_t tid; int pipefd[2]; dedup_arg_t dda = { 0 }; @@ -1403,7 +1289,12 @@ zfs_send(zfs_handle_t *zhp, const char *fromsnap, const char *tosnap, } } - if (flags->dedup && !flags->dryrun) { + if (zfs_spa_version(zhp, &spa_version) == 0 && + spa_version >= SPA_VERSION_USERREFS && + (flags.doall || flags.replicate)) + holdsnaps = B_TRUE; + + if (flags.dedup) { featureflags |= (DMU_BACKUP_FEATURE_DEDUP | DMU_BACKUP_FEATURE_DEDUPPROPS); if (err = pipe(pipefd)) { @@ -1423,13 +1314,13 @@ zfs_send(zfs_handle_t *zhp, const char *fromsnap, const char *tosnap, } } - if (flags->replicate || flags->doall || flags->props) { + if (flags.replicate || flags.doall || flags.props) { dmu_replay_record_t drr = { 0 }; char *packbuf = NULL; size_t buflen = 0; zio_cksum_t zc = { 0 }; - if (flags->replicate || flags->props) { + if (flags.replicate || flags.props) { nvlist_t *hdrnv; VERIFY(0 == nvlist_alloc(&hdrnv, NV_UNIQUE_NAME, 0)); @@ -1438,13 +1329,13 @@ zfs_send(zfs_handle_t *zhp, const char *fromsnap, const char *tosnap, "fromsnap", fromsnap)); } VERIFY(0 == nvlist_add_string(hdrnv, "tosnap", tosnap)); - if (!flags->replicate) { + if (!flags.replicate) { VERIFY(0 == nvlist_add_boolean(hdrnv, "not_recursive")); } err = gather_nvlist(zhp->zfs_hdl, zhp->zfs_name, - fromsnap, tosnap, flags->replicate, &fss, &fsavl); + fromsnap, tosnap, flags.replicate, &fss, &fsavl); if (err) goto err_out; VERIFY(0 == nvlist_add_nvlist(hdrnv, "fss", fss)); @@ -1461,34 +1352,33 @@ zfs_send(zfs_handle_t *zhp, const char *fromsnap, const char *tosnap, } } - if (!flags->dryrun) { - /* write first begin record */ - drr.drr_type = DRR_BEGIN; - drr.drr_u.drr_begin.drr_magic = DMU_BACKUP_MAGIC; - DMU_SET_STREAM_HDRTYPE(drr.drr_u.drr_begin. - drr_versioninfo, DMU_COMPOUNDSTREAM); - DMU_SET_FEATUREFLAGS(drr.drr_u.drr_begin. - drr_versioninfo, featureflags); - (void) snprintf(drr.drr_u.drr_begin.drr_toname, - sizeof (drr.drr_u.drr_begin.drr_toname), - "%s@%s", zhp->zfs_name, tosnap); - drr.drr_payloadlen = buflen; - err = cksum_and_write(&drr, sizeof (drr), &zc, outfd); - - /* write header nvlist */ - if (err != -1 && packbuf != NULL) { - err = cksum_and_write(packbuf, buflen, &zc, - outfd); - } - free(packbuf); - if (err == -1) { - fsavl_destroy(fsavl); - nvlist_free(fss); - err = errno; - goto stderr_out; - } + /* write first begin record */ + drr.drr_type = DRR_BEGIN; + drr.drr_u.drr_begin.drr_magic = DMU_BACKUP_MAGIC; + DMU_SET_STREAM_HDRTYPE(drr.drr_u.drr_begin.drr_versioninfo, + DMU_COMPOUNDSTREAM); + DMU_SET_FEATUREFLAGS(drr.drr_u.drr_begin.drr_versioninfo, + featureflags); + (void) snprintf(drr.drr_u.drr_begin.drr_toname, + sizeof (drr.drr_u.drr_begin.drr_toname), + "%s@%s", zhp->zfs_name, tosnap); + drr.drr_payloadlen = buflen; + err = cksum_and_write(&drr, sizeof (drr), &zc, outfd); + + /* write header nvlist */ + if (err != -1 && packbuf != NULL) { + err = cksum_and_write(packbuf, buflen, &zc, outfd); + } + free(packbuf); + if (err == -1) { + fsavl_destroy(fsavl); + nvlist_free(fss); + err = errno; + goto stderr_out; + } - /* write end record */ + /* write end record */ + if (err != -1) { bzero(&drr, sizeof (drr)); drr.drr_type = DRR_END; drr.drr_u.drr_end.drr_checksum = zc; @@ -1499,43 +1389,27 @@ zfs_send(zfs_handle_t *zhp, const char *fromsnap, const char *tosnap, err = errno; goto stderr_out; } - - err = 0; } } /* dump each stream */ sdd.fromsnap = fromsnap; sdd.tosnap = tosnap; - if (flags->dedup) + if (flags.dedup) sdd.outfd = pipefd[0]; else sdd.outfd = outfd; - sdd.replicate = flags->replicate; - sdd.doall = flags->doall; - sdd.fromorigin = flags->fromorigin; + sdd.replicate = flags.replicate; + sdd.doall = flags.doall; + sdd.fromorigin = flags.fromorigin; sdd.fss = fss; sdd.fsavl = fsavl; - sdd.verbose = flags->verbose; - sdd.parsable = flags->parsable; - sdd.progress = flags->progress; - sdd.dryrun = flags->dryrun; + sdd.verbose = flags.verbose; sdd.filter_cb = filter_func; sdd.filter_cb_arg = cb_arg; if (debugnvp) sdd.debugnv = *debugnvp; - - /* - * 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)) { + if (holdsnaps) { ++holdseq; (void) snprintf(sdd.holdtag, sizeof (sdd.holdtag), ".send-%d-%llu", getpid(), (u_longlong_t)holdseq); @@ -1547,31 +1421,11 @@ zfs_send(zfs_handle_t *zhp, const char *fromsnap, const char *tosnap, } else { sdd.cleanup_fd = -1; } - if (flags->verbose) { - /* - * Do a verbose no-op dry run to get all the verbose output - * before generating any data. Then do a non-verbose real - * run to generate the streams. - */ - sdd.dryrun = B_TRUE; - err = dump_filesystems(zhp, &sdd); - sdd.dryrun = flags->dryrun; - sdd.verbose = B_FALSE; - if (flags->parsable) { - (void) fprintf(stderr, "size\t%llu\n", - (longlong_t)sdd.size); - } else { - char buf[16]; - zfs_nicenum(sdd.size, buf, sizeof (buf)); - (void) fprintf(stderr, dgettext(TEXT_DOMAIN, - "total estimated size is %s\n"), buf); - } - } err = dump_filesystems(zhp, &sdd); fsavl_destroy(fsavl); nvlist_free(fss); - if (flags->dedup) { + if (flags.dedup) { (void) close(pipefd[0]); (void) pthread_join(tid, NULL); } @@ -1581,8 +1435,7 @@ zfs_send(zfs_handle_t *zhp, const char *fromsnap, const char *tosnap, sdd.cleanup_fd = -1; } - if (!flags->dryrun && (flags->replicate || flags->doall || - flags->props)) { + if (flags.replicate || flags.doall || flags.props) { /* * write final end record. NB: want to do this even if * there was some error, because it might not be totally @@ -1603,7 +1456,7 @@ stderr_out: err_out: if (sdd.cleanup_fd != -1) VERIFY(0 == close(sdd.cleanup_fd)); - if (flags->dedup) { + if (flags.dedup) { (void) pthread_cancel(tid); (void) pthread_join(tid, NULL); (void) close(pipefd[0]); @@ -1674,7 +1527,7 @@ recv_read_nvlist(libzfs_handle_t *hdl, int fd, int len, nvlist_t **nvp, static int recv_rename(libzfs_handle_t *hdl, const char *name, const char *tryname, - int baselen, char *newname, recvflags_t *flags) + int baselen, char *newname, recvflags_t flags) { static int seq; zfs_cmd_t zc = { 0 }; @@ -1686,7 +1539,7 @@ recv_rename(libzfs_handle_t *hdl, const char *name, const char *tryname, if (zhp == NULL) return (-1); clp = changelist_gather(zhp, ZFS_PROP_NAME, 0, - flags->force ? MS_FORCE : 0); + flags.force ? MS_FORCE : 0); zfs_close(zhp); if (clp == NULL) return (-1); @@ -1702,7 +1555,7 @@ recv_rename(libzfs_handle_t *hdl, const char *name, const char *tryname, (void) strlcpy(zc.zc_value, tryname, sizeof (zc.zc_value)); - if (flags->verbose) { + if (flags.verbose) { (void) printf("attempting rename %s to %s\n", zc.zc_name, zc.zc_value); } @@ -1721,19 +1574,19 @@ recv_rename(libzfs_handle_t *hdl, const char *name, const char *tryname, "recv-%u-%u", getpid(), seq); (void) strlcpy(zc.zc_value, newname, sizeof (zc.zc_value)); - if (flags->verbose) { + if (flags.verbose) { (void) printf("failed - trying rename %s to %s\n", zc.zc_name, zc.zc_value); } err = ioctl(hdl->libzfs_fd, ZFS_IOC_RENAME, &zc); if (err == 0) changelist_rename(clp, name, newname); - if (err && flags->verbose) { + if (err && flags.verbose) { (void) printf("failed (%u) - " "will try again on next pass\n", errno); } err = EAGAIN; - } else if (flags->verbose) { + } else if (flags.verbose) { if (err == 0) (void) printf("success\n"); else @@ -1748,7 +1601,7 @@ recv_rename(libzfs_handle_t *hdl, const char *name, const char *tryname, static int recv_destroy(libzfs_handle_t *hdl, const char *name, int baselen, - char *newname, recvflags_t *flags) + char *newname, recvflags_t flags) { zfs_cmd_t zc = { 0 }; int err = 0; @@ -1761,7 +1614,7 @@ recv_destroy(libzfs_handle_t *hdl, const char *name, int baselen, if (zhp == NULL) return (-1); clp = changelist_gather(zhp, ZFS_PROP_NAME, 0, - flags->force ? MS_FORCE : 0); + flags.force ? MS_FORCE : 0); if (zfs_get_type(zhp) == ZFS_TYPE_SNAPSHOT && zfs_spa_version(zhp, &spa_version) == 0 && spa_version >= SPA_VERSION_USERREFS) @@ -1777,11 +1630,11 @@ recv_destroy(libzfs_handle_t *hdl, const char *name, int baselen, zc.zc_defer_destroy = defer; (void) strlcpy(zc.zc_name, name, sizeof (zc.zc_name)); - if (flags->verbose) + if (flags.verbose) (void) printf("attempting destroy %s\n", zc.zc_name); err = ioctl(hdl->libzfs_fd, ZFS_IOC_DESTROY, &zc); if (err == 0) { - if (flags->verbose) + if (flags.verbose) (void) printf("success\n"); changelist_remove(clp, zc.zc_name); } @@ -1804,7 +1657,6 @@ recv_destroy(libzfs_handle_t *hdl, const char *name, int baselen, typedef struct guid_to_name_data { uint64_t guid; char *name; - char *skip; } guid_to_name_data_t; static int @@ -1813,35 +1665,21 @@ guid_to_name_cb(zfs_handle_t *zhp, void *arg) guid_to_name_data_t *gtnd = arg; int err; - if (gtnd->skip != NULL && - strcmp(zhp->zfs_name, gtnd->skip) == 0) { - return (0); - } - if (zhp->zfs_dmustats.dds_guid == gtnd->guid) { (void) strcpy(gtnd->name, zhp->zfs_name); zfs_close(zhp); return (EEXIST); } - err = zfs_iter_children(zhp, guid_to_name_cb, gtnd); zfs_close(zhp); return (err); } -/* - * Attempt to find the local dataset associated with this guid. In the case of - * multiple matches, we attempt to find the "best" match by searching - * progressively larger portions of the hierarchy. This allows one to send a - * tree of datasets individually and guarantee that we will find the source - * guid within that hierarchy, even if there are multiple matches elsewhere. - */ static int guid_to_name(libzfs_handle_t *hdl, const char *parent, uint64_t guid, char *name) { /* exhaustive search all local snapshots */ - char pname[ZFS_MAXNAMELEN]; guid_to_name_data_t gtnd; int err = 0; zfs_handle_t *zhp; @@ -1849,42 +1687,35 @@ guid_to_name(libzfs_handle_t *hdl, const char *parent, uint64_t guid, gtnd.guid = guid; gtnd.name = name; - gtnd.skip = NULL; - (void) strlcpy(pname, parent, sizeof (pname)); - - /* - * Search progressively larger portions of the hierarchy. This will - * select the "most local" version of the origin snapshot in the case - * that there are multiple matching snapshots in the system. - */ - while ((cp = strrchr(pname, '/')) != NULL) { + if (strchr(parent, '@') == NULL) { + zhp = make_dataset_handle(hdl, parent); + if (zhp != NULL) { + err = zfs_iter_children(zhp, guid_to_name_cb, >nd); + zfs_close(zhp); + if (err == EEXIST) + return (0); + } + } - /* Chop off the last component and open the parent */ + cp = strchr(parent, '/'); + if (cp) *cp = '\0'; - zhp = make_dataset_handle(hdl, pname); - - if (zhp == NULL) - continue; + zhp = make_dataset_handle(hdl, parent); + if (cp) + *cp = '/'; + if (zhp) { err = zfs_iter_children(zhp, guid_to_name_cb, >nd); zfs_close(zhp); - if (err == EEXIST) - return (0); - - /* - * Remember the dataset that we already searched, so we - * skip it next time through. - */ - gtnd.skip = pname; } - return (ENOENT); + return (err == EEXIST ? 0 : ENOENT); + } /* - * Return +1 if guid1 is before guid2, 0 if they are the same, and -1 if - * guid1 is after guid2. + * Return true if dataset guid1 is created before guid2. */ static int created_before(libzfs_handle_t *hdl, avl_tree_t *avl, @@ -1894,8 +1725,7 @@ created_before(libzfs_handle_t *hdl, avl_tree_t *avl, char *fsname, *snapname; char buf[ZFS_MAXNAMELEN]; int rv; - zfs_handle_t *guid1hdl, *guid2hdl; - uint64_t create1, create2; + zfs_node_t zn1, zn2; if (guid2 == 0) return (0); @@ -1905,38 +1735,30 @@ created_before(libzfs_handle_t *hdl, avl_tree_t *avl, nvfs = fsavl_find(avl, guid1, &snapname); VERIFY(0 == nvlist_lookup_string(nvfs, "name", &fsname)); (void) snprintf(buf, sizeof (buf), "%s@%s", fsname, snapname); - guid1hdl = zfs_open(hdl, buf, ZFS_TYPE_SNAPSHOT); - if (guid1hdl == NULL) + zn1.zn_handle = zfs_open(hdl, buf, ZFS_TYPE_SNAPSHOT); + if (zn1.zn_handle == NULL) return (-1); nvfs = fsavl_find(avl, guid2, &snapname); VERIFY(0 == nvlist_lookup_string(nvfs, "name", &fsname)); (void) snprintf(buf, sizeof (buf), "%s@%s", fsname, snapname); - guid2hdl = zfs_open(hdl, buf, ZFS_TYPE_SNAPSHOT); - if (guid2hdl == NULL) { - zfs_close(guid1hdl); + zn2.zn_handle = zfs_open(hdl, buf, ZFS_TYPE_SNAPSHOT); + if (zn2.zn_handle == NULL) { + zfs_close(zn2.zn_handle); return (-1); } - create1 = zfs_prop_get_int(guid1hdl, ZFS_PROP_CREATETXG); - create2 = zfs_prop_get_int(guid2hdl, ZFS_PROP_CREATETXG); + rv = (zfs_snapshot_compare(&zn1, &zn2) == -1); - if (create1 < create2) - rv = -1; - else if (create1 > create2) - rv = +1; - else - rv = 0; - - zfs_close(guid1hdl); - zfs_close(guid2hdl); + zfs_close(zn1.zn_handle); + zfs_close(zn2.zn_handle); return (rv); } static int recv_incremental_replication(libzfs_handle_t *hdl, const char *tofs, - recvflags_t *flags, nvlist_t *stream_nv, avl_tree_t *stream_avl, + recvflags_t flags, nvlist_t *stream_nv, avl_tree_t *stream_avl, nvlist_t *renamed) { nvlist_t *local_nv; @@ -1953,7 +1775,7 @@ recv_incremental_replication(libzfs_handle_t *hdl, const char *tofs, recursive = (nvlist_lookup_boolean(stream_nv, "not_recursive") == ENOENT); - if (flags->dryrun) + if (flags.dryrun) return (0); again: @@ -2013,7 +1835,7 @@ again: nvlist_t *origin_nvfs; char *origin_fsname; - if (flags->verbose) + if (flags.verbose) (void) printf("promoting %s\n", fsname); origin_nvfs = fsavl_find(local_avl, originguid, @@ -2061,7 +1883,7 @@ again: if (found == NULL) { char name[ZFS_MAXNAMELEN]; - if (!flags->force) + if (!flags.force) continue; (void) snprintf(name, sizeof (name), "%s@%s", @@ -2119,7 +1941,7 @@ again: /* check for delete */ if (stream_nvfs == NULL) { - if (!flags->force) + if (!flags.force) continue; error = recv_destroy(hdl, fsname, strlen(tofs)+1, @@ -2132,7 +1954,7 @@ again: } if (fromguid == 0) { - if (flags->verbose) { + if (flags.verbose) { (void) printf("local fs %s does not have " "fromsnap (%s in stream); must have " "been deleted locally; ignoring\n", @@ -2157,7 +1979,7 @@ again: if ((stream_parent_fromsnap_guid != 0 && parent_fromsnap_guid != 0 && stream_parent_fromsnap_guid != parent_fromsnap_guid) || - ((flags->isprefix || strcmp(tofs, fsname) != 0) && + ((flags.isprefix || strcmp(tofs, fsname) != 0) && (s1 != NULL) && (s2 != NULL) && strcmp(s1, s2) != 0)) { nvlist_t *parent; char tryname[ZFS_MAXNAMELEN]; @@ -2180,7 +2002,7 @@ again: "%s%s", pname, strrchr(stream_fsname, '/')); } else { tryname[0] = '\0'; - if (flags->verbose) { + if (flags.verbose) { (void) printf("local fs %s new parent " "not found\n", fsname); } @@ -2208,7 +2030,7 @@ again: if (needagain && progress) { /* do another pass to fix up temporary names */ - if (flags->verbose) + if (flags.verbose) (void) printf("another pass:\n"); goto again; } @@ -2218,7 +2040,7 @@ again: static int zfs_receive_package(libzfs_handle_t *hdl, int fd, const char *destname, - recvflags_t *flags, dmu_replay_record_t *drr, zio_cksum_t *zc, + recvflags_t flags, dmu_replay_record_t *drr, zio_cksum_t *zc, char **top_zfs, int cleanup_fd, uint64_t *action_handlep) { nvlist_t *stream_nv = NULL; @@ -2247,7 +2069,7 @@ zfs_receive_package(libzfs_handle_t *hdl, int fd, const char *destname, */ if (drr->drr_payloadlen != 0) { error = recv_read_nvlist(hdl, fd, drr->drr_payloadlen, - &stream_nv, flags->byteswap, zc); + &stream_nv, flags.byteswap, zc); if (error) { error = zfs_error(hdl, EZFS_BADSTREAM, errbuf); goto out; @@ -2268,9 +2090,9 @@ zfs_receive_package(libzfs_handle_t *hdl, int fd, const char *destname, * Read in the end record and verify checksum. */ if (0 != (error = recv_read(hdl, fd, &drre, sizeof (drre), - flags->byteswap, NULL))) + flags.byteswap, NULL))) goto out; - if (flags->byteswap) { + if (flags.byteswap) { drre.drr_type = BSWAP_32(drre.drr_type); drre.drr_u.drr_end.drr_checksum.zc_word[0] = BSWAP_64(drre.drr_u.drr_end.drr_checksum.zc_word[0]); @@ -2311,11 +2133,11 @@ zfs_receive_package(libzfs_handle_t *hdl, int fd, const char *destname, nvpair_t *pair = NULL; (void) strlcpy(tofs, destname, ZFS_MAXNAMELEN); - if (flags->isprefix) { + if (flags.isprefix) { struct drr_begin *drrb = &drr->drr_u.drr_begin; int i; - if (flags->istail) { + if (flags.istail) { cp = strrchr(drrb->drr_toname, '/'); if (cp == NULL) { (void) strlcat(tofs, "/", @@ -2333,7 +2155,7 @@ zfs_receive_package(libzfs_handle_t *hdl, int fd, const char *destname, *strchr(tofs, '@') = '\0'; } - if (recursive && !flags->dryrun && !flags->nomount) { + if (recursive && !flags.dryrun && !flags.nomount) { VERIFY(0 == nvlist_alloc(&renamed, NV_UNIQUE_NAME, 0)); } @@ -2507,7 +2329,7 @@ recv_skip(libzfs_handle_t *hdl, int fd, boolean_t byteswap) */ static int zfs_receive_one(libzfs_handle_t *hdl, int infd, const char *tosnap, - recvflags_t *flags, dmu_replay_record_t *drr, + recvflags_t flags, dmu_replay_record_t *drr, dmu_replay_record_t *drr_noswap, const char *sendfs, nvlist_t *stream_nv, avl_tree_t *stream_avl, char **top_zfs, int cleanup_fd, uint64_t *action_handlep) @@ -2549,7 +2371,7 @@ zfs_receive_one(libzfs_handle_t *hdl, int infd, const char *tosnap, if (err) VERIFY(0 == nvlist_alloc(&props, NV_UNIQUE_NAME, 0)); - if (flags->canmountoff) { + if (flags.canmountoff) { VERIFY(0 == nvlist_add_uint64(props, zfs_prop_to_name(ZFS_PROP_CANMOUNT), 0)); } @@ -2576,7 +2398,7 @@ zfs_receive_one(libzfs_handle_t *hdl, int infd, const char *tosnap, * If they specified a snapshot, chop the entire name stored in * the stream. */ - if (flags->istail) { + if (flags.istail) { /* * A filesystem was specified with -e. We want to tack on only * the tail of the sent snapshot path. @@ -2602,7 +2424,7 @@ zfs_receive_one(libzfs_handle_t *hdl, int infd, const char *tosnap, } else { chopprefix = drrb->drr_toname + (chopprefix - sendfs); } - } else if (flags->isprefix) { + } else if (flags.isprefix) { /* * A filesystem was specified with -d. We want to tack on * everything but the first element of the sent snapshot path @@ -2656,7 +2478,7 @@ zfs_receive_one(libzfs_handle_t *hdl, int infd, const char *tosnap, * Determine the name of the origin snapshot, store in zc_string. */ if (drrb->drr_flags & DRR_FLAG_CLONE) { - if (guid_to_name(hdl, zc.zc_value, + if (guid_to_name(hdl, tosnap, drrb->drr_fromguid, zc.zc_string) != 0) { zcmd_free_nvlists(&zc); zfs_error_aux(hdl, dgettext(TEXT_DOMAIN, @@ -2664,7 +2486,7 @@ zfs_receive_one(libzfs_handle_t *hdl, int infd, const char *tosnap, zc.zc_value); return (zfs_error(hdl, EZFS_NOENT, errbuf)); } - if (flags->verbose) + if (flags.verbose) (void) printf("found clone origin %s\n", zc.zc_string); } @@ -2687,7 +2509,7 @@ zfs_receive_one(libzfs_handle_t *hdl, int infd, const char *tosnap, !zfs_dataset_exists(hdl, zc.zc_name, ZFS_TYPE_DATASET)) { char suffix[ZFS_MAXNAMELEN]; (void) strcpy(suffix, strrchr(zc.zc_value, '/')); - if (guid_to_name(hdl, zc.zc_name, parent_snapguid, + if (guid_to_name(hdl, tosnap, parent_snapguid, zc.zc_value) == 0) { *strchr(zc.zc_value, '@') = '\0'; (void) strcat(zc.zc_value, suffix); @@ -2709,12 +2531,12 @@ zfs_receive_one(libzfs_handle_t *hdl, int infd, const char *tosnap, * topmost path in the stream, then if the fs does not exist we * should look no further. */ - if ((flags->isprefix || (*(chopprefix = drrb->drr_toname + + if ((flags.isprefix || (*(chopprefix = drrb->drr_toname + strlen(sendfs)) != '\0' && *chopprefix != '@')) && !zfs_dataset_exists(hdl, zc.zc_name, ZFS_TYPE_DATASET)) { char snap[ZFS_MAXNAMELEN]; (void) strcpy(snap, strchr(zc.zc_value, '@')); - if (guid_to_name(hdl, zc.zc_name, drrb->drr_fromguid, + if (guid_to_name(hdl, tosnap, drrb->drr_fromguid, zc.zc_value) == 0) { *strchr(zc.zc_value, '@') = '\0'; (void) strcat(zc.zc_value, snap); @@ -2736,7 +2558,7 @@ zfs_receive_one(libzfs_handle_t *hdl, int infd, const char *tosnap, * snapshots). */ if (stream_wantsnewfs) { - if (!flags->force) { + if (!flags.force) { zcmd_free_nvlists(&zc); zfs_error_aux(hdl, dgettext(TEXT_DOMAIN, "destination '%s' exists\n" @@ -2772,7 +2594,7 @@ zfs_receive_one(libzfs_handle_t *hdl, int infd, const char *tosnap, return (zfs_error(hdl, EZFS_EXISTS, errbuf)); } - if (!flags->dryrun && zhp->zfs_type == ZFS_TYPE_FILESYSTEM && + if (!flags.dryrun && zhp->zfs_type == ZFS_TYPE_FILESYSTEM && stream_wantsnewfs) { /* We can't do online recv in this case */ clp = changelist_gather(zhp, ZFS_PROP_NAME, 0, 0); @@ -2811,7 +2633,7 @@ zfs_receive_one(libzfs_handle_t *hdl, int infd, const char *tosnap, */ *cp = '\0'; - if (flags->isprefix && !flags->istail && !flags->dryrun && + if (flags.isprefix && !flags.istail && !flags.dryrun && create_parents(hdl, zc.zc_value, strlen(tosnap)) != 0) { zcmd_free_nvlists(&zc); return (zfs_error(hdl, EZFS_BADRESTORE, errbuf)); @@ -2822,18 +2644,18 @@ zfs_receive_one(libzfs_handle_t *hdl, int infd, const char *tosnap, zc.zc_begin_record = drr_noswap->drr_u.drr_begin; zc.zc_cookie = infd; - zc.zc_guid = flags->force; - if (flags->verbose) { + zc.zc_guid = flags.force; + if (flags.verbose) { (void) printf("%s %s stream of %s into %s\n", - flags->dryrun ? "would receive" : "receiving", + flags.dryrun ? "would receive" : "receiving", drrb->drr_fromguid ? "incremental" : "full", drrb->drr_toname, zc.zc_value); (void) fflush(stdout); } - if (flags->dryrun) { + if (flags.dryrun) { zcmd_free_nvlists(&zc); - return (recv_skip(hdl, infd, flags->byteswap)); + return (recv_skip(hdl, infd, flags.byteswap)); } zc.zc_nvlist_dst = (uint64_t)(uintptr_t)prop_errbuf; @@ -2914,12 +2736,12 @@ zfs_receive_one(libzfs_handle_t *hdl, int infd, const char *tosnap, nvlist_free(local_nv); if (fs != NULL) { - if (flags->verbose) { + if (flags.verbose) { (void) printf("snap %s already exists; " "ignoring\n", zc.zc_value); } err = ioctl_err = recv_skip(hdl, infd, - flags->byteswap); + flags.byteswap); } } *cp = '@'; @@ -2971,7 +2793,7 @@ zfs_receive_one(libzfs_handle_t *hdl, int infd, const char *tosnap, case EDQUOT: zfs_error_aux(hdl, dgettext(TEXT_DOMAIN, "destination %s space quota exceeded"), zc.zc_name); - (void) zfs_error(hdl, EZFS_NOSPC, errbuf); + (void) zfs_error(hdl, EZFS_BADRESTORE, errbuf); break; default: (void) zfs_standard_error(hdl, ioctl_errno, errbuf); @@ -3029,7 +2851,7 @@ zfs_receive_one(libzfs_handle_t *hdl, int infd, const char *tosnap, *action_handlep = zc.zc_action_handle; - if (flags->verbose) { + if (flags.verbose) { char buf1[64]; char buf2[64]; uint64_t bytes = zc.zc_cookie; @@ -3047,7 +2869,7 @@ zfs_receive_one(libzfs_handle_t *hdl, int infd, const char *tosnap, } static int -zfs_receive_impl(libzfs_handle_t *hdl, const char *tosnap, recvflags_t *flags, +zfs_receive_impl(libzfs_handle_t *hdl, const char *tosnap, recvflags_t flags, int infd, const char *sendfs, nvlist_t *stream_nv, avl_tree_t *stream_avl, char **top_zfs, int cleanup_fd, uint64_t *action_handlep) { @@ -3062,7 +2884,7 @@ zfs_receive_impl(libzfs_handle_t *hdl, const char *tosnap, recvflags_t *flags, (void) snprintf(errbuf, sizeof (errbuf), dgettext(TEXT_DOMAIN, "cannot receive")); - if (flags->isprefix && + if (flags.isprefix && !zfs_dataset_exists(hdl, tosnap, ZFS_TYPE_DATASET)) { zfs_error_aux(hdl, dgettext(TEXT_DOMAIN, "specified fs " "(%s) does not exist"), tosnap); @@ -3082,7 +2904,7 @@ zfs_receive_impl(libzfs_handle_t *hdl, const char *tosnap, recvflags_t *flags, /* the kernel needs the non-byteswapped begin record */ drr_noswap = drr; - flags->byteswap = B_FALSE; + flags.byteswap = B_FALSE; if (drrb->drr_magic == BSWAP_64(DMU_BACKUP_MAGIC)) { /* * We computed the checksum in the wrong byteorder in @@ -3090,7 +2912,7 @@ zfs_receive_impl(libzfs_handle_t *hdl, const char *tosnap, recvflags_t *flags, */ bzero(&zcksum, sizeof (zio_cksum_t)); fletcher_4_incremental_byteswap(&drr, sizeof (drr), &zcksum); - flags->byteswap = B_TRUE; + flags.byteswap = B_TRUE; drr.drr_type = BSWAP_32(drr.drr_type); drr.drr_payloadlen = BSWAP_32(drr.drr_payloadlen); @@ -3158,7 +2980,7 @@ zfs_receive_impl(libzfs_handle_t *hdl, const char *tosnap, recvflags_t *flags, * (-1 will override -2). */ int -zfs_receive(libzfs_handle_t *hdl, const char *tosnap, recvflags_t *flags, +zfs_receive(libzfs_handle_t *hdl, const char *tosnap, recvflags_t flags, int infd, avl_tree_t *stream_avl) { char *top_zfs = NULL; @@ -3174,7 +2996,7 @@ zfs_receive(libzfs_handle_t *hdl, const char *tosnap, recvflags_t *flags, VERIFY(0 == close(cleanup_fd)); - if (err == 0 && !flags->nomount && top_zfs) { + if (err == 0 && !flags.nomount && top_zfs) { zfs_handle_t *zhp; prop_changelist_t *clp; diff --git a/lib/libzfs/common/libzfs_status.c b/lib/libzfs/common/libzfs_status.c index af0707a62058..24725ec044ec 100644 --- a/lib/libzfs/common/libzfs_status.c +++ b/lib/libzfs/common/libzfs_status.c @@ -18,10 +18,8 @@ * * CDDL HEADER END */ - /* * Copyright (c) 2005, 2010, Oracle and/or its affiliates. All rights reserved. - * Copyright (c) 2012 by Delphix. All rights reserved. */ /* @@ -216,20 +214,6 @@ check_status(nvlist_t *config, boolean_t isimport) return (ZPOOL_STATUS_VERSION_NEWER); /* - * Unsupported feature(s). - */ - if (vs->vs_state == VDEV_STATE_CANT_OPEN && - vs->vs_aux == VDEV_AUX_UNSUP_FEAT) { - nvlist_t *nvinfo; - - verify(nvlist_lookup_nvlist(config, ZPOOL_CONFIG_LOAD_INFO, - &nvinfo) == 0); - if (nvlist_exists(nvinfo, ZPOOL_CONFIG_CAN_RDONLY)) - return (ZPOOL_STATUS_UNSUP_FEAT_WRITE); - return (ZPOOL_STATUS_UNSUP_FEAT_READ); - } - - /* * Check that the config is complete. */ if (vs->vs_state == VDEV_STATE_CANT_OPEN && @@ -316,7 +300,7 @@ check_status(nvlist_t *config, boolean_t isimport) /* * Outdated, but usable, version */ - if (SPA_VERSION_IS_SUPPORTED(version) && version != SPA_VERSION) + if (version < SPA_VERSION) return (ZPOOL_STATUS_VERSION_OLDER); return (ZPOOL_STATUS_OK); diff --git a/lib/libzfs/common/libzfs_util.c b/lib/libzfs/common/libzfs_util.c index 41e25e9100a0..01b7c8732efd 100644 --- a/lib/libzfs/common/libzfs_util.c +++ b/lib/libzfs/common/libzfs_util.c @@ -18,10 +18,8 @@ * * CDDL HEADER END */ - /* * Copyright (c) 2005, 2010, Oracle and/or its affiliates. All rights reserved. - * Copyright (c) 2012 by Delphix. All rights reserved. */ /* @@ -43,11 +41,9 @@ #include <sys/types.h> #include <libzfs.h> -#include <libzfs_core.h> #include "libzfs_impl.h" #include "zfs_prop.h" -#include "zfeature_common.h" int libzfs_errno(libzfs_handle_t *hdl) @@ -115,8 +111,7 @@ libzfs_error_description(libzfs_handle_t *hdl) case EZFS_RESILVERING: return (dgettext(TEXT_DOMAIN, "currently resilvering")); case EZFS_BADVERSION: - return (dgettext(TEXT_DOMAIN, "unsupported version or " - "feature")); + return (dgettext(TEXT_DOMAIN, "unsupported version")); case EZFS_POOLUNAVAIL: return (dgettext(TEXT_DOMAIN, "pool is unavailable")); case EZFS_DEVOVERFLOW: @@ -349,7 +344,6 @@ zfs_standard_error_fmt(libzfs_handle_t *hdl, int error, const char *fmt, ...) switch (error) { case ENXIO: case ENODEV: - case EPIPE: zfs_verror(hdl, EZFS_IO, fmt, ap); break; @@ -631,17 +625,8 @@ libzfs_init(void) 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(); zpool_prop_init(); - zpool_feature_init(); libzfs_mnttab_init(hdl); return (hdl); @@ -656,11 +641,12 @@ libzfs_fini(libzfs_handle_t *hdl) if (hdl->libzfs_sharetab) (void) fclose(hdl->libzfs_sharetab); zfs_uninit_libshare(hdl); + if (hdl->libzfs_log_str) + (void) free(hdl->libzfs_log_str); zpool_free_handles(hdl); libzfs_fru_clear(hdl, B_TRUE); namespace_clear(hdl); libzfs_mnttab_fini(hdl); - libzfs_core_fini(); free(hdl); } @@ -822,7 +808,17 @@ zcmd_read_dst_nvlist(libzfs_handle_t *hdl, zfs_cmd_t *zc, nvlist_t **nvlp) int zfs_ioctl(libzfs_handle_t *hdl, int request, zfs_cmd_t *zc) { - return (ioctl(hdl->libzfs_fd, request, zc)); + int error; + + 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); } /* @@ -1284,11 +1280,8 @@ addlist(libzfs_handle_t *hdl, char *propname, zprop_list_t **listp, * this is a pool property or if this isn't a user-defined * dataset property, */ - if (prop == ZPROP_INVAL && ((type == ZFS_TYPE_POOL && - !zpool_prop_feature(propname) && - !zpool_prop_unsupported(propname)) || - (type == ZFS_TYPE_DATASET && !zfs_prop_user(propname) && - !zfs_prop_userquota(propname) && !zfs_prop_written(propname)))) { + if (prop == ZPROP_INVAL && (type == ZFS_TYPE_POOL || + (!zfs_prop_user(propname) && !zfs_prop_userquota(propname)))) { zfs_error_aux(hdl, dgettext(TEXT_DOMAIN, "invalid property '%s'"), propname); return (zfs_error(hdl, EZFS_BADPROP, @@ -1300,8 +1293,7 @@ addlist(libzfs_handle_t *hdl, char *propname, zprop_list_t **listp, entry->pl_prop = prop; if (prop == ZPROP_INVAL) { - if ((entry->pl_user_prop = zfs_strdup(hdl, propname)) == - NULL) { + if ((entry->pl_user_prop = zfs_strdup(hdl, propname)) == NULL) { free(entry); return (-1); } diff --git a/lib/libzfs_core/common/libzfs_core.c b/lib/libzfs_core/common/libzfs_core.c deleted file mode 100644 index 73afd50b8de2..000000000000 --- a/lib/libzfs_core/common/libzfs_core.c +++ /dev/null @@ -1,477 +0,0 @@ -/* - * 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); -} diff --git a/lib/libzfs_core/common/libzfs_core.h b/lib/libzfs_core/common/libzfs_core.h deleted file mode 100644 index 9edc884a14d1..000000000000 --- a/lib/libzfs_core/common/libzfs_core.h +++ /dev/null @@ -1,62 +0,0 @@ -/* - * 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 */ diff --git a/lib/libzpool/common/kernel.c b/lib/libzpool/common/kernel.c index 04d530727f5c..f323bf60b099 100644 --- a/lib/libzpool/common/kernel.c +++ b/lib/libzpool/common/kernel.c @@ -20,7 +20,6 @@ */ /* * Copyright (c) 2005, 2010, Oracle and/or its affiliates. All rights reserved. - * Copyright (c) 2012 by Delphix. All rights reserved. */ #include <assert.h> @@ -46,7 +45,6 @@ int aok; uint64_t physmem; vnode_t *rootdir = (vnode_t *)0xabcd1234; char hw_serial[HW_HOSTID_LEN]; -vmem_t *zio_arena = NULL; struct utsname utsname = { "userland", "libzpool", "1", "1", "na" @@ -426,9 +424,7 @@ vn_rdwr(int uio, vnode_t *vp, void *addr, ssize_t len, offset_t offset, * To simulate partial disk writes, we split writes into two * system calls so that the process can be killed in between. */ - int sectors = len >> SPA_MINBLOCKSHIFT; - split = (sectors > 0 ? rand() % sectors : 0) << - SPA_MINBLOCKSHIFT; + split = (len > 0 ? rand() % len : 0); iolen = pwrite64(vp->v_fd, addr, split, offset); iolen += pwrite64(vp->v_fd, (char *)addr + split, len - split, offset + split); @@ -871,12 +867,6 @@ crgetuid(cred_t *cr) return (0); } -uid_t -crgetruid(cred_t *cr) -{ - return (0); -} - gid_t crgetgid(cred_t *cr) { diff --git a/lib/libzpool/common/sys/zfs_context.h b/lib/libzpool/common/sys/zfs_context.h index 39af927f7105..3b0390dca566 100644 --- a/lib/libzpool/common/sys/zfs_context.h +++ b/lib/libzpool/common/sys/zfs_context.h @@ -20,9 +20,6 @@ */ /* * Copyright (c) 2005, 2010, Oracle and/or its affiliates. All rights reserved. - * Copyright 2011 Nexenta Systems, Inc. All rights reserved. - * Copyright (c) 2012 by Delphix. All rights reserved. - * Copyright (c) 2012, Joyent, Inc. All rights reserved. */ #ifndef _SYS_ZFS_CONTEXT_H @@ -215,7 +212,6 @@ struct proc { }; extern struct proc p0; -#define curproc (&p0) #define PS_NONE -1 @@ -286,7 +282,6 @@ extern void rw_exit(krwlock_t *rwlp); #define rw_downgrade(rwlp) do { } while (0) extern uid_t crgetuid(cred_t *cr); -extern uid_t crgetruid(cred_t *cr); extern gid_t crgetgid(cred_t *cr); extern int crgetngroups(cred_t *cr); extern gid_t *crgetgroups(cred_t *cr); @@ -332,12 +327,9 @@ extern void kstat_delete(kstat_t *); #define kmem_debugging() 0 #define kmem_cache_reap_now(_c) /* nothing */ #define kmem_cache_set_move(_c, _cb) /* nothing */ -#define vmem_qcache_reap(_v) /* nothing */ #define POINTER_INVALIDATE(_pp) /* nothing */ #define POINTER_IS_VALID(_p) 0 -extern vmem_t *zio_arena; - typedef umem_cache_t kmem_cache_t; typedef enum kmem_cbrc { @@ -355,16 +347,6 @@ typedef struct taskq taskq_t; typedef uintptr_t taskqid_t; typedef void (task_func_t)(void *); -typedef struct taskq_ent { - struct taskq_ent *tqent_next; - struct taskq_ent *tqent_prev; - task_func_t *tqent_func; - void *tqent_arg; - uintptr_t tqent_flags; -} taskq_ent_t; - -#define TQENT_FLAG_PREALLOC 0x1 /* taskq_dispatch_ent used */ - #define TASKQ_PREPOPULATE 0x0001 #define TASKQ_CPR_SAFE 0x0002 /* Use CPR safe protocol */ #define TASKQ_DYNAMIC 0x0004 /* Use dynamic thread scheduling */ @@ -376,7 +358,6 @@ typedef struct taskq_ent { #define TQ_NOQUEUE 0x02 /* Do not enqueue if can't dispatch */ #define TQ_FRONT 0x08 /* Queue in front */ - extern taskq_t *system_taskq; extern taskq_t *taskq_create(const char *, int, pri_t, int, int, uint_t); @@ -385,8 +366,6 @@ extern taskq_t *taskq_create(const char *, int, pri_t, int, int, uint_t); #define taskq_create_sysdc(a, b, d, e, p, dc, f) \ (taskq_create(a, b, maxclsyspri, d, e, f)) extern taskqid_t taskq_dispatch(taskq_t *, task_func_t, void *, uint_t); -extern void taskq_dispatch_ent(taskq_t *, task_func_t, void *, uint_t, - taskq_ent_t *); extern void taskq_destroy(taskq_t *); extern void taskq_wait(taskq_t *); extern int taskq_member(taskq_t *, void *); diff --git a/lib/libzpool/common/taskq.c b/lib/libzpool/common/taskq.c index 2c5dfd86dcc0..8db5d11c1327 100644 --- a/lib/libzpool/common/taskq.c +++ b/lib/libzpool/common/taskq.c @@ -22,16 +22,19 @@ * Copyright 2010 Sun Microsystems, Inc. All rights reserved. * Use is subject to license terms. */ -/* - * Copyright 2011 Nexenta Systems, Inc. All rights reserved. - * Copyright 2012 Garrett D'Amore <garrett@damore.org>. All rights reserved. - */ #include <sys/zfs_context.h> int taskq_now; taskq_t *system_taskq; +typedef struct task { + struct task *task_next; + struct task *task_prev; + task_func_t *task_func; + void *task_arg; +} task_t; + #define TASKQ_ACTIVE 0x00010000 struct taskq { @@ -48,18 +51,18 @@ struct taskq { int tq_maxalloc; kcondvar_t tq_maxalloc_cv; int tq_maxalloc_wait; - taskq_ent_t *tq_freelist; - taskq_ent_t tq_task; + task_t *tq_freelist; + task_t tq_task; }; -static taskq_ent_t * +static task_t * task_alloc(taskq_t *tq, int tqflags) { - taskq_ent_t *t; + task_t *t; int rv; again: if ((t = tq->tq_freelist) != NULL && tq->tq_nalloc >= tq->tq_minalloc) { - tq->tq_freelist = t->tqent_next; + tq->tq_freelist = t->task_next; } else { if (tq->tq_nalloc >= tq->tq_maxalloc) { if (!(tqflags & KM_SLEEP)) @@ -84,7 +87,7 @@ again: if ((t = tq->tq_freelist) != NULL && tq->tq_nalloc >= tq->tq_minalloc) { } mutex_exit(&tq->tq_lock); - t = kmem_alloc(sizeof (taskq_ent_t), tqflags); + t = kmem_alloc(sizeof (task_t), tqflags); mutex_enter(&tq->tq_lock); if (t != NULL) @@ -94,15 +97,15 @@ again: if ((t = tq->tq_freelist) != NULL && tq->tq_nalloc >= tq->tq_minalloc) { } static void -task_free(taskq_t *tq, taskq_ent_t *t) +task_free(taskq_t *tq, task_t *t) { if (tq->tq_nalloc <= tq->tq_minalloc) { - t->tqent_next = tq->tq_freelist; + t->task_next = tq->tq_freelist; tq->tq_freelist = t; } else { tq->tq_nalloc--; mutex_exit(&tq->tq_lock); - kmem_free(t, sizeof (taskq_ent_t)); + kmem_free(t, sizeof (task_t)); mutex_enter(&tq->tq_lock); } @@ -113,7 +116,7 @@ task_free(taskq_t *tq, taskq_ent_t *t) taskqid_t taskq_dispatch(taskq_t *tq, task_func_t func, void *arg, uint_t tqflags) { - taskq_ent_t *t; + task_t *t; if (taskq_now) { func(arg); @@ -127,59 +130,26 @@ taskq_dispatch(taskq_t *tq, task_func_t func, void *arg, uint_t tqflags) return (0); } if (tqflags & TQ_FRONT) { - t->tqent_next = tq->tq_task.tqent_next; - t->tqent_prev = &tq->tq_task; + t->task_next = tq->tq_task.task_next; + t->task_prev = &tq->tq_task; } else { - t->tqent_next = &tq->tq_task; - t->tqent_prev = tq->tq_task.tqent_prev; + t->task_next = &tq->tq_task; + t->task_prev = tq->tq_task.task_prev; } - t->tqent_next->tqent_prev = t; - t->tqent_prev->tqent_next = t; - t->tqent_func = func; - t->tqent_arg = arg; - t->tqent_flags = 0; + t->task_next->task_prev = t; + t->task_prev->task_next = t; + t->task_func = func; + t->task_arg = arg; cv_signal(&tq->tq_dispatch_cv); mutex_exit(&tq->tq_lock); return (1); } void -taskq_dispatch_ent(taskq_t *tq, task_func_t func, void *arg, uint_t flags, - taskq_ent_t *t) -{ - ASSERT(func != NULL); - ASSERT(!(tq->tq_flags & TASKQ_DYNAMIC)); - - /* - * Mark it as a prealloc'd task. This is important - * to ensure that we don't free it later. - */ - t->tqent_flags |= TQENT_FLAG_PREALLOC; - /* - * Enqueue the task to the underlying queue. - */ - mutex_enter(&tq->tq_lock); - - if (flags & TQ_FRONT) { - t->tqent_next = tq->tq_task.tqent_next; - t->tqent_prev = &tq->tq_task; - } else { - t->tqent_next = &tq->tq_task; - t->tqent_prev = tq->tq_task.tqent_prev; - } - t->tqent_next->tqent_prev = t; - t->tqent_prev->tqent_next = t; - t->tqent_func = func; - t->tqent_arg = arg; - cv_signal(&tq->tq_dispatch_cv); - mutex_exit(&tq->tq_lock); -} - -void taskq_wait(taskq_t *tq) { mutex_enter(&tq->tq_lock); - while (tq->tq_task.tqent_next != &tq->tq_task || tq->tq_active != 0) + while (tq->tq_task.task_next != &tq->tq_task || tq->tq_active != 0) cv_wait(&tq->tq_wait_cv, &tq->tq_lock); mutex_exit(&tq->tq_lock); } @@ -188,32 +158,27 @@ static void * taskq_thread(void *arg) { taskq_t *tq = arg; - taskq_ent_t *t; - boolean_t prealloc; + task_t *t; mutex_enter(&tq->tq_lock); while (tq->tq_flags & TASKQ_ACTIVE) { - if ((t = tq->tq_task.tqent_next) == &tq->tq_task) { + if ((t = tq->tq_task.task_next) == &tq->tq_task) { if (--tq->tq_active == 0) cv_broadcast(&tq->tq_wait_cv); cv_wait(&tq->tq_dispatch_cv, &tq->tq_lock); tq->tq_active++; continue; } - t->tqent_prev->tqent_next = t->tqent_next; - t->tqent_next->tqent_prev = t->tqent_prev; - t->tqent_next = NULL; - t->tqent_prev = NULL; - prealloc = t->tqent_flags & TQENT_FLAG_PREALLOC; + t->task_prev->task_next = t->task_next; + t->task_next->task_prev = t->task_prev; mutex_exit(&tq->tq_lock); rw_enter(&tq->tq_threadlock, RW_READER); - t->tqent_func(t->tqent_arg); + t->task_func(t->task_arg); rw_exit(&tq->tq_threadlock); mutex_enter(&tq->tq_lock); - if (!prealloc) - task_free(tq, t); + task_free(tq, t); } tq->tq_nthreads--; cv_broadcast(&tq->tq_wait_cv); @@ -252,8 +217,8 @@ taskq_create(const char *name, int nthreads, pri_t pri, tq->tq_nthreads = nthreads; tq->tq_minalloc = minalloc; tq->tq_maxalloc = maxalloc; - tq->tq_task.tqent_next = &tq->tq_task; - tq->tq_task.tqent_prev = &tq->tq_task; + tq->tq_task.task_next = &tq->tq_task; + tq->tq_task.task_prev = &tq->tq_task; tq->tq_threadlist = kmem_alloc(nthreads * sizeof (thread_t), KM_SLEEP); if (flags & TASKQ_PREPOPULATE) { |