From d6a9bc60b0f90d843c0c10d72533bfbcd2737895 Mon Sep 17 00:00:00 2001 From: Martin Matuska Date: Sun, 19 Aug 2012 09:17:21 +0000 Subject: [PATCH 1/6] Update vendor/illumos to illumos-gate 13754:7231b684c18b References: https://www.illumos.org/issues/2978 Obtained from: ssh://anonhg@hg.illumos.org/illumos-gate --- tools/ctf/cvt/dwarf.c | 44 +++++++++++++++++++++++++++++++++++++------ 1 file changed, 38 insertions(+), 6 deletions(-) diff --git a/tools/ctf/cvt/dwarf.c b/tools/ctf/cvt/dwarf.c index ef92e384e435..e261818d3a66 100644 --- a/tools/ctf/cvt/dwarf.c +++ b/tools/ctf/cvt/dwarf.c @@ -1839,21 +1839,53 @@ die_resolve(dwarf_t *dw) } /* - * Any object containing at least one allocatable section of non-0 size is - * taken to be a file which should contain DWARF type information + * Any object containing a function or object symbol at any scope should also + * contain DWARF data. */ static boolean_t should_have_dwarf(Elf *elf) { Elf_Scn *scn = NULL; + Elf_Data *data = NULL; + GElf_Shdr shdr; + GElf_Sym sym; + uint32_t symdx = 0; + size_t nsyms = 0; + boolean_t found = B_FALSE; while ((scn = elf_nextscn(elf, scn)) != NULL) { - GElf_Shdr shdr; gelf_getshdr(scn, &shdr); - if ((shdr.sh_flags & SHF_ALLOC) && - (shdr.sh_size != 0)) - return (B_TRUE); + if (shdr.sh_type == SHT_SYMTAB) { + found = B_TRUE; + break; + } + } + + if (!found) + terminate("cannot convert stripped objects\n"); + + data = elf_getdata(scn, NULL); + nsyms = shdr.sh_size / shdr.sh_entsize; + + for (symdx = 0; symdx < nsyms; symdx++) { + gelf_getsym(data, symdx, &sym); + + if ((GELF_ST_TYPE(sym.st_info) == STT_FUNC) || + (GELF_ST_TYPE(sym.st_info) == STT_TLS) || + (GELF_ST_TYPE(sym.st_info) == STT_OBJECT)) { + char *name; + + name = elf_strptr(elf, shdr.sh_link, sym.st_name); + + /* Studio emits these local symbols regardless */ + if ((strcmp(name, "Bbss.bss") != 0) && + (strcmp(name, "Ttbss.bss") != 0) && + (strcmp(name, "Ddata.data") != 0) && + (strcmp(name, "Ttdata.data") != 0) && + (strcmp(name, "Drodata.rodata") != 0)) + return (B_TRUE); + } } return (B_FALSE); From 41adcc32e95ee4bc3686fa633a52224bcc447f8b Mon Sep 17 00:00:00 2001 From: Martin Matuska Date: Sun, 19 Aug 2012 09:20:22 +0000 Subject: [PATCH 2/6] Update vendor/illumos to illumos-gate 13758:23432da34147 (dtrace changes) References: https://www.illumos.org/issues/3021 https://www.illumos.org/issues/3022 https://www.illumos.org/issues/3023 https://www.illumos.org/issues/3024 https://www.illumos.org/issues/3025 https://www.illumos.org/issues/3026 Obtained from: ssh://anonhg@hg.illumos.org/illumos-gate --- cmd/dtrace/dtrace.c | 6 +- cmd/dtrace/test/cmd/scripts/dtest.pl | 3 + .../test/tst/common/aggs/tst.sizedkeys.d | 35 ++ .../test/tst/common/aggs/tst.sizedkeys.d.out | 6 + .../tst/common/arithmetic/tst.basics.d.out | 8 + .../test/tst/common/arithmetic/tst.compcast.d | 50 ++ .../tst/common/arithmetic/tst.compcast.d.out | 10 + .../test/tst/common/arithmetic/tst.complex.d | 57 --- .../common/arithmetic/tst.compnarrowassign.d | 36 ++ .../arithmetic/tst.compnarrowassign.d.out | 1 + .../test/tst/common/arithmetic/tst.execcast.d | 52 ++ .../tst/common/arithmetic/tst.execcast.d.out | 10 + .../test/tst/common/buffering/tst.fill1.d | 17 +- .../test/tst/common/buffering/tst.ring3.d | 28 +- .../test/tst/common/cg/err.D_NOREG.noreg.d | 41 ++ cmd/dtrace/test/tst/common/cg/err.baddif.d | 44 ++ .../env/err.D_PRAGMA_OPTSET.setfromscript.d | 25 + .../env/err.D_PRAGMA_OPTSET.unsetfromscript.d | 25 + .../test/tst/common/env/tst.ld_nolazyload.ksh | 33 ++ .../tst/common/env/tst.ld_nolazyload.ksh.out | 2 + .../test/tst/common/env/tst.setenv1.ksh | 33 ++ .../test/tst/common/env/tst.setenv1.ksh.out | 2 + .../test/tst/common/env/tst.setenv2.ksh | 33 ++ .../test/tst/common/env/tst.setenv2.ksh.out | 2 + .../test/tst/common/env/tst.unsetenv1.ksh | 33 ++ .../test/tst/common/env/tst.unsetenv1.ksh.out | 1 + .../test/tst/common/env/tst.unsetenv2.ksh | 35 ++ .../test/tst/common/env/tst.unsetenv2.ksh.out | 1 + .../test/tst/common/pid/tst.newprobes.ksh | 8 +- .../tst/common/pointers/tst.assigncast1.d | 28 ++ .../tst/common/pointers/tst.assigncast2.d | 29 ++ .../test/tst/common/pragma/tst.temporal.ksh | 106 ++++ .../test/tst/common/pragma/tst.temporal2.ksh | 102 ++++ .../test/tst/common/pragma/tst.temporal3.d | 48 ++ .../tst/common/predicates/tst.predcache.ksh | 197 -------- .../tst/common/print/err.D_PRINT_DYN.bad.d | 29 -- cmd/dtrace/test/tst/common/print/tst.dyn.d | 28 ++ cmd/dtrace/test/tst/common/print/tst.xlate.d | 42 ++ .../test/tst/common/print/tst.xlate.d.out | 8 + .../test/tst/common/printf/tst.ints.d.out | 4 +- cmd/dtrace/test/tst/common/printf/tst.signs.d | 38 ++ .../test/tst/common/printf/tst.signs.d.out | 3 + .../speculation/err.BufSizeVariations1.d | 14 +- .../speculation/tst.SpecSizeVariations3.d | 7 +- .../tst/common/trace/err.D_TRACE_DYN.bad.d | 29 -- cmd/dtrace/test/tst/common/trace/tst.dyn.d | 28 ++ .../common/tracemem/err.D_PROTO_LEN.toomany.d | 39 -- .../translators/man.TestTransStability.d | 61 --- .../translators/tst.TestTransStability1.ksh | 62 +++ .../tst.TestTransStability1.ksh.out | 14 + .../translators/tst.TestTransStability2.ksh | 60 +++ .../tst.TestTransStability2.ksh.out | 14 + lib/libdtrace/common/dt_aggregate.c | 30 +- lib/libdtrace/common/dt_cc.c | 90 ++-- lib/libdtrace/common/dt_cg.c | 345 +++++++++---- lib/libdtrace/common/dt_consume.c | 459 +++++++++++++----- lib/libdtrace/common/dt_dis.c | 23 +- lib/libdtrace/common/dt_error.c | 6 +- lib/libdtrace/common/dt_errtags.h | 5 +- lib/libdtrace/common/dt_impl.h | 12 +- lib/libdtrace/common/dt_open.c | 20 +- lib/libdtrace/common/dt_options.c | 63 ++- lib/libdtrace/common/dt_parser.c | 110 +++-- lib/libdtrace/common/dt_pq.c | 157 ++++++ lib/libdtrace/common/dt_printf.c | 5 +- lib/libdtrace/common/dt_proc.c | 68 ++- lib/libdtrace/common/dt_proc.h | 10 +- lib/libdtrace/common/dt_regset.c | 37 +- lib/libdtrace/common/dt_regset.h | 8 +- lib/libdtrace/common/dt_subr.c | 5 +- lib/libdtrace/i386/dt_isadep.c | 7 +- 71 files changed, 2265 insertions(+), 822 deletions(-) create mode 100644 cmd/dtrace/test/tst/common/aggs/tst.sizedkeys.d create mode 100644 cmd/dtrace/test/tst/common/aggs/tst.sizedkeys.d.out create mode 100644 cmd/dtrace/test/tst/common/arithmetic/tst.basics.d.out create mode 100644 cmd/dtrace/test/tst/common/arithmetic/tst.compcast.d create mode 100644 cmd/dtrace/test/tst/common/arithmetic/tst.compcast.d.out delete mode 100644 cmd/dtrace/test/tst/common/arithmetic/tst.complex.d create mode 100644 cmd/dtrace/test/tst/common/arithmetic/tst.compnarrowassign.d create mode 100644 cmd/dtrace/test/tst/common/arithmetic/tst.compnarrowassign.d.out create mode 100644 cmd/dtrace/test/tst/common/arithmetic/tst.execcast.d create mode 100644 cmd/dtrace/test/tst/common/arithmetic/tst.execcast.d.out create mode 100644 cmd/dtrace/test/tst/common/cg/err.D_NOREG.noreg.d create mode 100644 cmd/dtrace/test/tst/common/cg/err.baddif.d create mode 100644 cmd/dtrace/test/tst/common/env/err.D_PRAGMA_OPTSET.setfromscript.d create mode 100644 cmd/dtrace/test/tst/common/env/err.D_PRAGMA_OPTSET.unsetfromscript.d create mode 100644 cmd/dtrace/test/tst/common/env/tst.ld_nolazyload.ksh create mode 100644 cmd/dtrace/test/tst/common/env/tst.ld_nolazyload.ksh.out create mode 100644 cmd/dtrace/test/tst/common/env/tst.setenv1.ksh create mode 100644 cmd/dtrace/test/tst/common/env/tst.setenv1.ksh.out create mode 100644 cmd/dtrace/test/tst/common/env/tst.setenv2.ksh create mode 100644 cmd/dtrace/test/tst/common/env/tst.setenv2.ksh.out create mode 100644 cmd/dtrace/test/tst/common/env/tst.unsetenv1.ksh create mode 100644 cmd/dtrace/test/tst/common/env/tst.unsetenv1.ksh.out create mode 100644 cmd/dtrace/test/tst/common/env/tst.unsetenv2.ksh create mode 100644 cmd/dtrace/test/tst/common/env/tst.unsetenv2.ksh.out create mode 100644 cmd/dtrace/test/tst/common/pointers/tst.assigncast1.d create mode 100644 cmd/dtrace/test/tst/common/pointers/tst.assigncast2.d create mode 100644 cmd/dtrace/test/tst/common/pragma/tst.temporal.ksh create mode 100644 cmd/dtrace/test/tst/common/pragma/tst.temporal2.ksh create mode 100644 cmd/dtrace/test/tst/common/pragma/tst.temporal3.d delete mode 100644 cmd/dtrace/test/tst/common/predicates/tst.predcache.ksh delete mode 100644 cmd/dtrace/test/tst/common/print/err.D_PRINT_DYN.bad.d create mode 100644 cmd/dtrace/test/tst/common/print/tst.dyn.d create mode 100644 cmd/dtrace/test/tst/common/print/tst.xlate.d create mode 100644 cmd/dtrace/test/tst/common/print/tst.xlate.d.out create mode 100644 cmd/dtrace/test/tst/common/printf/tst.signs.d create mode 100644 cmd/dtrace/test/tst/common/printf/tst.signs.d.out delete mode 100644 cmd/dtrace/test/tst/common/trace/err.D_TRACE_DYN.bad.d create mode 100644 cmd/dtrace/test/tst/common/trace/tst.dyn.d delete mode 100644 cmd/dtrace/test/tst/common/tracemem/err.D_PROTO_LEN.toomany.d delete mode 100644 cmd/dtrace/test/tst/common/translators/man.TestTransStability.d create mode 100644 cmd/dtrace/test/tst/common/translators/tst.TestTransStability1.ksh create mode 100644 cmd/dtrace/test/tst/common/translators/tst.TestTransStability1.ksh.out create mode 100644 cmd/dtrace/test/tst/common/translators/tst.TestTransStability2.ksh create mode 100644 cmd/dtrace/test/tst/common/translators/tst.TestTransStability2.ksh.out create mode 100644 lib/libdtrace/common/dt_pq.c diff --git a/cmd/dtrace/dtrace.c b/cmd/dtrace/dtrace.c index 81a6953b63fa..e74e3df690c5 100644 --- a/cmd/dtrace/dtrace.c +++ b/cmd/dtrace/dtrace.c @@ -23,8 +23,9 @@ * Copyright 2006 Sun Microsystems, Inc. All rights reserved. * Use is subject to license terms. */ - -#pragma ident "%Z%%M% %I% %E% SMI" +/* + * Copyright (c) 2012 by Delphix. All rights reserved. + */ #include #include @@ -1339,6 +1340,7 @@ main(int argc, char *argv[]) (void) dtrace_setopt(g_dtp, "bufsize", "4m"); (void) dtrace_setopt(g_dtp, "aggsize", "4m"); + (void) dtrace_setopt(g_dtp, "temporal", "yes"); /* * If -G is specified, enable -xlink=dynamic and -xunodefs to permit diff --git a/cmd/dtrace/test/cmd/scripts/dtest.pl b/cmd/dtrace/test/cmd/scripts/dtest.pl index f11cf6916c52..d6f1c8c27771 100644 --- a/cmd/dtrace/test/cmd/scripts/dtest.pl +++ b/cmd/dtrace/test/cmd/scripts/dtest.pl @@ -27,6 +27,7 @@ # # Copyright (c) 2011, Joyent, Inc. All rights reserved. +# Copyright (c) 2012 by Delphix. All rights reserved. # require 5.8.4; @@ -612,6 +613,8 @@ if ($opt_x) { die "$PNAME: failed to open $PNAME.$$.log: $!\n" unless (!$opt_l || open(LOG, ">$PNAME.$$.log")); +$ENV{'DTRACE_DEBUG_REGSET'} = 'true'; + if ($opt_g) { $ENV{'UMEM_DEBUG'} = 'default,verbose'; $ENV{'UMEM_LOGGING'} = 'fail,contents'; diff --git a/cmd/dtrace/test/tst/common/aggs/tst.sizedkeys.d b/cmd/dtrace/test/tst/common/aggs/tst.sizedkeys.d new file mode 100644 index 000000000000..bb3ed4789bf5 --- /dev/null +++ b/cmd/dtrace/test/tst/common/aggs/tst.sizedkeys.d @@ -0,0 +1,35 @@ +/* + * CDDL HEADER START + * + * This file and its contents are supplied under the terms of the + * Common Development and Distribution License ("CDDL"), version 1.0. + * You may only use this file in accordance with the terms of version + * 1.0 of the CDDL. + * + * A full copy of the text of the CDDL should have accompanied this + * source. A copy of the CDDL is also available via the Internet at + * http://www.illumos.org/license/CDDL. + * + * CDDL HEADER END + */ + +/* + * Copyright (c) 2012 by Delphix. All rights reserved. + */ + +#pragma D option quiet + +/* + * Make sure the sizes of compatible keys doesn't affect the sort order. + */ + +BEGIN +{ + @[(int)1, 0] = sum(10); + @[(uint64_t)2, 0] = sum(20); + @[(int)3, 0] = sum(30); + @[(uint64_t)4, 0] = sum(40); + printa(@); + + exit(0); +} diff --git a/cmd/dtrace/test/tst/common/aggs/tst.sizedkeys.d.out b/cmd/dtrace/test/tst/common/aggs/tst.sizedkeys.d.out new file mode 100644 index 000000000000..83252ade53ae --- /dev/null +++ b/cmd/dtrace/test/tst/common/aggs/tst.sizedkeys.d.out @@ -0,0 +1,6 @@ + + 1 0 10 + 2 0 20 + 3 0 30 + 4 0 40 + diff --git a/cmd/dtrace/test/tst/common/arithmetic/tst.basics.d.out b/cmd/dtrace/test/tst/common/arithmetic/tst.basics.d.out new file mode 100644 index 000000000000..d3b6af813101 --- /dev/null +++ b/cmd/dtrace/test/tst/common/arithmetic/tst.basics.d.out @@ -0,0 +1,8 @@ +The value of i is 6 +The value of i is 18 +The value of i is 72 +The value of i is 25920 +The value of i is 935761216 +The value of i is -91738734 +The value of i is -91738729 + diff --git a/cmd/dtrace/test/tst/common/arithmetic/tst.compcast.d b/cmd/dtrace/test/tst/common/arithmetic/tst.compcast.d new file mode 100644 index 000000000000..714fbe373b2c --- /dev/null +++ b/cmd/dtrace/test/tst/common/arithmetic/tst.compcast.d @@ -0,0 +1,50 @@ +/* + * CDDL HEADER START + * + * This file and its contents are supplied under the terms of the + * Common Development and Distribution License ("CDDL"), version 1.0. + * You may only use this file in accordance with the terms of version + * 1.0 of the CDDL. + * + * A full copy of the text of the CDDL should have accompanied this + * source. A copy of the CDDL is also available via the Internet at + * http://www.illumos.org/license/CDDL. + * + * CDDL HEADER END + */ + +/* + * Copyright (c) 2012 by Delphix. All rights reserved. + */ + +/* + * Test compile-time casting between integer types of different size. + */ + +#pragma D option quiet + +int64_t x; + +BEGIN +{ + x = (int32_t)(int16_t)0xfff0; + printf("%16x %20d %20u\n", x, x, x); + x = (int32_t)(uint16_t)0xfff0; + printf("%16x %20d %20u\n", x, x, x); + x = (uint32_t)(int16_t)0xfff0; + printf("%16x %20d %20u\n", x, x, x); + x = (uint32_t)(uint16_t)0xfff0; + printf("%16x %20d %20u\n", x, x, x); + printf("\n"); + + x = (int16_t)(int32_t)0xfff0; + printf("%16x %20d %20u\n", x, x, x); + x = (int16_t)(uint32_t)0xfff0; + printf("%16x %20d %20u\n", x, x, x); + x = (uint16_t)(int32_t)0xfff0; + printf("%16x %20d %20u\n", x, x, x); + x = (uint16_t)(uint32_t)0xfff0; + printf("%16x %20d %20u\n", x, x, x); + + exit(0); +} diff --git a/cmd/dtrace/test/tst/common/arithmetic/tst.compcast.d.out b/cmd/dtrace/test/tst/common/arithmetic/tst.compcast.d.out new file mode 100644 index 000000000000..d43df27d5d5c --- /dev/null +++ b/cmd/dtrace/test/tst/common/arithmetic/tst.compcast.d.out @@ -0,0 +1,10 @@ +fffffffffffffff0 -16 18446744073709551600 + fff0 65520 65520 + fffffff0 4294967280 4294967280 + fff0 65520 65520 + +fffffffffffffff0 -16 18446744073709551600 +fffffffffffffff0 -16 18446744073709551600 + fff0 65520 65520 + fff0 65520 65520 + diff --git a/cmd/dtrace/test/tst/common/arithmetic/tst.complex.d b/cmd/dtrace/test/tst/common/arithmetic/tst.complex.d deleted file mode 100644 index 2db1b6350b94..000000000000 --- a/cmd/dtrace/test/tst/common/arithmetic/tst.complex.d +++ /dev/null @@ -1,57 +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 2006 Sun Microsystems, Inc. All rights reserved. - * Use is subject to license terms. - */ - -#pragma ident "%Z%%M% %I% %E% SMI" - -/* - * ASSERTION: - * Complex expressions. - * Call complex expressions and make sure test succeeds. - * Match expected output in tst.complex.d.out - * - * SECTION: Types, Operators, and Expressions/Arithmetic Operators - * - */ - -#pragma D option quiet - -BEGIN -{ - i = 0; - i = i++ + ++i; - printf("The value of i is %d\n", i); - i = i-- - --i; - printf("The value of i is %d\n", i); - i = i-- + ++i; - printf("The value of i is %d\n", i); - i += i++ + -- i + ++i - ++i * i ; - printf("The value of i is %d\n", i); - i -= i++ * 3; - printf("The value of i is %d\n", i); - i = i++/i--+i++-++i-++i; - printf("The value of i is %d\n", i); - exit (0); -} diff --git a/cmd/dtrace/test/tst/common/arithmetic/tst.compnarrowassign.d b/cmd/dtrace/test/tst/common/arithmetic/tst.compnarrowassign.d new file mode 100644 index 000000000000..0589b721b421 --- /dev/null +++ b/cmd/dtrace/test/tst/common/arithmetic/tst.compnarrowassign.d @@ -0,0 +1,36 @@ +/* + * CDDL HEADER START + * + * This file and its contents are supplied under the terms of the + * Common Development and Distribution License ("CDDL"), version 1.0. + * You may only use this file in accordance with the terms of version + * 1.0 of the CDDL. + * + * A full copy of the text of the CDDL should have accompanied this + * source. A copy of the CDDL is also available via the Internet at + * http://www.illumos.org/license/CDDL. + * + * CDDL HEADER END + */ + +/* + * Copyright (c) 2012 by Delphix. All rights reserved. + */ + +/* + * Test narrowing at assignment. + */ + +#pragma D option quiet + +uint16_t x; +uint32_t y; + +BEGIN +{ + x = 0xbeefcafe; + y = x; + printf("%x", y); /* where's the beef? */ + + exit(0); +} diff --git a/cmd/dtrace/test/tst/common/arithmetic/tst.compnarrowassign.d.out b/cmd/dtrace/test/tst/common/arithmetic/tst.compnarrowassign.d.out new file mode 100644 index 000000000000..ea17b160d298 --- /dev/null +++ b/cmd/dtrace/test/tst/common/arithmetic/tst.compnarrowassign.d.out @@ -0,0 +1 @@ +cafe diff --git a/cmd/dtrace/test/tst/common/arithmetic/tst.execcast.d b/cmd/dtrace/test/tst/common/arithmetic/tst.execcast.d new file mode 100644 index 000000000000..a7017bfee5e7 --- /dev/null +++ b/cmd/dtrace/test/tst/common/arithmetic/tst.execcast.d @@ -0,0 +1,52 @@ +/* + * CDDL HEADER START + * + * This file and its contents are supplied under the terms of the + * Common Development and Distribution License ("CDDL"), version 1.0. + * You may only use this file in accordance with the terms of version + * 1.0 of the CDDL. + * + * A full copy of the text of the CDDL should have accompanied this + * source. A copy of the CDDL is also available via the Internet at + * http://www.illumos.org/license/CDDL. + * + * CDDL HEADER END + */ + +/* + * Copyright (c) 2012 by Delphix. All rights reserved. + */ + +/* + * Test execution-time casting between integer types of different size. + */ + +#pragma D option quiet + +int64_t x; + +BEGIN +{ + z = 0xfff0; + + x = (int32_t)(int16_t)z; + printf("%16x %20d %20u\n", x, x, x); + x = (int32_t)(uint16_t)z; + printf("%16x %20d %20u\n", x, x, x); + x = (uint32_t)(int16_t)z; + printf("%16x %20d %20u\n", x, x, x); + x = (uint32_t)(uint16_t)z; + printf("%16x %20d %20u\n", x, x, x); + printf("\n"); + + x = (int16_t)(int32_t)z; + printf("%16x %20d %20u\n", x, x, x); + x = (int16_t)(uint32_t)z; + printf("%16x %20d %20u\n", x, x, x); + x = (uint16_t)(int32_t)z; + printf("%16x %20d %20u\n", x, x, x); + x = (uint16_t)(uint32_t)z; + printf("%16x %20d %20u\n", x, x, x); + + exit(0); +} diff --git a/cmd/dtrace/test/tst/common/arithmetic/tst.execcast.d.out b/cmd/dtrace/test/tst/common/arithmetic/tst.execcast.d.out new file mode 100644 index 000000000000..d43df27d5d5c --- /dev/null +++ b/cmd/dtrace/test/tst/common/arithmetic/tst.execcast.d.out @@ -0,0 +1,10 @@ +fffffffffffffff0 -16 18446744073709551600 + fff0 65520 65520 + fffffff0 4294967280 4294967280 + fff0 65520 65520 + +fffffffffffffff0 -16 18446744073709551600 +fffffffffffffff0 -16 18446744073709551600 + fff0 65520 65520 + fff0 65520 65520 + diff --git a/cmd/dtrace/test/tst/common/buffering/tst.fill1.d b/cmd/dtrace/test/tst/common/buffering/tst.fill1.d index 143ed641f9e7..fffc7e3d550c 100644 --- a/cmd/dtrace/test/tst/common/buffering/tst.fill1.d +++ b/cmd/dtrace/test/tst/common/buffering/tst.fill1.d @@ -23,26 +23,29 @@ * Copyright 2006 Sun Microsystems, Inc. All rights reserved. * Use is subject to license terms. */ - -#pragma ident "%Z%%M% %I% %E% SMI" +/* + * Copyright (c) 2012 by Delphix. All rights reserved. + */ /* * ASSERTION: * Positive test for fill buffer policy. * * SECTION: Buffers and Buffering/fill Policy; - * Buffers and Buffering/Buffer Sizes; + * Buffers and Buffering/Buffer Sizes; * Options and Tunables/bufsize; * Options and Tunables/bufpolicy; * Options and Tunables/statusrate */ /* - * This is a brute-force way of testing fill buffers. We assume that each - * printf() stores 8 bytes. Because each fill buffer is per-CPU, we must - * fill up our buffer in one series of enablings on a single CPU. + * This is a brute-force way of testing fill buffers. We assume that + * each printf() stores 16 bytes (4x 32-bit words for EPID, timestamp + * lo, timestamp hi, and the variable i). Because each fill buffer is + * per-CPU, we must fill up our buffer in one series of enablings on a + * single CPU. */ #pragma D option bufpolicy=fill -#pragma D option bufsize=64 +#pragma D option bufsize=128 #pragma D option statusrate=10ms #pragma D option quiet diff --git a/cmd/dtrace/test/tst/common/buffering/tst.ring3.d b/cmd/dtrace/test/tst/common/buffering/tst.ring3.d index 68e35889eca0..ea746948e5ef 100644 --- a/cmd/dtrace/test/tst/common/buffering/tst.ring3.d +++ b/cmd/dtrace/test/tst/common/buffering/tst.ring3.d @@ -23,8 +23,9 @@ * Copyright 2006 Sun Microsystems, Inc. All rights reserved. * Use is subject to license terms. */ - -#pragma ident "%Z%%M% %I% %E% SMI" +/* + * Copyright (c) 2012 by Delphix. All rights reserved. + */ /* * ASSERTION: @@ -37,19 +38,20 @@ */ /* - * We make some regrettable assumptions about the implementation in this test. - * First, we assume that each entry for the printf() of an int takes _exactly_ - * eight bytes (four bytes for the EPID, four bytes for the payload). Second, - * we assume that by allocating storage for n + 1 records, we will get exactly - * n. Here is why: the final predicate that evaluates to false will reserve - * space that it won't use. This act of reservation will advance the wrapped - * offset. That record won't be subsequently used, but the wrapped offset has - * advanced. (And in this case, that old record is clobbered by the exit() - * anyway.) Thirdly: we rely on t_cpu/cpu_id. Finally: we rely on being - * able to run on the CPU that we first ran on. + * We make some regrettable assumptions about the implementation in this + * test. First, we assume that each entry for the printf() of an int + * takes _exactly_ 16 bytes (4 bytes for the EPID, 8 bytes for the + * timestamp, 4 bytes for the payload). Second, we assume that by + * allocating storage for n + 1 records, we will get exactly n. Here is + * why: the final predicate that evaluates to false will reserve space + * that it won't use. This act of reservation will advance the wrapped + * offset. That record won't be subsequently used, but the wrapped + * offset has advanced. (And in this case, that old record is clobbered + * by the exit() anyway.) Thirdly: we rely on t_cpu/cpu_id. Finally: + * we rely on being able to run on the CPU that we first ran on. */ #pragma D option bufpolicy=ring -#pragma D option bufsize=40 +#pragma D option bufsize=80 #pragma D option quiet int n; diff --git a/cmd/dtrace/test/tst/common/cg/err.D_NOREG.noreg.d b/cmd/dtrace/test/tst/common/cg/err.D_NOREG.noreg.d new file mode 100644 index 000000000000..636e5686433d --- /dev/null +++ b/cmd/dtrace/test/tst/common/cg/err.D_NOREG.noreg.d @@ -0,0 +1,41 @@ +/* + * CDDL HEADER START + * + * This file and its contents are supplied under the terms of the + * Common Development and Distribution License ("CDDL"), version 1.0. + * You may only use this file in accordance with the terms of version + * 1.0 of the CDDL. + * + * A full copy of the text of the CDDL should have accompanied this + * source. A copy of the CDDL is also available via the Internet at + * http://www.illumos.org/license/CDDL. + * + * CDDL HEADER END + */ + +/* + * Copyright (c) 2012 by Delphix. All rights reserved. + */ + +/* + * Compile some code that requires exactly 9 registers. This should run out + * of registers. + * + * Changes to the code generator might cause this test to succeeed in which + * case the code should be changed to another sequence that exhausts the + * available internal registers. + * + * Note that this and err.baddif.d should be kept in sync. + */ + +BEGIN +{ + a = 4; + trace((a + a) * ((a + a) * ((a + a) * ((a + a) * ((a + a) * + ((a + a) * (a + a))))))); +} + +BEGIN +{ + exit(0); +} diff --git a/cmd/dtrace/test/tst/common/cg/err.baddif.d b/cmd/dtrace/test/tst/common/cg/err.baddif.d new file mode 100644 index 000000000000..d84934823354 --- /dev/null +++ b/cmd/dtrace/test/tst/common/cg/err.baddif.d @@ -0,0 +1,44 @@ +/* + * CDDL HEADER START + * + * This file and its contents are supplied under the terms of the + * Common Development and Distribution License ("CDDL"), version 1.0. + * You may only use this file in accordance with the terms of version + * 1.0 of the CDDL. + * + * A full copy of the text of the CDDL should have accompanied this + * source. A copy of the CDDL is also available via the Internet at + * http://www.illumos.org/license/CDDL. + * + * CDDL HEADER END + */ + +/* + * Copyright (c) 2012 by Delphix. All rights reserved. + */ + +/* + * Compile some code that requires exactly 9 registers. This should generate + * invalid DIF because the kernel will flag the fact that we're using more + * registers than are available internally. + * + * Changes to the code generator might cause this test to succeeed in which + * case the code should be changed to another sequence that exhausts the + * available internal registers. + * + * Note that this and err.D_NOREG.noreg.d should be kept in sync. + */ + +#pragma D option iregs=9 + +BEGIN +{ + a = 4; + trace((a + a) * ((a + a) * ((a + a) * ((a + a) * ((a + a) * + ((a + a) * (a + a))))))); +} + +BEGIN +{ + exit(0); +} diff --git a/cmd/dtrace/test/tst/common/env/err.D_PRAGMA_OPTSET.setfromscript.d b/cmd/dtrace/test/tst/common/env/err.D_PRAGMA_OPTSET.setfromscript.d new file mode 100644 index 000000000000..ec4b4ee0b179 --- /dev/null +++ b/cmd/dtrace/test/tst/common/env/err.D_PRAGMA_OPTSET.setfromscript.d @@ -0,0 +1,25 @@ +/* + * CDDL HEADER START + * + * This file and its contents are supplied under the terms of the + * Common Development and Distribution License ("CDDL"), version 1.0. + * You may only use this file in accordance with the terms of version + * 1.0 of the CDDL. + * + * A full copy of the text of the CDDL should have accompanied this + * source. A copy of the CDDL is also available via the Internet at + * http://www.illumos.org/license/CDDL. + * + * CDDL HEADER END + */ + +/* + * Copyright (c) 2012 by Delphix. All rights reserved. + */ + +#pragma D option setenv=balloon=something_bad_happens + +BEGIN +{ + exit(0); +} diff --git a/cmd/dtrace/test/tst/common/env/err.D_PRAGMA_OPTSET.unsetfromscript.d b/cmd/dtrace/test/tst/common/env/err.D_PRAGMA_OPTSET.unsetfromscript.d new file mode 100644 index 000000000000..7adc77fe7ea6 --- /dev/null +++ b/cmd/dtrace/test/tst/common/env/err.D_PRAGMA_OPTSET.unsetfromscript.d @@ -0,0 +1,25 @@ +/* + * CDDL HEADER START + * + * This file and its contents are supplied under the terms of the + * Common Development and Distribution License ("CDDL"), version 1.0. + * You may only use this file in accordance with the terms of version + * 1.0 of the CDDL. + * + * A full copy of the text of the CDDL should have accompanied this + * source. A copy of the CDDL is also available via the Internet at + * http://www.illumos.org/license/CDDL. + * + * CDDL HEADER END + */ + +/* + * Copyright (c) 2012 by Delphix. All rights reserved. + */ + +#pragma D option unsetenv=rectalexambot + +BEGIN +{ + exit(0); +} diff --git a/cmd/dtrace/test/tst/common/env/tst.ld_nolazyload.ksh b/cmd/dtrace/test/tst/common/env/tst.ld_nolazyload.ksh new file mode 100644 index 000000000000..731a207e6a7f --- /dev/null +++ b/cmd/dtrace/test/tst/common/env/tst.ld_nolazyload.ksh @@ -0,0 +1,33 @@ +# +# CDDL HEADER START +# +# This file and its contents are supplied under the terms of the +# Common Development and Distribution License ("CDDL"), version 1.0. +# You may only use this file in accordance with the terms of version +# 1.0 of the CDDL. +# +# A full copy of the text of the CDDL should have accompanied this +# source. A copy of the CDDL is also available via the Internet at +# http://www.illumos.org/license/CDDL. +# +# CDDL HEADER END +# + +# +# Copyright (c) 2012 by Delphix. All rights reserved. +# + +# +# Check that the LD_NOLAZYLOAD variable is set to 1 as expected. +# + +if [ $# != 1 ]; then + echo expected one argument: '<'dtrace-path'>' + exit 2 +fi + +dtrace=$1 + +$dtrace -q -Z -n doogle -c 'printenv LD_NOLAZYLOAD' + +exit $? diff --git a/cmd/dtrace/test/tst/common/env/tst.ld_nolazyload.ksh.out b/cmd/dtrace/test/tst/common/env/tst.ld_nolazyload.ksh.out new file mode 100644 index 000000000000..d474e1b4d626 --- /dev/null +++ b/cmd/dtrace/test/tst/common/env/tst.ld_nolazyload.ksh.out @@ -0,0 +1,2 @@ +1 + diff --git a/cmd/dtrace/test/tst/common/env/tst.setenv1.ksh b/cmd/dtrace/test/tst/common/env/tst.setenv1.ksh new file mode 100644 index 000000000000..b72b23d8a037 --- /dev/null +++ b/cmd/dtrace/test/tst/common/env/tst.setenv1.ksh @@ -0,0 +1,33 @@ +# +# CDDL HEADER START +# +# This file and its contents are supplied under the terms of the +# Common Development and Distribution License ("CDDL"), version 1.0. +# You may only use this file in accordance with the terms of version +# 1.0 of the CDDL. +# +# A full copy of the text of the CDDL should have accompanied this +# source. A copy of the CDDL is also available via the Internet at +# http://www.illumos.org/license/CDDL. +# +# CDDL HEADER END +# + +# +# Copyright (c) 2012 by Delphix. All rights reserved. +# + +# +# Reset an environment variable we already know to be set. +# + +if [ $# != 1 ]; then + echo expected one argument: '<'dtrace-path'>' + exit 2 +fi + +dtrace=$1 + +$dtrace -q -Z -n doogle -xsetenv=LD_NOLAZYLOAD=0 -c 'printenv LD_NOLAZYLOAD' + +exit $? diff --git a/cmd/dtrace/test/tst/common/env/tst.setenv1.ksh.out b/cmd/dtrace/test/tst/common/env/tst.setenv1.ksh.out new file mode 100644 index 000000000000..77ac542d4fbf --- /dev/null +++ b/cmd/dtrace/test/tst/common/env/tst.setenv1.ksh.out @@ -0,0 +1,2 @@ +0 + diff --git a/cmd/dtrace/test/tst/common/env/tst.setenv2.ksh b/cmd/dtrace/test/tst/common/env/tst.setenv2.ksh new file mode 100644 index 000000000000..4e962a812682 --- /dev/null +++ b/cmd/dtrace/test/tst/common/env/tst.setenv2.ksh @@ -0,0 +1,33 @@ +# +# CDDL HEADER START +# +# This file and its contents are supplied under the terms of the +# Common Development and Distribution License ("CDDL"), version 1.0. +# You may only use this file in accordance with the terms of version +# 1.0 of the CDDL. +# +# A full copy of the text of the CDDL should have accompanied this +# source. A copy of the CDDL is also available via the Internet at +# http://www.illumos.org/license/CDDL. +# +# CDDL HEADER END +# + +# +# Copyright (c) 2012 by Delphix. All rights reserved. +# + +# +# Test setting a variable that we isn't already set. +# + +if [ $# != 1 ]; then + echo expected one argument: '<'dtrace-path'>' + exit 2 +fi + +dtrace=$1 + +$dtrace -q -Z -n doogle -xsetenv=CORPORATIONS=PEOPLE -c 'printenv CORPORATIONS' + +exit $? diff --git a/cmd/dtrace/test/tst/common/env/tst.setenv2.ksh.out b/cmd/dtrace/test/tst/common/env/tst.setenv2.ksh.out new file mode 100644 index 000000000000..ca5c4ffdda9e --- /dev/null +++ b/cmd/dtrace/test/tst/common/env/tst.setenv2.ksh.out @@ -0,0 +1,2 @@ +PEOPLE + diff --git a/cmd/dtrace/test/tst/common/env/tst.unsetenv1.ksh b/cmd/dtrace/test/tst/common/env/tst.unsetenv1.ksh new file mode 100644 index 000000000000..73e1297d23b7 --- /dev/null +++ b/cmd/dtrace/test/tst/common/env/tst.unsetenv1.ksh @@ -0,0 +1,33 @@ +# +# CDDL HEADER START +# +# This file and its contents are supplied under the terms of the +# Common Development and Distribution License ("CDDL"), version 1.0. +# You may only use this file in accordance with the terms of version +# 1.0 of the CDDL. +# +# A full copy of the text of the CDDL should have accompanied this +# source. A copy of the CDDL is also available via the Internet at +# http://www.illumos.org/license/CDDL. +# +# CDDL HEADER END +# + +# +# Copyright (c) 2012 by Delphix. All rights reserved. +# + +# +# Test unsetting a variable we know to be set. +# + +if [ $# != 1 ]; then + echo expected one argument: '<'dtrace-path'>' + exit 2 +fi + +dtrace=$1 + +$dtrace -q -Z -n doogle -xunsetenv=LD_NOLAZYLOAD -c 'printenv LD_NOLAZYLOAD' + +exit $? diff --git a/cmd/dtrace/test/tst/common/env/tst.unsetenv1.ksh.out b/cmd/dtrace/test/tst/common/env/tst.unsetenv1.ksh.out new file mode 100644 index 000000000000..8b137891791f --- /dev/null +++ b/cmd/dtrace/test/tst/common/env/tst.unsetenv1.ksh.out @@ -0,0 +1 @@ + diff --git a/cmd/dtrace/test/tst/common/env/tst.unsetenv2.ksh b/cmd/dtrace/test/tst/common/env/tst.unsetenv2.ksh new file mode 100644 index 000000000000..467c60d775a6 --- /dev/null +++ b/cmd/dtrace/test/tst/common/env/tst.unsetenv2.ksh @@ -0,0 +1,35 @@ +# +# CDDL HEADER START +# +# This file and its contents are supplied under the terms of the +# Common Development and Distribution License ("CDDL"), version 1.0. +# You may only use this file in accordance with the terms of version +# 1.0 of the CDDL. +# +# A full copy of the text of the CDDL should have accompanied this +# source. A copy of the CDDL is also available via the Internet at +# http://www.illumos.org/license/CDDL. +# +# CDDL HEADER END +# + +# +# Copyright (c) 2012 by Delphix. All rights reserved. +# + +# +# Test invalid syntax to the unsetenv option. +# + +if [ $# != 1 ]; then + echo expected one argument: '<'dtrace-path'>' + exit 2 +fi + +dtrace=$1 + +$dtrace -q -Z -n doogle -xunsetenv=ed=screven -c 'true' 2>&1 + +[[ $? -eq 1 ]] && exit 0 + +exit 1 diff --git a/cmd/dtrace/test/tst/common/env/tst.unsetenv2.ksh.out b/cmd/dtrace/test/tst/common/env/tst.unsetenv2.ksh.out new file mode 100644 index 000000000000..a2dd32a393c2 --- /dev/null +++ b/cmd/dtrace/test/tst/common/env/tst.unsetenv2.ksh.out @@ -0,0 +1 @@ +dtrace: failed to set -x unsetenv: Invalid value for specified option diff --git a/cmd/dtrace/test/tst/common/pid/tst.newprobes.ksh b/cmd/dtrace/test/tst/common/pid/tst.newprobes.ksh index 35f0391ba87d..25ae061ec074 100644 --- a/cmd/dtrace/test/tst/common/pid/tst.newprobes.ksh +++ b/cmd/dtrace/test/tst/common/pid/tst.newprobes.ksh @@ -24,7 +24,9 @@ # Copyright 2008 Sun Microsystems, Inc. All rights reserved. # Use is subject to license terms. # -# ident "%Z%%M% %I% %E% SMI" + +# +# Copyright (c) 2012 by Delphix. All rights reserved. # if [ $# != 1 ]; then @@ -49,13 +51,13 @@ tick-1s tick-1s /(i % 2) == 0/ { - system("dtrace -c date -ln 'pid\$target::main:entry' >/dev/null"); + system("dtrace -c date -n 'pid\$target::main:entry' >/dev/null"); } tick-1s /(i % 2) == 1/ { - system("dtrace -c date -ln 'pid\$target::main:return' >/dev/null"); + system("dtrace -c date -n 'pid\$target::main:return' >/dev/null"); } EOF diff --git a/cmd/dtrace/test/tst/common/pointers/tst.assigncast1.d b/cmd/dtrace/test/tst/common/pointers/tst.assigncast1.d new file mode 100644 index 000000000000..0567123f3a8b --- /dev/null +++ b/cmd/dtrace/test/tst/common/pointers/tst.assigncast1.d @@ -0,0 +1,28 @@ +/* + * CDDL HEADER START + * + * This file and its contents are supplied under the terms of the + * Common Development and Distribution License ("CDDL"), version 1.0. + * You may only use this file in accordance with the terms of version + * 1.0 of the CDDL. + * + * A full copy of the text of the CDDL should have accompanied this + * source. A copy of the CDDL is also available via the Internet at + * http://www.illumos.org/license/CDDL. + * + * CDDL HEADER END + */ + +/* + * Copyright (c) 2012 by Delphix. All rights reserved. + */ + +BEGIN +{ + *((int *)alloca(4)) = 1; +} + +BEGIN +{ + exit(0); +} diff --git a/cmd/dtrace/test/tst/common/pointers/tst.assigncast2.d b/cmd/dtrace/test/tst/common/pointers/tst.assigncast2.d new file mode 100644 index 000000000000..6282e7ae15a3 --- /dev/null +++ b/cmd/dtrace/test/tst/common/pointers/tst.assigncast2.d @@ -0,0 +1,29 @@ +/* + * CDDL HEADER START + * + * This file and its contents are supplied under the terms of the + * Common Development and Distribution License ("CDDL"), version 1.0. + * You may only use this file in accordance with the terms of version + * 1.0 of the CDDL. + * + * A full copy of the text of the CDDL should have accompanied this + * source. A copy of the CDDL is also available via the Internet at + * http://www.illumos.org/license/CDDL. + * + * CDDL HEADER END + */ + +/* + * Copyright (c) 2012 by Delphix. All rights reserved. + */ + +BEGIN +{ + this->a = alloca(4); + *((int *)this->a) = 1; +} + +BEGIN +{ + exit(0); +} diff --git a/cmd/dtrace/test/tst/common/pragma/tst.temporal.ksh b/cmd/dtrace/test/tst/common/pragma/tst.temporal.ksh new file mode 100644 index 000000000000..9a0aed0678cf --- /dev/null +++ b/cmd/dtrace/test/tst/common/pragma/tst.temporal.ksh @@ -0,0 +1,106 @@ +#!/bin/ksh -p +# +# CDDL HEADER START +# +# This file and its contents are supplied under the terms of the +# Common Development and Distribution License ("CDDL"), version 1.0. +# You may only use this file in accordance with the terms of version +# 1.0 of the CDDL. +# +# A full copy of the text of the CDDL should have accompanied this +# source. A copy of the CDDL is also available via the Internet at +# http://www.illumos.org/license/CDDL. +# +# CDDL HEADER END +# + +# +# Copyright (c) 2012 by Delphix. All rights reserved. +# + +############################################################################ +# ASSERTION: +# temporal option causes output to be sorted +# +# SECTION: Pragma +# +# NOTES: The temporal option has no effect on a single-CPU system, so +# this needs to be run on a multi-CPU system to effectively test the +# temporal option. +# +############################################################################ + +if [ $# != 1 ]; then + echo expected one argument: '<'dtrace-path'>' + exit 2 +fi + +dtrace=$1 +file=/tmp/out.$$ + +rm -f $file + +$dtrace -o $file -c 'sleep 3' -s /dev/stdin < $file.2 + +sort -n $file.2 | diff $file.2 - +status=$? +if [ "$status" -ne 0 ]; then + echo $tst: output is not sorted + exit $status +fi + +head -n 1 $file.2 | grep begin >/dev/null +status=$? +if [ "$status" -ne 0 ]; then + echo $tst: begin probe did not fire + exit $status +fi + +tail -n 2 $file.2 | grep end >/dev/null +status=$? +if [ "$status" -ne 0 ]; then + echo $tst: end probe did not fire + exit $status +fi + +if [ $(tail -n 1 $file.2 | cut -f3 -d ' ') -ne \ + $(wc -l $file.2) ]; then + echo $tst: incorrect number of lines output + exit 1 +fi + +exit $status diff --git a/cmd/dtrace/test/tst/common/pragma/tst.temporal2.ksh b/cmd/dtrace/test/tst/common/pragma/tst.temporal2.ksh new file mode 100644 index 000000000000..4e8d592d81d6 --- /dev/null +++ b/cmd/dtrace/test/tst/common/pragma/tst.temporal2.ksh @@ -0,0 +1,102 @@ +#!/bin/ksh -p +# +# CDDL HEADER START +# +# This file and its contents are supplied under the terms of the +# Common Development and Distribution License ("CDDL"), version 1.0. +# You may only use this file in accordance with the terms of version +# 1.0 of the CDDL. +# +# A full copy of the text of the CDDL should have accompanied this +# source. A copy of the CDDL is also available via the Internet at +# http://www.illumos.org/license/CDDL. +# +# CDDL HEADER END +# + +# +# Copyright (c) 2012 by Delphix. All rights reserved. +# + +############################################################################ +# ASSERTION: +# temporal option causes output to be sorted, even when some +# buffers are empty +# +# SECTION: Pragma +# +# NOTES: The temporal option has no effect on a single-CPU system, so +# this needs to be run on a multi-CPU system to effectively test the +# temporal option. +# +############################################################################ + +if [ $# != 1 ]; then + echo expected one argument: '<'dtrace-path'>' + exit 2 +fi + +dtrace=$1 +file=/tmp/out.$$ + +rm -f $file + +$dtrace -o $file -s /dev/stdin < $file.2 + +sort -n $file.2 | diff $file.2 - +status=$? +if [ "$status" -ne 0 ]; then + echo $tst: output is not sorted + exit $status +fi + +exit $status diff --git a/cmd/dtrace/test/tst/common/pragma/tst.temporal3.d b/cmd/dtrace/test/tst/common/pragma/tst.temporal3.d new file mode 100644 index 000000000000..b4c0e557bea1 --- /dev/null +++ b/cmd/dtrace/test/tst/common/pragma/tst.temporal3.d @@ -0,0 +1,48 @@ +/* + * CDDL HEADER START + * + * This file and its contents are supplied under the terms of the + * Common Development and Distribution License ("CDDL"), version 1.0. + * You may only use this file in accordance with the terms of version + * 1.0 of the CDDL. + * + * A full copy of the text of the CDDL should have accompanied this + * source. A copy of the CDDL is also available via the Internet at + * http://www.illumos.org/license/CDDL. + * + * CDDL HEADER END + */ + +/* + * Copyright (c) 2012 by Delphix. All rights reserved. + */ + +/* + * This test excercises the "remnant" handling of the temporal option. + * At the end of one pass of retrieving and printing data from all CPUs, + * some unprocessed data will remain, because its timestamp is after the + * time covered by all CPUs' buffers. This unprocessed data is + * rearranged in a more space-efficient manner. If this is done + * incorrectly, an alignment error may occur. To test this, we use a + * high-frequency probe so that data will be recorded in subsequent + * CPU's buffers after the first CPU's buffer is obtained. The + * combination of data traced here (a 8-byte value and a 4-byte value) + * is effective to cause alignment problems with an incorrect + * implementation. + * + * This test needs to be run on a multi-CPU system to be effective. + */ + +#pragma D option quiet +#pragma D option temporal + +profile-4997 +{ + printf("%u %u", 1ULL, 2); +} + +tick-1 +/i++ == 10/ +{ + exit(0); +} diff --git a/cmd/dtrace/test/tst/common/predicates/tst.predcache.ksh b/cmd/dtrace/test/tst/common/predicates/tst.predcache.ksh deleted file mode 100644 index f06edcb5a4ec..000000000000 --- a/cmd/dtrace/test/tst/common/predicates/tst.predcache.ksh +++ /dev/null @@ -1,197 +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 2007 Sun Microsystems, Inc. All rights reserved. -# Use is subject to license terms. -# -# ident "%Z%%M% %I% %E% SMI" - -unload() -{ - # - # Get the list of services whose processes have USDT probes. Ideally - # it would be possible to unload the fasttrap provider while USDT - # probes exist -- once that fix is integrated, this hack can go away - # We create two lists -- one of regular SMF services and one of legacy - # services -- since each must be enabled and disabled using a specific - # mechanism. - # - pids=$(dtrace -l | \ - perl -ne 'print "$1\n" if (/^\s*\S+\s+\S*\D(\d+)\s+/);' | \ - sort | uniq | tr '\n' ',') - - ctids=$(ps -p $pids -o ctid | tail +2 | sort | uniq) - svcs= - lrcs= - - for ct in $ctids - do - line=$(svcs -o fmri,ctid | grep " $ct\$") - svc=$(echo $line | cut -d' ' -f1) - - if [[ $(svcs -Ho STA $svc) == "LRC" ]]; then - lrc=$(svcs -Ho SVC $svc | tr _ '?') - lrcs="$lrcs $lrc" - else - svcs="$svcs $svc" - fi - done - - for svc in $svcs - do - svcadm disable -ts $svc - done - - for lrc in $lrcs - do - # - # Does it seem a little paternalistic that lsvcrun requires - # this environment variable to be set? I'd say so... - # - SMF_RESTARTER=svc:/system/svc/restarter:default \ - /lib/svc/bin/lsvcrun $lrc stop - done - - modunload -i 0 - modunload -i 0 - modunload -i 0 - modinfo | grep dtrace - success=$? - - for svc in $svcs - do - svcadm enable -ts $svc - done - - for lrc in $lrcs - do - SMF_RESTARTER=svc:/system/svc/restarter:default \ - /lib/svc/bin/lsvcrun $lrc start - done - - if [ ! $success ]; then - echo $tst: could not unload dtrace - exit 1 - fi -} - -script1() -{ - $dtrace -s /dev/stdin <' - exit 2 -fi - -ppid=$$ -dtrace=$1 - -unload -script1 & -child=$! - -let waited=0 - -while [ "$waited" -lt 5 ]; do - seconds=`date +%S` - - if [ "$seconds" -ne "$last" ]; then - last=$seconds - let waited=waited+1 - fi -done - -wait $child -status=$? - -if [ "$status" -ne 0 ]; then - echo $tst: first dtrace failed - exit $status -fi - -unload -script2 & -child=$! - -let waited=0 - -while [ "$waited" -lt 10 ]; do - seconds=`date +%S` - - if [ "$seconds" -ne "$last" ]; then - last=$seconds - let waited=waited+1 - fi -done - -wait $child -status=$? - -exit $status diff --git a/cmd/dtrace/test/tst/common/print/err.D_PRINT_DYN.bad.d b/cmd/dtrace/test/tst/common/print/err.D_PRINT_DYN.bad.d deleted file mode 100644 index 892b44561376..000000000000 --- a/cmd/dtrace/test/tst/common/print/err.D_PRINT_DYN.bad.d +++ /dev/null @@ -1,29 +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) 2011 by Delphix. All rights reserved. - */ - -BEGIN -{ - print(*curpsinfo); -} diff --git a/cmd/dtrace/test/tst/common/print/tst.dyn.d b/cmd/dtrace/test/tst/common/print/tst.dyn.d new file mode 100644 index 000000000000..f17551facb4e --- /dev/null +++ b/cmd/dtrace/test/tst/common/print/tst.dyn.d @@ -0,0 +1,28 @@ +/* + * CDDL HEADER START + * + * This file and its contents are supplied under the terms of the + * Common Development and Distribution License ("CDDL"), version 1.0. + * You may only use this file in accordance with the terms of version + * 1.0 of the CDDL. + * + * A full copy of the text of the CDDL should have accompanied this + * source. A copy of the CDDL is also available via the Internet at + * http://www.illumos.org/license/CDDL. + * + * CDDL HEADER END + */ + +/* + * Copyright (c) 2012 by Delphix. All rights reserved. + */ + +BEGIN +{ + print(*curpsinfo); +} + +BEGIN +{ + exit(0); +} diff --git a/cmd/dtrace/test/tst/common/print/tst.xlate.d b/cmd/dtrace/test/tst/common/print/tst.xlate.d new file mode 100644 index 000000000000..e8125d4f5cba --- /dev/null +++ b/cmd/dtrace/test/tst/common/print/tst.xlate.d @@ -0,0 +1,42 @@ +/* + * CDDL HEADER START + * + * This file and its contents are supplied under the terms of the + * Common Development and Distribution License ("CDDL"), version 1.0. + * You may only use this file in accordance with the terms of version + * 1.0 of the CDDL. + * + * A full copy of the text of the CDDL should have accompanied this + * source. A copy of the CDDL is also available via the Internet at + * http://www.illumos.org/license/CDDL. + * + * CDDL HEADER END + */ + +/* + * Copyright (c) 2012 by Delphix. All rights reserved. + */ + +#pragma D option quiet + +typedef struct pancakes { + int i; + string s; + timespec_t t; +} pancakes_t; + +translator pancakes_t < void *V > { + i = 2 * 10; + s = strjoin("I like ", "pancakes"); + t = *(timespec_t *)`dtrace_zero; +}; + +BEGIN +{ + print(*(xlate < pancakes_t * > ((void *)NULL))); +} + +BEGIN +{ + exit(0); +} diff --git a/cmd/dtrace/test/tst/common/print/tst.xlate.d.out b/cmd/dtrace/test/tst/common/print/tst.xlate.d.out new file mode 100644 index 000000000000..9b01402af34b --- /dev/null +++ b/cmd/dtrace/test/tst/common/print/tst.xlate.d.out @@ -0,0 +1,8 @@ +pancakes_t { + int i = 0x14 + string s = [ "I like pancakes" ] + timespec_t t = { + time_t tv_sec = 0 + long tv_nsec = 0 + } +} diff --git a/cmd/dtrace/test/tst/common/printf/tst.ints.d.out b/cmd/dtrace/test/tst/common/printf/tst.ints.d.out index 4d2bb11207e1..bc7eaed0ec9a 100644 --- a/cmd/dtrace/test/tst/common/printf/tst.ints.d.out +++ b/cmd/dtrace/test/tst/common/printf/tst.ints.d.out @@ -1,6 +1,6 @@ -239 -52719 +-17 +-12817 -1867788817 1311768467294899695 diff --git a/cmd/dtrace/test/tst/common/printf/tst.signs.d b/cmd/dtrace/test/tst/common/printf/tst.signs.d new file mode 100644 index 000000000000..64e565e267b0 --- /dev/null +++ b/cmd/dtrace/test/tst/common/printf/tst.signs.d @@ -0,0 +1,38 @@ +/* + * CDDL HEADER START + * + * This file and its contents are supplied under the terms of the + * Common Development and Distribution License ("CDDL"), version 1.0. + * You may only use this file in accordance with the terms of version + * 1.0 of the CDDL. + * + * A full copy of the text of the CDDL should have accompanied this + * source. A copy of the CDDL is also available via the Internet at + * http://www.illumos.org/license/CDDL. + * + * CDDL HEADER END + */ + +/* + * Copyright (c) 2012 by Delphix. All rights reserved. + */ + +/* + * Check %d v. %i v. %u. + */ + +#pragma D option quiet + +uint16_t x; +int16_t y; + +BEGIN +{ + x = 0xffffffff; + y = 0xffffffff; + + printf("%d %i %u\n", x, x, x); + printf("%d %i %u\n", y, y, y); + + exit(0); +} diff --git a/cmd/dtrace/test/tst/common/printf/tst.signs.d.out b/cmd/dtrace/test/tst/common/printf/tst.signs.d.out new file mode 100644 index 000000000000..169ac59b9554 --- /dev/null +++ b/cmd/dtrace/test/tst/common/printf/tst.signs.d.out @@ -0,0 +1,3 @@ +65535 -1 65535 +-1 -1 65535 + diff --git a/cmd/dtrace/test/tst/common/speculation/err.BufSizeVariations1.d b/cmd/dtrace/test/tst/common/speculation/err.BufSizeVariations1.d index e97506e1108f..c59ea3bee57d 100644 --- a/cmd/dtrace/test/tst/common/speculation/err.BufSizeVariations1.d +++ b/cmd/dtrace/test/tst/common/speculation/err.BufSizeVariations1.d @@ -24,7 +24,10 @@ * Use is subject to license terms. */ -#pragma ident "%Z%%M% %I% %E% SMI" +/* + * Copyright (c) 2012 by Delphix. All rights reserved. + */ + /* * ASSERTION: @@ -35,17 +38,10 @@ * * NOTES: This test behaves differently depending on the values * assigned to bufsize. - * 1. 0 > bufsize. - * 2. 0 == bufsize. - * 3. 0 < bufsize <= 7 - * 4. 8 <= bufsize <= 31 - * 5. 32 <= bufsize <= 47 - * 6. 48 <= bufsize <= 71 - * 7. 72 <= bufsize */ #pragma D option quiet -#pragma D option bufsize=41 +#pragma D option bufsize=49 BEGIN { diff --git a/cmd/dtrace/test/tst/common/speculation/tst.SpecSizeVariations3.d b/cmd/dtrace/test/tst/common/speculation/tst.SpecSizeVariations3.d index 6b91efd9114b..99539f903eb6 100644 --- a/cmd/dtrace/test/tst/common/speculation/tst.SpecSizeVariations3.d +++ b/cmd/dtrace/test/tst/common/speculation/tst.SpecSizeVariations3.d @@ -24,7 +24,10 @@ * Use is subject to license terms. */ -#pragma ident "%Z%%M% %I% %E% SMI" +/* + * Copyright (c) 2012 by Delphix. All rights reserved. + */ + /* * ASSERTION: * Verify the behavior of speculations with changes in specsize. @@ -35,7 +38,7 @@ */ #pragma D option quiet -#pragma D option specsize=40 +#pragma D option specsize=48 BEGIN { diff --git a/cmd/dtrace/test/tst/common/trace/err.D_TRACE_DYN.bad.d b/cmd/dtrace/test/tst/common/trace/err.D_TRACE_DYN.bad.d deleted file mode 100644 index 8436df67353e..000000000000 --- a/cmd/dtrace/test/tst/common/trace/err.D_TRACE_DYN.bad.d +++ /dev/null @@ -1,29 +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) 2011 by Delphix. All rights reserved. - */ - -BEGIN -{ - trace(*curpsinfo); -} diff --git a/cmd/dtrace/test/tst/common/trace/tst.dyn.d b/cmd/dtrace/test/tst/common/trace/tst.dyn.d new file mode 100644 index 000000000000..24ad80fb469c --- /dev/null +++ b/cmd/dtrace/test/tst/common/trace/tst.dyn.d @@ -0,0 +1,28 @@ +/* + * CDDL HEADER START + * + * This file and its contents are supplied under the terms of the + * Common Development and Distribution License ("CDDL"), version 1.0. + * You may only use this file in accordance with the terms of version + * 1.0 of the CDDL. + * + * A full copy of the text of the CDDL should have accompanied this + * source. A copy of the CDDL is also available via the Internet at + * http://www.illumos.org/license/CDDL. + * + * CDDL HEADER END + */ + +/* + * Copyright (c) 2012 by Delphix. All rights reserved. + */ + +BEGIN +{ + trace(*curpsinfo); +} + +BEGIN +{ + exit(0); +} diff --git a/cmd/dtrace/test/tst/common/tracemem/err.D_PROTO_LEN.toomany.d b/cmd/dtrace/test/tst/common/tracemem/err.D_PROTO_LEN.toomany.d deleted file mode 100644 index dfe8e4d229fc..000000000000 --- a/cmd/dtrace/test/tst/common/tracemem/err.D_PROTO_LEN.toomany.d +++ /dev/null @@ -1,39 +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 2006 Sun Microsystems, Inc. All rights reserved. - * Use is subject to license terms. - */ - -#pragma ident "%Z%%M% %I% %E% SMI" - -/* - * ASSERTION: - * Test tracemem() with too many arguments. - * - * SECTION: Actions and Subroutines/tracemem() - */ - -BEGIN -{ - tracemem(123, 456, 789); -} diff --git a/cmd/dtrace/test/tst/common/translators/man.TestTransStability.d b/cmd/dtrace/test/tst/common/translators/man.TestTransStability.d deleted file mode 100644 index c664188f13a3..000000000000 --- a/cmd/dtrace/test/tst/common/translators/man.TestTransStability.d +++ /dev/null @@ -1,61 +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 2006 Sun Microsystems, Inc. All rights reserved. - * Use is subject to license terms. - */ - -#pragma ident "%Z%%M% %I% %E% SMI" - -/* - * ASSERTION: - * The D inline translation mechanism can be used to facilitate stable - * translations. - * - * SECTION: Translators/ Translator Declarations - * SECTION: Translators/ Translate Operator - * SECTION: Translators/Stable Translations - * - * NOTES: Uncomment the pragma that explicitly resets the attributes of - * myinfo identifier to Stable/Stable/Common from Private/Private/Unknown. - * Run the program with and without the comments as: - * /usr/sbin/dtrace -vs man.TestTransStability.d - */ - -#pragma D option quiet - -inline lwpsinfo_t *myinfo = xlate < lwpsinfo_t *> (curthread); - -/* -#pragma D attributes Stable/Stable/Common myinfo -*/ - -BEGIN -{ - trace(myinfo->pr_flag); - exit(0); -} - -ERROR -{ - exit(1); -} diff --git a/cmd/dtrace/test/tst/common/translators/tst.TestTransStability1.ksh b/cmd/dtrace/test/tst/common/translators/tst.TestTransStability1.ksh new file mode 100644 index 000000000000..16eeda32916b --- /dev/null +++ b/cmd/dtrace/test/tst/common/translators/tst.TestTransStability1.ksh @@ -0,0 +1,62 @@ +# +# CDDL HEADER START +# +# The contents of this file are subject to the terms of the +# Common Development and Distribution License (the "License"). +# You may not use this file except in compliance with the License. +# +# You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE +# or http://www.opensolaris.org/os/licensing. +# See the License for the specific language governing permissions +# and limitations under the License. +# +# When distributing Covered Code, include this CDDL HEADER in each +# file and include the License file at usr/src/OPENSOLARIS.LICENSE. +# If applicable, add the following below this CDDL HEADER, with the +# fields enclosed by brackets "[]" replaced with your own identifying +# information: Portions Copyright [yyyy] [name of copyright owner] +# +# CDDL HEADER END +# + +# +# Copyright 2006 Sun Microsystems, Inc. All rights reserved. +# Use is subject to license terms. +# + +# +# Copyright (c) 2012 by Delphix. All rights reserved. +# + +# +# Test the output for stable translations. +# + +if [ $# != 1 ]; then + echo expected one argument: '<'dtrace-path'>' + exit 2 +fi + +dtrace=$1 + +$dtrace -v -s /dev/stdin < (curthread); + +#pragma D attributes Stable/Stable/Common myinfo + +BEGIN +{ + this->a = myinfo->pr_flag; + exit(0); +} + +BEGIN +{ + exit(1); +} +EOF + +exit $? diff --git a/cmd/dtrace/test/tst/common/translators/tst.TestTransStability1.ksh.out b/cmd/dtrace/test/tst/common/translators/tst.TestTransStability1.ksh.out new file mode 100644 index 000000000000..43c1adb1a54f --- /dev/null +++ b/cmd/dtrace/test/tst/common/translators/tst.TestTransStability1.ksh.out @@ -0,0 +1,14 @@ + +Stability attributes for script /dev/stdin: + + Minimum Probe Description Attributes + Identifier Names: Unstable + Data Semantics: Unstable + Dependency Class: Common + + Minimum Statement Attributes + Identifier Names: Stable + Data Semantics: Stable + Dependency Class: Common + + diff --git a/cmd/dtrace/test/tst/common/translators/tst.TestTransStability2.ksh b/cmd/dtrace/test/tst/common/translators/tst.TestTransStability2.ksh new file mode 100644 index 000000000000..82070cde9237 --- /dev/null +++ b/cmd/dtrace/test/tst/common/translators/tst.TestTransStability2.ksh @@ -0,0 +1,60 @@ +# +# 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 2006 Sun Microsystems, Inc. All rights reserved. +# Use is subject to license terms. +# + +# +# Copyright (c) 2012 by Delphix. All rights reserved. +# + +# +# Test the output of unstable translations. +# + +if [ $# != 1 ]; then + echo expected one argument: '<'dtrace-path'>' + exit 2 +fi + +dtrace=$1 + +$dtrace -v -s /dev/stdin < (curthread); + +BEGIN +{ + this->a = myinfo->pr_flag; + exit(0); +} + +BEGIN +{ + exit(1); +} +EOF + +exit $? diff --git a/cmd/dtrace/test/tst/common/translators/tst.TestTransStability2.ksh.out b/cmd/dtrace/test/tst/common/translators/tst.TestTransStability2.ksh.out new file mode 100644 index 000000000000..f4b70f9573db --- /dev/null +++ b/cmd/dtrace/test/tst/common/translators/tst.TestTransStability2.ksh.out @@ -0,0 +1,14 @@ + +Stability attributes for script /dev/stdin: + + Minimum Probe Description Attributes + Identifier Names: Unstable + Data Semantics: Unstable + Dependency Class: Common + + Minimum Statement Attributes + Identifier Names: Private + Data Semantics: Private + Dependency Class: Unknown + + diff --git a/lib/libdtrace/common/dt_aggregate.c b/lib/libdtrace/common/dt_aggregate.c index bb766f71c466..1d78f086dba0 100644 --- a/lib/libdtrace/common/dt_aggregate.c +++ b/lib/libdtrace/common/dt_aggregate.c @@ -26,6 +26,7 @@ /* * Copyright (c) 2011, Joyent, Inc. All rights reserved. + * Copyright (c) 2012 by Delphix. All rights reserved. */ #include @@ -884,33 +885,14 @@ dt_aggregate_valcmp(const void *lhs, const void *rhs) caddr_t rdata = rh->dtahe_data.dtada_data; dtrace_recdesc_t *lrec, *rrec; int64_t *laddr, *raddr; - int rval, i; + int rval; - if ((rval = dt_aggregate_hashcmp(lhs, rhs)) != 0) - return (rval); + assert(lagg->dtagd_nrecs == ragg->dtagd_nrecs); - if (lagg->dtagd_nrecs > ragg->dtagd_nrecs) - return (DT_GREATERTHAN); + lrec = &lagg->dtagd_rec[lagg->dtagd_nrecs - 1]; + rrec = &ragg->dtagd_rec[ragg->dtagd_nrecs - 1]; - if (lagg->dtagd_nrecs < ragg->dtagd_nrecs) - return (DT_LESSTHAN); - - for (i = 0; i < lagg->dtagd_nrecs; i++) { - lrec = &lagg->dtagd_rec[i]; - rrec = &ragg->dtagd_rec[i]; - - if (lrec->dtrd_offset < rrec->dtrd_offset) - return (DT_LESSTHAN); - - if (lrec->dtrd_offset > rrec->dtrd_offset) - return (DT_GREATERTHAN); - - if (lrec->dtrd_action < rrec->dtrd_action) - return (DT_LESSTHAN); - - if (lrec->dtrd_action > rrec->dtrd_action) - return (DT_GREATERTHAN); - } + assert(lrec->dtrd_action == rrec->dtrd_action); laddr = (int64_t *)(uintptr_t)(ldata + lrec->dtrd_offset); raddr = (int64_t *)(uintptr_t)(rdata + rrec->dtrd_offset); diff --git a/lib/libdtrace/common/dt_cc.c b/lib/libdtrace/common/dt_cc.c index 8b8bcf475cba..4163e939944b 100644 --- a/lib/libdtrace/common/dt_cc.c +++ b/lib/libdtrace/common/dt_cc.c @@ -22,7 +22,7 @@ /* * 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. + * Copyright (c) 2012 by Delphix. All rights reserved. */ /* @@ -663,62 +663,47 @@ static void dt_action_trace(dtrace_hdl_t *dtp, dt_node_t *dnp, dtrace_stmtdesc_t *sdp) { dtrace_actdesc_t *ap = dt_stmt_action(dtp, sdp); + boolean_t istrace = (dnp->dn_ident->di_id == DT_ACT_TRACE); + const char *act = istrace ? "trace" : "print"; if (dt_node_is_void(dnp->dn_args)) { - dnerror(dnp->dn_args, D_TRACE_VOID, - "trace( ) may not be applied to a void expression\n"); + dnerror(dnp->dn_args, istrace ? D_TRACE_VOID : D_PRINT_VOID, + "%s( ) may not be applied to a void expression\n", act); } - if (dt_node_is_dynamic(dnp->dn_args)) { - dnerror(dnp->dn_args, D_TRACE_DYN, - "trace( ) may not be applied to a dynamic expression\n"); - } - - dt_cg(yypcb, dnp->dn_args); - ap->dtad_difo = dt_as(yypcb); - 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"); + if (dt_node_resolve(dnp->dn_args, DT_IDENT_XLPTR) != NULL) { + dnerror(dnp->dn_args, istrace ? D_TRACE_DYN : D_PRINT_DYN, + "%s( ) may not be applied to a translated pointer\n", act); } dt_cg(yypcb, dnp->dn_args); - dret = yypcb->pcb_dret; - dmp = dt_module_lookup_by_ctf(dtp, dret->dn_ctfp); + /* + * 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. + */ + if (dnp->dn_ident->di_id == DT_ACT_PRINT) { + dt_node_t *dret; + size_t n; + dt_module_t *dmp; - 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); + dret = yypcb->pcb_dret; + dmp = dt_module_lookup_by_ctf(dtp, dret->dn_ctfp); + + n = snprintf(NULL, 0, "%s`%d", dmp->dm_name, dret->dn_type) + 1; + sdp->dtsd_strdata = dt_alloc(dtp, n); + if (sdp->dtsd_strdata == NULL) + longjmp(yypcb->pcb_jmpbuf, EDT_NOMEM); + (void) snprintf(sdp->dtsd_strdata, n, "%s`%d", dmp->dm_name, + dret->dn_type); + } ap->dtad_difo = dt_as(yypcb); ap->dtad_kind = DTRACEACT_DIFEXPR; @@ -1073,6 +1058,9 @@ dt_compile_fun(dtrace_hdl_t *dtp, dt_node_t *dnp, dtrace_stmtdesc_t *sdp) case DT_ACT_PANIC: dt_action_panic(dtp, dnp->dn_expr, sdp); break; + case DT_ACT_PRINT: + dt_action_trace(dtp, dnp->dn_expr, sdp); + break; case DT_ACT_PRINTA: dt_action_printa(dtp, dnp->dn_expr, sdp); break; @@ -1103,9 +1091,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; @@ -2462,7 +2447,8 @@ dt_compile(dtrace_hdl_t *dtp, int context, dtrace_probespec_t pspec, void *arg, } out: - if (context != DT_CTX_DTYPE && DT_TREEDUMP_PASS(dtp, 3)) + if (context != DT_CTX_DTYPE && yypcb->pcb_root != NULL && + DT_TREEDUMP_PASS(dtp, 3)) dt_node_printr(yypcb->pcb_root, stderr, 0); if (dtp->dt_cdefs_fd != -1 && (ftruncate64(dtp->dt_cdefs_fd, 0) == -1 || diff --git a/lib/libdtrace/common/dt_cg.c b/lib/libdtrace/common/dt_cg.c index 4557c6f85cfa..3103106d2793 100644 --- a/lib/libdtrace/common/dt_cg.c +++ b/lib/libdtrace/common/dt_cg.c @@ -19,12 +19,15 @@ * * CDDL HEADER END */ + /* * Copyright 2005 Sun Microsystems, Inc. All rights reserved. * Use is subject to license terms. */ -#pragma ident "%Z%%M% %I% %E% SMI" +/* + * Copyright (c) 2012 by Delphix. All rights reserved. + */ #include #include @@ -193,9 +196,6 @@ dt_cg_ptrsize(dt_node_t *dnp, dt_irlist_t *dlp, dt_regset_t *drp, ssize_t size; int sreg; - if ((sreg = dt_regset_alloc(drp)) == -1) - longjmp(yypcb->pcb_jmpbuf, EDT_NOREG); - type = ctf_type_resolve(ctfp, dnp->dn_type); kind = ctf_type_kind(ctfp, type); assert(kind == CTF_K_POINTER || kind == CTF_K_ARRAY); @@ -212,6 +212,7 @@ dt_cg_ptrsize(dt_node_t *dnp, dt_irlist_t *dlp, dt_regset_t *drp, if ((size = ctf_type_size(ctfp, type)) == 1) return; /* multiply or divide by one can be omitted */ + sreg = dt_regset_alloc(drp); dt_cg_setx(dlp, sreg, size); instr = DIF_INSTR_FMT(op, dreg, sreg, dreg); dt_irlist_append(dlp, dt_cg_node_alloc(DT_LBL_NONE, instr)); @@ -251,9 +252,7 @@ dt_cg_field_get(dt_node_t *dnp, dt_irlist_t *dlp, dt_regset_t *drp, assert(dnp->dn_op == DT_TOK_PTR || dnp->dn_op == DT_TOK_DOT); r1 = dnp->dn_left->dn_reg; - - if ((r2 = dt_regset_alloc(drp)) == -1) - longjmp(yypcb->pcb_jmpbuf, EDT_NOREG); + r2 = dt_regset_alloc(drp); /* * On little-endian architectures, ctm_offset counts from the right so @@ -356,10 +355,9 @@ dt_cg_field_set(dt_node_t *src, dt_irlist_t *dlp, "bits %u\n", m.ctm_offset, m.ctm_type, e.cte_bits); } - if ((r1 = dt_regset_alloc(drp)) == -1 || - (r2 = dt_regset_alloc(drp)) == -1 || - (r3 = dt_regset_alloc(drp)) == -1) - longjmp(yypcb->pcb_jmpbuf, EDT_NOREG); + r1 = dt_regset_alloc(drp); + r2 = dt_regset_alloc(drp); + r3 = dt_regset_alloc(drp); /* * Compute shifts and masks. We need to compute "shift" as the amount @@ -423,8 +421,7 @@ dt_cg_store(dt_node_t *src, dt_irlist_t *dlp, dt_regset_t *drp, dt_node_t *dst) size = dt_node_type_size(src); if (src->dn_flags & DT_NF_REF) { - if ((reg = dt_regset_alloc(drp)) == -1) - longjmp(yypcb->pcb_jmpbuf, EDT_NOREG); + reg = dt_regset_alloc(drp); dt_cg_setx(dlp, reg, size); instr = DIF_INSTR_COPYS(src->dn_reg, reg, dst->dn_reg); dt_irlist_append(dlp, dt_cg_node_alloc(DT_LBL_NONE, instr)); @@ -474,30 +471,58 @@ dt_cg_typecast(const dt_node_t *src, const dt_node_t *dst, size_t dstsize = dt_node_type_size(dst); dif_instr_t instr; - int reg, n; + int rg; - if (dt_node_is_scalar(dst) && (dstsize < srcsize || - (src->dn_flags & DT_NF_SIGNED) ^ (dst->dn_flags & DT_NF_SIGNED))) { - if ((reg = dt_regset_alloc(drp)) == -1) - longjmp(yypcb->pcb_jmpbuf, EDT_NOREG); + if (!dt_node_is_scalar(dst)) + return; /* not a scalar */ + if (dstsize == srcsize && + ((src->dn_flags ^ dst->dn_flags) & DT_NF_SIGNED) != 0) + return; /* not narrowing or changing signed-ness */ + if (dstsize > srcsize && (src->dn_flags & DT_NF_SIGNED) == 0) + return; /* nothing to do in this case */ - if (dstsize < srcsize) - n = sizeof (uint64_t) * NBBY - dstsize * NBBY; - else - n = sizeof (uint64_t) * NBBY - srcsize * NBBY; + rg = dt_regset_alloc(drp); - dt_cg_setx(dlp, reg, n); + if (dstsize > srcsize) { + int n = sizeof (uint64_t) * NBBY - srcsize * NBBY; + int s = (dstsize - srcsize) * NBBY; - instr = DIF_INSTR_FMT(DIF_OP_SLL, - src->dn_reg, reg, dst->dn_reg); + dt_cg_setx(dlp, rg, n); + + instr = DIF_INSTR_FMT(DIF_OP_SLL, src->dn_reg, rg, dst->dn_reg); + dt_irlist_append(dlp, dt_cg_node_alloc(DT_LBL_NONE, instr)); + + if ((dst->dn_flags & DT_NF_SIGNED) || n == s) { + instr = DIF_INSTR_FMT(DIF_OP_SRA, + dst->dn_reg, rg, dst->dn_reg); + dt_irlist_append(dlp, + dt_cg_node_alloc(DT_LBL_NONE, instr)); + } else { + dt_cg_setx(dlp, rg, s); + instr = DIF_INSTR_FMT(DIF_OP_SRA, + dst->dn_reg, rg, dst->dn_reg); + dt_irlist_append(dlp, + dt_cg_node_alloc(DT_LBL_NONE, instr)); + dt_cg_setx(dlp, rg, n - s); + instr = DIF_INSTR_FMT(DIF_OP_SRL, + dst->dn_reg, rg, dst->dn_reg); + dt_irlist_append(dlp, + dt_cg_node_alloc(DT_LBL_NONE, instr)); + } + } else if (dstsize != sizeof (uint64_t)) { + int n = sizeof (uint64_t) * NBBY - dstsize * NBBY; + + dt_cg_setx(dlp, rg, n); + + instr = DIF_INSTR_FMT(DIF_OP_SLL, src->dn_reg, rg, dst->dn_reg); dt_irlist_append(dlp, dt_cg_node_alloc(DT_LBL_NONE, instr)); instr = DIF_INSTR_FMT((dst->dn_flags & DT_NF_SIGNED) ? - DIF_OP_SRA : DIF_OP_SRL, dst->dn_reg, reg, dst->dn_reg); - + DIF_OP_SRA : DIF_OP_SRL, dst->dn_reg, rg, dst->dn_reg); dt_irlist_append(dlp, dt_cg_node_alloc(DT_LBL_NONE, instr)); - dt_regset_free(drp, reg); } + + dt_regset_free(drp, rg); } /* @@ -523,8 +548,7 @@ dt_cg_arglist(dt_ident_t *idp, dt_node_t *args, for (dnp = args; dnp != NULL; dnp = dnp->dn_list) dt_cg_node(dnp, dlp, drp); - dt_irlist_append(dlp, - dt_cg_node_alloc(DT_LBL_NONE, DIF_INSTR_FLUSHTS)); + dt_irlist_append(dlp, dt_cg_node_alloc(DT_LBL_NONE, DIF_INSTR_FLUSHTS)); for (dnp = args; dnp != NULL; dnp = dnp->dn_list, i++) { dtrace_diftype_t t; @@ -538,17 +562,18 @@ dt_cg_arglist(dt_ident_t *idp, dt_node_t *args, dt_cg_typecast(dnp, &isp->dis_args[i], dlp, drp); isp->dis_args[i].dn_reg = -1; - if (t.dtdt_flags & DIF_TF_BYREF) + if (t.dtdt_flags & DIF_TF_BYREF) { op = DIF_OP_PUSHTR; - else + if (t.dtdt_size != 0) { + reg = dt_regset_alloc(drp); + dt_cg_setx(dlp, reg, t.dtdt_size); + } else { + reg = DIF_REG_R0; + } + } else { op = DIF_OP_PUSHTV; - - if (t.dtdt_size != 0) { - if ((reg = dt_regset_alloc(drp)) == -1) - longjmp(yypcb->pcb_jmpbuf, EDT_NOREG); - dt_cg_setx(dlp, reg, t.dtdt_size); - } else reg = DIF_REG_R0; + } instr = DIF_INSTR_PUSHTS(op, t.dtdt_kind, reg, dnp->dn_reg); dt_irlist_append(dlp, dt_cg_node_alloc(DT_LBL_NONE, instr)); @@ -629,9 +654,7 @@ dt_cg_prearith_op(dt_node_t *dnp, dt_irlist_t *dlp, dt_regset_t *drp, uint_t op) dt_cg_node(dnp->dn_child, dlp, drp); dnp->dn_reg = dnp->dn_child->dn_reg; - if ((reg = dt_regset_alloc(drp)) == -1) - longjmp(yypcb->pcb_jmpbuf, EDT_NOREG); - + reg = dt_regset_alloc(drp); dt_cg_setx(dlp, reg, size); instr = DIF_INSTR_FMT(op, dnp->dn_reg, reg, dnp->dn_reg); @@ -688,9 +711,7 @@ dt_cg_postarith_op(dt_node_t *dnp, dt_irlist_t *dlp, dt_cg_node(dnp->dn_child, dlp, drp); dnp->dn_reg = dnp->dn_child->dn_reg; - if ((nreg = dt_regset_alloc(drp)) == -1) - longjmp(yypcb->pcb_jmpbuf, EDT_NOREG); - + nreg = dt_regset_alloc(drp); dt_cg_setx(dlp, nreg, size); instr = DIF_INSTR_FMT(op, dnp->dn_reg, nreg, nreg); dt_irlist_append(dlp, dt_cg_node_alloc(DT_LBL_NONE, instr)); @@ -1008,9 +1029,7 @@ dt_cg_asgn_op(dt_node_t *dnp, dt_irlist_t *dlp, dt_regset_t *drp) * set it to the size of our data structure, and then replace * it with the result of an allocs of the specified size. */ - if ((r1 = dt_regset_alloc(drp)) == -1) - longjmp(yypcb->pcb_jmpbuf, EDT_NOREG); - + r1 = dt_regset_alloc(drp); dt_cg_setx(dlp, r1, ctf_type_size(dxp->dx_dst_ctfp, dxp->dx_dst_base)); @@ -1054,8 +1073,7 @@ dt_cg_asgn_op(dt_node_t *dnp, dt_irlist_t *dlp, dt_regset_t *drp) * and add r1 to it before storing the result. */ if (ctm.ctm_offset != 0) { - if ((r2 = dt_regset_alloc(drp)) == -1) - longjmp(yypcb->pcb_jmpbuf, EDT_NOREG); + r2 = dt_regset_alloc(drp); /* * Add the member offset rounded down to the @@ -1142,8 +1160,7 @@ dt_cg_assoc_op(dt_node_t *dnp, dt_irlist_t *dlp, dt_regset_t *drp) dt_cg_arglist(dnp->dn_ident, dnp->dn_args, dlp, drp); - if ((dnp->dn_reg = dt_regset_alloc(drp)) == -1) - longjmp(yypcb->pcb_jmpbuf, EDT_NOREG); + dnp->dn_reg = dt_regset_alloc(drp); if (dnp->dn_ident->di_flags & DT_IDFLG_TLS) op = DIF_OP_LDTAA; @@ -1273,9 +1290,7 @@ dt_cg_array_op(dt_node_t *dnp, dt_irlist_t *dlp, dt_regset_t *drp) if ((size = dt_node_type_size(dnp)) == sizeof (uint64_t)) return; - if ((reg = dt_regset_alloc(drp)) == -1) - longjmp(yypcb->pcb_jmpbuf, EDT_NOREG); - + reg = dt_regset_alloc(drp); assert(size < sizeof (uint64_t)); n = sizeof (uint64_t) * NBBY - size * NBBY; @@ -1338,6 +1353,162 @@ dt_cg_inline(dt_node_t *dnp, dt_irlist_t *dlp, dt_regset_t *drp) } } +typedef struct dt_xlmemb { + dt_ident_t *dtxl_idp; /* translated ident */ + dt_irlist_t *dtxl_dlp; /* instruction list */ + dt_regset_t *dtxl_drp; /* register set */ + int dtxl_sreg; /* location of the translation input */ + int dtxl_dreg; /* location of our allocated buffer */ +} dt_xlmemb_t; + +/*ARGSUSED*/ +static int +dt_cg_xlate_member(const char *name, ctf_id_t type, ulong_t off, void *arg) +{ + dt_xlmemb_t *dx = arg; + dt_ident_t *idp = dx->dtxl_idp; + dt_irlist_t *dlp = dx->dtxl_dlp; + dt_regset_t *drp = dx->dtxl_drp; + + dt_node_t *mnp; + dt_xlator_t *dxp; + + int reg, treg; + uint32_t instr; + size_t size; + + /* Generate code for the translation. */ + dxp = idp->di_data; + mnp = dt_xlator_member(dxp, name); + + /* If there's no translator for the given member, skip it. */ + if (mnp == NULL) + return (0); + + dxp->dx_ident->di_flags |= DT_IDFLG_CGREG; + dxp->dx_ident->di_id = dx->dtxl_sreg; + + dt_cg_node(mnp->dn_membexpr, dlp, drp); + + dxp->dx_ident->di_flags &= ~DT_IDFLG_CGREG; + dxp->dx_ident->di_id = 0; + + treg = mnp->dn_membexpr->dn_reg; + + /* Compute the offset into our buffer and store the result there. */ + reg = dt_regset_alloc(drp); + + dt_cg_setx(dlp, reg, off / NBBY); + instr = DIF_INSTR_FMT(DIF_OP_ADD, dx->dtxl_dreg, reg, reg); + dt_irlist_append(dlp, dt_cg_node_alloc(DT_LBL_NONE, instr)); + + size = ctf_type_size(mnp->dn_membexpr->dn_ctfp, + mnp->dn_membexpr->dn_type); + if (dt_node_is_scalar(mnp->dn_membexpr)) { + /* + * Copying scalars is simple. + */ + switch (size) { + case 1: + instr = DIF_INSTR_STORE(DIF_OP_STB, treg, reg); + break; + case 2: + instr = DIF_INSTR_STORE(DIF_OP_STH, treg, reg); + break; + case 4: + instr = DIF_INSTR_STORE(DIF_OP_STW, treg, reg); + break; + case 8: + instr = DIF_INSTR_STORE(DIF_OP_STX, treg, reg); + break; + default: + xyerror(D_UNKNOWN, "internal error -- unexpected " + "size: %lu\n", (ulong_t)size); + } + + dt_irlist_append(dlp, dt_cg_node_alloc(DT_LBL_NONE, instr)); + + } else if (dt_node_is_string(mnp->dn_membexpr)) { + int szreg; + + /* + * Use the copys instruction for strings. + */ + szreg = dt_regset_alloc(drp); + dt_cg_setx(dlp, szreg, size); + instr = DIF_INSTR_COPYS(treg, szreg, reg); + dt_irlist_append(dlp, dt_cg_node_alloc(DT_LBL_NONE, instr)); + dt_regset_free(drp, szreg); + } else { + int szreg; + + /* + * If it's anything else then we'll just bcopy it. + */ + szreg = dt_regset_alloc(drp); + dt_cg_setx(dlp, szreg, size); + dt_irlist_append(dlp, + dt_cg_node_alloc(DT_LBL_NONE, DIF_INSTR_FLUSHTS)); + instr = DIF_INSTR_PUSHTS(DIF_OP_PUSHTV, DIF_TYPE_CTF, + DIF_REG_R0, treg); + dt_irlist_append(dlp, dt_cg_node_alloc(DT_LBL_NONE, instr)); + instr = DIF_INSTR_PUSHTS(DIF_OP_PUSHTV, DIF_TYPE_CTF, + DIF_REG_R0, reg); + dt_irlist_append(dlp, dt_cg_node_alloc(DT_LBL_NONE, instr)); + instr = DIF_INSTR_PUSHTS(DIF_OP_PUSHTV, DIF_TYPE_CTF, + DIF_REG_R0, szreg); + dt_irlist_append(dlp, dt_cg_node_alloc(DT_LBL_NONE, instr)); + instr = DIF_INSTR_CALL(DIF_SUBR_BCOPY, szreg); + dt_irlist_append(dlp, dt_cg_node_alloc(DT_LBL_NONE, instr)); + dt_regset_free(drp, szreg); + } + + dt_regset_free(drp, reg); + dt_regset_free(drp, treg); + + return (0); +} + +/* + * If we're expanding a translated type, we create an appropriately sized + * buffer with alloca() and then translate each member into it. + */ +static int +dt_cg_xlate_expand(dt_node_t *dnp, dt_ident_t *idp, dt_irlist_t *dlp, + dt_regset_t *drp) +{ + dt_xlmemb_t dlm; + uint32_t instr; + int dreg; + size_t size; + + dreg = dt_regset_alloc(drp); + size = ctf_type_size(dnp->dn_ident->di_ctfp, dnp->dn_ident->di_type); + + /* Call alloca() to create the buffer. */ + dt_cg_setx(dlp, dreg, size); + + dt_irlist_append(dlp, dt_cg_node_alloc(DT_LBL_NONE, DIF_INSTR_FLUSHTS)); + + instr = DIF_INSTR_PUSHTS(DIF_OP_PUSHTV, DIF_TYPE_CTF, DIF_REG_R0, dreg); + dt_irlist_append(dlp, dt_cg_node_alloc(DT_LBL_NONE, instr)); + + instr = DIF_INSTR_CALL(DIF_SUBR_ALLOCA, dreg); + dt_irlist_append(dlp, dt_cg_node_alloc(DT_LBL_NONE, instr)); + + /* Generate the translation for each member. */ + dlm.dtxl_idp = idp; + dlm.dtxl_dlp = dlp; + dlm.dtxl_drp = drp; + dlm.dtxl_sreg = dnp->dn_reg; + dlm.dtxl_dreg = dreg; + (void) ctf_member_iter(dnp->dn_ident->di_ctfp, + dnp->dn_ident->di_type, dt_cg_xlate_member, + &dlm); + + return (dreg); +} + static void dt_cg_node(dt_node_t *dnp, dt_irlist_t *dlp, dt_regset_t *drp) { @@ -1350,7 +1521,6 @@ dt_cg_node(dt_node_t *dnp, dt_irlist_t *dlp, dt_regset_t *drp) dt_ident_t *idp; ssize_t stroff; uint_t op; - int reg; switch (dnp->dn_op) { case DT_TOK_COMMA: @@ -1552,7 +1722,16 @@ dt_cg_node(dt_node_t *dnp, dt_irlist_t *dlp, dt_regset_t *drp) dt_cg_node(dnp->dn_child, dlp, drp); dnp->dn_reg = dnp->dn_child->dn_reg; - if (!(dnp->dn_flags & DT_NF_REF)) { + if (dt_node_is_dynamic(dnp->dn_child)) { + int reg; + idp = dt_node_resolve(dnp->dn_child, DT_IDENT_XLPTR); + assert(idp != NULL); + reg = dt_cg_xlate_expand(dnp, idp, dlp, drp); + + dt_regset_free(drp, dnp->dn_child->dn_reg); + dnp->dn_reg = reg; + + } else if (!(dnp->dn_flags & DT_NF_REF)) { uint_t ubit = dnp->dn_flags & DT_NF_USERLAND; /* @@ -1588,10 +1767,7 @@ dt_cg_node(dt_node_t *dnp, dt_irlist_t *dlp, dt_regset_t *drp) case DT_TOK_SIZEOF: { size_t size = dt_node_sizeof(dnp->dn_child); - - if ((dnp->dn_reg = dt_regset_alloc(drp)) == -1) - longjmp(yypcb->pcb_jmpbuf, EDT_NOREG); - + dnp->dn_reg = dt_regset_alloc(drp); assert(size != 0); dt_cg_setx(dlp, dnp->dn_reg, size); break; @@ -1616,8 +1792,7 @@ dt_cg_node(dt_node_t *dnp, dt_irlist_t *dlp, dt_regset_t *drp) assert(dxp->dx_ident->di_flags & DT_IDFLG_CGREG); assert(dxp->dx_ident->di_id != 0); - if ((dnp->dn_reg = dt_regset_alloc(drp)) == -1) - longjmp(yypcb->pcb_jmpbuf, EDT_NOREG); + dnp->dn_reg = dt_regset_alloc(drp); if (dxp->dx_arg == -1) { instr = DIF_INSTR_MOV( @@ -1701,8 +1876,9 @@ dt_cg_node(dt_node_t *dnp, dt_irlist_t *dlp, dt_regset_t *drp) } if (m.ctm_offset != 0) { - if ((reg = dt_regset_alloc(drp)) == -1) - longjmp(yypcb->pcb_jmpbuf, EDT_NOREG); + int reg; + + reg = dt_regset_alloc(drp); /* * If the offset is not aligned on a byte boundary, it @@ -1748,8 +1924,7 @@ dt_cg_node(dt_node_t *dnp, dt_irlist_t *dlp, dt_regset_t *drp) break; case DT_TOK_STRING: - if ((dnp->dn_reg = dt_regset_alloc(drp)) == -1) - longjmp(yypcb->pcb_jmpbuf, EDT_NOREG); + dnp->dn_reg = dt_regset_alloc(drp); assert(dnp->dn_kind == DT_NODE_STRING); stroff = dt_strtab_insert(yypcb->pcb_strtab, dnp->dn_string); @@ -1772,8 +1947,7 @@ dt_cg_node(dt_node_t *dnp, dt_irlist_t *dlp, dt_regset_t *drp) */ if (dnp->dn_kind == DT_NODE_VAR && (dnp->dn_ident->di_flags & DT_IDFLG_CGREG)) { - if ((dnp->dn_reg = dt_regset_alloc(drp)) == -1) - longjmp(yypcb->pcb_jmpbuf, EDT_NOREG); + dnp->dn_reg = dt_regset_alloc(drp); instr = DIF_INSTR_MOV(dnp->dn_ident->di_id, dnp->dn_reg); dt_irlist_append(dlp, @@ -1803,11 +1977,9 @@ dt_cg_node(dt_node_t *dnp, dt_irlist_t *dlp, dt_regset_t *drp) dt_cg_arglist(dnp->dn_ident, dnp->dn_args, dlp, drp); - if ((dnp->dn_reg = dt_regset_alloc(drp)) == -1) - longjmp(yypcb->pcb_jmpbuf, EDT_NOREG); - - instr = DIF_INSTR_CALL( - dnp->dn_ident->di_id, dnp->dn_reg); + dnp->dn_reg = dt_regset_alloc(drp); + instr = DIF_INSTR_CALL(dnp->dn_ident->di_id, + dnp->dn_reg); dt_irlist_append(dlp, dt_cg_node_alloc(DT_LBL_NONE, instr)); @@ -1834,8 +2006,7 @@ dt_cg_node(dt_node_t *dnp, dt_irlist_t *dlp, dt_regset_t *drp) break; } - if ((dnp->dn_reg = dt_regset_alloc(drp)) == -1) - longjmp(yypcb->pcb_jmpbuf, EDT_NOREG); + dnp->dn_reg = dt_regset_alloc(drp); if (dnp->dn_ident->di_flags & DT_IDFLG_LOCAL) op = DIF_OP_LDLS; @@ -1865,9 +2036,7 @@ dt_cg_node(dt_node_t *dnp, dt_irlist_t *dlp, dt_regset_t *drp) dtrace_errmsg(dtp, dtrace_errno(dtp))); } - if ((dnp->dn_reg = dt_regset_alloc(drp)) == -1) - longjmp(yypcb->pcb_jmpbuf, EDT_NOREG); - + dnp->dn_reg = dt_regset_alloc(drp); dt_cg_xsetx(dlp, dnp->dn_ident, DT_LBL_NONE, dnp->dn_reg, sym.st_value); @@ -1887,9 +2056,7 @@ dt_cg_node(dt_node_t *dnp, dt_irlist_t *dlp, dt_regset_t *drp) break; case DT_TOK_INT: - if ((dnp->dn_reg = dt_regset_alloc(drp)) == -1) - longjmp(yypcb->pcb_jmpbuf, EDT_NOREG); - + dnp->dn_reg = dt_regset_alloc(drp); dt_cg_setx(dlp, dnp->dn_reg, dnp->dn_value); break; @@ -1904,6 +2071,7 @@ dt_cg(dt_pcb_t *pcb, dt_node_t *dnp) { dif_instr_t instr; dt_xlator_t *dxp; + dt_ident_t *idp; if (pcb->pcb_regs == NULL && (pcb->pcb_regs = dt_regset_create(pcb->pcb_hdl->dt_conf.dtc_difintregs)) == NULL) @@ -1930,9 +2098,9 @@ dt_cg(dt_pcb_t *pcb, dt_node_t *dnp) assert(pcb->pcb_dret == NULL); pcb->pcb_dret = dnp; - if (dt_node_is_dynamic(dnp)) { + if (dt_node_resolve(dnp, DT_IDENT_XLPTR) != NULL) { dnerror(dnp, D_CG_DYN, "expression cannot evaluate to result " - "of dynamic type\n"); + "of a translated pointer\n"); } /* @@ -1948,6 +2116,14 @@ dt_cg(dt_pcb_t *pcb, dt_node_t *dnp) } dt_cg_node(dnp, &pcb->pcb_ir, pcb->pcb_regs); + + if ((idp = dt_node_resolve(dnp, DT_IDENT_XLSOU)) != NULL) { + int reg = dt_cg_xlate_expand(dnp, idp, + &pcb->pcb_ir, pcb->pcb_regs); + dt_regset_free(pcb->pcb_regs, dnp->dn_reg); + dnp->dn_reg = reg; + } + instr = DIF_INSTR_RET(dnp->dn_reg); dt_regset_free(pcb->pcb_regs, dnp->dn_reg); dt_irlist_append(&pcb->pcb_ir, dt_cg_node_alloc(DT_LBL_NONE, instr)); @@ -1957,4 +2133,7 @@ dt_cg(dt_pcb_t *pcb, dt_node_t *dnp) dxp->dx_ident->di_id = 0; dxp->dx_ident->di_flags &= ~DT_IDFLG_CGREG; } + + dt_regset_free(pcb->pcb_regs, 0); + dt_regset_assert_free(pcb->pcb_regs); } diff --git a/lib/libdtrace/common/dt_consume.c b/lib/libdtrace/common/dt_consume.c index d3a554c1c6b7..f12a39991aea 100644 --- a/lib/libdtrace/common/dt_consume.c +++ b/lib/libdtrace/common/dt_consume.c @@ -25,7 +25,7 @@ /* * Copyright (c) 2011, Joyent, Inc. All rights reserved. - * Copyright (c) 2011 by Delphix. All rights reserved. + * Copyright (c) 2012 by Delphix. All rights reserved. */ #include @@ -37,6 +37,7 @@ #include #include #include +#include #define DT_MASK_LO 0x00000000FFFFFFFFULL @@ -438,17 +439,8 @@ dt_flowindent(dtrace_hdl_t *dtp, dtrace_probedata_t *data, dtrace_epid_t last, offs += epd->dtepd_size; do { - if (offs >= buf->dtbd_size) { - /* - * We're at the end -- maybe. If the oldest - * record is non-zero, we need to wrap. - */ - if (buf->dtbd_oldest != 0) { - offs = 0; - } else { - goto out; - } - } + if (offs >= buf->dtbd_size) + goto out; next = *(uint32_t *)((uintptr_t)buf->dtbd_data + offs); @@ -1700,26 +1692,27 @@ dt_setopt(dtrace_hdl_t *dtp, const dtrace_probedata_t *data, } static int -dt_consume_cpu(dtrace_hdl_t *dtp, FILE *fp, int cpu, dtrace_bufdesc_t *buf, +dt_consume_cpu(dtrace_hdl_t *dtp, FILE *fp, int cpu, + dtrace_bufdesc_t *buf, boolean_t just_one, dtrace_consume_probe_f *efunc, dtrace_consume_rec_f *rfunc, void *arg) { dtrace_epid_t id; - size_t offs, start = buf->dtbd_oldest, end = buf->dtbd_size; + size_t offs; int flow = (dtp->dt_options[DTRACEOPT_FLOWINDENT] != DTRACEOPT_UNSET); 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; bzero(&data, sizeof (data)); data.dtpda_handle = dtp; data.dtpda_cpu = cpu; + data.dtpda_flow = dtp->dt_flow; + data.dtpda_indent = dtp->dt_indent; + data.dtpda_prefix = dtp->dt_prefix; -again: - for (offs = start; offs < end; ) { + for (offs = buf->dtbd_oldest; offs < buf->dtbd_size; ) { dtrace_eprobedesc_t *epd; /* @@ -1754,7 +1747,8 @@ again: } if (flow) - (void) dt_flowindent(dtp, &data, last, buf, offs); + (void) dt_flowindent(dtp, &data, dtp->dt_last_epid, + buf, offs); rval = (*efunc)(&data, arg); @@ -1773,6 +1767,7 @@ again: return (dt_set_errno(dtp, EDT_BADRVAL)); for (i = 0; i < epd->dtepd_nrecs; i++) { + caddr_t addr; dtrace_recdesc_t *rec = &epd->dtepd_rec[i]; dtrace_actkind_t act = rec->dtrd_action; @@ -2132,14 +2127,16 @@ nextrec: rval = (*rfunc)(&data, NULL, arg); nextepid: offs += epd->dtepd_size; - last = id; + dtp->dt_last_epid = id; + if (just_one) { + buf->dtbd_oldest = offs; + break; + } } - if (buf->dtbd_oldest != 0 && start == buf->dtbd_oldest) { - end = buf->dtbd_oldest; - start = 0; - goto again; - } + dtp->dt_flow = data.dtpda_flow; + dtp->dt_indent = data.dtpda_indent; + dtp->dt_prefix = data.dtpda_prefix; if ((drops = buf->dtbd_drops) == 0) return (0); @@ -2152,6 +2149,126 @@ nextepid: return (dt_handle_cpudrop(dtp, cpu, DTRACEDROP_PRINCIPAL, drops)); } +/* + * Reduce memory usage by shrinking the buffer if it's no more than half full. + * Note, we need to preserve the alignment of the data at dtbd_oldest, which is + * only 4-byte aligned. + */ +static void +dt_realloc_buf(dtrace_hdl_t *dtp, dtrace_bufdesc_t *buf, int cursize) +{ + uint64_t used = buf->dtbd_size - buf->dtbd_oldest; + if (used < cursize / 2) { + int misalign = buf->dtbd_oldest & (sizeof (uint64_t) - 1); + char *newdata = dt_alloc(dtp, used + misalign); + if (newdata == NULL) + return; + bzero(newdata, misalign); + bcopy(buf->dtbd_data + buf->dtbd_oldest, + newdata + misalign, used); + dt_free(dtp, buf->dtbd_data); + buf->dtbd_oldest = misalign; + buf->dtbd_size = used + misalign; + buf->dtbd_data = newdata; + } +} + +/* + * If the ring buffer has wrapped, the data is not in order. Rearrange it + * so that it is. Note, we need to preserve the alignment of the data at + * dtbd_oldest, which is only 4-byte aligned. + */ +static int +dt_unring_buf(dtrace_hdl_t *dtp, dtrace_bufdesc_t *buf) +{ + int misalign; + char *newdata, *ndp; + + if (buf->dtbd_oldest == 0) + return (0); + + misalign = buf->dtbd_oldest & (sizeof (uint64_t) - 1); + newdata = ndp = dt_alloc(dtp, buf->dtbd_size + misalign); + + if (newdata == NULL) + return (-1); + + assert(0 == (buf->dtbd_size & (sizeof (uint64_t) - 1))); + + bzero(ndp, misalign); + ndp += misalign; + + bcopy(buf->dtbd_data + buf->dtbd_oldest, ndp, + buf->dtbd_size - buf->dtbd_oldest); + ndp += buf->dtbd_size - buf->dtbd_oldest; + + bcopy(buf->dtbd_data, ndp, buf->dtbd_oldest); + + dt_free(dtp, buf->dtbd_data); + buf->dtbd_oldest = 0; + buf->dtbd_data = newdata; + buf->dtbd_size += misalign; + + return (0); +} + +static void +dt_put_buf(dtrace_hdl_t *dtp, dtrace_bufdesc_t *buf) +{ + dt_free(dtp, buf->dtbd_data); + dt_free(dtp, buf); +} + +/* + * Returns 0 on success, in which case *cbp will be filled in if we retrieved + * data, or NULL if there is no data for this CPU. + * Returns -1 on failure and sets dt_errno. + */ +static int +dt_get_buf(dtrace_hdl_t *dtp, int cpu, dtrace_bufdesc_t **bufp) +{ + dtrace_optval_t size; + dtrace_bufdesc_t *buf = dt_zalloc(dtp, sizeof (*buf)); + int error; + + if (buf == NULL) + return (-1); + + (void) dtrace_getopt(dtp, "bufsize", &size); + buf->dtbd_data = dt_alloc(dtp, size); + if (buf->dtbd_data == NULL) { + dt_free(dtp, buf); + return (-1); + } + buf->dtbd_size = size; + buf->dtbd_cpu = cpu; + + if (dt_ioctl(dtp, DTRACEIOC_BUFSNAP, buf) == -1) { + dt_put_buf(dtp, buf); + /* + * If we failed with ENOENT, it may be because the + * CPU was unconfigured -- this is okay. Any other + * error, however, is unexpected. + */ + if (errno == ENOENT) { + *bufp = NULL; + return (0); + } + + return (dt_set_errno(dtp, errno)); + } + + error = dt_unring_buf(dtp, buf); + if (error != 0) { + dt_put_buf(dtp, buf); + return (error); + } + dt_realloc_buf(dtp, buf, size); + + *bufp = buf; + return (0); +} + typedef struct dt_begin { dtrace_consume_probe_f *dtbgn_probefunc; dtrace_consume_rec_f *dtbgn_recfunc; @@ -2164,7 +2281,7 @@ typedef struct dt_begin { static int dt_consume_begin_probe(const dtrace_probedata_t *data, void *arg) { - dt_begin_t *begin = (dt_begin_t *)arg; + dt_begin_t *begin = arg; dtrace_probedesc_t *pd = data->dtpda_pdesc; int r1 = (strcmp(pd->dtpd_provider, "dtrace") == 0); @@ -2189,7 +2306,7 @@ static int dt_consume_begin_record(const dtrace_probedata_t *data, const dtrace_recdesc_t *rec, void *arg) { - dt_begin_t *begin = (dt_begin_t *)arg; + dt_begin_t *begin = arg; return (begin->dtbgn_recfunc(data, rec, begin->dtbgn_arg)); } @@ -2215,7 +2332,7 @@ dt_consume_begin_error(const dtrace_errdata_t *data, void *arg) } static int -dt_consume_begin(dtrace_hdl_t *dtp, FILE *fp, dtrace_bufdesc_t *buf, +dt_consume_begin(dtrace_hdl_t *dtp, FILE *fp, dtrace_consume_probe_f *pf, dtrace_consume_rec_f *rf, void *arg) { /* @@ -2239,26 +2356,19 @@ dt_consume_begin(dtrace_hdl_t *dtp, FILE *fp, dtrace_bufdesc_t *buf, * first pass, and that we only process ERROR enablings _not_ induced * by BEGIN enablings in the second pass. */ + dt_begin_t begin; processorid_t cpu = dtp->dt_beganon; - dtrace_bufdesc_t nbuf; int rval, i; static int max_ncpus; - dtrace_optval_t size; + dtrace_bufdesc_t *buf; dtp->dt_beganon = -1; - if (dt_ioctl(dtp, DTRACEIOC_BUFSNAP, buf) == -1) { - /* - * We really don't expect this to fail, but it is at least - * technically possible for this to fail with ENOENT. In this - * case, we just drive on... - */ - if (errno == ENOENT) - return (0); - - return (dt_set_errno(dtp, errno)); - } + if (dt_get_buf(dtp, cpu, &buf) != 0) + return (-1); + if (buf == NULL) + return (0); if (!dtp->dt_stopped || buf->dtbd_cpu != dtp->dt_endedon) { /* @@ -2266,7 +2376,10 @@ dt_consume_begin(dtrace_hdl_t *dtp, FILE *fp, dtrace_bufdesc_t *buf, * we are, we actually processed any END probes on another * CPU. We can simply consume this buffer and return. */ - return (dt_consume_cpu(dtp, fp, cpu, buf, pf, rf, arg)); + rval = dt_consume_cpu(dtp, fp, cpu, buf, B_FALSE, + pf, rf, arg); + dt_put_buf(dtp, buf); + return (rval); } begin.dtbgn_probefunc = pf; @@ -2283,56 +2396,41 @@ dt_consume_begin(dtrace_hdl_t *dtp, FILE *fp, dtrace_bufdesc_t *buf, dtp->dt_errhdlr = dt_consume_begin_error; dtp->dt_errarg = &begin; - rval = dt_consume_cpu(dtp, fp, cpu, buf, dt_consume_begin_probe, - dt_consume_begin_record, &begin); + rval = dt_consume_cpu(dtp, fp, cpu, buf, B_FALSE, + dt_consume_begin_probe, dt_consume_begin_record, &begin); dtp->dt_errhdlr = begin.dtbgn_errhdlr; dtp->dt_errarg = begin.dtbgn_errarg; - if (rval != 0) + if (rval != 0) { + dt_put_buf(dtp, buf); return (rval); - - /* - * Now allocate a new buffer. We'll use this to deal with every other - * CPU. - */ - bzero(&nbuf, sizeof (dtrace_bufdesc_t)); - (void) dtrace_getopt(dtp, "bufsize", &size); - if ((nbuf.dtbd_data = malloc(size)) == NULL) - return (dt_set_errno(dtp, EDT_NOMEM)); + } if (max_ncpus == 0) max_ncpus = dt_sysconf(dtp, _SC_CPUID_MAX) + 1; for (i = 0; i < max_ncpus; i++) { - nbuf.dtbd_cpu = i; - + dtrace_bufdesc_t *nbuf; if (i == cpu) continue; - if (dt_ioctl(dtp, DTRACEIOC_BUFSNAP, &nbuf) == -1) { - /* - * If we failed with ENOENT, it may be because the - * CPU was unconfigured -- this is okay. Any other - * error, however, is unexpected. - */ - if (errno == ENOENT) - continue; - - free(nbuf.dtbd_data); - - return (dt_set_errno(dtp, errno)); + if (dt_get_buf(dtp, i, &nbuf) != 0) { + dt_put_buf(dtp, buf); + return (-1); } + if (nbuf == NULL) + continue; - if ((rval = dt_consume_cpu(dtp, fp, - i, &nbuf, pf, rf, arg)) != 0) { - free(nbuf.dtbd_data); + rval = dt_consume_cpu(dtp, fp, i, nbuf, B_FALSE, + pf, rf, arg); + dt_put_buf(dtp, nbuf); + if (rval != 0) { + dt_put_buf(dtp, buf); return (rval); } } - free(nbuf.dtbd_data); - /* * Okay -- we're done with the other buffers. Now we want to * reconsume the first buffer -- but this time we're looking for @@ -2347,8 +2445,8 @@ dt_consume_begin(dtrace_hdl_t *dtp, FILE *fp, dtrace_bufdesc_t *buf, dtp->dt_errhdlr = dt_consume_begin_error; dtp->dt_errarg = &begin; - rval = dt_consume_cpu(dtp, fp, cpu, buf, dt_consume_begin_probe, - dt_consume_begin_record, &begin); + rval = dt_consume_cpu(dtp, fp, cpu, buf, B_FALSE, + dt_consume_begin_probe, dt_consume_begin_record, &begin); dtp->dt_errhdlr = begin.dtbgn_errhdlr; dtp->dt_errarg = begin.dtbgn_errarg; @@ -2356,11 +2454,31 @@ dt_consume_begin(dtrace_hdl_t *dtp, FILE *fp, dtrace_bufdesc_t *buf, return (rval); } +/* ARGSUSED */ +static uint64_t +dt_buf_oldest(void *elem, void *arg) +{ + dtrace_bufdesc_t *buf = elem; + size_t offs = buf->dtbd_oldest; + + while (offs < buf->dtbd_size) { + dtrace_rechdr_t *dtrh = + (dtrace_rechdr_t *)(buf->dtbd_data + offs); + if (dtrh->dtrh_epid == DTRACE_EPIDNONE) { + offs += sizeof (dtrace_epid_t); + } else { + return (DTRACE_RECORD_LOAD_TIMESTAMP(dtrh)); + } + } + + /* There are no records left; use the time the buffer was retrieved. */ + return (buf->dtbd_timestamp); +} + int dtrace_consume(dtrace_hdl_t *dtp, FILE *fp, dtrace_consume_probe_f *pf, dtrace_consume_rec_f *rf, void *arg) { - dtrace_bufdesc_t *buf = &dtp->dt_buf; dtrace_optval_t size; static int max_ncpus; int i, rval; @@ -2388,71 +2506,158 @@ dtrace_consume(dtrace_hdl_t *dtp, FILE *fp, if (rf == NULL) rf = (dtrace_consume_rec_f *)dt_nullrec; - if (buf->dtbd_data == NULL) { - (void) dtrace_getopt(dtp, "bufsize", &size); - if ((buf->dtbd_data = malloc(size)) == NULL) - return (dt_set_errno(dtp, EDT_NOMEM)); - - buf->dtbd_size = size; - } - - /* - * If we have just begun, we want to first process the CPU that - * executed the BEGIN probe (if any). - */ - if (dtp->dt_active && dtp->dt_beganon != -1) { - buf->dtbd_cpu = dtp->dt_beganon; - if ((rval = dt_consume_begin(dtp, fp, buf, pf, rf, arg)) != 0) - return (rval); - } - - for (i = 0; i < max_ncpus; i++) { - buf->dtbd_cpu = i; - + if (dtp->dt_options[DTRACEOPT_TEMPORAL] == DTRACEOPT_UNSET) { /* - * If we have stopped, we want to process the CPU on which the - * END probe was processed only _after_ we have processed - * everything else. + * The output will not be in the order it was traced. Rather, + * we will consume all of the data from each CPU's buffer in + * turn. We apply special handling for the records from BEGIN + * and END probes so that they are consumed first and last, + * respectively. + * + * If we have just begun, we want to first process the CPU that + * executed the BEGIN probe (if any). */ - if (dtp->dt_stopped && (i == dtp->dt_endedon)) - continue; + if (dtp->dt_active && dtp->dt_beganon != -1 && + (rval = dt_consume_begin(dtp, fp, pf, rf, arg)) != 0) + return (rval); + + for (i = 0; i < max_ncpus; i++) { + dtrace_bufdesc_t *buf; - if (dt_ioctl(dtp, DTRACEIOC_BUFSNAP, buf) == -1) { /* - * If we failed with ENOENT, it may be because the - * CPU was unconfigured -- this is okay. Any other - * error, however, is unexpected. + * If we have stopped, we want to process the CPU on + * which the END probe was processed only _after_ we + * have processed everything else. */ - if (errno == ENOENT) + if (dtp->dt_stopped && (i == dtp->dt_endedon)) continue; - return (dt_set_errno(dtp, errno)); + if (dt_get_buf(dtp, i, &buf) != 0) + return (-1); + if (buf == NULL) + continue; + + dtp->dt_flow = 0; + dtp->dt_indent = 0; + dtp->dt_prefix = NULL; + rval = dt_consume_cpu(dtp, fp, i, + buf, B_FALSE, pf, rf, arg); + dt_put_buf(dtp, buf); + if (rval != 0) + return (rval); + } + if (dtp->dt_stopped) { + dtrace_bufdesc_t *buf; + + if (dt_get_buf(dtp, dtp->dt_endedon, &buf) != 0) + return (-1); + if (buf == NULL) + return (0); + + rval = dt_consume_cpu(dtp, fp, dtp->dt_endedon, + buf, B_FALSE, pf, rf, arg); + dt_put_buf(dtp, buf); + return (rval); + } + } else { + /* + * The output will be in the order it was traced (or for + * speculations, when it was committed). We retrieve a buffer + * from each CPU and put it into a priority queue, which sorts + * based on the first entry in the buffer. This is sufficient + * because entries within a buffer are already sorted. + * + * We then consume records one at a time, always consuming the + * oldest record, as determined by the priority queue. When + * we reach the end of the time covered by these buffers, + * we need to stop and retrieve more records on the next pass. + * The kernel tells us the time covered by each buffer, in + * dtbd_timestamp. The first buffer's timestamp tells us the + * time covered by all buffers, as subsequently retrieved + * buffers will cover to a more recent time. + */ + + uint64_t *drops = alloca(max_ncpus * sizeof (uint64_t)); + uint64_t first_timestamp = 0; + uint_t cookie = 0; + dtrace_bufdesc_t *buf; + + bzero(drops, max_ncpus * sizeof (uint64_t)); + + if (dtp->dt_bufq == NULL) { + dtp->dt_bufq = dt_pq_init(dtp, max_ncpus * 2, + dt_buf_oldest, NULL); + if (dtp->dt_bufq == NULL) /* ENOMEM */ + return (-1); } - if ((rval = dt_consume_cpu(dtp, fp, i, buf, pf, rf, arg)) != 0) - return (rval); - } + /* Retrieve data from each CPU. */ + (void) dtrace_getopt(dtp, "bufsize", &size); + for (i = 0; i < max_ncpus; i++) { + dtrace_bufdesc_t *buf; - if (!dtp->dt_stopped) - return (0); + if (dt_get_buf(dtp, i, &buf) != 0) + return (-1); + if (buf != NULL) { + if (first_timestamp == 0) + first_timestamp = buf->dtbd_timestamp; + assert(buf->dtbd_timestamp >= first_timestamp); - buf->dtbd_cpu = dtp->dt_endedon; + dt_pq_insert(dtp->dt_bufq, buf); + drops[i] = buf->dtbd_drops; + buf->dtbd_drops = 0; + } + } + + /* Consume records. */ + for (;;) { + dtrace_bufdesc_t *buf = dt_pq_pop(dtp->dt_bufq); + uint64_t timestamp; + + if (buf == NULL) + break; + + timestamp = dt_buf_oldest(buf, dtp); + assert(timestamp >= dtp->dt_last_timestamp); + dtp->dt_last_timestamp = timestamp; + + if (timestamp == buf->dtbd_timestamp) { + /* + * We've reached the end of the time covered + * by this buffer. If this is the oldest + * buffer, we must do another pass + * to retrieve more data. + */ + dt_put_buf(dtp, buf); + if (timestamp == first_timestamp && + !dtp->dt_stopped) + break; + continue; + } + + if ((rval = dt_consume_cpu(dtp, fp, + buf->dtbd_cpu, buf, B_TRUE, pf, rf, arg)) != 0) + return (rval); + dt_pq_insert(dtp->dt_bufq, buf); + } + + /* Consume drops. */ + for (i = 0; i < max_ncpus; i++) { + if (drops[i] != 0) { + int error = dt_handle_cpudrop(dtp, i, + DTRACEDROP_PRINCIPAL, drops[i]); + if (error != 0) + return (error); + } + } - if (dt_ioctl(dtp, DTRACEIOC_BUFSNAP, buf) == -1) { /* - * This _really_ shouldn't fail, but it is strictly speaking - * possible for this to return ENOENT if the CPU that called - * the END enabling somehow managed to become unconfigured. - * It's unclear how the user can possibly expect anything - * rational to happen in this case -- the state has been thrown - * out along with the unconfigured CPU -- so we'll just drive - * on... + * Reduce memory usage by re-allocating smaller buffers + * for the "remnants". */ - if (errno == ENOENT) - return (0); - - return (dt_set_errno(dtp, errno)); + while (buf = dt_pq_walk(dtp->dt_bufq, &cookie)) + dt_realloc_buf(dtp, buf, buf->dtbd_size); } - return (dt_consume_cpu(dtp, fp, dtp->dt_endedon, buf, pf, rf, arg)); + return (0); } diff --git a/lib/libdtrace/common/dt_dis.c b/lib/libdtrace/common/dt_dis.c index f4bb0c4bbae3..fff4235a6bc3 100644 --- a/lib/libdtrace/common/dt_dis.c +++ b/lib/libdtrace/common/dt_dis.c @@ -19,12 +19,15 @@ * * CDDL HEADER END */ + /* * Copyright 2005 Sun Microsystems, Inc. All rights reserved. * Use is subject to license terms. */ -#pragma ident "%Z%%M% %I% %E% SMI" +/* + * Copyright (c) 2012 by Delphix. All rights reserved. + */ #include #include @@ -212,12 +215,22 @@ dt_dis_pushts(const dtrace_difo_t *dp, { static const char *const tnames[] = { "D type", "string" }; uint_t type = DIF_INSTR_TYPE(in); + const char *pad; - (void) fprintf(fp, "%-4s DT_TYPE(%u), %%r%u, %%r%u", - name, type, DIF_INSTR_R2(in), DIF_INSTR_RS(in)); + if (DIF_INSTR_OP(in) == DIF_OP_PUSHTV) { + (void) fprintf(fp, "%-4s DT_TYPE(%u), %%r%u", + name, type, DIF_INSTR_RS(in)); + pad = "\t\t"; + } else { + (void) fprintf(fp, "%-4s DT_TYPE(%u), %%r%u, %%r%u", + name, type, DIF_INSTR_R2(in), DIF_INSTR_RS(in)); + pad = "\t"; + } - if (type < sizeof (tnames) / sizeof (tnames[0])) - (void) fprintf(fp, "\t! DT_TYPE(%u) = %s", type, tnames[type]); + if (type < sizeof (tnames) / sizeof (tnames[0])) { + (void) fprintf(fp, "%s! DT_TYPE(%u) = %s", pad, + type, tnames[type]); + } } static void diff --git a/lib/libdtrace/common/dt_error.c b/lib/libdtrace/common/dt_error.c index 0bfabc919c85..9c1cbd73bce7 100644 --- a/lib/libdtrace/common/dt_error.c +++ b/lib/libdtrace/common/dt_error.c @@ -18,11 +18,16 @@ * * 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. + */ + #include #include @@ -36,7 +41,6 @@ static const struct { { EDT_VERSREDUCED, "Requested version conflicts with earlier setting" }, { EDT_CTF, "Unexpected libctf error" }, { EDT_COMPILER, "Error in D program compilation" }, - { EDT_NOREG, "Insufficient registers to generate code" }, { EDT_NOTUPREG, "Insufficient tuple registers to generate code" }, { EDT_NOMEM, "Memory allocation failure" }, { EDT_INT2BIG, "Integer constant table limit exceeded" }, diff --git a/lib/libdtrace/common/dt_errtags.h b/lib/libdtrace/common/dt_errtags.h index 473e2addc789..0a9e7c029b4d 100644 --- a/lib/libdtrace/common/dt_errtags.h +++ b/lib/libdtrace/common/dt_errtags.h @@ -26,7 +26,7 @@ /* * Copyright (c) 2011, Joyent, Inc. All rights reserved. - * Copyright (c) 2011 by Delphix. All rights reserved. + * Copyright (c) 2012 by Delphix. All rights reserved. */ #ifndef _DT_ERRTAGS_H @@ -259,7 +259,8 @@ typedef enum { 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_LLQUANT_MAGTOOBIG, /* llquantize() high mag too large */ + D_NOREG /* no available internal registers */ } 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..fa4c66540d49 100644 --- a/lib/libdtrace/common/dt_impl.h +++ b/lib/libdtrace/common/dt_impl.h @@ -26,7 +26,7 @@ /* * Copyright (c) 2011, Joyent, Inc. All rights reserved. - * Copyright (c) 2011 by Delphix. All rights reserved. + * Copyright (c) 2012 by Delphix. All rights reserved. */ #ifndef _DT_IMPL_H @@ -55,6 +55,7 @@ extern "C" { #include #include #include +#include struct dt_module; /* see below */ struct dt_pfdict; /* see */ @@ -226,6 +227,7 @@ struct dtrace_hdl { uint_t dt_provbuckets; /* number of provider hash buckets */ uint_t dt_nprovs; /* number of providers in hash and list */ dt_proc_hash_t *dt_procs; /* hash table of grabbed process handles */ + char **dt_proc_env; /* additional environment variables */ dt_intdesc_t dt_ints[6]; /* cached integer type descriptions */ ctf_id_t dt_type_func; /* cached CTF identifier for function type */ ctf_id_t dt_type_fptr; /* cached CTF identifier for function pointer */ @@ -244,7 +246,7 @@ struct dtrace_hdl { 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 */ + dt_pq_t *dt_bufq; /* CPU-specific data queue */ struct dt_pfdict *dt_pfdict; /* dictionary of printf conversions */ dt_version_t dt_vmax; /* optional ceiling on program API binding */ dtrace_attribute_t dt_amin; /* optional floor on program attributes */ @@ -305,6 +307,11 @@ struct dtrace_hdl { struct utsname dt_uts; /* uname(2) information for system */ dt_list_t dt_lib_dep; /* scratch linked-list of lib dependencies */ dt_list_t dt_lib_dep_sorted; /* dependency sorted library list */ + dtrace_flowkind_t dt_flow; /* flow kind */ + const char *dt_prefix; /* recommended flow prefix */ + int dt_indent; /* recommended flow indent */ + dtrace_epid_t dt_last_epid; /* most recently consumed EPID */ + uint64_t dt_last_timestamp; /* most recently consumed timestamp */ }; /* @@ -438,7 +445,6 @@ enum { EDT_VERSREDUCED, /* requested API version has been reduced */ EDT_CTF, /* libctf called failed (dt_ctferr has more) */ EDT_COMPILER, /* error in D program compilation */ - EDT_NOREG, /* register allocation failure */ EDT_NOTUPREG, /* tuple register allocation failure */ EDT_NOMEM, /* memory allocation failure */ EDT_INT2BIG, /* integer limit exceeded */ diff --git a/lib/libdtrace/common/dt_open.c b/lib/libdtrace/common/dt_open.c index 502a9d42ad73..dd83370ee8e3 100644 --- a/lib/libdtrace/common/dt_open.c +++ b/lib/libdtrace/common/dt_open.c @@ -22,7 +22,7 @@ /* * 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. + * Copyright (c) 2012 by Delphix. All rights reserved. */ #include @@ -81,7 +81,7 @@ /* * The version number should be increased for every customer visible release - * of Solaris. The major number should be incremented when a fundamental + * of DTrace. The major number should be incremented when a fundamental * change has been made that would affect all consumers, and would reflect * sweeping changes to DTrace or the D language. The minor number should be * incremented when a change is introduced that could break scripts that had @@ -110,8 +110,9 @@ #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_1_9_1 DT_VERSION_NUMBER(1, 9, 1) +#define DT_VERS_LATEST DT_VERS_1_9_1 +#define DT_VERS_STRING "Sun D 1.9.1" const dt_version_t _dtrace_versions[] = { DT_VERS_1_0, /* D API 1.0.0 (PSARC 2001/466) Solaris 10 FCS */ @@ -132,6 +133,7 @@ const dt_version_t _dtrace_versions[] = { 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 */ + DT_VERS_1_9_1, /* D API 1.9.1 */ 0 }; @@ -937,7 +939,7 @@ alloc: dtp->dt_mods = calloc(dtp->dt_modbuckets, sizeof (dt_module_t *)); dtp->dt_provbuckets = _dtrace_strbuckets; dtp->dt_provs = calloc(dtp->dt_provbuckets, sizeof (dt_provider_t *)); - dt_proc_hash_create(dtp); + dt_proc_init(dtp); dtp->dt_vmax = DT_VERS_LATEST; dtp->dt_cpp_path = strdup(_dtrace_defcpp); dtp->dt_cpp_argv = malloc(sizeof (char *)); @@ -951,8 +953,9 @@ alloc: (void) uname(&dtp->dt_uts); if (dtp->dt_mods == NULL || dtp->dt_provs == NULL || - dtp->dt_procs == NULL || dtp->dt_ld_path == NULL || - dtp->dt_cpp_path == NULL || dtp->dt_cpp_argv == NULL) + dtp->dt_procs == NULL || dtp->dt_proc_env == NULL || + dtp->dt_ld_path == NULL || dtp->dt_cpp_path == NULL || + dtp->dt_cpp_argv == NULL) return (set_open_errno(dtp, errp, EDT_NOMEM)); for (i = 0; i < DTRACEOPT_MAX; i++) @@ -1318,7 +1321,7 @@ dtrace_close(dtrace_hdl_t *dtp) int i; if (dtp->dt_procs != NULL) - dt_proc_hash_destroy(dtp); + dt_proc_fini(dtp); while ((pgp = dt_list_next(&dtp->dt_programs)) != NULL) dt_program_destroy(dtp, pgp); @@ -1365,7 +1368,6 @@ dtrace_close(dtrace_hdl_t *dtp) dt_strdata_destroy(dtp); dt_buffered_destroy(dtp); dt_aggregate_destroy(dtp); - free(dtp->dt_buf.dtbd_data); dt_pfdict_destroy(dtp); dt_provmod_destroy(&dtp->dt_provmod); dt_dof_fini(dtp); diff --git a/lib/libdtrace/common/dt_options.c b/lib/libdtrace/common/dt_options.c index 426f8cb73c7a..cc3ae7b9d319 100644 --- a/lib/libdtrace/common/dt_options.c +++ b/lib/libdtrace/common/dt_options.c @@ -24,6 +24,10 @@ * Use is subject to license terms. */ +/* + * Copyright (c) 2012 by Delphix. All rights reserved. + */ + #include #include #include @@ -364,6 +368,61 @@ dt_opt_pgmax(dtrace_hdl_t *dtp, const char *arg, uintptr_t option) return (0); } +static int +dt_opt_setenv(dtrace_hdl_t *dtp, const char *arg, uintptr_t option) +{ + char **p; + char *var; + int i; + + /* + * We can't effectively set environment variables from #pragma lines + * since the processes have already been spawned. + */ + if (dtp->dt_pcb != NULL) + return (dt_set_errno(dtp, EDT_BADOPTCTX)); + + if (arg == NULL) + return (dt_set_errno(dtp, EDT_BADOPTVAL)); + + if (!option && strchr(arg, '=') != NULL) + return (dt_set_errno(dtp, EDT_BADOPTVAL)); + + for (i = 1, p = dtp->dt_proc_env; *p != NULL; i++, p++) + continue; + + for (p = dtp->dt_proc_env; *p != NULL; p++) { + var = strchr(*p, '='); + if (var == NULL) + var = *p + strlen(*p); + if (strncmp(*p, arg, var - *p) == 0) { + dt_free(dtp, *p); + *p = dtp->dt_proc_env[i - 1]; + dtp->dt_proc_env[i - 1] = NULL; + i--; + } + } + + if (option) { + if ((var = strdup(arg)) == NULL) + return (dt_set_errno(dtp, EDT_NOMEM)); + + if ((p = dt_alloc(dtp, sizeof (char *) * (i + 1))) == NULL) { + dt_free(dtp, var); + return (dt_set_errno(dtp, EDT_NOMEM)); + } + + bcopy(dtp->dt_proc_env, p, sizeof (char *) * i); + dt_free(dtp, dtp->dt_proc_env); + dtp->dt_proc_env = p; + + dtp->dt_proc_env[i - 1] = var; + dtp->dt_proc_env[i] = NULL; + } + + return (0); +} + /*ARGSUSED*/ static int dt_opt_stdc(dtrace_hdl_t *dtp, const char *arg, uintptr_t option) @@ -407,7 +466,6 @@ dt_opt_syslibdir(dtrace_hdl_t *dtp, const char *arg, uintptr_t option) return (0); } - /*ARGSUSED*/ static int dt_opt_tree(dtrace_hdl_t *dtp, const char *arg, uintptr_t option) @@ -874,6 +932,7 @@ static const dt_option_t _dtrace_ctoptions[] = { { "nolibs", dt_opt_cflags, DTRACE_C_NOLIBS }, { "pgmax", dt_opt_pgmax }, { "pspec", dt_opt_cflags, DTRACE_C_PSPEC }, + { "setenv", dt_opt_setenv, 1 }, { "stdc", dt_opt_stdc }, { "strip", dt_opt_dflags, DTRACE_D_STRIP }, { "syslibdir", dt_opt_syslibdir }, @@ -882,6 +941,7 @@ static const dt_option_t _dtrace_ctoptions[] = { { "udefs", dt_opt_invcflags, DTRACE_C_UNODEF }, { "undef", dt_opt_cpp_opts, (uintptr_t)"-U" }, { "unodefs", dt_opt_cflags, DTRACE_C_UNODEF }, + { "unsetenv", dt_opt_setenv, 0 }, { "verbose", dt_opt_cflags, DTRACE_C_DIFV }, { "version", dt_opt_version }, { "zdefs", dt_opt_cflags, DTRACE_C_ZDEFS }, @@ -909,6 +969,7 @@ static const dt_option_t _dtrace_rtoptions[] = { { "statusrate", dt_opt_rate, DTRACEOPT_STATUSRATE }, { "strsize", dt_opt_strsize, DTRACEOPT_STRSIZE }, { "ustackframes", dt_opt_runtime, DTRACEOPT_USTACKFRAMES }, + { "temporal", dt_opt_runtime, DTRACEOPT_TEMPORAL }, { NULL } }; diff --git a/lib/libdtrace/common/dt_parser.c b/lib/libdtrace/common/dt_parser.c index 05715894a7df..6f837c4bedff 100644 --- a/lib/libdtrace/common/dt_parser.c +++ b/lib/libdtrace/common/dt_parser.c @@ -22,6 +22,7 @@ /* * Copyright (c) 2003, 2010, Oracle and/or its affiliates. All rights reserved. * Copyright (c) 2011, Joyent Inc. All rights reserved. + * Copyright (c) 2012 by Delphix. All rights reserved. */ /* @@ -93,6 +94,7 @@ */ #include +#include #include #include #include @@ -1856,6 +1858,38 @@ dt_node_op1(int op, dt_node_t *cp) return (dnp); } +/* + * If an integer constant is being cast to another integer type, we can + * perform the cast as part of integer constant folding in this pass. We must + * take action when the integer is being cast to a smaller type or if it is + * changing signed-ness. If so, we first shift rp's bits bits high (losing + * excess bits if narrowing) and then shift them down with either a logical + * shift (unsigned) or arithmetic shift (signed). + */ +static void +dt_cast(dt_node_t *lp, dt_node_t *rp) +{ + size_t srcsize = dt_node_type_size(rp); + size_t dstsize = dt_node_type_size(lp); + + if (dstsize < srcsize) { + int n = (sizeof (uint64_t) - dstsize) * NBBY; + rp->dn_value <<= n; + rp->dn_value >>= n; + } else if (dstsize > srcsize) { + int n = (sizeof (uint64_t) - srcsize) * NBBY; + int s = (dstsize - srcsize) * NBBY; + + rp->dn_value <<= n; + if (rp->dn_flags & DT_NF_SIGNED) { + rp->dn_value = (intmax_t)rp->dn_value >> s; + rp->dn_value >>= n - s; + } else { + rp->dn_value >>= n; + } + } +} + dt_node_t * dt_node_op2(int op, dt_node_t *lp, dt_node_t *rp) { @@ -2005,32 +2039,9 @@ dt_node_op2(int op, dt_node_t *lp, dt_node_t *rp) } } - /* - * If an integer constant is being cast to another integer type, we can - * perform the cast as part of integer constant folding in this pass. - * We must take action when the integer is being cast to a smaller type - * or if it is changing signed-ness. If so, we first shift rp's bits - * bits high (losing excess bits if narrowing) and then shift them down - * with either a logical shift (unsigned) or arithmetic shift (signed). - */ if (op == DT_TOK_LPAR && rp->dn_kind == DT_NODE_INT && dt_node_is_integer(lp)) { - size_t srcsize = dt_node_type_size(rp); - size_t dstsize = dt_node_type_size(lp); - - if ((dstsize < srcsize) || ((lp->dn_flags & DT_NF_SIGNED) ^ - (rp->dn_flags & DT_NF_SIGNED))) { - int n = dstsize < srcsize ? - (sizeof (uint64_t) * NBBY - dstsize * NBBY) : - (sizeof (uint64_t) * NBBY - srcsize * NBBY); - - rp->dn_value <<= n; - if (lp->dn_flags & DT_NF_SIGNED) - rp->dn_value = (intmax_t)rp->dn_value >> n; - else - rp->dn_value = rp->dn_value >> n; - } - + dt_cast(lp, rp); dt_node_type_propagate(lp, rp); dt_node_attr_assign(rp, dt_attr_min(lp->dn_attr, rp->dn_attr)); dt_node_free(lp); @@ -2889,14 +2900,14 @@ dt_cook_op1(dt_node_t *dnp, uint_t idflags) case DT_TOK_DEREF: /* * If the deref operator is applied to a translated pointer, - * we can just set our output type to the base translation. + * we set our output type to the output of the translation. */ if ((idp = dt_node_resolve(cp, DT_IDENT_XLPTR)) != NULL) { dt_xlator_t *dxp = idp->di_data; dnp->dn_ident = &dxp->dx_souid; dt_node_type_assign(dnp, - DT_DYN_CTFP(dtp), DT_DYN_TYPE(dtp)); + dnp->dn_ident->di_ctfp, dnp->dn_ident->di_type); break; } @@ -3072,6 +3083,31 @@ dt_cook_op1(dt_node_t *dnp, uint_t idflags) return (dnp); } +static void +dt_assign_common(dt_node_t *dnp) +{ + dt_node_t *lp = dnp->dn_left; + dt_node_t *rp = dnp->dn_right; + int op = dnp->dn_op; + + if (rp->dn_kind == DT_NODE_INT) + dt_cast(lp, rp); + + if (!(lp->dn_flags & DT_NF_LVALUE)) { + xyerror(D_OP_LVAL, "operator %s requires modifiable " + "lvalue as an operand\n", opstr(op)); + /* see K&R[A7.17] */ + } + + if (!(lp->dn_flags & DT_NF_WRITABLE)) { + xyerror(D_OP_WRITE, "operator %s can only be applied " + "to a writable variable\n", opstr(op)); + } + + dt_node_type_propagate(lp, dnp); /* see K&R[A7.17] */ + dt_node_attr_assign(dnp, dt_attr_min(lp->dn_attr, rp->dn_attr)); +} + static dt_node_t * dt_cook_op2(dt_node_t *dnp, uint_t idflags) { @@ -3550,19 +3586,7 @@ dt_cook_op2(dt_node_t *dnp, uint_t idflags) } } asgn_common: - if (!(lp->dn_flags & DT_NF_LVALUE)) { - xyerror(D_OP_LVAL, "operator %s requires modifiable " - "lvalue as an operand\n", opstr(op)); - /* see K&R[A7.17] */ - } - - if (!(lp->dn_flags & DT_NF_WRITABLE)) { - xyerror(D_OP_WRITE, "operator %s can only be applied " - "to a writable variable\n", opstr(op)); - } - - dt_node_type_propagate(lp, dnp); /* see K&R[A7.17] */ - dt_node_attr_assign(dnp, dt_attr_min(lp->dn_attr, rp->dn_attr)); + dt_assign_common(dnp); break; case DT_TOK_PTR: @@ -3867,6 +3891,14 @@ asgn_common: dt_node_type_propagate(lp, dnp); /* see K&R[A7.5] */ dt_node_attr_assign(dnp, dt_attr_min(lp->dn_attr, rp->dn_attr)); + + /* + * If it's a pointer then should be able to (attempt to) + * assign to it. + */ + if (lkind == CTF_K_POINTER) + dnp->dn_flags |= DT_NF_WRITABLE; + break; } diff --git a/lib/libdtrace/common/dt_pq.c b/lib/libdtrace/common/dt_pq.c new file mode 100644 index 000000000000..0cd556abd8f5 --- /dev/null +++ b/lib/libdtrace/common/dt_pq.c @@ -0,0 +1,157 @@ +/* + * CDDL HEADER START + * + * This file and its contents are supplied under the terms of the + * Common Development and Distribution License ("CDDL"), version 1.0. + * You may only use this file in accordance with the terms of version + * 1.0 of the CDDL. + * + * A full copy of the text of the CDDL should have accompanied this + * source. A copy of the CDDL is also available via the Internet at + * http://www.illumos.org/license/CDDL. + * + * CDDL HEADER END + */ + +/* + * Copyright (c) 2012 by Delphix. All rights reserved. + */ + +#include +#include +#include +#include + +/* + * Create a new priority queue. + * + * size is the maximum number of items that will be stored in the priority + * queue at one time. + */ +dt_pq_t * +dt_pq_init(dtrace_hdl_t *dtp, uint_t size, dt_pq_value_f value_cb, void *cb_arg) +{ + dt_pq_t *p; + assert(size > 1); + + if ((p = dt_zalloc(dtp, sizeof (dt_pq_t))) == NULL) + return (NULL); + + p->dtpq_items = dt_zalloc(dtp, size * sizeof (p->dtpq_items[0])); + if (p->dtpq_items == NULL) { + dt_free(dtp, p); + return (NULL); + } + + p->dtpq_hdl = dtp; + p->dtpq_size = size; + p->dtpq_last = 1; + p->dtpq_value = value_cb; + p->dtpq_arg = cb_arg; + + return (p); +} + +void +dt_pq_fini(dt_pq_t *p) +{ + dtrace_hdl_t *dtp = p->dtpq_hdl; + + dt_free(dtp, p->dtpq_items); + dt_free(dtp, p); +} + +static uint64_t +dt_pq_getvalue(dt_pq_t *p, uint_t index) +{ + void *item = p->dtpq_items[index]; + return (p->dtpq_value(item, p->dtpq_arg)); +} + +void +dt_pq_insert(dt_pq_t *p, void *item) +{ + uint_t i; + + assert(p->dtpq_last < p->dtpq_size); + + i = p->dtpq_last++; + p->dtpq_items[i] = item; + + while (i > 1 && dt_pq_getvalue(p, i) < dt_pq_getvalue(p, i / 2)) { + void *tmp = p->dtpq_items[i]; + p->dtpq_items[i] = p->dtpq_items[i / 2]; + p->dtpq_items[i / 2] = tmp; + i /= 2; + } +} + +/* + * Return elements from the priority queue. *cookie should be zero when first + * called. Returns NULL when there are no more elements. + */ +void * +dt_pq_walk(dt_pq_t *p, uint_t *cookie) +{ + (*cookie)++; + if (*cookie >= p->dtpq_last) + return (NULL); + + return (p->dtpq_items[*cookie]); +} + +void * +dt_pq_pop(dt_pq_t *p) +{ + uint_t i = 1; + void *ret; + + assert(p->dtpq_last > 0); + + if (p->dtpq_last == 1) + return (NULL); + + ret = p->dtpq_items[1]; + + p->dtpq_last--; + p->dtpq_items[1] = p->dtpq_items[p->dtpq_last]; + p->dtpq_items[p->dtpq_last] = NULL; + + for (;;) { + uint_t lc = i * 2; + uint_t rc = i * 2 + 1; + uint_t c; + uint64_t v; + void *tmp; + + if (lc >= p->dtpq_last) + break; + + if (rc >= p->dtpq_last) { + c = lc; + v = dt_pq_getvalue(p, lc); + } else { + uint64_t lv = dt_pq_getvalue(p, lc); + uint64_t rv = dt_pq_getvalue(p, rc); + + if (lv < rv) { + c = lc; + v = lv; + } else { + c = rc; + v = rv; + } + } + + if (v >= dt_pq_getvalue(p, i)) + break; + + tmp = p->dtpq_items[i]; + p->dtpq_items[i] = p->dtpq_items[c]; + p->dtpq_items[c] = tmp; + + i = c; + } + + return (ret); +} diff --git a/lib/libdtrace/common/dt_printf.c b/lib/libdtrace/common/dt_printf.c index eabc42338bcc..8d96bd4c7160 100644 --- a/lib/libdtrace/common/dt_printf.c +++ b/lib/libdtrace/common/dt_printf.c @@ -22,6 +22,7 @@ /* * Copyright (c) 2003, 2010, Oracle and/or its affiliates. All rights reserved. * Copyright (c) 2011, Joyent, Inc. All rights reserved. + * Copyright (c) 2012 by Delphix. All rights reserved. */ #include @@ -154,7 +155,7 @@ static int pfcheck_dint(dt_pfargv_t *pfv, dt_pfargd_t *pfd, dt_node_t *dnp) { if (dnp->dn_flags & DT_NF_SIGNED) - pfd->pfd_flags |= DT_PFCONV_SIGNED; + pfd->pfd_fmt[strlen(pfd->pfd_fmt) - 1] = 'i'; else pfd->pfd_fmt[strlen(pfd->pfd_fmt) - 1] = 'u'; @@ -642,7 +643,7 @@ static const dt_pfconv_t _dtrace_conversions[] = { { "hu", "u", "unsigned short", pfcheck_type, pfprint_uint }, { "hx", "x", "short", pfcheck_xshort, pfprint_uint }, { "hX", "X", "short", pfcheck_xshort, pfprint_uint }, -{ "i", "i", pfproto_xint, pfcheck_dint, pfprint_dint }, +{ "i", "i", pfproto_xint, pfcheck_xint, pfprint_sint }, { "I", "s", pfproto_cstr, pfcheck_str, pfprint_inetaddr }, { "k", "s", "stack", pfcheck_stack, pfprint_stack }, { "lc", "lc", "int", pfcheck_type, pfprint_sint }, /* a.k.a. wint_t */ diff --git a/lib/libdtrace/common/dt_proc.c b/lib/libdtrace/common/dt_proc.c index 96e85f1bdb0f..03fe05f21f59 100644 --- a/lib/libdtrace/common/dt_proc.c +++ b/lib/libdtrace/common/dt_proc.c @@ -24,6 +24,10 @@ * Use is subject to license terms. */ +/* + * Copyright (c) 2012 by Delphix. All rights reserved. + */ + /* * DTrace Process Control * @@ -460,7 +464,7 @@ dt_proc_control(void *arg) dt_proc_control_data_t *datap = arg; dtrace_hdl_t *dtp = datap->dpcd_hdl; dt_proc_t *dpr = datap->dpcd_proc; - dt_proc_hash_t *dph = dpr->dpr_hdl->dt_procs; + dt_proc_hash_t *dph = dtp->dt_procs; struct ps_prochandle *P = dpr->dpr_proc; int pfd = Pctlfd(P); @@ -870,7 +874,8 @@ dt_proc_create(dtrace_hdl_t *dtp, const char *file, char *const *argv) (void) pthread_mutex_init(&dpr->dpr_lock, NULL); (void) pthread_cond_init(&dpr->dpr_cv, NULL); - if ((dpr->dpr_proc = Pcreate(file, argv, &err, NULL, 0)) == NULL) { + dpr->dpr_proc = Pxcreate(file, argv, dtp->dt_proc_env, &err, NULL, 0); + if (dpr->dpr_proc == NULL) { return (dt_proc_error(dtp, dpr, "failed to execute %s: %s\n", file, Pcreate_error(err))); } @@ -1034,30 +1039,75 @@ dt_proc_unlock(dtrace_hdl_t *dtp, struct ps_prochandle *P) } void -dt_proc_hash_create(dtrace_hdl_t *dtp) +dt_proc_init(dtrace_hdl_t *dtp) { + extern char **environ; + static char *envdef[] = { + "LD_NOLAZYLOAD=1", /* linker lazy loading hides funcs */ + NULL + }; + char **p; + int i; + if ((dtp->dt_procs = dt_zalloc(dtp, sizeof (dt_proc_hash_t) + - sizeof (dt_proc_t *) * _dtrace_pidbuckets - 1)) != NULL) { + sizeof (dt_proc_t *) * _dtrace_pidbuckets - 1)) == NULL) + return; - (void) pthread_mutex_init(&dtp->dt_procs->dph_lock, NULL); - (void) pthread_cond_init(&dtp->dt_procs->dph_cv, NULL); + (void) pthread_mutex_init(&dtp->dt_procs->dph_lock, NULL); + (void) pthread_cond_init(&dtp->dt_procs->dph_cv, NULL); - dtp->dt_procs->dph_hashlen = _dtrace_pidbuckets; - dtp->dt_procs->dph_lrulim = _dtrace_pidlrulim; + dtp->dt_procs->dph_hashlen = _dtrace_pidbuckets; + dtp->dt_procs->dph_lrulim = _dtrace_pidlrulim; + + + /* + * Count how big our environment needs to be. + */ + for (i = 1, p = environ; *p != NULL; i++, p++) + continue; + for (p = envdef; *p != NULL; i++, p++) + continue; + + if ((dtp->dt_proc_env = dt_zalloc(dtp, sizeof (char *) * i)) == NULL) + return; + + for (i = 0, p = environ; *p != NULL; i++, p++) { + if ((dtp->dt_proc_env[i] = strdup(*p)) == NULL) + goto err; } + for (p = envdef; *p != NULL; i++, p++) { + if ((dtp->dt_proc_env[i] = strdup(*p)) == NULL) + goto err; + } + + return; + +err: + while (--i != 0) { + dt_free(dtp, dtp->dt_proc_env[i]); + } + dt_free(dtp, dtp->dt_proc_env); + dtp->dt_proc_env = NULL; } void -dt_proc_hash_destroy(dtrace_hdl_t *dtp) +dt_proc_fini(dtrace_hdl_t *dtp) { dt_proc_hash_t *dph = dtp->dt_procs; dt_proc_t *dpr; + char **p; while ((dpr = dt_list_next(&dph->dph_lrulist)) != NULL) dt_proc_destroy(dtp, dpr->dpr_proc); dtp->dt_procs = NULL; dt_free(dtp, dph); + + for (p = dtp->dt_proc_env; *p != NULL; p++) + dt_free(dtp, *p); + + dt_free(dtp, dtp->dt_proc_env); + dtp->dt_proc_env = NULL; } struct ps_prochandle * diff --git a/lib/libdtrace/common/dt_proc.h b/lib/libdtrace/common/dt_proc.h index a3236694b2b7..599a0f9118b7 100644 --- a/lib/libdtrace/common/dt_proc.h +++ b/lib/libdtrace/common/dt_proc.h @@ -24,11 +24,13 @@ * Use is subject to license terms. */ +/* + * Copyright (c) 2012 by Delphix. All rights reserved. + */ + #ifndef _DT_PROC_H #define _DT_PROC_H -#pragma ident "%Z%%M% %I% %E% SMI" - #include #include #include @@ -106,8 +108,8 @@ extern void dt_proc_lock(dtrace_hdl_t *, struct ps_prochandle *); extern void dt_proc_unlock(dtrace_hdl_t *, struct ps_prochandle *); extern dt_proc_t *dt_proc_lookup(dtrace_hdl_t *, struct ps_prochandle *, int); -extern void dt_proc_hash_create(dtrace_hdl_t *); -extern void dt_proc_hash_destroy(dtrace_hdl_t *); +extern void dt_proc_init(dtrace_hdl_t *); +extern void dt_proc_fini(dtrace_hdl_t *); #ifdef __cplusplus } diff --git a/lib/libdtrace/common/dt_regset.c b/lib/libdtrace/common/dt_regset.c index 05cc15c91257..0c747ed133ca 100644 --- a/lib/libdtrace/common/dt_regset.c +++ b/lib/libdtrace/common/dt_regset.c @@ -19,12 +19,15 @@ * * CDDL HEADER END */ + /* * Copyright 2003 Sun Microsystems, Inc. All rights reserved. * Use is subject to license terms. */ -#pragma ident "%Z%%M% %I% %E% SMI" +/* + * Copyright (c) 2012 by Delphix. All rights reserved. + */ #include #include @@ -33,18 +36,19 @@ #include #include +#include dt_regset_t * -dt_regset_create(ulong_t size) +dt_regset_create(ulong_t nregs) { - ulong_t n = BT_BITOUL(size + 1); /* + 1 for %r0 */ + ulong_t n = BT_BITOUL(nregs); dt_regset_t *drp = malloc(sizeof (dt_regset_t)); if (drp == NULL) return (NULL); drp->dr_bitmap = malloc(sizeof (ulong_t) * n); - drp->dr_size = size + 1; + drp->dr_size = nregs; if (drp->dr_bitmap == NULL) { dt_regset_destroy(drp); @@ -68,6 +72,25 @@ dt_regset_reset(dt_regset_t *drp) bzero(drp->dr_bitmap, sizeof (ulong_t) * BT_BITOUL(drp->dr_size)); } +void +dt_regset_assert_free(dt_regset_t *drp) +{ + int reg; + boolean_t fail = B_FALSE; + for (reg = 0; reg < drp->dr_size; reg++) { + if (BT_TEST(drp->dr_bitmap, reg) != 0) { + dt_dprintf("%%r%d was left allocated\n", reg); + fail = B_TRUE; + } + } + + /* + * We set this during dtest runs to check for register leaks. + */ + if (fail && getenv("DTRACE_DEBUG_REGSET") != NULL) + abort(); +} + int dt_regset_alloc(dt_regset_t *drp) { @@ -95,13 +118,15 @@ dt_regset_alloc(dt_regset_t *drp) } } - return (-1); /* no available registers */ + xyerror(D_NOREG, "Insufficient registers to generate code"); + /*NOTREACHED*/ + return (-1); } void dt_regset_free(dt_regset_t *drp, int reg) { - assert(reg > 0 && reg < drp->dr_size); + assert(reg >= 0 && reg < drp->dr_size); assert(BT_TEST(drp->dr_bitmap, reg) != 0); BT_CLEAR(drp->dr_bitmap, reg); } diff --git a/lib/libdtrace/common/dt_regset.h b/lib/libdtrace/common/dt_regset.h index 25e64d048e60..35082846d9d1 100644 --- a/lib/libdtrace/common/dt_regset.h +++ b/lib/libdtrace/common/dt_regset.h @@ -19,16 +19,19 @@ * * CDDL HEADER END */ + /* * Copyright 2003 Sun Microsystems, Inc. All rights reserved. * Use is subject to license terms. */ +/* + * Copyright (c) 2012 by Delphix. All rights reserved. + */ + #ifndef _DT_REGSET_H #define _DT_REGSET_H -#pragma ident "%Z%%M% %I% %E% SMI" - #include #ifdef __cplusplus @@ -45,6 +48,7 @@ extern void dt_regset_destroy(dt_regset_t *); extern void dt_regset_reset(dt_regset_t *); extern int dt_regset_alloc(dt_regset_t *); extern void dt_regset_free(dt_regset_t *, int); +extern void dt_regset_assert_free(dt_regset_t *); #ifdef __cplusplus } diff --git a/lib/libdtrace/common/dt_subr.c b/lib/libdtrace/common/dt_subr.c index f586504cfbcc..25e206eb4cc4 100644 --- a/lib/libdtrace/common/dt_subr.c +++ b/lib/libdtrace/common/dt_subr.c @@ -21,6 +21,7 @@ /* * Copyright (c) 2003, 2010, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2012 by Delphix. All rights reserved. */ #include @@ -577,8 +578,8 @@ dt_printf(dtrace_hdl_t *dtp, FILE *fp, const char *format, ...) size_t avail; /* - * It's not legal to use buffered ouput if there is not a - * handler for buffered output. + * Using buffered output is not allowed if a handler has + * not been installed. */ if (dtp->dt_bufhdlr == NULL) { va_end(ap); diff --git a/lib/libdtrace/i386/dt_isadep.c b/lib/libdtrace/i386/dt_isadep.c index c1484a40742f..d16b393f3d9b 100644 --- a/lib/libdtrace/i386/dt_isadep.c +++ b/lib/libdtrace/i386/dt_isadep.c @@ -24,6 +24,10 @@ * Use is subject to license terms. */ +/* + * Copyright (c) 2012 by Delphix. All rights reserved. + */ + #include #include #include @@ -481,7 +485,8 @@ dt_instr_size(uchar_t *instr, dtrace_hdl_t *dtp, pid_t pid, uintptr_t addr, * another debugger attached to this process. The original instruction * can't be recovered so this must fail. */ - if (x86dis.d86_len == 1 && instr[0] == FASTTRAP_INSTR) + if (x86dis.d86_len == 1 && + (uchar_t)x86dis.d86_bytes[0] == FASTTRAP_INSTR) return (-1); return (x86dis.d86_len); From 9de3bb3344d8f81432a770357165ea8501d3848a Mon Sep 17 00:00:00 2001 From: Martin Matuska Date: Sun, 19 Aug 2012 09:21:20 +0000 Subject: [PATCH 3/6] Update vendor-sys/illumos to illumos-gate 13758:23432da34147 (dtrace) References: https://www.illumos.org/issues/3021 https://www.illumos.org/issues/3022 https://www.illumos.org/issues/3023 https://www.illumos.org/issues/3024 https://www.illumos.org/issues/3025 https://www.illumos.org/issues/3026 Obtained from: ssh://anonhg@hg.illumos.org/illumos-gate --- uts/common/dtrace/dtrace.c | 225 ++++++++++++++++++++--------------- uts/common/sys/dtrace.h | 37 +++++- uts/common/sys/dtrace_impl.h | 57 +++++---- 3 files changed, 189 insertions(+), 130 deletions(-) diff --git a/uts/common/dtrace/dtrace.c b/uts/common/dtrace/dtrace.c index 0c5e4b3a011a..501366158840 100644 --- a/uts/common/dtrace/dtrace.c +++ b/uts/common/dtrace/dtrace.c @@ -22,6 +22,7 @@ /* * Copyright (c) 2003, 2010, Oracle and/or its affiliates. All rights reserved. * Copyright (c) 2011, Joyent, Inc. All rights reserved. + * Copyright (c) 2012 by Delphix. All rights reserved. */ /* @@ -2401,9 +2402,10 @@ dtrace_speculation_commit(dtrace_state_t *state, processorid_t cpu, { dtrace_speculation_t *spec; dtrace_buffer_t *src, *dest; - uintptr_t daddr, saddr, dlimit; + uintptr_t daddr, saddr, dlimit, slimit; dtrace_speculation_state_t current, new; intptr_t offs; + uint64_t timestamp; if (which == 0) return; @@ -2479,7 +2481,37 @@ dtrace_speculation_commit(dtrace_state_t *state, processorid_t cpu, } /* - * We have the space; copy the buffer across. (Note that this is a + * We have sufficient space to copy the speculative buffer into the + * primary buffer. First, modify the speculative buffer, filling + * in the timestamp of all entries with the current time. The data + * must have the commit() time rather than the time it was traced, + * so that all entries in the primary buffer are in timestamp order. + */ + timestamp = dtrace_gethrtime(); + saddr = (uintptr_t)src->dtb_tomax; + slimit = saddr + src->dtb_offset; + while (saddr < slimit) { + size_t size; + dtrace_rechdr_t *dtrh = (dtrace_rechdr_t *)saddr; + + if (dtrh->dtrh_epid == DTRACE_EPIDNONE) { + saddr += sizeof (dtrace_epid_t); + continue; + } + ASSERT3U(dtrh->dtrh_epid, <=, state->dts_necbs); + size = state->dts_ecbs[dtrh->dtrh_epid - 1]->dte_size; + + ASSERT3U(saddr + size, <=, slimit); + ASSERT3U(size, >=, sizeof (dtrace_rechdr_t)); + ASSERT3U(DTRACE_RECORD_LOAD_TIMESTAMP(dtrh), ==, UINT64_MAX); + + DTRACE_RECORD_STORE_TIMESTAMP(dtrh, timestamp); + + saddr += size; + } + + /* + * Copy the buffer across. (Note that this is a * highly subobtimal bcopy(); in the unlikely event that this becomes * a serious performance issue, a high-performance DTrace-specific * bcopy() should obviously be invented.) @@ -5951,7 +5983,7 @@ dtrace_probe(dtrace_id_t id, uintptr_t arg0, uintptr_t arg1, if (now - state->dts_alive > dtrace_deadman_timeout) { /* * We seem to be dead. Unless we (a) have kernel - * destructive permissions (b) have expicitly enabled + * destructive permissions (b) have explicitly enabled * destructive actions and (c) destructive actions have * not been disabled, we're going to transition into * the KILLED state, from which no further processing @@ -5979,8 +6011,18 @@ dtrace_probe(dtrace_id_t id, uintptr_t arg0, uintptr_t arg1, tomax = buf->dtb_tomax; ASSERT(tomax != NULL); - if (ecb->dte_size != 0) - DTRACE_STORE(uint32_t, tomax, offs, ecb->dte_epid); + if (ecb->dte_size != 0) { + dtrace_rechdr_t dtrh; + if (!(mstate.dtms_present & DTRACE_MSTATE_TIMESTAMP)) { + mstate.dtms_timestamp = dtrace_gethrtime(); + mstate.dtms_present |= DTRACE_MSTATE_TIMESTAMP; + } + ASSERT3U(ecb->dte_size, >=, sizeof (dtrace_rechdr_t)); + dtrh.dtrh_epid = ecb->dte_epid; + DTRACE_RECORD_STORE_TIMESTAMP(&dtrh, + mstate.dtms_timestamp); + *((dtrace_rechdr_t *)(tomax + offs)) = dtrh; + } mstate.dtms_epid = ecb->dte_epid; mstate.dtms_present |= DTRACE_MSTATE_EPID; @@ -6144,7 +6186,9 @@ dtrace_probe(dtrace_id_t id, uintptr_t arg0, uintptr_t arg1, continue; switch (act->dta_kind) { - case DTRACEACT_SPECULATE: + case DTRACEACT_SPECULATE: { + dtrace_rechdr_t *dtrh; + ASSERT(buf == &state->dts_buffer[cpuid]); buf = dtrace_speculation_buffer(state, cpuid, val); @@ -6166,10 +6210,23 @@ dtrace_probe(dtrace_id_t id, uintptr_t arg0, uintptr_t arg1, tomax = buf->dtb_tomax; ASSERT(tomax != NULL); - if (ecb->dte_size != 0) - DTRACE_STORE(uint32_t, tomax, offs, - ecb->dte_epid); + if (ecb->dte_size == 0) + continue; + + ASSERT3U(ecb->dte_size, >=, + sizeof (dtrace_rechdr_t)); + dtrh = ((void *)(tomax + offs)); + dtrh->dtrh_epid = ecb->dte_epid; + /* + * When the speculation is committed, all of + * the records in the speculative buffer will + * have their timestamps set to the commit + * time. Until then, it is set to a sentinel + * value, for debugability. + */ + DTRACE_RECORD_STORE_TIMESTAMP(dtrh, UINT64_MAX); continue; + } case DTRACEACT_CHILL: if (dtrace_priv_kernel_destructive(state)) @@ -9369,9 +9426,9 @@ dtrace_ecb_add(dtrace_state_t *state, dtrace_probe_t *probe) /* * The default size is the size of the default action: recording - * the epid. + * the header. */ - ecb->dte_size = ecb->dte_needed = sizeof (dtrace_epid_t); + ecb->dte_size = ecb->dte_needed = sizeof (dtrace_rechdr_t); ecb->dte_alignment = sizeof (dtrace_epid_t); epid = state->dts_epid++; @@ -9470,122 +9527,89 @@ dtrace_ecb_enable(dtrace_ecb_t *ecb) static void dtrace_ecb_resize(dtrace_ecb_t *ecb) { - uint32_t maxalign = sizeof (dtrace_epid_t); - uint32_t align = sizeof (uint8_t), offs, diff; dtrace_action_t *act; - int wastuple = 0; + uint32_t curneeded = UINT32_MAX; uint32_t aggbase = UINT32_MAX; - dtrace_state_t *state = ecb->dte_state; /* - * If we record anything, we always record the epid. (And we always - * record it first.) + * If we record anything, we always record the dtrace_rechdr_t. (And + * we always record it first.) */ - offs = sizeof (dtrace_epid_t); - ecb->dte_size = ecb->dte_needed = sizeof (dtrace_epid_t); + ecb->dte_size = sizeof (dtrace_rechdr_t); + ecb->dte_alignment = sizeof (dtrace_epid_t); for (act = ecb->dte_action; act != NULL; act = act->dta_next) { dtrace_recdesc_t *rec = &act->dta_rec; + ASSERT(rec->dtrd_size > 0 || rec->dtrd_alignment == 1); - if ((align = rec->dtrd_alignment) > maxalign) - maxalign = align; - - if (!wastuple && act->dta_intuple) { - /* - * This is the first record in a tuple. Align the - * offset to be at offset 4 in an 8-byte aligned - * block. - */ - diff = offs + sizeof (dtrace_aggid_t); - - if (diff = (diff & (sizeof (uint64_t) - 1))) - offs += sizeof (uint64_t) - diff; - - aggbase = offs - sizeof (dtrace_aggid_t); - ASSERT(!(aggbase & (sizeof (uint64_t) - 1))); - } - - /*LINTED*/ - if (rec->dtrd_size != 0 && (diff = (offs & (align - 1)))) { - /* - * The current offset is not properly aligned; align it. - */ - offs += align - diff; - } - - rec->dtrd_offset = offs; - - if (offs + rec->dtrd_size > ecb->dte_needed) { - ecb->dte_needed = offs + rec->dtrd_size; - - if (ecb->dte_needed > state->dts_needed) - state->dts_needed = ecb->dte_needed; - } + ecb->dte_alignment = MAX(ecb->dte_alignment, + rec->dtrd_alignment); if (DTRACEACT_ISAGG(act->dta_kind)) { dtrace_aggregation_t *agg = (dtrace_aggregation_t *)act; - dtrace_action_t *first = agg->dtag_first, *prev; - ASSERT(rec->dtrd_size != 0 && first != NULL); - ASSERT(wastuple); + ASSERT(rec->dtrd_size != 0); + ASSERT(agg->dtag_first != NULL); + ASSERT(act->dta_prev->dta_intuple); ASSERT(aggbase != UINT32_MAX); + ASSERT(curneeded != UINT32_MAX); agg->dtag_base = aggbase; - while ((prev = first->dta_prev) != NULL && - DTRACEACT_ISAGG(prev->dta_kind)) { - agg = (dtrace_aggregation_t *)prev; - first = agg->dtag_first; - } + curneeded = P2ROUNDUP(curneeded, rec->dtrd_alignment); + rec->dtrd_offset = curneeded; + curneeded += rec->dtrd_size; + ecb->dte_needed = MAX(ecb->dte_needed, curneeded); - if (prev != NULL) { - offs = prev->dta_rec.dtrd_offset + - prev->dta_rec.dtrd_size; - } else { - offs = sizeof (dtrace_epid_t); + aggbase = UINT32_MAX; + curneeded = UINT32_MAX; + } else if (act->dta_intuple) { + if (curneeded == UINT32_MAX) { + /* + * This is the first record in a tuple. Align + * curneeded to be at offset 4 in an 8-byte + * aligned block. + */ + ASSERT(act->dta_prev == NULL || + !act->dta_prev->dta_intuple); + ASSERT3U(aggbase, ==, UINT32_MAX); + curneeded = P2PHASEUP(ecb->dte_size, + sizeof (uint64_t), sizeof (dtrace_aggid_t)); + + aggbase = curneeded - sizeof (dtrace_aggid_t); + ASSERT(IS_P2ALIGNED(aggbase, + sizeof (uint64_t))); } - wastuple = 0; + curneeded = P2ROUNDUP(curneeded, rec->dtrd_alignment); + rec->dtrd_offset = curneeded; + curneeded += rec->dtrd_size; } else { - if (!act->dta_intuple) - ecb->dte_size = offs + rec->dtrd_size; + /* tuples must be followed by an aggregation */ + ASSERT(act->dta_prev == NULL || + !act->dta_prev->dta_intuple); - offs += rec->dtrd_size; + ecb->dte_size = P2ROUNDUP(ecb->dte_size, + rec->dtrd_alignment); + rec->dtrd_offset = ecb->dte_size; + ecb->dte_size += rec->dtrd_size; + ecb->dte_needed = MAX(ecb->dte_needed, ecb->dte_size); } - - wastuple = act->dta_intuple; } if ((act = ecb->dte_action) != NULL && !(act->dta_kind == DTRACEACT_SPECULATE && act->dta_next == NULL) && - ecb->dte_size == sizeof (dtrace_epid_t)) { + ecb->dte_size == sizeof (dtrace_rechdr_t)) { /* - * If the size is still sizeof (dtrace_epid_t), then all + * If the size is still sizeof (dtrace_rechdr_t), then all * actions store no data; set the size to 0. */ - ecb->dte_alignment = maxalign; ecb->dte_size = 0; - - /* - * If the needed space is still sizeof (dtrace_epid_t), then - * all actions need no additional space; set the needed - * size to 0. - */ - if (ecb->dte_needed == sizeof (dtrace_epid_t)) - ecb->dte_needed = 0; - - return; } - /* - * Set our alignment, and make sure that the dte_size and dte_needed - * are aligned to the size of an EPID. - */ - ecb->dte_alignment = maxalign; - ecb->dte_size = (ecb->dte_size + (sizeof (dtrace_epid_t) - 1)) & - ~(sizeof (dtrace_epid_t) - 1); - ecb->dte_needed = (ecb->dte_needed + (sizeof (dtrace_epid_t) - 1)) & - ~(sizeof (dtrace_epid_t) - 1); - ASSERT(ecb->dte_size <= ecb->dte_needed); + ecb->dte_size = P2ROUNDUP(ecb->dte_size, sizeof (dtrace_epid_t)); + ecb->dte_needed = P2ROUNDUP(ecb->dte_needed, (sizeof (dtrace_epid_t))); + ecb->dte_state->dts_needed = MAX(ecb->dte_state->dts_needed, + ecb->dte_needed); } static dtrace_action_t * @@ -9955,7 +9979,7 @@ dtrace_ecb_action_add(dtrace_ecb_t *ecb, dtrace_actdesc_t *desc) break; case DTRACEACT_SPECULATE: - if (ecb->dte_size > sizeof (dtrace_epid_t)) + if (ecb->dte_size > sizeof (dtrace_rechdr_t)) return (EINVAL); if (dp == NULL) @@ -10068,7 +10092,7 @@ dtrace_ecb_action_remove(dtrace_ecb_t *ecb) ecb->dte_action = NULL; ecb->dte_action_last = NULL; - ecb->dte_size = sizeof (dtrace_epid_t); + ecb->dte_size = 0; } static void @@ -10339,12 +10363,13 @@ dtrace_buffer_switch(dtrace_buffer_t *buf) caddr_t tomax = buf->dtb_tomax; caddr_t xamot = buf->dtb_xamot; dtrace_icookie_t cookie; - hrtime_t now = dtrace_gethrtime(); + hrtime_t now; ASSERT(!(buf->dtb_flags & DTRACEBUF_NOSWITCH)); ASSERT(!(buf->dtb_flags & DTRACEBUF_RING)); cookie = dtrace_interrupt_disable(); + now = dtrace_gethrtime(); buf->dtb_tomax = xamot; buf->dtb_xamot = tomax; buf->dtb_xamot_drops = buf->dtb_drops; @@ -10639,7 +10664,7 @@ dtrace_buffer_reserve(dtrace_buffer_t *buf, size_t needed, size_t align, if (epid == DTRACE_EPIDNONE) { size = sizeof (uint32_t); } else { - ASSERT(epid <= state->dts_necbs); + ASSERT3U(epid, <=, state->dts_necbs); ASSERT(state->dts_ecbs[epid - 1] != NULL); size = state->dts_ecbs[epid - 1]->dte_size; @@ -15623,6 +15648,7 @@ dtrace_ioctl(dev_t dev, int cmd, intptr_t arg, int md, cred_t *cr, int *rv) desc.dtbd_drops = buf->dtb_drops; desc.dtbd_errors = buf->dtb_errors; desc.dtbd_oldest = buf->dtb_xamot_offset; + desc.dtbd_timestamp = dtrace_gethrtime(); mutex_exit(&dtrace_lock); @@ -15675,6 +15701,7 @@ dtrace_ioctl(dev_t dev, int cmd, intptr_t arg, int md, cred_t *cr, int *rv) desc.dtbd_drops = buf->dtb_xamot_drops; desc.dtbd_errors = buf->dtb_xamot_errors; desc.dtbd_oldest = 0; + desc.dtbd_timestamp = buf->dtb_switched; mutex_exit(&dtrace_lock); diff --git a/uts/common/sys/dtrace.h b/uts/common/sys/dtrace.h index c15799a4e4a2..fd7612f88a00 100644 --- a/uts/common/sys/dtrace.h +++ b/uts/common/sys/dtrace.h @@ -26,6 +26,7 @@ /* * Copyright (c) 2011, Joyent, Inc. All rights reserved. + * Copyright (c) 2012 by Delphix. All rights reserved. */ #ifndef _SYS_DTRACE_H @@ -919,10 +920,10 @@ typedef struct dtrace_ecbdesc { * DTrace Metadata Description Structures * * DTrace separates the trace data stream from the metadata stream. The only - * metadata tokens placed in the data stream are enabled probe identifiers - * (EPIDs) or (in the case of aggregations) aggregation identifiers. In order - * to determine the structure of the data, DTrace consumers pass the token to - * the kernel, and receive in return a corresponding description of the enabled + * metadata tokens placed in the data stream are the dtrace_rechdr_t (EPID + + * timestamp) or (in the case of aggregations) aggregation identifiers. To + * determine the structure of the data, DTrace consumers pass the token to the + * kernel, and receive in return a corresponding description of the enabled * probe (via the dtrace_eprobedesc structure) or the aggregation (via the * dtrace_aggdesc structure). Both of these structures are expressed in terms * of record descriptions (via the dtrace_recdesc structure) that describe the @@ -1017,7 +1018,8 @@ typedef struct dtrace_fmtdesc { #define DTRACEOPT_AGGSORTREV 24 /* reverse-sort aggregations */ #define DTRACEOPT_AGGSORTPOS 25 /* agg. position to sort on */ #define DTRACEOPT_AGGSORTKEYPOS 26 /* agg. key position to sort on */ -#define DTRACEOPT_MAX 27 /* number of options */ +#define DTRACEOPT_TEMPORAL 27 /* temporally ordered output */ +#define DTRACEOPT_MAX 28 /* number of options */ #define DTRACEOPT_UNSET (dtrace_optval_t)-2 /* unset option */ @@ -1037,7 +1039,9 @@ typedef struct dtrace_fmtdesc { * where user-level wishes the kernel to snapshot the buffer to (the * dtbd_data field). The kernel uses the same structure to pass back some * information regarding the buffer: the size of data actually copied out, the - * number of drops, the number of errors, and the offset of the oldest record. + * number of drops, the number of errors, the offset of the oldest record, + * and the time of the snapshot. + * * If the buffer policy is a "switch" policy, taking a snapshot of the * principal buffer has the additional effect of switching the active and * inactive buffers. Taking a snapshot of the aggregation buffer _always_ has @@ -1050,8 +1054,29 @@ typedef struct dtrace_bufdesc { uint64_t dtbd_drops; /* number of drops */ DTRACE_PTR(char, dtbd_data); /* data */ uint64_t dtbd_oldest; /* offset of oldest record */ + uint64_t dtbd_timestamp; /* hrtime of snapshot */ } dtrace_bufdesc_t; +/* + * Each record in the buffer (dtbd_data) begins with a header that includes + * the epid and a timestamp. The timestamp is split into two 4-byte parts + * so that we do not require 8-byte alignment. + */ +typedef struct dtrace_rechdr { + dtrace_epid_t dtrh_epid; /* enabled probe id */ + uint32_t dtrh_timestamp_hi; /* high bits of hrtime_t */ + uint32_t dtrh_timestamp_lo; /* low bits of hrtime_t */ +} dtrace_rechdr_t; + +#define DTRACE_RECORD_LOAD_TIMESTAMP(dtrh) \ + ((dtrh)->dtrh_timestamp_lo + \ + ((uint64_t)(dtrh)->dtrh_timestamp_hi << 32)) + +#define DTRACE_RECORD_STORE_TIMESTAMP(dtrh, hrtime) { \ + (dtrh)->dtrh_timestamp_lo = (uint32_t)hrtime; \ + (dtrh)->dtrh_timestamp_hi = hrtime >> 32; \ +} + /* * DTrace Status * diff --git a/uts/common/sys/dtrace_impl.h b/uts/common/sys/dtrace_impl.h index 3bebd0cb30b0..d7800821378e 100644 --- a/uts/common/sys/dtrace_impl.h +++ b/uts/common/sys/dtrace_impl.h @@ -26,6 +26,7 @@ /* * Copyright (c) 2011, Joyent, Inc. All rights reserved. + * Copyright (c) 2012 by Delphix. All rights reserved. */ #ifndef _SYS_DTRACE_IMPL_H @@ -199,15 +200,18 @@ typedef struct dtrace_hash { * predicate is non-NULL, the DIF object is executed. If the result is * non-zero, the action list is processed, with each action being executed * accordingly. When the action list has been completely executed, processing - * advances to the next ECB. processing advances to the next ECB. If the - * result is non-zero; For each ECB, it first determines the The ECB - * abstraction allows disjoint consumers to multiplex on single probes. + * advances to the next ECB. The ECB abstraction allows disjoint consumers + * to multiplex on single probes. + * + * Execution of the ECB results in consuming dte_size bytes in the buffer + * to record data. During execution, dte_needed bytes must be available in + * the buffer. This space is used for both recorded data and tuple data. */ struct dtrace_ecb { dtrace_epid_t dte_epid; /* enabled probe ID */ uint32_t dte_alignment; /* required alignment */ - size_t dte_needed; /* bytes needed */ - size_t dte_size; /* total size of payload */ + size_t dte_needed; /* space needed for execution */ + size_t dte_size; /* size of recorded payload */ dtrace_predicate_t *dte_predicate; /* predicate, if any */ dtrace_action_t *dte_action; /* actions, if any */ dtrace_ecb_t *dte_next; /* next ECB on probe */ @@ -265,27 +269,30 @@ typedef struct dtrace_aggregation { * the EPID, the consumer can determine the data layout. (The data buffer * layout is shown schematically below.) By assuring that one can determine * data layout from the EPID, the metadata stream can be separated from the - * data stream -- simplifying the data stream enormously. + * data stream -- simplifying the data stream enormously. The ECB always + * proceeds the recorded data as part of the dtrace_rechdr_t structure that + * includes the EPID and a high-resolution timestamp used for output ordering + * consistency. * - * base of data buffer ---> +------+--------------------+------+ - * | EPID | data | EPID | - * +------+--------+------+----+------+ - * | data | EPID | data | - * +---------------+------+-----------+ - * | data, cont. | - * +------+--------------------+------+ - * | EPID | data | | - * +------+--------------------+ | - * | || | - * | || | - * | \/ | - * : : - * . . - * . . - * . . - * : : - * | | - * limit of data buffer ---> +----------------------------------+ + * base of data buffer ---> +--------+--------------------+--------+ + * | rechdr | data | rechdr | + * +--------+------+--------+----+--------+ + * | data | rechdr | data | + * +---------------+--------+-------------+ + * | data, cont. | + * +--------+--------------------+--------+ + * | rechdr | data | | + * +--------+--------------------+ | + * | || | + * | || | + * | \/ | + * : : + * . . + * . . + * . . + * : : + * | | + * limit of data buffer ---> +--------------------------------------+ * * When evaluating an ECB, dtrace_probe() determines if the ECB's needs of the * principal buffer (both scratch and payload) exceed the available space. If From 49d55f91bb70eb69f797c59261d3ea1b1b618895 Mon Sep 17 00:00:00 2001 From: Martin Matuska Date: Sun, 19 Aug 2012 09:30:58 +0000 Subject: [PATCH 4/6] Update vendor/illumos to illumos-gate 13773:00c2a08cf1bb References: https://www.illumos.org/issues/2399 (zfs manual page) Obtained from: ssh://anonhg@hg.illumos.org/illumos-gate --- man/man1m/zfs.1m | 101 ++++++++++++++++++++++++++++++++++++++++++++--- 1 file changed, 95 insertions(+), 6 deletions(-) diff --git a/man/man1m/zfs.1m b/man/man1m/zfs.1m index 32b0cb282ef9..19d44973b737 100644 --- a/man/man1m/zfs.1m +++ b/man/man1m/zfs.1m @@ -7,7 +7,7 @@ .\" 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] .\" Copyright 2011 Joshua M. Clulow -.TH ZFS 1M "28 Jul 2011" +.TH ZFS 1M "Aug 16, 2012" .SH NAME zfs \- configures ZFS file systems .SH SYNOPSIS @@ -219,6 +219,10 @@ zfs \- configures ZFS file systems \fBzfs\fR \fBrelease\fR [\fB-r\fR] \fItag\fR \fIsnapshot\fR... .fi +.LP +.nf +\fBzfs\fR \fBdiff\fR [\fB-FHt\fR] \fIsnapshot\fR \fIsnapshot|filesystem\fR + .SH DESCRIPTION .sp .LP @@ -1758,7 +1762,7 @@ filesystem's oldest or newest snapshot will be implied. .sp Multiple snapshots (or ranges of snapshots) of the same filesystem or volume may be specified -in a comma-separated list of snapshots. +in a comma-separated list of snapshots. Only the snapshot's short name (the part after the \fB@\fR) should be specified when using a range or comma-separated list to identify multiple snapshots. @@ -1831,8 +1835,6 @@ options, as they can destroy large portions of a pool and cause unexpected behavior for mounted file systems in use. .RE -.RE - .sp .ne 2 .na @@ -3057,6 +3059,9 @@ clone subcommand Must also have the 'create' ability and 'mount' ability in the origin file system create subcommand Must also have the 'mount' ability destroy subcommand Must also have the 'mount' ability +diff subcommand Allows lookup of paths within a dataset + given an object number, and the ability to + create snapshots necessary to 'zfs diff'. mount subcommand Allows mount/umount of ZFS datasets promote subcommand Must also have the 'mount' and 'promote' ability in the origin file system @@ -3267,6 +3272,68 @@ Recursively releases a hold with the given tag on the snapshots of all descendent file systems. .RE +.sp +.ne 2 +.na +\fBzfs diff\fR [\fB-FHt\fR] \fIsnapshot\fR \fIsnapshot|filesystem\fR +.ad +.sp .6 +.RS 4n +Display the difference between a snapshot of a given filesystem and another +snapshot of that filesystem from a later time or the current contents of the +filesystem. The first column is a character indicating the type of change, +the other columns indicate pathname, new pathname (in case of rename), change +in link count, and optionally file type and/or change time. + +The types of change are: +.in +2 +.nf +- The path has been removed ++ The path has been created +M The path has been modified +R The path has been renamed +.fi +.in -2 +.sp +.ne 2 +.na +\fB-F\fR +.ad +.sp .6 +.RS 4n +Display an indication of the type of file, in a manner similar to the \fB-F\fR +option of \fBls\fR(1). +.in +2 +.nf +B Block device +C Character device +/ Directory +> Door +| Named pipe +@ Symbolic link +P Event port += Socket +F Regular file +.fi +.in -2 +.RE +.sp +.ne 2 +.na +\fB-H\fR +.ad +.sp .6 +.RS 4n +Give more parseable tab-separated output, without header lines and without arrows. +.RE +.sp +.ne 2 +.na +\fB-t\fR +.ad +.sp .6 +.RS 4n +Display the path's inode change time as the first column of output. .RE .SH EXAMPLES @@ -3650,7 +3717,7 @@ access for system \fBneo\fR on the \fBtank/home\fR file system. .sp .in +2 .nf -# \fB# zfs set sharenfs='rw=@123.123.0.0/16,root=neo' tank/home\fR +# \fBzfs set sharenfs='rw=@123.123.0.0/16,root=neo' tank/home\fR .fi .in -2 .sp @@ -3706,7 +3773,7 @@ The permissions on \fBtank/users\fR are also displayed. .sp .in +2 .nf -# \fB# zfs allow staff create,mount tank/users\fR +# \fBzfs allow staff create,mount tank/users\fR # \fBzfs allow -c destroy tank/users\fR # \fBzfs allow tank/users\fR ------------------------------------------------------------- @@ -3795,6 +3862,28 @@ Local+Descendent permissions on (tank/users) .in -2 .sp +.LP +\fBExample 23\fR Showing the differences between a snapshot and a ZFS Dataset +.sp +.LP +The following example shows how to see what has changed between a prior +snapshot of a ZFS Dataset and its current state. The \fB-F\fR option is used +to indicate type information for the files affected. + +.sp +.in +2 +.nf +# zfs diff -F tank/test@before tank/test +M / /tank/test/ +M F /tank/test/linked (+1) +R F /tank/test/oldname -> /tank/test/newname +- F /tank/test/deleted ++ F /tank/test/created +M F /tank/test/modified +.fi +.in -2 +.sp + .SH EXIT STATUS .sp .LP From 86c5495ef24264f1ca0c36d31944fde8072c656c Mon Sep 17 00:00:00 2001 From: Martin Matuska Date: Sun, 19 Aug 2012 09:34:04 +0000 Subject: [PATCH 5/6] Update vendor-sys/illumos/dist to illumos-gate 13772:2579580ac955 References: https://www.illumos.org/issues/3085 (zfs diff panics) Obtained from: ssh://anonhg@hg.illumos.org/illumos-gate --- uts/common/Makefile.files | 4 ++-- uts/common/fs/zfs/dsl_dataset.c | 7 ++++--- uts/common/fs/zfs/spa_history.c | 4 +++- 3 files changed, 9 insertions(+), 6 deletions(-) diff --git a/uts/common/Makefile.files b/uts/common/Makefile.files index a2b4396f7316..4213fa8720c0 100644 --- a/uts/common/Makefile.files +++ b/uts/common/Makefile.files @@ -1846,7 +1846,7 @@ IDM_OBJS += $(IDM_SHARED_OBJS) \ VR_OBJS += vr.o -ATGE_OBJS += atge_main.o atge_l1e.o atge_mii.o atge_l1.o +ATGE_OBJS += atge_main.o atge_l1e.o atge_mii.o atge_l1.o atge_l1c.o YGE_OBJS = yge.o @@ -1921,7 +1921,7 @@ IXGBE_OBJS = ixgbe_82598.o ixgbe_82599.o ixgbe_api.o \ ixgbe_buf.o ixgbe_debug.o ixgbe_gld.o \ ixgbe_log.o ixgbe_main.o \ ixgbe_osdep.o ixgbe_rx.o ixgbe_stat.o \ - ixgbe_tx.o + ixgbe_tx.o ixgbe_x540.o ixgbe_mbx.o # # NIU 10G/1G driver module diff --git a/uts/common/fs/zfs/dsl_dataset.c b/uts/common/fs/zfs/dsl_dataset.c index 555797e77efe..12ed3ca16fd3 100644 --- a/uts/common/fs/zfs/dsl_dataset.c +++ b/uts/common/fs/zfs/dsl_dataset.c @@ -3903,6 +3903,10 @@ dsl_dataset_user_release_sync(void *arg1, void *tag, dmu_tx_t *tx) VERIFY(error == 0 || error == ENOENT); zapobj = ds->ds_phys->ds_userrefs_obj; VERIFY(0 == zap_remove(mos, zapobj, ra->htag, tx)); + + spa_history_log_internal_ds(ds, "release", tx, + "tag = %s refs now = %lld", ra->htag, (longlong_t)refs); + if (ds->ds_userrefs == 0 && ds->ds_phys->ds_num_children == 1 && DS_IS_DEFER_DESTROY(ds)) { struct dsl_ds_destroyarg dsda = {0}; @@ -3913,9 +3917,6 @@ dsl_dataset_user_release_sync(void *arg1, void *tag, dmu_tx_t *tx) /* We already did the destroy_check */ dsl_dataset_destroy_sync(&dsda, tag, tx); } - - spa_history_log_internal_ds(ds, "release", tx, - "tag = %s refs now = %lld", ra->htag, (longlong_t)refs); } static int diff --git a/uts/common/fs/zfs/spa_history.c b/uts/common/fs/zfs/spa_history.c index f2c32f548b41..96970dafba69 100644 --- a/uts/common/fs/zfs/spa_history.c +++ b/uts/common/fs/zfs/spa_history.c @@ -440,8 +440,10 @@ log_internal(nvlist_t *nvl, const char *operation, spa_t *spa, * If this is part of creating a pool, not everything is * initialized yet, so don't bother logging the internal events. */ - if (tx->tx_txg == TXG_INITIAL) + if (tx->tx_txg == TXG_INITIAL) { + fnvlist_free(nvl); return; + } msg = kmem_alloc(vsnprintf(NULL, 0, fmt, adx) + 1, KM_SLEEP); (void) vsprintf(msg, fmt, adx); From b15aa3a4ae71c04bf81bbceccecde17f08054e5b Mon Sep 17 00:00:00 2001 From: Martin Matuska Date: Thu, 23 Aug 2012 09:18:52 +0000 Subject: [PATCH 6/6] Update vendor/illumos and vendor-sys/illumos to revision 13777:b1e53580146d Obtained from: ssh://anonhg@hg.illumos.org/illumos-gate --- cmd/ztest/ztest.c | 26 ++++++- lib/libzfs/common/libzfs_import.c | 85 ++++++++++------------ uts/common/fs/zfs/dmu.c | 4 +- uts/common/fs/zfs/dmu_send.c | 7 -- uts/common/fs/zfs/dsl_dataset.c | 107 ++++++++++++--------------- uts/common/fs/zfs/dsl_dir.c | 10 +-- uts/common/fs/zfs/dsl_pool.c | 116 ++++++++++++++++++++++-------- uts/common/fs/zfs/spa.c | 76 +++++++++++++++----- uts/common/fs/zfs/spa_misc.c | 17 ++++- uts/common/fs/zfs/sys/dsl_pool.h | 7 +- uts/common/fs/zfs/sys/spa_impl.h | 1 + uts/common/fs/zfs/sys/txg.h | 5 +- uts/common/fs/zfs/sys/vdev.h | 2 +- uts/common/fs/zfs/sys/zil.h | 2 + uts/common/fs/zfs/sys/zil_impl.h | 2 + uts/common/fs/zfs/txg.c | 3 +- uts/common/fs/zfs/vdev.c | 8 +-- uts/common/fs/zfs/vdev_label.c | 75 ++++++++++++------- uts/common/fs/zfs/zil.c | 55 ++++++++++++-- 19 files changed, 393 insertions(+), 215 deletions(-) diff --git a/cmd/ztest/ztest.c b/cmd/ztest/ztest.c index 63acd0c3aab8..bb6398cbda8c 100644 --- a/cmd/ztest/ztest.c +++ b/cmd/ztest/ztest.c @@ -362,7 +362,7 @@ ztest_info_t ztest_info[] = { { ztest_spa_rename, 1, &zopt_rarely }, { ztest_scrub, 1, &zopt_rarely }, { ztest_dsl_dataset_promote_busy, 1, &zopt_rarely }, - { ztest_vdev_attach_detach, 1, &zopt_rarely }, + { ztest_vdev_attach_detach, 1, &zopt_rarely }, { ztest_vdev_LUN_growth, 1, &zopt_rarely }, { ztest_vdev_add_remove, 1, &ztest_opts.zo_vdevtime }, @@ -413,6 +413,13 @@ static spa_t *ztest_spa = NULL; static ztest_ds_t *ztest_ds; static mutex_t ztest_vdev_lock; + +/* + * The ztest_name_lock protects the pool and dataset namespace used by + * the individual tests. To modify the namespace, consumers must grab + * this lock as writer. Grabbing the lock as reader will ensure that the + * namespace does not change while the lock is held. + */ static rwlock_t ztest_name_lock; static boolean_t ztest_dump_core = B_TRUE; @@ -2223,6 +2230,7 @@ ztest_zil_remount(ztest_ds_t *zd, uint64_t id) { objset_t *os = zd->zd_os; + VERIFY(mutex_lock(&zd->zd_dirobj_lock) == 0); (void) rw_wrlock(&zd->zd_zilog_lock); /* zfsvfs_teardown() */ @@ -2233,6 +2241,7 @@ ztest_zil_remount(ztest_ds_t *zd, uint64_t id) zil_replay(os, zd, ztest_replay_vector); (void) rw_unlock(&zd->zd_zilog_lock); + VERIFY(mutex_unlock(&zd->zd_dirobj_lock) == 0); } /* @@ -4852,10 +4861,16 @@ ztest_reguid(ztest_ds_t *zd, uint64_t id) { spa_t *spa = ztest_spa; uint64_t orig, load; + int error; orig = spa_guid(spa); load = spa_load_guid(spa); - if (spa_change_guid(spa) != 0) + + (void) rw_wrlock(&ztest_name_lock); + error = spa_change_guid(spa); + (void) rw_unlock(&ztest_name_lock); + + if (error != 0) return; if (ztest_opts.zo_verbose >= 3) { @@ -5531,8 +5546,15 @@ ztest_freeze(void) */ kernel_init(FREAD | FWRITE); VERIFY3U(0, ==, spa_open(ztest_opts.zo_pool, &spa, FTAG)); + ASSERT(spa_freeze_txg(spa) == UINT64_MAX); VERIFY3U(0, ==, ztest_dataset_open(0)); ztest_dataset_close(0); + + spa->spa_debug = B_TRUE; + ztest_spa = spa; + txg_wait_synced(spa_get_dsl(spa), 0); + ztest_reguid(NULL, 0); + spa_close(spa, FTAG); kernel_fini(); } diff --git a/lib/libzfs/common/libzfs_import.c b/lib/libzfs/common/libzfs_import.c index 414aa2f747b1..36d7420c3bb1 100644 --- a/lib/libzfs/common/libzfs_import.c +++ b/lib/libzfs/common/libzfs_import.c @@ -21,7 +21,7 @@ /* * 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. + * Copyright (c) 2012 by Delphix. All rights reserved. */ /* @@ -439,8 +439,8 @@ 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; - uint64_t version, guid; + char *name, *hostname; + uint64_t guid; uint_t children = 0; nvlist_t **child = NULL; uint_t holes; @@ -526,61 +526,54 @@ get_configs(libzfs_handle_t *hdl, pool_list_t *pl, boolean_t active_ok) * configuration: * * version - * pool guid - * name + * pool guid + * name + * pool txg (if available) * comment (if available) - * pool state + * pool state * hostid (if available) * hostname (if available) */ - uint64_t state; + uint64_t state, version, pool_txg; + char *comment = NULL; - verify(nvlist_lookup_uint64(tmp, - ZPOOL_CONFIG_VERSION, &version) == 0); - if (nvlist_add_uint64(config, - ZPOOL_CONFIG_VERSION, version) != 0) - goto nomem; - verify(nvlist_lookup_uint64(tmp, - ZPOOL_CONFIG_POOL_GUID, &guid) == 0); - if (nvlist_add_uint64(config, - ZPOOL_CONFIG_POOL_GUID, guid) != 0) - goto nomem; - verify(nvlist_lookup_string(tmp, - ZPOOL_CONFIG_POOL_NAME, &name) == 0); - if (nvlist_add_string(config, - ZPOOL_CONFIG_POOL_NAME, name) != 0) - goto nomem; + version = fnvlist_lookup_uint64(tmp, + ZPOOL_CONFIG_VERSION); + fnvlist_add_uint64(config, + ZPOOL_CONFIG_VERSION, version); + guid = fnvlist_lookup_uint64(tmp, + ZPOOL_CONFIG_POOL_GUID); + fnvlist_add_uint64(config, + ZPOOL_CONFIG_POOL_GUID, guid); + name = fnvlist_lookup_string(tmp, + ZPOOL_CONFIG_POOL_NAME); + fnvlist_add_string(config, + ZPOOL_CONFIG_POOL_NAME, name); + + if (nvlist_lookup_uint64(tmp, + ZPOOL_CONFIG_POOL_TXG, &pool_txg) == 0) + fnvlist_add_uint64(config, + ZPOOL_CONFIG_POOL_TXG, pool_txg); - /* - * 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; + ZPOOL_CONFIG_COMMENT, &comment) == 0) + fnvlist_add_string(config, + ZPOOL_CONFIG_COMMENT, comment); - verify(nvlist_lookup_uint64(tmp, - ZPOOL_CONFIG_POOL_STATE, &state) == 0); - if (nvlist_add_uint64(config, - ZPOOL_CONFIG_POOL_STATE, state) != 0) - goto nomem; + state = fnvlist_lookup_uint64(tmp, + ZPOOL_CONFIG_POOL_STATE); + fnvlist_add_uint64(config, + ZPOOL_CONFIG_POOL_STATE, state); hostid = 0; if (nvlist_lookup_uint64(tmp, ZPOOL_CONFIG_HOSTID, &hostid) == 0) { - if (nvlist_add_uint64(config, - ZPOOL_CONFIG_HOSTID, hostid) != 0) - goto nomem; - verify(nvlist_lookup_string(tmp, - ZPOOL_CONFIG_HOSTNAME, - &hostname) == 0); - if (nvlist_add_string(config, - ZPOOL_CONFIG_HOSTNAME, - hostname) != 0) - goto nomem; + fnvlist_add_uint64(config, + ZPOOL_CONFIG_HOSTID, hostid); + hostname = fnvlist_lookup_string(tmp, + ZPOOL_CONFIG_HOSTNAME); + fnvlist_add_string(config, + ZPOOL_CONFIG_HOSTNAME, hostname); } config_seen = B_TRUE; diff --git a/uts/common/fs/zfs/dmu.c b/uts/common/fs/zfs/dmu.c index 94fa52f40d4f..fa49735c87b1 100644 --- a/uts/common/fs/zfs/dmu.c +++ b/uts/common/fs/zfs/dmu.c @@ -1759,15 +1759,15 @@ dmu_init(void) dnode_init(); dbuf_init(); zfetch_init(); - arc_init(); l2arc_init(); + arc_init(); } void dmu_fini(void) { - l2arc_fini(); arc_fini(); + l2arc_fini(); zfetch_fini(); dbuf_fini(); dnode_fini(); diff --git a/uts/common/fs/zfs/dmu_send.c b/uts/common/fs/zfs/dmu_send.c index 5a2c6e2ce759..e2b0c822bbce 100644 --- a/uts/common/fs/zfs/dmu_send.c +++ b/uts/common/fs/zfs/dmu_send.c @@ -1608,13 +1608,6 @@ dmu_recv_existing_end(dmu_recv_cookie_t *drc) dsl_dataset_t *ds = drc->drc_logical_ds; int err, myerr; - /* - * XXX hack; seems the ds is still dirty and dsl_pool_zil_clean() - * expects it to have a ds_user_ptr (and zil), but clone_swap() - * can close it. - */ - txg_wait_synced(ds->ds_dir->dd_pool, 0); - if (dsl_dataset_tryown(ds, FALSE, dmu_recv_tag)) { err = dsl_dataset_clone_swap(drc->drc_real_ds, ds, drc->drc_force); diff --git a/uts/common/fs/zfs/dsl_dataset.c b/uts/common/fs/zfs/dsl_dataset.c index 12ed3ca16fd3..eb38f08d7878 100644 --- a/uts/common/fs/zfs/dsl_dataset.c +++ b/uts/common/fs/zfs/dsl_dataset.c @@ -103,14 +103,8 @@ dsl_dataset_block_born(dsl_dataset_t *ds, const blkptr_t *bp, dmu_tx_t *tx) ASSERT(BP_GET_TYPE(bp) != DMU_OT_NONE); ASSERT(DMU_OT_IS_VALID(BP_GET_TYPE(bp))); if (ds == NULL) { - /* - * Account for the meta-objset space in its placeholder - * dsl_dir. - */ - ASSERT3U(compressed, ==, uncompressed); /* it's all metadata */ - dsl_dir_diduse_space(tx->tx_pool->dp_mos_dir, DD_USED_HEAD, - used, compressed, uncompressed, tx); - dsl_dir_dirty(tx->tx_pool->dp_mos_dir, tx); + dsl_pool_mos_diduse_space(tx->tx_pool, + used, compressed, uncompressed); return; } dmu_buf_will_dirty(ds->ds_dbuf, tx); @@ -146,15 +140,9 @@ dsl_dataset_block_kill(dsl_dataset_t *ds, const blkptr_t *bp, dmu_tx_t *tx, ASSERT(used > 0); if (ds == NULL) { - /* - * Account for the meta-objset space in its placeholder - * dataset. - */ dsl_free(tx->tx_pool, tx->tx_txg, bp); - - dsl_dir_diduse_space(tx->tx_pool->dp_mos_dir, DD_USED_HEAD, - -used, -compressed, -uncompressed, tx); - dsl_dir_dirty(tx->tx_pool->dp_mos_dir, tx); + dsl_pool_mos_diduse_space(tx->tx_pool, + -used, -compressed, -uncompressed); return (used); } ASSERT3P(tx->tx_pool, ==, ds->ds_dir->dd_pool); @@ -1068,26 +1056,26 @@ dsl_dataset_destroy(dsl_dataset_t *ds, void *tag, boolean_t defer) dd = ds->ds_dir; - /* - * Check for errors and mark this ds as inconsistent, in - * case we crash while freeing the objects. - */ - err = dsl_sync_task_do(dd->dd_pool, dsl_dataset_destroy_begin_check, - dsl_dataset_destroy_begin_sync, ds, NULL, 0); - if (err) - goto out; - - err = dmu_objset_from_ds(ds, &os); - if (err) - goto out; - - /* - * If async destruction is not enabled try to remove all objects - * while in the open context so that there is less work to do in - * the syncing context. - */ if (!spa_feature_is_enabled(dsl_dataset_get_spa(ds), &spa_feature_table[SPA_FEATURE_ASYNC_DESTROY])) { + /* + * Check for errors and mark this ds as inconsistent, in + * case we crash while freeing the objects. + */ + err = dsl_sync_task_do(dd->dd_pool, + dsl_dataset_destroy_begin_check, + dsl_dataset_destroy_begin_sync, ds, NULL, 0); + if (err) + goto out; + + err = dmu_objset_from_ds(ds, &os); + if (err) + goto out; + + /* + * Remove all objects while in the open context so that + * there is less work to do in the syncing context. + */ for (obj = 0; err == 0; err = dmu_object_next(os, &obj, FALSE, ds->ds_phys->ds_prev_snap_txg)) { /* @@ -1098,30 +1086,25 @@ dsl_dataset_destroy(dsl_dataset_t *ds, void *tag, boolean_t defer) } if (err != ESRCH) goto out; - } - /* - * Only the ZIL knows how to free log blocks. - */ - zil_destroy(dmu_objset_zil(os), B_FALSE); + /* + * Sync out all in-flight IO. + */ + txg_wait_synced(dd->dd_pool, 0); - /* - * Sync out all in-flight IO. - */ - txg_wait_synced(dd->dd_pool, 0); + /* + * If we managed to free all the objects in open + * context, the user space accounting should be zero. + */ + if (ds->ds_phys->ds_bp.blk_fill == 0 && + dmu_objset_userused_enabled(os)) { + uint64_t count; - /* - * If we managed to free all the objects in open - * context, the user space accounting should be zero. - */ - if (ds->ds_phys->ds_bp.blk_fill == 0 && - dmu_objset_userused_enabled(os)) { - uint64_t count; - - ASSERT(zap_count(os, DMU_USERUSED_OBJECT, &count) != 0 || - count == 0); - ASSERT(zap_count(os, DMU_GROUPUSED_OBJECT, &count) != 0 || - count == 0); + ASSERT(zap_count(os, DMU_USERUSED_OBJECT, + &count) != 0 || count == 0); + ASSERT(zap_count(os, DMU_GROUPUSED_OBJECT, + &count) != 0 || count == 0); + } } rw_enter(&dd->dd_pool->dp_config_rwlock, RW_READER); @@ -1859,6 +1842,7 @@ dsl_dataset_destroy_sync(void *arg1, void *tag, dmu_tx_t *tx) } else { zfeature_info_t *async_destroy = &spa_feature_table[SPA_FEATURE_ASYNC_DESTROY]; + objset_t *os; /* * There's no next snapshot, so this is a head dataset. @@ -1870,6 +1854,8 @@ dsl_dataset_destroy_sync(void *arg1, void *tag, dmu_tx_t *tx) dsl_deadlist_free(mos, ds->ds_phys->ds_deadlist_obj, tx); ds->ds_phys->ds_deadlist_obj = 0; + VERIFY3U(0, ==, dmu_objset_from_ds(ds, &os)); + if (!spa_feature_is_enabled(dp->dp_spa, async_destroy)) { err = old_synchronous_dataset_destroy(ds, tx); } else { @@ -1879,12 +1865,12 @@ dsl_dataset_destroy_sync(void *arg1, void *tag, dmu_tx_t *tx) */ uint64_t used, comp, uncomp; - ASSERT(err == 0 || err == EBUSY); + zil_destroy_sync(dmu_objset_zil(os), tx); + if (!spa_feature_is_active(dp->dp_spa, async_destroy)) { spa_feature_incr(dp->dp_spa, async_destroy, tx); - dp->dp_bptree_obj = bptree_alloc( - dp->dp_meta_objset, tx); - VERIFY(zap_add(dp->dp_meta_objset, + dp->dp_bptree_obj = bptree_alloc(mos, tx); + VERIFY(zap_add(mos, DMU_POOL_DIRECTORY_OBJECT, DMU_POOL_BPTREE_OBJ, sizeof (uint64_t), 1, &dp->dp_bptree_obj, tx) == 0); @@ -1897,7 +1883,7 @@ dsl_dataset_destroy_sync(void *arg1, void *tag, dmu_tx_t *tx) ASSERT(!DS_UNIQUE_IS_ACCURATE(ds) || ds->ds_phys->ds_unique_bytes == used); - bptree_add(dp->dp_meta_objset, dp->dp_bptree_obj, + bptree_add(mos, dp->dp_bptree_obj, &ds->ds_phys->ds_bp, ds->ds_phys->ds_prev_snap_txg, used, comp, uncomp, tx); dsl_dir_diduse_space(ds->ds_dir, DD_USED_HEAD, @@ -2179,7 +2165,6 @@ dsl_dataset_sync(dsl_dataset_t *ds, zio_t *zio, dmu_tx_t *tx) dmu_buf_will_dirty(ds->ds_dbuf, tx); ds->ds_phys->ds_fsid_guid = ds->ds_fsid_guid; - dsl_dir_dirty(ds->ds_dir, tx); dmu_objset_sync(ds->ds_objset, zio, tx); } diff --git a/uts/common/fs/zfs/dsl_dir.c b/uts/common/fs/zfs/dsl_dir.c index 74c1050fabf0..8c867df86fa1 100644 --- a/uts/common/fs/zfs/dsl_dir.c +++ b/uts/common/fs/zfs/dsl_dir.c @@ -190,7 +190,6 @@ errout: kmem_free(dd, sizeof (dsl_dir_t)); dmu_buf_rele(dbuf, tag); return (err); - } void @@ -224,7 +223,7 @@ dsl_dir_name(dsl_dir_t *dd, char *buf) } } -/* Calculate name legnth, avoiding all the strcat calls of dsl_dir_name */ +/* Calculate name length, avoiding all the strcat calls of dsl_dir_name */ int dsl_dir_namelen(dsl_dir_t *dd) { @@ -582,8 +581,6 @@ dsl_dir_sync(dsl_dir_t *dd, dmu_tx_t *tx) { ASSERT(dmu_tx_is_syncing(tx)); - dmu_buf_will_dirty(dd->dd_dbuf, tx); - mutex_enter(&dd->dd_lock); ASSERT3U(dd->dd_tempreserved[tx->tx_txg&TXG_MASK], ==, 0); dprintf_dd(dd, "txg=%llu towrite=%lluK\n", tx->tx_txg, @@ -940,8 +937,6 @@ dsl_dir_diduse_space(dsl_dir_t *dd, dd_used_t type, ASSERT(dmu_tx_is_syncing(tx)); ASSERT(type < DD_USED_NUM); - dsl_dir_dirty(dd, tx); - if (needlock) mutex_enter(&dd->dd_lock); accounted_delta = parent_delta(dd, dd->dd_phys->dd_used_bytes, used); @@ -950,6 +945,7 @@ dsl_dir_diduse_space(dsl_dir_t *dd, dd_used_t type, dd->dd_phys->dd_compressed_bytes >= -compressed); ASSERT(uncompressed >= 0 || dd->dd_phys->dd_uncompressed_bytes >= -uncompressed); + dmu_buf_will_dirty(dd->dd_dbuf, tx); dd->dd_phys->dd_used_bytes += used; dd->dd_phys->dd_uncompressed_bytes += uncompressed; dd->dd_phys->dd_compressed_bytes += compressed; @@ -991,13 +987,13 @@ dsl_dir_transfer_space(dsl_dir_t *dd, int64_t delta, if (delta == 0 || !(dd->dd_phys->dd_flags & DD_FLAG_USED_BREAKDOWN)) return; - dsl_dir_dirty(dd, tx); if (needlock) mutex_enter(&dd->dd_lock); ASSERT(delta > 0 ? dd->dd_phys->dd_used_breakdown[oldtype] >= delta : dd->dd_phys->dd_used_breakdown[newtype] >= -delta); ASSERT(dd->dd_phys->dd_used_bytes >= ABS(delta)); + dmu_buf_will_dirty(dd->dd_dbuf, tx); dd->dd_phys->dd_used_breakdown[oldtype] -= delta; dd->dd_phys->dd_used_breakdown[newtype] += delta; if (needlock) diff --git a/uts/common/fs/zfs/dsl_pool.c b/uts/common/fs/zfs/dsl_pool.c index e9223944d1b4..7a83c7b62640 100644 --- a/uts/common/fs/zfs/dsl_pool.c +++ b/uts/common/fs/zfs/dsl_pool.c @@ -42,6 +42,7 @@ #include #include #include +#include int zfs_no_write_throttle = 0; int zfs_write_limit_shift = 3; /* 1/8th of physical memory */ @@ -86,12 +87,12 @@ dsl_pool_open_impl(spa_t *spa, uint64_t txg) txg_list_create(&dp->dp_dirty_datasets, offsetof(dsl_dataset_t, ds_dirty_link)); + txg_list_create(&dp->dp_dirty_zilogs, + offsetof(zilog_t, zl_dirty_link)); txg_list_create(&dp->dp_dirty_dirs, offsetof(dsl_dir_t, dd_dirty_link)); txg_list_create(&dp->dp_sync_tasks, offsetof(dsl_sync_task_group_t, dstg_node)); - list_create(&dp->dp_synced_datasets, sizeof (dsl_dataset_t), - offsetof(dsl_dataset_t, ds_synced_link)); mutex_init(&dp->dp_lock, NULL, MUTEX_DEFAULT, NULL); @@ -224,9 +225,9 @@ dsl_pool_close(dsl_pool_t *dp) dmu_objset_evict(dp->dp_meta_objset); txg_list_destroy(&dp->dp_dirty_datasets); + txg_list_destroy(&dp->dp_dirty_zilogs); txg_list_destroy(&dp->dp_sync_tasks); txg_list_destroy(&dp->dp_dirty_dirs); - list_destroy(&dp->dp_synced_datasets); arc_flush(dp->dp_spa); txg_fini(dp); @@ -306,6 +307,21 @@ dsl_pool_create(spa_t *spa, nvlist_t *zplprops, uint64_t txg) return (dp); } +/* + * Account for the meta-objset space in its placeholder dsl_dir. + */ +void +dsl_pool_mos_diduse_space(dsl_pool_t *dp, + int64_t used, int64_t comp, int64_t uncomp) +{ + ASSERT3U(comp, ==, uncomp); /* it's all metadata */ + mutex_enter(&dp->dp_lock); + dp->dp_mos_used_delta += used; + dp->dp_mos_compressed_delta += comp; + dp->dp_mos_uncompressed_delta += uncomp; + mutex_exit(&dp->dp_lock); +} + static int deadlist_enqueue_cb(void *arg, const blkptr_t *bp, dmu_tx_t *tx) { @@ -324,11 +340,14 @@ dsl_pool_sync(dsl_pool_t *dp, uint64_t txg) dmu_tx_t *tx; dsl_dir_t *dd; dsl_dataset_t *ds; - dsl_sync_task_group_t *dstg; objset_t *mos = dp->dp_meta_objset; hrtime_t start, write_time; uint64_t data_written; int err; + list_t synced_datasets; + + list_create(&synced_datasets, sizeof (dsl_dataset_t), + offsetof(dsl_dataset_t, ds_synced_link)); /* * We need to copy dp_space_towrite() before doing @@ -351,7 +370,7 @@ dsl_pool_sync(dsl_pool_t *dp, uint64_t txg) * may sync newly-created datasets on pass 2. */ ASSERT(!list_link_active(&ds->ds_synced_link)); - list_insert_tail(&dp->dp_synced_datasets, ds); + list_insert_tail(&synced_datasets, ds); dsl_dataset_sync(ds, zio, tx); } DTRACE_PROBE(pool_sync__1setup); @@ -361,15 +380,20 @@ dsl_pool_sync(dsl_pool_t *dp, uint64_t txg) ASSERT(err == 0); DTRACE_PROBE(pool_sync__2rootzio); - for (ds = list_head(&dp->dp_synced_datasets); ds; - ds = list_next(&dp->dp_synced_datasets, ds)) + /* + * After the data blocks have been written (ensured by the zio_wait() + * above), update the user/group space accounting. + */ + for (ds = list_head(&synced_datasets); ds; + ds = list_next(&synced_datasets, ds)) dmu_objset_do_userquota_updates(ds->ds_objset, tx); /* * Sync the datasets again to push out the changes due to * userspace updates. This must be done before we process the - * sync tasks, because that could cause a snapshot of a dataset - * whose ds_bp will be rewritten when we do this 2nd sync. + * sync tasks, so that any snapshots will have the correct + * user accounting information (and we won't get confused + * about which blocks are part of the snapshot). */ zio = zio_root(dp->dp_spa, NULL, NULL, ZIO_FLAG_MUSTSUCCEED); while (ds = txg_list_remove(&dp->dp_dirty_datasets, txg)) { @@ -380,30 +404,42 @@ dsl_pool_sync(dsl_pool_t *dp, uint64_t txg) err = zio_wait(zio); /* - * Move dead blocks from the pending deadlist to the on-disk - * deadlist. + * Now that the datasets have been completely synced, we can + * clean up our in-memory structures accumulated while syncing: + * + * - move dead blocks from the pending deadlist to the on-disk deadlist + * - clean up zil records + * - release hold from dsl_dataset_dirty() */ - for (ds = list_head(&dp->dp_synced_datasets); ds; - ds = list_next(&dp->dp_synced_datasets, ds)) { + while (ds = list_remove_head(&synced_datasets)) { + objset_t *os = ds->ds_objset; bplist_iterate(&ds->ds_pending_deadlist, deadlist_enqueue_cb, &ds->ds_deadlist, tx); + ASSERT(!dmu_objset_is_dirty(os, txg)); + dmu_buf_rele(ds->ds_dbuf, ds); } - while (dstg = txg_list_remove(&dp->dp_sync_tasks, txg)) { - /* - * No more sync tasks should have been added while we - * were syncing. - */ - ASSERT(spa_sync_pass(dp->dp_spa) == 1); - dsl_sync_task_group_sync(dstg, tx); - } - DTRACE_PROBE(pool_sync__3task); - start = gethrtime(); while (dd = txg_list_remove(&dp->dp_dirty_dirs, txg)) dsl_dir_sync(dd, tx); write_time += gethrtime() - start; + /* + * The MOS's space is accounted for in the pool/$MOS + * (dp_mos_dir). We can't modify the mos while we're syncing + * it, so we remember the deltas and apply them here. + */ + if (dp->dp_mos_used_delta != 0 || dp->dp_mos_compressed_delta != 0 || + dp->dp_mos_uncompressed_delta != 0) { + dsl_dir_diduse_space(dp->dp_mos_dir, DD_USED_HEAD, + dp->dp_mos_used_delta, + dp->dp_mos_compressed_delta, + dp->dp_mos_uncompressed_delta, tx); + dp->dp_mos_used_delta = 0; + dp->dp_mos_compressed_delta = 0; + dp->dp_mos_uncompressed_delta = 0; + } + start = gethrtime(); if (list_head(&mos->os_dirty_dnodes[txg & TXG_MASK]) != NULL || list_head(&mos->os_free_dnodes[txg & TXG_MASK]) != NULL) { @@ -419,6 +455,27 @@ dsl_pool_sync(dsl_pool_t *dp, uint64_t txg) hrtime_t, dp->dp_read_overhead); write_time -= dp->dp_read_overhead; + /* + * If we modify a dataset in the same txg that we want to destroy it, + * its dsl_dir's dd_dbuf will be dirty, and thus have a hold on it. + * dsl_dir_destroy_check() will fail if there are unexpected holds. + * Therefore, we want to sync the MOS (thus syncing the dd_dbuf + * and clearing the hold on it) before we process the sync_tasks. + * The MOS data dirtied by the sync_tasks will be synced on the next + * pass. + */ + DTRACE_PROBE(pool_sync__3task); + if (!txg_list_empty(&dp->dp_sync_tasks, txg)) { + dsl_sync_task_group_t *dstg; + /* + * No more sync tasks should have been added while we + * were syncing. + */ + ASSERT(spa_sync_pass(dp->dp_spa) == 1); + while (dstg = txg_list_remove(&dp->dp_sync_tasks, txg)) + dsl_sync_task_group_sync(dstg, tx); + } + dmu_tx_commit(tx); dp->dp_space_towrite[txg & TXG_MASK] = 0; @@ -467,15 +524,14 @@ dsl_pool_sync(dsl_pool_t *dp, uint64_t txg) void dsl_pool_sync_done(dsl_pool_t *dp, uint64_t txg) { + zilog_t *zilog; dsl_dataset_t *ds; - objset_t *os; - while (ds = list_head(&dp->dp_synced_datasets)) { - list_remove(&dp->dp_synced_datasets, ds); - os = ds->ds_objset; - zil_clean(os->os_zil, txg); - ASSERT(!dmu_objset_is_dirty(os, txg)); - dmu_buf_rele(ds->ds_dbuf, ds); + while (zilog = txg_list_remove(&dp->dp_dirty_zilogs, txg)) { + ds = dmu_objset_ds(zilog->zl_os); + zil_clean(zilog, txg); + ASSERT(!dmu_objset_is_dirty(zilog->zl_os, txg)); + dmu_buf_rele(ds->ds_dbuf, zilog); } ASSERT(!dmu_objset_is_dirty(dp->dp_meta_objset, txg)); } diff --git a/uts/common/fs/zfs/spa.c b/uts/common/fs/zfs/spa.c index 9c4af11134d3..2bb6fac11a2e 100644 --- a/uts/common/fs/zfs/spa.c +++ b/uts/common/fs/zfs/spa.c @@ -116,6 +116,8 @@ const zio_taskq_info_t zio_taskqs[ZIO_TYPES][ZIO_TASKQ_TYPES] = { static dsl_syncfunc_t spa_sync_version; static dsl_syncfunc_t spa_sync_props; +static dsl_checkfunc_t spa_change_guid_check; +static dsl_syncfunc_t spa_change_guid_sync; static boolean_t spa_has_active_shared_spare(spa_t *spa); static int spa_load_impl(spa_t *spa, uint64_t, nvlist_t *config, spa_load_state_t state, spa_import_type_t type, boolean_t mosconfig, @@ -675,6 +677,47 @@ spa_prop_clear_bootfs(spa_t *spa, uint64_t dsobj, dmu_tx_t *tx) } } +/*ARGSUSED*/ +static int +spa_change_guid_check(void *arg1, void *arg2, dmu_tx_t *tx) +{ + spa_t *spa = arg1; + uint64_t *newguid = arg2; + vdev_t *rvd = spa->spa_root_vdev; + uint64_t vdev_state; + + spa_config_enter(spa, SCL_STATE, FTAG, RW_READER); + vdev_state = rvd->vdev_state; + spa_config_exit(spa, SCL_STATE, FTAG); + + if (vdev_state != VDEV_STATE_HEALTHY) + return (ENXIO); + + ASSERT3U(spa_guid(spa), !=, *newguid); + + return (0); +} + +static void +spa_change_guid_sync(void *arg1, void *arg2, dmu_tx_t *tx) +{ + spa_t *spa = arg1; + uint64_t *newguid = arg2; + uint64_t oldguid; + vdev_t *rvd = spa->spa_root_vdev; + + oldguid = spa_guid(spa); + + spa_config_enter(spa, SCL_STATE, FTAG, RW_READER); + rvd->vdev_guid = *newguid; + rvd->vdev_guid_sum += (*newguid - oldguid); + vdev_config_dirty(rvd); + spa_config_exit(spa, SCL_STATE, FTAG); + + spa_history_log_internal(spa, "guid change", tx, "old=%lld new=%lld", + oldguid, *newguid); +} + /* * Change the GUID for the pool. This is done so that we can later * re-import a pool built from a clone of our own vdevs. We will modify @@ -687,29 +730,23 @@ spa_prop_clear_bootfs(spa_t *spa, uint64_t dsobj, dmu_tx_t *tx) int spa_change_guid(spa_t *spa) { - uint64_t oldguid, newguid; - uint64_t txg; + int error; + uint64_t guid; - if (!(spa_mode_global & FWRITE)) - return (EROFS); + mutex_enter(&spa_namespace_lock); + guid = spa_generate_guid(NULL); - txg = spa_vdev_enter(spa); + error = dsl_sync_task_do(spa_get_dsl(spa), spa_change_guid_check, + spa_change_guid_sync, spa, &guid, 5); - if (spa->spa_root_vdev->vdev_state != VDEV_STATE_HEALTHY) - return (spa_vdev_exit(spa, NULL, txg, ENXIO)); + if (error == 0) { + spa_config_sync(spa, B_FALSE, B_TRUE); + spa_event_notify(spa, NULL, ESC_ZFS_POOL_REGUID); + } - oldguid = spa_guid(spa); - newguid = spa_generate_guid(NULL); - ASSERT3U(oldguid, !=, newguid); + mutex_exit(&spa_namespace_lock); - spa->spa_root_vdev->vdev_guid = newguid; - spa->spa_root_vdev->vdev_guid_sum += (newguid - oldguid); - - vdev_config_dirty(spa->spa_root_vdev); - - spa_event_notify(spa, NULL, ESC_ZFS_POOL_REGUID); - - return (spa_vdev_exit(spa, NULL, txg, 0)); + return (error); } /* @@ -6062,6 +6099,9 @@ spa_sync(spa_t *spa, uint64_t txg) rvd->vdev_children, txg, B_TRUE); } + if (error == 0) + spa->spa_last_synced_guid = rvd->vdev_guid; + spa_config_exit(spa, SCL_STATE, FTAG); if (error == 0) diff --git a/uts/common/fs/zfs/spa_misc.c b/uts/common/fs/zfs/spa_misc.c index 9400194a93b8..9f50e38652ce 100644 --- a/uts/common/fs/zfs/spa_misc.c +++ b/uts/common/fs/zfs/spa_misc.c @@ -1348,16 +1348,29 @@ spa_name(spa_t *spa) uint64_t spa_guid(spa_t *spa) { + dsl_pool_t *dp = spa_get_dsl(spa); + uint64_t guid; + /* * If we fail to parse the config during spa_load(), we can go through * the error path (which posts an ereport) and end up here with no root * vdev. We stash the original pool guid in 'spa_config_guid' to handle * this case. */ - if (spa->spa_root_vdev != NULL) + if (spa->spa_root_vdev == NULL) + return (spa->spa_config_guid); + + guid = spa->spa_last_synced_guid != 0 ? + spa->spa_last_synced_guid : spa->spa_root_vdev->vdev_guid; + + /* + * Return the most recently synced out guid unless we're + * in syncing context. + */ + if (dp && dsl_pool_sync_context(dp)) return (spa->spa_root_vdev->vdev_guid); else - return (spa->spa_config_guid); + return (guid); } uint64_t diff --git a/uts/common/fs/zfs/sys/dsl_pool.h b/uts/common/fs/zfs/sys/dsl_pool.h index 9ff414888cb0..5c1d71e0d258 100644 --- a/uts/common/fs/zfs/sys/dsl_pool.h +++ b/uts/common/fs/zfs/sys/dsl_pool.h @@ -82,7 +82,6 @@ typedef struct dsl_pool { /* No lock needed - sync context only */ blkptr_t dp_meta_rootbp; - list_t dp_synced_datasets; hrtime_t dp_read_overhead; uint64_t dp_throughput; /* bytes per millisec */ uint64_t dp_write_limit; @@ -96,10 +95,14 @@ typedef struct dsl_pool { kmutex_t dp_lock; uint64_t dp_space_towrite[TXG_SIZE]; uint64_t dp_tempreserved[TXG_SIZE]; + uint64_t dp_mos_used_delta; + uint64_t dp_mos_compressed_delta; + uint64_t dp_mos_uncompressed_delta; /* Has its own locking */ tx_state_t dp_tx; txg_list_t dp_dirty_datasets; + txg_list_t dp_dirty_zilogs; txg_list_t dp_dirty_dirs; txg_list_t dp_sync_tasks; @@ -139,6 +142,8 @@ int dsl_read_nolock(zio_t *pio, spa_t *spa, const blkptr_t *bpp, void dsl_pool_create_origin(dsl_pool_t *dp, dmu_tx_t *tx); void dsl_pool_upgrade_clones(dsl_pool_t *dp, dmu_tx_t *tx); void dsl_pool_upgrade_dir_clones(dsl_pool_t *dp, dmu_tx_t *tx); +void dsl_pool_mos_diduse_space(dsl_pool_t *dp, + int64_t used, int64_t comp, int64_t uncomp); taskq_t *dsl_pool_vnrele_taskq(dsl_pool_t *dp); diff --git a/uts/common/fs/zfs/sys/spa_impl.h b/uts/common/fs/zfs/sys/spa_impl.h index 5118954b0016..027832e8587c 100644 --- a/uts/common/fs/zfs/sys/spa_impl.h +++ b/uts/common/fs/zfs/sys/spa_impl.h @@ -141,6 +141,7 @@ struct spa { vdev_t *spa_root_vdev; /* top-level vdev container */ uint64_t spa_config_guid; /* config pool guid */ uint64_t spa_load_guid; /* spa_load initialized guid */ + uint64_t spa_last_synced_guid; /* last synced guid */ list_t spa_config_dirty_list; /* vdevs with dirty config */ list_t spa_state_dirty_list; /* vdevs with dirty state */ spa_aux_vdev_t spa_spares; /* hot spares */ diff --git a/uts/common/fs/zfs/sys/txg.h b/uts/common/fs/zfs/sys/txg.h index e323d5efabb7..1287f09c7ee8 100644 --- a/uts/common/fs/zfs/sys/txg.h +++ b/uts/common/fs/zfs/sys/txg.h @@ -22,6 +22,9 @@ * Copyright 2010 Sun Microsystems, Inc. All rights reserved. * Use is subject to license terms. */ +/* + * Copyright (c) 2012 by Delphix. All rights reserved. + */ #ifndef _SYS_TXG_H #define _SYS_TXG_H @@ -115,7 +118,7 @@ extern boolean_t txg_sync_waiting(struct dsl_pool *dp); extern void txg_list_create(txg_list_t *tl, size_t offset); extern void txg_list_destroy(txg_list_t *tl); -extern int txg_list_empty(txg_list_t *tl, uint64_t txg); +extern boolean_t txg_list_empty(txg_list_t *tl, uint64_t txg); extern int txg_list_add(txg_list_t *tl, void *p, uint64_t txg); extern int txg_list_add_tail(txg_list_t *tl, void *p, uint64_t txg); extern void *txg_list_remove(txg_list_t *tl, uint64_t txg); diff --git a/uts/common/fs/zfs/sys/vdev.h b/uts/common/fs/zfs/sys/vdev.h index 2329d5b85c68..7e34889b61f0 100644 --- a/uts/common/fs/zfs/sys/vdev.h +++ b/uts/common/fs/zfs/sys/vdev.h @@ -142,7 +142,7 @@ extern nvlist_t *vdev_config_generate(spa_t *spa, vdev_t *vd, struct uberblock; extern uint64_t vdev_label_offset(uint64_t psize, int l, uint64_t offset); extern int vdev_label_number(uint64_t psise, uint64_t offset); -extern nvlist_t *vdev_label_read_config(vdev_t *vd, int label); +extern nvlist_t *vdev_label_read_config(vdev_t *vd, uint64_t txg); extern void vdev_uberblock_load(vdev_t *, struct uberblock *, nvlist_t **); typedef enum { diff --git a/uts/common/fs/zfs/sys/zil.h b/uts/common/fs/zfs/sys/zil.h index a4c5575b2dba..e52c65bb762f 100644 --- a/uts/common/fs/zfs/sys/zil.h +++ b/uts/common/fs/zfs/sys/zil.h @@ -20,6 +20,7 @@ */ /* * Copyright (c) 2005, 2010, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2012 by Delphix. All rights reserved. */ /* Portions Copyright 2010 Robert Milkowski */ @@ -395,6 +396,7 @@ extern void zil_replay(objset_t *os, void *arg, zil_replay_func_t *replay_func[TX_MAX_TYPE]); extern boolean_t zil_replaying(zilog_t *zilog, dmu_tx_t *tx); extern void zil_destroy(zilog_t *zilog, boolean_t keep_first); +extern void zil_destroy_sync(zilog_t *zilog, dmu_tx_t *tx); extern void zil_rollback_destroy(zilog_t *zilog, dmu_tx_t *tx); extern itx_t *zil_itx_create(uint64_t txtype, size_t lrsize); diff --git a/uts/common/fs/zfs/sys/zil_impl.h b/uts/common/fs/zfs/sys/zil_impl.h index 1d4c0cc6c1de..58566203b697 100644 --- a/uts/common/fs/zfs/sys/zil_impl.h +++ b/uts/common/fs/zfs/sys/zil_impl.h @@ -20,6 +20,7 @@ */ /* * Copyright (c) 2005, 2010, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2012 by Delphix. All rights reserved. */ /* Portions Copyright 2010 Robert Milkowski */ @@ -130,6 +131,7 @@ struct zilog { zil_header_t zl_old_header; /* debugging aid */ uint_t zl_prev_blks[ZIL_PREV_BLKS]; /* size - sector rounded */ uint_t zl_prev_rotor; /* rotor for zl_prev[] */ + txg_node_t zl_dirty_link; /* protected by dp_dirty_zilogs list */ }; typedef struct zil_bp_node { diff --git a/uts/common/fs/zfs/txg.c b/uts/common/fs/zfs/txg.c index 55b1f3884bf3..91a639a648e2 100644 --- a/uts/common/fs/zfs/txg.c +++ b/uts/common/fs/zfs/txg.c @@ -21,6 +21,7 @@ /* * Copyright (c) 2005, 2010, Oracle and/or its affiliates. All rights reserved. * Portions Copyright 2011 Martin Matuska + * Copyright (c) 2012 by Delphix. All rights reserved. */ #include @@ -587,7 +588,7 @@ txg_list_destroy(txg_list_t *tl) mutex_destroy(&tl->tl_lock); } -int +boolean_t txg_list_empty(txg_list_t *tl, uint64_t txg) { return (tl->tl_head[txg & TXG_MASK] == NULL); diff --git a/uts/common/fs/zfs/vdev.c b/uts/common/fs/zfs/vdev.c index 6fbaf7b7ecca..0b8e073f90f0 100644 --- a/uts/common/fs/zfs/vdev.c +++ b/uts/common/fs/zfs/vdev.c @@ -1327,9 +1327,9 @@ vdev_validate(vdev_t *vd, boolean_t strict) if (vd->vdev_ops->vdev_op_leaf && vdev_readable(vd)) { uint64_t aux_guid = 0; nvlist_t *nvl; + uint64_t txg = strict ? spa->spa_config_txg : -1ULL; - if ((label = vdev_label_read_config(vd, VDEV_BEST_LABEL)) == - NULL) { + if ((label = vdev_label_read_config(vd, txg)) == NULL) { vdev_set_state(vd, B_TRUE, VDEV_STATE_CANT_OPEN, VDEV_AUX_BAD_LABEL); return (0); @@ -1511,7 +1511,7 @@ vdev_reopen(vdev_t *vd) !l2arc_vdev_present(vd)) l2arc_add_vdev(spa, vd); } else { - (void) vdev_validate(vd, B_TRUE); + (void) vdev_validate(vd, spa_last_synced_txg(spa)); } /* @@ -1970,7 +1970,7 @@ vdev_validate_aux(vdev_t *vd) if (!vdev_readable(vd)) return (0); - if ((label = vdev_label_read_config(vd, VDEV_BEST_LABEL)) == NULL) { + if ((label = vdev_label_read_config(vd, -1ULL)) == NULL) { vdev_set_state(vd, B_TRUE, VDEV_STATE_CANT_OPEN, VDEV_AUX_CORRUPT_DATA); return (-1); diff --git a/uts/common/fs/zfs/vdev_label.c b/uts/common/fs/zfs/vdev_label.c index b9436472495d..e573feb5d239 100644 --- a/uts/common/fs/zfs/vdev_label.c +++ b/uts/common/fs/zfs/vdev_label.c @@ -433,17 +433,22 @@ vdev_top_config_generate(spa_t *spa, nvlist_t *config) } /* - * Returns the configuration from the label of the given vdev. If 'label' is - * VDEV_BEST_LABEL, each label of the vdev will be read until a valid - * configuration is found; otherwise, only the specified label will be read. + * Returns the configuration from the label of the given vdev. For vdevs + * which don't have a txg value stored on their label (i.e. spares/cache) + * or have not been completely initialized (txg = 0) just return + * the configuration from the first valid label we find. Otherwise, + * find the most up-to-date label that does not exceed the specified + * 'txg' value. */ nvlist_t * -vdev_label_read_config(vdev_t *vd, int label) +vdev_label_read_config(vdev_t *vd, uint64_t txg) { spa_t *spa = vd->vdev_spa; nvlist_t *config = NULL; vdev_phys_t *vp; zio_t *zio; + uint64_t best_txg = 0; + int error = 0; int flags = ZIO_FLAG_CONFIG_WRITER | ZIO_FLAG_CANFAIL | ZIO_FLAG_SPECULATIVE; @@ -456,8 +461,7 @@ vdev_label_read_config(vdev_t *vd, int label) retry: for (int l = 0; l < VDEV_LABELS; l++) { - if (label >= 0 && label < VDEV_LABELS && label != l) - continue; + nvlist_t *label = NULL; zio = zio_root(spa, NULL, NULL, flags); @@ -467,12 +471,31 @@ retry: if (zio_wait(zio) == 0 && nvlist_unpack(vp->vp_nvlist, sizeof (vp->vp_nvlist), - &config, 0) == 0) - break; + &label, 0) == 0) { + uint64_t label_txg = 0; - if (config != NULL) { - nvlist_free(config); - config = NULL; + /* + * Auxiliary vdevs won't have txg values in their + * labels and newly added vdevs may not have been + * completely initialized so just return the + * configuration from the first valid label we + * encounter. + */ + error = nvlist_lookup_uint64(label, + ZPOOL_CONFIG_POOL_TXG, &label_txg); + if ((error || label_txg == 0) && !config) { + config = label; + break; + } else if (label_txg <= txg && label_txg > best_txg) { + best_txg = label_txg; + nvlist_free(config); + config = fnvlist_dup(label); + } + } + + if (label != NULL) { + nvlist_free(label); + label = NULL; } } @@ -507,7 +530,7 @@ vdev_inuse(vdev_t *vd, uint64_t crtxg, vdev_labeltype_t reason, /* * Read the label, if any, and perform some basic sanity checks. */ - if ((label = vdev_label_read_config(vd, VDEV_BEST_LABEL)) == NULL) + if ((label = vdev_label_read_config(vd, -1ULL)) == NULL) return (B_FALSE); (void) nvlist_lookup_uint64(label, ZPOOL_CONFIG_CREATE_TXG, @@ -867,7 +890,6 @@ vdev_uberblock_compare(uberblock_t *ub1, uberblock_t *ub2) struct ubl_cbdata { uberblock_t *ubl_ubbest; /* Best uberblock */ vdev_t *ubl_vd; /* vdev associated with the above */ - int ubl_label; /* Label associated with the above */ }; static void @@ -886,15 +908,13 @@ vdev_uberblock_load_done(zio_t *zio) if (ub->ub_txg <= spa->spa_load_max_txg && vdev_uberblock_compare(ub, cbp->ubl_ubbest) > 0) { /* - * Keep track of the vdev and label in which this - * uberblock was found. We will use this information - * later to obtain the config nvlist associated with + * Keep track of the vdev in which this uberblock + * was found. We will use this information later + * to obtain the config nvlist associated with * this uberblock. */ *cbp->ubl_ubbest = *ub; cbp->ubl_vd = vd; - cbp->ubl_label = vdev_label_number(vd->vdev_psize, - zio->io_offset); } mutex_exit(&rio->io_lock); } @@ -926,12 +946,11 @@ vdev_uberblock_load_impl(zio_t *zio, vdev_t *vd, int flags, * Reads the 'best' uberblock from disk along with its associated * configuration. First, we read the uberblock array of each label of each * vdev, keeping track of the uberblock with the highest txg in each array. - * Then, we read the configuration from the same label as the best uberblock. + * Then, we read the configuration from the same vdev as the best uberblock. */ void vdev_uberblock_load(vdev_t *rvd, uberblock_t *ub, nvlist_t **config) { - int i; zio_t *zio; spa_t *spa = rvd->vdev_spa; struct ubl_cbdata cb; @@ -951,13 +970,15 @@ vdev_uberblock_load(vdev_t *rvd, uberblock_t *ub, nvlist_t **config) zio = zio_root(spa, NULL, &cb, flags); vdev_uberblock_load_impl(zio, rvd, flags, &cb); (void) zio_wait(zio); - if (cb.ubl_vd != NULL) { - for (i = cb.ubl_label % 2; i < VDEV_LABELS; i += 2) { - *config = vdev_label_read_config(cb.ubl_vd, i); - if (*config != NULL) - break; - } - } + + /* + * It's possible that the best uberblock was discovered on a label + * that has a configuration which was written in a future txg. + * Search all labels on this vdev to find the configuration that + * matches the txg for our uberblock. + */ + if (cb.ubl_vd != NULL) + *config = vdev_label_read_config(cb.ubl_vd, ub->ub_txg); spa_config_exit(spa, SCL_ALL, FTAG); } diff --git a/uts/common/fs/zfs/zil.c b/uts/common/fs/zfs/zil.c index 081242cece5d..0ae4c22d3a4b 100644 --- a/uts/common/fs/zfs/zil.c +++ b/uts/common/fs/zfs/zil.c @@ -20,7 +20,7 @@ */ /* * Copyright (c) 2005, 2010, Oracle and/or its affiliates. All rights reserved. - * Copyright (c) 2011 by Delphix. All rights reserved. + * Copyright (c) 2012 by Delphix. All rights reserved. */ /* Portions Copyright 2010 Robert Milkowski */ @@ -454,6 +454,37 @@ zil_alloc_lwb(zilog_t *zilog, blkptr_t *bp, uint64_t txg) return (lwb); } +/* + * Called when we create in-memory log transactions so that we know + * to cleanup the itxs at the end of spa_sync(). + */ +void +zilog_dirty(zilog_t *zilog, uint64_t txg) +{ + dsl_pool_t *dp = zilog->zl_dmu_pool; + dsl_dataset_t *ds = dmu_objset_ds(zilog->zl_os); + + if (dsl_dataset_is_snapshot(ds)) + panic("dirtying snapshot!"); + + if (txg_list_add(&dp->dp_dirty_zilogs, zilog, txg) == 0) { + /* up the hold count until we can be written out */ + dmu_buf_add_ref(ds->ds_dbuf, zilog); + } +} + +boolean_t +zilog_is_dirty(zilog_t *zilog) +{ + dsl_pool_t *dp = zilog->zl_dmu_pool; + + for (int t = 0; t < TXG_SIZE; t++) { + if (txg_list_member(&dp->dp_dirty_zilogs, zilog, t)) + return (B_TRUE); + } + return (B_FALSE); +} + /* * Create an on-disk intent log. */ @@ -570,14 +601,21 @@ zil_destroy(zilog_t *zilog, boolean_t keep_first) kmem_cache_free(zil_lwb_cache, lwb); } } else if (!keep_first) { - (void) zil_parse(zilog, zil_free_log_block, - zil_free_log_record, tx, zh->zh_claim_txg); + zil_destroy_sync(zilog, tx); } mutex_exit(&zilog->zl_lock); dmu_tx_commit(tx); } +void +zil_destroy_sync(zilog_t *zilog, dmu_tx_t *tx) +{ + ASSERT(list_is_empty(&zilog->zl_lwb_list)); + (void) zil_parse(zilog, zil_free_log_block, + zil_free_log_record, tx, zilog->zl_header->zh_claim_txg); +} + int zil_claim(const char *osname, void *txarg) { @@ -991,6 +1029,8 @@ zil_lwb_commit(zilog_t *zilog, itx_t *itx, lwb_t *lwb) return (NULL); ASSERT(lwb->lwb_buf != NULL); + ASSERT(zilog_is_dirty(zilog) || + spa_freeze_txg(zilog->zl_spa) != UINT64_MAX); if (lrc->lrc_txtype == TX_WRITE && itx->itx_wr_state == WR_NEED_COPY) dlen = P2ROUNDUP_TYPED( @@ -1211,7 +1251,7 @@ zil_itx_assign(zilog_t *zilog, itx_t *itx, dmu_tx_t *tx) if ((itx->itx_lr.lrc_txtype & ~TX_CI) == TX_RENAME) zil_async_to_sync(zilog, itx->itx_oid); - if (spa_freeze_txg(zilog->zl_spa) != UINT64_MAX) + if (spa_freeze_txg(zilog->zl_spa) != UINT64_MAX) txg = ZILTEST_TXG; else txg = dmu_tx_get_txg(tx); @@ -1262,6 +1302,7 @@ zil_itx_assign(zilog_t *zilog, itx_t *itx, dmu_tx_t *tx) } itx->itx_lr.lrc_txg = dmu_tx_get_txg(tx); + zilog_dirty(zilog, txg); mutex_exit(&itxg->itxg_lock); /* Release the old itxs now we've dropped the lock */ @@ -1271,7 +1312,10 @@ zil_itx_assign(zilog_t *zilog, itx_t *itx, dmu_tx_t *tx) /* * If there are any in-memory intent log transactions which have now been - * synced then start up a taskq to free them. + * synced then start up a taskq to free them. We should only do this after we + * have written out the uberblocks (i.e. txg has been comitted) so that + * don't inadvertently clean out in-memory log records that would be required + * by zil_commit(). */ void zil_clean(zilog_t *zilog, uint64_t synced_txg) @@ -1739,6 +1783,7 @@ zil_close(zilog_t *zilog) mutex_exit(&zilog->zl_lock); if (txg) txg_wait_synced(zilog->zl_dmu_pool, txg); + ASSERT(!zilog_is_dirty(zilog)); taskq_destroy(zilog->zl_clean_taskq); zilog->zl_clean_taskq = NULL;