summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorJohn Sonnenschein <johns@joyent.com>2011-12-13 06:55:43 +0000
committerJohn Sonnenschein <johns@joyent.com>2011-12-13 06:55:43 +0000
commit73c531dd5303a633bcaaf609c6eeb2554096b478 (patch)
tree41cd342a9302e3f92a961716a5b27ba78912e937
parentcf1f80d4478d278b94ad9c99026c1b589864f7da (diff)
parentf113db6b62228353583f701aefa9a8f2acbf64b8 (diff)
downloadillumos-joyent-73c531dd5303a633bcaaf609c6eeb2554096b478.tar.gz
Merge branch 'master' into gcc4
-rw-r--r--exception_lists/copyright2
-rw-r--r--manifest163
-rw-r--r--usr/src/cmd/beadm/beadm.c5
-rw-r--r--usr/src/cmd/dis/dis_target.c47
-rw-r--r--usr/src/cmd/dis/dis_target.h2
-rw-r--r--usr/src/cmd/dlmgmtd/dlmgmt_door.c5
-rw-r--r--usr/src/cmd/dtrace/test/tst/common/print/err.D_PRINT_DYN.bad.d29
-rw-r--r--usr/src/cmd/dtrace/test/tst/common/print/err.D_PRINT_VOID.bad.d29
-rw-r--r--usr/src/cmd/dtrace/test/tst/common/print/err.D_PROTO_LEN.bad.d29
-rw-r--r--usr/src/cmd/dtrace/test/tst/common/print/tst.array.d62
-rw-r--r--usr/src/cmd/dtrace/test/tst/common/print/tst.array.d.out23
-rw-r--r--usr/src/cmd/dtrace/test/tst/common/print/tst.bitfield.d49
-rw-r--r--usr/src/cmd/dtrace/test/tst/common/print/tst.bitfield.d.out6
-rw-r--r--usr/src/cmd/dtrace/test/tst/common/print/tst.primitive.d45
-rw-r--r--usr/src/cmd/dtrace/test/tst/common/print/tst.primitive.d.out11
-rw-r--r--usr/src/cmd/dtrace/test/tst/common/print/tst.struct.d59
-rw-r--r--usr/src/cmd/dtrace/test/tst/common/print/tst.struct.d.out12
-rw-r--r--usr/src/cmd/dtrace/test/tst/common/trace/err.D_TRACE_DYN.bad.d29
-rw-r--r--usr/src/cmd/fs.d/nfs/mountd/mountd.c245
-rw-r--r--usr/src/cmd/mdb/common/mdb/mdb_modapi.c49
-rw-r--r--usr/src/cmd/mdb/common/mdb/mdb_modapi.h30
-rw-r--r--usr/src/cmd/mdb/common/modules/conf/mapfile-extern1
-rw-r--r--usr/src/cmd/mdb/common/modules/genunix/kgrep.c12
-rw-r--r--usr/src/cmd/mdb/common/modules/genunix/kmem.c29
-rw-r--r--usr/src/cmd/mdb/common/modules/libumem/umem.c29
-rw-r--r--usr/src/cmd/mdb/i86pc/modules/unix/unix.c75
-rw-r--r--usr/src/cmd/ndmpd/ndmp/ndmpd_zfs.c5
-rw-r--r--usr/src/cmd/ps/ps.c6
-rw-r--r--usr/src/cmd/ps/ucbps.c7
-rw-r--r--usr/src/cmd/smbsrv/smbadm/smbadm.c215
-rw-r--r--usr/src/cmd/truss/codes.c10
-rw-r--r--usr/src/cmd/zfs/zfs_main.c466
-rw-r--r--usr/src/cmd/zoneadm/zoneadm.c14
-rw-r--r--usr/src/cmd/zoneadmd/mcap.c1
-rw-r--r--usr/src/cmd/zoneadmd/vplat.c4
-rw-r--r--usr/src/cmd/zoneadmd/zoneadmd.c14
-rw-r--r--usr/src/cmd/zoneadmd/zoneadmd.h1
-rw-r--r--usr/src/cmd/zonecfg/zonecfg.c82
-rw-r--r--usr/src/cmd/zonecfg/zonecfg.h6
-rw-r--r--usr/src/cmd/zonecfg/zonecfg_grammar.y14
-rw-r--r--usr/src/cmd/zonecfg/zonecfg_lex.l3
-rw-r--r--usr/src/cmd/zpool/zpool_main.c107
-rw-r--r--usr/src/cmd/ztest/ztest.c36
-rw-r--r--usr/src/common/bignum/bignumimpl.c2
-rw-r--r--usr/src/common/zfs/zfs_prop.c20
-rw-r--r--usr/src/common/zfs/zpool_prop.c4
-rw-r--r--usr/src/head/arpa/inet.h6
-rw-r--r--usr/src/lib/brand/joyent/zone/statechange.ksh36
-rw-r--r--usr/src/lib/brand/kvm/zone/config.xml1
-rwxr-xr-xusr/src/lib/brand/kvm/zone/kinstall.ksh5
-rwxr-xr-xusr/src/lib/brand/kvm/zone/statechange.ksh6
-rw-r--r--usr/src/lib/libbe/common/be_create.c42
-rw-r--r--usr/src/lib/libdtrace/Makefile.com3
-rw-r--r--usr/src/lib/libdtrace/common/dt_cc.c49
-rw-r--r--usr/src/lib/libdtrace/common/dt_consume.c30
-rw-r--r--usr/src/lib/libdtrace/common/dt_dof.c14
-rw-r--r--usr/src/lib/libdtrace/common/dt_errtags.h3
-rw-r--r--usr/src/lib/libdtrace/common/dt_impl.h7
-rw-r--r--usr/src/lib/libdtrace/common/dt_map.c172
-rw-r--r--usr/src/lib/libdtrace/common/dt_open.c10
-rw-r--r--usr/src/lib/libdtrace/common/dt_print.c642
-rw-r--r--usr/src/lib/libdtrace/common/dt_program.c2
-rw-r--r--usr/src/lib/libdtrace/common/dtrace.h13
-rw-r--r--usr/src/lib/libnsl/Makefile.com5
-rw-r--r--usr/src/lib/libnsl/common/llib-lnsl5
-rw-r--r--usr/src/lib/libnsl/common/mapfile-vers3
-rw-r--r--usr/src/lib/libnsl/nss/inet_matchaddr.c150
-rw-r--r--usr/src/lib/libsmbfs/netsmb/smbfs_api.h2
-rw-r--r--usr/src/lib/libsmbfs/smb/ntlmssp.c6
-rw-r--r--usr/src/lib/libxnet/common/mapfile-vers7
-rw-r--r--usr/src/lib/libzfs/Makefile.com3
-rw-r--r--usr/src/lib/libzfs/common/libzfs.h56
-rw-r--r--usr/src/lib/libzfs/common/libzfs_dataset.c454
-rw-r--r--usr/src/lib/libzfs/common/libzfs_graph.c653
-rw-r--r--usr/src/lib/libzfs/common/libzfs_impl.h4
-rw-r--r--usr/src/lib/libzfs/common/libzfs_import.c18
-rw-r--r--usr/src/lib/libzfs/common/libzfs_iter.c462
-rw-r--r--usr/src/lib/libzfs/common/libzfs_pool.c48
-rw-r--r--usr/src/lib/libzfs/common/libzfs_sendrecv.c547
-rw-r--r--usr/src/lib/libzfs/common/libzfs_util.c5
-rw-r--r--usr/src/lib/libzfs/common/mapfile-vers11
-rw-r--r--usr/src/lib/libzonecfg/common/getzoneent.c8
-rw-r--r--usr/src/lib/libzonecfg/common/libzonecfg.c10
-rw-r--r--usr/src/lib/smbsrv/libmlsvc/common/smb_share.c11
-rw-r--r--usr/src/lib/smbsrv/libsmb/common/smb_lgrp.c20
-rw-r--r--usr/src/lib/smbsrv/libsmb/common/smb_sam.c117
-rw-r--r--usr/src/lib/smbsrv/libsmb/common/smb_util.c249
-rw-r--r--usr/src/man/man1m/beadm.1m14
-rw-r--r--usr/src/man/man1m/mount_tmpfs.1m14
-rw-r--r--usr/src/man/man1m/smbadm.1m20
-rw-r--r--usr/src/man/man1m/zfs.1m240
-rw-r--r--usr/src/man/man1m/zpool.1m30
-rw-r--r--usr/src/pkg/Makefile2
-rw-r--r--usr/src/pkg/manifests/system-dtrace-tests.mf14
-rw-r--r--usr/src/tools/env/illumos.sh3
-rw-r--r--usr/src/ucbhead/stdio.h66
-rw-r--r--usr/src/ucblib/libucb/port/gen/setbuffer.c7
-rw-r--r--usr/src/uts/Makefile.uts5
-rw-r--r--usr/src/uts/common/dtrace/dtrace.c14
-rw-r--r--usr/src/uts/common/fs/dev/sdev_vnops.c18
-rw-r--r--usr/src/uts/common/fs/nfs/nfs4_rnode.c5
-rw-r--r--usr/src/uts/common/fs/nfs/nfs_subr.c6
-rw-r--r--usr/src/uts/common/fs/smbsrv/smb_common_open.c7
-rw-r--r--usr/src/uts/common/fs/smbsrv/smb_dispatch.c10
-rw-r--r--usr/src/uts/common/fs/smbsrv/smb_nt_transact_notify_change.c3
-rw-r--r--usr/src/uts/common/fs/smbsrv/smb_server.c11
-rw-r--r--usr/src/uts/common/fs/smbsrv/smb_session.c50
-rw-r--r--usr/src/uts/common/fs/smbsrv/smb_session_setup_andx.c7
-rw-r--r--usr/src/uts/common/fs/smbsrv/smb_write.c10
-rw-r--r--usr/src/uts/common/fs/tmpfs/tmp_vfsops.c20
-rw-r--r--usr/src/uts/common/fs/zfs/arc.c10
-rw-r--r--usr/src/uts/common/fs/zfs/bpobj.c7
-rw-r--r--usr/src/uts/common/fs/zfs/dmu.c3
-rw-r--r--usr/src/uts/common/fs/zfs/dmu_send.c106
-rw-r--r--usr/src/uts/common/fs/zfs/dsl_dataset.c314
-rw-r--r--usr/src/uts/common/fs/zfs/dsl_deadlist.c30
-rw-r--r--usr/src/uts/common/fs/zfs/dsl_deleg.c11
-rw-r--r--usr/src/uts/common/fs/zfs/dsl_pool.c4
-rw-r--r--usr/src/uts/common/fs/zfs/spa.c93
-rw-r--r--usr/src/uts/common/fs/zfs/spa_config.c6
-rw-r--r--usr/src/uts/common/fs/zfs/spa_history.c7
-rw-r--r--usr/src/uts/common/fs/zfs/spa_misc.c16
-rw-r--r--usr/src/uts/common/fs/zfs/sys/dmu.h5
-rw-r--r--usr/src/uts/common/fs/zfs/sys/dsl_dataset.h5
-rw-r--r--usr/src/uts/common/fs/zfs/sys/dsl_deleg.h4
-rw-r--r--usr/src/uts/common/fs/zfs/sys/spa.h3
-rw-r--r--usr/src/uts/common/fs/zfs/sys/spa_impl.h5
-rw-r--r--usr/src/uts/common/fs/zfs/sys/vdev_disk.h13
-rw-r--r--usr/src/uts/common/fs/zfs/sys/vdev_raidz.h49
-rw-r--r--usr/src/uts/common/fs/zfs/sys/zio.h2
-rw-r--r--usr/src/uts/common/fs/zfs/vdev.c3
-rw-r--r--usr/src/uts/common/fs/zfs/vdev_disk.c16
-rw-r--r--usr/src/uts/common/fs/zfs/vdev_raidz.c133
-rw-r--r--usr/src/uts/common/fs/zfs/zap_micro.c3
-rw-r--r--usr/src/uts/common/fs/zfs/zfs_ioctl.c223
-rw-r--r--usr/src/uts/common/fs/zfs/zfs_vnops.c31
-rw-r--r--usr/src/uts/common/fs/zfs/zio_checksum.c2
-rw-r--r--usr/src/uts/common/fs/zfs/zvol.c49
-rw-r--r--usr/src/uts/common/inet/ip/ip_ftable.c5
-rw-r--r--usr/src/uts/common/inet/tcp/tcp_input.c7
-rw-r--r--usr/src/uts/common/netinet/in.h34
-rw-r--r--usr/src/uts/common/os/panic.c7
-rw-r--r--usr/src/uts/common/smbsrv/smb_kproto.h4
-rw-r--r--usr/src/uts/common/sys/fs/zfs.h17
-rw-r--r--usr/src/uts/common/sys/sysevent/eventdefs.h2
145 files changed, 5611 insertions, 2183 deletions
diff --git a/exception_lists/copyright b/exception_lists/copyright
index d85cf2bb05..764e72552c 100644
--- a/exception_lists/copyright
+++ b/exception_lists/copyright
@@ -20,12 +20,14 @@
#
# Copyright (c) 2009, 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.
#
syntax: glob
exception_lists/closed-bins
exception_lists/cstyle
exception_lists/hdrchk
+usr/src/cmd/dtrace/test/tst/common/*/*.out
usr/src/cmd/krb5/kadmin/cli/kadmin_ct.c
usr/src/cmd/krb5/kadmin/cli/kadmin.h
usr/src/cmd/krb5/kadmin/cli/ss_wrapper.c
diff --git a/manifest b/manifest
index 17015d2c48..36e57b9769 100644
--- a/manifest
+++ b/manifest
@@ -11912,6 +11912,7 @@ f usr/share/man/man1m/share.1m 0444 root bin
f usr/share/man/man1m/shareall.1m 0444 root bin
f usr/share/man/man1m/sharectl.1m 0444 root bin
f usr/share/man/man1m/sharemgr.1m 0444 root bin
+f usr/share/man/man1m/share_nfs.1m 0444 root bin
f usr/share/man/man1m/showmount.1m 0444 root bin
f usr/share/man/man1m/shutdown.1m 0444 root bin
f usr/share/man/man1m/smbios.1m 0444 root bin
@@ -11953,6 +11954,7 @@ f usr/share/man/man1m/umountall.1m 0444 root bin
f usr/share/man/man1m/unlink.1m 0444 root bin
f usr/share/man/man1m/unshare.1m 0444 root bin
f usr/share/man/man1m/unshareall.1m 0444 root bin
+f usr/share/man/man1m/unshare_nfs.1m 0444 root bin
f usr/share/man/man1m/update_drv.1m 0444 root bin
f usr/share/man/man1m/updatemedia.1m 0444 root bin
f usr/share/man/man1m/useradd.1m 0444 root bin
@@ -11977,7 +11979,17 @@ f usr/share/man/man1m/zpool.1m 0444 root bin
f usr/share/man/man1m/zstreamdump.1m 0444 root bin
d usr/share/man/man2 0755 root bin
f usr/share/man/man2/Intro.2 0444 root bin
-f usr/share/man/man2/__sparc_utrap_install.2 0444 root bin
+f usr/share/man/man2/_exit.2 0444 root bin
+f usr/share/man/man2/_Exit.2 0444 root bin
+f usr/share/man/man2/_lwp_cond_broadcast.2 0444 root bin
+f usr/share/man/man2/_lwp_cond_reltimedwait.2 0444 root bin
+f usr/share/man/man2/_lwp_cond_timedwait.2 0444 root bin
+f usr/share/man/man2/_lwp_continue.2 0444 root bin
+f usr/share/man/man2/_lwp_mutex_trylock.2 0444 root bin
+f usr/share/man/man2/_lwp_mutex_unlock.2 0444 root bin
+f usr/share/man/man2/_lwp_sema_init.2 0444 root bin
+f usr/share/man/man2/_lwp_sema_post.2 0444 root bin
+f usr/share/man/man2/_lwp_sema_trywait.2 0444 root bin
f usr/share/man/man2/_lwp_cond_signal.2 0444 root bin
f usr/share/man/man2/_lwp_cond_wait.2 0444 root bin
f usr/share/man/man2/_lwp_info.2 0444 root bin
@@ -12002,33 +12014,67 @@ f usr/share/man/man2/close.2 0444 root bin
f usr/share/man/man2/creat.2 0444 root bin
f usr/share/man/man2/dup.2 0444 root bin
f usr/share/man/man2/exec.2 0444 root bin
+f usr/share/man/man2/execl.2 0444 root bin
+f usr/share/man/man2/execle.2 0444 root bin
+f usr/share/man/man2/execlp.2 0444 root bin
+f usr/share/man/man2/execv.2 0444 root bin
+f usr/share/man/man2/execve.2 0444 root bin
+f usr/share/man/man2/execvp.2 0444 root bin
f usr/share/man/man2/exit.2 0444 root bin
+f usr/share/man/man2/faccessat.2 0444 root bin
+f usr/share/man/man2/facl.2 0444 root bin
+f usr/share/man/man2/fchdir.2 0444 root bin
+f usr/share/man/man2/fchmod.2 0444 root bin
+f usr/share/man/man2/fchown.2 0444 root bin
+f usr/share/man/man2/fchownat.2 0444 root bin
+f usr/share/man/man2/fchroot.2 0444 root bin
f usr/share/man/man2/fcntl.2 0444 root bin
f usr/share/man/man2/fork.2 0444 root bin
+f usr/share/man/man2/fork1.2 0444 root bin
+f usr/share/man/man2/forkall.2 0444 root bin
+f usr/share/man/man2/forkallx.2 0444 root bin
+f usr/share/man/man2/forkx.2 0444 root bin
f usr/share/man/man2/fpathconf.2 0444 root bin
+f usr/share/man/man2/fstat.2 0444 root bin
+f usr/share/man/man2/fstatat.2 0444 root bin
+f usr/share/man/man2/fstatvfs.2 0444 root bin
+f usr/share/man/man2/futimesat.2 0444 root bin
f usr/share/man/man2/getacct.2 0444 root bin
+f usr/share/man/man2/getaudit_addr.2 0444 root bin
f usr/share/man/man2/getaudit.2 0444 root bin
f usr/share/man/man2/getauid.2 0444 root bin
f usr/share/man/man2/getcontext.2 0444 root bin
f usr/share/man/man2/getdents.2 0444 root bin
+f usr/share/man/man2/getegid.2 0444 root bin
+f usr/share/man/man2/geteuid.2 0444 root bin
+f usr/share/man/man2/getgid.2 0444 root bin
f usr/share/man/man2/getgroups.2 0444 root bin
f usr/share/man/man2/getisax.2 0444 root bin
f usr/share/man/man2/getitimer.2 0444 root bin
-f usr/share/man/man2/getlabel.2 0444 root bin
f usr/share/man/man2/getmsg.2 0444 root bin
f usr/share/man/man2/getpflags.2 0444 root bin
+f usr/share/man/man2/getpgid.2 0444 root bin
+f usr/share/man/man2/getpgrp.2 0444 root bin
f usr/share/man/man2/getpid.2 0444 root bin
+f usr/share/man/man2/getpmsg.2 0444 root bin
+f usr/share/man/man2/getppid.2 0444 root bin
f usr/share/man/man2/getppriv.2 0444 root bin
+f usr/share/man/man2/getprojid.2 0444 root bin
+f usr/share/man/man2/getrctl.2 0444 root bin
f usr/share/man/man2/getrlimit.2 0444 root bin
f usr/share/man/man2/getsid.2 0444 root bin
+f usr/share/man/man2/gettaskid.2 0444 root bin
f usr/share/man/man2/getuid.2 0444 root bin
f usr/share/man/man2/getustack.2 0444 root bin
+f usr/share/man/man2/intro.2 0444 root bin
f usr/share/man/man2/ioctl.2 0444 root bin
f usr/share/man/man2/issetugid.2 0444 root bin
f usr/share/man/man2/kill.2 0444 root bin
+f usr/share/man/man2/lchown.2 0444 root bin
f usr/share/man/man2/link.2 0444 root bin
f usr/share/man/man2/llseek.2 0444 root bin
f usr/share/man/man2/lseek.2 0444 root bin
+f usr/share/man/man2/lstat.2 0444 root bin
f usr/share/man/man2/memcntl.2 0444 root bin
f usr/share/man/man2/meminfo.2 0444 root bin
f usr/share/man/man2/mincore.2 0444 root bin
@@ -12049,40 +12095,68 @@ f usr/share/man/man2/nice.2 0444 root bin
f usr/share/man/man2/ntp_adjtime.2 0444 root bin
f usr/share/man/man2/ntp_gettime.2 0444 root bin
f usr/share/man/man2/open.2 0444 root bin
+f usr/share/man/man2/openat.2 0444 root bin
f usr/share/man/man2/p_online.2 0444 root bin
+f usr/share/man/man2/pathconf.2 0444 root bin
f usr/share/man/man2/pause.2 0444 root bin
f usr/share/man/man2/pcsample.2 0444 root bin
f usr/share/man/man2/pipe.2 0444 root bin
f usr/share/man/man2/poll.2 0444 root bin
+f usr/share/man/man2/pread.2 0444 root bin
f usr/share/man/man2/priocntl.2 0444 root bin
f usr/share/man/man2/priocntlset.2 0444 root bin
f usr/share/man/man2/processor_bind.2 0444 root bin
f usr/share/man/man2/processor_info.2 0444 root bin
f usr/share/man/man2/profil.2 0444 root bin
+f usr/share/man/man2/pset_assign.2 0444 root bin
f usr/share/man/man2/pset_bind.2 0444 root bin
f usr/share/man/man2/pset_create.2 0444 root bin
+f usr/share/man/man2/pset_destroy.2 0444 root bin
+f usr/share/man/man2/pset_getattr.2 0444 root bin
f usr/share/man/man2/pset_info.2 0444 root bin
f usr/share/man/man2/pset_list.2 0444 root bin
f usr/share/man/man2/pset_setattr.2 0444 root bin
+f usr/share/man/man2/putacct.2 0444 root bin
f usr/share/man/man2/putmsg.2 0444 root bin
+f usr/share/man/man2/putpmsg.2 0444 root bin
+f usr/share/man/man2/pwrite.2 0444 root bin
f usr/share/man/man2/read.2 0444 root bin
f usr/share/man/man2/readlink.2 0444 root bin
+f usr/share/man/man2/readv.2 0444 root bin
f usr/share/man/man2/rename.2 0444 root bin
+f usr/share/man/man2/renameat.2 0444 root bin
f usr/share/man/man2/resolvepath.2 0444 root bin
f usr/share/man/man2/rmdir.2 0444 root bin
+f usr/share/man/man2/sbrk.2 0444 root bin
f usr/share/man/man2/semctl.2 0444 root bin
f usr/share/man/man2/semget.2 0444 root bin
f usr/share/man/man2/semids.2 0444 root bin
f usr/share/man/man2/semop.2 0444 root bin
+f usr/share/man/man2/semtimedop.2 0444 root bin
+f usr/share/man/man2/setaudit_addr.2 0444 root bin
+f usr/share/man/man2/setaudit.2 0444 root bin
+f usr/share/man/man2/setauid.2 0444 root bin
+f usr/share/man/man2/setcontext.2 0444 root bin
+f usr/share/man/man2/setegid.2 0444 root bin
+f usr/share/man/man2/seteuid.2 0444 root bin
+f usr/share/man/man2/setgid.2 0444 root bin
+f usr/share/man/man2/setgroups.2 0444 root bin
+f usr/share/man/man2/setitimer.2 0444 root bin
+f usr/share/man/man2/setpflags.2 0444 root bin
f usr/share/man/man2/setpgid.2 0444 root bin
f usr/share/man/man2/setpgrp.2 0444 root bin
+f usr/share/man/man2/setppriv.2 0444 root bin
f usr/share/man/man2/setrctl.2 0444 root bin
f usr/share/man/man2/setregid.2 0444 root bin
f usr/share/man/man2/setreuid.2 0444 root bin
+f usr/share/man/man2/setrlimit.2 0444 root bin
f usr/share/man/man2/setsid.2 0444 root bin
f usr/share/man/man2/settaskid.2 0444 root bin
f usr/share/man/man2/setuid.2 0444 root bin
+f usr/share/man/man2/setustack.2 0444 root bin
+f usr/share/man/man2/shmat.2 0444 root bin
f usr/share/man/man2/shmctl.2 0444 root bin
+f usr/share/man/man2/shmdt.2 0444 root bin
f usr/share/man/man2/shmget.2 0444 root bin
f usr/share/man/man2/shmids.2 0444 root bin
f usr/share/man/man2/shmop.2 0444 root bin
@@ -12091,6 +12165,7 @@ f usr/share/man/man2/sigaltstack.2 0444 root bin
f usr/share/man/man2/sigpending.2 0444 root bin
f usr/share/man/man2/sigprocmask.2 0444 root bin
f usr/share/man/man2/sigsend.2 0444 root bin
+f usr/share/man/man2/sigsendset.2 0444 root bin
f usr/share/man/man2/sigsuspend.2 0444 root bin
f usr/share/man/man2/sigwait.2 0444 root bin
f usr/share/man/man2/stat.2 0444 root bin
@@ -12107,16 +12182,21 @@ f usr/share/man/man2/uadmin.2 0444 root bin
f usr/share/man/man2/ulimit.2 0444 root bin
f usr/share/man/man2/umask.2 0444 root bin
f usr/share/man/man2/umount.2 0444 root bin
+f usr/share/man/man2/umount2.2 0444 root bin
f usr/share/man/man2/uname.2 0444 root bin
f usr/share/man/man2/unlink.2 0444 root bin
+f usr/share/man/man2/unlinkat.2 0444 root bin
f usr/share/man/man2/ustat.2 0444 root bin
f usr/share/man/man2/utime.2 0444 root bin
f usr/share/man/man2/utimes.2 0444 root bin
f usr/share/man/man2/uucopy.2 0444 root bin
f usr/share/man/man2/vfork.2 0444 root bin
+f usr/share/man/man2/vforkx.2 0444 root bin
f usr/share/man/man2/vhangup.2 0444 root bin
f usr/share/man/man2/waitid.2 0444 root bin
+f usr/share/man/man2/wracct.2 0444 root bin
f usr/share/man/man2/write.2 0444 root bin
+f usr/share/man/man2/writev.2 0444 root bin
f usr/share/man/man2/yield.2 0444 root bin
d usr/share/man/man3 0755 root bin
f usr/share/man/man3/Intro.3 0444 root bin
@@ -15075,7 +15155,86 @@ f usr/share/man/man5/zones.5 0444 root bin
d usr/share/man/man7 0755 root bin
f usr/share/man/man7/FSS.7 0444 root bin
d usr/share/man/man7d 0755 root bin
+f usr/share/man/man7d/aac.7d 0444 root bin
+f usr/share/man/man7d/afe.7d 0444 root bin
+f usr/share/man/man7d/ahci.7d 0444 root bin
+f usr/share/man/man7d/amd8111s.7d 0444 root bin
+f usr/share/man/man7d/amr.7d 0444 root bin
+f usr/share/man/man7d/arcmsr.7d 0444 root bin
+f usr/share/man/man7d/asy.7d 0444 root bin
+f usr/share/man/man7d/ata.7d 0444 root bin
+f usr/share/man/man7d/atge.7d 0444 root bin
+f usr/share/man/man7d/bcm_sata.7d 0444 root bin
+f usr/share/man/man7d/bfe.7d 0444 root bin
+f usr/share/man/man7d/bge.7d 0444 root bin
+f usr/share/man/man7d/chxge.7d 0444 root bin
+f usr/share/man/man7d/cmdk.7d 0444 root bin
+f usr/share/man/man7d/devinfo.7d 0444 root bin
+f usr/share/man/man7d/dmfe.7d 0444 root bin
+f usr/share/man/man7d/dnet.7d 0444 root bin
+f usr/share/man/man7d/dtrace.7d 0444 root bin
+f usr/share/man/man7d/ehci.7d 0444 root bin
+f usr/share/man/man7d/fasttrap.7d 0444 root bin
+f usr/share/man/man7d/fbt.7d 0444 root bin
+f usr/share/man/man7d/heci.7d 0444 root bin
+f usr/share/man/man7d/hid.7d 0444 root bin
+f usr/share/man/man7d/hubd.7d 0444 root bin
+f usr/share/man/man7d/hwahc.7d 0444 root bin
+f usr/share/man/man7d/hwarc.7d 0444 root bin
+f usr/share/man/man7d/hxge.7d 0444 root bin
+f usr/share/man/man7d/igb.7d 0444 root bin
+f usr/share/man/man7d/ipnet.7d 0444 root bin
+f usr/share/man/man7d/iscsi.7d 0444 root bin
+f usr/share/man/man7d/ixgbe.7d 0444 root bin
f usr/share/man/man7d/kmdb.7d 0444 root bin
+f usr/share/man/man7d/ksyms.7d 0444 root bin
+f usr/share/man/man7d/llc1.7d 0444 root bin
+f usr/share/man/man7d/lockstat.7d 0444 root bin
+f usr/share/man/man7d/lofi.7d 0444 root bin
+f usr/share/man/man7d/log.7d 0444 root bin
+f usr/share/man/man7d/mega_sas.7d 0444 root bin
+f usr/share/man/man7d/mpt_sas.7d 0444 root bin
+f usr/share/man/man7d/mr_sas.7d 0444 root bin
+f usr/share/man/man7d/ntxn.7d 0444 root bin
+f usr/share/man/man7d/nulldriver.7d 0444 root bin
+f usr/share/man/man7d/nv_sata.7d 0444 root bin
+f usr/share/man/man7d/nxge.7d 0444 root bin
+f usr/share/man/man7d/ohci.7d 0444 root bin
+f usr/share/man/man7d/pcata.7d 0444 root bin
+f usr/share/man/man7d/physmem.7d 0444 root bin
+f usr/share/man/man7d/pm.7d 0444 root bin
+f usr/share/man/man7d/poll.7d 0444 root bin
+f usr/share/man/man7d/profile.7d 0444 root bin
+f usr/share/man/man7d/ptm.7d 0444 root bin
+f usr/share/man/man7d/pts.7d 0444 root bin
+f usr/share/man/man7d/qlc.7d 0444 root bin
+f usr/share/man/man7d/ramdisk.7d 0444 root bin
+f usr/share/man/man7d/random.7d 0444 root bin
+f usr/share/man/man7d/rge.7d 0444 root bin
+f usr/share/man/man7d/sad.7d 0444 root bin
+f usr/share/man/man7d/scsa2usb.7d 0444 root bin
+f usr/share/man/man7d/sd.7d 0444 root bin
+f usr/share/man/man7d/sdt.7d 0444 root bin
+f usr/share/man/man7d/ses.7d 0444 root bin
+f usr/share/man/man7d/sfe.7d 0444 root bin
+f usr/share/man/man7d/sgen.7d 0444 root bin
+f usr/share/man/man7d/si3124.7d 0444 root bin
+f usr/share/man/man7d/smbios.7d 0444 root bin
+f usr/share/man/man7d/st.7d 0444 root bin
+f usr/share/man/man7d/sysmsg.7d 0444 root bin
+f usr/share/man/man7d/systrace.7d 0444 root bin
+f usr/share/man/man7d/tzmon.7d 0444 root bin
+f usr/share/man/man7d/ugen.7d 0444 root bin
+f usr/share/man/man7d/uhci.7d 0444 root bin
+f usr/share/man/man7d/usb_mid.7d 0444 root bin
+f usr/share/man/man7d/usbftdi.7d 0444 root bin
+f usr/share/man/man7d/usbsacm.7d 0444 root bin
+f usr/share/man/man7d/usbsksp.7d 0444 root bin
+f usr/share/man/man7d/usbsprl.7d 0444 root bin
+f usr/share/man/man7d/vr.7d 0444 root bin
+f usr/share/man/man7d/xge.7d 0444 root bin
+f usr/share/man/man7d/yge.7d 0444 root bin
+f usr/share/man/man7d/zcons.7d 0444 root bin
d usr/share/man/man7fs 0755 root bin
f usr/share/man/man7fs/ctfs.7fs 0444 root bin
f usr/share/man/man7fs/dcfs.7fs 0444 root bin
diff --git a/usr/src/cmd/beadm/beadm.c b/usr/src/cmd/beadm/beadm.c
index 7918e00b55..5be10c10d7 100644
--- a/usr/src/cmd/beadm/beadm.c
+++ b/usr/src/cmd/beadm/beadm.c
@@ -1046,6 +1046,11 @@ be_do_destroy(int argc, char **argv)
(void) fprintf(stderr, _("You have insufficient privileges to "
"execute this command.\n"));
break;
+ case BE_ERR_SS_EXISTS:
+ (void) fprintf(stderr, _("Unable to destroy %s: "
+ "BE has snapshots.\nUse 'beadm destroy -s %s' or "
+ "'zfs -r destroy <dataset>'.\n"), be_name, be_name);
+ break;
default:
(void) fprintf(stderr, _("Unable to destroy %s.\n"), be_name);
(void) fprintf(stderr, "%s\n", be_err_to_str(err));
diff --git a/usr/src/cmd/dis/dis_target.c b/usr/src/cmd/dis/dis_target.c
index c509157335..e47d77fe8d 100644
--- a/usr/src/cmd/dis/dis_target.c
+++ b/usr/src/cmd/dis/dis_target.c
@@ -309,6 +309,47 @@ construct_symtab(dis_tgt_t *tgt)
sym->se_shndx = sym->se_sym.st_shndx;
}
+ /* Deal with symbols with special section indicies */
+ if (sym->se_shndx == SHN_ABS) {
+ /*
+ * If st_value == 0, references to these
+ * symbols in code are modified in situ
+ * thus we will never attempt to look
+ * them up.
+ */
+ if (sym->se_sym.st_value == 0) {
+ /*
+ * References to these symbols in code
+ * are modified in situ by the runtime
+ * linker and no code on disk will ever
+ * attempt to look them up.
+ */
+ nsym++;
+ continue;
+ } else {
+ /*
+ * If st_value != 0, (such as examining
+ * something in /system/object/.../object)
+ * the values should resolve to a value
+ * within an existing section (such as
+ * .data). This also means it never needs
+ * to have st_value mapped.
+ */
+ sym++;
+ continue;
+ }
+ }
+
+ /*
+ * Ignore the symbol if it has some other special
+ * section index
+ */
+ if (sym->se_shndx == SHN_UNDEF ||
+ sym->se_shndx >= SHN_LORESERVE) {
+ nsym++;
+ continue;
+ }
+
if ((sym->se_name = elf_strptr(tgt->dt_elf, shdr.sh_link,
(size_t)sym->se_sym.st_name)) == NULL) {
warn("%s: failed to lookup symbol %d name",
@@ -466,13 +507,12 @@ dis_tgt_create(const char *file)
idx = 0;
dis_tgt_section_iter(current, tgt_scn_init, &idx);
+ current->dt_filename = file;
create_addrmap(current);
if (current->dt_symidx != 0)
construct_symtab(current);
- current->dt_filename = file;
-
cmd = elf_next(elf);
}
@@ -669,8 +709,10 @@ dis_tgt_lookup(dis_tgt_t *tgt, uint64_t addr, off_t *offset, int cache_result,
return (sym->se_name);
}
+#if !defined(__sparc)
/*
* Given an address, return the starting offset of the next symbol in the file.
+ * Only needed on variable length instruction architectures.
*/
off_t
dis_tgt_next_symbol(dis_tgt_t *tgt, uint64_t addr)
@@ -686,6 +728,7 @@ dis_tgt_next_symbol(dis_tgt_t *tgt, uint64_t addr)
return (0);
}
+#endif
/*
* Iterate over all sections in the target, executing the given callback for
diff --git a/usr/src/cmd/dis/dis_target.h b/usr/src/cmd/dis/dis_target.h
index fa6c14c378..c6d13ab8dc 100644
--- a/usr/src/cmd/dis/dis_target.h
+++ b/usr/src/cmd/dis/dis_target.h
@@ -54,7 +54,9 @@ const char *dis_find_section(dis_tgt_t *, uint64_t, off_t *);
const char *dis_tgt_name(dis_tgt_t *);
const char *dis_tgt_member(dis_tgt_t *);
void dis_tgt_ehdr(dis_tgt_t *, GElf_Ehdr *);
+#if !defined(__sparc)
off_t dis_tgt_next_symbol(dis_tgt_t *, uint64_t);
+#endif
dis_tgt_t *dis_tgt_next(dis_tgt_t *);
/*
diff --git a/usr/src/cmd/dlmgmtd/dlmgmt_door.c b/usr/src/cmd/dlmgmtd/dlmgmt_door.c
index 29d265cfdb..ef5fa0e745 100644
--- a/usr/src/cmd/dlmgmtd/dlmgmt_door.c
+++ b/usr/src/cmd/dlmgmtd/dlmgmt_door.c
@@ -1329,6 +1329,10 @@ dlmgmt_zonehalt(void *argp, void *retp, size_t *sz, zoneid_t zoneid,
int err = 0;
dlmgmt_door_zonehalt_t *zonehalt = argp;
dlmgmt_zonehalt_retval_t *retvalp = retp;
+ static char my_pid[10];
+
+ if (my_pid[0] == NULL)
+ (void) snprintf(my_pid, sizeof (my_pid), "%d\n", getpid());
if ((err = dlmgmt_checkprivs(0, cred)) == 0) {
if (zoneid != GLOBAL_ZONEID) {
@@ -1353,6 +1357,7 @@ dlmgmt_zonehalt(void *argp, void *retp, size_t *sz, zoneid_t zoneid,
while ((fd = open(ZONE_LOCK, O_WRONLY |
O_CREAT | O_EXCL, S_IRUSR | S_IWUSR)) < 0)
(void) sleep(1);
+ (void) write(fd, my_pid, sizeof(my_pid));
(void) close(fd);
dlmgmt_table_lock(B_TRUE);
diff --git a/usr/src/cmd/dtrace/test/tst/common/print/err.D_PRINT_DYN.bad.d b/usr/src/cmd/dtrace/test/tst/common/print/err.D_PRINT_DYN.bad.d
new file mode 100644
index 0000000000..892b445613
--- /dev/null
+++ b/usr/src/cmd/dtrace/test/tst/common/print/err.D_PRINT_DYN.bad.d
@@ -0,0 +1,29 @@
+/*
+ * 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/usr/src/cmd/dtrace/test/tst/common/print/err.D_PRINT_VOID.bad.d b/usr/src/cmd/dtrace/test/tst/common/print/err.D_PRINT_VOID.bad.d
new file mode 100644
index 0000000000..902f07272d
--- /dev/null
+++ b/usr/src/cmd/dtrace/test/tst/common/print/err.D_PRINT_VOID.bad.d
@@ -0,0 +1,29 @@
+/*
+ * 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((void)`p0);
+}
diff --git a/usr/src/cmd/dtrace/test/tst/common/print/err.D_PROTO_LEN.bad.d b/usr/src/cmd/dtrace/test/tst/common/print/err.D_PROTO_LEN.bad.d
new file mode 100644
index 0000000000..a1d3be1f62
--- /dev/null
+++ b/usr/src/cmd/dtrace/test/tst/common/print/err.D_PROTO_LEN.bad.d
@@ -0,0 +1,29 @@
+/*
+ * 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();
+}
diff --git a/usr/src/cmd/dtrace/test/tst/common/print/tst.array.d b/usr/src/cmd/dtrace/test/tst/common/print/tst.array.d
new file mode 100644
index 0000000000..9650bf7c0f
--- /dev/null
+++ b/usr/src/cmd/dtrace/test/tst/common/print/tst.array.d
@@ -0,0 +1,62 @@
+/*
+ * CDDL HEADER START
+ *
+ * The contents of this file are subject to the terms of the
+ * Common Development and Distribution License (the "License").
+ * You may not use this file except in compliance with the License.
+ *
+ * You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE
+ * or http://www.opensolaris.org/os/licensing.
+ * See the License for the specific language governing permissions
+ * and limitations under the License.
+ *
+ * When distributing Covered Code, include this CDDL HEADER in each
+ * file and include the License file at usr/src/OPENSOLARIS.LICENSE.
+ * If applicable, add the following below this CDDL HEADER, with the
+ * fields enclosed by brackets "[]" replaced with your own identifying
+ * information: Portions Copyright [yyyy] [name of copyright owner]
+ *
+ * CDDL HEADER END
+ */
+
+/*
+ * Copyright (c) 2011 by Delphix. All rights reserved.
+ */
+
+#pragma D option quiet
+
+typedef struct bar {
+ int alpha;
+} bar_t;
+
+typedef struct foo {
+ int a[3];
+ char b[30];
+ bar_t c[2];
+ char d[3];
+} foo_t;
+
+BEGIN
+{
+ this->f = (foo_t *)alloca(sizeof (foo_t));
+
+ this->f->a[0] = 1;
+ this->f->a[1] = 2;
+ this->f->a[2] = 3;
+ this->f->b[0] = 'a';
+ this->f->b[1] = 'b';
+ this->f->b[2] = 0;
+ this->f->c[0].alpha = 5;
+ this->f->c[1].alpha = 6;
+ this->f->c[2].alpha = 7;
+ this->f->d[0] = 4;
+ this->f->d[1] = 0;
+ this->f->d[2] = 0;
+
+ print(this->f->a);
+ print(this->f->b);
+ print(this->f->c);
+ print(*this->f);
+
+ exit(0);
+}
diff --git a/usr/src/cmd/dtrace/test/tst/common/print/tst.array.d.out b/usr/src/cmd/dtrace/test/tst/common/print/tst.array.d.out
new file mode 100644
index 0000000000..0702d4bb5a
--- /dev/null
+++ b/usr/src/cmd/dtrace/test/tst/common/print/tst.array.d.out
@@ -0,0 +1,23 @@
+int [3] [ 0x1, 0x2, 0x3 ]
+char [30] "ab"
+bar_t [2] [
+ bar_t {
+ int alpha = 0x5
+ },
+ bar_t {
+ int alpha = 0x6
+ }
+]
+foo_t {
+ int [3] a = [ 0x1, 0x2, 0x3 ]
+ char [30] b = [ "ab" ]
+ bar_t [2] c = [
+ bar_t {
+ int alpha = 0x5
+ },
+ bar_t {
+ int alpha = 0x6
+ }
+ ]
+ char [3] d = [ '\004', '\0', '\0' ]
+}
diff --git a/usr/src/cmd/dtrace/test/tst/common/print/tst.bitfield.d b/usr/src/cmd/dtrace/test/tst/common/print/tst.bitfield.d
new file mode 100644
index 0000000000..ff77bb0ec7
--- /dev/null
+++ b/usr/src/cmd/dtrace/test/tst/common/print/tst.bitfield.d
@@ -0,0 +1,49 @@
+/*
+ * 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.
+ */
+
+#pragma D option quiet
+
+typedef struct forward forward_t;
+
+typedef struct foo {
+ int a:4;
+ int b:7;
+ int c:1;
+ int d:2;
+} foo_t;
+
+BEGIN
+{
+ this->s = (foo_t *)alloca(sizeof (foo_t));
+
+ this->s->a = 1;
+ this->s->b = 5;
+ this->s->c = 0;
+ this->s->d = 2;
+
+ print(*this->s);
+
+ exit(0);
+}
diff --git a/usr/src/cmd/dtrace/test/tst/common/print/tst.bitfield.d.out b/usr/src/cmd/dtrace/test/tst/common/print/tst.bitfield.d.out
new file mode 100644
index 0000000000..309444d5c8
--- /dev/null
+++ b/usr/src/cmd/dtrace/test/tst/common/print/tst.bitfield.d.out
@@ -0,0 +1,6 @@
+foo_t {
+ int a :4 = 0x1
+ int b :7 = 0x5
+ int c :1 = 0
+ int d :2 = 0x2
+}
diff --git a/usr/src/cmd/dtrace/test/tst/common/print/tst.primitive.d b/usr/src/cmd/dtrace/test/tst/common/print/tst.primitive.d
new file mode 100644
index 0000000000..559dab1840
--- /dev/null
+++ b/usr/src/cmd/dtrace/test/tst/common/print/tst.primitive.d
@@ -0,0 +1,45 @@
+/*
+ * 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.
+ */
+
+#pragma D option quiet
+
+BEGIN
+{
+ i = (int)'a';
+
+ printf("\n");
+
+ print((char)'a');
+ print((int)-1);
+ print((unsigned int)23);
+ print((short)456);
+ print((unsigned short)789);
+ print((long)1234);
+ print((ulong_t)56789);
+ print((void *)0x1234);
+ print("hello");
+
+ exit(0);
+}
diff --git a/usr/src/cmd/dtrace/test/tst/common/print/tst.primitive.d.out b/usr/src/cmd/dtrace/test/tst/common/print/tst.primitive.d.out
new file mode 100644
index 0000000000..f7e4076726
--- /dev/null
+++ b/usr/src/cmd/dtrace/test/tst/common/print/tst.primitive.d.out
@@ -0,0 +1,11 @@
+
+char 'a'
+int 0xffffffff
+unsigned int 0x17
+short 0x1c8
+unsigned short 0x315
+long 0x4d2
+ulong_t 0xddd5
+void * 0x1234
+string "hello"
+
diff --git a/usr/src/cmd/dtrace/test/tst/common/print/tst.struct.d b/usr/src/cmd/dtrace/test/tst/common/print/tst.struct.d
new file mode 100644
index 0000000000..2fb1c41401
--- /dev/null
+++ b/usr/src/cmd/dtrace/test/tst/common/print/tst.struct.d
@@ -0,0 +1,59 @@
+/*
+ * 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.
+ */
+
+#pragma D option quiet
+
+typedef struct forward forward_t;
+
+typedef struct foo {
+ int a;
+ void *b;
+ struct {
+ uint64_t alpha;
+ uint64_t beta;
+ } c;
+ ushort_t d;
+ int e;
+ forward_t *f;
+ void (*g)();
+} foo_t;
+
+BEGIN
+{
+ this->s = (foo_t *)alloca(sizeof (foo_t));
+
+ this->s->a = 1;
+ this->s->b = (void *)2;
+ this->s->c.alpha = 3;
+ this->s->c.beta = 4;
+ this->s->d = 5;
+ this->s->e = 6;
+ this->s->f = (void *)7;
+ this->s->g = (void *)8;
+
+ print(*this->s);
+
+ exit(0);
+}
diff --git a/usr/src/cmd/dtrace/test/tst/common/print/tst.struct.d.out b/usr/src/cmd/dtrace/test/tst/common/print/tst.struct.d.out
new file mode 100644
index 0000000000..b7b2108375
--- /dev/null
+++ b/usr/src/cmd/dtrace/test/tst/common/print/tst.struct.d.out
@@ -0,0 +1,12 @@
+foo_t {
+ int a = 0x1
+ void *b = 0x2
+ struct c = {
+ uint64_t alpha = 0x3
+ uint64_t beta = 0x4
+ }
+ ushort_t d = 0x5
+ int e = 0x6
+ forward_t *f = 0x7
+ int (*)() g = 0x8
+}
diff --git a/usr/src/cmd/dtrace/test/tst/common/trace/err.D_TRACE_DYN.bad.d b/usr/src/cmd/dtrace/test/tst/common/trace/err.D_TRACE_DYN.bad.d
new file mode 100644
index 0000000000..8436df6735
--- /dev/null
+++ b/usr/src/cmd/dtrace/test/tst/common/trace/err.D_TRACE_DYN.bad.d
@@ -0,0 +1,29 @@
+/*
+ * 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/usr/src/cmd/fs.d/nfs/mountd/mountd.c b/usr/src/cmd/fs.d/nfs/mountd/mountd.c
index 8c8f9b5875..dbf4c11ea1 100644
--- a/usr/src/cmd/fs.d/nfs/mountd/mountd.c
+++ b/usr/src/cmd/fs.d/nfs/mountd/mountd.c
@@ -17,10 +17,9 @@
* information: Portions Copyright [yyyy] [name of copyright owner]
*
* CDDL HEADER END
- */
-
-/*
+ *
* Copyright (c) 1989, 2010, Oracle and/or its affiliates. All rights reserved.
+ * Copyright 2011 Nexenta Systems, Inc. All rights reserved.
*/
/* Copyright (c) 1983, 1984, 1985, 1986, 1987, 1988, 1989 AT&T */
@@ -112,7 +111,6 @@ static int mount(struct svc_req *r);
static void sh_free(struct sh_list *);
static void umount(struct svc_req *);
static void umountall(struct svc_req *);
-static int netmatch(struct netbuf *, char *);
static void sigexit(int);
static int newopts(char *);
static tsol_tpent_t *get_client_template(struct sockaddr *);
@@ -1711,10 +1709,10 @@ done:
* We match on aliases of the hostname as well as on the canonical name.
* Names in the access list may be either hosts or netgroups; they're
* not distinguished syntactically. We check for hosts first because
- * it's cheaper (just M*N strcmp()s), then try netgroups.
+ * it's cheaper, then try netgroups.
*
* If pnb and pclnames are NULL, it means that we have to use transp
- * to resolve client's IP address to host name. If they aren't NULL
+ * to resolve client IP address to hostname. If they aren't NULL
* then transp argument won't be used and can be NULL.
*/
int
@@ -1722,84 +1720,112 @@ in_access_list(SVCXPRT *transp, struct netbuf **pnb,
struct nd_hostservlist **pclnames,
char *access_list) /* N.B. we clobber this "input" parameter */
{
- int nentries;
- char *gr;
- char *lasts;
+ char addr[INET_ADDRSTRLEN];
+ char buff[256];
+ int nentries = 0;
+ char *cstr = access_list;
+ char *gr = access_list;
char *host;
int off;
int i;
- int netgroup_match;
int response;
+ int sbr = 0;
struct nd_hostservlist *clnames;
+ struct netent n, *np;
- /*
- * If no access list - then it's unrestricted
- */
+ /* If no access list - then it's unrestricted */
if (access_list == NULL || *access_list == '\0')
return (1);
assert(transp != NULL || (*pnb != NULL && *pclnames != NULL));
- nentries = 0;
+ /* Get client address if it wasn't provided */
+ if (*pnb == NULL)
+ /* Don't grant access if client address isn't known */
+ if ((*pnb = svc_getrpccaller(transp)) == NULL)
+ return (0);
- for (gr = strtok_r(access_list, ":", &lasts);
- gr != NULL; gr = strtok_r(NULL, ":", &lasts)) {
+ /* Try to lookup client hostname if it wasn't provided */
+ if (*pclnames == NULL)
+ getclientsnames(transp, pnb, pclnames);
+ clnames = *pclnames;
+
+ for (;;) {
+ if ((cstr = strpbrk(cstr, "[]:")) != NULL) {
+ switch (*cstr) {
+ case '[':
+ case ']':
+ sbr = !sbr;
+ cstr++;
+ continue;
+ case ':':
+ if (sbr) {
+ cstr++;
+ continue;
+ }
+ *cstr = '\0';
+ }
+ }
/*
- * If the list name has a '-' prepended
- * then a match of the following name
- * implies failure instead of success.
+ * If the list name has a '-' prepended then a match of
+ * the following name implies failure instead of success.
*/
if (*gr == '-') {
response = 0;
gr++;
- } else
+ } else {
response = 1;
+ }
/*
- * If the list name begins with an at
- * sign then do a network comparison.
+ * First check if we have '@' entry, as it doesn't
+ * require client hostname.
*/
if (*gr == '@') {
- /*
- * Just get the netbuf, avoiding the costly name
- * lookup. This will suffice for access based
- * solely on addresses.
- */
- if (*pnb == NULL) {
- /*
- * Don't grant access if client's address isn't
- * known.
- */
- if ((*pnb = svc_getrpccaller(transp)) == NULL)
- return (0);
+ gr++;
+
+ /* Netname support */
+ if (!isdigit(*gr) && *gr != '[') {
+ if ((np = getnetbyname_r(gr, &n, buff,
+ sizeof (buff))) != NULL &&
+ np->n_net != 0) {
+ while ((np->n_net & 0xFF000000u) == 0)
+ np->n_net <<= 8;
+ np->n_net = htonl(np->n_net);
+ if (inet_ntop(AF_INET, &np->n_net, addr,
+ INET_ADDRSTRLEN) == NULL)
+ break;
+ if (inet_matchaddr((*pnb)->buf, addr))
+ return (response);
+ }
+ } else {
+ if (inet_matchaddr((*pnb)->buf, gr))
+ return (response);
}
- if (netmatch(*pnb, gr + 1))
- return (response);
+ if (cstr == NULL)
+ break;
+
+ gr = ++cstr;
+
continue;
}
/*
- * We need to get the host name if we haven't gotten
- * it by now!
+ * No other checks can be performed if client address
+ * can't be resolved.
*/
- if (*pclnames == NULL) {
- DTRACE_PROBE(mountd, name_by_addrlist);
- /*
- * Do not grant access if we can't
- * get a name!
- */
- if (getclientsnames(transp, pnb, pclnames) != 0)
- return (0);
- }
+ if (clnames == NULL) {
+ if (cstr == NULL)
+ break;
- clnames = *pclnames;
+ gr = ++cstr;
- /*
- * The following loops through all the
- * client's aliases. Usually it's just one name.
- */
+ continue;
+ }
+
+ /* Otherwise loop through all client hostname aliases */
for (i = 0; i < clnames->h_cnt; i++) {
host = clnames->h_hostservs[i].h_host;
@@ -1820,120 +1846,25 @@ in_access_list(SVCXPRT *transp, struct netbuf **pnb,
return (response);
}
}
- } else
-
- /*
- * Just do a hostname match
- */
- if (strcasecmp(gr, host) == 0) {
- return (response); /* Matched a hostname */
+ } else {
+ /* Just do a hostname match */
+ if (strcasecmp(gr, host) == 0)
+ return (response);
}
}
nentries++;
- }
-
- /*
- * We need to get the host name if we haven't gotten
- * it by now!
- */
- if (*pclnames == NULL) {
- DTRACE_PROBE(mountd, name_by_netgroup);
- /*
- * Do not grant access if we can't
- * get a name!
- */
- if (getclientsnames(transp, pnb, pclnames) != 0)
- return (0);
- }
-
- netgroup_match = netgroup_check(*pclnames, access_list, nentries);
-
- return (netgroup_match);
-}
-
-int
-netmatch(struct netbuf *nb, char *name)
-{
- uint_t claddr;
- struct netent n, *np;
- char *mp, *p;
- uint_t addr, mask;
- int i, bits;
- char buff[256];
-
- /*
- * Check if it's an IPv4 addr
- */
- if (nb->len != sizeof (struct sockaddr_in))
- return (0);
- (void) memcpy(&claddr,
- /* LINTED pointer alignment */
- &((struct sockaddr_in *)nb->buf)->sin_addr.s_addr,
- sizeof (struct in_addr));
- claddr = ntohl(claddr);
-
- mp = strchr(name, '/');
- if (mp)
- *mp++ = '\0';
+ if (cstr == NULL)
+ break;
- if (isdigit(*name)) {
- /*
- * Convert a dotted IP address
- * to an IP address. The conversion
- * is not the same as that in inet_addr().
- */
- p = name;
- addr = 0;
- for (i = 0; i < 4; i++) {
- addr |= atoi(p) << ((3-i) * 8);
- p = strchr(p, '.');
- if (p == NULL)
- break;
- p++;
- }
- } else {
- /*
- * Turn the netname into
- * an IP address.
- */
- np = getnetbyname_r(name, &n, buff, sizeof (buff));
- if (np == NULL) {
- syslog(LOG_DEBUG, "getnetbyname_r: %s: %m", name);
- return (0);
- }
- addr = np->n_net;
+ gr = ++cstr;
}
- /*
- * If the mask is specified explicitly then
- * use that value, e.g.
- *
- * @109.104.56/28
- *
- * otherwise assume a mask from the zero octets
- * in the least significant bits of the address, e.g.
- *
- * @109.104 or @109.104.0.0
- */
- if (mp) {
- bits = atoi(mp);
- mask = bits ? ~0 << ((sizeof (struct in_addr) * NBBY) - bits)
- : 0;
- addr &= mask;
- } else {
- if ((addr & IN_CLASSA_HOST) == 0)
- mask = IN_CLASSA_NET;
- else if ((addr & IN_CLASSB_HOST) == 0)
- mask = IN_CLASSB_NET;
- else if ((addr & IN_CLASSC_HOST) == 0)
- mask = IN_CLASSC_NET;
- else
- mask = IN_CLASSE_NET;
- }
+ if (clnames == NULL)
+ return (0);
- return ((claddr & mask) == addr);
+ return (netgroup_check(clnames, access_list, nentries));
}
diff --git a/usr/src/cmd/mdb/common/mdb/mdb_modapi.c b/usr/src/cmd/mdb/common/mdb/mdb_modapi.c
index 509ffeb6ac..59c34022c7 100644
--- a/usr/src/cmd/mdb/common/mdb/mdb_modapi.c
+++ b/usr/src/cmd/mdb/common/mdb/mdb_modapi.c
@@ -793,6 +793,55 @@ mdb_object_iter(mdb_object_cb_t cb, void *data)
}
/*
+ * Private callback structure for implementing mdb_symbol_iter, below.
+ */
+typedef struct {
+ mdb_symbol_cb_t si_cb;
+ void *si_arg;
+ int si_rval;
+} symbol_iter_arg_t;
+
+/*ARGSUSED*/
+static int
+mdb_symbol_cb(void *data, const GElf_Sym *gsym, const char *name,
+ const mdb_syminfo_t *sip, const char *obj)
+{
+ symbol_iter_arg_t *arg = data;
+ mdb_symbol_t sym;
+
+ if (arg->si_rval != 0)
+ return (0);
+
+ bzero(&sym, sizeof (sym));
+ sym.sym_name = name;
+ sym.sym_object = obj;
+ sym.sym_sym = gsym;
+ sym.sym_table = sip->sym_table;
+ sym.sym_id = sip->sym_id;
+
+ arg->si_rval = arg->si_cb(&sym, arg->si_arg);
+
+ return (0);
+}
+
+int
+mdb_symbol_iter(const char *obj, uint_t which, uint_t type,
+ mdb_symbol_cb_t cb, void *data)
+{
+ symbol_iter_arg_t arg;
+
+ arg.si_cb = cb;
+ arg.si_arg = data;
+ arg.si_rval = 0;
+
+ if (mdb_tgt_symbol_iter(mdb.m_target, obj, which, type,
+ mdb_symbol_cb, &arg) != 0)
+ return (-1);
+
+ return (arg.si_rval);
+}
+
+/*
* Private structure and function for implementing mdb_dumpptr on top
* of mdb_dump_internal
*/
diff --git a/usr/src/cmd/mdb/common/mdb/mdb_modapi.h b/usr/src/cmd/mdb/common/mdb/mdb_modapi.h
index aa7e8409b6..37f96e4640 100644
--- a/usr/src/cmd/mdb/common/mdb/mdb_modapi.h
+++ b/usr/src/cmd/mdb/common/mdb/mdb_modapi.h
@@ -169,6 +169,14 @@ typedef struct mdb_object {
uintptr_t obj_size; /* in memory size of object in bytes */
} mdb_object_t;
+typedef struct mdb_symbol {
+ const char *sym_name; /* name of symbol */
+ const char *sym_object; /* name of containing object */
+ const GElf_Sym *sym_sym; /* ELF symbol information */
+ uint_t sym_table; /* symbol table id */
+ uint_t sym_id; /* symbol identifier */
+} mdb_symbol_t;
+
extern int mdb_pwalk(const char *, mdb_walk_cb_t, void *, uintptr_t);
extern int mdb_walk(const char *, mdb_walk_cb_t, void *);
@@ -285,6 +293,28 @@ extern ssize_t mdb_get_xdata(const char *, void *, size_t);
typedef int (*mdb_object_cb_t)(mdb_object_t *, void *);
extern int mdb_object_iter(mdb_object_cb_t, void *);
+#define MDB_SYMTAB 1 /* Normal symbol table (.symtab) */
+#define MDB_DYNSYM 2 /* Dynamic symbol table (.dynsym) */
+
+#define MDB_BIND_LOCAL 0x0001 /* Local (static-scope) symbols */
+#define MDB_BIND_GLOBAL 0x0002 /* Global symbols */
+#define MDB_BIND_WEAK 0x0004 /* Weak binding symbols */
+#define MDB_BIND_ANY 0x0007 /* Any of the above */
+
+#define MDB_TYPE_NOTYPE 0x0100 /* Symbol has no type */
+#define MDB_TYPE_OBJECT 0x0200 /* Symbol refers to data */
+#define MDB_TYPE_FUNC 0x0400 /* Symbol refers to text */
+#define MDB_TYPE_SECT 0x0800 /* Symbol refers to a section */
+#define MDB_TYPE_FILE 0x1000 /* Symbol refers to a source file */
+#define MDB_TYPE_COMMON 0x2000 /* Symbol refers to a common block */
+#define MDB_TYPE_TLS 0x4000 /* Symbol refers to TLS */
+
+#define MDB_TYPE_ANY 0x7f00 /* Any of the above */
+
+typedef int (*mdb_symbol_cb_t)(mdb_symbol_t *, void *);
+extern int mdb_symbol_iter(const char *, uint_t, uint_t, mdb_symbol_cb_t,
+ void *);
+
#define MDB_STATE_IDLE 0 /* Target is idle (not running yet) */
#define MDB_STATE_RUNNING 1 /* Target is currently executing */
#define MDB_STATE_STOPPED 2 /* Target is stopped */
diff --git a/usr/src/cmd/mdb/common/modules/conf/mapfile-extern b/usr/src/cmd/mdb/common/modules/conf/mapfile-extern
index ff6292e606..8dc39bb019 100644
--- a/usr/src/cmd/mdb/common/modules/conf/mapfile-extern
+++ b/usr/src/cmd/mdb/common/modules/conf/mapfile-extern
@@ -143,6 +143,7 @@ SYMBOL_SCOPE {
mdb_set_pipe { FLAGS = EXTERN };
mdb_snprintf { FLAGS = EXTERN };
mdb_strtoull { FLAGS = EXTERN };
+ mdb_symbol_iter { FLAGS = EXTERN };
mdb_tgt_notsup { FLAGS = EXTERN };
mdb_vnode2path { FLAGS = EXTERN };
mdb_vread { FLAGS = EXTERN };
diff --git a/usr/src/cmd/mdb/common/modules/genunix/kgrep.c b/usr/src/cmd/mdb/common/modules/genunix/kgrep.c
index c0eab1aec1..7052827562 100644
--- a/usr/src/cmd/mdb/common/modules/genunix/kgrep.c
+++ b/usr/src/cmd/mdb/common/modules/genunix/kgrep.c
@@ -23,7 +23,9 @@
* Use is subject to license terms.
*/
-#pragma ident "%Z%%M% %I% %E% SMI"
+/*
+ * Copyright 2011 Joyent, Inc. All rights reserved.
+ */
/*
* Generic memory walker, used by both the genunix and libumem dmods.
@@ -154,8 +156,14 @@ kgrep_range_fancybits(uintptr_t base, uintptr_t lim, void *kg_arg) \
for (pos = page; pos < page_end; pos++) { \
cur = *pos; \
\
+ /* \
+ * Due to C's (surprising) integral promotion \
+ * rules for unsigned types smaller than an \
+ * int, we need to explicitly cast the result \
+ * of cur minus pattern, below. \
+ */ \
if (((cur ^ pattern) & mask) != 0 && \
- (cur - pattern) >= dist) \
+ (uintbits_t)(cur - pattern) >= dist) \
continue; \
\
out = cur; \
diff --git a/usr/src/cmd/mdb/common/modules/genunix/kmem.c b/usr/src/cmd/mdb/common/modules/genunix/kmem.c
index 1dcac5344f..909b7ecc7b 100644
--- a/usr/src/cmd/mdb/common/modules/genunix/kmem.c
+++ b/usr/src/cmd/mdb/common/modules/genunix/kmem.c
@@ -23,6 +23,10 @@
* Use is subject to license terms.
*/
+/*
+ * Copyright 2011 Joyent, Inc. All rights reserved.
+ */
+
#include <mdb/mdb_param.h>
#include <mdb/mdb_modapi.h>
#include <mdb/mdb_ctf.h>
@@ -1121,7 +1125,7 @@ bufctl_walk_callback(kmem_cache_t *cp, mdb_walk_state_t *wsp, uintptr_t buf)
typedef struct kmem_walk {
int kmw_type;
- int kmw_addr; /* cache address */
+ uintptr_t kmw_addr; /* cache address */
kmem_cache_t *kmw_cp;
size_t kmw_csize;
@@ -1488,15 +1492,24 @@ kmem_walk_step(mdb_walk_state_t *wsp)
buf = bc.bc_addr;
} else {
/*
- * Otherwise the buffer is in the slab which
- * we've read in; we just need to determine
- * its offset in the slab to find the
- * kmem_bufctl_t.
+ * Otherwise the buffer is (or should be) in the slab
+ * that we've read in; determine its offset in the
+ * slab, validate that it's not corrupt, and add to
+ * our base address to find the umem_bufctl_t. (Note
+ * that we don't need to add the size of the bufctl
+ * to our offset calculation because of the slop that's
+ * allocated for the buffer at ubase.)
*/
- bc = *((kmem_bufctl_t *)
- ((uintptr_t)bcp - (uintptr_t)kbase +
- (uintptr_t)ubase));
+ uintptr_t offs = (uintptr_t)bcp - (uintptr_t)kbase;
+
+ if (offs > chunks * chunksize) {
+ mdb_warn("found corrupt bufctl ptr %p"
+ " in slab %p in cache %p\n", bcp,
+ wsp->walk_addr, addr);
+ break;
+ }
+ bc = *((kmem_bufctl_t *)((uintptr_t)ubase + offs));
buf = KMEM_BUF(cp, bcp);
}
diff --git a/usr/src/cmd/mdb/common/modules/libumem/umem.c b/usr/src/cmd/mdb/common/modules/libumem/umem.c
index fc2126de05..0bd52baf1e 100644
--- a/usr/src/cmd/mdb/common/modules/libumem/umem.c
+++ b/usr/src/cmd/mdb/common/modules/libumem/umem.c
@@ -23,6 +23,10 @@
* Use is subject to license terms.
*/
+/*
+ * Copyright 2011 Joyent, Inc. All rights reserved.
+ */
+
#include "umem.h"
#include <sys/vmem_impl_user.h>
@@ -920,7 +924,7 @@ bufctl_walk_callback(umem_cache_t *cp, mdb_walk_state_t *wsp, uintptr_t buf)
typedef struct umem_walk {
int umw_type;
- int umw_addr; /* cache address */
+ uintptr_t umw_addr; /* cache address */
umem_cache_t *umw_cp;
size_t umw_csize;
@@ -1266,15 +1270,24 @@ umem_walk_step(mdb_walk_state_t *wsp)
buf = bc.bc_addr;
} else {
/*
- * Otherwise the buffer is in the slab which
- * we've read in; we just need to determine
- * its offset in the slab to find the
- * umem_bufctl_t.
+ * Otherwise the buffer is (or should be) in the slab
+ * that we've read in; determine its offset in the
+ * slab, validate that it's not corrupt, and add to
+ * our base address to find the umem_bufctl_t. (Note
+ * that we don't need to add the size of the bufctl
+ * to our offset calculation because of the slop that's
+ * allocated for the buffer at ubase.)
*/
- bc = *((umem_bufctl_t *)
- ((uintptr_t)bcp - (uintptr_t)kbase +
- (uintptr_t)ubase));
+ uintptr_t offs = (uintptr_t)bcp - (uintptr_t)kbase;
+
+ if (offs > chunks * chunksize) {
+ mdb_warn("found corrupt bufctl ptr %p"
+ " in slab %p in cache %p\n", bcp,
+ wsp->walk_addr, addr);
+ break;
+ }
+ bc = *((umem_bufctl_t *)((uintptr_t)ubase + offs));
buf = UMEM_BUF(cp, bcp);
}
diff --git a/usr/src/cmd/mdb/i86pc/modules/unix/unix.c b/usr/src/cmd/mdb/i86pc/modules/unix/unix.c
index d774cde91f..2e11fcf668 100644
--- a/usr/src/cmd/mdb/i86pc/modules/unix/unix.c
+++ b/usr/src/cmd/mdb/i86pc/modules/unix/unix.c
@@ -22,6 +22,10 @@
* Copyright (c) 1999, 2010, Oracle and/or its affiliates. All rights reserved.
*/
+/*
+ * Copyright 2011 Joyent, Inc. All rights reserved.
+ */
+
#include <mdb/mdb_modapi.h>
#include <mdb/mdb_ctf.h>
#include <sys/cpuvar.h>
@@ -745,6 +749,75 @@ ptable_help(void)
"-m Interpret the PFN as an MFN (machine frame number)\n");
}
+/*
+ * NSEC_SHIFT is replicated here (it is not defined in a header file),
+ * but for amusement, the reader is directed to the comment that explains
+ * the rationale for this particular value on x86. Spoiler: the value is
+ * selected to accommodate 60 MHz Pentiums! (And a confession: if the voice
+ * in that comment sounds too familiar, it's because your author also wrote
+ * that code -- some fifteen years prior to this writing in 2011...)
+ */
+#define NSEC_SHIFT 5
+
+/*ARGSUSED*/
+static int
+scalehrtime_cmd(uintptr_t addr, uint_t flags, int argc, const mdb_arg_t *argv)
+{
+ uint32_t nsec_scale;
+ hrtime_t tsc = addr, hrt;
+ unsigned int *tscp = (unsigned int *)&tsc;
+ uintptr_t scalehrtimef;
+ uint64_t scale;
+ GElf_Sym sym;
+
+ if (!(flags & DCMD_ADDRSPEC)) {
+ if (argc != 1)
+ return (DCMD_USAGE);
+
+ switch (argv[0].a_type) {
+ case MDB_TYPE_STRING:
+ tsc = mdb_strtoull(argv[0].a_un.a_str);
+ break;
+ case MDB_TYPE_IMMEDIATE:
+ tsc = argv[0].a_un.a_val;
+ break;
+ default:
+ return (DCMD_USAGE);
+ }
+ }
+
+ if (mdb_readsym(&scalehrtimef,
+ sizeof (scalehrtimef), "scalehrtimef") == -1) {
+ mdb_warn("couldn't read 'scalehrtimef'");
+ return (DCMD_ERR);
+ }
+
+ if (mdb_lookup_by_name("tsc_scalehrtime", &sym) == -1) {
+ mdb_warn("couldn't find 'tsc_scalehrtime'");
+ return (DCMD_ERR);
+ }
+
+ if (sym.st_value != scalehrtimef) {
+ mdb_warn("::scalehrtime requires that scalehrtimef "
+ "be set to tsc_scalehrtime\n");
+ return (DCMD_ERR);
+ }
+
+ if (mdb_readsym(&nsec_scale, sizeof (nsec_scale), "nsec_scale") == -1) {
+ mdb_warn("couldn't read 'nsec_scale'");
+ return (DCMD_ERR);
+ }
+
+ scale = (uint64_t)nsec_scale;
+
+ hrt = ((uint64_t)tscp[1] * scale) << NSEC_SHIFT;
+ hrt += ((uint64_t)tscp[0] * scale) >> (32 - NSEC_SHIFT);
+
+ mdb_printf("0x%llx\n", hrt);
+
+ return (DCMD_OK);
+}
+
static const mdb_dcmd_t dcmds[] = {
{ "gate_desc", ":", "dump a gate descriptor", gate_desc },
{ "idt", ":[-v]", "dump an IDT", idt },
@@ -765,6 +838,8 @@ static const mdb_dcmd_t dcmds[] = {
{ "mfntopfn", ":", "convert hypervisor machine page to physical page",
mfntopfn_dcmd },
{ "memseg_list", ":", "show memseg list", memseg_list },
+ { "scalehrtime", ":",
+ "scale an unscaled high-res time", scalehrtime_cmd },
{ NULL }
};
diff --git a/usr/src/cmd/ndmpd/ndmp/ndmpd_zfs.c b/usr/src/cmd/ndmpd/ndmp/ndmpd_zfs.c
index c72a3a8ea6..6afb3d3c45 100644
--- a/usr/src/cmd/ndmpd/ndmp/ndmpd_zfs.c
+++ b/usr/src/cmd/ndmpd/ndmp/ndmpd_zfs.c
@@ -1,5 +1,6 @@
/*
* Copyright (c) 2010, Oracle and/or its affiliates. All rights reserved.
+ * Copyright (c) 2011 by Delphix. All rights reserved.
*/
/*
@@ -652,7 +653,7 @@ ndmpd_zfs_backup_send_read(ndmpd_zfs_args_t *ndmpd_zfs_args)
fromsnap = ndmpd_zfs_args->nz_fromsnap;
}
- err = zfs_send(zhp, fromsnap, ndmpd_zfs_args->nz_snapname, flags,
+ err = zfs_send(zhp, fromsnap, ndmpd_zfs_args->nz_snapname, &flags,
ndmpd_zfs_args->nz_pipe_fd[PIPE_ZFS], NULL, NULL, NULL);
if (err && !session->ns_data.dd_abort)
@@ -915,7 +916,7 @@ ndmpd_zfs_restore_recv_write(ndmpd_zfs_args_t *ndmpd_zfs_args)
flags.force = B_TRUE;
err = zfs_receive(ndmpd_zfs_args->nz_zlibh, ndmpd_zfs_args->nz_dataset,
- flags, ndmpd_zfs_args->nz_pipe_fd[PIPE_ZFS], NULL);
+ &flags, ndmpd_zfs_args->nz_pipe_fd[PIPE_ZFS], NULL);
if (err && !session->ns_data.dd_abort)
NDMPD_ZFS_LOG_ZERR(ndmpd_zfs_args, "zfs_receive: %d", err);
diff --git a/usr/src/cmd/ps/ps.c b/usr/src/cmd/ps/ps.c
index 757785882b..e607dd5644 100644
--- a/usr/src/cmd/ps/ps.c
+++ b/usr/src/cmd/ps/ps.c
@@ -1228,10 +1228,14 @@ static char *
gettty(psinfo_t *psinfo)
{
extern char *_ttyname_dev(dev_t, char *, size_t);
+ static zoneid_t zid = -1;
char devname[TTYNAME_MAX];
char *retval;
- if (psinfo->pr_ttydev == PRNODEV)
+ if (zid == -1)
+ zid = getzoneid();
+
+ if (psinfo->pr_ttydev == PRNODEV || psinfo->pr_zoneid != zid)
return ("?");
if ((retval = devlookup(psinfo->pr_ttydev)) != NULL)
diff --git a/usr/src/cmd/ps/ucbps.c b/usr/src/cmd/ps/ucbps.c
index 4731f260e9..60235e2ae9 100644
--- a/usr/src/cmd/ps/ucbps.c
+++ b/usr/src/cmd/ps/ucbps.c
@@ -65,6 +65,7 @@
#include <stdarg.h>
#include <sys/proc.h>
#include <priv_utils.h>
+#include <zone.h>
#define NTTYS 2 /* max ttys that can be specified with the -t option */
/* only one tty can be specified with SunOS ps */
@@ -803,10 +804,14 @@ static char *
gettty(psinfo_t *psinfo)
{
extern char *_ttyname_dev(dev_t, char *, size_t);
+ static zoneid_t zid = -1;
char devname[TTYNAME_MAX];
char *retval;
- if (psinfo->pr_ttydev == PRNODEV)
+ if (zid == -1)
+ zid = getzoneid();
+
+ if (psinfo->pr_ttydev == PRNODEV || psinfo->pr_zoneid != zid)
return ("?");
if ((retval = devlookup(psinfo->pr_ttydev)) != NULL)
diff --git a/usr/src/cmd/smbsrv/smbadm/smbadm.c b/usr/src/cmd/smbsrv/smbadm/smbadm.c
index df7f163599..7874a71bed 100644
--- a/usr/src/cmd/smbsrv/smbadm/smbadm.c
+++ b/usr/src/cmd/smbsrv/smbadm/smbadm.c
@@ -19,6 +19,7 @@
* CDDL HEADER END
*/
/*
+ * Copyright 2011 Nexenta Systems, Inc. All rights reserved.
* Copyright (c) 2007, 2010, Oracle and/or its affiliates. All rights reserved.
*/
@@ -58,6 +59,7 @@ typedef enum {
HELP_GET,
HELP_JOIN,
HELP_LIST,
+ HELP_LOOKUP,
HELP_RENAME,
HELP_SET,
HELP_SHOW,
@@ -70,6 +72,11 @@ typedef enum {
#define SMBADM_CMDF_GROUP 0x02
#define SMBADM_CMDF_TYPEMASK 0x0F
+typedef enum {
+ SMBADM_GRP_ADDMEMBER = 0,
+ SMBADM_GRP_DELMEMBER,
+} smbadm_grp_action_t;
+
#define SMBADM_ANSBUFSIZ 64
typedef struct smbadm_cmdinfo {
@@ -96,6 +103,9 @@ static void smbadm_extract_domain(char *, char **, char **);
static int smbadm_join(int, char **);
static int smbadm_list(int, char **);
+static int smbadm_lookup(int, char **);
+static void smbadm_lookup_name(char *);
+static void smbadm_lookup_sid(char *);
static int smbadm_group_create(int, char **);
static int smbadm_group_delete(int, char **);
static int smbadm_group_rename(int, char **);
@@ -105,6 +115,8 @@ static int smbadm_group_getprop(int, char **);
static int smbadm_group_setprop(int, char **);
static int smbadm_group_addmember(int, char **);
static int smbadm_group_delmember(int, char **);
+static int smbadm_group_add_del_member(char *, char *, smbadm_grp_action_t);
+
static int smbadm_user_disable(int, char **);
static int smbadm_user_enable(int, char **);
@@ -126,6 +138,8 @@ static smbadm_cmdinfo_t smbadm_cmdtable[] =
SMBADM_CMDF_NONE, SMBADM_VALUE_AUTH },
{ "list", smbadm_list, HELP_LIST,
SMBADM_CMDF_NONE, SMBADM_BASIC_AUTH },
+ { "lookup", smbadm_lookup, HELP_LOOKUP,
+ SMBADM_CMDF_NONE, SMBADM_BASIC_AUTH },
{ "remove-member", smbadm_group_delmember, HELP_DEL_MEMBER,
SMBADM_CMDF_GROUP, SMBADM_ACTION_AUTH },
{ "rename", smbadm_group_rename, HELP_RENAME,
@@ -229,6 +243,12 @@ smbadm_cmdusage(FILE *fp, smbadm_cmdinfo_t *cmd)
gettext("\t\t[+] selected domain controller\n"));
return;
+ case HELP_LOOKUP:
+ (void) fprintf(fp,
+ gettext("\t%s user-or-group-name\n"),
+ cmd->name);
+ return;
+
case HELP_DEL_MEMBER:
(void) fprintf(fp,
gettext("\t%s -m member [[-m member] ...] group\n"),
@@ -718,6 +738,70 @@ smbadm_list(int argc, char **argv)
}
/*
+ * smbadm_lookup
+ *
+ * Lookup the SID for a given account (user or group)
+ */
+static int
+smbadm_lookup(int argc, char **argv)
+{
+ int i;
+
+ if (argc < 2) {
+ (void) fprintf(stderr, gettext("missing account name\n"));
+ smbadm_usage(B_FALSE);
+ }
+
+ for (i = 1; i < argc; i++) {
+ if (strncmp(argv[i], "S-1-", 4) == 0)
+ smbadm_lookup_sid(argv[i]);
+ else
+ smbadm_lookup_name(argv[i]);
+ }
+ return (0);
+}
+
+static void
+smbadm_lookup_name(char *name)
+{
+ lsa_account_t acct;
+ int rc;
+
+ if ((rc = smb_lookup_name(name, SidTypeUnknown, &acct)) != 0) {
+ (void) fprintf(stderr, gettext(
+ "\t\t%s: lookup name failed, rc=%d\n"),
+ name, rc);
+ return;
+ }
+ if (acct.a_status != NT_STATUS_SUCCESS) {
+ (void) fprintf(stderr, gettext("\t\t%s [%s]\n"),
+ name, xlate_nt_status(acct.a_status));
+ return;
+ }
+ (void) printf("\t%s\n", acct.a_sid);
+}
+
+static void
+smbadm_lookup_sid(char *sidstr)
+{
+ lsa_account_t acct;
+ int rc;
+
+ if ((rc = smb_lookup_sid(sidstr, &acct)) != 0) {
+ (void) fprintf(stderr, gettext(
+ "\t\t%s: lookup SID failed, rc=%d\n"),
+ sidstr, rc);
+ return;
+ }
+ if (acct.a_status != NT_STATUS_SUCCESS) {
+ (void) fprintf(stderr, gettext("\t\t%s [%s]\n"),
+ sidstr, xlate_nt_status(acct.a_status));
+ return;
+ }
+ (void) printf("\t%s\\%s\n", acct.a_domain, acct.a_name);
+}
+
+/*
* smbadm_group_create
*
* Creates a local SMB group
@@ -797,9 +881,9 @@ static void
smbadm_group_show_name(const char *domain, const char *name)
{
if (strchr(domain, '.') != NULL)
- (void) printf(gettext("\t\t%s@%s\n"), name, domain);
+ (void) printf("\t\t%s@%s\n", name, domain);
else
- (void) printf(gettext("\t\t%s\\%s\n"), domain, name);
+ (void) printf("\t\t%s\\%s\n", domain, name);
}
/*
@@ -1133,12 +1217,9 @@ smbadm_group_getprop(int argc, char **argv)
static int
smbadm_group_addmember(int argc, char **argv)
{
- lsa_account_t acct;
char *gname = NULL;
char **mname;
char option;
- smb_gsid_t msid;
- int status;
int mcnt = 0;
int ret = 0;
int i;
@@ -1176,39 +1257,11 @@ smbadm_group_addmember(int argc, char **argv)
smbadm_usage(B_FALSE);
}
-
for (i = 0; i < mcnt; i++) {
- ret = 0;
if (mname[i] == NULL)
continue;
-
- ret = smb_lookup_name(mname[i], SidTypeUnknown, &acct);
- if ((ret != 0) || (acct.a_status != NT_STATUS_SUCCESS)) {
- (void) fprintf(stderr,
- gettext("failed to add %s: unable to obtain SID\n"),
- mname[i]);
- continue;
- }
-
- msid.gs_type = acct.a_sidtype;
-
- if ((msid.gs_sid = smb_sid_fromstr(acct.a_sid)) == NULL) {
- (void) fprintf(stderr,
- gettext("failed to add %s: no memory\n"), mname[i]);
- continue;
- }
-
- status = smb_lgrp_add_member(gname, msid.gs_sid, msid.gs_type);
- smb_sid_free(msid.gs_sid);
- if (status != SMB_LGRP_SUCCESS) {
- (void) fprintf(stderr,
- gettext("failed to add %s (%s)\n"),
- mname[i], smb_lgrp_strerror(status));
- ret = 1;
- } else {
- (void) printf(gettext("'%s' is now a member of '%s'\n"),
- mname[i], gname);
- }
+ ret |= smbadm_group_add_del_member(
+ gname, mname[i], SMBADM_GRP_ADDMEMBER);
}
free(mname);
@@ -1221,12 +1274,9 @@ smbadm_group_addmember(int argc, char **argv)
static int
smbadm_group_delmember(int argc, char **argv)
{
- lsa_account_t acct;
char *gname = NULL;
char **mname;
char option;
- smb_gsid_t msid;
- int status;
int mcnt = 0;
int ret = 0;
int i;
@@ -1268,40 +1318,77 @@ smbadm_group_delmember(int argc, char **argv)
ret = 0;
if (mname[i] == NULL)
continue;
+ ret |= smbadm_group_add_del_member(
+ gname, mname[i], SMBADM_GRP_DELMEMBER);
+ }
- ret = smb_lookup_name(mname[i], SidTypeUnknown, &acct);
- if ((ret != 0) || (acct.a_status != NT_STATUS_SUCCESS)) {
- (void) fprintf(stderr,
- gettext("failed to remove %s: "
- "unable to obtain SID\n"),
- mname[i]);
- continue;
- }
+ free(mname);
+ return (ret);
+}
- msid.gs_type = acct.a_sidtype;
+static int
+smbadm_group_add_del_member(char *gname, char *mname,
+ smbadm_grp_action_t act)
+{
+ lsa_account_t acct;
+ smb_gsid_t msid;
+ char *sidstr;
+ char *act_str;
+ int rc;
- if ((msid.gs_sid = smb_sid_fromstr(acct.a_sid)) == NULL) {
+ if (strncmp(mname, "S-1-", 4) == 0) {
+ /*
+ * We are given a SID. Just use it.
+ *
+ * We'e like the real account type if we can get it,
+ * but don't want to error out if we can't get it.
+ */
+ sidstr = mname;
+ rc = smb_lookup_sid(sidstr, &acct);
+ if ((rc != 0) || (acct.a_status != NT_STATUS_SUCCESS))
+ acct.a_sidtype = SidTypeUnknown;
+ } else {
+ rc = smb_lookup_name(mname, SidTypeUnknown, &acct);
+ if ((rc != 0) || (acct.a_status != NT_STATUS_SUCCESS)) {
(void) fprintf(stderr,
- gettext("failed to remove %s: no memory\n"),
- mname[i]);
- continue;
+ gettext("%s: name lookup failed\n"), mname);
+ return (1);
}
+ sidstr = acct.a_sid;
+ }
- status = smb_lgrp_del_member(gname, msid.gs_sid, msid.gs_type);
- smb_sid_free(msid.gs_sid);
- if (status != SMB_LGRP_SUCCESS) {
- (void) fprintf(stderr,
- gettext("failed to remove %s (%s)\n"),
- mname[i], smb_lgrp_strerror(status));
- ret = 1;
- } else {
- (void) printf(
- gettext("'%s' has been removed from %s\n"),
- mname[i], gname);
- }
+ msid.gs_type = acct.a_sidtype;
+ if ((msid.gs_sid = smb_sid_fromstr(sidstr)) == NULL) {
+ (void) fprintf(stderr,
+ gettext("%s: no memory for SID\n"), sidstr);
+ return (1);
}
- return (ret);
+ switch (act) {
+ case SMBADM_GRP_ADDMEMBER:
+ act_str = gettext("add");
+ rc = smb_lgrp_add_member(gname,
+ msid.gs_sid, msid.gs_type);
+ break;
+ case SMBADM_GRP_DELMEMBER:
+ act_str = gettext("remove");
+ rc = smb_lgrp_del_member(gname,
+ msid.gs_sid, msid.gs_type);
+ break;
+ default:
+ rc = SMB_LGRP_INTERNAL_ERROR;
+ break;
+ }
+
+ smb_sid_free(msid.gs_sid);
+
+ if (rc != SMB_LGRP_SUCCESS) {
+ (void) fprintf(stderr,
+ gettext("failed to %s %s (%s)\n"),
+ act_str, mname, smb_lgrp_strerror(rc));
+ return (1);
+ }
+ return (0);
}
static int
diff --git a/usr/src/cmd/truss/codes.c b/usr/src/cmd/truss/codes.c
index 119dba0aac..d39dab0b05 100644
--- a/usr/src/cmd/truss/codes.c
+++ b/usr/src/cmd/truss/codes.c
@@ -21,6 +21,8 @@
/*
* Copyright (c) 1989, 2010, Oracle and/or its affiliates. All rights reserved.
+ * Copyright (c) 2011 by Delphix. All rights reserved.
+ * Copyright 2011 Nexenta Systems, Inc. All rights reserved.
*/
/* Copyright (c) 1984, 1986, 1987, 1988, 1989 AT&T */
@@ -1202,8 +1204,6 @@ const struct ioc {
"zfs_cmd_t" },
{ (uint_t)ZFS_IOC_PROMOTE, "ZFS_IOC_PROMOTE",
"zfs_cmd_t" },
- { (uint_t)ZFS_IOC_DESTROY_SNAPS, "ZFS_IOC_DESTROY_SNAPS",
- "zfs_cmd_t" },
{ (uint_t)ZFS_IOC_SNAPSHOT, "ZFS_IOC_SNAPSHOT",
"zfs_cmd_t" },
{ (uint_t)ZFS_IOC_DSOBJ_TO_DSNAME, "ZFS_IOC_DSOBJ_TO_DSNAME",
@@ -1248,6 +1248,12 @@ const struct ioc {
"zfs_cmd_t" },
{ (uint_t)ZFS_IOC_OBJ_TO_STATS, "ZFS_IOC_OBJ_TO_STATS",
"zfs_cmd_t" },
+ { (uint_t)ZFS_IOC_POOL_REGUID, "ZFS_IOC_POOL_REGUID",
+ "zfs_cmd_t" },
+ { (uint_t)ZFS_IOC_SPACE_WRITTEN, "ZFS_IOC_SPACE_WRITTEN",
+ "zfs_cmd_t" },
+ { (uint_t)ZFS_IOC_DESTROY_SNAPS_NVL, "ZFS_IOC_DESTROY_SNAPS_NVL",
+ "zfs_cmd_t" },
/* kssl ioctls */
{ (uint_t)KSSL_ADD_ENTRY, "KSSL_ADD_ENTRY",
diff --git a/usr/src/cmd/zfs/zfs_main.c b/usr/src/cmd/zfs/zfs_main.c
index 4ce51c5b2c..d041c33029 100644
--- a/usr/src/cmd/zfs/zfs_main.c
+++ b/usr/src/cmd/zfs/zfs_main.c
@@ -23,6 +23,7 @@
* Copyright (c) 2005, 2010, Oracle and/or its affiliates. All rights reserved.
* Copyright 2011 Nexenta Systems, Inc. All rights reserved.
* Copyright 2011 Joyent, Inc. All rights reserved.
+ * Copyright (c) 2011 by Delphix. All rights reserved.
*/
#include <assert.h>
@@ -139,7 +140,7 @@ typedef enum {
HELP_HOLD,
HELP_HOLDS,
HELP_RELEASE,
- HELP_DIFF
+ HELP_DIFF,
} zfs_help_t;
typedef struct zfs_command {
@@ -211,8 +212,9 @@ get_usage(zfs_help_t idx)
"\tcreate [-ps] [-b blocksize] [-o property=value] ... "
"-V <size> <volume>\n"));
case HELP_DESTROY:
- return (gettext("\tdestroy [-rRfF] <filesystem|volume>\n"
- "\tdestroy [-rRdF] <snapshot>\n"));
+ return (gettext("\tdestroy [-fnpRrv] <filesystem|volume>\n"
+ "\tdestroy [-dnpRrv] "
+ "<filesystem|volume>@<snap>[%<snap>][,...]\n"));
case HELP_GET:
return (gettext("\tget [-rHp] [-d max] "
"[-o \"all\" | field[,...]] [-s source[,...]]\n"
@@ -246,7 +248,8 @@ get_usage(zfs_help_t idx)
case HELP_ROLLBACK:
return (gettext("\trollback [-rRf] <snapshot>\n"));
case HELP_SEND:
- return (gettext("\tsend [-RDp] [-[iI] snapshot] <snapshot>\n"));
+ return (gettext("\tsend [-DnPpRrv] [-[iI] snapshot] "
+ "<snapshot>\n"));
case HELP_SET:
return (gettext("\tset <property=value> "
"<filesystem|volume|snapshot> ...\n"));
@@ -425,6 +428,8 @@ usage(boolean_t requested)
(void) fprintf(fp, "YES NO <size> | none\n");
(void) fprintf(fp, "\t%-15s ", "groupquota@...");
(void) fprintf(fp, "YES NO <size> | none\n");
+ (void) fprintf(fp, "\t%-15s ", "written@<snap>");
+ (void) fprintf(fp, " NO NO <size>\n");
(void) fprintf(fp, gettext("\nSizes are specified in bytes "
"with standard units such as K, M, G, etc.\n"));
@@ -871,16 +876,24 @@ badusage:
*/
typedef struct destroy_cbdata {
boolean_t cb_first;
- int cb_force;
- boolean_t cb_wait;
- int cb_recurse;
- int cb_error;
- int cb_needforce;
- int cb_doclones;
- boolean_t cb_closezhp;
+ boolean_t cb_force;
+ boolean_t cb_wait;
+ boolean_t cb_recurse;
+ boolean_t cb_error;
+ boolean_t cb_doclones;
zfs_handle_t *cb_target;
- char *cb_snapname;
boolean_t cb_defer_destroy;
+ boolean_t cb_verbose;
+ boolean_t cb_parsable;
+ boolean_t cb_dryrun;
+ nvlist_t *cb_nvl;
+
+ /* first snap in contiguous run */
+ zfs_handle_t *cb_firstsnap;
+ /* previous snap in contiguous run */
+ zfs_handle_t *cb_prevsnap;
+ int64_t cb_snapused;
+ char *cb_snapspec;
} destroy_cbdata_t;
/*
@@ -910,7 +923,7 @@ destroy_check_dependent(zfs_handle_t *zhp, void *data)
(void) fprintf(stderr, gettext("use '-r' to destroy "
"the following datasets:\n"));
cbp->cb_first = B_FALSE;
- cbp->cb_error = 1;
+ cbp->cb_error = B_TRUE;
}
(void) fprintf(stderr, "%s\n", zfs_get_name(zhp));
@@ -931,7 +944,8 @@ destroy_check_dependent(zfs_handle_t *zhp, void *data)
(void) fprintf(stderr, gettext("use '-R' to destroy "
"the following datasets:\n"));
cbp->cb_first = B_FALSE;
- cbp->cb_error = 1;
+ cbp->cb_error = B_TRUE;
+ cbp->cb_dryrun = B_TRUE;
}
(void) fprintf(stderr, "%s\n", zfs_get_name(zhp));
@@ -951,6 +965,19 @@ destroy_callback(zfs_handle_t *zhp, void *data)
ts.tv_sec = 0;
ts.tv_nsec = 500 * (NANOSEC / MILLISEC);
+ const char *name = zfs_get_name(zhp);
+
+ if (cbp->cb_verbose) {
+ if (cbp->cb_parsable) {
+ (void) printf("destroy\t%s\n", name);
+ } else if (cbp->cb_dryrun) {
+ (void) printf(gettext("would destroy %s\n"),
+ name);
+ } else {
+ (void) printf(gettext("will destroy %s\n"),
+ name);
+ }
+ }
/*
* Ignore pools (which we've already flagged as an error before getting
@@ -971,15 +998,17 @@ destroy_callback(zfs_handle_t *zhp, void *data)
* When retrying, try every 500ms until either succeeding or seeing a
* non-EBUSY error code.
*/
- while ((err = zfs_destroy(zhp, cbp->cb_defer_destroy)) != 0) {
- if (cbp->cb_wait && libzfs_errno(g_zfs) == EZFS_BUSY) {
- (void) nanosleep(&ts, NULL);
- continue;
- }
- (void) fprintf(stderr, "%s: %s\n", libzfs_error_action(g_zfs),
- libzfs_error_description(g_zfs));
- break;
- }
+ if (!cbp->cb_dryrun) {
+ while ((err = zfs_destroy(zhp, cbp->cb_defer_destroy)) != 0) {
+ if (cbp->cb_wait && libzfs_errno(g_zfs) == EZFS_BUSY) {
+ (void) nanosleep(&ts, NULL);
+ continue;
+ }
+ (void) fprintf(stderr, "%s: %s\n", libzfs_error_action(g_zfs),
+ libzfs_error_description(g_zfs));
+ break;
+ }
+ }
libzfs_print_on_error(g_zfs, B_TRUE);
@@ -989,39 +1018,142 @@ out:
}
static int
-destroy_snap_clones(zfs_handle_t *zhp, void *arg)
+destroy_print_cb(zfs_handle_t *zhp, void *arg)
{
- destroy_cbdata_t *cbp = arg;
- char thissnap[MAXPATHLEN];
- zfs_handle_t *szhp;
- boolean_t closezhp = cbp->cb_closezhp;
- int rv;
+ destroy_cbdata_t *cb = arg;
+ const char *name = zfs_get_name(zhp);
+ int err = 0;
- (void) snprintf(thissnap, sizeof (thissnap),
- "%s@%s", zfs_get_name(zhp), cbp->cb_snapname);
+ if (nvlist_exists(cb->cb_nvl, name)) {
+ if (cb->cb_firstsnap == NULL)
+ cb->cb_firstsnap = zfs_handle_dup(zhp);
+ if (cb->cb_prevsnap != NULL)
+ zfs_close(cb->cb_prevsnap);
+ /* this snap continues the current range */
+ cb->cb_prevsnap = zfs_handle_dup(zhp);
+ if (cb->cb_verbose) {
+ if (cb->cb_parsable) {
+ (void) printf("destroy\t%s\n", name);
+ } else if (cb->cb_dryrun) {
+ (void) printf(gettext("would destroy %s\n"),
+ name);
+ } else {
+ (void) printf(gettext("will destroy %s\n"),
+ name);
+ }
+ }
+ } else if (cb->cb_firstsnap != NULL) {
+ /* end of this range */
+ uint64_t used = 0;
+ err = zfs_get_snapused_int(cb->cb_firstsnap,
+ cb->cb_prevsnap, &used);
+ cb->cb_snapused += used;
+ zfs_close(cb->cb_firstsnap);
+ cb->cb_firstsnap = NULL;
+ zfs_close(cb->cb_prevsnap);
+ cb->cb_prevsnap = NULL;
+ }
+ zfs_close(zhp);
+ return (err);
+}
- libzfs_print_on_error(g_zfs, B_FALSE);
- szhp = zfs_open(g_zfs, thissnap, ZFS_TYPE_SNAPSHOT);
- libzfs_print_on_error(g_zfs, B_TRUE);
- if (szhp) {
- /*
- * Destroy any clones of this snapshot
- */
- if (zfs_iter_dependents(szhp, B_FALSE, destroy_callback,
- cbp) != 0) {
- zfs_close(szhp);
- if (closezhp)
- zfs_close(zhp);
- return (-1);
+static int
+destroy_print_snapshots(zfs_handle_t *fs_zhp, destroy_cbdata_t *cb)
+{
+ int err;
+ assert(cb->cb_firstsnap == NULL);
+ assert(cb->cb_prevsnap == NULL);
+ err = zfs_iter_snapshots_sorted(fs_zhp, destroy_print_cb, cb);
+ if (cb->cb_firstsnap != NULL) {
+ uint64_t used = 0;
+ if (err == 0) {
+ err = zfs_get_snapused_int(cb->cb_firstsnap,
+ cb->cb_prevsnap, &used);
}
- zfs_close(szhp);
+ cb->cb_snapused += used;
+ zfs_close(cb->cb_firstsnap);
+ cb->cb_firstsnap = NULL;
+ zfs_close(cb->cb_prevsnap);
+ cb->cb_prevsnap = NULL;
}
+ return (err);
+}
- cbp->cb_closezhp = B_TRUE;
- rv = zfs_iter_filesystems(zhp, destroy_snap_clones, arg);
- if (closezhp)
- zfs_close(zhp);
- return (rv);
+static int
+snapshot_to_nvl_cb(zfs_handle_t *zhp, void *arg)
+{
+ destroy_cbdata_t *cb = arg;
+ int err = 0;
+
+ /* Check for clones. */
+ if (!cb->cb_doclones) {
+ cb->cb_target = zhp;
+ cb->cb_first = B_TRUE;
+ err = zfs_iter_dependents(zhp, B_TRUE,
+ destroy_check_dependent, cb);
+ }
+
+ if (err == 0) {
+ if (nvlist_add_boolean(cb->cb_nvl, zfs_get_name(zhp)))
+ nomem();
+ }
+ zfs_close(zhp);
+ return (err);
+}
+
+static int
+gather_snapshots(zfs_handle_t *zhp, void *arg)
+{
+ destroy_cbdata_t *cb = arg;
+ int err = 0;
+
+ err = zfs_iter_snapspec(zhp, cb->cb_snapspec, snapshot_to_nvl_cb, cb);
+ if (err == ENOENT)
+ err = 0;
+ if (err != 0)
+ goto out;
+
+ if (cb->cb_verbose) {
+ err = destroy_print_snapshots(zhp, cb);
+ if (err != 0)
+ goto out;
+ }
+
+ if (cb->cb_recurse)
+ err = zfs_iter_filesystems(zhp, gather_snapshots, cb);
+
+out:
+ zfs_close(zhp);
+ return (err);
+}
+
+static int
+destroy_clones(destroy_cbdata_t *cb)
+{
+ nvpair_t *pair;
+ for (pair = nvlist_next_nvpair(cb->cb_nvl, NULL);
+ pair != NULL;
+ pair = nvlist_next_nvpair(cb->cb_nvl, pair)) {
+ zfs_handle_t *zhp = zfs_open(g_zfs, nvpair_name(pair),
+ ZFS_TYPE_SNAPSHOT);
+ if (zhp != NULL) {
+ boolean_t defer = cb->cb_defer_destroy;
+ int err;
+
+ /*
+ * We can't defer destroy non-snapshots, so set it to
+ * false while destroying the clones.
+ */
+ cb->cb_defer_destroy = B_FALSE;
+ err = zfs_iter_dependents(zhp, B_FALSE,
+ destroy_callback, cb);
+ cb->cb_defer_destroy = defer;
+ zfs_close(zhp);
+ if (err != 0)
+ return (err);
+ }
+ }
+ return (0);
}
static int
@@ -1030,28 +1162,38 @@ zfs_do_destroy(int argc, char **argv)
destroy_cbdata_t cb = { 0 };
int c;
zfs_handle_t *zhp;
- char *cp;
+ char *at;
zfs_type_t type = ZFS_TYPE_DATASET;
/* check options */
- while ((c = getopt(argc, argv, "dfFrR")) != -1) {
+ while ((c = getopt(argc, argv, "vpndfFrR")) != -1) {
switch (c) {
+ case 'v':
+ cb.cb_verbose = B_TRUE;
+ break;
+ case 'p':
+ cb.cb_verbose = B_TRUE;
+ cb.cb_parsable = B_TRUE;
+ break;
+ case 'n':
+ cb.cb_dryrun = B_TRUE;
+ break;
case 'd':
cb.cb_defer_destroy = B_TRUE;
type = ZFS_TYPE_SNAPSHOT;
break;
case 'f':
- cb.cb_force = 1;
+ cb.cb_force = B_TRUE;
break;
case 'F':
cb.cb_wait = B_TRUE;
break;
case 'r':
- cb.cb_recurse = 1;
+ cb.cb_recurse = B_TRUE;
break;
case 'R':
- cb.cb_recurse = 1;
- cb.cb_doclones = 1;
+ cb.cb_recurse = B_TRUE;
+ cb.cb_doclones = B_TRUE;
break;
case '?':
default:
@@ -1066,7 +1208,7 @@ zfs_do_destroy(int argc, char **argv)
/* check number of arguments */
if (argc == 0) {
- (void) fprintf(stderr, gettext("missing path argument\n"));
+ (void) fprintf(stderr, gettext("missing dataset argument\n"));
usage(B_FALSE);
}
if (argc > 1) {
@@ -1074,91 +1216,117 @@ zfs_do_destroy(int argc, char **argv)
usage(B_FALSE);
}
- /*
- * If we are doing recursive destroy of a snapshot, then the
- * named snapshot may not exist. Go straight to libzfs.
- */
- if (cb.cb_recurse && (cp = strchr(argv[0], '@'))) {
- int ret;
+ at = strchr(argv[0], '@');
+ if (at != NULL) {
+ int err;
- *cp = '\0';
- if ((zhp = zfs_open(g_zfs, argv[0], ZFS_TYPE_DATASET)) == NULL)
+ /* Build the list of snaps to destroy in cb_nvl. */
+ if (nvlist_alloc(&cb.cb_nvl, NV_UNIQUE_NAME, 0) != 0)
+ nomem();
+
+ *at = '\0';
+ zhp = zfs_open(g_zfs, argv[0],
+ ZFS_TYPE_FILESYSTEM | ZFS_TYPE_VOLUME);
+ if (zhp == NULL)
return (1);
- *cp = '@';
- cp++;
- if (cb.cb_doclones) {
- boolean_t defer = cb.cb_defer_destroy;
+ cb.cb_snapspec = at + 1;
+ if (gather_snapshots(zfs_handle_dup(zhp), &cb) != 0 ||
+ cb.cb_error) {
+ zfs_close(zhp);
+ nvlist_free(cb.cb_nvl);
+ return (1);
+ }
- /*
- * Temporarily ignore the defer_destroy setting since
- * it's not supported for clones.
- */
- cb.cb_defer_destroy = B_FALSE;
- cb.cb_snapname = cp;
- if (destroy_snap_clones(zhp, &cb) != 0) {
- zfs_close(zhp);
- return (1);
+ if (nvlist_empty(cb.cb_nvl)) {
+ (void) fprintf(stderr, gettext("could not find any "
+ "snapshots to destroy; check snapshot names.\n"));
+ zfs_close(zhp);
+ nvlist_free(cb.cb_nvl);
+ return (1);
+ }
+
+ if (cb.cb_verbose) {
+ char buf[16];
+ zfs_nicenum(cb.cb_snapused, buf, sizeof (buf));
+ if (cb.cb_parsable) {
+ (void) printf("reclaim\t%llu\n",
+ cb.cb_snapused);
+ } else if (cb.cb_dryrun) {
+ (void) printf(gettext("would reclaim %s\n"),
+ buf);
+ } else {
+ (void) printf(gettext("will reclaim %s\n"),
+ buf);
}
- cb.cb_defer_destroy = defer;
}
- ret = zfs_destroy_snaps(zhp, cp, cb.cb_defer_destroy);
- zfs_close(zhp);
- if (ret) {
- (void) fprintf(stderr,
- gettext("no snapshots destroyed\n"));
+ if (!cb.cb_dryrun) {
+ if (cb.cb_doclones)
+ err = destroy_clones(&cb);
+ if (err == 0) {
+ err = zfs_destroy_snaps_nvl(zhp, cb.cb_nvl,
+ cb.cb_defer_destroy);
+ }
}
- return (ret != 0);
- }
- /* Open the given dataset */
- if ((zhp = zfs_open(g_zfs, argv[0], type)) == NULL)
- return (1);
+ zfs_close(zhp);
+ nvlist_free(cb.cb_nvl);
+ if (err != 0)
+ return (1);
+ } else {
+ /* Open the given dataset */
+ if ((zhp = zfs_open(g_zfs, argv[0], type)) == NULL)
+ return (1);
- cb.cb_target = zhp;
+ cb.cb_target = zhp;
- /*
- * Perform an explicit check for pools before going any further.
- */
- if (!cb.cb_recurse && strchr(zfs_get_name(zhp), '/') == NULL &&
- zfs_get_type(zhp) == ZFS_TYPE_FILESYSTEM) {
- (void) fprintf(stderr, gettext("cannot destroy '%s': "
- "operation does not apply to pools\n"),
- zfs_get_name(zhp));
- (void) fprintf(stderr, gettext("use 'zfs destroy -r "
- "%s' to destroy all datasets in the pool\n"),
- zfs_get_name(zhp));
- (void) fprintf(stderr, gettext("use 'zpool destroy %s' "
- "to destroy the pool itself\n"), zfs_get_name(zhp));
- zfs_close(zhp);
- return (1);
- }
+ /*
+ * Perform an explicit check for pools before going any further.
+ */
+ if (!cb.cb_recurse && strchr(zfs_get_name(zhp), '/') == NULL &&
+ zfs_get_type(zhp) == ZFS_TYPE_FILESYSTEM) {
+ (void) fprintf(stderr, gettext("cannot destroy '%s': "
+ "operation does not apply to pools\n"),
+ zfs_get_name(zhp));
+ (void) fprintf(stderr, gettext("use 'zfs destroy -r "
+ "%s' to destroy all datasets in the pool\n"),
+ zfs_get_name(zhp));
+ (void) fprintf(stderr, gettext("use 'zpool destroy %s' "
+ "to destroy the pool itself\n"), zfs_get_name(zhp));
+ zfs_close(zhp);
+ return (1);
+ }
- /*
- * Check for any dependents and/or clones.
- */
- cb.cb_first = B_TRUE;
- if (!cb.cb_doclones && !cb.cb_defer_destroy &&
- zfs_iter_dependents(zhp, B_TRUE, destroy_check_dependent,
- &cb) != 0) {
- zfs_close(zhp);
- return (1);
- }
+ /*
+ * Check for any dependents and/or clones.
+ */
+ cb.cb_first = B_TRUE;
+ if (!cb.cb_doclones &&
+ zfs_iter_dependents(zhp, B_TRUE, destroy_check_dependent,
+ &cb) != 0) {
+ zfs_close(zhp);
+ return (1);
+ }
- if (cb.cb_error || (!cb.cb_defer_destroy &&
- (zfs_iter_dependents(zhp, B_FALSE, destroy_callback, &cb) != 0))) {
- zfs_close(zhp);
- return (1);
- }
+ if (cb.cb_error) {
+ zfs_close(zhp);
+ return (1);
+ }
- /*
- * Do the real thing. The callback will close the handle regardless of
- * whether it succeeds or not.
- */
+ if (zfs_iter_dependents(zhp, B_FALSE, destroy_callback,
+ &cb) != 0) {
+ zfs_close(zhp);
+ return (1);
+ }
- if (destroy_callback(zhp, &cb) != 0)
- return (1);
+ /*
+ * Do the real thing. The callback will close the
+ * handle regardless of whether it succeeds or not.
+ */
+ if (destroy_callback(zhp, &cb) != 0)
+ return (1);
+ }
return (0);
}
@@ -1260,6 +1428,17 @@ get_callback(zfs_handle_t *zhp, void *data)
zprop_print_one_property(zfs_get_name(zhp), cbp,
pl->pl_user_prop, buf, sourcetype, source, NULL);
+ } else if (zfs_prop_written(pl->pl_user_prop)) {
+ sourcetype = ZPROP_SRC_LOCAL;
+
+ if (zfs_prop_get_written(zhp, pl->pl_user_prop,
+ buf, sizeof (buf), cbp->cb_literal) != 0) {
+ sourcetype = ZPROP_SRC_NONE;
+ (void) strlcpy(buf, "-", sizeof (buf));
+ }
+
+ zprop_print_one_property(zfs_get_name(zhp), cbp,
+ pl->pl_user_prop, buf, sourcetype, source, NULL);
} else {
if (nvlist_lookup_nvlist(user_props,
pl->pl_user_prop, &propval) != 0) {
@@ -1804,8 +1983,8 @@ zfs_do_upgrade(int argc, char **argv)
"---------------\n");
(void) printf(gettext(" 1 Initial ZFS filesystem version\n"));
(void) printf(gettext(" 2 Enhanced directory entries\n"));
- (void) printf(gettext(" 3 Case insensitive and File system "
- "unique identifier (FUID)\n"));
+ (void) printf(gettext(" 3 Case insensitive and filesystem "
+ "user identifier (FUID)\n"));
(void) printf(gettext(" 4 userquota, groupquota "
"properties\n"));
(void) printf(gettext(" 5 System attributes\n"));
@@ -2679,6 +2858,13 @@ print_dataset(zfs_handle_t *zhp, zprop_list_t *pl, boolean_t scripted,
else
propstr = property;
right_justify = B_TRUE;
+ } else if (zfs_prop_written(pl->pl_user_prop)) {
+ if (zfs_prop_get_written(zhp, pl->pl_user_prop,
+ property, sizeof (property), B_FALSE) != 0)
+ propstr = "-";
+ else
+ propstr = property;
+ right_justify = B_TRUE;
} else {
if (nvlist_lookup_nvlist(userprops,
pl->pl_user_prop, &propval) != 0)
@@ -3293,9 +3479,6 @@ usage:
}
/*
- * zfs send [-vDp] -R [-i|-I <@snap>] <fs@snap>
- * zfs send [-vDp] [-i|-I <@snap>] <fs@snap>
- *
* Send a backup stream to stdout.
*/
static int
@@ -3307,11 +3490,11 @@ zfs_do_send(int argc, char **argv)
zfs_handle_t *zhp;
sendflags_t flags = { 0 };
int c, err;
- nvlist_t *dbgnv;
+ nvlist_t *dbgnv = NULL;
boolean_t extraverbose = B_FALSE;
/* check options */
- while ((c = getopt(argc, argv, ":i:I:RDpv")) != -1) {
+ while ((c = getopt(argc, argv, ":i:I:RDpvnP")) != -1) {
switch (c) {
case 'i':
if (fromname)
@@ -3330,6 +3513,10 @@ zfs_do_send(int argc, char **argv)
case 'p':
flags.props = B_TRUE;
break;
+ case 'P':
+ flags.parsable = B_TRUE;
+ flags.verbose = B_TRUE;
+ break;
case 'v':
if (flags.verbose)
extraverbose = B_TRUE;
@@ -3338,6 +3525,9 @@ zfs_do_send(int argc, char **argv)
case 'D':
flags.dedup = B_TRUE;
break;
+ case 'n':
+ flags.dryrun = B_TRUE;
+ break;
case ':':
(void) fprintf(stderr, gettext("missing argument for "
"'%c' option\n"), optopt);
@@ -3363,7 +3553,7 @@ zfs_do_send(int argc, char **argv)
usage(B_FALSE);
}
- if (isatty(STDOUT_FILENO)) {
+ if (!flags.dryrun && isatty(STDOUT_FILENO)) {
(void) fprintf(stderr,
gettext("Error: Stream can not be written to a terminal.\n"
"You must redirect standard output.\n"));
@@ -3417,10 +3607,10 @@ zfs_do_send(int argc, char **argv)
if (flags.replicate && fromname == NULL)
flags.doall = B_TRUE;
- err = zfs_send(zhp, fromname, toname, flags, STDOUT_FILENO, NULL, 0,
+ err = zfs_send(zhp, fromname, toname, &flags, STDOUT_FILENO, NULL, 0,
extraverbose ? &dbgnv : NULL);
- if (extraverbose) {
+ if (extraverbose && dbgnv != NULL) {
/*
* dump_nvlist prints to stdout, but that's been
* redirected to a file. Make it print to stderr
@@ -3501,7 +3691,7 @@ zfs_do_receive(int argc, char **argv)
return (1);
}
- err = zfs_receive(g_zfs, argv[0], flags, STDIN_FILENO, NULL);
+ err = zfs_receive(g_zfs, argv[0], &flags, STDIN_FILENO, NULL);
return (err != 0);
}
diff --git a/usr/src/cmd/zoneadm/zoneadm.c b/usr/src/cmd/zoneadm/zoneadm.c
index 9d9d782d0a..b63c448d9c 100644
--- a/usr/src/cmd/zoneadm/zoneadm.c
+++ b/usr/src/cmd/zoneadm/zoneadm.c
@@ -2913,7 +2913,6 @@ install_func(int argc, char *argv[])
boolean_t brand_help = B_FALSE;
boolean_t do_dataset = B_TRUE;
char opts[128];
- char *new_uuid = NULL;
if (target_zone == NULL) {
sub_usage(SHELP_INSTALL, CMD_INSTALL);
@@ -2956,7 +2955,7 @@ install_func(int argc, char *argv[])
if (postcmdbuf[0] != '\0')
do_postinstall = B_TRUE;
- (void) strcpy(opts, "?U:x:");
+ (void) strcpy(opts, "?x:");
/*
* Fetch the list of recognized command-line options from
* the brand configuration file.
@@ -2988,10 +2987,6 @@ install_func(int argc, char *argv[])
}
/* Ignore unknown options - may be brand specific. */
break;
- case 'U':
- new_uuid = optarg;
- continue; /* internal arg, don't pass thru */
- break;
case 'x':
if (strcmp(optarg, "nodataset") == 0) {
do_dataset = B_FALSE;
@@ -3077,13 +3072,6 @@ install_func(int argc, char *argv[])
goto done;
}
- if (new_uuid != NULL &&
- (err = zonecfg_set_uuid(target_zone, zonepath, new_uuid) != Z_OK)) {
- errno = err;
- zperror2(target_zone, gettext("could not set UUID"));
- goto done;
- }
-
if (do_postinstall) {
status = do_subproc(postcmdbuf);
diff --git a/usr/src/cmd/zoneadmd/mcap.c b/usr/src/cmd/zoneadmd/mcap.c
index db6ce68dcb..3330da3197 100644
--- a/usr/src/cmd/zoneadmd/mcap.c
+++ b/usr/src/cmd/zoneadmd/mcap.c
@@ -585,7 +585,6 @@ again:
free(buf);
return (0);
}
- goto again;
}
if (n > got) {
diff --git a/usr/src/cmd/zoneadmd/vplat.c b/usr/src/cmd/zoneadmd/vplat.c
index 77b4dc2334..b09f124dea 100644
--- a/usr/src/cmd/zoneadmd/vplat.c
+++ b/usr/src/cmd/zoneadmd/vplat.c
@@ -2439,6 +2439,7 @@ configure_shared_network_interfaces(zlog_t *zlogp)
for (;;) {
if (zonecfg_getnwifent(handle, &nwiftab) != Z_OK)
break;
+ nwifent_free_attrs(&nwiftab);
if (configure_one_interface(zlogp, zoneid, &nwiftab) !=
Z_OK) {
(void) zonecfg_endnwifent(handle);
@@ -2930,6 +2931,7 @@ configure_exclusive_network_interfaces(zlog_t *zlogp, zoneid_t zoneid)
if (zonecfg_getnwifent(handle, &nwiftab) != Z_OK)
break;
+ nwifent_free_attrs(&nwiftab);
if (prof == NULL) {
if (zone_get_devroot(zone_name, rootpath,
sizeof (rootpath)) != Z_OK) {
@@ -4851,6 +4853,8 @@ error:
}
if (rctlbuf != NULL)
free(rctlbuf);
+ if (zfsbuf != NULL)
+ free(zfsbuf);
priv_freeset(privs);
if (fp != NULL)
zonecfg_close_scratch(fp);
diff --git a/usr/src/cmd/zoneadmd/zoneadmd.c b/usr/src/cmd/zoneadmd/zoneadmd.c
index f7425fbc7b..70540f3bda 100644
--- a/usr/src/cmd/zoneadmd/zoneadmd.c
+++ b/usr/src/cmd/zoneadmd/zoneadmd.c
@@ -817,6 +817,7 @@ setup_subproc_env(boolean_t debug)
rap = rap->zone_res_attr_next)
set_zonecfg_env(RSRC_NET, phys, rap->zone_res_attr_name,
rap->zone_res_attr_value);
+ nwifent_free_attrs(&ntab);
}
(void) setenv("_ZONECFG_net_resources", net_resources, 1);
@@ -855,6 +856,19 @@ done:
return (res);
}
+void
+nwifent_free_attrs(struct zone_nwiftab *np)
+{
+ struct zone_res_attrtab *rap;
+
+ for (rap = np->zone_nwif_attrp; rap != NULL; ) {
+ struct zone_res_attrtab *tp = rap;
+
+ rap = rap->zone_res_attr_next;
+ free(tp);
+ }
+}
+
/*
* If retstr is not NULL, the output of the subproc is returned in the str,
* otherwise it is output using zerror(). Any memory allocated for retstr
diff --git a/usr/src/cmd/zoneadmd/zoneadmd.h b/usr/src/cmd/zoneadmd/zoneadmd.h
index 49aa9e8cf6..4310ded0bd 100644
--- a/usr/src/cmd/zoneadmd/zoneadmd.h
+++ b/usr/src/cmd/zoneadmd/zoneadmd.h
@@ -97,6 +97,7 @@ extern dladm_handle_t dld_handle;
extern void zerror(zlog_t *, boolean_t, const char *, ...);
extern char *localize_msg(char *locale, const char *msg);
+extern void nwifent_free_attrs(struct zone_nwiftab *);
/*
* Eventstream interfaces.
diff --git a/usr/src/cmd/zonecfg/zonecfg.c b/usr/src/cmd/zonecfg/zonecfg.c
index bb4b2779e7..f3d267b9dc 100644
--- a/usr/src/cmd/zonecfg/zonecfg.c
+++ b/usr/src/cmd/zonecfg/zonecfg.c
@@ -78,6 +78,7 @@
#include <libinetutil.h>
#include <pwd.h>
#include <inet/ip.h>
+#include <uuid/uuid.h>
#include <libzonecfg.h>
#include "zonecfg.h"
@@ -187,6 +188,7 @@ char *res_types[] = {
"fs-allowed",
ALIAS_MAXPROCS,
ALIAS_ZFSPRI,
+ "uuid",
NULL
};
@@ -239,6 +241,7 @@ char *prop_types[] = {
"vlan-id",
"global-nic",
"property",
+ "uuid",
NULL
};
@@ -356,6 +359,7 @@ static const char *set_cmds[] = {
"set fs-allowed=",
"set " ALIAS_MAXPROCS "=",
"set " ALIAS_ZFSPRI "=",
+ "set uuid=",
NULL
};
@@ -388,6 +392,7 @@ static const char *info_cmds[] = {
"info admin",
"info fs-allowed",
"info max-processes",
+ "info uuid",
NULL
};
@@ -544,6 +549,7 @@ static zone_dochandle_t handle;
/* used all over the place */
static char zone[ZONENAME_MAX];
static char revert_zone[ZONENAME_MAX];
+static char new_uuid[UUID_PRINTABLE_STRING_LENGTH];
/* global brand operations */
static brand_handle_t brand;
@@ -1190,8 +1196,10 @@ usage(boolean_t verbose, uint_t flags)
execname, cmd_to_str(CMD_HELP));
(void) fprintf(fp, "\t%s {-z <zone>|-u <uuid>}\t\t\t(%s)\n",
execname, gettext("interactive"));
- (void) fprintf(fp, "\t%s {-z <zone>|-u <uuid>} <command>\n", execname);
- (void) fprintf(fp, "\t%s {-z <zone>|-u <uuid>} -f <command-file>\n",
+ (void) fprintf(fp, "\t%s {-z <zone>|-u <uuid>} <command>\n",
+ execname);
+ (void) fprintf(fp,
+ "\t%s {-z <zone>|-u <uuid>} -f <command-file>\n",
execname);
}
if (flags & HELP_SUBCMDS) {
@@ -1281,6 +1289,8 @@ usage(boolean_t verbose, uint_t flags)
(void) fprintf(fp, "\t%s\t%s\n", gettext("(global)"),
pt_to_str(PT_SHARES));
(void) fprintf(fp, "\t%s\t%s\n", gettext("(global)"),
+ pt_to_str(PT_UUID));
+ (void) fprintf(fp, "\t%s\t%s\n", gettext("(global)"),
pt_to_str(PT_ZFSPRI));
(void) fprintf(fp, "\t%s\t\t%s, %s, %s, %s, %s\n",
rt_to_str(RT_FS), pt_to_str(PT_DIR),
@@ -1618,6 +1628,7 @@ create_func(cmd_t *cmd)
boolean_t force = B_FALSE;
boolean_t attach = B_FALSE;
boolean_t arg_err = B_FALSE;
+ uuid_t uuid;
assert(cmd != NULL);
@@ -1718,6 +1729,10 @@ create_func(cmd_t *cmd)
zonecfg_fini_handle(handle);
handle = tmphandle;
got_handle = B_TRUE;
+
+ /* Allocate a new uuid for this new zone */
+ uuid_generate(uuid);
+ uuid_unparse(uuid, new_uuid);
}
/*
@@ -1778,6 +1793,7 @@ export_func(cmd_t *cmd)
FILE *of;
boolean_t autoboot;
zone_iptype_t iptype;
+ uuid_t uuid;
boolean_t need_to_close = B_FALSE;
boolean_t arg_err = B_FALSE;
@@ -1888,6 +1904,14 @@ export_func(cmd_t *cmd)
pt_to_str(PT_FS_ALLOWED), fsallowedp);
}
+ if (zonecfg_get_uuid(zone, uuid) == Z_OK && !uuid_is_null(uuid)) {
+ char suuid[UUID_PRINTABLE_STRING_LENGTH];
+
+ uuid_unparse(uuid, suuid);
+ (void) fprintf(of, "%s %s=%s\n", cmd_to_str(CMD_SET),
+ pt_to_str(PT_UUID), suuid);
+ }
+
if ((err = zonecfg_setfsent(handle)) != Z_OK) {
zone_perror(zone, err, B_FALSE);
goto done;
@@ -2542,7 +2566,7 @@ static boolean_t
gz_invalid_rt_property(int type)
{
return (global_zone && (type == RT_ZONENAME || type == RT_ZONEPATH ||
- type == RT_AUTOBOOT || type == RT_LIMITPRIV ||
+ type == RT_AUTOBOOT || type == RT_LIMITPRIV || type == RT_UUID ||
type == RT_BOOTARGS || type == RT_BRAND || type == RT_SCHED ||
type == RT_IPTYPE || type == RT_HOSTID || type == RT_FS_ALLOWED));
}
@@ -2551,7 +2575,7 @@ static boolean_t
gz_invalid_property(int type)
{
return (global_zone && (type == PT_ZONENAME || type == PT_ZONEPATH ||
- type == PT_AUTOBOOT || type == PT_LIMITPRIV ||
+ type == PT_AUTOBOOT || type == PT_LIMITPRIV || type == PT_UUID ||
type == PT_BOOTARGS || type == PT_BRAND || type == PT_SCHED ||
type == PT_IPTYPE || type == PT_HOSTID || type == PT_FS_ALLOWED));
}
@@ -3783,6 +3807,8 @@ clear_global(cmd_t *cmd)
/* FALLTHRU */
case PT_ZONEPATH:
/* FALLTHRU */
+ case PT_UUID:
+ /* FALLTHRU */
case PT_BRAND:
zone_perror(pt_to_str(type), Z_CLEAR_DISALLOW, B_TRUE);
return;
@@ -4340,6 +4366,8 @@ set_func(cmd_t *cmd)
res_type = RT_FS_ALLOWED;
} else if (prop_type == PT_ZFSPRI) {
res_type = RT_ZFSPRI;
+ } else if (prop_type == PT_UUID) {
+ res_type = RT_UUID;
} else {
zerr(gettext("Cannot set a resource-specific property "
"from the global scope."));
@@ -4563,6 +4591,15 @@ set_func(cmd_t *cmd)
}
need_to_commit = B_TRUE;
return;
+ case RT_UUID:
+ /*
+ * We can't set here. We have to wait until commit since the
+ * uuid will be updating the index file and we may not have
+ * created the zone yet.
+ */
+ (void) strlcpy(new_uuid, prop_id, sizeof (new_uuid));
+ need_to_commit = B_TRUE;
+ return;
case RT_FS_ALLOWED:
if ((err = zonecfg_set_fs_allowed(handle, prop_id)) != Z_OK)
zone_perror(zone, err, B_TRUE);
@@ -5160,6 +5197,23 @@ info_hostid(zone_dochandle_t handle, FILE *fp)
}
static void
+info_uuid(FILE *fp)
+{
+ uuid_t uuid;
+ char suuid[UUID_PRINTABLE_STRING_LENGTH];
+
+ if (new_uuid[0] != '\0') {
+ (void) fprintf(fp, "%s: %s\n", pt_to_str(PT_UUID), new_uuid);
+ } else if (zonecfg_get_uuid(zone, uuid) == Z_OK &&
+ !uuid_is_null(uuid)) {
+ uuid_unparse(uuid, suuid);
+ (void) fprintf(fp, "%s: %s\n", pt_to_str(PT_UUID), suuid);
+ } else {
+ (void) fprintf(fp, "%s:\n", pt_to_str(PT_UUID));
+ }
+}
+
+static void
info_fs_allowed(zone_dochandle_t handle, FILE *fp)
{
char fsallowedp[ZONE_FS_ALLOWED_MAX];
@@ -5772,6 +5826,7 @@ info_func(cmd_t *cmd)
info_iptype(handle, fp);
info_hostid(handle, fp);
info_fs_allowed(handle, fp);
+ info_uuid(fp);
}
info_aliased_rctl(handle, fp, ALIAS_MAXLWPS);
info_aliased_rctl(handle, fp, ALIAS_MAXPROCS);
@@ -5877,6 +5932,9 @@ info_func(cmd_t *cmd)
case RT_HOSTID:
info_hostid(handle, fp);
break;
+ case RT_UUID:
+ info_uuid(fp);
+ break;
case RT_ADMIN:
info_auth(handle, fp, cmd);
break;
@@ -6355,6 +6413,18 @@ verify_func(cmd_t *cmd)
(void) strlcpy(revert_zone, zone,
sizeof (revert_zone));
}
+
+ /*
+ * Commit a new uuid at this point since we now know the
+ * zone index entry will exist.
+ */
+ if (new_uuid[0] != '\0') {
+ if ((err = zonecfg_set_uuid(zone, zonepath,
+ new_uuid)) != Z_OK)
+ zone_perror(zone, err, B_FALSE);
+ else
+ new_uuid[0] = '\0';
+ }
} else {
zerr(gettext("Zone %s failed to verify"), zone);
}
@@ -7465,8 +7535,8 @@ main(int argc, char *argv[])
if (uuid_parse((char *)optarg, uuidin) == -1)
return (Z_INVALID_PROPERTY);
- if (zonecfg_get_name_by_uuid(uuidin, zonename, ZONENAME_MAX) !=
- Z_OK) {
+ if (zonecfg_get_name_by_uuid(uuidin, zonename,
+ ZONENAME_MAX) != Z_OK) {
zone_perror(optarg, Z_BOGUS_ZONE_NAME, B_TRUE);
usage(B_FALSE, HELP_SYNTAX);
exit(Z_USAGE);
diff --git a/usr/src/cmd/zonecfg/zonecfg.h b/usr/src/cmd/zonecfg/zonecfg.h
index 960a35d8a1..f8c78437ad 100644
--- a/usr/src/cmd/zonecfg/zonecfg.h
+++ b/usr/src/cmd/zonecfg/zonecfg.h
@@ -92,9 +92,10 @@ extern "C" {
#define RT_FS_ALLOWED 27
#define RT_MAXPROCS 28 /* really a rctl alias property, but for info */
#define RT_ZFSPRI 29 /* really a rctl alias property, but for info */
+#define RT_UUID 30 /* really a property, but for info */
#define RT_MIN RT_UNKNOWN
-#define RT_MAX RT_ZFSPRI
+#define RT_MAX RT_UUID
/* property types: increment PT_MAX when expanding this list */
#define PT_UNKNOWN 0
@@ -144,9 +145,10 @@ extern "C" {
#define PT_VLANID 44
#define PT_GNIC 45
#define PT_NPROP 46
+#define PT_UUID 47
#define PT_MIN PT_UNKNOWN
-#define PT_MAX PT_NPROP
+#define PT_MAX PT_UUID
#define MAX_EQ_PROP_PAIRS 3
diff --git a/usr/src/cmd/zonecfg/zonecfg_grammar.y b/usr/src/cmd/zonecfg/zonecfg_grammar.y
index 521953a909..4e82c75e66 100644
--- a/usr/src/cmd/zonecfg/zonecfg_grammar.y
+++ b/usr/src/cmd/zonecfg/zonecfg_grammar.y
@@ -137,7 +137,7 @@ complex_piece_func(int cp_type, const char *str, complex_property_ptr_t cp_next)
%token OPEN_PAREN CLOSE_PAREN COMMA DATASET LIMITPRIV BOOTARGS BRAND PSET PCAP
%token MCAP NCPUS IMPORTANCE SHARES MAXLWPS MAXSHMMEM MAXSHMIDS MAXMSGIDS
%token MAXSEMIDS LOCKED SWAP SCHED CLEAR DEFROUTER ADMIN USER AUTHS MAXPROCS
-%token ZFSPRI MAC VLANID GNIC NPROP
+%token ZFSPRI MAC VLANID GNIC NPROP UUID
%type <strval> TOKEN EQUAL OPEN_SQ_BRACKET CLOSE_SQ_BRACKET
property_value OPEN_PAREN CLOSE_PAREN COMMA simple_prop_val
@@ -147,7 +147,7 @@ complex_piece_func(int cp_type, const char *str, complex_property_ptr_t cp_next)
%type <ival> property_name SPECIAL RAW DIR OPTIONS TYPE ADDRESS PHYSICAL NAME
MATCH ZONENAME ZONEPATH AUTOBOOT POOL LIMITPRIV BOOTARGS VALUE PRIV LIMIT
ACTION BRAND SCHED IPTYPE DEFROUTER HOSTID USER AUTHS FS_ALLOWED
- ALLOWED_ADDRESS MAC VLANID GNIC NPROP
+ ALLOWED_ADDRESS MAC VLANID GNIC NPROP UUID
%type <cmd> command
%type <cmd> add_command ADD
%type <cmd> cancel_command CANCEL
@@ -652,6 +652,15 @@ info_command: INFO
$$->cmd_res_type = RT_FS_ALLOWED;
$$->cmd_prop_nv_pairs = 0;
}
+ | INFO UUID
+ {
+ if (($$ = alloc_cmd()) == NULL)
+ YYERROR;
+ cmd = $$;
+ $$->cmd_handler = &info_func;
+ $$->cmd_res_type = RT_UUID;
+ $$->cmd_prop_nv_pairs = 0;
+ }
| INFO ZFSPRI
{
if (($$ = alloc_cmd()) == NULL)
@@ -1014,6 +1023,7 @@ property_name: SPECIAL { $$ = PT_SPECIAL; }
| USER { $$ = PT_USER; }
| AUTHS { $$ = PT_AUTHS; }
| FS_ALLOWED { $$ = PT_FS_ALLOWED; }
+ | UUID { $$ = PT_UUID; }
| ZFSPRI { $$ = PT_ZFSPRI; }
/*
diff --git a/usr/src/cmd/zonecfg/zonecfg_lex.l b/usr/src/cmd/zonecfg/zonecfg_lex.l
index 21a48f3ec3..328a75c922 100644
--- a/usr/src/cmd/zonecfg/zonecfg_lex.l
+++ b/usr/src/cmd/zonecfg/zonecfg_lex.l
@@ -322,6 +322,9 @@ static char *create_token(char *s);
<TSTATE>fs-allowed { return FS_ALLOWED; }
<CSTATE>fs-allowed { return FS_ALLOWED; }
+<TSTATE>uuid { return UUID; }
+<CSTATE>uuid { return UUID; }
+
<TSTATE>zfs-io-priority { return ZFSPRI; }
<CSTATE>zfs-io-priority { return ZFSPRI; }
diff --git a/usr/src/cmd/zpool/zpool_main.c b/usr/src/cmd/zpool/zpool_main.c
index 572bd94ae5..1d1fb2befb 100644
--- a/usr/src/cmd/zpool/zpool_main.c
+++ b/usr/src/cmd/zpool/zpool_main.c
@@ -23,6 +23,7 @@
* Copyright (c) 2005, 2010, Oracle and/or its affiliates. All rights reserved.
* Copyright 2011 Joyent, Inc. All rights reserved.
* Copyright 2011 Nexenta Systems, Inc. All rights reserved.
+ * Copyright (c) 2011 by Delphix. All rights reserved.
*/
#include <assert.h>
@@ -66,6 +67,8 @@ static int zpool_do_online(int, char **);
static int zpool_do_offline(int, char **);
static int zpool_do_clear(int, char **);
+static int zpool_do_reguid(int, char **);
+
static int zpool_do_attach(int, char **);
static int zpool_do_detach(int, char **);
static int zpool_do_replace(int, char **);
@@ -123,7 +126,8 @@ typedef enum {
HELP_UPGRADE,
HELP_GET,
HELP_SET,
- HELP_SPLIT
+ HELP_SPLIT,
+ HELP_REGUID
} zpool_help_t;
@@ -167,6 +171,7 @@ static zpool_command_t command_table[] = {
{ "import", zpool_do_import, HELP_IMPORT },
{ "export", zpool_do_export, HELP_EXPORT },
{ "upgrade", zpool_do_upgrade, HELP_UPGRADE },
+ { "reguid", zpool_do_reguid, HELP_REGUID },
{ NULL },
{ "history", zpool_do_history, HELP_HISTORY },
{ "get", zpool_do_get, HELP_GET },
@@ -245,6 +250,8 @@ get_usage(zpool_help_t idx) {
return (gettext("\tsplit [-n] [-R altroot] [-o mntopts]\n"
"\t [-o property=value] <pool> <newpool> "
"[<device> ...]\n"));
+ case HELP_REGUID:
+ return (gettext("\treguid <pool>\n"));
}
abort();
@@ -1328,6 +1335,7 @@ show_import(nvlist_t *config)
const char *health;
uint_t vsc;
int namewidth;
+ char *comment;
verify(nvlist_lookup_string(config, ZPOOL_CONFIG_POOL_NAME,
&name) == 0);
@@ -1344,9 +1352,9 @@ show_import(nvlist_t *config)
reason = zpool_import_status(config, &msgid);
- (void) printf(gettext(" pool: %s\n"), name);
- (void) printf(gettext(" id: %llu\n"), (u_longlong_t)guid);
- (void) printf(gettext(" state: %s"), health);
+ (void) printf(gettext(" pool: %s\n"), name);
+ (void) printf(gettext(" id: %llu\n"), (u_longlong_t)guid);
+ (void) printf(gettext(" state: %s"), health);
if (pool_state == POOL_STATE_DESTROYED)
(void) printf(gettext(" (DESTROYED)"));
(void) printf("\n");
@@ -1355,58 +1363,59 @@ show_import(nvlist_t *config)
case ZPOOL_STATUS_MISSING_DEV_R:
case ZPOOL_STATUS_MISSING_DEV_NR:
case ZPOOL_STATUS_BAD_GUID_SUM:
- (void) printf(gettext("status: One or more devices are missing "
- "from the system.\n"));
+ (void) printf(gettext(" status: One or more devices are "
+ "missing from the system.\n"));
break;
case ZPOOL_STATUS_CORRUPT_LABEL_R:
case ZPOOL_STATUS_CORRUPT_LABEL_NR:
- (void) printf(gettext("status: One or more devices contains "
+ (void) printf(gettext(" status: One or more devices contains "
"corrupted data.\n"));
break;
case ZPOOL_STATUS_CORRUPT_DATA:
- (void) printf(gettext("status: The pool data is corrupted.\n"));
+ (void) printf(
+ gettext(" status: The pool data is corrupted.\n"));
break;
case ZPOOL_STATUS_OFFLINE_DEV:
- (void) printf(gettext("status: One or more devices "
+ (void) printf(gettext(" status: One or more devices "
"are offlined.\n"));
break;
case ZPOOL_STATUS_CORRUPT_POOL:
- (void) printf(gettext("status: The pool metadata is "
+ (void) printf(gettext(" status: The pool metadata is "
"corrupted.\n"));
break;
case ZPOOL_STATUS_VERSION_OLDER:
- (void) printf(gettext("status: The pool is formatted using an "
+ (void) printf(gettext(" status: The pool is formatted using an "
"older on-disk version.\n"));
break;
case ZPOOL_STATUS_VERSION_NEWER:
- (void) printf(gettext("status: The pool is formatted using an "
+ (void) printf(gettext(" status: The pool is formatted using an "
"incompatible version.\n"));
break;
case ZPOOL_STATUS_HOSTID_MISMATCH:
- (void) printf(gettext("status: The pool was last accessed by "
+ (void) printf(gettext(" status: The pool was last accessed by "
"another system.\n"));
break;
case ZPOOL_STATUS_FAULTED_DEV_R:
case ZPOOL_STATUS_FAULTED_DEV_NR:
- (void) printf(gettext("status: One or more devices are "
+ (void) printf(gettext(" status: One or more devices are "
"faulted.\n"));
break;
case ZPOOL_STATUS_BAD_LOG:
- (void) printf(gettext("status: An intent log record cannot be "
+ (void) printf(gettext(" status: An intent log record cannot be "
"read.\n"));
break;
case ZPOOL_STATUS_RESILVERING:
- (void) printf(gettext("status: One or more devices were being "
+ (void) printf(gettext(" status: One or more devices were being "
"resilvered.\n"));
break;
@@ -1422,26 +1431,26 @@ show_import(nvlist_t *config)
*/
if (vs->vs_state == VDEV_STATE_HEALTHY) {
if (reason == ZPOOL_STATUS_VERSION_OLDER)
- (void) printf(gettext("action: The pool can be "
+ (void) printf(gettext(" action: The pool can be "
"imported using its name or numeric identifier, "
"though\n\tsome features will not be available "
"without an explicit 'zpool upgrade'.\n"));
else if (reason == ZPOOL_STATUS_HOSTID_MISMATCH)
- (void) printf(gettext("action: The pool can be "
+ (void) printf(gettext(" action: The pool can be "
"imported using its name or numeric "
"identifier and\n\tthe '-f' flag.\n"));
else
- (void) printf(gettext("action: The pool can be "
+ (void) printf(gettext(" action: The pool can be "
"imported using its name or numeric "
"identifier.\n"));
} else if (vs->vs_state == VDEV_STATE_DEGRADED) {
- (void) printf(gettext("action: The pool can be imported "
+ (void) printf(gettext(" action: The pool can be imported "
"despite missing or damaged devices. The\n\tfault "
"tolerance of the pool may be compromised if imported.\n"));
} else {
switch (reason) {
case ZPOOL_STATUS_VERSION_NEWER:
- (void) printf(gettext("action: The pool cannot be "
+ (void) printf(gettext(" action: The pool cannot be "
"imported. Access the pool on a system running "
"newer\n\tsoftware, or recreate the pool from "
"backup.\n"));
@@ -1449,16 +1458,20 @@ show_import(nvlist_t *config)
case ZPOOL_STATUS_MISSING_DEV_R:
case ZPOOL_STATUS_MISSING_DEV_NR:
case ZPOOL_STATUS_BAD_GUID_SUM:
- (void) printf(gettext("action: The pool cannot be "
+ (void) printf(gettext(" action: The pool cannot be "
"imported. Attach the missing\n\tdevices and try "
"again.\n"));
break;
default:
- (void) printf(gettext("action: The pool cannot be "
+ (void) printf(gettext(" action: The pool cannot be "
"imported due to damaged devices or data.\n"));
}
}
+ /* Print the comment attached to the pool. */
+ if (nvlist_lookup_string(config, ZPOOL_CONFIG_COMMENT, &comment) == 0)
+ (void) printf(gettext("comment: %s\n"), comment);
+
/*
* If the state is "closed" or "can't open", and the aux state
* is "corrupt data":
@@ -1479,7 +1492,7 @@ show_import(nvlist_t *config)
(void) printf(gettext(" see: http://www.sun.com/msg/%s\n"),
msgid);
- (void) printf(gettext("config:\n\n"));
+ (void) printf(gettext(" config:\n\n"));
namewidth = max_width(NULL, nvroot, 0, 0);
if (namewidth < 10)
@@ -3200,6 +3213,52 @@ zpool_do_clear(int argc, char **argv)
return (ret);
}
+/*
+ * zpool reguid <pool>
+ */
+int
+zpool_do_reguid(int argc, char **argv)
+{
+ int c;
+ char *poolname;
+ zpool_handle_t *zhp;
+ int ret = 0;
+
+ /* check options */
+ while ((c = getopt(argc, argv, "")) != -1) {
+ switch (c) {
+ case '?':
+ (void) fprintf(stderr, gettext("invalid option '%c'\n"),
+ optopt);
+ usage(B_FALSE);
+ }
+ }
+
+ argc -= optind;
+ argv += optind;
+
+ /* get pool name and check number of arguments */
+ if (argc < 1) {
+ (void) fprintf(stderr, gettext("missing pool name\n"));
+ usage(B_FALSE);
+ }
+
+ if (argc > 1) {
+ (void) fprintf(stderr, gettext("too many arguments\n"));
+ usage(B_FALSE);
+ }
+
+ poolname = argv[0];
+ if ((zhp = zpool_open(g_zfs, poolname)) == NULL)
+ return (1);
+
+ ret = zpool_reguid(zhp);
+
+ zpool_close(zhp);
+ return (ret);
+}
+
+
typedef struct scrub_cbdata {
int cb_type;
int cb_argc;
diff --git a/usr/src/cmd/ztest/ztest.c b/usr/src/cmd/ztest/ztest.c
index 25d1204564..6129745ffa 100644
--- a/usr/src/cmd/ztest/ztest.c
+++ b/usr/src/cmd/ztest/ztest.c
@@ -21,6 +21,7 @@
/*
* Copyright (c) 2005, 2010, Oracle and/or its affiliates. All rights reserved.
* Copyright (c) 2011 by Delphix. All rights reserved.
+ * Copyright 2011 Nexenta Systems, Inc. All rights reserved.
*/
/*
@@ -257,6 +258,7 @@ ztest_func_t ztest_vdev_LUN_growth;
ztest_func_t ztest_vdev_add_remove;
ztest_func_t ztest_vdev_aux_add_remove;
ztest_func_t ztest_split_pool;
+ztest_func_t ztest_reguid;
uint64_t zopt_always = 0ULL * NANOSEC; /* all the time */
uint64_t zopt_incessant = 1ULL * NANOSEC / 10; /* every 1/10 second */
@@ -287,6 +289,7 @@ ztest_info_t ztest_info[] = {
{ ztest_fault_inject, 1, &zopt_sometimes },
{ ztest_ddt_repair, 1, &zopt_sometimes },
{ ztest_dmu_snapshot_hold, 1, &zopt_sometimes },
+ { ztest_reguid, 1, &zopt_sometimes },
{ ztest_spa_rename, 1, &zopt_rarely },
{ ztest_scrub, 1, &zopt_rarely },
{ ztest_dsl_dataset_promote_busy, 1, &zopt_rarely },
@@ -323,6 +326,7 @@ typedef struct ztest_shared {
uint64_t zs_vdev_aux;
uint64_t zs_alloc;
uint64_t zs_space;
+ uint64_t zs_guid;
mutex_t zs_vdev_lock;
rwlock_t zs_name_lock;
ztest_info_t zs_info[ZTEST_FUNCS];
@@ -4641,7 +4645,7 @@ ztest_ddt_repair(ztest_ds_t *zd, uint64_t id)
object = od[0].od_object;
blocksize = od[0].od_blocksize;
- pattern = spa_guid(spa) ^ dmu_objset_fsid_guid(os);
+ pattern = zs->zs_guid ^ dmu_objset_fsid_guid(os);
ASSERT(object != 0);
@@ -4712,6 +4716,31 @@ ztest_scrub(ztest_ds_t *zd, uint64_t id)
}
/*
+ * Change the guid for the pool.
+ */
+/* ARGSUSED */
+void
+ztest_reguid(ztest_ds_t *zd, uint64_t id)
+{
+ ztest_shared_t *zs = ztest_shared;
+ spa_t *spa = zs->zs_spa;
+ uint64_t orig, load;
+
+ orig = spa_guid(spa);
+ load = spa_load_guid(spa);
+ if (spa_change_guid(spa) != 0)
+ return;
+
+ if (zopt_verbose >= 3) {
+ (void) printf("Changed guid old %llu -> %llu\n",
+ (u_longlong_t)orig, (u_longlong_t)spa_guid(spa));
+ }
+
+ VERIFY3U(orig, !=, spa_guid(spa));
+ VERIFY3U(load, ==, spa_load_guid(spa));
+}
+
+/*
* Rename the pool to a different name and then rename it back.
*/
/* ARGSUSED */
@@ -5146,6 +5175,7 @@ ztest_run(ztest_shared_t *zs)
{
thread_t *tid;
spa_t *spa;
+ objset_t *os;
thread_t resume_tid;
int error;
@@ -5177,6 +5207,10 @@ ztest_run(ztest_shared_t *zs)
spa->spa_debug = B_TRUE;
zs->zs_spa = spa;
+ VERIFY3U(0, ==, dmu_objset_hold(zs->zs_pool, FTAG, &os));
+ zs->zs_guid = dmu_objset_fsid_guid(os);
+ dmu_objset_rele(os, FTAG);
+
spa->spa_dedup_ditto = 2 * ZIO_DEDUPDITTO_MIN;
/*
diff --git a/usr/src/common/bignum/bignumimpl.c b/usr/src/common/bignum/bignumimpl.c
index a608fe5b75..d2fb14a18f 100644
--- a/usr/src/common/bignum/bignumimpl.c
+++ b/usr/src/common/bignum/bignumimpl.c
@@ -1462,7 +1462,7 @@ big_sqr_vec(BIG_CHUNK_TYPE *r, BIG_CHUNK_TYPE *a, int len)
#else /* ! UMUL64 */
#if (BIG_CHUNK_SIZE != 32)
-#error Do not use 64-bit chunks without defining UMUL64
+#error "Don't use 64-bit chunks without defining UMUL64"
#endif
diff --git a/usr/src/common/zfs/zfs_prop.c b/usr/src/common/zfs/zfs_prop.c
index a595217541..5d316022aa 100644
--- a/usr/src/common/zfs/zfs_prop.c
+++ b/usr/src/common/zfs/zfs_prop.c
@@ -21,6 +21,7 @@
/*
* Copyright (c) 2005, 2010, Oracle and/or its affiliates. All rights reserved.
* Copyright (c) 2011 by Delphix. All rights reserved.
+ * Copyright (c) 2011 by Joyent, Inc. All rights reserved.
*/
/* Portions Copyright 2010 Robert Milkowski */
@@ -68,6 +69,7 @@ zfs_prop_init(void)
{ "fletcher2", ZIO_CHECKSUM_FLETCHER_2 },
{ "fletcher4", ZIO_CHECKSUM_FLETCHER_4 },
{ "sha256", ZIO_CHECKSUM_SHA256 },
+ { "noparity", ZIO_CHECKSUM_NOPARITY },
{ NULL }
};
@@ -267,7 +269,7 @@ zfs_prop_init(void)
/* default index properties */
zprop_register_index(ZFS_PROP_VERSION, "version", 0, PROP_DEFAULT,
ZFS_TYPE_FILESYSTEM | ZFS_TYPE_SNAPSHOT,
- "1 | 2 | 3 | 4 | current", "VERSION", version_table);
+ "1 | 2 | 3 | 4 | 5 | current", "VERSION", version_table);
zprop_register_index(ZFS_PROP_CANMOUNT, "canmount", ZFS_CANMOUNT_ON,
PROP_DEFAULT, ZFS_TYPE_FILESYSTEM, "on | off | noauto",
"CANMOUNT", canmount_table);
@@ -297,6 +299,8 @@ zfs_prop_init(void)
/* string properties */
zprop_register_string(ZFS_PROP_ORIGIN, "origin", NULL, PROP_READONLY,
ZFS_TYPE_FILESYSTEM | ZFS_TYPE_VOLUME, "<snapshot>", "ORIGIN");
+ zprop_register_string(ZFS_PROP_CLONES, "clones", NULL, PROP_READONLY,
+ ZFS_TYPE_SNAPSHOT, "<dataset>[,...]", "CLONES");
zprop_register_string(ZFS_PROP_MOUNTPOINT, "mountpoint", "/",
PROP_INHERIT, ZFS_TYPE_FILESYSTEM, "<path> | legacy | none",
"MOUNTPOINT");
@@ -342,6 +346,8 @@ zfs_prop_init(void)
ZFS_TYPE_FILESYSTEM | ZFS_TYPE_VOLUME, "<size>", "USEDREFRESERV");
zprop_register_number(ZFS_PROP_USERREFS, "userrefs", 0, PROP_READONLY,
ZFS_TYPE_SNAPSHOT, "<count>", "USERREFS");
+ zprop_register_number(ZFS_PROP_WRITTEN, "written", 0, PROP_READONLY,
+ ZFS_TYPE_DATASET, "<size>", "WRITTEN");
/* default number properties */
zprop_register_number(ZFS_PROP_QUOTA, "quota", 0, PROP_DEFAULT,
@@ -468,6 +474,18 @@ zfs_prop_userquota(const char *name)
}
/*
+ * Returns true if this is a valid written@ property.
+ * Note that after the @, any character is valid (eg, another @, for
+ * written@pool/fs@origin).
+ */
+boolean_t
+zfs_prop_written(const char *name)
+{
+ static const char *prefix = "written@";
+ return (strncmp(name, prefix, strlen(prefix)) == 0);
+}
+
+/*
* Tables of index types, plus functions to convert between the user view
* (strings) and internal representation (uint64_t).
*/
diff --git a/usr/src/common/zfs/zpool_prop.c b/usr/src/common/zfs/zpool_prop.c
index 988d05de6e..add5bfb3a0 100644
--- a/usr/src/common/zfs/zpool_prop.c
+++ b/usr/src/common/zfs/zpool_prop.c
@@ -20,6 +20,8 @@
*/
/*
* Copyright (c) 2007, 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.
*/
#include <sys/zio.h>
@@ -69,6 +71,8 @@ zpool_prop_init(void)
ZFS_TYPE_POOL, "<filesystem>", "BOOTFS");
zprop_register_string(ZPOOL_PROP_CACHEFILE, "cachefile", NULL,
PROP_DEFAULT, ZFS_TYPE_POOL, "<file> | none", "CACHEFILE");
+ zprop_register_string(ZPOOL_PROP_COMMENT, "comment", NULL,
+ PROP_DEFAULT, ZFS_TYPE_POOL, "<comment-string>", "COMMENT");
/* readonly number properties */
zprop_register_number(ZPOOL_PROP_SIZE, "size", 0, PROP_READONLY,
diff --git a/usr/src/head/arpa/inet.h b/usr/src/head/arpa/inet.h
index a72d573899..be7074c68e 100644
--- a/usr/src/head/arpa/inet.h
+++ b/usr/src/head/arpa/inet.h
@@ -17,10 +17,11 @@
* information: Portions Copyright [yyyy] [name of copyright owner]
*
* CDDL HEADER END
- */
-/*
+ *
* Copyright 2009 Sun Microsystems, Inc. All rights reserved.
* Use is subject to license terms.
+ *
+ * Copyright 2011 Nexenta Systems, Inc. All rights reserved.
*/
/* Copyright (c) 1983, 1984, 1985, 1986, 1987, 1988, 1989 AT&T */
@@ -56,6 +57,7 @@ extern "C" {
#ifdef __STDC__
#if !defined(_XPG4_2) || defined(__EXTENSIONS__)
extern int inet_net_pton(int, const char *, void *, size_t);
+extern boolean_t inet_matchaddr(const void *, const char *);
#endif /* !defined(_XPG4_2) || defined(__EXTENSIONS__) */
#if !defined(_XPG4_2) || defined(_XPG6) || defined(__EXTENSIONS__)
diff --git a/usr/src/lib/brand/joyent/zone/statechange.ksh b/usr/src/lib/brand/joyent/zone/statechange.ksh
index 30e3e4be13..7d7d0213a4 100644
--- a/usr/src/lib/brand/joyent/zone/statechange.ksh
+++ b/usr/src/lib/brand/joyent/zone/statechange.ksh
@@ -63,13 +63,42 @@ SNAPSHOT_DIR=root/checkpoints
#
lock_file()
{
+ local cnt=0
+ local prev_pid=0
while true; do
if (set -o noclobber; echo "$$" >$LOCKFILE) 2>/dev/null; then
trap 'rm -f $LOCKFILE; exit $?' INT TERM EXIT
break;
- else
+ fi
+
+ local hold_pid=`cat $LOCKFILE 2>/dev/null`
+
+ # the file might be gone or empty when we run the cat cmd
+ if [[ -z "$hold_pid" ]]; then
sleep 1
+ cnt=0
+ continue
+ fi
+
+ # if held by a different process, restart counter
+ if [[ $prev_pid != $hold_pid ]]; then
+ prev_pid=$hold_pid
+ cnt=0
fi
+
+ [[ $cnt == 20 || $cnt == 40 ]] && \
+ logger -p daemon.err "dlmgmtd lock file $LOCKFILE" \
+ "held by pid $hold_pid for $cnt seconds"
+
+ if [[ $cnt == 60 ]]; then
+ logger -p daemon.err "breaking dlmgmtd lock" \
+ "held by pid $hold_pid after $cnt seconds"
+ unlock_file
+ continue
+ fi
+
+ sleep 1
+ let cnt=$cnt+1
done
}
@@ -197,10 +226,7 @@ setup_net()
# Set up antispoof options
- # XXX For backwards compatibility, special handling for
- # zone named "dhcpd". Remove this check once property
- # is added to zone.
- if [[ $ZONENAME == "dhcpd" ]] || [[ $dhcp_server == "1" ]]; then
+ if [[ $dhcp_server == "1" ]] || [[ $dhcp_server == "true" ]]; then
enable_dhcp="true"
# This needs to be off for dhcp server zones
allow_ip_spoof=1
diff --git a/usr/src/lib/brand/kvm/zone/config.xml b/usr/src/lib/brand/kvm/zone/config.xml
index af9b565be2..b49f839d67 100644
--- a/usr/src/lib/brand/kvm/zone/config.xml
+++ b/usr/src/lib/brand/kvm/zone/config.xml
@@ -74,6 +74,7 @@
<privilege set="default" name="net_privaddr" />
<privilege set="default" name="net_rawaccess" ip-type="exclusive" />
<privilege set="default" name="proc_chroot" />
+ <privilege set="default" name="proc_clock_highres" />
<privilege set="default" name="sys_audit" />
<privilege set="default" name="proc_audit" />
<privilege set="default" name="proc_lock_memory" />
diff --git a/usr/src/lib/brand/kvm/zone/kinstall.ksh b/usr/src/lib/brand/kvm/zone/kinstall.ksh
index 912fbeaeb1..abd60a17b7 100755
--- a/usr/src/lib/brand/kvm/zone/kinstall.ksh
+++ b/usr/src/lib/brand/kvm/zone/kinstall.ksh
@@ -81,13 +81,16 @@ if [ ! -d ${ZROOT}/tmp ]; then
chmod 1777 ${ZROOT}/tmp
fi
-
# The dataset quota must be a number.
case $ZQUOTA in *[!0-9]*)
print -u2 "Brand error: The quota $ZQUOTA is not a number"
exit $ZONE_SUBPROC_USAGE;;
esac
+if [[ ${ZQUOTA} != "0" ]]; then
+ zfs set quota=${ZQUOTA}g ${PDS_NAME}/${bname}
+fi
+
final_setup
exit $ZONE_SUBPROC_OK
diff --git a/usr/src/lib/brand/kvm/zone/statechange.ksh b/usr/src/lib/brand/kvm/zone/statechange.ksh
index d34177da62..6efe6f3cb5 100755
--- a/usr/src/lib/brand/kvm/zone/statechange.ksh
+++ b/usr/src/lib/brand/kvm/zone/statechange.ksh
@@ -91,6 +91,7 @@ setup_net()
do
# Get simplified versions of the network config. variables.
address=$(eval echo \$_ZONECFG_net_${nic}_address)
+ dhcp_server=$(eval echo \$_ZONECFG_net_${nic}_dhcp_server)
global_nic=$(eval echo \$_ZONECFG_net_${nic}_global_nic)
mac_addr=$(eval echo \$_ZONECFG_net_${nic}_mac_addr)
vlan_id=$(eval echo \$_ZONECFG_net_${nic}_vlan_id)
@@ -198,10 +199,7 @@ setup_net()
# Set up antispoof options
- # XXX For backwards compatibility, special handling for
- # zone named "dhcpd". Remove this check once property
- # is added to zone.
- if [[ $ZONENAME == "dhcpd" ]] || [[ $dhcp_server == "1" ]]; then
+ if [[ $dhcp_server == "1" ]] || [[ $dhcp_server == "true" ]]; then
enable_dhcp="true"
# This needs to be off for dhcp server zones
allow_ip_spoof=1
diff --git a/usr/src/lib/libbe/common/be_create.c b/usr/src/lib/libbe/common/be_create.c
index 0153be3c40..48bf4ec6bf 100644
--- a/usr/src/lib/libbe/common/be_create.c
+++ b/usr/src/lib/libbe/common/be_create.c
@@ -65,6 +65,7 @@ static int be_destroy_callback(zfs_handle_t *, void *);
static int be_send_fs_callback(zfs_handle_t *, void *);
static int be_demote_callback(zfs_handle_t *, void *);
static int be_demote_find_clone_callback(zfs_handle_t *, void *);
+static int be_has_snapshot_callback(zfs_handle_t *, void *);
static int be_demote_get_one_clone(zfs_handle_t *, void *);
static int be_get_snap(char *, char **);
static int be_prep_clone_send_fs(zfs_handle_t *, be_transaction_data_t *,
@@ -386,6 +387,7 @@ be_destroy(nvlist_t *be_attrs)
be_destroy_data_t dd = { 0 };
int ret = BE_SUCCESS;
uint16_t flags = 0;
+ boolean_t bs_found = B_FALSE;
int zret;
char obe_root_ds[MAXPATHLEN];
char *mp = NULL;
@@ -469,6 +471,16 @@ be_destroy(nvlist_t *be_attrs)
return (zfs_err_to_be_err(g_zfs));
}
+ /*
+ * Check if BE has snapshots and BE_DESTROY_FLAG_SNAPSHOTS
+ * is not set.
+ */
+ (void) zfs_iter_snapshots(zhp, be_has_snapshot_callback, &bs_found);
+ if (!dd.destroy_snaps && bs_found) {
+ ZFS_CLOSE(zhp);
+ return (BE_ERR_SS_EXISTS);
+ }
+
/* Get the UUID of the global BE */
if (be_get_uuid(zfs_get_name(zhp), &dd.gz_be_uuid) != BE_SUCCESS) {
be_print_err(gettext("be_destroy: BE has no UUID (%s)\n"),
@@ -1232,6 +1244,32 @@ be_exists_callback(zpool_handle_t *zlp, void *data)
}
/*
+ * Function: be_has_snapshots_callback
+ * Description: Callback function used to find out if a BE has snapshots.
+ * Parameters:
+ * zlp - zpool_handle_t pointer to the current pool being
+ * looked at.
+ * data - be_snap_found_t pointer.
+ * Return:
+ * 1 - BE has no snapshots.
+ * 0 - BE has snapshots.
+ * Scope:
+ * Private
+ */
+static int
+be_has_snapshot_callback(zfs_handle_t *zhp, void *data)
+{
+ boolean_t *bs = data;
+ if (zfs_get_name(zhp) == NULL) {
+ zfs_close(zhp);
+ return (1);
+ }
+ *bs = B_TRUE;
+ zfs_close(zhp);
+ return (0);
+}
+
+/*
* Function: be_set_uuid
* Description: This function generates a uuid, unparses it into
* string representation, and sets that string into
@@ -2387,7 +2425,7 @@ be_send_fs_callback(zfs_handle_t *zhp, void *data)
(void) close(srpipe[0]);
/* Send dataset */
- if (zfs_send(zhp, NULL, bt->obe_snap_name, send_flags,
+ if (zfs_send(zhp, NULL, bt->obe_snap_name, &send_flags,
srpipe[1], NULL, NULL, NULL) != 0) {
_exit(1);
}
@@ -2399,7 +2437,7 @@ be_send_fs_callback(zfs_handle_t *zhp, void *data)
(void) close(srpipe[1]);
/* Receive dataset */
- if (zfs_receive(g_zfs, clone_ds, flags, srpipe[0], NULL) != 0) {
+ if (zfs_receive(g_zfs, clone_ds, &flags, srpipe[0], NULL) != 0) {
be_print_err(gettext("be_send_fs_callback: failed to "
"recv dataset (%s)\n"), clone_ds);
}
diff --git a/usr/src/lib/libdtrace/Makefile.com b/usr/src/lib/libdtrace/Makefile.com
index 5d2d85caa5..095659d9ea 100644
--- a/usr/src/lib/libdtrace/Makefile.com
+++ b/usr/src/lib/libdtrace/Makefile.com
@@ -20,7 +20,7 @@
#
#
# Copyright (c) 2003, 2010, Oracle and/or its affiliates. All rights reserved.
-#
+# Copyright (c) 2011 by Delphix. All rights reserved.
#
LIBRARY = libdtrace.a
@@ -53,6 +53,7 @@ LIBSRCS = \
dt_pcb.c \
dt_pid.c \
dt_pragma.c \
+ dt_print.c \
dt_printf.c \
dt_proc.c \
dt_provider.c \
diff --git a/usr/src/lib/libdtrace/common/dt_cc.c b/usr/src/lib/libdtrace/common/dt_cc.c
index c72cc93a8f..8b98b6d6f8 100644
--- a/usr/src/lib/libdtrace/common/dt_cc.c
+++ b/usr/src/lib/libdtrace/common/dt_cc.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) 2011 by Delphix. All rights reserved.
*/
/*
@@ -678,6 +679,51 @@ dt_action_trace(dtrace_hdl_t *dtp, dt_node_t *dnp, dtrace_stmtdesc_t *sdp)
ap->dtad_kind = DTRACEACT_DIFEXPR;
}
+/*
+ * The print() action behaves identically to trace(), except that it stores the
+ * CTF type of the argument (if present) within the DOF for the DIFEXPR action.
+ * To do this, we set the 'dtsd_strdata' to point to the fully-qualified CTF
+ * type ID for the result of the DIF action. We use the ID instead of the name
+ * to handles complex types like arrays and function pointers that can't be
+ * resolved by ctf_type_lookup(). This is later processed by
+ * dtrace_dof_create() and turned into a reference into the string table so
+ * that we can get the type information when we process the data after the
+ * fact.
+ */
+static void
+dt_action_print(dtrace_hdl_t *dtp, dt_node_t *dnp, dtrace_stmtdesc_t *sdp)
+{
+ dtrace_actdesc_t *ap = dt_stmt_action(dtp, sdp);
+ dt_node_t *dret;
+ size_t len;
+ dt_module_t *dmp;
+
+ if (dt_node_is_void(dnp->dn_args)) {
+ dnerror(dnp->dn_args, D_PRINT_VOID,
+ "print( ) may not be applied to a void expression\n");
+ }
+
+ if (dt_node_is_dynamic(dnp->dn_args)) {
+ dnerror(dnp->dn_args, D_PRINT_DYN,
+ "print( ) may not be applied to a dynamic expression\n");
+ }
+
+ dt_cg(yypcb, dnp->dn_args);
+
+ dret = yypcb->pcb_dret;
+ dmp = dt_module_lookup_by_ctf(dtp, dret->dn_ctfp);
+
+ len = snprintf(NULL, 0, "%s`%d", dmp->dm_name, dret->dn_type) + 1;
+ sdp->dtsd_strdata = dt_alloc(dtp, len);
+ if (sdp->dtsd_strdata == NULL)
+ longjmp(yypcb->pcb_jmpbuf, EDT_NOMEM);
+ (void) snprintf(sdp->dtsd_strdata, len, "%s`%d", dmp->dm_name,
+ dret->dn_type);
+
+ ap->dtad_difo = dt_as(yypcb);
+ ap->dtad_kind = DTRACEACT_DIFEXPR;
+}
+
static void
dt_action_tracemem(dtrace_hdl_t *dtp, dt_node_t *dnp, dtrace_stmtdesc_t *sdp)
{
@@ -1057,6 +1103,9 @@ 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;
diff --git a/usr/src/lib/libdtrace/common/dt_consume.c b/usr/src/lib/libdtrace/common/dt_consume.c
index 0d99a47e70..d3a554c1c6 100644
--- a/usr/src/lib/libdtrace/common/dt_consume.c
+++ b/usr/src/lib/libdtrace/common/dt_consume.c
@@ -25,6 +25,7 @@
/*
* Copyright (c) 2011, Joyent, Inc. All rights reserved.
+ * Copyright (c) 2011 by Delphix. All rights reserved.
*/
#include <stdlib.h>
@@ -1975,6 +1976,35 @@ again:
goto nextrec;
}
+ /*
+ * If this is a DIF expression, and the record has a
+ * format set, this indicates we have a CTF type name
+ * associated with the data and we should try to print
+ * it out by type.
+ */
+ if (act == DTRACEACT_DIFEXPR) {
+ const char *strdata = dt_strdata_lookup(dtp,
+ rec->dtrd_format);
+ if (strdata != NULL) {
+ n = dtrace_print(dtp, fp, strdata,
+ addr, rec->dtrd_size);
+
+ /*
+ * dtrace_print() will return -1 on
+ * error, or return the number of bytes
+ * consumed. It will return 0 if the
+ * type couldn't be determined, and we
+ * should fall through to the normal
+ * trace method.
+ */
+ if (n < 0)
+ return (-1);
+
+ if (n > 0)
+ goto nextrec;
+ }
+ }
+
nofmt:
if (act == DTRACEACT_PRINTA) {
dt_print_aggdata_t pd;
diff --git a/usr/src/lib/libdtrace/common/dt_dof.c b/usr/src/lib/libdtrace/common/dt_dof.c
index a7eb8e4d23..04c4c89cdb 100644
--- a/usr/src/lib/libdtrace/common/dt_dof.c
+++ b/usr/src/lib/libdtrace/common/dt_dof.c
@@ -21,6 +21,7 @@
/*
* Copyright (c) 2003, 2010, Oracle and/or its affiliates. All rights reserved.
+ * Copyright (c) 2011 by Delphix. All rights reserved.
*/
#include <sys/types.h>
@@ -754,16 +755,23 @@ dtrace_dof_create(dtrace_hdl_t *dtp, dtrace_prog_t *pgp, uint_t flags)
dofa[i].dofa_difo = DOF_SECIDX_NONE;
/*
- * If the first action in a statement has format data,
- * add the format string to the global string table.
+ * If the first action in a statement has string data,
+ * add the string to the global string table. This can
+ * be due either to a printf() format string
+ * (dtsd_fmtdata) or a print() type string
+ * (dtsd_strdata).
*/
if (sdp != NULL && ap == sdp->dtsd_action) {
if (sdp->dtsd_fmtdata != NULL) {
(void) dtrace_printf_format(dtp,
sdp->dtsd_fmtdata, fmt, maxfmt + 1);
strndx = dof_add_string(ddo, fmt);
- } else
+ } else if (sdp->dtsd_strdata != NULL) {
+ strndx = dof_add_string(ddo,
+ sdp->dtsd_strdata);
+ } else {
strndx = 0; /* use dtad_arg instead */
+ }
if ((next = dt_list_next(next)) != NULL)
sdp = next->ds_desc;
diff --git a/usr/src/lib/libdtrace/common/dt_errtags.h b/usr/src/lib/libdtrace/common/dt_errtags.h
index 106ee1847e..473e2addc7 100644
--- a/usr/src/lib/libdtrace/common/dt_errtags.h
+++ b/usr/src/lib/libdtrace/common/dt_errtags.h
@@ -26,6 +26,7 @@
/*
* Copyright (c) 2011, Joyent, Inc. All rights reserved.
+ * Copyright (c) 2011 by Delphix. All rights reserved.
*/
#ifndef _DT_ERRTAGS_H
@@ -189,6 +190,8 @@ typedef enum {
D_PRINTA_AGGPROTO, /* printa() aggregation mismatch */
D_TRACE_VOID, /* trace() argument has void type */
D_TRACE_DYN, /* trace() argument has dynamic type */
+ D_PRINT_VOID, /* print() argument has void type */
+ D_PRINT_DYN, /* print() argument has dynamic type */
D_TRACEMEM_ADDR, /* tracemem() address bad type */
D_TRACEMEM_SIZE, /* tracemem() size bad type */
D_TRACEMEM_ARGS, /* tracemem() illegal number of args */
diff --git a/usr/src/lib/libdtrace/common/dt_impl.h b/usr/src/lib/libdtrace/common/dt_impl.h
index 90bb70d866..7b9eb5e78b 100644
--- a/usr/src/lib/libdtrace/common/dt_impl.h
+++ b/usr/src/lib/libdtrace/common/dt_impl.h
@@ -26,6 +26,7 @@
/*
* Copyright (c) 2011, Joyent, Inc. All rights reserved.
+ * Copyright (c) 2011 by Delphix. All rights reserved.
*/
#ifndef _DT_IMPL_H
@@ -240,6 +241,8 @@ struct dtrace_hdl {
dtrace_aggdesc_t **dt_aggdesc; /* aggregation descriptions */
int dt_maxformat; /* max format ID */
void **dt_formats; /* pointer to format array */
+ int dt_maxstrdata; /* max strdata ID */
+ char **dt_strdata; /* pointer to strdata array */
dt_aggregate_t dt_aggregate; /* aggregate */
dtrace_bufdesc_t dt_buf; /* staging buffer */
struct dt_pfdict *dt_pfdict; /* dictionary of printf conversions */
@@ -418,6 +421,7 @@ struct dtrace_hdl {
#define DT_ACT_UMOD DT_ACT(26) /* umod() action */
#define DT_ACT_UADDR DT_ACT(27) /* uaddr() action */
#define DT_ACT_SETOPT DT_ACT(28) /* setopt() action */
+#define DT_ACT_PRINT DT_ACT(29) /* print() action */
/*
* Sentinel to tell freopen() to restore the saved stdout. This must not
@@ -601,6 +605,9 @@ extern void dt_aggid_destroy(dtrace_hdl_t *);
extern void *dt_format_lookup(dtrace_hdl_t *, int);
extern void dt_format_destroy(dtrace_hdl_t *);
+extern const char *dt_strdata_lookup(dtrace_hdl_t *, int);
+extern void dt_strdata_destroy(dtrace_hdl_t *);
+
extern int dt_print_quantize(dtrace_hdl_t *, FILE *,
const void *, size_t, uint64_t);
extern int dt_print_lquantize(dtrace_hdl_t *, FILE *,
diff --git a/usr/src/lib/libdtrace/common/dt_map.c b/usr/src/lib/libdtrace/common/dt_map.c
index 15361862de..8a3ce817e4 100644
--- a/usr/src/lib/libdtrace/common/dt_map.c
+++ b/usr/src/lib/libdtrace/common/dt_map.c
@@ -23,7 +23,9 @@
* Use is subject to license terms.
*/
-#pragma ident "%Z%%M% %I% %E% SMI"
+/*
+ * Copyright (c) 2011 by Delphix. All rights reserved.
+ */
#include <stdlib.h>
#include <strings.h>
@@ -35,10 +37,81 @@
#include <dt_printf.h>
static int
+dt_strdata_add(dtrace_hdl_t *dtp, dtrace_recdesc_t *rec, void ***data, int *max)
+{
+ int maxformat;
+ dtrace_fmtdesc_t fmt;
+ void *result;
+
+ if (rec->dtrd_format == 0)
+ return (0);
+
+ if (rec->dtrd_format <= *max &&
+ (*data)[rec->dtrd_format - 1] != NULL) {
+ return (0);
+ }
+
+ bzero(&fmt, sizeof (fmt));
+ fmt.dtfd_format = rec->dtrd_format;
+ fmt.dtfd_string = NULL;
+ fmt.dtfd_length = 0;
+
+ if (dt_ioctl(dtp, DTRACEIOC_FORMAT, &fmt) == -1)
+ return (dt_set_errno(dtp, errno));
+
+ if ((fmt.dtfd_string = dt_alloc(dtp, fmt.dtfd_length)) == NULL)
+ return (dt_set_errno(dtp, EDT_NOMEM));
+
+ if (dt_ioctl(dtp, DTRACEIOC_FORMAT, &fmt) == -1) {
+ free(fmt.dtfd_string);
+ return (dt_set_errno(dtp, errno));
+ }
+
+ while (rec->dtrd_format > (maxformat = *max)) {
+ int new_max = maxformat ? (maxformat << 1) : 1;
+ size_t nsize = new_max * sizeof (void *);
+ size_t osize = maxformat * sizeof (void *);
+ void **new_data = dt_zalloc(dtp, nsize);
+
+ if (new_data == NULL) {
+ dt_free(dtp, fmt.dtfd_string);
+ return (dt_set_errno(dtp, EDT_NOMEM));
+ }
+
+ bcopy(*data, new_data, osize);
+ free(*data);
+
+ *data = new_data;
+ *max = new_max;
+ }
+
+ switch (rec->dtrd_action) {
+ case DTRACEACT_DIFEXPR:
+ result = fmt.dtfd_string;
+ break;
+ case DTRACEACT_PRINTA:
+ result = dtrace_printa_create(dtp, fmt.dtfd_string);
+ dt_free(dtp, fmt.dtfd_string);
+ break;
+ default:
+ result = dtrace_printf_create(dtp, fmt.dtfd_string);
+ dt_free(dtp, fmt.dtfd_string);
+ break;
+ }
+
+ if (result == NULL)
+ return (-1);
+
+ (*data)[rec->dtrd_format - 1] = result;
+
+ return (0);
+}
+
+static int
dt_epid_add(dtrace_hdl_t *dtp, dtrace_epid_t id)
{
dtrace_id_t max;
- int rval, i, maxformat;
+ int rval, i;
dtrace_eprobedesc_t *enabled, *nenabled;
dtrace_probedesc_t *probe;
@@ -124,71 +197,23 @@ dt_epid_add(dtrace_hdl_t *dtp, dtrace_epid_t id)
}
for (i = 0; i < enabled->dtepd_nrecs; i++) {
- dtrace_fmtdesc_t fmt;
dtrace_recdesc_t *rec = &enabled->dtepd_rec[i];
- if (!DTRACEACT_ISPRINTFLIKE(rec->dtrd_action))
- continue;
-
- if (rec->dtrd_format == 0)
- continue;
-
- if (rec->dtrd_format <= dtp->dt_maxformat &&
- dtp->dt_formats[rec->dtrd_format - 1] != NULL)
- continue;
-
- bzero(&fmt, sizeof (fmt));
- fmt.dtfd_format = rec->dtrd_format;
- fmt.dtfd_string = NULL;
- fmt.dtfd_length = 0;
-
- if (dt_ioctl(dtp, DTRACEIOC_FORMAT, &fmt) == -1) {
- rval = dt_set_errno(dtp, errno);
- goto err;
- }
-
- if ((fmt.dtfd_string = malloc(fmt.dtfd_length)) == NULL) {
- rval = dt_set_errno(dtp, EDT_NOMEM);
- goto err;
- }
-
- if (dt_ioctl(dtp, DTRACEIOC_FORMAT, &fmt) == -1) {
- rval = dt_set_errno(dtp, errno);
- free(fmt.dtfd_string);
- goto err;
- }
-
- while (rec->dtrd_format > (maxformat = dtp->dt_maxformat)) {
- int new_max = maxformat ? (maxformat << 1) : 1;
- size_t nsize = new_max * sizeof (void *);
- size_t osize = maxformat * sizeof (void *);
- void **new_formats = malloc(nsize);
-
- if (new_formats == NULL) {
- rval = dt_set_errno(dtp, EDT_NOMEM);
- free(fmt.dtfd_string);
+ if (DTRACEACT_ISPRINTFLIKE(rec->dtrd_action)) {
+ if (dt_strdata_add(dtp, rec, &dtp->dt_formats,
+ &dtp->dt_maxformat) != 0) {
+ rval = -1;
+ goto err;
+ }
+ } else if (rec->dtrd_action == DTRACEACT_DIFEXPR) {
+ if (dt_strdata_add(dtp, rec,
+ (void ***)&dtp->dt_strdata,
+ &dtp->dt_maxstrdata) != 0) {
+ rval = -1;
goto err;
}
-
- bzero(new_formats, nsize);
- bcopy(dtp->dt_formats, new_formats, osize);
- free(dtp->dt_formats);
-
- dtp->dt_formats = new_formats;
- dtp->dt_maxformat = new_max;
}
- dtp->dt_formats[rec->dtrd_format - 1] =
- rec->dtrd_action == DTRACEACT_PRINTA ?
- dtrace_printa_create(dtp, fmt.dtfd_string) :
- dtrace_printf_create(dtp, fmt.dtfd_string);
-
- free(fmt.dtfd_string);
-
- if (dtp->dt_formats[rec->dtrd_format - 1] == NULL) {
- rval = -1; /* dt_errno is set for us */
- goto err;
- }
}
dtp->dt_pdesc[id] = probe;
@@ -424,3 +449,28 @@ dt_aggid_destroy(dtrace_hdl_t *dtp)
dtp->dt_aggdesc = NULL;
dtp->dt_maxagg = 0;
}
+
+const char *
+dt_strdata_lookup(dtrace_hdl_t *dtp, int idx)
+{
+ if (idx == 0 || idx > dtp->dt_maxstrdata)
+ return (NULL);
+
+ if (dtp->dt_strdata == NULL)
+ return (NULL);
+
+ return (dtp->dt_strdata[idx - 1]);
+}
+
+void
+dt_strdata_destroy(dtrace_hdl_t *dtp)
+{
+ int i;
+
+ for (i = 0; i < dtp->dt_maxstrdata; i++) {
+ free(dtp->dt_strdata[i]);
+ }
+
+ free(dtp->dt_strdata);
+ dtp->dt_strdata = NULL;
+}
diff --git a/usr/src/lib/libdtrace/common/dt_open.c b/usr/src/lib/libdtrace/common/dt_open.c
index 211ff67276..502a9d42ad 100644
--- a/usr/src/lib/libdtrace/common/dt_open.c
+++ b/usr/src/lib/libdtrace/common/dt_open.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) 2011 by Delphix. All rights reserved.
*/
#include <sys/types.h>
@@ -108,8 +109,9 @@
#define DT_VERS_1_7_1 DT_VERSION_NUMBER(1, 7, 1)
#define DT_VERS_1_8 DT_VERSION_NUMBER(1, 8, 0)
#define DT_VERS_1_8_1 DT_VERSION_NUMBER(1, 8, 1)
-#define DT_VERS_LATEST DT_VERS_1_8_1
-#define DT_VERS_STRING "Sun D 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"
const dt_version_t _dtrace_versions[] = {
DT_VERS_1_0, /* D API 1.0.0 (PSARC 2001/466) Solaris 10 FCS */
@@ -129,6 +131,7 @@ const dt_version_t _dtrace_versions[] = {
DT_VERS_1_7_1, /* D API 1.7.1 */
DT_VERS_1_8, /* D API 1.8 */
DT_VERS_1_8_1, /* D API 1.8.1 */
+ DT_VERS_1_9, /* D API 1.9 */
0
};
@@ -304,6 +307,8 @@ static const dt_ident_t _dtrace_globals[] = {
&dt_idops_type, "pid_t" },
{ "ppid", DT_IDENT_SCALAR, 0, DIF_VAR_PPID, DT_ATTR_STABCMN, DT_VERS_1_0,
&dt_idops_type, "pid_t" },
+{ "print", DT_IDENT_ACTFUNC, 0, DT_ACT_PRINT, DT_ATTR_STABCMN, DT_VERS_1_9,
+ &dt_idops_func, "void(@)" },
{ "printa", DT_IDENT_ACTFUNC, 0, DT_ACT_PRINTA, DT_ATTR_STABCMN, DT_VERS_1_0,
&dt_idops_func, "void(@, ...)" },
{ "printf", DT_IDENT_ACTFUNC, 0, DT_ACT_PRINTF, DT_ATTR_STABCMN, DT_VERS_1_0,
@@ -1357,6 +1362,7 @@ dtrace_close(dtrace_hdl_t *dtp)
dt_epid_destroy(dtp);
dt_aggid_destroy(dtp);
dt_format_destroy(dtp);
+ dt_strdata_destroy(dtp);
dt_buffered_destroy(dtp);
dt_aggregate_destroy(dtp);
free(dtp->dt_buf.dtbd_data);
diff --git a/usr/src/lib/libdtrace/common/dt_print.c b/usr/src/lib/libdtrace/common/dt_print.c
new file mode 100644
index 0000000000..5841699ad0
--- /dev/null
+++ b/usr/src/lib/libdtrace/common/dt_print.c
@@ -0,0 +1,642 @@
+/*
+ * CDDL HEADER START
+ *
+ * The contents of this file are subject to the terms of the
+ * Common Development and Distribution License (the "License").
+ * You may not use this file except in compliance with the License.
+ *
+ * You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE
+ * or http://www.opensolaris.org/os/licensing.
+ * See the License for the specific language governing permissions
+ * and limitations under the License.
+ *
+ * When distributing Covered Code, include this CDDL HEADER in each
+ * file and include the License file at usr/src/OPENSOLARIS.LICENSE.
+ * If applicable, add the following below this CDDL HEADER, with the
+ * fields enclosed by brackets "[]" replaced with your own identifying
+ * information: Portions Copyright [yyyy] [name of copyright owner]
+ *
+ * CDDL HEADER END
+ */
+/*
+ * Copyright 2009 Sun Microsystems, Inc. All rights reserved.
+ * Use is subject to license terms.
+ */
+/*
+ * Copyright (c) 2011 by Delphix. All rights reserved.
+ */
+
+/*
+ * DTrace print() action
+ *
+ * This file contains the post-processing logic for the print() action. The
+ * print action behaves identically to trace() in that it generates a
+ * DTRACEACT_DIFEXPR action, but the action argument field refers to a CTF type
+ * string stored in the DOF string table (similar to printf formats). We
+ * take the result of the trace action and post-process it in the fashion of
+ * MDB's ::print dcmd.
+ *
+ * This implementation differs from MDB's in the following ways:
+ *
+ * - We do not expose any options or flags. The behavior of print() is
+ * equivalent to "::print -tn".
+ *
+ * - MDB will display "holes" in structures (unused padding between
+ * members).
+ *
+ * - When printing arrays of structures, MDB will leave a trailing ','
+ * after the last element.
+ *
+ * - MDB will print time_t types as date and time.
+ *
+ * - MDB will detect when an enum is actually the OR of several flags,
+ * and print it out with the constituent flags separated.
+ *
+ * - For large arrays, MDB will print the first few members and then
+ * print a "..." continuation line.
+ *
+ * - MDB will break and wrap arrays at 80 columns.
+ *
+ * - MDB prints out floats and doubles by hand, as it must run in kmdb
+ * context. We're able to leverage the printf() format strings,
+ * but the result is a slightly different format.
+ */
+
+#include <sys/sysmacros.h>
+#include <strings.h>
+#include <stdlib.h>
+#include <alloca.h>
+#include <assert.h>
+#include <ctype.h>
+#include <errno.h>
+#include <limits.h>
+#include <sys/socket.h>
+#include <netdb.h>
+#include <netinet/in.h>
+#include <arpa/inet.h>
+#include <arpa/nameser.h>
+
+#include <dt_module.h>
+#include <dt_printf.h>
+#include <dt_string.h>
+#include <dt_impl.h>
+
+/* determines whether the given integer CTF encoding is a character */
+#define CTF_IS_CHAR(e) \
+ (((e).cte_format & (CTF_INT_CHAR | CTF_INT_SIGNED)) == \
+ (CTF_INT_CHAR | CTF_INT_SIGNED) && (e).cte_bits == NBBY)
+/* determines whether the given CTF kind is a struct or union */
+#define CTF_IS_STRUCTLIKE(k) \
+ ((k) == CTF_K_STRUCT || (k) == CTF_K_UNION)
+
+/*
+ * Print structure passed down recursively through printing algorithm.
+ */
+typedef struct dt_printarg {
+ caddr_t pa_addr; /* base address of trace data */
+ ctf_file_t *pa_ctfp; /* CTF container */
+ int pa_depth; /* member depth */
+ int pa_nest; /* nested array depth */
+ FILE *pa_file; /* output file */
+} dt_printarg_t;
+
+static int dt_print_member(const char *, ctf_id_t, ulong_t, int, void *);
+
+/*
+ * Safe version of ctf_type_name() that will fall back to just "<ctfid>" if it
+ * can't resolve the type.
+ */
+static void
+dt_print_type_name(ctf_file_t *ctfp, ctf_id_t id, char *buf, size_t buflen)
+{
+ if (ctf_type_name(ctfp, id, buf, buflen) == NULL)
+ (void) snprintf(buf, buflen, "<%ld>", id);
+}
+
+/*
+ * Print any necessary trailing braces for structures or unions. We don't get
+ * invoked when a struct or union ends, so we infer the need to print braces
+ * based on the depth the last time we printed something and the new depth.
+ */
+static void
+dt_print_trailing_braces(dt_printarg_t *pap, int depth)
+{
+ int d;
+
+ for (d = pap->pa_depth; d > depth; d--) {
+ (void) fprintf(pap->pa_file, "%*s}%s",
+ (d + pap->pa_nest - 1) * 4, "",
+ d == depth + 1 ? "" : "\n");
+ }
+}
+
+/*
+ * Print the appropriate amount of indentation given the current depth and
+ * array nesting.
+ */
+static void
+dt_print_indent(dt_printarg_t *pap)
+{
+ (void) fprintf(pap->pa_file, "%*s",
+ (pap->pa_depth + pap->pa_nest) * 4, "");
+}
+
+/*
+ * Print a bitfield. It's worth noting that the D compiler support for
+ * bitfields is currently broken; printing "D`user_desc_t" (pulled in by the
+ * various D provider files) will produce incorrect results compared to
+ * "genunix`user_desc_t".
+ */
+static void
+print_bitfield(dt_printarg_t *pap, ulong_t off, ctf_encoding_t *ep)
+{
+ FILE *fp = pap->pa_file;
+ caddr_t addr = pap->pa_addr + off / NBBY;
+ uint64_t mask = (1ULL << ep->cte_bits) - 1;
+ uint64_t value = 0;
+ size_t size = (ep->cte_bits + (NBBY - 1)) / NBBY;
+ uint8_t *buf = (uint8_t *)&value;
+ uint8_t shift;
+
+ /*
+ * On big-endian machines, we need to adjust the buf pointer to refer
+ * to the lowest 'size' bytes in 'value', and we need to shift based on
+ * the offset from the end of the data, not the offset of the start.
+ */
+#ifdef _BIG_ENDIAN
+ buf += sizeof (value) - size;
+ off += ep->cte_bits;
+#endif
+ bcopy(addr, buf, size);
+ shift = off % NBBY;
+
+ /*
+ * Offsets are counted from opposite ends on little- and
+ * big-endian machines.
+ */
+#ifdef _BIG_ENDIAN
+ shift = NBBY - shift;
+#endif
+
+ /*
+ * If the bits we want do not begin on a byte boundary, shift the data
+ * right so that the value is in the lowest 'cte_bits' of 'value'.
+ */
+ if (off % NBBY != 0)
+ value >>= shift;
+ value &= mask;
+
+ (void) fprintf(fp, "%#llx", (u_longlong_t)value);
+}
+
+/*
+ * Dump the contents of memory as a fixed-size integer in hex.
+ */
+static void
+dt_print_hex(FILE *fp, caddr_t addr, size_t size)
+{
+ switch (size) {
+ case sizeof (uint8_t):
+ (void) fprintf(fp, "%#x", *(uint8_t *)addr);
+ break;
+ case sizeof (uint16_t):
+ (void) fprintf(fp, "%#x", *(uint16_t *)addr);
+ break;
+ case sizeof (uint32_t):
+ (void) fprintf(fp, "%#x", *(uint32_t *)addr);
+ break;
+ case sizeof (uint64_t):
+ (void) fprintf(fp, "%#llx",
+ (unsigned long long)*(uint64_t *)addr);
+ break;
+ default:
+ (void) fprintf(fp, "<invalid size %u>", (uint_t)size);
+ }
+}
+
+/*
+ * Print an integer type. Before dumping the contents via dt_print_hex(), we
+ * first check the encoding to see if it's part of a bitfield or a character.
+ */
+static void
+dt_print_int(ctf_id_t base, ulong_t off, dt_printarg_t *pap)
+{
+ FILE *fp = pap->pa_file;
+ ctf_file_t *ctfp = pap->pa_ctfp;
+ ctf_encoding_t e;
+ size_t size;
+ caddr_t addr = pap->pa_addr + off / NBBY;
+
+ if (ctf_type_encoding(ctfp, base, &e) == CTF_ERR) {
+ (void) fprintf(fp, "<unknown encoding>");
+ return;
+ }
+
+ /*
+ * This comes from MDB - it's not clear under what circumstances this
+ * would be found.
+ */
+ if (e.cte_format & CTF_INT_VARARGS) {
+ (void) fprintf(fp, "...");
+ return;
+ }
+
+ /*
+ * We print this as a bitfield if the bit encoding indicates it's not
+ * an even power of two byte size, or is larger than 8 bytes.
+ */
+ size = e.cte_bits / NBBY;
+ if (size > 8 || (e.cte_bits % NBBY) != 0 || (size & (size - 1)) != 0) {
+ print_bitfield(pap, off, &e);
+ return;
+ }
+
+ /*
+ * If this is a character, print it out as such.
+ */
+ if (CTF_IS_CHAR(e)) {
+ char c = *(char *)addr;
+ if (isprint(c))
+ (void) fprintf(fp, "'%c'", c);
+ else if (c == 0)
+ (void) fprintf(fp, "'\\0'");
+ else
+ (void) fprintf(fp, "'\\%03o'", c);
+ return;
+ }
+
+ dt_print_hex(fp, addr, size);
+}
+
+/*
+ * Print a floating point (float, double, long double) value.
+ */
+/* ARGSUSED */
+static void
+dt_print_float(ctf_id_t base, ulong_t off, dt_printarg_t *pap)
+{
+ FILE *fp = pap->pa_file;
+ ctf_file_t *ctfp = pap->pa_ctfp;
+ ctf_encoding_t e;
+ caddr_t addr = pap->pa_addr + off / NBBY;
+
+ if (ctf_type_encoding(ctfp, base, &e) == 0) {
+ if (e.cte_format == CTF_FP_SINGLE &&
+ e.cte_bits == sizeof (float) * NBBY) {
+ (void) fprintf(fp, "%+.7e", *((float *)addr));
+ } else if (e.cte_format == CTF_FP_DOUBLE &&
+ e.cte_bits == sizeof (double) * NBBY) {
+ (void) fprintf(fp, "%+.7e", *((double *)addr));
+ } else if (e.cte_format == CTF_FP_LDOUBLE &&
+ e.cte_bits == sizeof (long double) * NBBY) {
+ (void) fprintf(fp, "%+.16LE", *((long double *)addr));
+ } else {
+ (void) fprintf(fp, "<unknown encoding>");
+ }
+ }
+}
+
+/*
+ * A pointer is printed as a fixed-size integer. This is used both for
+ * pointers and functions.
+ */
+static void
+dt_print_ptr(ctf_id_t base, ulong_t off, dt_printarg_t *pap)
+{
+ FILE *fp = pap->pa_file;
+ ctf_file_t *ctfp = pap->pa_ctfp;
+ caddr_t addr = pap->pa_addr + off / NBBY;
+ size_t size = ctf_type_size(ctfp, base);
+
+ dt_print_hex(fp, addr, size);
+}
+
+/*
+ * Print out an array. This is somewhat complex, as we must manually visit
+ * each member, and recursively invoke ctf_type_visit() for each member. If
+ * the members are non-structs, then we print them out directly:
+ *
+ * [ 0x14, 0x2e, 0 ]
+ *
+ * If they are structs, then we print out the necessary leading and trailing
+ * braces, to end up with:
+ *
+ * [
+ * type {
+ * ...
+ * },
+ * type {
+ * ...
+ * }
+ * ]
+ *
+ * We also use a heuristic to detect whether the array looks like a character
+ * array. If the encoding indicates it's a character, and we have all
+ * printable characters followed by a null byte, then we display it as a
+ * string:
+ *
+ * [ "string" ]
+ */
+static void
+dt_print_array(ctf_id_t base, ulong_t off, dt_printarg_t *pap)
+{
+ FILE *fp = pap->pa_file;
+ ctf_file_t *ctfp = pap->pa_ctfp;
+ caddr_t addr = pap->pa_addr + off / NBBY;
+ ctf_arinfo_t car;
+ ssize_t eltsize;
+ ctf_encoding_t e;
+ int i;
+ boolean_t isstring;
+ int kind;
+ ctf_id_t rtype;
+
+ if (ctf_array_info(ctfp, base, &car) == CTF_ERR) {
+ (void) fprintf(fp, "0x%p", (void *)addr);
+ return;
+ }
+
+ if ((eltsize = ctf_type_size(ctfp, car.ctr_contents)) < 0 ||
+ (rtype = ctf_type_resolve(ctfp, car.ctr_contents)) == CTF_ERR ||
+ (kind = ctf_type_kind(ctfp, rtype)) == CTF_ERR) {
+ (void) fprintf(fp, "<invalid type %lu>", car.ctr_contents);
+ return;
+ }
+
+ /* see if this looks like a string */
+ isstring = B_FALSE;
+ if (kind == CTF_K_INTEGER &&
+ ctf_type_encoding(ctfp, rtype, &e) != CTF_ERR && CTF_IS_CHAR(e)) {
+ char c;
+ for (i = 0; i < car.ctr_nelems; i++) {
+ c = *((char *)addr + eltsize * i);
+ if (!isprint(c) || c == '\0')
+ break;
+ }
+
+ if (i != car.ctr_nelems && c == '\0')
+ isstring = B_TRUE;
+ }
+
+ /*
+ * As a slight aesthetic optimization, if we are a top-level type, then
+ * don't bother printing out the brackets. This lets print("foo") look
+ * like:
+ *
+ * string "foo"
+ *
+ * As D will internally represent this as a char[256] array.
+ */
+ if (!isstring || pap->pa_depth != 0)
+ (void) fprintf(fp, "[ ");
+
+ if (isstring)
+ (void) fprintf(fp, "\"");
+
+ for (i = 0; i < car.ctr_nelems; i++) {
+ if (isstring) {
+ char c = *((char *)addr + eltsize * i);
+ if (c == '\0')
+ break;
+ (void) fprintf(fp, "%c", c);
+ } else {
+ /*
+ * Recursively invoke ctf_type_visit() on each member.
+ * We setup a new printarg struct with 'pa_nest' set to
+ * indicate that we are within a nested array.
+ */
+ dt_printarg_t pa = *pap;
+ pa.pa_nest += pap->pa_depth + 1;
+ pa.pa_depth = 0;
+ pa.pa_addr = addr + eltsize * i;
+ (void) ctf_type_visit(ctfp, car.ctr_contents,
+ dt_print_member, &pa);
+
+ dt_print_trailing_braces(&pa, 0);
+ if (i != car.ctr_nelems - 1)
+ (void) fprintf(fp, ", ");
+ else if (CTF_IS_STRUCTLIKE(kind))
+ (void) fprintf(fp, "\n");
+ }
+ }
+
+ if (isstring)
+ (void) fprintf(fp, "\"");
+
+ if (!isstring || pap->pa_depth != 0) {
+ if (CTF_IS_STRUCTLIKE(kind))
+ dt_print_indent(pap);
+ else
+ (void) fprintf(fp, " ");
+ (void) fprintf(fp, "]");
+ }
+}
+
+/*
+ * This isued by both structs and unions to print the leading brace.
+ */
+/* ARGSUSED */
+static void
+dt_print_structlike(ctf_id_t id, ulong_t off, dt_printarg_t *pap)
+{
+ (void) fprintf(pap->pa_file, "{");
+}
+
+/*
+ * For enums, we try to print the enum name, and fall back to the value if it
+ * can't be determined. We do not do any fancy flag processing like mdb.
+ */
+/* ARGSUSED */
+static void
+dt_print_enum(ctf_id_t base, ulong_t off, dt_printarg_t *pap)
+{
+ FILE *fp = pap->pa_file;
+ ctf_file_t *ctfp = pap->pa_ctfp;
+ const char *ename;
+ int value = 0;
+
+ if ((ename = ctf_enum_name(ctfp, base, value)) != NULL)
+ (void) fprintf(fp, "%s", ename);
+ else
+ (void) fprintf(fp, "%d", value);
+}
+
+/*
+ * Forward declaration. There's not much to do here without the complete
+ * type information, so just print out this fact and drive on.
+ */
+/* ARGSUSED */
+static void
+dt_print_tag(ctf_id_t base, ulong_t off, dt_printarg_t *pap)
+{
+ (void) fprintf(pap->pa_file, "<forward decl>");
+}
+
+typedef void dt_printarg_f(ctf_id_t, ulong_t, dt_printarg_t *);
+
+static dt_printarg_f *const dt_printfuncs[] = {
+ dt_print_int, /* CTF_K_INTEGER */
+ dt_print_float, /* CTF_K_FLOAT */
+ dt_print_ptr, /* CTF_K_POINTER */
+ dt_print_array, /* CTF_K_ARRAY */
+ dt_print_ptr, /* CTF_K_FUNCTION */
+ dt_print_structlike, /* CTF_K_STRUCT */
+ dt_print_structlike, /* CTF_K_UNION */
+ dt_print_enum, /* CTF_K_ENUM */
+ dt_print_tag /* CTF_K_FORWARD */
+};
+
+/*
+ * Print one member of a structure. This callback is invoked from
+ * ctf_type_visit() recursively.
+ */
+static int
+dt_print_member(const char *name, ctf_id_t id, ulong_t off, int depth,
+ void *data)
+{
+ char type[DT_TYPE_NAMELEN];
+ int kind;
+ dt_printarg_t *pap = data;
+ FILE *fp = pap->pa_file;
+ ctf_file_t *ctfp = pap->pa_ctfp;
+ boolean_t arraymember;
+ boolean_t brief;
+ ctf_encoding_t e;
+ ctf_id_t rtype;
+
+ dt_print_trailing_braces(pap, depth);
+ /*
+ * dt_print_trailing_braces() doesn't include the trailing newline; add
+ * it here if necessary.
+ */
+ if (depth < pap->pa_depth)
+ (void) fprintf(fp, "\n");
+ pap->pa_depth = depth;
+
+ if ((rtype = ctf_type_resolve(ctfp, id)) == CTF_ERR ||
+ (kind = ctf_type_kind(ctfp, rtype)) == CTF_ERR ||
+ kind < CTF_K_INTEGER || kind > CTF_K_FORWARD) {
+ dt_print_indent(pap);
+ (void) fprintf(fp, "%s = <invalid type %lu>", name, id);
+ return (0);
+ }
+
+ dt_print_type_name(ctfp, id, type, sizeof (type));
+
+ arraymember = (pap->pa_nest != 0 && depth == 0);
+ brief = (arraymember && !CTF_IS_STRUCTLIKE(kind));
+
+ if (!brief) {
+ /*
+ * If this is a direct array member and a struct (otherwise
+ * brief would be true), then print a trailing newline, as the
+ * array printing code doesn't include it because it might be a
+ * simple type.
+ */
+ if (arraymember)
+ (void) fprintf(fp, "\n");
+ dt_print_indent(pap);
+
+ /* always print the type */
+ (void) fprintf(fp, "%s", type);
+ if (name[0] != '\0') {
+ /*
+ * For aesthetics, we don't include a space between the
+ * type name and member name if the type is a pointer.
+ * This will give us "void *foo =" instead of "void *
+ * foo =". Unions also have the odd behavior that the
+ * type name is returned as "union ", with a trailing
+ * space, so we also avoid printing a space if the type
+ * name already ends with a space.
+ */
+ if (type[strlen(type) - 1] != '*' &&
+ type[strlen(type) -1] != ' ') {
+ (void) fprintf(fp, " ");
+ }
+ (void) fprintf(fp, "%s", name);
+
+ /*
+ * If this looks like a bitfield, or is an integer not
+ * aligned on a byte boundary, print the number of
+ * bits after the name.
+ */
+ if (kind == CTF_K_INTEGER &&
+ ctf_type_encoding(ctfp, id, &e) == 0) {
+ ulong_t bits = e.cte_bits;
+ ulong_t size = bits / NBBY;
+
+ if (bits % NBBY != 0 ||
+ off % NBBY != 0 ||
+ size > 8 ||
+ size != ctf_type_size(ctfp, id)) {
+ (void) fprintf(fp, " :%lu", bits);
+ }
+ }
+
+ (void) fprintf(fp, " =");
+ }
+ (void) fprintf(fp, " ");
+ }
+
+ dt_printfuncs[kind - 1](rtype, off, pap);
+
+ /* direct simple array members are not separated by newlines */
+ if (!brief)
+ (void) fprintf(fp, "\n");
+
+ return (0);
+}
+
+/*
+ * Main print function invoked by dt_consume_cpu().
+ */
+int
+dtrace_print(dtrace_hdl_t *dtp, FILE *fp, const char *typename,
+ caddr_t addr, size_t len)
+{
+ const char *s;
+ char *object;
+ dt_printarg_t pa;
+ ctf_id_t id;
+ dt_module_t *dmp;
+
+ /*
+ * Split the fully-qualified type ID (module`id). This should
+ * always be the format, but if for some reason we don't find the
+ * expected value, return 0 to fall back to the generic trace()
+ * behavior.
+ */
+ for (s = typename; *s != '\0' && *s != '`'; s++)
+ ;
+
+ if (*s != '`')
+ return (0);
+
+ object = alloca(s - typename + 1);
+ bcopy(typename, object, s - typename);
+ object[s - typename] = '\0';
+ id = atoi(s + 1);
+
+ /*
+ * Try to get the CTF kind for this id. If something has gone horribly
+ * wrong and we can't resolve the ID, bail out and let trace() do the
+ * work.
+ */
+ dmp = dt_module_lookup_by_name(dtp, object);
+ if (dmp == NULL || ctf_type_kind(dt_module_getctf(dtp, dmp),
+ id) == CTF_ERR) {
+ return (0);
+ }
+
+ /* setup the print structure and kick off the main print routine */
+ pa.pa_addr = addr;
+ pa.pa_ctfp = dt_module_getctf(dtp, dmp);
+ pa.pa_nest = 0;
+ pa.pa_depth = 0;
+ pa.pa_file = fp;
+ (void) ctf_type_visit(pa.pa_ctfp, id, dt_print_member, &pa);
+
+ dt_print_trailing_braces(&pa, 0);
+
+ return (len);
+}
diff --git a/usr/src/lib/libdtrace/common/dt_program.c b/usr/src/lib/libdtrace/common/dt_program.c
index 471e3c9096..e4f9d8dd1c 100644
--- a/usr/src/lib/libdtrace/common/dt_program.c
+++ b/usr/src/lib/libdtrace/common/dt_program.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) 2011 by Delphix. All rights reserved.
*/
#include <unistd.h>
@@ -356,6 +357,7 @@ dtrace_stmt_destroy(dtrace_hdl_t *dtp, dtrace_stmtdesc_t *sdp)
if (sdp->dtsd_fmtdata != NULL)
dt_printf_destroy(sdp->dtsd_fmtdata);
+ dt_free(dtp, sdp->dtsd_strdata);
dt_ecbdesc_release(dtp, sdp->dtsd_ecbdesc);
dt_free(dtp, sdp);
diff --git a/usr/src/lib/libdtrace/common/dtrace.h b/usr/src/lib/libdtrace/common/dtrace.h
index c1b31151da..d3031d8c4c 100644
--- a/usr/src/lib/libdtrace/common/dtrace.h
+++ b/usr/src/lib/libdtrace/common/dtrace.h
@@ -151,6 +151,7 @@ typedef struct dtrace_stmtdesc {
dtrace_actdesc_t *dtsd_action_last; /* last action in action list */
void *dtsd_aggdata; /* aggregation data */
void *dtsd_fmtdata; /* type-specific output data */
+ void *dtsd_strdata; /* type-specific string data */
void (*dtsd_callback)(); /* callback function for EPID */
void *dtsd_data; /* callback data pointer */
dtrace_attribute_t dtsd_descattr; /* probedesc attributes */
@@ -243,6 +244,18 @@ extern int dtrace_freopen(dtrace_hdl_t *, FILE *, void *,
const void *, size_t);
/*
+ * Type-specific output printing
+ *
+ * The print() action will associate a string data record that is actually the
+ * fully-qualified type name of the data traced by the DIFEXPR action. This is
+ * stored in the same 'format' record from the kernel, but we know by virtue of
+ * the fact that the action is still DIFEXPR that it is actually a reference to
+ * plain string data.
+ */
+extern int dtrace_print(dtrace_hdl_t *, FILE *, const char *,
+ caddr_t, size_t);
+
+/*
* DTrace Work Interface
*/
typedef enum {
diff --git a/usr/src/lib/libnsl/Makefile.com b/usr/src/lib/libnsl/Makefile.com
index cea06c2c54..8469102553 100644
--- a/usr/src/lib/libnsl/Makefile.com
+++ b/usr/src/lib/libnsl/Makefile.com
@@ -21,6 +21,7 @@
#
# Copyright (c) 1997, 2010, Oracle and/or its affiliates. All rights reserved.
+# Copyright 2011 Nexenta Systems, Inc. All rights reserved.
#
LIBRARY= libnsl.a
@@ -41,8 +42,8 @@ NETDIR= netdir.o
NSS= \
gethostbyname_r.o gethostent.o gethostent_r.o gethostent6.o gethostby_door.o \
-getipnodeby_door.o getipnodeby.o getrpcent.o getrpcent_r.o inet_pton.o \
-inet_ntop.o netdir_inet.o netdir_inet_sundry.o \
+getipnodeby_door.o getipnodeby.o getrpcent.o getrpcent_r.o inet_matchaddr.o \
+inet_pton.o inet_ntop.o netdir_inet.o netdir_inet_sundry.o \
parse.o getauthattr.o getprofattr.o getexecattr.o getuserattr.o getauuser.o
NETSELECT= netselect.o
diff --git a/usr/src/lib/libnsl/common/llib-lnsl b/usr/src/lib/libnsl/common/llib-lnsl
index 8e70bbd2c8..106dab70d6 100644
--- a/usr/src/lib/libnsl/common/llib-lnsl
+++ b/usr/src/lib/libnsl/common/llib-lnsl
@@ -22,6 +22,8 @@
/*
* Copyright 2009 Sun Microsystems, Inc. All rights reserved.
* Use is subject to license terms.
+ *
+ * Copyright 2011 Nexenta Systems, Inc. All rights reserved.
*/
@@ -437,6 +439,9 @@ void setrpcent(const int stay);
void endrpcent(void);
struct rpcent *getrpcent_r(struct rpcent *result, char *buffer, int buflen);
+/* inet_matchaddr.c */
+boolean_t inet_matchaddr(const void *, const char *);
+
/* inet_ntop.c */
const char *inet_ntop(int af, const void *src, char *dst, socklen_t size);
diff --git a/usr/src/lib/libnsl/common/mapfile-vers b/usr/src/lib/libnsl/common/mapfile-vers
index f150c1e905..f875cd99fc 100644
--- a/usr/src/lib/libnsl/common/mapfile-vers
+++ b/usr/src/lib/libnsl/common/mapfile-vers
@@ -20,7 +20,7 @@
#
#
# Copyright (c) 2006, 2010, Oracle and/or its affiliates. All rights reserved.
-#
+# Copyright 2011 Nexenta Systems, Inc. All rights reserved.
#
#
@@ -467,6 +467,7 @@ $endif
SYMBOL_VERSION SUNWprivate_1.5 {
global:
+ inet_matchaddr;
clnt_create_service_timed;
} SUNWprivate_1.4;
diff --git a/usr/src/lib/libnsl/nss/inet_matchaddr.c b/usr/src/lib/libnsl/nss/inet_matchaddr.c
new file mode 100644
index 0000000000..566c1ae1ad
--- /dev/null
+++ b/usr/src/lib/libnsl/nss/inet_matchaddr.c
@@ -0,0 +1,150 @@
+/*
+ * 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.
+ *
+ * Copyright 2011 Nexenta Systems, Inc. All rights reserved.
+ */
+
+/*
+ * inet_matchaddr
+ *
+ * Match IPv4 or IPv6 address provided in sa (sockaddr_in/sockaddr_in6)
+ * against standard text representation specified in name:
+ *
+ * IPv4:
+ * IPv4
+ * IPv4/netmask
+ *
+ * IPv6:
+ * [IPv6]
+ * [IPv6]/prefix
+ */
+
+#include <sys/socket.h>
+#include <sys/types.h>
+
+#include <arpa/inet.h>
+
+#include <netinet/in.h>
+
+#include <ctype.h>
+#include <err.h>
+#include <netdb.h>
+#include <stdlib.h>
+#include <strings.h>
+
+
+boolean_t
+inet_matchaddr(const void *sa, const char *name)
+{
+ boolean_t ret = B_FALSE;
+ char *lname, *mp, *p;
+ uint32_t claddr4 = 0;
+
+ if ((p = lname = strdup(name)) == NULL)
+ err(1, "strdup");
+
+ if ((mp = strchr(p, '/')) != NULL)
+ *mp++ = '\0';
+
+ switch (((struct sockaddr_in *)sa)->sin_family) {
+ case AF_INET6: {
+ char *pp;
+ int prefix6;
+ ipaddr_t ipaddr4;
+ struct in6_addr hcaddr6;
+ struct in6_addr *claddr6 =
+ &((struct sockaddr_in6 *)sa)->sin6_addr;
+
+ if (!IN6_IS_ADDR_V4MAPPED(claddr6)) {
+ /* IPv6 address */
+ if ((p = strchr(p, '[')) == NULL)
+ break;
+ p++;
+
+ if ((pp = strchr(p, ']')) == NULL)
+ break;
+ *pp = '\0';
+
+ if (inet_pton(AF_INET6, p, &hcaddr6) != 1)
+ break;
+
+ if (mp != NULL) {
+ /* Match only first prefix bits */
+ if ((prefix6 = (int)strtol(mp,
+ (char **)NULL, 10)) == 0)
+ break;
+ ret = IN6_ARE_PREFIXEDADDR_EQUAL(claddr6,
+ &hcaddr6, prefix6);
+ break;
+ } else {
+ /* No prefix, exact match */
+ ret = IN6_ARE_ADDR_EQUAL(claddr6, &hcaddr6);
+ break;
+ }
+ } else {
+ /* IPv4-mapped IPv6 address, fallthrough to IPv4 */
+ IN6_V4MAPPED_TO_IPADDR(claddr6, ipaddr4);
+ claddr4 = ntohl(ipaddr4);
+ }
+ /*FALLTHROUGH*/
+ }
+ case AF_INET: {
+ int bits, i;
+ uint32_t hcaddr4 = 0, mask4;
+
+ if (claddr4 == 0)
+ claddr4 = ntohl(
+ ((struct sockaddr_in *)sa)->sin_addr.s_addr);
+
+ for (i = 0; i < 4; i++) {
+ hcaddr4 |= (int)strtol(p, (char **)NULL, 10) <<
+ ((3 - i) * 8);
+ if ((p = strchr(p, '.')) == NULL)
+ break;
+ p++;
+ }
+
+ if (hcaddr4 == 0)
+ break;
+
+ if (mp != NULL) {
+ /* Mask is specified explicitly */
+ if ((bits = (int)strtol(mp, (char **)NULL, 10)) == 0)
+ break;
+ mask4 = bits ? ~0 << ((sizeof (struct in_addr) * NBBY)
+ - bits) : 0;
+ hcaddr4 &= mask4;
+ } else {
+ /*
+ * Use old-fashioned implicit netmasking by checking
+ * for lower-end zeroes. On the off chance we don't
+ * match any well-known prefixes, return an exact-
+ * match prefix which is misleadingly labelled as
+ * IN_CLASSE_NET.
+ */
+ if ((hcaddr4 & IN_CLASSA_HOST) == 0)
+ mask4 = IN_CLASSA_NET;
+ else if ((hcaddr4 & IN_CLASSB_HOST) == 0)
+ mask4 = IN_CLASSB_NET;
+ else if ((hcaddr4 & IN_CLASSC_HOST) == 0)
+ mask4 = IN_CLASSC_NET;
+ else
+ mask4 = IN_CLASSE_NET;
+ }
+
+ ret = ((claddr4 & mask4) == hcaddr4);
+ break;
+ }
+ }
+
+ free(lname);
+
+ return (ret);
+}
diff --git a/usr/src/lib/libsmbfs/netsmb/smbfs_api.h b/usr/src/lib/libsmbfs/netsmb/smbfs_api.h
index 8987f1a934..bc320ee8ab 100644
--- a/usr/src/lib/libsmbfs/netsmb/smbfs_api.h
+++ b/usr/src/lib/libsmbfs/netsmb/smbfs_api.h
@@ -90,7 +90,7 @@ typedef enum {
#define SMB_AT_NTLM1 4 /* NTLM (v1) */
#define SMB_AT_NTLM2 8 /* NTLMv2 */
#define SMB_AT_KRB5 0x10 /* Kerberos5 (AD) */
-#define SMB_AT_DEFAULT (SMB_AT_KRB5 | SMB_AT_NTLM2 | SMB_AT_NTLM1)
+#define SMB_AT_DEFAULT (SMB_AT_KRB5 | SMB_AT_NTLM2)
struct smb_ctx; /* anonymous here; real one in smb_lib.h */
typedef struct smb_ctx smb_ctx_t;
diff --git a/usr/src/lib/libsmbfs/smb/ntlmssp.c b/usr/src/lib/libsmbfs/smb/ntlmssp.c
index 687d91b355..5766ec835c 100644
--- a/usr/src/lib/libsmbfs/smb/ntlmssp.c
+++ b/usr/src/lib/libsmbfs/smb/ntlmssp.c
@@ -20,6 +20,7 @@
*/
/*
+ * Copyright 2011 Nexenta Systems, Inc. All rights reserved.
* Copyright (c) 2009, 2010, Oracle and/or its affiliates. All rights reserved.
*/
@@ -243,6 +244,11 @@ ntlmssp_put_type1(struct ssp_ctx *sp, struct mbdata *out_mb)
ctx->ct_hflags2 |= SMB_FLAGS2_SECURITY_SIGNATURE;
}
+ if (ctx->ct_authflags & SMB_AT_NTLM2)
+ ssp_st->ss_flags |= NTLMSSP_NEGOTIATE_EXTENDED_SESSIONSECURITY;
+ if (ctx->ct_authflags & SMB_AT_NTLM1)
+ ssp_st->ss_flags |= NTLMSSP_NEGOTIATE_LM_KEY;
+
bcopy(ntlmssp_id, &hdr.h_id, ID_SZ);
hdr.h_type = 1; /* Type 1 */
hdr.h_flags = ssp_st->ss_flags;
diff --git a/usr/src/lib/libxnet/common/mapfile-vers b/usr/src/lib/libxnet/common/mapfile-vers
index 72d7871838..a284ae3311 100644
--- a/usr/src/lib/libxnet/common/mapfile-vers
+++ b/usr/src/lib/libxnet/common/mapfile-vers
@@ -39,8 +39,13 @@ $mapfile_version 2
SYMBOL_VERSION SUNW_1.4 {
global:
- freeaddrinfo { TYPE = FUNCTION; FILTER = libsocket.so.1 };
gai_strerror { TYPE = FUNCTION; FILTER = libsocket.so.1 };
+} SUNW_1.3.1;
+
+SYMBOL_VERSION SUNW_1.3.1 {
+ global:
+ __xnet_getaddrinfo { TYPE = FUNCTION; FILTER = libsocket.so.1 };
+ freeaddrinfo { TYPE = FUNCTION; FILTER = libsocket.so.1 };
getaddrinfo { TYPE = FUNCTION; FILTER = libsocket.so.1 };
getnameinfo { TYPE = FUNCTION; FILTER = libsocket.so.1 };
inet_ntop { TYPE = FUNCTION; FILTER = libnsl.so.1 };
diff --git a/usr/src/lib/libzfs/Makefile.com b/usr/src/lib/libzfs/Makefile.com
index 77e2aa4467..44327f934b 100644
--- a/usr/src/lib/libzfs/Makefile.com
+++ b/usr/src/lib/libzfs/Makefile.com
@@ -20,6 +20,7 @@
#
#
# Copyright (c) 2005, 2010, Oracle and/or its affiliates. All rights reserved.
+# Copyright (c) 2011 by Delphix. All rights reserved.
#
LIBRARY= libzfs.a
@@ -40,8 +41,8 @@ OBJS_COMMON= \
libzfs_dataset.o \
libzfs_diff.o \
libzfs_fru.o \
- libzfs_graph.o \
libzfs_import.o \
+ libzfs_iter.o \
libzfs_mount.o \
libzfs_pool.o \
libzfs_sendrecv.o \
diff --git a/usr/src/lib/libzfs/common/libzfs.h b/usr/src/lib/libzfs/common/libzfs.h
index 6c10dec621..3f093e3767 100644
--- a/usr/src/lib/libzfs/common/libzfs.h
+++ b/usr/src/lib/libzfs/common/libzfs.h
@@ -21,8 +21,9 @@
/*
* Copyright (c) 2005, 2010, Oracle and/or its affiliates. All rights reserved.
- * Copyright 2010 Nexenta Systems, Inc. All rights reserved.
* Copyright 2011 Joyent, Inc. All rights reserved.
+ * Copyright 2011 Nexenta Systems, Inc. All rights reserved.
+ * Copyright (c) 2011 by Delphix. All rights reserved.
*/
#ifndef _LIBZFS_H
@@ -231,6 +232,7 @@ typedef struct splitflags {
*/
extern int zpool_scan(zpool_handle_t *, pool_scan_func_t);
extern int zpool_clear(zpool_handle_t *, const char *, nvlist_t *);
+extern int zpool_reguid(zpool_handle_t *);
extern int zpool_vdev_online(zpool_handle_t *, const char *, int,
vdev_state_t *);
@@ -382,6 +384,7 @@ extern void zpool_explain_recover(libzfs_handle_t *, const char *, int,
* underlying datasets, only the references to them.
*/
extern zfs_handle_t *zfs_open(libzfs_handle_t *, const char *, int);
+extern zfs_handle_t *zfs_handle_dup(zfs_handle_t *);
extern void zfs_close(zfs_handle_t *);
extern zfs_type_t zfs_get_type(const zfs_handle_t *);
extern const char *zfs_get_name(const zfs_handle_t *);
@@ -415,12 +418,20 @@ extern int zfs_prop_get_userquota_int(zfs_handle_t *zhp, const char *propname,
uint64_t *propvalue);
extern int zfs_prop_get_userquota(zfs_handle_t *zhp, const char *propname,
char *propbuf, int proplen, boolean_t literal);
+extern int zfs_prop_get_written_int(zfs_handle_t *zhp, const char *propname,
+ uint64_t *propvalue);
+extern int zfs_prop_get_written(zfs_handle_t *zhp, const char *propname,
+ char *propbuf, int proplen, boolean_t literal);
+extern int zfs_get_snapused_int(zfs_handle_t *firstsnap, zfs_handle_t *lastsnap,
+ uint64_t *usedp);
extern uint64_t zfs_prop_get_int(zfs_handle_t *, zfs_prop_t);
extern int zfs_prop_inherit(zfs_handle_t *, const char *, boolean_t);
extern const char *zfs_prop_values(zfs_prop_t);
extern int zfs_prop_is_string(zfs_prop_t prop);
extern nvlist_t *zfs_get_user_props(zfs_handle_t *);
extern nvlist_t *zfs_get_recvd_props(zfs_handle_t *);
+extern nvlist_t *zfs_get_clones_nvl(zfs_handle_t *);
+
typedef struct zprop_list {
int pl_prop;
@@ -495,6 +506,7 @@ extern int zfs_iter_dependents(zfs_handle_t *, boolean_t, zfs_iter_f, void *);
extern int zfs_iter_filesystems(zfs_handle_t *, zfs_iter_f, void *);
extern int zfs_iter_snapshots(zfs_handle_t *, zfs_iter_f, void *);
extern int zfs_iter_snapshots_sorted(zfs_handle_t *, zfs_iter_f, void *);
+extern int zfs_iter_snapspec(zfs_handle_t *, const char *, zfs_iter_f, void *);
typedef struct get_all_cb {
zfs_handle_t **cb_handles;
@@ -515,6 +527,7 @@ extern int zfs_create(libzfs_handle_t *, const char *, zfs_type_t,
extern int zfs_create_ancestors(libzfs_handle_t *, const char *);
extern int zfs_destroy(zfs_handle_t *, boolean_t);
extern int zfs_destroy_snaps(zfs_handle_t *, char *, boolean_t);
+extern int zfs_destroy_snaps_nvl(zfs_handle_t *, nvlist_t *, boolean_t);
extern int zfs_clone(zfs_handle_t *, const char *, nvlist_t *);
extern int zfs_snapshot(libzfs_handle_t *, const char *, boolean_t, nvlist_t *);
extern int zfs_rollback(zfs_handle_t *, zfs_handle_t *, boolean_t);
@@ -522,29 +535,34 @@ extern int zfs_rename(zfs_handle_t *, const char *, boolean_t);
typedef struct sendflags {
/* print informational messages (ie, -v was specified) */
- int verbose : 1;
+ boolean_t verbose;
/* recursive send (ie, -R) */
- int replicate : 1;
+ boolean_t replicate;
/* for incrementals, do all intermediate snapshots */
- int doall : 1; /* (ie, -I) */
+ boolean_t doall;
/* if dataset is a clone, do incremental from its origin */
- int fromorigin : 1;
+ boolean_t fromorigin;
/* do deduplication */
- int dedup : 1;
+ boolean_t dedup;
/* send properties (ie, -p) */
- int props : 1;
+ boolean_t props;
+
+ /* do not send (no-op, ie. -n) */
+ boolean_t dryrun;
+
+ /* parsable verbose output (ie. -P) */
+ boolean_t parsable;
} sendflags_t;
typedef boolean_t (snapfilter_cb_t)(zfs_handle_t *, void *);
-extern int zfs_send(zfs_handle_t *zhp, const char *fromsnap, const char *tosnap,
- sendflags_t flags, int outfd, snapfilter_cb_t filter_func,
- void *cb_arg, nvlist_t **debugnvp);
+extern int zfs_send(zfs_handle_t *, const char *, const char *,
+ sendflags_t *, int, snapfilter_cb_t, void *, nvlist_t **);
extern int zfs_promote(zfs_handle_t *);
extern int zfs_hold(zfs_handle_t *, const char *, const char *, boolean_t,
@@ -564,34 +582,34 @@ extern int zfs_set_fsacl(zfs_handle_t *, boolean_t, nvlist_t *);
typedef struct recvflags {
/* print informational messages (ie, -v was specified) */
- int verbose : 1;
+ boolean_t verbose;
/* the destination is a prefix, not the exact fs (ie, -d) */
- int isprefix : 1;
+ boolean_t isprefix;
/*
* Only the tail of the sent snapshot path is appended to the
* destination to determine the received snapshot name (ie, -e).
*/
- int istail : 1;
+ boolean_t istail;
/* do not actually do the recv, just check if it would work (ie, -n) */
- int dryrun : 1;
+ boolean_t dryrun;
/* rollback/destroy filesystems as necessary (eg, -F) */
- int force : 1;
+ boolean_t force;
/* set "canmount=off" on all modified filesystems */
- int canmountoff : 1;
+ boolean_t canmountoff;
/* byteswap flag is used internally; callers need not specify */
- int byteswap : 1;
+ boolean_t byteswap;
/* do not mount file systems as they are extracted (private) */
- int nomount : 1;
+ boolean_t nomount;
} recvflags_t;
-extern int zfs_receive(libzfs_handle_t *, const char *, recvflags_t,
+extern int zfs_receive(libzfs_handle_t *, const char *, recvflags_t *,
int, avl_tree_t *);
typedef enum diff_flags {
diff --git a/usr/src/lib/libzfs/common/libzfs_dataset.c b/usr/src/lib/libzfs/common/libzfs_dataset.c
index b2508895a8..43cff1f7e7 100644
--- a/usr/src/lib/libzfs/common/libzfs_dataset.c
+++ b/usr/src/lib/libzfs/common/libzfs_dataset.c
@@ -497,7 +497,7 @@ make_dataset_handle(libzfs_handle_t *hdl, const char *path)
return (zhp);
}
-static zfs_handle_t *
+zfs_handle_t *
make_dataset_handle_zc(libzfs_handle_t *hdl, zfs_cmd_t *zc)
{
zfs_handle_t *zhp = calloc(sizeof (zfs_handle_t), 1);
@@ -514,6 +514,53 @@ make_dataset_handle_zc(libzfs_handle_t *hdl, zfs_cmd_t *zc)
return (zhp);
}
+zfs_handle_t *
+zfs_handle_dup(zfs_handle_t *zhp_orig)
+{
+ zfs_handle_t *zhp = calloc(sizeof (zfs_handle_t), 1);
+
+ if (zhp == NULL)
+ return (NULL);
+
+ zhp->zfs_hdl = zhp_orig->zfs_hdl;
+ zhp->zpool_hdl = zhp_orig->zpool_hdl;
+ (void) strlcpy(zhp->zfs_name, zhp_orig->zfs_name,
+ sizeof (zhp->zfs_name));
+ zhp->zfs_type = zhp_orig->zfs_type;
+ zhp->zfs_head_type = zhp_orig->zfs_head_type;
+ zhp->zfs_dmustats = zhp_orig->zfs_dmustats;
+ if (zhp_orig->zfs_props != NULL) {
+ if (nvlist_dup(zhp_orig->zfs_props, &zhp->zfs_props, 0) != 0) {
+ (void) no_memory(zhp->zfs_hdl);
+ zfs_close(zhp);
+ return (NULL);
+ }
+ }
+ if (zhp_orig->zfs_user_props != NULL) {
+ if (nvlist_dup(zhp_orig->zfs_user_props,
+ &zhp->zfs_user_props, 0) != 0) {
+ (void) no_memory(zhp->zfs_hdl);
+ zfs_close(zhp);
+ return (NULL);
+ }
+ }
+ if (zhp_orig->zfs_recvd_props != NULL) {
+ if (nvlist_dup(zhp_orig->zfs_recvd_props,
+ &zhp->zfs_recvd_props, 0)) {
+ (void) no_memory(zhp->zfs_hdl);
+ zfs_close(zhp);
+ return (NULL);
+ }
+ }
+ zhp->zfs_mntcheck = zhp_orig->zfs_mntcheck;
+ if (zhp_orig->zfs_mntopts != NULL) {
+ zhp->zfs_mntopts = zfs_strdup(zhp_orig->zfs_hdl,
+ zhp_orig->zfs_mntopts);
+ }
+ zhp->zfs_props_table = zhp_orig->zfs_props_table;
+ return (zhp);
+}
+
/*
* Opens the given snapshot, filesystem, or volume. The 'types'
* argument is a mask of acceptable types. The function will print an
@@ -877,6 +924,12 @@ zfs_valid_proplist(libzfs_handle_t *hdl, zfs_type_t type, nvlist_t *nvl,
goto error;
}
continue;
+ } else if (prop == ZPROP_INVAL && zfs_prop_written(propname)) {
+ zfs_error_aux(hdl, dgettext(TEXT_DOMAIN,
+ "'%s' is readonly"),
+ propname);
+ (void) zfs_error(hdl, EZFS_PROPREADONLY, errbuf);
+ goto error;
}
if (prop == ZPROP_INVAL) {
@@ -1850,8 +1903,6 @@ zfs_prop_get_recvd(zfs_handle_t *zhp, const char *propname, char *propbuf,
err = zfs_prop_get(zhp, prop, propbuf, proplen,
NULL, NULL, 0, literal);
zfs_unset_recvd_props_mode(zhp, &cookie);
- } else if (zfs_prop_userquota(propname)) {
- return (-1);
} else {
nvlist_t *propval;
char *recvdval;
@@ -1866,6 +1917,120 @@ zfs_prop_get_recvd(zfs_handle_t *zhp, const char *propname, char *propbuf,
return (err == 0 ? 0 : -1);
}
+static int
+get_clones_string(zfs_handle_t *zhp, char *propbuf, size_t proplen)
+{
+ nvlist_t *value;
+ nvpair_t *pair;
+
+ value = zfs_get_clones_nvl(zhp);
+ if (value == NULL)
+ return (-1);
+
+ propbuf[0] = '\0';
+ for (pair = nvlist_next_nvpair(value, NULL); pair != NULL;
+ pair = nvlist_next_nvpair(value, pair)) {
+ if (propbuf[0] != '\0')
+ (void) strlcat(propbuf, ",", proplen);
+ (void) strlcat(propbuf, nvpair_name(pair), proplen);
+ }
+
+ return (0);
+}
+
+struct get_clones_arg {
+ uint64_t numclones;
+ nvlist_t *value;
+ const char *origin;
+ char buf[ZFS_MAXNAMELEN];
+};
+
+int
+get_clones_cb(zfs_handle_t *zhp, void *arg)
+{
+ struct get_clones_arg *gca = arg;
+
+ if (gca->numclones == 0) {
+ zfs_close(zhp);
+ return (0);
+ }
+
+ if (zfs_prop_get(zhp, ZFS_PROP_ORIGIN, gca->buf, sizeof (gca->buf),
+ NULL, NULL, 0, B_TRUE) != 0)
+ goto out;
+ if (strcmp(gca->buf, gca->origin) == 0) {
+ if (nvlist_add_boolean(gca->value, zfs_get_name(zhp)) != 0) {
+ zfs_close(zhp);
+ return (no_memory(zhp->zfs_hdl));
+ }
+ gca->numclones--;
+ }
+
+out:
+ (void) zfs_iter_children(zhp, get_clones_cb, gca);
+ zfs_close(zhp);
+ return (0);
+}
+
+nvlist_t *
+zfs_get_clones_nvl(zfs_handle_t *zhp)
+{
+ nvlist_t *nv, *value;
+
+ if (nvlist_lookup_nvlist(zhp->zfs_props,
+ zfs_prop_to_name(ZFS_PROP_CLONES), &nv) != 0) {
+ struct get_clones_arg gca;
+
+ /*
+ * if this is a snapshot, then the kernel wasn't able
+ * to get the clones. Do it by slowly iterating.
+ */
+ if (zhp->zfs_type != ZFS_TYPE_SNAPSHOT)
+ return (NULL);
+ if (nvlist_alloc(&nv, NV_UNIQUE_NAME, 0) != 0)
+ return (NULL);
+ if (nvlist_alloc(&value, NV_UNIQUE_NAME, 0) != 0) {
+ nvlist_free(nv);
+ return (NULL);
+ }
+
+ gca.numclones = zfs_prop_get_int(zhp, ZFS_PROP_NUMCLONES);
+ gca.value = value;
+ gca.origin = zhp->zfs_name;
+
+ if (gca.numclones != 0) {
+ zfs_handle_t *root;
+ char pool[ZFS_MAXNAMELEN];
+ char *cp = pool;
+
+ /* get the pool name */
+ (void) strlcpy(pool, zhp->zfs_name, sizeof (pool));
+ (void) strsep(&cp, "/@");
+ root = zfs_open(zhp->zfs_hdl, pool,
+ ZFS_TYPE_FILESYSTEM);
+
+ (void) get_clones_cb(root, &gca);
+ }
+
+ if (gca.numclones != 0 ||
+ nvlist_add_nvlist(nv, ZPROP_VALUE, value) != 0 ||
+ nvlist_add_nvlist(zhp->zfs_props,
+ zfs_prop_to_name(ZFS_PROP_CLONES), nv) != 0) {
+ nvlist_free(nv);
+ nvlist_free(value);
+ return (NULL);
+ }
+ nvlist_free(nv);
+ nvlist_free(value);
+ verify(0 == nvlist_lookup_nvlist(zhp->zfs_props,
+ zfs_prop_to_name(ZFS_PROP_CLONES), &nv));
+ }
+
+ verify(nvlist_lookup_nvlist(nv, ZPROP_VALUE, &value) == 0);
+
+ return (value);
+}
+
/*
* Retrieve a property from the given object. If 'literal' is specified, then
* numbers are left as exact values. Otherwise, numbers are converted to a
@@ -1994,6 +2159,11 @@ zfs_prop_get(zfs_handle_t *zhp, zfs_prop_t prop, char *propbuf, size_t proplen,
return (-1);
break;
+ case ZFS_PROP_CLONES:
+ if (get_clones_string(zhp, propbuf, proplen) != 0)
+ return (-1);
+ break;
+
case ZFS_PROP_QUOTA:
case ZFS_PROP_REFQUOTA:
case ZFS_PROP_RESERVATION:
@@ -2354,7 +2524,7 @@ zfs_prop_get_userquota_common(zfs_handle_t *zhp, const char *propname,
int err;
zfs_cmd_t zc = { 0 };
- (void) strncpy(zc.zc_name, zhp->zfs_name, sizeof (zc.zc_name));
+ (void) strlcpy(zc.zc_name, zhp->zfs_name, sizeof (zc.zc_name));
err = userquota_propname_decode(propname,
zfs_prop_get_int(zhp, ZFS_PROP_ZONED),
@@ -2406,144 +2576,95 @@ zfs_prop_get_userquota(zfs_handle_t *zhp, const char *propname,
return (0);
}
-/*
- * Returns the name of the given zfs handle.
- */
-const char *
-zfs_get_name(const zfs_handle_t *zhp)
+int
+zfs_prop_get_written_int(zfs_handle_t *zhp, const char *propname,
+ uint64_t *propvalue)
{
- return (zhp->zfs_name);
-}
+ int err;
+ zfs_cmd_t zc = { 0 };
+ const char *snapname;
-/*
- * Returns the type of the given zfs handle.
- */
-zfs_type_t
-zfs_get_type(const zfs_handle_t *zhp)
-{
- return (zhp->zfs_type);
-}
+ (void) strlcpy(zc.zc_name, zhp->zfs_name, sizeof (zc.zc_name));
-static int
-zfs_do_list_ioctl(zfs_handle_t *zhp, int arg, zfs_cmd_t *zc)
-{
- int rc;
- uint64_t orig_cookie;
+ snapname = strchr(propname, '@') + 1;
+ if (strchr(snapname, '@')) {
+ (void) strlcpy(zc.zc_value, snapname, sizeof (zc.zc_value));
+ } else {
+ /* snapname is the short name, append it to zhp's fsname */
+ char *cp;
+
+ (void) strlcpy(zc.zc_value, zhp->zfs_name,
+ sizeof (zc.zc_value));
+ cp = strchr(zc.zc_value, '@');
+ if (cp != NULL)
+ *cp = '\0';
+ (void) strlcat(zc.zc_value, "@", sizeof (zc.zc_value));
+ (void) strlcat(zc.zc_value, snapname, sizeof (zc.zc_value));
+ }
- orig_cookie = zc->zc_cookie;
-top:
- (void) strlcpy(zc->zc_name, zhp->zfs_name, sizeof (zc->zc_name));
- rc = ioctl(zhp->zfs_hdl->libzfs_fd, arg, zc);
+ err = ioctl(zhp->zfs_hdl->libzfs_fd, ZFS_IOC_SPACE_WRITTEN, &zc);
+ if (err)
+ return (err);
- if (rc == -1) {
- switch (errno) {
- case ENOMEM:
- /* expand nvlist memory and try again */
- if (zcmd_expand_dst_nvlist(zhp->zfs_hdl, zc) != 0) {
- zcmd_free_nvlists(zc);
- return (-1);
- }
- zc->zc_cookie = orig_cookie;
- goto top;
- /*
- * An errno value of ESRCH indicates normal completion.
- * If ENOENT is returned, then the underlying dataset
- * has been removed since we obtained the handle.
- */
- case ESRCH:
- case ENOENT:
- rc = 1;
- break;
- default:
- rc = zfs_standard_error(zhp->zfs_hdl, errno,
- dgettext(TEXT_DOMAIN,
- "cannot iterate filesystems"));
- break;
- }
- }
- return (rc);
+ *propvalue = zc.zc_cookie;
+ return (0);
}
-/*
- * Iterate over all child filesystems
- */
int
-zfs_iter_filesystems(zfs_handle_t *zhp, zfs_iter_f func, void *data)
+zfs_prop_get_written(zfs_handle_t *zhp, const char *propname,
+ char *propbuf, int proplen, boolean_t literal)
{
- zfs_cmd_t zc = { 0 };
- zfs_handle_t *nzhp;
- int ret;
-
- if (zhp->zfs_type != ZFS_TYPE_FILESYSTEM)
- return (0);
+ int err;
+ uint64_t propvalue;
- if (zcmd_alloc_dst_nvlist(zhp->zfs_hdl, &zc, 0) != 0)
- return (-1);
+ err = zfs_prop_get_written_int(zhp, propname, &propvalue);
- while ((ret = zfs_do_list_ioctl(zhp, ZFS_IOC_DATASET_LIST_NEXT,
- &zc)) == 0) {
- /*
- * Silently ignore errors, as the only plausible explanation is
- * that the pool has since been removed.
- */
- if ((nzhp = make_dataset_handle_zc(zhp->zfs_hdl,
- &zc)) == NULL) {
- continue;
- }
+ if (err)
+ return (err);
- if ((ret = func(nzhp, data)) != 0) {
- zcmd_free_nvlists(&zc);
- return (ret);
- }
+ if (literal) {
+ (void) snprintf(propbuf, proplen, "%llu", propvalue);
+ } else {
+ zfs_nicenum(propvalue, propbuf, proplen);
}
- zcmd_free_nvlists(&zc);
- return ((ret < 0) ? ret : 0);
+ return (0);
}
-/*
- * Iterate over all snapshots
- */
int
-zfs_iter_snapshots(zfs_handle_t *zhp, zfs_iter_f func, void *data)
+zfs_get_snapused_int(zfs_handle_t *firstsnap, zfs_handle_t *lastsnap,
+ uint64_t *usedp)
{
+ int err;
zfs_cmd_t zc = { 0 };
- zfs_handle_t *nzhp;
- int ret;
- if (zhp->zfs_type == ZFS_TYPE_SNAPSHOT)
- return (0);
+ (void) strlcpy(zc.zc_name, lastsnap->zfs_name, sizeof (zc.zc_name));
+ (void) strlcpy(zc.zc_value, firstsnap->zfs_name, sizeof (zc.zc_value));
- if (zcmd_alloc_dst_nvlist(zhp->zfs_hdl, &zc, 0) != 0)
- return (-1);
- while ((ret = zfs_do_list_ioctl(zhp, ZFS_IOC_SNAPSHOT_LIST_NEXT,
- &zc)) == 0) {
+ err = ioctl(lastsnap->zfs_hdl->libzfs_fd, ZFS_IOC_SPACE_SNAPS, &zc);
+ if (err)
+ return (err);
- if ((nzhp = make_dataset_handle_zc(zhp->zfs_hdl,
- &zc)) == NULL) {
- continue;
- }
+ *usedp = zc.zc_cookie;
- if ((ret = func(nzhp, data)) != 0) {
- zcmd_free_nvlists(&zc);
- return (ret);
- }
- }
- zcmd_free_nvlists(&zc);
- return ((ret < 0) ? ret : 0);
+ return (0);
}
/*
- * Iterate over all children, snapshots and filesystems
+ * Returns the name of the given zfs handle.
*/
-int
-zfs_iter_children(zfs_handle_t *zhp, zfs_iter_f func, void *data)
+const char *
+zfs_get_name(const zfs_handle_t *zhp)
{
- int ret;
-
- if ((ret = zfs_iter_filesystems(zhp, func, data)) != 0)
- return (ret);
+ return (zhp->zfs_name);
+}
- return (zfs_iter_snapshots(zhp, func, data));
+/*
+ * Returns the type of the given zfs handle.
+ */
+zfs_type_t
+zfs_get_type(const zfs_handle_t *zhp)
+{
+ return (zhp->zfs_type);
}
/*
@@ -2569,18 +2690,19 @@ is_descendant(const char *ds1, const char *ds2)
/*
* Given a complete name, return just the portion that refers to the parent.
- * Can return NULL if this is a pool.
+ * Will return -1 if there is no parent (path is just the name of the
+ * pool).
*/
static int
parent_name(const char *path, char *buf, size_t buflen)
{
- char *loc;
+ char *slashp;
- if ((loc = strrchr(path, '/')) == NULL)
- return (-1);
+ (void) strlcpy(buf, path, buflen);
- (void) strncpy(buf, path, MIN(buflen, loc - path));
- buf[loc - path] = '\0';
+ if ((slashp = strrchr(buf, '/')) == NULL)
+ return (-1);
+ *slashp = '\0';
return (0);
}
@@ -2979,9 +3101,8 @@ zfs_destroy(zfs_handle_t *zhp, boolean_t defer)
}
struct destroydata {
- char *snapname;
- boolean_t gotone;
- boolean_t closezhp;
+ nvlist_t *nvl;
+ const char *snapname;
};
static int
@@ -2990,24 +3111,19 @@ zfs_check_snap_cb(zfs_handle_t *zhp, void *arg)
struct destroydata *dd = arg;
zfs_handle_t *szhp;
char name[ZFS_MAXNAMELEN];
- boolean_t closezhp = dd->closezhp;
int rv = 0;
- (void) strlcpy(name, zhp->zfs_name, sizeof (name));
- (void) strlcat(name, "@", sizeof (name));
- (void) strlcat(name, dd->snapname, sizeof (name));
+ (void) snprintf(name, sizeof (name),
+ "%s@%s", zhp->zfs_name, dd->snapname);
szhp = make_dataset_handle(zhp->zfs_hdl, name);
if (szhp) {
- dd->gotone = B_TRUE;
+ verify(nvlist_add_boolean(dd->nvl, name) == 0);
zfs_close(szhp);
}
- dd->closezhp = B_TRUE;
- if (!dd->gotone)
- rv = zfs_iter_filesystems(zhp, zfs_check_snap_cb, arg);
- if (closezhp)
- zfs_close(zhp);
+ rv = zfs_iter_filesystems(zhp, zfs_check_snap_cb, dd);
+ zfs_close(zhp);
return (rv);
}
@@ -3017,29 +3133,45 @@ zfs_check_snap_cb(zfs_handle_t *zhp, void *arg)
int
zfs_destroy_snaps(zfs_handle_t *zhp, char *snapname, boolean_t defer)
{
- zfs_cmd_t zc = { 0 };
int ret;
struct destroydata dd = { 0 };
dd.snapname = snapname;
- (void) zfs_check_snap_cb(zhp, &dd);
+ verify(nvlist_alloc(&dd.nvl, NV_UNIQUE_NAME, 0) == 0);
+ (void) zfs_check_snap_cb(zfs_handle_dup(zhp), &dd);
- if (!dd.gotone) {
- return (zfs_standard_error_fmt(zhp->zfs_hdl, ENOENT,
+ if (nvlist_next_nvpair(dd.nvl, NULL) == NULL) {
+ ret = zfs_standard_error_fmt(zhp->zfs_hdl, ENOENT,
dgettext(TEXT_DOMAIN, "cannot destroy '%s@%s'"),
- zhp->zfs_name, snapname));
+ zhp->zfs_name, snapname);
+ } else {
+ ret = zfs_destroy_snaps_nvl(zhp, dd.nvl, defer);
}
+ nvlist_free(dd.nvl);
+ return (ret);
+}
+
+/*
+ * Destroys all the snapshots named in the nvlist. They must be underneath
+ * the zhp (either snapshots of it, or snapshots of its descendants).
+ */
+int
+zfs_destroy_snaps_nvl(zfs_handle_t *zhp, nvlist_t *snaps, boolean_t defer)
+{
+ int ret;
+ zfs_cmd_t zc = { 0 };
(void) strlcpy(zc.zc_name, zhp->zfs_name, sizeof (zc.zc_name));
- (void) strlcpy(zc.zc_value, snapname, sizeof (zc.zc_value));
+ if (zcmd_write_src_nvlist(zhp->zfs_hdl, &zc, snaps) != 0)
+ return (-1);
zc.zc_defer_destroy = defer;
- ret = zfs_ioctl(zhp->zfs_hdl, ZFS_IOC_DESTROY_SNAPS, &zc);
+ ret = zfs_ioctl(zhp->zfs_hdl, ZFS_IOC_DESTROY_SNAPS_NVL, &zc);
if (ret != 0) {
char errbuf[1024];
(void) snprintf(errbuf, sizeof (errbuf), dgettext(TEXT_DOMAIN,
- "cannot destroy '%s@%s'"), zc.zc_name, snapname);
+ "cannot destroy snapshots in %s"), zc.zc_name);
switch (errno) {
case EEXIST:
@@ -3075,7 +3207,7 @@ zfs_clone(zfs_handle_t *zhp, const char *target, nvlist_t *props)
(void) snprintf(errbuf, sizeof (errbuf), dgettext(TEXT_DOMAIN,
"cannot create '%s'"), target);
- /* validate the target name */
+ /* validate the target/clone name */
if (!zfs_validate_name(hdl, target, ZFS_TYPE_FILESYSTEM, B_TRUE))
return (zfs_error(hdl, EZFS_INVALIDNAME, errbuf));
@@ -3412,42 +3544,6 @@ zfs_rollback(zfs_handle_t *zhp, zfs_handle_t *snap, boolean_t force)
}
/*
- * Iterate over all dependents for a given dataset. This includes both
- * hierarchical dependents (children) and data dependents (snapshots and
- * clones). The bulk of the processing occurs in get_dependents() in
- * libzfs_graph.c.
- */
-int
-zfs_iter_dependents(zfs_handle_t *zhp, boolean_t allowrecursion,
- zfs_iter_f func, void *data)
-{
- char **dependents;
- size_t count;
- int i;
- zfs_handle_t *child;
- int ret = 0;
-
- if (get_dependents(zhp->zfs_hdl, allowrecursion, zhp->zfs_name,
- &dependents, &count) != 0)
- return (-1);
-
- for (i = 0; i < count; i++) {
- if ((child = make_dataset_handle(zhp->zfs_hdl,
- dependents[i])) == NULL)
- continue;
-
- if ((ret = func(child, data)) != 0)
- break;
- }
-
- for (i = 0; i < count; i++)
- free(dependents[i]);
- free(dependents);
-
- return (ret);
-}
-
-/*
* Renames the given dataset.
*/
int
@@ -3896,7 +3992,7 @@ zfs_userspace(zfs_handle_t *zhp, zfs_userquota_prop_t type,
int error;
zfs_useracct_t buf[100];
- (void) strncpy(zc.zc_name, zhp->zfs_name, sizeof (zc.zc_name));
+ (void) strlcpy(zc.zc_name, zhp->zfs_name, sizeof (zc.zc_name));
zc.zc_objset_type = type;
zc.zc_nvlist_dst = (uintptr_t)buf;
diff --git a/usr/src/lib/libzfs/common/libzfs_graph.c b/usr/src/lib/libzfs/common/libzfs_graph.c
deleted file mode 100644
index bc21c51ae2..0000000000
--- a/usr/src/lib/libzfs/common/libzfs_graph.c
+++ /dev/null
@@ -1,653 +0,0 @@
-/*
- * CDDL HEADER START
- *
- * The contents of this file are subject to the terms of the
- * Common Development and Distribution License (the "License").
- * You may not use this file except in compliance with the License.
- *
- * You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE
- * or http://www.opensolaris.org/os/licensing.
- * See the License for the specific language governing permissions
- * and limitations under the License.
- *
- * When distributing Covered Code, include this CDDL HEADER in each
- * file and include the License file at usr/src/OPENSOLARIS.LICENSE.
- * If applicable, add the following below this CDDL HEADER, with the
- * fields enclosed by brackets "[]" replaced with your own identifying
- * information: Portions Copyright [yyyy] [name of copyright owner]
- *
- * CDDL HEADER END
- */
-/*
- * Copyright 2009 Sun Microsystems, Inc. All rights reserved.
- * Use is subject to license terms.
- */
-
-/*
- * Iterate over all children of the current object. This includes the normal
- * dataset hierarchy, but also arbitrary hierarchies due to clones. We want to
- * walk all datasets in the pool, and construct a directed graph of the form:
- *
- * home
- * |
- * +----+----+
- * | |
- * v v ws
- * bar baz |
- * | |
- * v v
- * @yesterday ----> foo
- *
- * In order to construct this graph, we have to walk every dataset in the pool,
- * because the clone parent is stored as a property of the child, not the
- * parent. The parent only keeps track of the number of clones.
- *
- * In the normal case (without clones) this would be rather expensive. To avoid
- * unnecessary computation, we first try a walk of the subtree hierarchy
- * starting from the initial node. At each dataset, we construct a node in the
- * graph and an edge leading from its parent. If we don't see any snapshots
- * with a non-zero clone count, then we are finished.
- *
- * If we do find a cloned snapshot, then we finish the walk of the current
- * subtree, but indicate that we need to do a complete walk. We then perform a
- * global walk of all datasets, avoiding the subtree we already processed.
- *
- * At the end of this, we'll end up with a directed graph of all relevant (and
- * possible some irrelevant) datasets in the system. We need to both find our
- * limiting subgraph and determine a safe ordering in which to destroy the
- * datasets. We do a topological ordering of our graph starting at our target
- * dataset, and then walk the results in reverse.
- *
- * It's possible for the graph to have cycles if, for example, the user renames
- * a clone to be the parent of its origin snapshot. The user can request to
- * generate an error in this case, or ignore the cycle and continue.
- *
- * When removing datasets, we want to destroy the snapshots in chronological
- * order (because this is the most efficient method). In order to accomplish
- * this, we store the creation transaction group with each vertex and keep each
- * vertex's edges sorted according to this value. The topological sort will
- * automatically walk the snapshots in the correct order.
- */
-
-#include <assert.h>
-#include <libintl.h>
-#include <stdio.h>
-#include <stdlib.h>
-#include <string.h>
-#include <strings.h>
-#include <unistd.h>
-
-#include <libzfs.h>
-
-#include "libzfs_impl.h"
-#include "zfs_namecheck.h"
-
-#define MIN_EDGECOUNT 4
-
-/*
- * Vertex structure. Indexed by dataset name, this structure maintains a list
- * of edges to other vertices.
- */
-struct zfs_edge;
-typedef struct zfs_vertex {
- char zv_dataset[ZFS_MAXNAMELEN];
- struct zfs_vertex *zv_next;
- int zv_visited;
- uint64_t zv_txg;
- struct zfs_edge **zv_edges;
- int zv_edgecount;
- int zv_edgealloc;
-} zfs_vertex_t;
-
-enum {
- VISIT_SEEN = 1,
- VISIT_SORT_PRE,
- VISIT_SORT_POST
-};
-
-/*
- * Edge structure. Simply maintains a pointer to the destination vertex. There
- * is no need to store the source vertex, since we only use edges in the context
- * of the source vertex.
- */
-typedef struct zfs_edge {
- zfs_vertex_t *ze_dest;
- struct zfs_edge *ze_next;
-} zfs_edge_t;
-
-#define ZFS_GRAPH_SIZE 1027 /* this could be dynamic some day */
-
-/*
- * Graph structure. Vertices are maintained in a hash indexed by dataset name.
- */
-typedef struct zfs_graph {
- zfs_vertex_t **zg_hash;
- size_t zg_size;
- size_t zg_nvertex;
- const char *zg_root;
- int zg_clone_count;
-} zfs_graph_t;
-
-/*
- * Allocate a new edge pointing to the target vertex.
- */
-static zfs_edge_t *
-zfs_edge_create(libzfs_handle_t *hdl, zfs_vertex_t *dest)
-{
- zfs_edge_t *zep = zfs_alloc(hdl, sizeof (zfs_edge_t));
-
- if (zep == NULL)
- return (NULL);
-
- zep->ze_dest = dest;
-
- return (zep);
-}
-
-/*
- * Destroy an edge.
- */
-static void
-zfs_edge_destroy(zfs_edge_t *zep)
-{
- free(zep);
-}
-
-/*
- * Allocate a new vertex with the given name.
- */
-static zfs_vertex_t *
-zfs_vertex_create(libzfs_handle_t *hdl, const char *dataset)
-{
- zfs_vertex_t *zvp = zfs_alloc(hdl, sizeof (zfs_vertex_t));
-
- if (zvp == NULL)
- return (NULL);
-
- assert(strlen(dataset) < ZFS_MAXNAMELEN);
-
- (void) strlcpy(zvp->zv_dataset, dataset, sizeof (zvp->zv_dataset));
-
- if ((zvp->zv_edges = zfs_alloc(hdl,
- MIN_EDGECOUNT * sizeof (void *))) == NULL) {
- free(zvp);
- return (NULL);
- }
-
- zvp->zv_edgealloc = MIN_EDGECOUNT;
-
- return (zvp);
-}
-
-/*
- * Destroy a vertex. Frees up any associated edges.
- */
-static void
-zfs_vertex_destroy(zfs_vertex_t *zvp)
-{
- int i;
-
- for (i = 0; i < zvp->zv_edgecount; i++)
- zfs_edge_destroy(zvp->zv_edges[i]);
-
- free(zvp->zv_edges);
- free(zvp);
-}
-
-/*
- * Given a vertex, add an edge to the destination vertex.
- */
-static int
-zfs_vertex_add_edge(libzfs_handle_t *hdl, zfs_vertex_t *zvp,
- zfs_vertex_t *dest)
-{
- zfs_edge_t *zep = zfs_edge_create(hdl, dest);
-
- if (zep == NULL)
- return (-1);
-
- if (zvp->zv_edgecount == zvp->zv_edgealloc) {
- void *ptr;
-
- if ((ptr = zfs_realloc(hdl, zvp->zv_edges,
- zvp->zv_edgealloc * sizeof (void *),
- zvp->zv_edgealloc * 2 * sizeof (void *))) == NULL)
- return (-1);
-
- zvp->zv_edges = ptr;
- zvp->zv_edgealloc *= 2;
- }
-
- zvp->zv_edges[zvp->zv_edgecount++] = zep;
-
- return (0);
-}
-
-static int
-zfs_edge_compare(const void *a, const void *b)
-{
- const zfs_edge_t *ea = *((zfs_edge_t **)a);
- const zfs_edge_t *eb = *((zfs_edge_t **)b);
-
- if (ea->ze_dest->zv_txg < eb->ze_dest->zv_txg)
- return (-1);
- if (ea->ze_dest->zv_txg > eb->ze_dest->zv_txg)
- return (1);
- return (0);
-}
-
-/*
- * Sort the given vertex edges according to the creation txg of each vertex.
- */
-static void
-zfs_vertex_sort_edges(zfs_vertex_t *zvp)
-{
- if (zvp->zv_edgecount == 0)
- return;
-
- qsort(zvp->zv_edges, zvp->zv_edgecount, sizeof (void *),
- zfs_edge_compare);
-}
-
-/*
- * Construct a new graph object. We allow the size to be specified as a
- * parameter so in the future we can size the hash according to the number of
- * datasets in the pool.
- */
-static zfs_graph_t *
-zfs_graph_create(libzfs_handle_t *hdl, const char *dataset, size_t size)
-{
- zfs_graph_t *zgp = zfs_alloc(hdl, sizeof (zfs_graph_t));
-
- if (zgp == NULL)
- return (NULL);
-
- zgp->zg_size = size;
- if ((zgp->zg_hash = zfs_alloc(hdl,
- size * sizeof (zfs_vertex_t *))) == NULL) {
- free(zgp);
- return (NULL);
- }
-
- zgp->zg_root = dataset;
- zgp->zg_clone_count = 0;
-
- return (zgp);
-}
-
-/*
- * Destroy a graph object. We have to iterate over all the hash chains,
- * destroying each vertex in the process.
- */
-static void
-zfs_graph_destroy(zfs_graph_t *zgp)
-{
- int i;
- zfs_vertex_t *current, *next;
-
- for (i = 0; i < zgp->zg_size; i++) {
- current = zgp->zg_hash[i];
- while (current != NULL) {
- next = current->zv_next;
- zfs_vertex_destroy(current);
- current = next;
- }
- }
-
- free(zgp->zg_hash);
- free(zgp);
-}
-
-/*
- * Graph hash function. Classic bernstein k=33 hash function, taken from
- * usr/src/cmd/sgs/tools/common/strhash.c
- */
-static size_t
-zfs_graph_hash(zfs_graph_t *zgp, const char *str)
-{
- size_t hash = 5381;
- int c;
-
- while ((c = *str++) != 0)
- hash = ((hash << 5) + hash) + c; /* hash * 33 + c */
-
- return (hash % zgp->zg_size);
-}
-
-/*
- * Given a dataset name, finds the associated vertex, creating it if necessary.
- */
-static zfs_vertex_t *
-zfs_graph_lookup(libzfs_handle_t *hdl, zfs_graph_t *zgp, const char *dataset,
- uint64_t txg)
-{
- size_t idx = zfs_graph_hash(zgp, dataset);
- zfs_vertex_t *zvp;
-
- for (zvp = zgp->zg_hash[idx]; zvp != NULL; zvp = zvp->zv_next) {
- if (strcmp(zvp->zv_dataset, dataset) == 0) {
- if (zvp->zv_txg == 0)
- zvp->zv_txg = txg;
- return (zvp);
- }
- }
-
- if ((zvp = zfs_vertex_create(hdl, dataset)) == NULL)
- return (NULL);
-
- zvp->zv_next = zgp->zg_hash[idx];
- zvp->zv_txg = txg;
- zgp->zg_hash[idx] = zvp;
- zgp->zg_nvertex++;
-
- return (zvp);
-}
-
-/*
- * Given two dataset names, create an edge between them. For the source vertex,
- * mark 'zv_visited' to indicate that we have seen this vertex, and not simply
- * created it as a destination of another edge. If 'dest' is NULL, then this
- * is an individual vertex (i.e. the starting vertex), so don't add an edge.
- */
-static int
-zfs_graph_add(libzfs_handle_t *hdl, zfs_graph_t *zgp, const char *source,
- const char *dest, uint64_t txg)
-{
- zfs_vertex_t *svp, *dvp;
-
- if ((svp = zfs_graph_lookup(hdl, zgp, source, 0)) == NULL)
- return (-1);
- svp->zv_visited = VISIT_SEEN;
- if (dest != NULL) {
- dvp = zfs_graph_lookup(hdl, zgp, dest, txg);
- if (dvp == NULL)
- return (-1);
- if (zfs_vertex_add_edge(hdl, svp, dvp) != 0)
- return (-1);
- }
-
- return (0);
-}
-
-/*
- * Iterate over all children of the given dataset, adding any vertices
- * as necessary. Returns -1 if there was an error, or 0 otherwise.
- * This is a simple recursive algorithm - the ZFS namespace typically
- * is very flat. We manually invoke the necessary ioctl() calls to
- * avoid the overhead and additional semantics of zfs_open().
- */
-static int
-iterate_children(libzfs_handle_t *hdl, zfs_graph_t *zgp, const char *dataset)
-{
- zfs_cmd_t zc = { 0 };
- zfs_vertex_t *zvp;
-
- /*
- * Look up the source vertex, and avoid it if we've seen it before.
- */
- zvp = zfs_graph_lookup(hdl, zgp, dataset, 0);
- if (zvp == NULL)
- return (-1);
- if (zvp->zv_visited == VISIT_SEEN)
- return (0);
-
- /*
- * Iterate over all children
- */
- for ((void) strlcpy(zc.zc_name, dataset, sizeof (zc.zc_name));
- ioctl(hdl->libzfs_fd, ZFS_IOC_DATASET_LIST_NEXT, &zc) == 0;
- (void) strlcpy(zc.zc_name, dataset, sizeof (zc.zc_name))) {
- /*
- * Get statistics for this dataset, to determine the type of the
- * dataset and clone statistics. If this fails, the dataset has
- * since been removed, and we're pretty much screwed anyway.
- */
- zc.zc_objset_stats.dds_origin[0] = '\0';
- if (ioctl(hdl->libzfs_fd, ZFS_IOC_OBJSET_STATS, &zc) != 0)
- continue;
-
- if (zc.zc_objset_stats.dds_origin[0] != '\0') {
- if (zfs_graph_add(hdl, zgp,
- zc.zc_objset_stats.dds_origin, zc.zc_name,
- zc.zc_objset_stats.dds_creation_txg) != 0)
- return (-1);
- /*
- * Count origins only if they are contained in the graph
- */
- if (isa_child_of(zc.zc_objset_stats.dds_origin,
- zgp->zg_root))
- zgp->zg_clone_count--;
- }
-
- /*
- * Add an edge between the parent and the child.
- */
- if (zfs_graph_add(hdl, zgp, dataset, zc.zc_name,
- zc.zc_objset_stats.dds_creation_txg) != 0)
- return (-1);
-
- /*
- * Recursively visit child
- */
- if (iterate_children(hdl, zgp, zc.zc_name))
- return (-1);
- }
-
- /*
- * Now iterate over all snapshots.
- */
- bzero(&zc, sizeof (zc));
-
- for ((void) strlcpy(zc.zc_name, dataset, sizeof (zc.zc_name));
- ioctl(hdl->libzfs_fd, ZFS_IOC_SNAPSHOT_LIST_NEXT, &zc) == 0;
- (void) strlcpy(zc.zc_name, dataset, sizeof (zc.zc_name))) {
-
- /*
- * Get statistics for this dataset, to determine the type of the
- * dataset and clone statistics. If this fails, the dataset has
- * since been removed, and we're pretty much screwed anyway.
- */
- if (ioctl(hdl->libzfs_fd, ZFS_IOC_OBJSET_STATS, &zc) != 0)
- continue;
-
- /*
- * Add an edge between the parent and the child.
- */
- if (zfs_graph_add(hdl, zgp, dataset, zc.zc_name,
- zc.zc_objset_stats.dds_creation_txg) != 0)
- return (-1);
-
- zgp->zg_clone_count += zc.zc_objset_stats.dds_num_clones;
- }
-
- zvp->zv_visited = VISIT_SEEN;
-
- return (0);
-}
-
-/*
- * Returns false if there are no snapshots with dependent clones in this
- * subtree or if all of those clones are also in this subtree. Returns
- * true if there is an error or there are external dependents.
- */
-static boolean_t
-external_dependents(libzfs_handle_t *hdl, zfs_graph_t *zgp, const char *dataset)
-{
- zfs_cmd_t zc = { 0 };
-
- /*
- * Check whether this dataset is a clone or has clones since
- * iterate_children() only checks the children.
- */
- (void) strlcpy(zc.zc_name, dataset, sizeof (zc.zc_name));
- if (ioctl(hdl->libzfs_fd, ZFS_IOC_OBJSET_STATS, &zc) != 0)
- return (B_TRUE);
-
- if (zc.zc_objset_stats.dds_origin[0] != '\0') {
- if (zfs_graph_add(hdl, zgp,
- zc.zc_objset_stats.dds_origin, zc.zc_name,
- zc.zc_objset_stats.dds_creation_txg) != 0)
- return (B_TRUE);
- if (isa_child_of(zc.zc_objset_stats.dds_origin, dataset))
- zgp->zg_clone_count--;
- }
-
- if ((zc.zc_objset_stats.dds_num_clones) ||
- iterate_children(hdl, zgp, dataset))
- return (B_TRUE);
-
- return (zgp->zg_clone_count != 0);
-}
-
-/*
- * Construct a complete graph of all necessary vertices. First, iterate over
- * only our object's children. If no cloned snapshots are found, or all of
- * the cloned snapshots are in this subtree then return a graph of the subtree.
- * Otherwise, start at the root of the pool and iterate over all datasets.
- */
-static zfs_graph_t *
-construct_graph(libzfs_handle_t *hdl, const char *dataset)
-{
- zfs_graph_t *zgp = zfs_graph_create(hdl, dataset, ZFS_GRAPH_SIZE);
- int ret = 0;
-
- if (zgp == NULL)
- return (zgp);
-
- if ((strchr(dataset, '/') == NULL) ||
- (external_dependents(hdl, zgp, dataset))) {
- /*
- * Determine pool name and try again.
- */
- int len = strcspn(dataset, "/@") + 1;
- char *pool = zfs_alloc(hdl, len);
-
- if (pool == NULL) {
- zfs_graph_destroy(zgp);
- return (NULL);
- }
- (void) strlcpy(pool, dataset, len);
-
- if (iterate_children(hdl, zgp, pool) == -1 ||
- zfs_graph_add(hdl, zgp, pool, NULL, 0) != 0) {
- free(pool);
- zfs_graph_destroy(zgp);
- return (NULL);
- }
- free(pool);
- }
-
- if (ret == -1 || zfs_graph_add(hdl, zgp, dataset, NULL, 0) != 0) {
- zfs_graph_destroy(zgp);
- return (NULL);
- }
-
- return (zgp);
-}
-
-/*
- * Given a graph, do a recursive topological sort into the given array. This is
- * really just a depth first search, so that the deepest nodes appear first.
- * hijack the 'zv_visited' marker to avoid visiting the same vertex twice.
- */
-static int
-topo_sort(libzfs_handle_t *hdl, boolean_t allowrecursion, char **result,
- size_t *idx, zfs_vertex_t *zgv)
-{
- int i;
-
- if (zgv->zv_visited == VISIT_SORT_PRE && !allowrecursion) {
- /*
- * If we've already seen this vertex as part of our depth-first
- * search, then we have a cyclic dependency, and we must return
- * an error.
- */
- zfs_error_aux(hdl, dgettext(TEXT_DOMAIN,
- "recursive dependency at '%s'"),
- zgv->zv_dataset);
- return (zfs_error(hdl, EZFS_RECURSIVE,
- dgettext(TEXT_DOMAIN,
- "cannot determine dependent datasets")));
- } else if (zgv->zv_visited >= VISIT_SORT_PRE) {
- /*
- * If we've already processed this as part of the topological
- * sort, then don't bother doing so again.
- */
- return (0);
- }
-
- zgv->zv_visited = VISIT_SORT_PRE;
-
- /* avoid doing a search if we don't have to */
- zfs_vertex_sort_edges(zgv);
- for (i = 0; i < zgv->zv_edgecount; i++) {
- if (topo_sort(hdl, allowrecursion, result, idx,
- zgv->zv_edges[i]->ze_dest) != 0)
- return (-1);
- }
-
- /* we may have visited this in the course of the above */
- if (zgv->zv_visited == VISIT_SORT_POST)
- return (0);
-
- if ((result[*idx] = zfs_alloc(hdl,
- strlen(zgv->zv_dataset) + 1)) == NULL)
- return (-1);
-
- (void) strcpy(result[*idx], zgv->zv_dataset);
- *idx += 1;
- zgv->zv_visited = VISIT_SORT_POST;
- return (0);
-}
-
-/*
- * The only public interface for this file. Do the dirty work of constructing a
- * child list for the given object. Construct the graph, do the toplogical
- * sort, and then return the array of strings to the caller.
- *
- * The 'allowrecursion' parameter controls behavior when cycles are found. If
- * it is set, the the cycle is ignored and the results returned as if the cycle
- * did not exist. If it is not set, then the routine will generate an error if
- * a cycle is found.
- */
-int
-get_dependents(libzfs_handle_t *hdl, boolean_t allowrecursion,
- const char *dataset, char ***result, size_t *count)
-{
- zfs_graph_t *zgp;
- zfs_vertex_t *zvp;
-
- if ((zgp = construct_graph(hdl, dataset)) == NULL)
- return (-1);
-
- if ((*result = zfs_alloc(hdl,
- zgp->zg_nvertex * sizeof (char *))) == NULL) {
- zfs_graph_destroy(zgp);
- return (-1);
- }
-
- if ((zvp = zfs_graph_lookup(hdl, zgp, dataset, 0)) == NULL) {
- free(*result);
- zfs_graph_destroy(zgp);
- return (-1);
- }
-
- *count = 0;
- if (topo_sort(hdl, allowrecursion, *result, count, zvp) != 0) {
- free(*result);
- zfs_graph_destroy(zgp);
- return (-1);
- }
-
- /*
- * Get rid of the last entry, which is our starting vertex and not
- * strictly a dependent.
- */
- assert(*count > 0);
- free((*result)[*count - 1]);
- (*count)--;
-
- zfs_graph_destroy(zgp);
-
- return (0);
-}
diff --git a/usr/src/lib/libzfs/common/libzfs_impl.h b/usr/src/lib/libzfs/common/libzfs_impl.h
index c9b09a2050..b1eae47ed2 100644
--- a/usr/src/lib/libzfs/common/libzfs_impl.h
+++ b/usr/src/lib/libzfs/common/libzfs_impl.h
@@ -21,6 +21,7 @@
/*
* Copyright (c) 2005, 2010, Oracle and/or its affiliates. All rights reserved.
+ * Copyright (c) 2011 by Delphix. All rights reserved.
*/
#ifndef _LIBFS_IMPL_H
@@ -115,7 +116,7 @@ struct zpool_handle {
diskaddr_t zpool_start_block;
};
-typedef enum {
+typedef enum {
PROTO_NFS = 0,
PROTO_SMB = 1,
PROTO_END = 2
@@ -147,6 +148,7 @@ int zpool_standard_error_fmt(libzfs_handle_t *, int, const char *, ...);
int get_dependents(libzfs_handle_t *, boolean_t, const char *, char ***,
size_t *);
+zfs_handle_t *make_dataset_handle_zc(libzfs_handle_t *, zfs_cmd_t *);
int zprop_parse_value(libzfs_handle_t *, nvpair_t *, int, zfs_type_t,
diff --git a/usr/src/lib/libzfs/common/libzfs_import.c b/usr/src/lib/libzfs/common/libzfs_import.c
index e1370350fd..414aa2f747 100644
--- a/usr/src/lib/libzfs/common/libzfs_import.c
+++ b/usr/src/lib/libzfs/common/libzfs_import.c
@@ -20,6 +20,8 @@
*/
/*
* 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.
*/
/*
@@ -437,7 +439,7 @@ get_configs(libzfs_handle_t *hdl, pool_list_t *pl, boolean_t active_ok)
uint_t i, nspares, nl2cache;
boolean_t config_seen;
uint64_t best_txg;
- char *name, *hostname;
+ char *name, *hostname, *comment;
uint64_t version, guid;
uint_t children = 0;
nvlist_t **child = NULL;
@@ -526,6 +528,7 @@ get_configs(libzfs_handle_t *hdl, pool_list_t *pl, boolean_t active_ok)
* version
* pool guid
* name
+ * comment (if available)
* pool state
* hostid (if available)
* hostname (if available)
@@ -547,11 +550,24 @@ get_configs(libzfs_handle_t *hdl, pool_list_t *pl, boolean_t active_ok)
if (nvlist_add_string(config,
ZPOOL_CONFIG_POOL_NAME, name) != 0)
goto nomem;
+
+ /*
+ * COMMENT is optional, don't bail if it's not
+ * there, instead, set it to NULL.
+ */
+ if (nvlist_lookup_string(tmp,
+ ZPOOL_CONFIG_COMMENT, &comment) != 0)
+ comment = NULL;
+ else if (nvlist_add_string(config,
+ ZPOOL_CONFIG_COMMENT, comment) != 0)
+ goto nomem;
+
verify(nvlist_lookup_uint64(tmp,
ZPOOL_CONFIG_POOL_STATE, &state) == 0);
if (nvlist_add_uint64(config,
ZPOOL_CONFIG_POOL_STATE, state) != 0)
goto nomem;
+
hostid = 0;
if (nvlist_lookup_uint64(tmp,
ZPOOL_CONFIG_HOSTID, &hostid) == 0) {
diff --git a/usr/src/lib/libzfs/common/libzfs_iter.c b/usr/src/lib/libzfs/common/libzfs_iter.c
new file mode 100644
index 0000000000..212383d0e6
--- /dev/null
+++ b/usr/src/lib/libzfs/common/libzfs_iter.c
@@ -0,0 +1,462 @@
+/*
+ * CDDL HEADER START
+ *
+ * The contents of this file are subject to the terms of the
+ * Common Development and Distribution License (the "License").
+ * You may not use this file except in compliance with the License.
+ *
+ * You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE
+ * or http://www.opensolaris.org/os/licensing.
+ * See the License for the specific language governing permissions
+ * and limitations under the License.
+ *
+ * When distributing Covered Code, include this CDDL HEADER in each
+ * file and include the License file at usr/src/OPENSOLARIS.LICENSE.
+ * If applicable, add the following below this CDDL HEADER, with the
+ * fields enclosed by brackets "[]" replaced with your own identifying
+ * information: Portions Copyright [yyyy] [name of copyright owner]
+ *
+ * CDDL HEADER END
+ */
+
+/*
+ * Copyright (c) 2005, 2010, Oracle and/or its affiliates. All rights reserved.
+ * Copyright 2010 Nexenta Systems, Inc. All rights reserved.
+ * Copyright (c) 2011 by Delphix. All rights reserved.
+ */
+
+#include <stdio.h>
+#include <stdlib.h>
+#include <strings.h>
+#include <unistd.h>
+#include <stddef.h>
+#include <libintl.h>
+#include <libzfs.h>
+
+#include "libzfs_impl.h"
+
+int
+zfs_iter_clones(zfs_handle_t *zhp, zfs_iter_f func, void *data)
+{
+ nvlist_t *nvl = zfs_get_clones_nvl(zhp);
+ nvpair_t *pair;
+
+ if (nvl == NULL)
+ return (0);
+
+ for (pair = nvlist_next_nvpair(nvl, NULL); pair != NULL;
+ pair = nvlist_next_nvpair(nvl, pair)) {
+ zfs_handle_t *clone = zfs_open(zhp->zfs_hdl, nvpair_name(pair),
+ ZFS_TYPE_FILESYSTEM | ZFS_TYPE_VOLUME);
+ if (clone != NULL) {
+ int err = func(clone, data);
+ if (err != 0)
+ return (err);
+ }
+ }
+ return (0);
+}
+
+static int
+zfs_do_list_ioctl(zfs_handle_t *zhp, int arg, zfs_cmd_t *zc)
+{
+ int rc;
+ uint64_t orig_cookie;
+
+ orig_cookie = zc->zc_cookie;
+top:
+ (void) strlcpy(zc->zc_name, zhp->zfs_name, sizeof (zc->zc_name));
+ rc = ioctl(zhp->zfs_hdl->libzfs_fd, arg, zc);
+
+ if (rc == -1) {
+ switch (errno) {
+ case ENOMEM:
+ /* expand nvlist memory and try again */
+ if (zcmd_expand_dst_nvlist(zhp->zfs_hdl, zc) != 0) {
+ zcmd_free_nvlists(zc);
+ return (-1);
+ }
+ zc->zc_cookie = orig_cookie;
+ goto top;
+ /*
+ * An errno value of ESRCH indicates normal completion.
+ * If ENOENT is returned, then the underlying dataset
+ * has been removed since we obtained the handle.
+ */
+ case ESRCH:
+ case ENOENT:
+ rc = 1;
+ break;
+ default:
+ rc = zfs_standard_error(zhp->zfs_hdl, errno,
+ dgettext(TEXT_DOMAIN,
+ "cannot iterate filesystems"));
+ break;
+ }
+ }
+ return (rc);
+}
+
+/*
+ * Iterate over all child filesystems
+ */
+int
+zfs_iter_filesystems(zfs_handle_t *zhp, zfs_iter_f func, void *data)
+{
+ zfs_cmd_t zc = { 0 };
+ zfs_handle_t *nzhp;
+ int ret;
+
+ if (zhp->zfs_type != ZFS_TYPE_FILESYSTEM)
+ return (0);
+
+ if (zcmd_alloc_dst_nvlist(zhp->zfs_hdl, &zc, 0) != 0)
+ return (-1);
+
+ while ((ret = zfs_do_list_ioctl(zhp, ZFS_IOC_DATASET_LIST_NEXT,
+ &zc)) == 0) {
+ /*
+ * Silently ignore errors, as the only plausible explanation is
+ * that the pool has since been removed.
+ */
+ if ((nzhp = make_dataset_handle_zc(zhp->zfs_hdl,
+ &zc)) == NULL) {
+ continue;
+ }
+
+ if ((ret = func(nzhp, data)) != 0) {
+ zcmd_free_nvlists(&zc);
+ return (ret);
+ }
+ }
+ zcmd_free_nvlists(&zc);
+ return ((ret < 0) ? ret : 0);
+}
+
+/*
+ * Iterate over all snapshots
+ */
+int
+zfs_iter_snapshots(zfs_handle_t *zhp, zfs_iter_f func, void *data)
+{
+ zfs_cmd_t zc = { 0 };
+ zfs_handle_t *nzhp;
+ int ret;
+
+ if (zhp->zfs_type == ZFS_TYPE_SNAPSHOT)
+ return (0);
+
+ if (zcmd_alloc_dst_nvlist(zhp->zfs_hdl, &zc, 0) != 0)
+ return (-1);
+ while ((ret = zfs_do_list_ioctl(zhp, ZFS_IOC_SNAPSHOT_LIST_NEXT,
+ &zc)) == 0) {
+
+ if ((nzhp = make_dataset_handle_zc(zhp->zfs_hdl,
+ &zc)) == NULL) {
+ continue;
+ }
+
+ if ((ret = func(nzhp, data)) != 0) {
+ zcmd_free_nvlists(&zc);
+ return (ret);
+ }
+ }
+ zcmd_free_nvlists(&zc);
+ return ((ret < 0) ? ret : 0);
+}
+
+/*
+ * Routines for dealing with the sorted snapshot functionality
+ */
+typedef struct zfs_node {
+ zfs_handle_t *zn_handle;
+ avl_node_t zn_avlnode;
+} zfs_node_t;
+
+static int
+zfs_sort_snaps(zfs_handle_t *zhp, void *data)
+{
+ avl_tree_t *avl = data;
+ zfs_node_t *node;
+ zfs_node_t search;
+
+ search.zn_handle = zhp;
+ node = avl_find(avl, &search, NULL);
+ if (node) {
+ /*
+ * If this snapshot was renamed while we were creating the
+ * AVL tree, it's possible that we already inserted it under
+ * its old name. Remove the old handle before adding the new
+ * one.
+ */
+ zfs_close(node->zn_handle);
+ avl_remove(avl, node);
+ free(node);
+ }
+
+ node = zfs_alloc(zhp->zfs_hdl, sizeof (zfs_node_t));
+ node->zn_handle = zhp;
+ avl_add(avl, node);
+
+ return (0);
+}
+
+static int
+zfs_snapshot_compare(const void *larg, const void *rarg)
+{
+ zfs_handle_t *l = ((zfs_node_t *)larg)->zn_handle;
+ zfs_handle_t *r = ((zfs_node_t *)rarg)->zn_handle;
+ uint64_t lcreate, rcreate;
+
+ /*
+ * Sort them according to creation time. We use the hidden
+ * CREATETXG property to get an absolute ordering of snapshots.
+ */
+ lcreate = zfs_prop_get_int(l, ZFS_PROP_CREATETXG);
+ rcreate = zfs_prop_get_int(r, ZFS_PROP_CREATETXG);
+
+ if (lcreate < rcreate)
+ return (-1);
+ else if (lcreate > rcreate)
+ return (+1);
+ else
+ return (0);
+}
+
+int
+zfs_iter_snapshots_sorted(zfs_handle_t *zhp, zfs_iter_f callback, void *data)
+{
+ int ret = 0;
+ zfs_node_t *node;
+ avl_tree_t avl;
+ void *cookie = NULL;
+
+ avl_create(&avl, zfs_snapshot_compare,
+ sizeof (zfs_node_t), offsetof(zfs_node_t, zn_avlnode));
+
+ ret = zfs_iter_snapshots(zhp, zfs_sort_snaps, &avl);
+
+ for (node = avl_first(&avl); node != NULL; node = AVL_NEXT(&avl, node))
+ ret |= callback(node->zn_handle, data);
+
+ while ((node = avl_destroy_nodes(&avl, &cookie)) != NULL)
+ free(node);
+
+ avl_destroy(&avl);
+
+ return (ret);
+}
+
+typedef struct {
+ char *ssa_first;
+ char *ssa_last;
+ boolean_t ssa_seenfirst;
+ boolean_t ssa_seenlast;
+ zfs_iter_f ssa_func;
+ void *ssa_arg;
+} snapspec_arg_t;
+
+static int
+snapspec_cb(zfs_handle_t *zhp, void *arg) {
+ snapspec_arg_t *ssa = arg;
+ char *shortsnapname;
+ int err = 0;
+
+ if (ssa->ssa_seenlast)
+ return (0);
+ shortsnapname = zfs_strdup(zhp->zfs_hdl,
+ strchr(zfs_get_name(zhp), '@') + 1);
+
+ if (!ssa->ssa_seenfirst && strcmp(shortsnapname, ssa->ssa_first) == 0)
+ ssa->ssa_seenfirst = B_TRUE;
+
+ if (ssa->ssa_seenfirst) {
+ err = ssa->ssa_func(zhp, ssa->ssa_arg);
+ } else {
+ zfs_close(zhp);
+ }
+
+ if (strcmp(shortsnapname, ssa->ssa_last) == 0)
+ ssa->ssa_seenlast = B_TRUE;
+ free(shortsnapname);
+
+ return (err);
+}
+
+/*
+ * spec is a string like "A,B%C,D"
+ *
+ * <snaps>, where <snaps> can be:
+ * <snap> (single snapshot)
+ * <snap>%<snap> (range of snapshots, inclusive)
+ * %<snap> (range of snapshots, starting with earliest)
+ * <snap>% (range of snapshots, ending with last)
+ * % (all snapshots)
+ * <snaps>[,...] (comma separated list of the above)
+ *
+ * If a snapshot can not be opened, continue trying to open the others, but
+ * return ENOENT at the end.
+ */
+int
+zfs_iter_snapspec(zfs_handle_t *fs_zhp, const char *spec_orig,
+ zfs_iter_f func, void *arg)
+{
+ char buf[ZFS_MAXNAMELEN];
+ char *comma_separated, *cp;
+ int err = 0;
+ int ret = 0;
+
+ (void) strlcpy(buf, spec_orig, sizeof (buf));
+ cp = buf;
+
+ while ((comma_separated = strsep(&cp, ",")) != NULL) {
+ char *pct = strchr(comma_separated, '%');
+ if (pct != NULL) {
+ snapspec_arg_t ssa = { 0 };
+ ssa.ssa_func = func;
+ ssa.ssa_arg = arg;
+
+ if (pct == comma_separated)
+ ssa.ssa_seenfirst = B_TRUE;
+ else
+ ssa.ssa_first = comma_separated;
+ *pct = '\0';
+ ssa.ssa_last = pct + 1;
+
+ /*
+ * If there is a lastname specified, make sure it
+ * exists.
+ */
+ if (ssa.ssa_last[0] != '\0') {
+ char snapname[ZFS_MAXNAMELEN];
+ (void) snprintf(snapname, sizeof (snapname),
+ "%s@%s", zfs_get_name(fs_zhp),
+ ssa.ssa_last);
+ if (!zfs_dataset_exists(fs_zhp->zfs_hdl,
+ snapname, ZFS_TYPE_SNAPSHOT)) {
+ ret = ENOENT;
+ continue;
+ }
+ }
+
+ err = zfs_iter_snapshots_sorted(fs_zhp,
+ snapspec_cb, &ssa);
+ if (ret == 0)
+ ret = err;
+ if (ret == 0 && (!ssa.ssa_seenfirst ||
+ (ssa.ssa_last[0] != '\0' && !ssa.ssa_seenlast))) {
+ ret = ENOENT;
+ }
+ } else {
+ char snapname[ZFS_MAXNAMELEN];
+ zfs_handle_t *snap_zhp;
+ (void) snprintf(snapname, sizeof (snapname), "%s@%s",
+ zfs_get_name(fs_zhp), comma_separated);
+ snap_zhp = make_dataset_handle(fs_zhp->zfs_hdl,
+ snapname);
+ if (snap_zhp == NULL) {
+ ret = ENOENT;
+ continue;
+ }
+ err = func(snap_zhp, arg);
+ if (ret == 0)
+ ret = err;
+ }
+ }
+
+ return (ret);
+}
+
+/*
+ * Iterate over all children, snapshots and filesystems
+ */
+int
+zfs_iter_children(zfs_handle_t *zhp, zfs_iter_f func, void *data)
+{
+ int ret;
+
+ if ((ret = zfs_iter_filesystems(zhp, func, data)) != 0)
+ return (ret);
+
+ return (zfs_iter_snapshots(zhp, func, data));
+}
+
+
+typedef struct iter_stack_frame {
+ struct iter_stack_frame *next;
+ zfs_handle_t *zhp;
+} iter_stack_frame_t;
+
+typedef struct iter_dependents_arg {
+ boolean_t first;
+ boolean_t allowrecursion;
+ iter_stack_frame_t *stack;
+ zfs_iter_f func;
+ void *data;
+} iter_dependents_arg_t;
+
+static int
+iter_dependents_cb(zfs_handle_t *zhp, void *arg)
+{
+ iter_dependents_arg_t *ida = arg;
+ int err;
+ boolean_t first = ida->first;
+ ida->first = B_FALSE;
+
+ if (zhp->zfs_type == ZFS_TYPE_SNAPSHOT) {
+ err = zfs_iter_clones(zhp, iter_dependents_cb, ida);
+ } else {
+ iter_stack_frame_t isf;
+ iter_stack_frame_t *f;
+
+ /*
+ * check if there is a cycle by seeing if this fs is already
+ * on the stack.
+ */
+ for (f = ida->stack; f != NULL; f = f->next) {
+ if (f->zhp->zfs_dmustats.dds_guid ==
+ zhp->zfs_dmustats.dds_guid) {
+ if (ida->allowrecursion) {
+ zfs_close(zhp);
+ return (0);
+ } else {
+ zfs_error_aux(zhp->zfs_hdl,
+ dgettext(TEXT_DOMAIN,
+ "recursive dependency at '%s'"),
+ zfs_get_name(zhp));
+ err = zfs_error(zhp->zfs_hdl,
+ EZFS_RECURSIVE,
+ dgettext(TEXT_DOMAIN,
+ "cannot determine dependent "
+ "datasets"));
+ zfs_close(zhp);
+ return (err);
+ }
+ }
+ }
+
+ isf.zhp = zhp;
+ isf.next = ida->stack;
+ ida->stack = &isf;
+ err = zfs_iter_filesystems(zhp, iter_dependents_cb, ida);
+ if (err == 0)
+ err = zfs_iter_snapshots(zhp, iter_dependents_cb, ida);
+ ida->stack = isf.next;
+ }
+ if (!first && err == 0)
+ err = ida->func(zhp, ida->data);
+ return (err);
+}
+
+int
+zfs_iter_dependents(zfs_handle_t *zhp, boolean_t allowrecursion,
+ zfs_iter_f func, void *data)
+{
+ iter_dependents_arg_t ida;
+ ida.allowrecursion = allowrecursion;
+ ida.stack = NULL;
+ ida.func = func;
+ ida.data = data;
+ ida.first = B_TRUE;
+ return (iter_dependents_cb(zfs_handle_dup(zhp), &ida));
+}
diff --git a/usr/src/lib/libzfs/common/libzfs_pool.c b/usr/src/lib/libzfs/common/libzfs_pool.c
index ba4b8199cc..8eb7e2ca15 100644
--- a/usr/src/lib/libzfs/common/libzfs_pool.c
+++ b/usr/src/lib/libzfs/common/libzfs_pool.c
@@ -22,6 +22,8 @@
/*
* Copyright (c) 2005, 2010, Oracle and/or its affiliates. All rights reserved.
* Copyright 2011 Joyent, Inc. All rights reserved.
+ * Copyright 2011 Nexenta Systems, Inc. All rights reserved.
+ * Copyright (c) 2011 by Delphix. All rights reserved.
*/
#include <ctype.h>
@@ -234,6 +236,7 @@ zpool_get_prop(zpool_handle_t *zhp, zpool_prop_t prop, char *buf, size_t len,
case ZPOOL_PROP_ALTROOT:
case ZPOOL_PROP_CACHEFILE:
+ case ZPOOL_PROP_COMMENT:
if (zhp->zpool_props != NULL ||
zpool_get_all_props(zhp) == 0) {
(void) strlcpy(buf,
@@ -390,7 +393,7 @@ zpool_valid_proplist(libzfs_handle_t *hdl, const char *poolname,
zpool_prop_t prop;
char *strval;
uint64_t intval;
- char *slash;
+ char *slash, *check;
struct stat64 statbuf;
zpool_handle_t *zhp;
nvlist_t *nvroot;
@@ -549,6 +552,26 @@ zpool_valid_proplist(libzfs_handle_t *hdl, const char *poolname,
*slash = '/';
break;
+ case ZPOOL_PROP_COMMENT:
+ for (check = strval; *check != '\0'; check++) {
+ if (!isprint(*check)) {
+ zfs_error_aux(hdl,
+ dgettext(TEXT_DOMAIN,
+ "comment may only have printable "
+ "characters"));
+ (void) zfs_error(hdl, EZFS_BADPROP,
+ errbuf);
+ goto error;
+ }
+ }
+ if (strlen(strval) > ZPROP_MAX_COMMENT) {
+ zfs_error_aux(hdl, dgettext(TEXT_DOMAIN,
+ "comment must not exceed %d characters"),
+ ZPROP_MAX_COMMENT);
+ (void) zfs_error(hdl, EZFS_BADPROP, errbuf);
+ goto error;
+ }
+ break;
case ZPOOL_PROP_READONLY:
if (!flags.import) {
zfs_error_aux(hdl, dgettext(TEXT_DOMAIN,
@@ -2975,6 +2998,26 @@ zpool_vdev_clear(zpool_handle_t *zhp, uint64_t guid)
}
/*
+ * Change the GUID for a pool.
+ */
+int
+zpool_reguid(zpool_handle_t *zhp)
+{
+ char msg[1024];
+ libzfs_handle_t *hdl = zhp->zpool_hdl;
+ zfs_cmd_t zc = { 0 };
+
+ (void) snprintf(msg, sizeof (msg),
+ dgettext(TEXT_DOMAIN, "cannot reguid '%s'"), zhp->zpool_name);
+
+ (void) strlcpy(zc.zc_name, zhp->zpool_name, sizeof (zc.zc_name));
+ if (zfs_ioctl(hdl, ZFS_IOC_POOL_REGUID, &zc) == 0)
+ return (0);
+
+ return (zpool_standard_error(hdl, errno, msg));
+}
+
+/*
* Convert from a devid string to a path.
*/
static char *
@@ -3707,8 +3750,7 @@ supported_dump_vdev_type(libzfs_handle_t *hdl, nvlist_t *config, char *errbuf)
uint_t children, c;
verify(nvlist_lookup_string(config, ZPOOL_CONFIG_TYPE, &type) == 0);
- if (strcmp(type, VDEV_TYPE_RAIDZ) == 0 ||
- strcmp(type, VDEV_TYPE_FILE) == 0 ||
+ if (strcmp(type, VDEV_TYPE_FILE) == 0 ||
strcmp(type, VDEV_TYPE_LOG) == 0 ||
strcmp(type, VDEV_TYPE_HOLE) == 0 ||
strcmp(type, VDEV_TYPE_MISSING) == 0) {
diff --git a/usr/src/lib/libzfs/common/libzfs_sendrecv.c b/usr/src/lib/libzfs/common/libzfs_sendrecv.c
index 3093ab974d..224e46812a 100644
--- a/usr/src/lib/libzfs/common/libzfs_sendrecv.c
+++ b/usr/src/lib/libzfs/common/libzfs_sendrecv.c
@@ -21,6 +21,7 @@
/*
* Copyright (c) 2005, 2010, Oracle and/or its affiliates. All rights reserved.
+ * Copyright (c) 2011 by Delphix. All rights reserved.
*/
#include <assert.h>
@@ -50,7 +51,7 @@
/* in libzfs_dataset.c */
extern void zfs_setprop_error(libzfs_handle_t *, zfs_prop_t, int, char *);
-static int zfs_receive_impl(libzfs_handle_t *, const char *, recvflags_t,
+static int zfs_receive_impl(libzfs_handle_t *, const char *, recvflags_t *,
int, const char *, nvlist_t *, avl_tree_t *, char **, int, uint64_t *);
static const zio_cksum_t zero_cksum = { 0 };
@@ -771,88 +772,6 @@ gather_nvlist(libzfs_handle_t *hdl, const char *fsname, const char *fromsnap,
}
/*
- * Routines for dealing with the sorted snapshot functionality
- */
-typedef struct zfs_node {
- zfs_handle_t *zn_handle;
- avl_node_t zn_avlnode;
-} zfs_node_t;
-
-static int
-zfs_sort_snaps(zfs_handle_t *zhp, void *data)
-{
- avl_tree_t *avl = data;
- zfs_node_t *node;
- zfs_node_t search;
-
- search.zn_handle = zhp;
- node = avl_find(avl, &search, NULL);
- if (node) {
- /*
- * If this snapshot was renamed while we were creating the
- * AVL tree, it's possible that we already inserted it under
- * its old name. Remove the old handle before adding the new
- * one.
- */
- zfs_close(node->zn_handle);
- avl_remove(avl, node);
- free(node);
- }
-
- node = zfs_alloc(zhp->zfs_hdl, sizeof (zfs_node_t));
- node->zn_handle = zhp;
- avl_add(avl, node);
-
- return (0);
-}
-
-static int
-zfs_snapshot_compare(const void *larg, const void *rarg)
-{
- zfs_handle_t *l = ((zfs_node_t *)larg)->zn_handle;
- zfs_handle_t *r = ((zfs_node_t *)rarg)->zn_handle;
- uint64_t lcreate, rcreate;
-
- /*
- * Sort them according to creation time. We use the hidden
- * CREATETXG property to get an absolute ordering of snapshots.
- */
- lcreate = zfs_prop_get_int(l, ZFS_PROP_CREATETXG);
- rcreate = zfs_prop_get_int(r, ZFS_PROP_CREATETXG);
-
- if (lcreate < rcreate)
- return (-1);
- else if (lcreate > rcreate)
- return (+1);
- else
- return (0);
-}
-
-int
-zfs_iter_snapshots_sorted(zfs_handle_t *zhp, zfs_iter_f callback, void *data)
-{
- int ret = 0;
- zfs_node_t *node;
- avl_tree_t avl;
- void *cookie = NULL;
-
- avl_create(&avl, zfs_snapshot_compare,
- sizeof (zfs_node_t), offsetof(zfs_node_t, zn_avlnode));
-
- ret = zfs_iter_snapshots(zhp, zfs_sort_snaps, &avl);
-
- for (node = avl_first(&avl); node != NULL; node = AVL_NEXT(&avl, node))
- ret |= callback(node->zn_handle, data);
-
- while ((node = avl_destroy_nodes(&avl, &cookie)) != NULL)
- free(node);
-
- avl_destroy(&avl);
-
- return (ret);
-}
-
-/*
* Routines specific to "zfs send"
*/
typedef struct send_dump_data {
@@ -862,7 +781,7 @@ typedef struct send_dump_data {
char prevsnap[ZFS_MAXNAMELEN];
uint64_t prevsnap_obj;
boolean_t seenfrom, seento, replicate, doall, fromorigin;
- boolean_t verbose;
+ boolean_t verbose, dryrun, parsable;
int outfd;
boolean_t err;
nvlist_t *fss;
@@ -872,8 +791,69 @@ typedef struct send_dump_data {
nvlist_t *debugnv;
char holdtag[ZFS_MAXNAMELEN];
int cleanup_fd;
+ uint64_t size;
} send_dump_data_t;
+static int
+estimate_ioctl(zfs_handle_t *zhp, uint64_t fromsnap_obj,
+ boolean_t fromorigin, uint64_t *sizep)
+{
+ zfs_cmd_t zc = { 0 };
+ libzfs_handle_t *hdl = zhp->zfs_hdl;
+
+ assert(zhp->zfs_type == ZFS_TYPE_SNAPSHOT);
+ assert(fromsnap_obj == 0 || !fromorigin);
+
+ (void) strlcpy(zc.zc_name, zhp->zfs_name, sizeof (zc.zc_name));
+ zc.zc_obj = fromorigin;
+ zc.zc_sendobj = zfs_prop_get_int(zhp, ZFS_PROP_OBJSETID);
+ zc.zc_fromobj = fromsnap_obj;
+ zc.zc_guid = 1; /* estimate flag */
+
+ if (zfs_ioctl(zhp->zfs_hdl, ZFS_IOC_SEND, &zc) != 0) {
+ char errbuf[1024];
+ (void) snprintf(errbuf, sizeof (errbuf), dgettext(TEXT_DOMAIN,
+ "warning: cannot estimate space for '%s'"), zhp->zfs_name);
+
+ switch (errno) {
+ case EXDEV:
+ zfs_error_aux(hdl, dgettext(TEXT_DOMAIN,
+ "not an earlier snapshot from the same fs"));
+ return (zfs_error(hdl, EZFS_CROSSTARGET, errbuf));
+
+ case ENOENT:
+ if (zfs_dataset_exists(hdl, zc.zc_name,
+ ZFS_TYPE_SNAPSHOT)) {
+ zfs_error_aux(hdl, dgettext(TEXT_DOMAIN,
+ "incremental source (@%s) does not exist"),
+ zc.zc_value);
+ }
+ return (zfs_error(hdl, EZFS_NOENT, errbuf));
+
+ case EDQUOT:
+ case EFBIG:
+ case EIO:
+ case ENOLINK:
+ case ENOSPC:
+ case ENOSTR:
+ case ENXIO:
+ case EPIPE:
+ case ERANGE:
+ case EFAULT:
+ case EROFS:
+ zfs_error_aux(hdl, strerror(errno));
+ return (zfs_error(hdl, EZFS_BADBACKUP, errbuf));
+
+ default:
+ return (zfs_standard_error(hdl, errno, errbuf));
+ }
+ }
+
+ *sizep = zc.zc_objset_type;
+
+ return (0);
+}
+
/*
* Dumps a backup of the given snapshot (incremental from fromsnap if it's not
* NULL) to the file descriptor specified by outfd.
@@ -901,7 +881,7 @@ dump_ioctl(zfs_handle_t *zhp, const char *fromsnap, uint64_t fromsnap_obj,
"fromsnap", fromsnap));
}
- if (ioctl(zhp->zfs_hdl->libzfs_fd, ZFS_IOC_SEND, &zc) != 0) {
+ if (zfs_ioctl(zhp->zfs_hdl, ZFS_IOC_SEND, &zc) != 0) {
char errbuf[1024];
(void) snprintf(errbuf, sizeof (errbuf), dgettext(TEXT_DOMAIN,
"warning: cannot send '%s'"), zhp->zfs_name);
@@ -914,7 +894,6 @@ dump_ioctl(zfs_handle_t *zhp, const char *fromsnap, uint64_t fromsnap_obj,
nvlist_free(thisdbg);
switch (errno) {
-
case EXDEV:
zfs_error_aux(hdl, dgettext(TEXT_DOMAIN,
"not an earlier snapshot from the same fs"));
@@ -964,6 +943,9 @@ hold_for_send(zfs_handle_t *zhp, send_dump_data_t *sdd)
assert(zhp->zfs_type == ZFS_TYPE_SNAPSHOT);
+ if (sdd->dryrun)
+ return (0);
+
/*
* zfs_send() only opens a cleanup_fd for sends that need it,
* e.g. replication and doall.
@@ -997,7 +979,7 @@ dump_snapshot(zfs_handle_t *zhp, void *arg)
send_dump_data_t *sdd = arg;
char *thissnap;
int err;
- boolean_t isfromsnap, istosnap;
+ boolean_t isfromsnap, istosnap, fromorigin;
boolean_t exclude = B_FALSE;
thissnap = strchr(zhp->zfs_name, '@') + 1;
@@ -1074,15 +1056,47 @@ dump_snapshot(zfs_handle_t *zhp, void *arg)
return (err);
}
- /* send it */
+ fromorigin = sdd->prevsnap[0] == '\0' &&
+ (sdd->fromorigin || sdd->replicate);
+
if (sdd->verbose) {
- (void) fprintf(stderr, "sending from @%s to %s\n",
- sdd->prevsnap, zhp->zfs_name);
+ uint64_t size;
+ err = estimate_ioctl(zhp, sdd->prevsnap_obj,
+ fromorigin, &size);
+
+ if (sdd->parsable) {
+ if (sdd->prevsnap[0] != '\0') {
+ (void) fprintf(stderr, "incremental\t%s\t%s",
+ sdd->prevsnap, zhp->zfs_name);
+ } else {
+ (void) fprintf(stderr, "full\t%s",
+ zhp->zfs_name);
+ }
+ } else {
+ (void) fprintf(stderr, dgettext(TEXT_DOMAIN,
+ "send from @%s to %s"),
+ sdd->prevsnap, zhp->zfs_name);
+ }
+ if (err == 0) {
+ if (sdd->parsable) {
+ (void) fprintf(stderr, "\t%llu\n",
+ (longlong_t)size);
+ } else {
+ char buf[16];
+ zfs_nicenum(size, buf, sizeof (buf));
+ (void) fprintf(stderr, dgettext(TEXT_DOMAIN,
+ " estimated size is %s\n"), buf);
+ }
+ sdd->size += size;
+ } else {
+ (void) fprintf(stderr, "\n");
+ }
}
- err = dump_ioctl(zhp, sdd->prevsnap, sdd->prevsnap_obj,
- sdd->prevsnap[0] == '\0' && (sdd->fromorigin || sdd->replicate),
- sdd->outfd, sdd->debugnv);
+ if (!sdd->dryrun) {
+ err = dump_ioctl(zhp, sdd->prevsnap, sdd->prevsnap_obj,
+ fromorigin, sdd->outfd, sdd->debugnv);
+ }
(void) strcpy(sdd->prevsnap, thissnap);
sdd->prevsnap_obj = zfs_prop_get_int(zhp, ZFS_PROP_OBJSETID);
@@ -1101,8 +1115,8 @@ dump_filesystem(zfs_handle_t *zhp, void *arg)
(void) snprintf(zc.zc_name, sizeof (zc.zc_name), "%s@%s",
zhp->zfs_name, sdd->tosnap);
if (ioctl(zhp->zfs_hdl->libzfs_fd, ZFS_IOC_OBJSET_STATS, &zc) != 0) {
- (void) fprintf(stderr, "WARNING: "
- "could not send %s@%s: does not exist\n",
+ (void) fprintf(stderr, dgettext(TEXT_DOMAIN,
+ "WARNING: could not send %s@%s: does not exist\n"),
zhp->zfs_name, sdd->tosnap);
sdd->err = B_TRUE;
return (0);
@@ -1131,23 +1145,24 @@ dump_filesystem(zfs_handle_t *zhp, void *arg)
rv = zfs_iter_snapshots_sorted(zhp, dump_snapshot, arg);
if (!sdd->seenfrom) {
- (void) fprintf(stderr,
+ (void) fprintf(stderr, dgettext(TEXT_DOMAIN,
"WARNING: could not send %s@%s:\n"
- "incremental source (%s@%s) does not exist\n",
+ "incremental source (%s@%s) does not exist\n"),
zhp->zfs_name, sdd->tosnap,
zhp->zfs_name, sdd->fromsnap);
sdd->err = B_TRUE;
} else if (!sdd->seento) {
if (sdd->fromsnap) {
- (void) fprintf(stderr,
+ (void) fprintf(stderr, dgettext(TEXT_DOMAIN,
"WARNING: could not send %s@%s:\n"
"incremental source (%s@%s) "
- "is not earlier than it\n",
+ "is not earlier than it\n"),
zhp->zfs_name, sdd->tosnap,
zhp->zfs_name, sdd->fromsnap);
} else {
- (void) fprintf(stderr, "WARNING: "
- "could not send %s@%s: does not exist\n",
+ (void) fprintf(stderr, dgettext(TEXT_DOMAIN,
+ "WARNING: "
+ "could not send %s@%s: does not exist\n"),
zhp->zfs_name, sdd->tosnap);
}
sdd->err = B_TRUE;
@@ -1193,11 +1208,12 @@ again:
needagain = progress = B_FALSE;
for (fspair = nvlist_next_nvpair(sdd->fss, NULL); fspair;
fspair = nvlist_next_nvpair(sdd->fss, fspair)) {
- nvlist_t *fslist;
+ nvlist_t *fslist, *parent_nv;
char *fsname;
zfs_handle_t *zhp;
int err;
uint64_t origin_guid = 0;
+ uint64_t parent_guid = 0;
VERIFY(nvpair_value_nvlist(fspair, &fslist) == 0);
if (nvlist_lookup_boolean(fslist, "sent") == 0)
@@ -1205,13 +1221,23 @@ again:
VERIFY(nvlist_lookup_string(fslist, "name", &fsname) == 0);
(void) nvlist_lookup_uint64(fslist, "origin", &origin_guid);
+ (void) nvlist_lookup_uint64(fslist, "parentfromsnap",
+ &parent_guid);
+
+ if (parent_guid != 0) {
+ parent_nv = fsavl_find(sdd->fsavl, parent_guid, NULL);
+ if (!nvlist_exists(parent_nv, "sent")) {
+ /* parent has not been sent; skip this one */
+ needagain = B_TRUE;
+ continue;
+ }
+ }
if (origin_guid != 0) {
nvlist_t *origin_nv = fsavl_find(sdd->fsavl,
origin_guid, NULL);
if (origin_nv != NULL &&
- nvlist_lookup_boolean(origin_nv,
- "sent") == ENOENT) {
+ !nvlist_exists(origin_nv, "sent")) {
/*
* origin has not been sent yet;
* skip this clone.
@@ -1235,6 +1261,16 @@ again:
assert(progress);
goto again;
}
+
+ /* clean out the sent flags in case we reuse this fss */
+ for (fspair = nvlist_next_nvpair(sdd->fss, NULL); fspair;
+ fspair = nvlist_next_nvpair(sdd->fss, fspair)) {
+ nvlist_t *fslist;
+
+ VERIFY(nvpair_value_nvlist(fspair, &fslist) == 0);
+ (void) nvlist_remove_all(fslist, "sent");
+ }
+
return (0);
}
@@ -1256,12 +1292,12 @@ again:
*/
int
zfs_send(zfs_handle_t *zhp, const char *fromsnap, const char *tosnap,
- sendflags_t flags, int outfd, snapfilter_cb_t filter_func,
+ sendflags_t *flags, int outfd, snapfilter_cb_t filter_func,
void *cb_arg, nvlist_t **debugnvp)
{
char errbuf[1024];
send_dump_data_t sdd = { 0 };
- int err;
+ int err = 0;
nvlist_t *fss = NULL;
avl_tree_t *fsavl = NULL;
static uint64_t holdseq;
@@ -1289,12 +1325,12 @@ zfs_send(zfs_handle_t *zhp, const char *fromsnap, const char *tosnap,
}
}
- if (zfs_spa_version(zhp, &spa_version) == 0 &&
+ if (!flags->dryrun && zfs_spa_version(zhp, &spa_version) == 0 &&
spa_version >= SPA_VERSION_USERREFS &&
- (flags.doall || flags.replicate))
+ (flags->doall || flags->replicate))
holdsnaps = B_TRUE;
- if (flags.dedup) {
+ if (flags->dedup && !flags->dryrun) {
featureflags |= (DMU_BACKUP_FEATURE_DEDUP |
DMU_BACKUP_FEATURE_DEDUPPROPS);
if (err = pipe(pipefd)) {
@@ -1314,13 +1350,13 @@ zfs_send(zfs_handle_t *zhp, const char *fromsnap, const char *tosnap,
}
}
- if (flags.replicate || flags.doall || flags.props) {
+ if (flags->replicate || flags->doall || flags->props) {
dmu_replay_record_t drr = { 0 };
char *packbuf = NULL;
size_t buflen = 0;
zio_cksum_t zc = { 0 };
- if (flags.replicate || flags.props) {
+ if (flags->replicate || flags->props) {
nvlist_t *hdrnv;
VERIFY(0 == nvlist_alloc(&hdrnv, NV_UNIQUE_NAME, 0));
@@ -1329,13 +1365,13 @@ zfs_send(zfs_handle_t *zhp, const char *fromsnap, const char *tosnap,
"fromsnap", fromsnap));
}
VERIFY(0 == nvlist_add_string(hdrnv, "tosnap", tosnap));
- if (!flags.replicate) {
+ if (!flags->replicate) {
VERIFY(0 == nvlist_add_boolean(hdrnv,
"not_recursive"));
}
err = gather_nvlist(zhp->zfs_hdl, zhp->zfs_name,
- fromsnap, tosnap, flags.replicate, &fss, &fsavl);
+ fromsnap, tosnap, flags->replicate, &fss, &fsavl);
if (err)
goto err_out;
VERIFY(0 == nvlist_add_nvlist(hdrnv, "fss", fss));
@@ -1352,33 +1388,34 @@ zfs_send(zfs_handle_t *zhp, const char *fromsnap, const char *tosnap,
}
}
- /* write first begin record */
- drr.drr_type = DRR_BEGIN;
- drr.drr_u.drr_begin.drr_magic = DMU_BACKUP_MAGIC;
- DMU_SET_STREAM_HDRTYPE(drr.drr_u.drr_begin.drr_versioninfo,
- DMU_COMPOUNDSTREAM);
- DMU_SET_FEATUREFLAGS(drr.drr_u.drr_begin.drr_versioninfo,
- featureflags);
- (void) snprintf(drr.drr_u.drr_begin.drr_toname,
- sizeof (drr.drr_u.drr_begin.drr_toname),
- "%s@%s", zhp->zfs_name, tosnap);
- drr.drr_payloadlen = buflen;
- err = cksum_and_write(&drr, sizeof (drr), &zc, outfd);
-
- /* write header nvlist */
- if (err != -1 && packbuf != NULL) {
- err = cksum_and_write(packbuf, buflen, &zc, outfd);
- }
- free(packbuf);
- if (err == -1) {
- fsavl_destroy(fsavl);
- nvlist_free(fss);
- err = errno;
- goto stderr_out;
- }
+ if (!flags->dryrun) {
+ /* write first begin record */
+ drr.drr_type = DRR_BEGIN;
+ drr.drr_u.drr_begin.drr_magic = DMU_BACKUP_MAGIC;
+ DMU_SET_STREAM_HDRTYPE(drr.drr_u.drr_begin.
+ drr_versioninfo, DMU_COMPOUNDSTREAM);
+ DMU_SET_FEATUREFLAGS(drr.drr_u.drr_begin.
+ drr_versioninfo, featureflags);
+ (void) snprintf(drr.drr_u.drr_begin.drr_toname,
+ sizeof (drr.drr_u.drr_begin.drr_toname),
+ "%s@%s", zhp->zfs_name, tosnap);
+ drr.drr_payloadlen = buflen;
+ err = cksum_and_write(&drr, sizeof (drr), &zc, outfd);
+
+ /* write header nvlist */
+ if (err != -1 && packbuf != NULL) {
+ err = cksum_and_write(packbuf, buflen, &zc,
+ outfd);
+ }
+ free(packbuf);
+ if (err == -1) {
+ fsavl_destroy(fsavl);
+ nvlist_free(fss);
+ err = errno;
+ goto stderr_out;
+ }
- /* write end record */
- if (err != -1) {
+ /* write end record */
bzero(&drr, sizeof (drr));
drr.drr_type = DRR_END;
drr.drr_u.drr_end.drr_checksum = zc;
@@ -1389,22 +1426,26 @@ zfs_send(zfs_handle_t *zhp, const char *fromsnap, const char *tosnap,
err = errno;
goto stderr_out;
}
+
+ err = 0;
}
}
/* dump each stream */
sdd.fromsnap = fromsnap;
sdd.tosnap = tosnap;
- if (flags.dedup)
+ if (flags->dedup)
sdd.outfd = pipefd[0];
else
sdd.outfd = outfd;
- sdd.replicate = flags.replicate;
- sdd.doall = flags.doall;
- sdd.fromorigin = flags.fromorigin;
+ sdd.replicate = flags->replicate;
+ sdd.doall = flags->doall;
+ sdd.fromorigin = flags->fromorigin;
sdd.fss = fss;
sdd.fsavl = fsavl;
- sdd.verbose = flags.verbose;
+ sdd.verbose = flags->verbose;
+ sdd.parsable = flags->parsable;
+ sdd.dryrun = flags->dryrun;
sdd.filter_cb = filter_func;
sdd.filter_cb_arg = cb_arg;
if (debugnvp)
@@ -1421,11 +1462,31 @@ zfs_send(zfs_handle_t *zhp, const char *fromsnap, const char *tosnap,
} else {
sdd.cleanup_fd = -1;
}
+ if (flags->verbose) {
+ /*
+ * Do a verbose no-op dry run to get all the verbose output
+ * before generating any data. Then do a non-verbose real
+ * run to generate the streams.
+ */
+ sdd.dryrun = B_TRUE;
+ err = dump_filesystems(zhp, &sdd);
+ sdd.dryrun = flags->dryrun;
+ sdd.verbose = B_FALSE;
+ if (flags->parsable) {
+ (void) fprintf(stderr, "size\t%llu\n",
+ (longlong_t)sdd.size);
+ } else {
+ char buf[16];
+ zfs_nicenum(sdd.size, buf, sizeof (buf));
+ (void) fprintf(stderr, dgettext(TEXT_DOMAIN,
+ "total estimated size is %s\n"), buf);
+ }
+ }
err = dump_filesystems(zhp, &sdd);
fsavl_destroy(fsavl);
nvlist_free(fss);
- if (flags.dedup) {
+ if (flags->dedup) {
(void) close(pipefd[0]);
(void) pthread_join(tid, NULL);
}
@@ -1435,7 +1496,8 @@ zfs_send(zfs_handle_t *zhp, const char *fromsnap, const char *tosnap,
sdd.cleanup_fd = -1;
}
- if (flags.replicate || flags.doall || flags.props) {
+ if (!flags->dryrun && (flags->replicate || flags->doall ||
+ flags->props)) {
/*
* write final end record. NB: want to do this even if
* there was some error, because it might not be totally
@@ -1456,7 +1518,7 @@ stderr_out:
err_out:
if (sdd.cleanup_fd != -1)
VERIFY(0 == close(sdd.cleanup_fd));
- if (flags.dedup) {
+ if (flags->dedup) {
(void) pthread_cancel(tid);
(void) pthread_join(tid, NULL);
(void) close(pipefd[0]);
@@ -1527,7 +1589,7 @@ recv_read_nvlist(libzfs_handle_t *hdl, int fd, int len, nvlist_t **nvp,
static int
recv_rename(libzfs_handle_t *hdl, const char *name, const char *tryname,
- int baselen, char *newname, recvflags_t flags)
+ int baselen, char *newname, recvflags_t *flags)
{
static int seq;
zfs_cmd_t zc = { 0 };
@@ -1539,7 +1601,7 @@ recv_rename(libzfs_handle_t *hdl, const char *name, const char *tryname,
if (zhp == NULL)
return (-1);
clp = changelist_gather(zhp, ZFS_PROP_NAME, 0,
- flags.force ? MS_FORCE : 0);
+ flags->force ? MS_FORCE : 0);
zfs_close(zhp);
if (clp == NULL)
return (-1);
@@ -1555,7 +1617,7 @@ recv_rename(libzfs_handle_t *hdl, const char *name, const char *tryname,
(void) strlcpy(zc.zc_value, tryname, sizeof (zc.zc_value));
- if (flags.verbose) {
+ if (flags->verbose) {
(void) printf("attempting rename %s to %s\n",
zc.zc_name, zc.zc_value);
}
@@ -1574,19 +1636,19 @@ recv_rename(libzfs_handle_t *hdl, const char *name, const char *tryname,
"recv-%u-%u", getpid(), seq);
(void) strlcpy(zc.zc_value, newname, sizeof (zc.zc_value));
- if (flags.verbose) {
+ if (flags->verbose) {
(void) printf("failed - trying rename %s to %s\n",
zc.zc_name, zc.zc_value);
}
err = ioctl(hdl->libzfs_fd, ZFS_IOC_RENAME, &zc);
if (err == 0)
changelist_rename(clp, name, newname);
- if (err && flags.verbose) {
+ if (err && flags->verbose) {
(void) printf("failed (%u) - "
"will try again on next pass\n", errno);
}
err = EAGAIN;
- } else if (flags.verbose) {
+ } else if (flags->verbose) {
if (err == 0)
(void) printf("success\n");
else
@@ -1601,7 +1663,7 @@ recv_rename(libzfs_handle_t *hdl, const char *name, const char *tryname,
static int
recv_destroy(libzfs_handle_t *hdl, const char *name, int baselen,
- char *newname, recvflags_t flags)
+ char *newname, recvflags_t *flags)
{
zfs_cmd_t zc = { 0 };
int err = 0;
@@ -1614,7 +1676,7 @@ recv_destroy(libzfs_handle_t *hdl, const char *name, int baselen,
if (zhp == NULL)
return (-1);
clp = changelist_gather(zhp, ZFS_PROP_NAME, 0,
- flags.force ? MS_FORCE : 0);
+ flags->force ? MS_FORCE : 0);
if (zfs_get_type(zhp) == ZFS_TYPE_SNAPSHOT &&
zfs_spa_version(zhp, &spa_version) == 0 &&
spa_version >= SPA_VERSION_USERREFS)
@@ -1630,11 +1692,11 @@ recv_destroy(libzfs_handle_t *hdl, const char *name, int baselen,
zc.zc_defer_destroy = defer;
(void) strlcpy(zc.zc_name, name, sizeof (zc.zc_name));
- if (flags.verbose)
+ if (flags->verbose)
(void) printf("attempting destroy %s\n", zc.zc_name);
err = ioctl(hdl->libzfs_fd, ZFS_IOC_DESTROY, &zc);
if (err == 0) {
- if (flags.verbose)
+ if (flags->verbose)
(void) printf("success\n");
changelist_remove(clp, zc.zc_name);
}
@@ -1657,6 +1719,7 @@ recv_destroy(libzfs_handle_t *hdl, const char *name, int baselen,
typedef struct guid_to_name_data {
uint64_t guid;
char *name;
+ char *skip;
} guid_to_name_data_t;
static int
@@ -1665,21 +1728,35 @@ guid_to_name_cb(zfs_handle_t *zhp, void *arg)
guid_to_name_data_t *gtnd = arg;
int err;
+ if (gtnd->skip != NULL &&
+ strcmp(zhp->zfs_name, gtnd->skip) == 0) {
+ return (0);
+ }
+
if (zhp->zfs_dmustats.dds_guid == gtnd->guid) {
(void) strcpy(gtnd->name, zhp->zfs_name);
zfs_close(zhp);
return (EEXIST);
}
+
err = zfs_iter_children(zhp, guid_to_name_cb, gtnd);
zfs_close(zhp);
return (err);
}
+/*
+ * Attempt to find the local dataset associated with this guid. In the case of
+ * multiple matches, we attempt to find the "best" match by searching
+ * progressively larger portions of the hierarchy. This allows one to send a
+ * tree of datasets individually and guarantee that we will find the source
+ * guid within that hierarchy, even if there are multiple matches elsewhere.
+ */
static int
guid_to_name(libzfs_handle_t *hdl, const char *parent, uint64_t guid,
char *name)
{
/* exhaustive search all local snapshots */
+ char pname[ZFS_MAXNAMELEN];
guid_to_name_data_t gtnd;
int err = 0;
zfs_handle_t *zhp;
@@ -1687,35 +1764,42 @@ guid_to_name(libzfs_handle_t *hdl, const char *parent, uint64_t guid,
gtnd.guid = guid;
gtnd.name = name;
+ gtnd.skip = NULL;
- if (strchr(parent, '@') == NULL) {
- zhp = make_dataset_handle(hdl, parent);
- if (zhp != NULL) {
- err = zfs_iter_children(zhp, guid_to_name_cb, &gtnd);
- zfs_close(zhp);
- if (err == EEXIST)
- return (0);
- }
- }
+ (void) strlcpy(pname, parent, sizeof (pname));
- cp = strchr(parent, '/');
- if (cp)
+ /*
+ * Search progressively larger portions of the hierarchy. This will
+ * select the "most local" version of the origin snapshot in the case
+ * that there are multiple matching snapshots in the system.
+ */
+ while ((cp = strrchr(pname, '/')) != NULL) {
+
+ /* Chop off the last component and open the parent */
*cp = '\0';
- zhp = make_dataset_handle(hdl, parent);
- if (cp)
- *cp = '/';
+ zhp = make_dataset_handle(hdl, pname);
+
+ if (zhp == NULL)
+ continue;
- if (zhp) {
err = zfs_iter_children(zhp, guid_to_name_cb, &gtnd);
zfs_close(zhp);
- }
+ if (err == EEXIST)
+ return (0);
- return (err == EEXIST ? 0 : ENOENT);
+ /*
+ * Remember the dataset that we already searched, so we
+ * skip it next time through.
+ */
+ gtnd.skip = pname;
+ }
+ return (ENOENT);
}
/*
- * Return true if dataset guid1 is created before guid2.
+ * Return +1 if guid1 is before guid2, 0 if they are the same, and -1 if
+ * guid1 is after guid2.
*/
static int
created_before(libzfs_handle_t *hdl, avl_tree_t *avl,
@@ -1725,7 +1809,8 @@ created_before(libzfs_handle_t *hdl, avl_tree_t *avl,
char *fsname, *snapname;
char buf[ZFS_MAXNAMELEN];
int rv;
- zfs_node_t zn1, zn2;
+ zfs_handle_t *guid1hdl, *guid2hdl;
+ uint64_t create1, create2;
if (guid2 == 0)
return (0);
@@ -1735,30 +1820,38 @@ created_before(libzfs_handle_t *hdl, avl_tree_t *avl,
nvfs = fsavl_find(avl, guid1, &snapname);
VERIFY(0 == nvlist_lookup_string(nvfs, "name", &fsname));
(void) snprintf(buf, sizeof (buf), "%s@%s", fsname, snapname);
- zn1.zn_handle = zfs_open(hdl, buf, ZFS_TYPE_SNAPSHOT);
- if (zn1.zn_handle == NULL)
+ guid1hdl = zfs_open(hdl, buf, ZFS_TYPE_SNAPSHOT);
+ if (guid1hdl == NULL)
return (-1);
nvfs = fsavl_find(avl, guid2, &snapname);
VERIFY(0 == nvlist_lookup_string(nvfs, "name", &fsname));
(void) snprintf(buf, sizeof (buf), "%s@%s", fsname, snapname);
- zn2.zn_handle = zfs_open(hdl, buf, ZFS_TYPE_SNAPSHOT);
- if (zn2.zn_handle == NULL) {
- zfs_close(zn2.zn_handle);
+ guid2hdl = zfs_open(hdl, buf, ZFS_TYPE_SNAPSHOT);
+ if (guid2hdl == NULL) {
+ zfs_close(guid1hdl);
return (-1);
}
- rv = (zfs_snapshot_compare(&zn1, &zn2) == -1);
+ create1 = zfs_prop_get_int(guid1hdl, ZFS_PROP_CREATETXG);
+ create2 = zfs_prop_get_int(guid2hdl, ZFS_PROP_CREATETXG);
- zfs_close(zn1.zn_handle);
- zfs_close(zn2.zn_handle);
+ if (create1 < create2)
+ rv = -1;
+ else if (create1 > create2)
+ rv = +1;
+ else
+ rv = 0;
+
+ zfs_close(guid1hdl);
+ zfs_close(guid2hdl);
return (rv);
}
static int
recv_incremental_replication(libzfs_handle_t *hdl, const char *tofs,
- recvflags_t flags, nvlist_t *stream_nv, avl_tree_t *stream_avl,
+ recvflags_t *flags, nvlist_t *stream_nv, avl_tree_t *stream_avl,
nvlist_t *renamed)
{
nvlist_t *local_nv;
@@ -1775,7 +1868,7 @@ recv_incremental_replication(libzfs_handle_t *hdl, const char *tofs,
recursive = (nvlist_lookup_boolean(stream_nv, "not_recursive") ==
ENOENT);
- if (flags.dryrun)
+ if (flags->dryrun)
return (0);
again:
@@ -1835,7 +1928,7 @@ again:
nvlist_t *origin_nvfs;
char *origin_fsname;
- if (flags.verbose)
+ if (flags->verbose)
(void) printf("promoting %s\n", fsname);
origin_nvfs = fsavl_find(local_avl, originguid,
@@ -1883,7 +1976,7 @@ again:
if (found == NULL) {
char name[ZFS_MAXNAMELEN];
- if (!flags.force)
+ if (!flags->force)
continue;
(void) snprintf(name, sizeof (name), "%s@%s",
@@ -1941,7 +2034,7 @@ again:
/* check for delete */
if (stream_nvfs == NULL) {
- if (!flags.force)
+ if (!flags->force)
continue;
error = recv_destroy(hdl, fsname, strlen(tofs)+1,
@@ -1954,7 +2047,7 @@ again:
}
if (fromguid == 0) {
- if (flags.verbose) {
+ if (flags->verbose) {
(void) printf("local fs %s does not have "
"fromsnap (%s in stream); must have "
"been deleted locally; ignoring\n",
@@ -1979,7 +2072,7 @@ again:
if ((stream_parent_fromsnap_guid != 0 &&
parent_fromsnap_guid != 0 &&
stream_parent_fromsnap_guid != parent_fromsnap_guid) ||
- ((flags.isprefix || strcmp(tofs, fsname) != 0) &&
+ ((flags->isprefix || strcmp(tofs, fsname) != 0) &&
(s1 != NULL) && (s2 != NULL) && strcmp(s1, s2) != 0)) {
nvlist_t *parent;
char tryname[ZFS_MAXNAMELEN];
@@ -2002,7 +2095,7 @@ again:
"%s%s", pname, strrchr(stream_fsname, '/'));
} else {
tryname[0] = '\0';
- if (flags.verbose) {
+ if (flags->verbose) {
(void) printf("local fs %s new parent "
"not found\n", fsname);
}
@@ -2030,7 +2123,7 @@ again:
if (needagain && progress) {
/* do another pass to fix up temporary names */
- if (flags.verbose)
+ if (flags->verbose)
(void) printf("another pass:\n");
goto again;
}
@@ -2040,7 +2133,7 @@ again:
static int
zfs_receive_package(libzfs_handle_t *hdl, int fd, const char *destname,
- recvflags_t flags, dmu_replay_record_t *drr, zio_cksum_t *zc,
+ recvflags_t *flags, dmu_replay_record_t *drr, zio_cksum_t *zc,
char **top_zfs, int cleanup_fd, uint64_t *action_handlep)
{
nvlist_t *stream_nv = NULL;
@@ -2069,7 +2162,7 @@ zfs_receive_package(libzfs_handle_t *hdl, int fd, const char *destname,
*/
if (drr->drr_payloadlen != 0) {
error = recv_read_nvlist(hdl, fd, drr->drr_payloadlen,
- &stream_nv, flags.byteswap, zc);
+ &stream_nv, flags->byteswap, zc);
if (error) {
error = zfs_error(hdl, EZFS_BADSTREAM, errbuf);
goto out;
@@ -2090,9 +2183,9 @@ zfs_receive_package(libzfs_handle_t *hdl, int fd, const char *destname,
* Read in the end record and verify checksum.
*/
if (0 != (error = recv_read(hdl, fd, &drre, sizeof (drre),
- flags.byteswap, NULL)))
+ flags->byteswap, NULL)))
goto out;
- if (flags.byteswap) {
+ if (flags->byteswap) {
drre.drr_type = BSWAP_32(drre.drr_type);
drre.drr_u.drr_end.drr_checksum.zc_word[0] =
BSWAP_64(drre.drr_u.drr_end.drr_checksum.zc_word[0]);
@@ -2133,11 +2226,11 @@ zfs_receive_package(libzfs_handle_t *hdl, int fd, const char *destname,
nvpair_t *pair = NULL;
(void) strlcpy(tofs, destname, ZFS_MAXNAMELEN);
- if (flags.isprefix) {
+ if (flags->isprefix) {
struct drr_begin *drrb = &drr->drr_u.drr_begin;
int i;
- if (flags.istail) {
+ if (flags->istail) {
cp = strrchr(drrb->drr_toname, '/');
if (cp == NULL) {
(void) strlcat(tofs, "/",
@@ -2155,7 +2248,7 @@ zfs_receive_package(libzfs_handle_t *hdl, int fd, const char *destname,
*strchr(tofs, '@') = '\0';
}
- if (recursive && !flags.dryrun && !flags.nomount) {
+ if (recursive && !flags->dryrun && !flags->nomount) {
VERIFY(0 == nvlist_alloc(&renamed,
NV_UNIQUE_NAME, 0));
}
@@ -2329,7 +2422,7 @@ recv_skip(libzfs_handle_t *hdl, int fd, boolean_t byteswap)
*/
static int
zfs_receive_one(libzfs_handle_t *hdl, int infd, const char *tosnap,
- recvflags_t flags, dmu_replay_record_t *drr,
+ recvflags_t *flags, dmu_replay_record_t *drr,
dmu_replay_record_t *drr_noswap, const char *sendfs,
nvlist_t *stream_nv, avl_tree_t *stream_avl, char **top_zfs, int cleanup_fd,
uint64_t *action_handlep)
@@ -2371,7 +2464,7 @@ zfs_receive_one(libzfs_handle_t *hdl, int infd, const char *tosnap,
if (err)
VERIFY(0 == nvlist_alloc(&props, NV_UNIQUE_NAME, 0));
- if (flags.canmountoff) {
+ if (flags->canmountoff) {
VERIFY(0 == nvlist_add_uint64(props,
zfs_prop_to_name(ZFS_PROP_CANMOUNT), 0));
}
@@ -2398,7 +2491,7 @@ zfs_receive_one(libzfs_handle_t *hdl, int infd, const char *tosnap,
* If they specified a snapshot, chop the entire name stored in
* the stream.
*/
- if (flags.istail) {
+ if (flags->istail) {
/*
* A filesystem was specified with -e. We want to tack on only
* the tail of the sent snapshot path.
@@ -2424,7 +2517,7 @@ zfs_receive_one(libzfs_handle_t *hdl, int infd, const char *tosnap,
} else {
chopprefix = drrb->drr_toname + (chopprefix - sendfs);
}
- } else if (flags.isprefix) {
+ } else if (flags->isprefix) {
/*
* A filesystem was specified with -d. We want to tack on
* everything but the first element of the sent snapshot path
@@ -2478,7 +2571,7 @@ zfs_receive_one(libzfs_handle_t *hdl, int infd, const char *tosnap,
* Determine the name of the origin snapshot, store in zc_string.
*/
if (drrb->drr_flags & DRR_FLAG_CLONE) {
- if (guid_to_name(hdl, tosnap,
+ if (guid_to_name(hdl, zc.zc_value,
drrb->drr_fromguid, zc.zc_string) != 0) {
zcmd_free_nvlists(&zc);
zfs_error_aux(hdl, dgettext(TEXT_DOMAIN,
@@ -2486,7 +2579,7 @@ zfs_receive_one(libzfs_handle_t *hdl, int infd, const char *tosnap,
zc.zc_value);
return (zfs_error(hdl, EZFS_NOENT, errbuf));
}
- if (flags.verbose)
+ if (flags->verbose)
(void) printf("found clone origin %s\n", zc.zc_string);
}
@@ -2509,7 +2602,7 @@ zfs_receive_one(libzfs_handle_t *hdl, int infd, const char *tosnap,
!zfs_dataset_exists(hdl, zc.zc_name, ZFS_TYPE_DATASET)) {
char suffix[ZFS_MAXNAMELEN];
(void) strcpy(suffix, strrchr(zc.zc_value, '/'));
- if (guid_to_name(hdl, tosnap, parent_snapguid,
+ if (guid_to_name(hdl, zc.zc_name, parent_snapguid,
zc.zc_value) == 0) {
*strchr(zc.zc_value, '@') = '\0';
(void) strcat(zc.zc_value, suffix);
@@ -2531,12 +2624,12 @@ zfs_receive_one(libzfs_handle_t *hdl, int infd, const char *tosnap,
* topmost path in the stream, then if the fs does not exist we
* should look no further.
*/
- if ((flags.isprefix || (*(chopprefix = drrb->drr_toname +
+ if ((flags->isprefix || (*(chopprefix = drrb->drr_toname +
strlen(sendfs)) != '\0' && *chopprefix != '@')) &&
!zfs_dataset_exists(hdl, zc.zc_name, ZFS_TYPE_DATASET)) {
char snap[ZFS_MAXNAMELEN];
(void) strcpy(snap, strchr(zc.zc_value, '@'));
- if (guid_to_name(hdl, tosnap, drrb->drr_fromguid,
+ if (guid_to_name(hdl, zc.zc_name, drrb->drr_fromguid,
zc.zc_value) == 0) {
*strchr(zc.zc_value, '@') = '\0';
(void) strcat(zc.zc_value, snap);
@@ -2558,7 +2651,7 @@ zfs_receive_one(libzfs_handle_t *hdl, int infd, const char *tosnap,
* snapshots).
*/
if (stream_wantsnewfs) {
- if (!flags.force) {
+ if (!flags->force) {
zcmd_free_nvlists(&zc);
zfs_error_aux(hdl, dgettext(TEXT_DOMAIN,
"destination '%s' exists\n"
@@ -2594,7 +2687,7 @@ zfs_receive_one(libzfs_handle_t *hdl, int infd, const char *tosnap,
return (zfs_error(hdl, EZFS_EXISTS, errbuf));
}
- if (!flags.dryrun && zhp->zfs_type == ZFS_TYPE_FILESYSTEM &&
+ if (!flags->dryrun && zhp->zfs_type == ZFS_TYPE_FILESYSTEM &&
stream_wantsnewfs) {
/* We can't do online recv in this case */
clp = changelist_gather(zhp, ZFS_PROP_NAME, 0, 0);
@@ -2633,7 +2726,7 @@ zfs_receive_one(libzfs_handle_t *hdl, int infd, const char *tosnap,
*/
*cp = '\0';
- if (flags.isprefix && !flags.istail && !flags.dryrun &&
+ if (flags->isprefix && !flags->istail && !flags->dryrun &&
create_parents(hdl, zc.zc_value, strlen(tosnap)) != 0) {
zcmd_free_nvlists(&zc);
return (zfs_error(hdl, EZFS_BADRESTORE, errbuf));
@@ -2644,18 +2737,18 @@ zfs_receive_one(libzfs_handle_t *hdl, int infd, const char *tosnap,
zc.zc_begin_record = drr_noswap->drr_u.drr_begin;
zc.zc_cookie = infd;
- zc.zc_guid = flags.force;
- if (flags.verbose) {
+ zc.zc_guid = flags->force;
+ if (flags->verbose) {
(void) printf("%s %s stream of %s into %s\n",
- flags.dryrun ? "would receive" : "receiving",
+ flags->dryrun ? "would receive" : "receiving",
drrb->drr_fromguid ? "incremental" : "full",
drrb->drr_toname, zc.zc_value);
(void) fflush(stdout);
}
- if (flags.dryrun) {
+ if (flags->dryrun) {
zcmd_free_nvlists(&zc);
- return (recv_skip(hdl, infd, flags.byteswap));
+ return (recv_skip(hdl, infd, flags->byteswap));
}
zc.zc_nvlist_dst = (uint64_t)(uintptr_t)prop_errbuf;
@@ -2736,12 +2829,12 @@ zfs_receive_one(libzfs_handle_t *hdl, int infd, const char *tosnap,
nvlist_free(local_nv);
if (fs != NULL) {
- if (flags.verbose) {
+ if (flags->verbose) {
(void) printf("snap %s already exists; "
"ignoring\n", zc.zc_value);
}
err = ioctl_err = recv_skip(hdl, infd,
- flags.byteswap);
+ flags->byteswap);
}
}
*cp = '@';
@@ -2793,7 +2886,7 @@ zfs_receive_one(libzfs_handle_t *hdl, int infd, const char *tosnap,
case EDQUOT:
zfs_error_aux(hdl, dgettext(TEXT_DOMAIN,
"destination %s space quota exceeded"), zc.zc_name);
- (void) zfs_error(hdl, EZFS_BADRESTORE, errbuf);
+ (void) zfs_error(hdl, EZFS_NOSPC, errbuf);
break;
default:
(void) zfs_standard_error(hdl, ioctl_errno, errbuf);
@@ -2851,7 +2944,7 @@ zfs_receive_one(libzfs_handle_t *hdl, int infd, const char *tosnap,
*action_handlep = zc.zc_action_handle;
- if (flags.verbose) {
+ if (flags->verbose) {
char buf1[64];
char buf2[64];
uint64_t bytes = zc.zc_cookie;
@@ -2869,7 +2962,7 @@ zfs_receive_one(libzfs_handle_t *hdl, int infd, const char *tosnap,
}
static int
-zfs_receive_impl(libzfs_handle_t *hdl, const char *tosnap, recvflags_t flags,
+zfs_receive_impl(libzfs_handle_t *hdl, const char *tosnap, recvflags_t *flags,
int infd, const char *sendfs, nvlist_t *stream_nv, avl_tree_t *stream_avl,
char **top_zfs, int cleanup_fd, uint64_t *action_handlep)
{
@@ -2884,7 +2977,7 @@ zfs_receive_impl(libzfs_handle_t *hdl, const char *tosnap, recvflags_t flags,
(void) snprintf(errbuf, sizeof (errbuf), dgettext(TEXT_DOMAIN,
"cannot receive"));
- if (flags.isprefix &&
+ if (flags->isprefix &&
!zfs_dataset_exists(hdl, tosnap, ZFS_TYPE_DATASET)) {
zfs_error_aux(hdl, dgettext(TEXT_DOMAIN, "specified fs "
"(%s) does not exist"), tosnap);
@@ -2904,7 +2997,7 @@ zfs_receive_impl(libzfs_handle_t *hdl, const char *tosnap, recvflags_t flags,
/* the kernel needs the non-byteswapped begin record */
drr_noswap = drr;
- flags.byteswap = B_FALSE;
+ flags->byteswap = B_FALSE;
if (drrb->drr_magic == BSWAP_64(DMU_BACKUP_MAGIC)) {
/*
* We computed the checksum in the wrong byteorder in
@@ -2912,7 +3005,7 @@ zfs_receive_impl(libzfs_handle_t *hdl, const char *tosnap, recvflags_t flags,
*/
bzero(&zcksum, sizeof (zio_cksum_t));
fletcher_4_incremental_byteswap(&drr, sizeof (drr), &zcksum);
- flags.byteswap = B_TRUE;
+ flags->byteswap = B_TRUE;
drr.drr_type = BSWAP_32(drr.drr_type);
drr.drr_payloadlen = BSWAP_32(drr.drr_payloadlen);
@@ -2980,7 +3073,7 @@ zfs_receive_impl(libzfs_handle_t *hdl, const char *tosnap, recvflags_t flags,
* (-1 will override -2).
*/
int
-zfs_receive(libzfs_handle_t *hdl, const char *tosnap, recvflags_t flags,
+zfs_receive(libzfs_handle_t *hdl, const char *tosnap, recvflags_t *flags,
int infd, avl_tree_t *stream_avl)
{
char *top_zfs = NULL;
@@ -2996,7 +3089,7 @@ zfs_receive(libzfs_handle_t *hdl, const char *tosnap, recvflags_t flags,
VERIFY(0 == close(cleanup_fd));
- if (err == 0 && !flags.nomount && top_zfs) {
+ if (err == 0 && !flags->nomount && top_zfs) {
zfs_handle_t *zhp;
prop_changelist_t *clp;
diff --git a/usr/src/lib/libzfs/common/libzfs_util.c b/usr/src/lib/libzfs/common/libzfs_util.c
index 01b7c8732e..6754bb98d0 100644
--- a/usr/src/lib/libzfs/common/libzfs_util.c
+++ b/usr/src/lib/libzfs/common/libzfs_util.c
@@ -20,6 +20,7 @@
*/
/*
* Copyright (c) 2005, 2010, Oracle and/or its affiliates. All rights reserved.
+ * Copyright (c) 2011 by Delphix. All rights reserved.
*/
/*
@@ -344,6 +345,7 @@ zfs_standard_error_fmt(libzfs_handle_t *hdl, int error, const char *fmt, ...)
switch (error) {
case ENXIO:
case ENODEV:
+ case EPIPE:
zfs_verror(hdl, EZFS_IO, fmt, ap);
break;
@@ -1281,7 +1283,8 @@ addlist(libzfs_handle_t *hdl, char *propname, zprop_list_t **listp,
* dataset property,
*/
if (prop == ZPROP_INVAL && (type == ZFS_TYPE_POOL ||
- (!zfs_prop_user(propname) && !zfs_prop_userquota(propname)))) {
+ (!zfs_prop_user(propname) && !zfs_prop_userquota(propname) &&
+ !zfs_prop_written(propname)))) {
zfs_error_aux(hdl, dgettext(TEXT_DOMAIN,
"invalid property '%s'"), propname);
return (zfs_error(hdl, EZFS_BADPROP,
diff --git a/usr/src/lib/libzfs/common/mapfile-vers b/usr/src/lib/libzfs/common/mapfile-vers
index b435b58e05..e4a45d3ecb 100644
--- a/usr/src/lib/libzfs/common/mapfile-vers
+++ b/usr/src/lib/libzfs/common/mapfile-vers
@@ -19,7 +19,8 @@
# CDDL HEADER END
#
# Copyright (c) 2006, 2010, Oracle and/or its affiliates. All rights reserved.
-# Copyright 2010 Nexenta Systems, Inc. All rights reserved.
+# Copyright 2011 Nexenta Systems, Inc. All rights reserved.
+# Copyright (c) 2011 by Delphix. All rights reserved.
#
# MAPFILE HEADER START
#
@@ -68,13 +69,16 @@ SYMBOL_VERSION SUNWprivate_1.1 {
zfs_deleg_share_nfs;
zfs_destroy;
zfs_destroy_snaps;
+ zfs_destroy_snaps_nvl;
zfs_expand_proplist;
zfs_get_handle;
zfs_get_holds;
zfs_get_name;
zfs_get_pool_handle;
+ zfs_get_snapused_int;
zfs_get_user_props;
zfs_get_type;
+ zfs_handle_dup;
zfs_history_event_names;
zfs_hold;
zfs_is_mounted;
@@ -87,6 +91,7 @@ SYMBOL_VERSION SUNWprivate_1.1 {
zfs_iter_root;
zfs_iter_snapshots;
zfs_iter_snapshots_sorted;
+ zfs_iter_snapspec;
zfs_mount;
zfs_name_to_prop;
zfs_name_valid;
@@ -106,6 +111,8 @@ SYMBOL_VERSION SUNWprivate_1.1 {
zfs_prop_get_table;
zfs_prop_get_userquota_int;
zfs_prop_get_userquota;
+ zfs_prop_get_written_int;
+ zfs_prop_get_written;
zfs_prop_inherit;
zfs_prop_inheritable;
zfs_prop_init;
@@ -118,6 +125,7 @@ SYMBOL_VERSION SUNWprivate_1.1 {
zfs_prop_userquota;
zfs_prop_valid_for_type;
zfs_prop_values;
+ zfs_prop_written;
zfs_prune_proplist;
zfs_receive;
zfs_refresh_properties;
@@ -199,6 +207,7 @@ SYMBOL_VERSION SUNWprivate_1.1 {
zpool_prop_values;
zpool_read_label;
zpool_refresh_stats;
+ zpool_reguid;
zpool_scan;
zpool_search_import;
zpool_set_history_str;
diff --git a/usr/src/lib/libzonecfg/common/getzoneent.c b/usr/src/lib/libzonecfg/common/getzoneent.c
index 76cc918553..76664fcc92 100644
--- a/usr/src/lib/libzonecfg/common/getzoneent.c
+++ b/usr/src/lib/libzonecfg/common/getzoneent.c
@@ -403,14 +403,6 @@ putzoneent(struct zoneent *ze, zoneent_op_t operation)
*/
if (ze->zone_state >= 0) {
zone_state = zone_state_str(ze->zone_state);
-
- /*
- * If the caller is uninstalling this zone,
- * then wipe out the uuid. The zone's contents
- * are no longer known.
- */
- if (ze->zone_state < ZONE_STATE_INSTALLED)
- zone_uuid = "";
}
/* If a new name is supplied, use it. */
diff --git a/usr/src/lib/libzonecfg/common/libzonecfg.c b/usr/src/lib/libzonecfg/common/libzonecfg.c
index f5ac4975d8..97fd1f52e2 100644
--- a/usr/src/lib/libzonecfg/common/libzonecfg.c
+++ b/usr/src/lib/libzonecfg/common/libzonecfg.c
@@ -4768,7 +4768,7 @@ get_pool_sched_class(char *poolname, char *class, int clsize)
pool_conf_t *poolconf;
pool_t *pool;
pool_elem_t *pe;
- pool_value_t *pv = pool_value_alloc();
+ pool_value_t *pv;
const char *sched_str;
if (pool_get_status(&status) != PO_SUCCESS || status != POOL_ENABLED)
@@ -4789,15 +4789,23 @@ get_pool_sched_class(char *poolname, char *class, int clsize)
return (Z_NO_POOL);
}
+ if ((pv = pool_value_alloc()) == NULL) {
+ (void) pool_conf_close(poolconf);
+ pool_conf_free(poolconf);
+ return (Z_NO_POOL);
+ }
+
pe = pool_to_elem(poolconf, pool);
if (pool_get_property(poolconf, pe, "pool.scheduler", pv) !=
POC_STRING) {
(void) pool_conf_close(poolconf);
+ pool_value_free(pv);
pool_conf_free(poolconf);
return (Z_NO_ENTRY);
}
(void) pool_value_get_string(pv, &sched_str);
(void) pool_conf_close(poolconf);
+ pool_value_free(pv);
pool_conf_free(poolconf);
if (strlcpy(class, sched_str, clsize) >= clsize)
return (Z_TOO_BIG);
diff --git a/usr/src/lib/smbsrv/libmlsvc/common/smb_share.c b/usr/src/lib/smbsrv/libmlsvc/common/smb_share.c
index 5f62c02e51..fd8e091147 100644
--- a/usr/src/lib/smbsrv/libmlsvc/common/smb_share.c
+++ b/usr/src/lib/smbsrv/libmlsvc/common/smb_share.c
@@ -17,9 +17,9 @@
* information: Portions Copyright [yyyy] [name of copyright owner]
*
* CDDL HEADER END
- */
-/*
+ *
* Copyright (c) 2007, 2010, Oracle and/or its affiliates. All rights reserved.
+ * Copyright 2011 Nexenta Systems, Inc. All rights reserved.
*/
/*
@@ -739,9 +739,6 @@ smb_shr_exists(char *sharename)
* Precedence is none is checked first followed by ro then rw if
* needed. If x is wildcard (< 0) then check to see if the other
* values are a match. If a match, that wins.
- *
- * ipv6 is wide open (returns SMB_SHRF_ACC_OPEN) for now until the underlying
- * functions support ipv6.
*/
uint32_t
smb_shr_hostaccess(smb_inaddr_t *ipaddr, char *none_list, char *ro_list,
@@ -753,10 +750,6 @@ smb_shr_hostaccess(smb_inaddr_t *ipaddr, char *none_list, char *ro_list,
int rw = 0;
if (!smb_inet_iszero(ipaddr)) {
-
- if (ipaddr->a_family == AF_INET6)
- return (SMB_SHRF_ACC_OPEN);
-
if ((flag & SMB_SHRF_ACC_NONE) != 0)
none = smb_chk_hostaccess(ipaddr, none_list);
if ((flag & SMB_SHRF_ACC_RO) != 0)
diff --git a/usr/src/lib/smbsrv/libsmb/common/smb_lgrp.c b/usr/src/lib/smbsrv/libsmb/common/smb_lgrp.c
index ea51a7e369..8435a20c32 100644
--- a/usr/src/lib/smbsrv/libsmb/common/smb_lgrp.c
+++ b/usr/src/lib/smbsrv/libsmb/common/smb_lgrp.c
@@ -20,6 +20,7 @@
*/
/*
+ * Copyright 2011 Nexenta Systems, Inc. All rights reserved.
* Copyright (c) 2008, 2010, Oracle and/or its affiliates. All rights reserved.
*/
@@ -1033,14 +1034,25 @@ smb_lgrp_err_to_ntstatus(uint32_t lgrp_err)
* smb_lgrp_chkmember
*
* Determines valid account types for being member of
- * a local group.
- *
- * Currently, we just support users as valid members.
+ * a local group. We really have no business trying to
+ * keep track of the "type" of SIDs in a group, so just
+ * validate that the SID type is a known enum value.
*/
static boolean_t
smb_lgrp_chkmember(uint16_t sid_type)
{
- return (sid_type == SidTypeUser);
+ switch (sid_type) {
+ case SidTypeNull:
+ case SidTypeUser:
+ case SidTypeGroup:
+ case SidTypeAlias:
+ case SidTypeWellKnownGroup:
+ case SidTypeDeletedAccount:
+ case SidTypeInvalid:
+ case SidTypeUnknown:
+ return (B_TRUE);
+ }
+ return (B_FALSE);
}
/*
diff --git a/usr/src/lib/smbsrv/libsmb/common/smb_sam.c b/usr/src/lib/smbsrv/libsmb/common/smb_sam.c
index 21be70116b..7016f5a878 100644
--- a/usr/src/lib/smbsrv/libsmb/common/smb_sam.c
+++ b/usr/src/lib/smbsrv/libsmb/common/smb_sam.c
@@ -19,6 +19,7 @@
* CDDL HEADER END
*/
/*
+ * Copyright 2011 Nexenta Systems, Inc. All rights reserved.
* Copyright 2010 Sun Microsystems, Inc. All rights reserved.
* Use is subject to license terms.
*/
@@ -299,24 +300,45 @@ smb_sam_usr_cnt(void)
}
/*
- * Returns a list of local groups which the given user is
- * their member. A pointer to an array of smb_ids_t
- * structure is returned which must be freed by caller.
+ * Updates a list of groups in which the given user is a member
+ * by adding any local (SAM) groups.
+ *
+ * We are a member of local groups where the local group
+ * contains either the user's primary SID, or any of their
+ * other SIDs such as from domain groups, SID history, etc.
+ * We can have indirect membership via domain groups.
*/
uint32_t
smb_sam_usr_groups(smb_sid_t *user_sid, smb_ids_t *gids)
{
- smb_id_t *ids;
+ smb_ids_t new_gids;
+ smb_id_t *ids, *new_ids;
smb_giter_t gi;
smb_group_t lgrp;
- int total_cnt, gcnt;
+ int i, gcnt, total_cnt;
+ uint32_t ret;
+ boolean_t member;
+ /*
+ * First pass: count groups to be added (gcnt)
+ */
gcnt = 0;
if (smb_lgrp_iteropen(&gi) != SMB_LGRP_SUCCESS)
return (NT_STATUS_INTERNAL_ERROR);
while (smb_lgrp_iterate(&gi, &lgrp) == SMB_LGRP_SUCCESS) {
+ member = B_FALSE;
if (smb_lgrp_is_member(&lgrp, user_sid))
+ member = B_TRUE;
+ else for (i = 0, ids = gids->i_ids;
+ i < gids->i_cnt; i++, ids++) {
+ if (smb_lgrp_is_member(&lgrp, ids->i_sid)) {
+ member = B_TRUE;
+ break;
+ }
+ }
+ /* Careful: only count lgrp once */
+ if (member)
gcnt++;
smb_lgrp_free(&lgrp);
}
@@ -325,35 +347,86 @@ smb_sam_usr_groups(smb_sid_t *user_sid, smb_ids_t *gids)
if (gcnt == 0)
return (NT_STATUS_SUCCESS);
- total_cnt = gids->i_cnt + gcnt;
- gids->i_ids = realloc(gids->i_ids, total_cnt * sizeof (smb_id_t));
- if (gids->i_ids == NULL)
- return (NT_STATUS_NO_MEMORY);
-
+ /*
+ * Second pass: add to groups list.
+ * Do not modify gcnt after here.
+ */
if (smb_lgrp_iteropen(&gi) != SMB_LGRP_SUCCESS)
return (NT_STATUS_INTERNAL_ERROR);
- ids = gids->i_ids + gids->i_cnt;
+ /*
+ * Expand the list (copy to a new, larger one)
+ * Note: were're copying pointers from the old
+ * array to the new (larger) array, and then
+ * adding new pointers after what we copied.
+ */
+ ret = 0;
+ new_gids.i_cnt = gids->i_cnt;
+ total_cnt = gids->i_cnt + gcnt;
+ new_gids.i_ids = malloc(total_cnt * sizeof (smb_id_t));
+ if (new_gids.i_ids == NULL) {
+ ret = NT_STATUS_NO_MEMORY;
+ goto out;
+ }
+ (void) memcpy(new_gids.i_ids, gids->i_ids,
+ gids->i_cnt * sizeof (smb_id_t));
+ new_ids = new_gids.i_ids + gids->i_cnt;
+ (void) memset(new_ids, 0, gcnt * sizeof (smb_id_t));
+
+ /*
+ * Add group SIDs starting at the end of the
+ * previous list. (new_ids)
+ */
while (smb_lgrp_iterate(&gi, &lgrp) == SMB_LGRP_SUCCESS) {
- if (gcnt == 0) {
- smb_lgrp_free(&lgrp);
- break;
+ member = B_FALSE;
+ if (smb_lgrp_is_member(&lgrp, user_sid))
+ member = B_TRUE;
+ else for (i = 0, ids = gids->i_ids;
+ i < gids->i_cnt; i++, ids++) {
+ if (smb_lgrp_is_member(&lgrp, ids->i_sid)) {
+ member = B_TRUE;
+ break;
+ }
}
- if (smb_lgrp_is_member(&lgrp, user_sid)) {
- ids->i_sid = smb_sid_dup(lgrp.sg_id.gs_sid);
- if (ids->i_sid == NULL) {
+ if (member && (new_gids.i_cnt < (gids->i_cnt + gcnt))) {
+ new_ids->i_sid = smb_sid_dup(lgrp.sg_id.gs_sid);
+ if (new_ids->i_sid == NULL) {
smb_lgrp_free(&lgrp);
- return (NT_STATUS_NO_MEMORY);
+ ret = NT_STATUS_NO_MEMORY;
+ goto out;
}
- ids->i_attrs = lgrp.sg_attr;
- gids->i_cnt++;
- gcnt--;
- ids++;
+ new_ids->i_attrs = lgrp.sg_attr;
+ new_ids++;
+ new_gids.i_cnt++;
}
smb_lgrp_free(&lgrp);
}
+
+out:
smb_lgrp_iterclose(&gi);
+ if (ret != 0) {
+ if (new_gids.i_ids != NULL) {
+ /*
+ * Free only the new sids we added.
+ * The old ones were copied ptrs.
+ */
+ ids = new_gids.i_ids + gids->i_cnt;
+ for (i = 0; i < gcnt; i++, ids++) {
+ smb_sid_free(ids->i_sid);
+ }
+ free(new_gids.i_ids);
+ }
+ return (ret);
+ }
+
+ /*
+ * Success! Update passed gids and
+ * free the old array.
+ */
+ free(gids->i_ids);
+ *gids = new_gids;
+
return (NT_STATUS_SUCCESS);
}
diff --git a/usr/src/lib/smbsrv/libsmb/common/smb_util.c b/usr/src/lib/smbsrv/libsmb/common/smb_util.c
index 27d770912a..3bd80e4425 100644
--- a/usr/src/lib/smbsrv/libsmb/common/smb_util.c
+++ b/usr/src/lib/smbsrv/libsmb/common/smb_util.c
@@ -77,11 +77,9 @@ static void smb_log_trace(int, const char *);
static smb_log_t *smb_log_get(smb_log_hdl_t);
static void smb_log_dump(smb_log_t *);
-static uint_t smb_make_mask(char *, uint_t);
-static boolean_t smb_netmatch(struct netbuf *, char *);
static boolean_t smb_netgroup_match(struct nd_hostservlist *, char *, int);
-extern int __multi_innetgr();
+extern int __multi_innetgr();
extern int __netdir_getbyaddr_nosrv(struct netconfig *,
struct nd_hostservlist **, struct netbuf *);
@@ -413,54 +411,80 @@ rand_hash(
int
smb_chk_hostaccess(smb_inaddr_t *ipaddr, char *access_list)
{
- int nentries;
- char *gr;
- char *lasts;
+ char addr[INET_ADDRSTRLEN];
+ char buff[256];
+ char *cstr = access_list, *gr = access_list;
char *host;
- int off;
+ int clres;
int i;
+ int nentries = 0;
+ int off;
int response;
- int clres;
+ int sbr = 0;
struct nd_hostservlist *clnames;
struct in_addr inaddr;
struct sockaddr_in sa;
+ struct sockaddr_in6 sa6;
struct netbuf buf;
struct netconfig *config;
+ struct netent n, *np;
if (access_list == NULL)
return (0);
- inaddr.s_addr = ipaddr->a_ipv4;
-
- /*
- * If access list is empty or "*" - then it's "all"
- */
+ /* If access list is empty or "*" - then it's "all" */
if (*access_list == '\0' || strcmp(access_list, "*") == 0)
return (-1);
- nentries = 0;
-
- sa.sin_family = AF_INET;
- sa.sin_port = 0;
- sa.sin_addr = inaddr;
-
- buf.len = buf.maxlen = sizeof (sa);
- buf.buf = (char *)&sa;
+ switch (ipaddr->a_family) {
+ case AF_INET:
+ inaddr.s_addr = ipaddr->a_ipv4;
+ sa.sin_family = AF_INET;
+ sa.sin_port = 0;
+ sa.sin_addr = inaddr;
+ buf.len = buf.maxlen = sizeof (sa);
+ buf.buf = (char *)&sa;
+ config = getnetconfigent("tcp");
+ break;
+ case AF_INET6:
+ sa6.sin6_family = AF_INET6;
+ sa6.sin6_port = 0;
+ sa6.sin6_addr = ipaddr->a_ipv6;
+ buf.len = buf.maxlen = sizeof (sa6);
+ buf.buf = (char *)&sa6;
+ config = getnetconfigent("tcp6");
+ break;
+ default:
+ return (1);
+ }
- config = getnetconfigent("tcp");
if (config == NULL)
return (1);
+ /* Try to lookup client hostname */
clres = __netdir_getbyaddr_nosrv(config, &clnames, &buf);
freenetconfigent(config);
- for (gr = strtok_r(access_list, ":", &lasts);
- gr != NULL; gr = strtok_r(NULL, ":", &lasts)) {
+ for (;;) {
+ if ((cstr = strpbrk(cstr, "[]:")) != NULL) {
+ switch (*cstr) {
+ case '[':
+ case ']':
+ sbr = !sbr;
+ cstr++;
+ continue;
+ case ':':
+ if (sbr) {
+ cstr++;
+ continue;
+ }
+ *cstr = '\0';
+ }
+ }
/*
- * If the list name has a '-' prepended
- * then a match of the following name
- * implies failure instead of success.
+ * If the list name has a '-' prepended then a match of
+ * the following name implies failure instead of success.
*/
if (*gr == '-') {
response = 0;
@@ -470,21 +494,53 @@ smb_chk_hostaccess(smb_inaddr_t *ipaddr, char *access_list)
}
/*
- * First check if we have '@' entry, as smb_netmatch doesn't
- * care if client address can be resolved.
+ * First check if we have '@' entry, as it doesn't
+ * require client hostname.
*/
- if (*gr == '@')
- if (smb_netmatch(&buf, gr + 1))
- return (response);
+ if (*gr == '@') {
+ gr++;
+
+ if (!isdigit(*gr) && *gr != '[') {
+ /* Netname support */
+ if ((np = getnetbyname_r(gr, &n, buff,
+ sizeof (buff))) != NULL &&
+ np->n_net != 0) {
+ while ((np->n_net & 0xFF000000u) == 0)
+ np->n_net <<= 8;
+ np->n_net = htonl(np->n_net);
+ if (inet_ntop(AF_INET, &np->n_net, addr,
+ INET_ADDRSTRLEN) == NULL)
+ break;
+ if (inet_matchaddr(buf.buf, addr))
+ return (response);
+ }
+ } else {
+ if (inet_matchaddr(buf.buf, gr))
+ return (response);
+ }
+
+ if (cstr == NULL)
+ break;
+
+ gr = ++cstr;
+
+ continue;
+ }
+
/*
* No other checks can be performed if client address
* can't be resolved.
*/
- if (clres)
+ if (clres) {
+ if (cstr == NULL)
+ break;
+
+ gr = ++cstr;
+
continue;
- /*
- * Otherwise loop through all client hostname aliases.
- */
+ }
+
+ /* Otherwise loop through all client hostname aliases */
for (i = 0; i < clnames->h_cnt; i++) {
host = clnames->h_hostservs[i].h_host;
/*
@@ -494,7 +550,7 @@ smb_chk_hostaccess(smb_inaddr_t *ipaddr, char *access_list)
* suffix.
*/
if (*gr == '.') {
- if (*(gr + 1) == '\0') { /* single dot */
+ if (*(gr + 1) == '\0') {
if (strchr(host, '.') == NULL)
return (response);
} else {
@@ -505,15 +561,18 @@ smb_chk_hostaccess(smb_inaddr_t *ipaddr, char *access_list)
}
}
} else {
- /*
- * Just do a hostname match
- */
+ /* Just do a hostname match */
if (strcasecmp(gr, host) == 0)
return (response);
}
}
nentries++;
+
+ if (cstr == NULL)
+ break;
+
+ gr = ++cstr;
}
if (clres)
@@ -523,116 +582,6 @@ smb_chk_hostaccess(smb_inaddr_t *ipaddr, char *access_list)
}
/*
- * smb_make_mask
- *
- * Construct a mask for an IPv4 address using the @<dotted-ip>/<len>
- * syntax or use the default mask for the IP address.
- */
-static uint_t
-smb_make_mask(char *maskstr, uint_t addr)
-{
- uint_t mask;
- uint_t bits;
-
- /*
- * If the mask is specified explicitly then
- * use that value, e.g.
- *
- * @109.104.56/28
- *
- * otherwise assume a mask from the zero octets
- * in the least significant bits of the address, e.g.
- *
- * @109.104 or @109.104.0.0
- */
- if (maskstr) {
- bits = atoi(maskstr);
- mask = bits ? ~0 << ((sizeof (struct in_addr) * NBBY) - bits)
- : 0;
- addr &= mask;
- } else {
- if ((addr & IN_CLASSA_HOST) == 0)
- mask = IN_CLASSA_NET;
- else if ((addr & IN_CLASSB_HOST) == 0)
- mask = IN_CLASSB_NET;
- else if ((addr & IN_CLASSC_HOST) == 0)
- mask = IN_CLASSC_NET;
- else
- mask = IN_CLASSE_NET;
- }
-
- return (mask);
-}
-
-/*
- * smb_netmatch
- *
- * Check to see if the address in the netbuf matches the "net"
- * specified by name. The format of "name" can be:
- * fully qualified domain name
- * dotted IP address
- * dotted IP address followed by '/<len>'
- * See sharen_nfs(1M) for details.
- */
-
-static boolean_t
-smb_netmatch(struct netbuf *nb, char *name)
-{
- uint_t claddr;
- struct netent n, *np;
- char *mp, *p;
- uint_t addr, mask;
- int i;
- char buff[256];
-
- /*
- * Check if it's an IPv4 addr
- */
- if (nb->len != sizeof (struct sockaddr_in))
- return (B_FALSE);
-
- (void) memcpy(&claddr,
- /* LINTED pointer alignment */
- &((struct sockaddr_in *)nb->buf)->sin_addr.s_addr,
- sizeof (struct in_addr));
- claddr = ntohl(claddr);
-
- mp = strchr(name, '/');
- if (mp)
- *mp++ = '\0';
-
- if (isdigit(*name)) {
- /*
- * Convert a dotted IP address
- * to an IP address. The conversion
- * is not the same as that in inet_addr().
- */
- p = name;
- addr = 0;
- for (i = 0; i < 4; i++) {
- addr |= atoi(p) << ((3-i) * 8);
- p = strchr(p, '.');
- if (p == NULL)
- break;
- p++;
- }
- } else {
- /*
- * Turn the netname into
- * an IP address.
- */
- np = getnetbyname_r(name, &n, buff, sizeof (buff));
- if (np == NULL) {
- return (B_FALSE);
- }
- addr = np->n_net;
- }
-
- mask = smb_make_mask(mp, addr);
- return ((claddr & mask) == addr);
-}
-
-/*
* smb_netgroup_match
*
* Check whether any of the hostnames in clnames are
diff --git a/usr/src/man/man1m/beadm.1m b/usr/src/man/man1m/beadm.1m
index ded01aa60b..d5747d3c4f 100644
--- a/usr/src/man/man1m/beadm.1m
+++ b/usr/src/man/man1m/beadm.1m
@@ -18,7 +18,7 @@ beadm \- utility for managing zfs boot environments
.LP
.nf
-\fBbeadm\fR \fBdestroy\fR [\fB-fF\fR] \fIbeName\fR | \fIbeName@snapshot\fR
+\fBbeadm\fR \fBdestroy\fR [\fB-fFs\fR] \fIbeName\fR | \fIbeName@snapshot\fR
.fi
.LP
@@ -254,7 +254,7 @@ Creates a snapshot of the existing BE named beName.
.sp
.ne 2
.na
-\fBbeadm\fR \fBdestroy\fR [\fB-fF\fR] \fIbeName\fR | \fIbeName@snapshot\fR
+\fBbeadm\fR \fBdestroy\fR [\fB-fFs\fR] \fIbeName\fR | \fIbeName@snapshot\fR
.ad
.sp .6
.RS 4n
@@ -284,6 +284,16 @@ Forcefully unmount the boot environment if it is currently mounted.
Force the action without prompting to verify the destruction of the boot
environment.
.RE
+.sp
+.ne 2
+.na
+\fB-s\fR
+.ad
+.sp .6
+.RS 4n
+Destroy all snapshots of the boot
+environment.
+.RE
.RE
.sp
diff --git a/usr/src/man/man1m/mount_tmpfs.1m b/usr/src/man/man1m/mount_tmpfs.1m
index a4f38d3b1f..3520a3f31b 100644
--- a/usr/src/man/man1m/mount_tmpfs.1m
+++ b/usr/src/man/man1m/mount_tmpfs.1m
@@ -1,9 +1,10 @@
'\" te
.\" Copyright (c) 2003, Sun Microsystems, Inc. All Rights Reserved
+.\" Copyright (c) 2011, Joyent, Inc. All Rights Reserved
.\" 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]
-.TH MOUNT_TMPFS 1M "Nov 24, 2003"
+.TH MOUNT_TMPFS 1M "Dec 2, 2011"
.SH NAME
mount_tmpfs \- mount tmpfs file systems
.SH SYNOPSIS
@@ -45,6 +46,17 @@ available:
.sp
.ne 2
.na
+\fB\fBremount\fR\fR
+.ad
+.sp .6
+.RS 19n
+Remounts a file system with a new size. A size not explicitly
+set with \fBremount\fR reverts to no limit.
+.RE
+
+.sp
+.ne 2
+.na
\fBsize=\fIsz\fR\fR
.ad
.RS 19n
diff --git a/usr/src/man/man1m/smbadm.1m b/usr/src/man/man1m/smbadm.1m
index bd7ec4f262..b1e6e2de98 100644
--- a/usr/src/man/man1m/smbadm.1m
+++ b/usr/src/man/man1m/smbadm.1m
@@ -1,4 +1,5 @@
'\" te
+.\" Copyright 2011 Nexenta Systems, Inc. All rights reserved.
.\" Copyright (c) 2009, Sun Microsystems, Inc. All Rights Reserved.
.\" 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.
@@ -55,6 +56,11 @@ membership
.LP
.nf
+\fBsmbadm lookup\fR \fIaccount-name\fR [\fIaccount-name\fR [\&.\|.\|.]]
+.fi
+
+.LP
+.nf
\fBsmbadm remove-member\fR -m \fImember\fR [[-m \fImember\fR] \&.\|.\|.] \fIgroup\fR
.fi
@@ -398,6 +404,20 @@ Selected domain controller
.sp
.ne 2
.na
+\fB\fBlookup\fR\fR \fIaccount-name\fR [\fIaccount-name\fR [\&.\|.\|.]]
+
+.ad
+.sp .6
+.RS 4n
+Lookup the SID for the given \fIaccount-name\fR, or lookup the
+\fIaccount-name\fR for the given SID. This sub-command is
+primarily for diagnostic use, to confirm whether the server
+can lookup domain accounts and/or SIDs.
+.RE
+
+.sp
+.ne 2
+.na
\fB\fBremove-member\fR -m \fImember\fR [[-m \fImember\fR] \&.\|.\|.]
\fIgroup\fR\fR
.ad
diff --git a/usr/src/man/man1m/zfs.1m b/usr/src/man/man1m/zfs.1m
index d1052c7d2c..8a8e9e59ca 100644
--- a/usr/src/man/man1m/zfs.1m
+++ b/usr/src/man/man1m/zfs.1m
@@ -1,15 +1,13 @@
'\" te
.\" Copyright (c) 2009 Sun Microsystems, Inc. All Rights Reserved.
.\" Copyright (c) 2011 Joyent, Inc. All Rights Reserved.
-.\" 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]
+.\" Copyright (c) 2011 by Delphix. All rights reserved.
.\" 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]
.\" Copyright 2011 Nexenta Systems, Inc. All rights reserved.
.\" Copyright 2011 by Delphix. All rights reserved.
-.TH ZFS 1M "Sep 24, 2009"
+.TH ZFS 1M "28 Jul 2011"
.SH NAME
zfs \- configures ZFS file systems
.SH SYNOPSIS
@@ -30,12 +28,12 @@ zfs \- configures ZFS file systems
.LP
.nf
-\fBzfs\fR \fBdestroy\fR [\fB-rRf\fR] \fIfilesystem\fR|\fIvolume\fR
+\fBzfs\fR \fBdestroy\fR [\fB-fnpRrv\fR] \fIfilesystem\fR|\fIvolume\fR
.fi
.LP
.nf
-\fBzfs\fR \fBdestroy\fR [\fB-rRd\fR] \fIsnapshot\fR
+\fBzfs\fR \fBdestroy\fR [\fB-dnpRrv\fR] \fIfilesystem\fR|\fIvolume\fR@\fIsnap\fR[%\fIsnap\fR][,...]
.fi
.LP
@@ -110,13 +108,13 @@ zfs \- configures ZFS file systems
.LP
.nf
\fBzfs\fR \fBuserspace\fR [\fB-niHp\fR] [\fB-o\fR \fIfield\fR[,...]] [\fB-sS\fR \fIfield\fR] ...
- [\fB-t\fR \fItype\fR [,...]] \fIfilesystem\fR|\fIsnapshot\fR
+ [\fB-t\fR \fItype\fR[,...]] \fIfilesystem\fR|\fIsnapshot\fR
.fi
.LP
.nf
\fBzfs\fR \fBgroupspace\fR [\fB-niHp\fR] [\fB-o\fR \fIfield\fR[,...]] [\fB-sS\fR \fIfield\fR] ...
- [\fB-t\fR \fItype\fR [,...]] \fIfilesystem\fR|\fIsnapshot\fR
+ [\fB-t\fR \fItype\fR[,...]] \fIfilesystem\fR|\fIsnapshot\fR
.fi
.LP
@@ -146,7 +144,7 @@ zfs \- configures ZFS file systems
.LP
.nf
-\fBzfs\fR \fBsend\fR [\fB-vR\fR] [\fB-\fR[\fBiI\fR] \fIsnapshot\fR] \fIsnapshot\fR
+\fBzfs\fR \fBsend\fR [\fB-DnPpRrv\fR] [\fB-\fR[\fBiI\fR] \fIsnapshot\fR] \fIsnapshot\fR
.fi
.LP
@@ -484,6 +482,19 @@ The time this dataset was created.
.sp
.ne 2
.na
+\fB\fBclones\fR\fR
+.ad
+.sp .6
+.RS 4n
+For snapshots, this property is a comma-separated list of filesystems or
+volumes which are clones of this snapshot. The clones' \fBorigin\fR property
+is this snapshot. If the \fBclones\fR property is not empty, then this
+snapshot can not be destroyed (even with the \fB-r\fR or \fB-f\fR options).
+.RE
+
+.sp
+.ne 2
+.na
\fB\fBdefer_destroy\fR\fR
.ad
.sp .6
@@ -512,8 +523,7 @@ property can be either \fByes\fR or \fBno\fR.
.sp .6
.RS 4n
For cloned file systems or volumes, the snapshot from which the clone was
-created. The origin cannot be destroyed (even with the \fB-r\fR or \fB-f\fR
-options) so long as a clone exists.
+created. See also the \fBclones\fR property.
.RE
.sp
@@ -733,6 +743,36 @@ This property can also be referred to by its shortened column name,
.RE
.sp
+.ne 2
+.na
+\fB\fBwritten\fR\fR
+.ad
+.sp .6
+.RS 4n
+The amount of \fBreferenced\fR space written to this dataset since the
+previous snapshot.
+.RE
+
+.sp
+.ne 2
+.na
+\fB\fBwritten@\fR\fIsnapshot\fR\fR
+.ad
+.sp .6
+.RS 4n
+The amount of \fBreferenced\fR space written to this dataset since the
+specified snapshot. This is the space that is referenced by this dataset
+but was not referenced by the specified snapshot.
+.sp
+The \fIsnapshot\fR may be specified as a short snapshot name (just the part
+after the \fB@\fR), in which case it will be interpreted as a snapshot in
+the same filesystem as this dataset.
+The \fIsnapshot\fR be a full snapshot name (\fIfilesystem\fR@\fIsnapshot\fR),
+which for clones may be a snapshot in the origin's filesystem (or the origin
+of the origin's filesystem, etc).
+.RE
+
+.sp
.LP
The following native properties can be used to change the behavior of a
\fBZFS\fR dataset.
@@ -841,7 +881,7 @@ Changing this property affects only newly-written data.
.ne 2
.na
\fB\fBcompression\fR=\fBon\fR | \fBoff\fR | \fBlzjb\fR | \fBgzip\fR |
-\fBgzip-\fR\fIN\fR\fR
+\fBgzip-\fR\fIN\fR | \fBzle\fR\fR
.ad
.sp .6
.RS 4n
@@ -852,7 +892,8 @@ algorithm. The \fBgzip\fR compression algorithm uses the same compression as
the \fBgzip\fR(1) command. You can specify the \fBgzip\fR level by using the
value \fBgzip-\fR\fIN\fR where \fIN\fR is an integer from 1 (fastest) to 9
(best compression ratio). Currently, \fBgzip\fR is equivalent to \fBgzip-6\fR
-(which is also the default for \fBgzip\fR(1)).
+(which is also the default for \fBgzip\fR(1)). The \fBzle\fR compression
+algorithm compresses runs of zeros.
.sp
This property can also be referred to by its shortened column name
\fBcompress\fR. Changing this property affects only newly-written data.
@@ -1251,6 +1292,26 @@ the file system as discussed in the "Snapshots" section. The default value is
.sp
.ne 2
.na
+\fB\fBsync\fR=\fBdefault\fR | \fBalways\fR | \fBdisabled\fR\fR
+.ad
+.sp .6
+.RS 4n
+Controls the behavior of synchronous requests (e.g. fsync, O_DSYNC).
+\fBdefault\fR is the POSIX specified behavior of ensuring all synchronous
+requests are written to stable storage and all devices are flushed to ensure
+data is not cached by device controllers (this is the default). \fBalways\fR
+causes every file system transaction to be written and flushed before its
+system call returns. This has a large performance penalty. \fBdisabled\fR
+disables synchronous requests. File system transactions are only committed to
+stable storage periodically. This option will give the highest performance.
+However, it is very dangerous as ZFS would be ignoring the synchronous
+transaction demands of applications such as databases or NFS. Administrators
+should only use this option when the risks are understood.
+.RE
+
+.sp
+.ne 2
+.na
\fB\fBversion\fR=\fB1\fR | \fB2\fR | \fBcurrent\fR\fR
.ad
.sp .6
@@ -1597,7 +1658,7 @@ behavior is undefined.
.sp
.ne 2
.na
-\fB\fBzfs destroy\fR [\fB-rRf\fR] \fIfilesystem\fR|\fIvolume\fR\fR
+\fBzfs destroy\fR [\fB-fnpRrv\fR] \fIfilesystem\fR|\fIvolume\fR
.ad
.sp .6
.RS 4n
@@ -1637,6 +1698,38 @@ Force an unmount of any file systems using the \fBunmount -f\fR command. This
option has no effect on non-file systems or unmounted file systems.
.RE
+.sp
+.ne 2
+.na
+\fB\fB-n\fR\fR
+.ad
+.sp .6
+.RS 4n
+Do a dry-run ("No-op") deletion. No data will be deleted. This is
+useful in conjunction with the \fB-v\fR or \fB-p\fR flags to determine what
+data would be deleted.
+.RE
+
+.sp
+.ne 2
+.na
+\fB\fB-p\fR\fR
+.ad
+.sp .6
+.RS 4n
+Print machine-parsable verbose information about the deleted data.
+.RE
+
+.sp
+.ne 2
+.na
+\fB\fB-v\fR\fR
+.ad
+.sp .6
+.RS 4n
+Print verbose information about the deleted data.
+.RE
+.sp
Extreme care should be taken when applying either the \fB-r\fR or the \fB-R\fR
options, as they can destroy large portions of a pool and cause unexpected
behavior for mounted file systems in use.
@@ -1645,19 +1738,31 @@ behavior for mounted file systems in use.
.sp
.ne 2
.na
-\fB\fBzfs destroy\fR [\fB-rRd\fR] \fIsnapshot\fR\fR
+\fBzfs destroy\fR [\fB-dnpRrv\fR] \fIfilesystem\fR|\fIvolume\fR@\fIsnap\fR[%\fIsnap\fR][,...]
.ad
.sp .6
.RS 4n
-The given snapshot is destroyed immediately if and only if the \fBzfs
+The given snapshots are destroyed immediately if and only if the \fBzfs
destroy\fR command without the \fB-d\fR option would have destroyed it. Such
immediate destruction would occur, for example, if the snapshot had no clones
and the user-initiated reference count were zero.
.sp
-If the snapshot does not qualify for immediate destruction, it is marked for
+If a snapshot does not qualify for immediate destruction, it is marked for
deferred deletion. In this state, it exists as a usable, visible snapshot until
both of the preconditions listed above are met, at which point it is destroyed.
.sp
+An inclusive range of snapshots may be specified by separating the
+first and last snapshots with a percent sign.
+The first and/or last snapshots may be left blank, in which case the
+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.
+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.
+.sp
.ne 2
.na
\fB\fB-d\fR\fR
@@ -1688,6 +1793,44 @@ descendent file systems.
Recursively destroy all dependents.
.RE
+.sp
+.ne 2
+.na
+\fB\fB-n\fR\fR
+.ad
+.sp .6
+.RS 4n
+Do a dry-run ("No-op") deletion. No data will be deleted. This is
+useful in conjunction with the \fB-v\fR or \fB-p\fR flags to determine what
+data would be deleted.
+.RE
+
+.sp
+.ne 2
+.na
+\fB\fB-p\fR\fR
+.ad
+.sp .6
+.RS 4n
+Print machine-parsable verbose information about the deleted data.
+.RE
+
+.sp
+.ne 2
+.na
+\fB\fB-v\fR\fR
+.ad
+.sp .6
+.RS 4n
+Print verbose information about the deleted data.
+.RE
+
+.sp
+Extreme care should be taken when applying either the \fB-r\fR or the \fB-f\fR
+options, as they can destroy large portions of a pool and cause unexpected
+behavior for mounted file systems in use.
+.RE
+
.RE
.sp
@@ -2579,8 +2722,7 @@ Unshare the specified filesystem. The command can also be given a path to a
.sp
.ne 2
.na
-\fB\fBzfs send\fR [\fB-vR\fR] [\fB-\fR[\fBiI\fR] \fIsnapshot\fR]
-\fIsnapshot\fR\fR
+\fBzfs send\fR [\fB-DnPpRrv\fR] [\fB-\fR[\fBiI\fR] \fIsnapshot\fR] \fIsnapshot\fR
.ad
.sp .6
.RS 4n
@@ -2641,6 +2783,66 @@ snapshots and file systems that do not exist on the sending side are destroyed.
.sp
.ne 2
.na
+\fB\fB-D\fR\fR
+.ad
+.sp .6
+.RS 4n
+Generate a deduplicated stream. Blocks which would have been sent multiple
+times in the send stream will only be sent once. The receiving system must
+also support this feature to recieve a deduplicated stream. This flag can
+be used regardless of the dataset's \fBdedup\fR property, but performance
+will be much better if the filesystem uses a dedup-capable checksum (eg.
+\fBsha256\fR).
+.RE
+
+.sp
+.ne 2
+.na
+\fB\fB-r\fR\fR
+.ad
+.sp .6
+.RS 4n
+Recursively send all descendant snapshots. This is similar to the \fB-R\fR
+flag, but information about deleted and renamed datasets is not included, and
+property information is only included if the \fB-p\fR flag is specified.
+.RE
+
+.sp
+.ne 2
+.na
+\fB\fB-p\fR\fR
+.ad
+.sp .6
+.RS 4n
+Include the dataset's properties in the stream. This flag is implicit when
+\fB-R\fR is specified. The receiving system must also support this feature.
+.RE
+
+.sp
+.ne 2
+.na
+\fB\fB-n\fR\fR
+.ad
+.sp .6
+.RS 4n
+Do a dry-run ("No-op") send. Do not generate any actual send data. This is
+useful in conjunction with the \fB-v\fR or \fB-P\fR flags to determine what
+data will be sent.
+.RE
+
+.sp
+.ne 2
+.na
+\fB\fB-P\fR\fR
+.ad
+.sp .6
+.RS 4n
+Print machine-parsable verbose information about the stream package generated.
+.RE
+
+.sp
+.ne 2
+.na
\fB\fB-v\fR\fR
.ad
.sp .6
diff --git a/usr/src/man/man1m/zpool.1m b/usr/src/man/man1m/zpool.1m
index 24cbd03c56..1d1fd378a7 100644
--- a/usr/src/man/man1m/zpool.1m
+++ b/usr/src/man/man1m/zpool.1m
@@ -1,10 +1,11 @@
'\" te
.\" Copyright (c) 2007, Sun Microsystems, Inc. All Rights Reserved.
.\" Copyright (c) 2011, Joyent, Inc. All Rights Reserved.
+.\" Copyright 2011, Nexenta Systems, Inc. All Rights Reserved.
.\" 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]
-.TH ZPOOL 1M "Sep 21, 2009"
+.TH ZPOOL 1M "Nov 14, 2011"
.SH NAME
zpool \- configures ZFS storage pools
.SH SYNOPSIS
@@ -98,6 +99,11 @@ zpool \- configures ZFS storage pools
.LP
.nf
+\fBzpool reguid\fR \fIpool\fR
+.fi
+
+.LP
+.nf
\fBzpool remove\fR \fIpool\fR \fIdevice\fR ...
.fi
@@ -541,6 +547,17 @@ shortened column name, "cap".
.sp
.ne 2
.na
+\fB\fBcomment\fR\fR
+.ad
+.RS 20n
+A text string consisting of printable ASCII characters that will be stored
+such that it is available even if the pool becomes faulted. An administrator
+can provide additional information about a pool using this property.
+.RE
+
+.sp
+.ne 2
+.na
\fB\fBhealth\fR\fR
.ad
.RS 20n
@@ -1463,6 +1480,17 @@ become available to the pool.
.sp
.ne 2
.na
+\fB\fBzpool reguid\fR \fIpool\fR
+.ad
+.sp .6
+.RS 4n
+Generates a new unique identifier for the pool. You must ensure that all devices in this pool are online and
+healthy before performing this action.
+.RE
+
+.sp
+.ne 2
+.na
\fB\fBzpool remove\fR \fIpool\fR \fIdevice\fR ...\fR
.ad
.sp .6
diff --git a/usr/src/pkg/Makefile b/usr/src/pkg/Makefile
index 378a0f6791..e01f585ed6 100644
--- a/usr/src/pkg/Makefile
+++ b/usr/src/pkg/Makefile
@@ -485,7 +485,7 @@ $(REPOS:%=$(PKGDEST)/repo.%):
$(PDIR)/%.mog: manifests/%.mf
@print "Processing manifest $(<F)"
- @pkgfmt -c $<
+ @env PKGFMT_OUTPUT=v1 pkgfmt -c $<
$(PKGDEBUG)$(RM) $(@) $(@:%.mog=%) $(@:%.mog=%.nodepend) \
$(@:%.mog=%.lics) $(PDIR)/$(@F:%.mog=%).metadata.* $(@).vars
$(PKGDEBUG)$(PKGMOGRIFY) $(PKGMOG_VERBOSE) $(PM_INC:%= -I %) \
diff --git a/usr/src/pkg/manifests/system-dtrace-tests.mf b/usr/src/pkg/manifests/system-dtrace-tests.mf
index 968dde6851..f609e2793a 100644
--- a/usr/src/pkg/manifests/system-dtrace-tests.mf
+++ b/usr/src/pkg/manifests/system-dtrace-tests.mf
@@ -21,6 +21,7 @@
#
# Copyright (c) 2010, Oracle and/or its affiliates. All rights reserved.
+# Copyright (c) 2011 by Delphix. All rights reserved.
#
set name=pkg.fmri value=pkg:/system/dtrace/tests@$(PKGVERS)
@@ -83,6 +84,7 @@ dir path=opt/SUNWdtrt/tst/common/pointers
dir path=opt/SUNWdtrt/tst/common/pragma
dir path=opt/SUNWdtrt/tst/common/predicates
dir path=opt/SUNWdtrt/tst/common/preprocessor
+dir path=opt/SUNWdtrt/tst/common/print
dir path=opt/SUNWdtrt/tst/common/printa
dir path=opt/SUNWdtrt/tst/common/printf
dir path=opt/SUNWdtrt/tst/common/privs
@@ -1220,6 +1222,17 @@ file path=opt/SUNWdtrt/tst/common/preprocessor/tst.preexpifelse.d mode=0444
file path=opt/SUNWdtrt/tst/common/preprocessor/tst.preexpifelse.d.out \
mode=0444
file path=opt/SUNWdtrt/tst/common/preprocessor/tst.withinprobe.d mode=0444
+file path=opt/SUNWdtrt/tst/common/print/err.D_PRINT_DYN.bad.d mode=0444
+file path=opt/SUNWdtrt/tst/common/print/err.D_PRINT_VOID.bad.d mode=0444
+file path=opt/SUNWdtrt/tst/common/print/err.D_PROTO_LEN.bad.d mode=0444
+file path=opt/SUNWdtrt/tst/common/print/tst.array.d mode=0444
+file path=opt/SUNWdtrt/tst/common/print/tst.array.d.out mode=0444
+file path=opt/SUNWdtrt/tst/common/print/tst.bitfield.d mode=0444
+file path=opt/SUNWdtrt/tst/common/print/tst.bitfield.d.out mode=0444
+file path=opt/SUNWdtrt/tst/common/print/tst.primitive.d mode=0444
+file path=opt/SUNWdtrt/tst/common/print/tst.primitive.d.out mode=0444
+file path=opt/SUNWdtrt/tst/common/print/tst.struct.d mode=0444
+file path=opt/SUNWdtrt/tst/common/print/tst.struct.d.out mode=0444
file path=opt/SUNWdtrt/tst/common/printa/err.D_PRINTA_AGGARG.badagg.d \
mode=0444
file path=opt/SUNWdtrt/tst/common/printa/err.D_PRINTA_AGGARG.badfmt.d \
@@ -1753,6 +1766,7 @@ file path=opt/SUNWdtrt/tst/common/tick-n/tst.tickus.d.out mode=0444
file path=opt/SUNWdtrt/tst/common/tick-n/tst.tickusec.d mode=0444
file path=opt/SUNWdtrt/tst/common/tick-n/tst.tickusec.d.out mode=0444
file path=opt/SUNWdtrt/tst/common/trace/err.D_PROTO_LEN.bad.d mode=0444
+file path=opt/SUNWdtrt/tst/common/trace/err.D_TRACE_DYN.bad.d mode=0444
file path=opt/SUNWdtrt/tst/common/trace/err.D_TRACE_VOID.bad.d mode=0444
file path=opt/SUNWdtrt/tst/common/trace/tst.misc.d mode=0444
file path=opt/SUNWdtrt/tst/common/trace/tst.qstring.d mode=0444
diff --git a/usr/src/tools/env/illumos.sh b/usr/src/tools/env/illumos.sh
index 24475d0d37..28013d654a 100644
--- a/usr/src/tools/env/illumos.sh
+++ b/usr/src/tools/env/illumos.sh
@@ -181,6 +181,9 @@ export PARENT_TOOLS_ROOT="$PARENT_WS/usr/src/tools/proto/root_$MACH-nd"
export PKGARCHIVE="${CODEMGR_WS}/packages/${MACH}/nightly"
# export PKGPUBLISHER_REDIST='on-redist'
+# Package manifest format version.
+export PKGFMT_OUTPUT='v1'
+
# we want make to do as much as it can, just in case there's more than
# one problem.
export MAKEFLAGS='k'
diff --git a/usr/src/ucbhead/stdio.h b/usr/src/ucbhead/stdio.h
index 6d544b81b8..dd6cc3bce9 100644
--- a/usr/src/ucbhead/stdio.h
+++ b/usr/src/ucbhead/stdio.h
@@ -81,29 +81,8 @@ typedef long fpos_t;
#define NULL 0
#endif
-#if defined(__STDC__)
-
#define BUFSIZ 1024
-#else /* !defined(__STDC__) */
-
-#if pdp11 || u370
-
-#if pdp11
-#define BUFSIZ 512
-#define _STDIO_REVERSE
-#else /* u370 */
-#define BUFSIZ 4096
-#define _STDIO_REVERSE
-#define _STDIO_ALLOCATE
-#endif
-
-#else
-#define BUFSIZ 1024
-#endif
-
-#endif /* __STDC__ */
-
#if defined(__i386)
#define _NFILE 60 /* initial number of streams: Intel x86 ABI */
#else
@@ -143,31 +122,19 @@ typedef long fpos_t;
#define L_tmpnam 25 /* (sizeof(P_tmpdir) + 15) */
-#if defined(__STDC__)
#define stdin (&__iob[0])
#define stdout (&__iob[1])
#define stderr (&__iob[2])
-#else
-#define stdin (&_iob[0])
-#define stdout (&_iob[1])
-#define stderr (&_iob[2])
-#endif
#ifndef _FILEDEFED
#define _FILEDEFED
typedef __FILE FILE;
#endif
-#if defined(__STDC__)
extern FILE __iob[_NFILE];
-#else
-extern FILE _iob[_NFILE];
-#endif
extern FILE *_lastbuf;
extern unsigned char *_bufendtab[];
-#ifndef _STDIO_ALLOCATE
extern unsigned char _sibuf[], _sobuf[];
-#endif
/* Large file interfaces */
/* transition back from explicit 64-bit offset to implicit (64-bit) offset */
@@ -192,7 +159,6 @@ extern unsigned char _sibuf[], _sobuf[];
#endif
#endif
-#if defined(__STDC__)
extern int remove(const char *);
extern int rename(const char *, const char *);
@@ -261,44 +227,16 @@ extern int fileno(FILE *);
#endif /* !defined(_STRICT_STDC) */
-#else /* !defined __STDC__ */
-#define _bufend(p) _bufendtab[fileno(p)]
-#define _bufsiz(p) (_bufend(p) - (p)->_base)
-
-extern FILE *fopen(), *fdopen(), *freopen(), *popen();
-extern long ftell();
-extern void rewind(), setbuf(), setbuffer();
-extern int setlinebuf();
-extern char *ctermid(), *cuserid(), *fgets(), *gets(), *sprintf(),
- *vsprintf();
-extern int fclose(), fflush(), fread(), fwrite(), fseek(), fgetc(),
- getw(), pclose(), printf(), fprintf(),
- vprintf(), vfprintf(), fputc(), putw(),
- puts(), fputs(), scanf(), fscanf(), sscanf(),
- setvbuf(), system(), ungetc();
-extern int fileno();
-extern int getc(), getchar(), putc(), putchar(), feof(), ferror();
-extern void clearerr();
-
-#endif /* __STDC__ */
#ifndef __lint
#ifndef _LP64
-#ifdef __STDC__
#define getc(p) (--(p)->_cnt < 0 ? __filbuf(p) : (int)*(p)->_ptr++)
#define putc(x, p) (--(p)->_cnt < 0 ? __flsbuf((x), (p)) \
: (int)(*(p)->_ptr++ = (x)))
-#else /* __STDC__ */
-
-#define getc(p) (--(p)->_cnt < 0 ? _filbuf(p) : (int)*(p)->_ptr++)
-#define putc(x, p) (--(p)->_cnt < 0 ? \
- _flsbuf((unsigned char) (x), (p)) : \
- (int)(*(p)->_ptr++ = (unsigned char)(x)))
-#endif /* __STDC__ */
#define clearerr(p) ((void) ((p)->_flag &= ~(_IOERR | _IOEOF)))
#define feof(p) ((p)->_flag & _IOEOF)
@@ -313,12 +251,8 @@ extern void clearerr();
#if defined(_LARGEFILE64_SOURCE) && !((_FILE_OFFSET_BITS == 64) && \
!defined(__PRAGMA_REDEFINE_EXTNAME))
-#if defined(__STDC__)
extern FILE *fopen64(const char *, const char *);
extern FILE *freopen64(const char *, const char *, FILE *);
-#else
-extern FILE *fopen64(), *freopen64();
-#endif
#endif /* _LARGEFILE64_SOURCE... */
#ifdef __cplusplus
diff --git a/usr/src/ucblib/libucb/port/gen/setbuffer.c b/usr/src/ucblib/libucb/port/gen/setbuffer.c
index 47aa76f88b..8eeea0179b 100644
--- a/usr/src/ucblib/libucb/port/gen/setbuffer.c
+++ b/usr/src/ucblib/libucb/port/gen/setbuffer.c
@@ -36,8 +36,6 @@
* Use is subject to license terms.
*/
-#pragma ident "%Z%%M% %I% %E% SMI"
-
/*LINTLIBRARY*/
#include <sys/types.h>
@@ -61,14 +59,11 @@ setbuffer(FILE *iop, char *abuf, int asize)
iop->_flag &= ~(_IOMYBUF | _IONBF | _IOLBF);
if (buf == 0) {
iop->_flag |= _IONBF;
-#ifndef _STDIO_ALLOCATE
if (fno < 2) {
/* use special buffer for std{in,out} */
buf = (fno == 0) ? _sibuf : _sobuf;
size = BUFSIZ - _SMBFSZ;
- } else /* needed for ifdef */
-#endif
- if (fno < _NFILE) {
+ } else if (fno < _NFILE) {
buf = _smbuf[fno];
size = _SMBFSZ - PUSHBACK;
} else if ((buf = (Uchar *)malloc(_SMBFSZ * sizeof (Uchar))) !=
diff --git a/usr/src/uts/Makefile.uts b/usr/src/uts/Makefile.uts
index 61ce96b688..9107d00708 100644
--- a/usr/src/uts/Makefile.uts
+++ b/usr/src/uts/Makefile.uts
@@ -22,6 +22,7 @@
#
# Copyright (c) 1991, 2010, Oracle and/or its affiliates. All rights reserved.
# Copyright (c) 2011 Bayard G. Bell. All rights reserved.
+# Copyright (c) 2011 by Delphix. All rights reserved.
#
#
@@ -318,8 +319,8 @@ CTFMERGE_GENUNIX = \
# is not being used, the value of $VERSION will be used.
#
# For the ease of developers dropping modules onto possibly unrelated systems,
-# you can set NO_GENUNIX_MERGE= in the environment to skip uniquifying against
-# genunix.
+# you can set NO_GENUNIX_UNIQUIFY= in the environment to skip uniquifying
+# against genunix.
#
NO_GENUNIX_UNIQUIFY=$(POUND_SIGN)
SKIP_GENUNIX_UNIQUIFY=no
diff --git a/usr/src/uts/common/dtrace/dtrace.c b/usr/src/uts/common/dtrace/dtrace.c
index eb60c15c04..0f880f2458 100644
--- a/usr/src/uts/common/dtrace/dtrace.c
+++ b/usr/src/uts/common/dtrace/dtrace.c
@@ -9848,12 +9848,14 @@ dtrace_ecb_action_add(dtrace_ecb_t *ecb, dtrace_actdesc_t *desc)
case DTRACEACT_PRINTA:
case DTRACEACT_SYSTEM:
case DTRACEACT_FREOPEN:
+ case DTRACEACT_DIFEXPR:
/*
* We know that our arg is a string -- turn it into a
* format.
*/
if (arg == NULL) {
- ASSERT(desc->dtad_kind == DTRACEACT_PRINTA);
+ ASSERT(desc->dtad_kind == DTRACEACT_PRINTA ||
+ desc->dtad_kind == DTRACEACT_DIFEXPR);
format = 0;
} else {
ASSERT(arg != NULL);
@@ -9864,7 +9866,6 @@ dtrace_ecb_action_add(dtrace_ecb_t *ecb, dtrace_actdesc_t *desc)
/*FALLTHROUGH*/
case DTRACEACT_LIBACT:
- case DTRACEACT_DIFEXPR:
case DTRACEACT_TRACEMEM:
case DTRACEACT_TRACEMEM_DYNSIZE:
if (dp == NULL)
@@ -11887,15 +11888,20 @@ dtrace_dof_actdesc(dof_hdr_t *dof, dof_sec_t *sec, dtrace_vstate_t *vstate,
(uintptr_t)sec->dofs_offset + offs);
kind = (dtrace_actkind_t)desc->dofa_kind;
- if (DTRACEACT_ISPRINTFLIKE(kind) &&
+ if ((DTRACEACT_ISPRINTFLIKE(kind) &&
(kind != DTRACEACT_PRINTA ||
+ desc->dofa_strtab != DOF_SECIDX_NONE)) ||
+ (kind == DTRACEACT_DIFEXPR &&
desc->dofa_strtab != DOF_SECIDX_NONE)) {
dof_sec_t *strtab;
char *str, *fmt;
uint64_t i;
/*
- * printf()-like actions must have a format string.
+ * The argument to these actions is an index into the
+ * DOF string table. For printf()-like actions, this
+ * is the format string. For print(), this is the
+ * CTF type of the expression result.
*/
if ((strtab = dtrace_dof_sect(dof,
DOF_SECT_STRTAB, desc->dofa_strtab)) == NULL)
diff --git a/usr/src/uts/common/fs/dev/sdev_vnops.c b/usr/src/uts/common/fs/dev/sdev_vnops.c
index fb1d93d06b..89c5decbf0 100644
--- a/usr/src/uts/common/fs/dev/sdev_vnops.c
+++ b/usr/src/uts/common/fs/dev/sdev_vnops.c
@@ -1142,9 +1142,21 @@ sdev_readdir(struct vnode *dvp, struct uio *uiop, struct cred *cred, int *eofp,
struct sdev_node *parent = VTOSDEV(dvp);
int error;
- /* execute access is required to search the directory */
- if ((error = VOP_ACCESS(dvp, VEXEC, 0, cred, ct)) != 0)
- return (error);
+ /*
+ * We must check that we have execute access to search the directory --
+ * but because our sdev_contents lock is already held as a reader (the
+ * caller must have done a VOP_RWLOCK()), we call directly into the
+ * underlying access routine if sdev_attr is non-NULL.
+ */
+ if (parent->sdev_attr != NULL) {
+ VERIFY(RW_READ_HELD(&parent->sdev_contents));
+
+ if (sdev_unlocked_access(parent, VEXEC, cred) != 0)
+ return (EACCES);
+ } else {
+ if ((error = VOP_ACCESS(dvp, VEXEC, 0, cred, ct)) != 0)
+ return (error);
+ }
ASSERT(parent);
if (!SDEV_IS_GLOBAL(parent))
diff --git a/usr/src/uts/common/fs/nfs/nfs4_rnode.c b/usr/src/uts/common/fs/nfs/nfs4_rnode.c
index b7d9b830f6..a5b19334dd 100644
--- a/usr/src/uts/common/fs/nfs/nfs4_rnode.c
+++ b/usr/src/uts/common/fs/nfs/nfs4_rnode.c
@@ -28,6 +28,9 @@
* All Rights Reserved
*/
+/*
+ * Copyright 2011 Nexenta Systems, Inc. All rights reserved.
+ */
#include <sys/param.h>
#include <sys/types.h>
@@ -1864,7 +1867,7 @@ nfs4_rnode_init(void)
(ulong_t)((kmem_maxavail() >> 2) / sizeof (struct rnode4));
if (nrnode > nrnode4_max || (nrnode == 0 && ncsize == 0)) {
zcmn_err(GLOBAL_ZONEID, CE_NOTE,
- "setting nrnode to max value of %ld", nrnode4_max);
+ "!setting nrnode to max value of %ld", nrnode4_max);
nrnode = nrnode4_max;
}
rtable4size = 1 << highbit(nrnode / rnode4_hashlen);
diff --git a/usr/src/uts/common/fs/nfs/nfs_subr.c b/usr/src/uts/common/fs/nfs/nfs_subr.c
index 73fb3477d8..787e92c3a4 100644
--- a/usr/src/uts/common/fs/nfs/nfs_subr.c
+++ b/usr/src/uts/common/fs/nfs/nfs_subr.c
@@ -23,6 +23,10 @@
* Use is subject to license terms.
*/
+/*
+ * Copyright 2011 Nexenta Systems, Inc. All rights reserved.
+ */
+
#include <sys/param.h>
#include <sys/types.h>
#include <sys/systm.h>
@@ -3451,7 +3455,7 @@ nfs_subrinit(void)
nrnode_max = (ulong_t)((kmem_maxavail() >> 2) / sizeof (struct rnode));
if (nrnode > nrnode_max || (nrnode == 0 && ncsize == 0)) {
zcmn_err(GLOBAL_ZONEID, CE_NOTE,
- "setting nrnode to max value of %ld", nrnode_max);
+ "!setting nrnode to max value of %ld", nrnode_max);
nrnode = nrnode_max;
}
diff --git a/usr/src/uts/common/fs/smbsrv/smb_common_open.c b/usr/src/uts/common/fs/smbsrv/smb_common_open.c
index 26b17be90f..d858d3d6d9 100644
--- a/usr/src/uts/common/fs/smbsrv/smb_common_open.c
+++ b/usr/src/uts/common/fs/smbsrv/smb_common_open.c
@@ -20,6 +20,7 @@
*/
/*
+ * Copyright 2011 Nexenta Systems, Inc. All rights reserved.
* Copyright (c) 2007, 2010, Oracle and/or its affiliates. All rights reserved.
*/
@@ -59,11 +60,15 @@ static boolean_t smb_open_overwrite(smb_arg_open_t *);
* FILE_WRITE_ATTRIBUTES, FILE_WRITE_EA, and FILE_APPEND_DATA
*
* GENERIC_EXECUTE STANDARD_RIGHTS_EXECUTE, SYNCHRONIZE, and FILE_EXECUTE.
+ *
+ * Careful, we have to emulate some Windows behavior here.
+ * When requested access == zero, you get READ_CONTROL.
+ * MacOS 10.7 depends on this.
*/
uint32_t
smb_access_generic_to_file(uint32_t desired_access)
{
- uint32_t access = 0;
+ uint32_t access = READ_CONTROL;
if (desired_access & GENERIC_ALL)
return (FILE_ALL_ACCESS & ~SYNCHRONIZE);
diff --git a/usr/src/uts/common/fs/smbsrv/smb_dispatch.c b/usr/src/uts/common/fs/smbsrv/smb_dispatch.c
index e5a00c57b2..1afcf18b28 100644
--- a/usr/src/uts/common/fs/smbsrv/smb_dispatch.c
+++ b/usr/src/uts/common/fs/smbsrv/smb_dispatch.c
@@ -20,6 +20,7 @@
*/
/*
+ * Copyright 2011 Nexenta Systems, Inc. All rights reserved.
* Copyright (c) 2007, 2010, Oracle and/or its affiliates. All rights reserved.
*/
@@ -523,6 +524,7 @@ smb_dispatch_request(struct smb_request *sr)
smb_session_t *session;
uint32_t capabilities;
uint32_t byte_count;
+ uint32_t max_bytes;
session = sr->session;
capabilities = session->capabilities;
@@ -624,12 +626,18 @@ andx_more:
* and this is SmbReadX/SmbWriteX since this enables
* large reads/write and bcc is only 16-bits.
*/
+ max_bytes = sr->command.max_bytes - sr->command.chain_offset;
if (((sr->smb_com == SMB_COM_READ_ANDX) &&
(capabilities & CAP_LARGE_READX)) ||
((sr->smb_com == SMB_COM_WRITE_ANDX) &&
(capabilities & CAP_LARGE_WRITEX))) {
- byte_count = sr->command.max_bytes - sr->command.chain_offset;
+ /* May be > BCC */
+ byte_count = max_bytes;
+ } else if (max_bytes < (uint32_t)sr->smb_bcc) {
+ /* BCC is bogus. Will fail later. */
+ byte_count = max_bytes;
} else {
+ /* ordinary case */
byte_count = (uint32_t)sr->smb_bcc;
}
diff --git a/usr/src/uts/common/fs/smbsrv/smb_nt_transact_notify_change.c b/usr/src/uts/common/fs/smbsrv/smb_nt_transact_notify_change.c
index 97e9e7fb66..2efd4cba5a 100644
--- a/usr/src/uts/common/fs/smbsrv/smb_nt_transact_notify_change.c
+++ b/usr/src/uts/common/fs/smbsrv/smb_nt_transact_notify_change.c
@@ -20,6 +20,7 @@
*/
/*
+ * Copyright 2011 Nexenta Systems, Inc. All rights reserved.
* Copyright (c) 2007, 2010, Oracle and/or its affiliates. All rights reserved.
*/
@@ -201,7 +202,7 @@ smb_nt_transact_notify_change(struct smb_request *sr, struct smb_xa *xa)
node = sr->fid_ofile->f_node;
- if (!smb_node_is_dir(node)) {
+ if (node == NULL || !smb_node_is_dir(node)) {
/*
* Notify change requests are only valid on directories.
*/
diff --git a/usr/src/uts/common/fs/smbsrv/smb_server.c b/usr/src/uts/common/fs/smbsrv/smb_server.c
index bef039cfea..813031c327 100644
--- a/usr/src/uts/common/fs/smbsrv/smb_server.c
+++ b/usr/src/uts/common/fs/smbsrv/smb_server.c
@@ -1102,17 +1102,6 @@ smb_server_disconnect_share(smb_llist_t *ll, const char *sharename)
*/
void
-smb_server_reconnection_check(smb_server_t *sv, smb_session_t *session)
-{
- ASSERT(sv == session->s_server);
-
- smb_session_reconnection_check(&sv->sv_nbt_daemon.ld_session_list,
- session);
- smb_session_reconnection_check(&sv->sv_tcp_daemon.ld_session_list,
- session);
-}
-
-void
smb_server_get_cfg(smb_server_t *sv, smb_kmod_cfg_t *cfg)
{
rw_enter(&sv->sv_cfg_lock, RW_READER);
diff --git a/usr/src/uts/common/fs/smbsrv/smb_session.c b/usr/src/uts/common/fs/smbsrv/smb_session.c
index be8d9c3ff8..6e1bd6d69a 100644
--- a/usr/src/uts/common/fs/smbsrv/smb_session.c
+++ b/usr/src/uts/common/fs/smbsrv/smb_session.c
@@ -19,6 +19,7 @@
* CDDL HEADER END
*/
/*
+ * Copyright 2011 Nexenta Systems, Inc. All rights reserved.
* Copyright (c) 2007, 2010, Oracle and/or its affiliates. All rights reserved.
*/
#include <sys/atomic.h>
@@ -94,47 +95,6 @@ smb_session_correct_keep_alive_values(smb_llist_t *ll, uint32_t new_keep_alive)
}
/*
- * smb_reconnection_check
- *
- * This function is called when a client indicates its current connection
- * should be the only one it has with the server, as indicated by VC=0 in
- * a SessionSetupX request. We go through the session list and destroy any
- * stale connections for that client.
- *
- * Clients don't associate IP addresses and servers. So a client may make
- * independent connections (i.e. with VC=0) to a server with multiple
- * IP addresses. So, when checking for a reconnection, we need to include
- * the local IP address, to which the client is connecting, when checking
- * for stale sessions.
- *
- * Also check the server's NetBIOS name to support simultaneous access by
- * multiple clients behind a NAT server. This will only work for SMB over
- * NetBIOS on TCP port 139, it will not work SMB over TCP port 445 because
- * there is no NetBIOS name. See also Knowledge Base article Q301673.
- */
-void
-smb_session_reconnection_check(smb_llist_t *ll, smb_session_t *sess)
-{
- smb_session_t *sn;
-
- smb_llist_enter(ll, RW_READER);
- sn = smb_llist_head(ll);
- while (sn != NULL) {
- SMB_SESSION_VALID(sn);
- if ((sn != sess) &&
- smb_inet_equal(&sn->ipaddr, &sess->ipaddr) &&
- smb_inet_equal(&sn->local_ipaddr, &sess->local_ipaddr) &&
- (strcasecmp(sn->workstation, sess->workstation) == 0) &&
- (sn->opentime <= sess->opentime) &&
- (sn->s_kid < sess->s_kid)) {
- smb_session_disconnect(sn);
- }
- sn = smb_llist_next(ll, sn);
- }
- smb_llist_exit(ll);
-}
-
-/*
* Send a session message - supports SMB-over-NBT and SMB-over-TCP.
*
* The mbuf chain is copied into a contiguous buffer so that the whole
@@ -408,6 +368,7 @@ smb_request_cancel(smb_request_t *sr)
mutex_enter(&sr->sr_mutex);
switch (sr->sr_state) {
+ case SMB_REQ_STATE_INITIALIZING:
case SMB_REQ_STATE_SUBMITTED:
case SMB_REQ_STATE_ACTIVE:
case SMB_REQ_STATE_CLEANED_UP:
@@ -445,11 +406,8 @@ smb_request_cancel(smb_request_t *sr)
* is completing.
*/
break;
- /*
- * Cases included:
- * SMB_REQ_STATE_FREE:
- * SMB_REQ_STATE_INITIALIZING:
- */
+
+ case SMB_REQ_STATE_FREE:
default:
SMB_PANIC();
}
diff --git a/usr/src/uts/common/fs/smbsrv/smb_session_setup_andx.c b/usr/src/uts/common/fs/smbsrv/smb_session_setup_andx.c
index 7c91728bd7..b3e5789826 100644
--- a/usr/src/uts/common/fs/smbsrv/smb_session_setup_andx.c
+++ b/usr/src/uts/common/fs/smbsrv/smb_session_setup_andx.c
@@ -19,6 +19,7 @@
* CDDL HEADER END
*/
/*
+ * Copyright 2011 Nexenta Systems, Inc. All rights reserved.
* Copyright (c) 2007, 2010, Oracle and/or its affiliates. All rights reserved.
*/
@@ -157,9 +158,6 @@ smb_post_session_setup_andx(smb_request_t *sr)
}
/*
- * If the vcnumber is zero, discard any other connections associated with
- * this client.
- *
* If signing has not already been enabled on this session check to see if
* it should be enabled. The first authenticated logon provides the MAC
* key and sequence numbers for signing all subsequent sessions on the same
@@ -180,9 +178,6 @@ smb_com_session_setup_andx(smb_request_t *sr)
char ipaddr_buf[INET6_ADDRSTRLEN];
int rc;
- if (sr->session->vcnumber == 0)
- smb_server_reconnection_check(sr->sr_server, sr->session);
-
if (smb_authenticate(sr, sinfo, &session_key) != 0)
return (SDRC_ERROR);
diff --git a/usr/src/uts/common/fs/smbsrv/smb_write.c b/usr/src/uts/common/fs/smbsrv/smb_write.c
index d136fb91fa..8c6c2a70a7 100644
--- a/usr/src/uts/common/fs/smbsrv/smb_write.c
+++ b/usr/src/uts/common/fs/smbsrv/smb_write.c
@@ -20,6 +20,7 @@
*/
/*
+ * Copyright 2011 Nexenta Systems, Inc. All rights reserved.
* Copyright (c) 2007, 2010, Oracle and/or its affiliates. All rights reserved.
*/
@@ -29,14 +30,6 @@
#include <smbsrv/netbios.h>
-/*
- * The limit in bytes that the marshalling will grow the buffer
- * chain to accomodate incoming data on SmbWriteX requests.
- * This sets the upper limit for the data-count per SmbWriteX
- * request.
- */
-#define SMB_WRITEX_MAX 102400
-
static int smb_write_truncate(smb_request_t *, smb_rw_param_t *);
@@ -418,7 +411,6 @@ smb_com_write_andx(smb_request_t *sr)
return (SDRC_ERROR);
}
- sr->smb_data.max_bytes = SMB_WRITEX_MAX;
rc = smbsr_decode_data(sr, "#.#B", param->rw_dsoff, param->rw_count,
&param->rw_vdb);
diff --git a/usr/src/uts/common/fs/tmpfs/tmp_vfsops.c b/usr/src/uts/common/fs/tmpfs/tmp_vfsops.c
index f8a36a528f..f22cc3ecf0 100644
--- a/usr/src/uts/common/fs/tmpfs/tmp_vfsops.c
+++ b/usr/src/uts/common/fs/tmpfs/tmp_vfsops.c
@@ -20,6 +20,7 @@
*/
/*
* Copyright (c) 1990, 2010, Oracle and/or its affiliates. All rights reserved.
+ * Copyright (c) 2011, Joyent, Inc. All rights reserved.
*/
#include <sys/types.h>
@@ -76,7 +77,7 @@ static vfsdef_t vfw = {
VFSDEF_VERSION,
"tmpfs",
tmpfsinit,
- VSW_HASPROTO|VSW_STATS|VSW_ZMOUNT,
+ VSW_HASPROTO|VSW_CANREMOUNT|VSW_STATS|VSW_ZMOUNT,
&tmpfs_proto_opttbl
};
@@ -249,7 +250,7 @@ tmp_mount(
return (ENOTDIR);
mutex_enter(&mvp->v_lock);
- if ((uap->flags & MS_OVERLAY) == 0 &&
+ if ((uap->flags & MS_REMOUNT) == 0 && (uap->flags & MS_OVERLAY) == 0 &&
(mvp->v_count != 1 || (mvp->v_flag & VROOT))) {
mutex_exit(&mvp->v_lock);
return (EBUSY);
@@ -286,6 +287,21 @@ tmp_mount(
(uap->flags & MS_SYSSPACE) ? UIO_SYSSPACE : UIO_USERSPACE, &dpn))
goto out;
+ if (uap->flags & MS_REMOUNT) {
+ tm = (struct tmount *)VFSTOTM(vfsp);
+
+ /*
+ * If we change the size so its less than what is currently
+ * being used, we allow that. The file system will simply be
+ * full until enough files have been removed to get below the
+ * new max.
+ */
+ mutex_enter(&tm->tm_contents);
+ tm->tm_anonmax = anonmax;
+ mutex_exit(&tm->tm_contents);
+ goto out;
+ }
+
if ((tm = tmp_memalloc(sizeof (struct tmount), 0)) == NULL) {
pn_free(&dpn);
error = ENOMEM;
diff --git a/usr/src/uts/common/fs/zfs/arc.c b/usr/src/uts/common/fs/zfs/arc.c
index 673dbf11a9..a4adb09e16 100644
--- a/usr/src/uts/common/fs/zfs/arc.c
+++ b/usr/src/uts/common/fs/zfs/arc.c
@@ -20,6 +20,8 @@
*/
/*
* 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.
*/
/*
@@ -1218,7 +1220,7 @@ arc_buf_alloc(spa_t *spa, int size, void *tag, arc_buf_contents_t type)
ASSERT(BUF_EMPTY(hdr));
hdr->b_size = size;
hdr->b_type = type;
- hdr->b_spa = spa_guid(spa);
+ hdr->b_spa = spa_load_guid(spa);
hdr->b_state = arc_anon;
hdr->b_arc_access = 0;
buf = kmem_cache_alloc(buf_cache, KM_PUSHPAGE);
@@ -1920,7 +1922,7 @@ arc_flush(spa_t *spa)
uint64_t guid = 0;
if (spa)
- guid = spa_guid(spa);
+ guid = spa_load_guid(spa);
while (list_head(&arc_mru->arcs_list[ARC_BUFC_DATA])) {
(void) arc_evict(arc_mru, guid, -1, FALSE, ARC_BUFC_DATA);
@@ -2677,7 +2679,7 @@ arc_read_nolock(zio_t *pio, spa_t *spa, const blkptr_t *bp,
arc_buf_t *buf;
kmutex_t *hash_lock;
zio_t *rzio;
- uint64_t guid = spa_guid(spa);
+ uint64_t guid = spa_load_guid(spa);
top:
hdr = buf_hash_find(guid, BP_IDENTITY(bp), BP_PHYSICAL_BIRTH(bp),
@@ -4240,7 +4242,7 @@ l2arc_write_buffers(spa_t *spa, l2arc_dev_t *dev, uint64_t target_sz)
boolean_t have_lock, full;
l2arc_write_callback_t *cb;
zio_t *pio, *wzio;
- uint64_t guid = spa_guid(spa);
+ uint64_t guid = spa_load_guid(spa);
ASSERT(dev->l2ad_vdev != NULL);
diff --git a/usr/src/uts/common/fs/zfs/bpobj.c b/usr/src/uts/common/fs/zfs/bpobj.c
index 72be312356..022921c666 100644
--- a/usr/src/uts/common/fs/zfs/bpobj.c
+++ b/usr/src/uts/common/fs/zfs/bpobj.c
@@ -20,11 +20,13 @@
*/
/*
* Copyright (c) 2005, 2010, Oracle and/or its affiliates. All rights reserved.
+ * Copyright (c) 2011 by Delphix. All rights reserved.
*/
#include <sys/bpobj.h>
#include <sys/zfs_context.h>
#include <sys/refcount.h>
+#include <sys/dsl_pool.h>
uint64_t
bpobj_alloc(objset_t *os, int blocksize, dmu_tx_t *tx)
@@ -440,7 +442,10 @@ space_range_cb(void *arg, const blkptr_t *bp, dmu_tx_t *tx)
struct space_range_arg *sra = arg;
if (bp->blk_birth > sra->mintxg && bp->blk_birth <= sra->maxtxg) {
- sra->used += bp_get_dsize_sync(sra->spa, bp);
+ if (dsl_pool_sync_context(spa_get_dsl(sra->spa)))
+ sra->used += bp_get_dsize_sync(sra->spa, bp);
+ else
+ sra->used += bp_get_dsize(sra->spa, bp);
sra->comp += BP_GET_PSIZE(bp);
sra->uncomp += BP_GET_UCSIZE(bp);
}
diff --git a/usr/src/uts/common/fs/zfs/dmu.c b/usr/src/uts/common/fs/zfs/dmu.c
index 6482972931..743f5c4656 100644
--- a/usr/src/uts/common/fs/zfs/dmu.c
+++ b/usr/src/uts/common/fs/zfs/dmu.c
@@ -20,6 +20,7 @@
*/
/*
* Copyright (c) 2005, 2010, Oracle and/or its affiliates. All rights reserved.
+ * Copyright 2011, Joyent, Inc. All rights reserved.
*/
#include <sys/dmu.h>
@@ -1563,7 +1564,7 @@ dmu_write_policy(objset_t *os, dnode_t *dn, int level, int wp, zio_prop_t *zp)
if (wp & WP_NOFILL) {
ASSERT(!ismd && level == 0);
- checksum = ZIO_CHECKSUM_OFF;
+ checksum = ZIO_CHECKSUM_NOPARITY;
compress = ZIO_COMPRESS_OFF;
dedup = B_FALSE;
}
diff --git a/usr/src/uts/common/fs/zfs/dmu_send.c b/usr/src/uts/common/fs/zfs/dmu_send.c
index 99341d2139..fc94f35805 100644
--- a/usr/src/uts/common/fs/zfs/dmu_send.c
+++ b/usr/src/uts/common/fs/zfs/dmu_send.c
@@ -20,9 +20,11 @@
*/
/*
* Copyright (c) 2005, 2010, Oracle and/or its affiliates. All rights reserved.
+ * Copyright (c) 2011 by Delphix. All rights reserved.
*/
/*
* Copyright 2011 Nexenta Systems, Inc. All rights reserved.
+ * Copyright (c) 2011 by Delphix. All rights reserved.
*/
#include <sys/dmu.h>
@@ -47,6 +49,9 @@
#include <sys/ddt.h>
#include <sys/zfs_onexit.h>
+/* Set this tunable to TRUE to replace corrupt data with 0x2f5baddb10c */
+int zfs_send_corrupt_data = B_FALSE;
+
static char *dmu_recv_tag = "dmu_recv_tag";
/*
@@ -368,8 +373,20 @@ backup_cb(spa_t *spa, zilog_t *zilog, const blkptr_t *bp, arc_buf_t *pbuf,
if (dsl_read(NULL, spa, bp, pbuf,
arc_getbuf_func, &abuf, ZIO_PRIORITY_ASYNC_READ,
- ZIO_FLAG_CANFAIL, &aflags, zb) != 0)
- return (EIO);
+ ZIO_FLAG_CANFAIL, &aflags, zb) != 0) {
+ if (zfs_send_corrupt_data) {
+ /* Send a block filled with 0x"zfs badd bloc" */
+ abuf = arc_buf_alloc(spa, blksz, &abuf,
+ ARC_BUFC_DATA);
+ uint64_t *ptr;
+ for (ptr = abuf->b_data;
+ (char *)ptr < (char *)abuf->b_data + blksz;
+ ptr++)
+ *ptr = 0x2f5baddb10c;
+ } else {
+ return (EIO);
+ }
+ }
err = dump_data(ba, type, zb->zb_object, zb->zb_blkid * blksz,
blksz, bp, abuf->b_data);
@@ -498,6 +515,86 @@ dmu_sendbackup(objset_t *tosnap, objset_t *fromsnap, boolean_t fromorigin,
return (0);
}
+int
+dmu_send_estimate(objset_t *tosnap, objset_t *fromsnap, boolean_t fromorigin,
+ uint64_t *sizep)
+{
+ dsl_dataset_t *ds = tosnap->os_dsl_dataset;
+ dsl_dataset_t *fromds = fromsnap ? fromsnap->os_dsl_dataset : NULL;
+ dsl_pool_t *dp = ds->ds_dir->dd_pool;
+ int err;
+ uint64_t size;
+
+ /* tosnap must be a snapshot */
+ if (ds->ds_phys->ds_next_snap_obj == 0)
+ return (EINVAL);
+
+ /* fromsnap must be an earlier snapshot from the same fs as tosnap */
+ if (fromds && (ds->ds_dir != fromds->ds_dir ||
+ fromds->ds_phys->ds_creation_txg >= ds->ds_phys->ds_creation_txg))
+ return (EXDEV);
+
+ if (fromorigin) {
+ if (fromsnap)
+ return (EINVAL);
+
+ if (dsl_dir_is_clone(ds->ds_dir)) {
+ rw_enter(&dp->dp_config_rwlock, RW_READER);
+ err = dsl_dataset_hold_obj(dp,
+ ds->ds_dir->dd_phys->dd_origin_obj, FTAG, &fromds);
+ rw_exit(&dp->dp_config_rwlock);
+ if (err)
+ return (err);
+ } else {
+ fromorigin = B_FALSE;
+ }
+ }
+
+ /* Get uncompressed size estimate of changed data. */
+ if (fromds == NULL) {
+ size = ds->ds_phys->ds_uncompressed_bytes;
+ } else {
+ uint64_t used, comp;
+ err = dsl_dataset_space_written(fromds, ds,
+ &used, &comp, &size);
+ if (fromorigin)
+ dsl_dataset_rele(fromds, FTAG);
+ if (err)
+ return (err);
+ }
+
+ /*
+ * Assume that space (both on-disk and in-stream) is dominated by
+ * data. We will adjust for indirect blocks and the copies property,
+ * but ignore per-object space used (eg, dnodes and DRR_OBJECT records).
+ */
+
+ /*
+ * Subtract out approximate space used by indirect blocks.
+ * Assume most space is used by data blocks (non-indirect, non-dnode).
+ * Assume all blocks are recordsize. Assume ditto blocks and
+ * internal fragmentation counter out compression.
+ *
+ * Therefore, space used by indirect blocks is sizeof(blkptr_t) per
+ * block, which we observe in practice.
+ */
+ uint64_t recordsize;
+ rw_enter(&dp->dp_config_rwlock, RW_READER);
+ err = dsl_prop_get_ds(ds, "recordsize",
+ sizeof (recordsize), 1, &recordsize, NULL);
+ rw_exit(&dp->dp_config_rwlock);
+ if (err)
+ return (err);
+ size -= size / recordsize * sizeof (blkptr_t);
+
+ /* Add in the space for the record associated with each block. */
+ size += size / recordsize * sizeof (dmu_replay_record_t);
+
+ *sizep = size;
+
+ return (0);
+}
+
struct recvbeginsyncarg {
const char *tofs;
const char *tosnap;
@@ -1497,7 +1594,7 @@ dmu_recv_existing_end(dmu_recv_cookie_t *drc)
{
struct recvendsyncarg resa;
dsl_dataset_t *ds = drc->drc_logical_ds;
- int err;
+ int err, myerr;
/*
* XXX hack; seems the ds is still dirty and dsl_pool_zil_clean()
@@ -1535,7 +1632,8 @@ out:
if (err == 0 && drc->drc_guid_to_ds_map != NULL)
(void) add_ds_to_guidmap(drc->drc_guid_to_ds_map, ds);
dsl_dataset_disown(ds, dmu_recv_tag);
- (void) dsl_dataset_destroy(drc->drc_real_ds, dmu_recv_tag, B_FALSE);
+ myerr = dsl_dataset_destroy(drc->drc_real_ds, dmu_recv_tag, B_FALSE);
+ ASSERT3U(myerr, ==, 0);
return (err);
}
diff --git a/usr/src/uts/common/fs/zfs/dsl_dataset.c b/usr/src/uts/common/fs/zfs/dsl_dataset.c
index 5fe1a647e0..5ef7f54af1 100644
--- a/usr/src/uts/common/fs/zfs/dsl_dataset.c
+++ b/usr/src/uts/common/fs/zfs/dsl_dataset.c
@@ -902,69 +902,56 @@ dsl_dataset_create_sync(dsl_dir_t *pdd, const char *lastname,
return (dsobj);
}
-struct destroyarg {
- dsl_sync_task_group_t *dstg;
- char *snapname;
- char *failed;
- boolean_t defer;
-};
-
-static int
-dsl_snapshot_destroy_one(const char *name, void *arg)
-{
- struct destroyarg *da = arg;
- dsl_dataset_t *ds;
- int err;
- char *dsname;
-
- dsname = kmem_asprintf("%s@%s", name, da->snapname);
- err = dsl_dataset_own(dsname, B_TRUE, da->dstg, &ds);
- strfree(dsname);
- if (err == 0) {
- struct dsl_ds_destroyarg *dsda;
-
- dsl_dataset_make_exclusive(ds, da->dstg);
- dsda = kmem_zalloc(sizeof (struct dsl_ds_destroyarg), KM_SLEEP);
- dsda->ds = ds;
- dsda->defer = da->defer;
- dsl_sync_task_create(da->dstg, dsl_dataset_destroy_check,
- dsl_dataset_destroy_sync, dsda, da->dstg, 0);
- } else if (err == ENOENT) {
- err = 0;
- } else {
- (void) strcpy(da->failed, name);
- }
- return (err);
-}
-
/*
- * Destroy 'snapname' in all descendants of 'fsname'.
+ * The snapshots must all be in the same pool.
*/
-#pragma weak dmu_snapshots_destroy = dsl_snapshots_destroy
int
-dsl_snapshots_destroy(char *fsname, char *snapname, boolean_t defer)
+dmu_snapshots_destroy_nvl(nvlist_t *snaps, boolean_t defer, char *failed)
{
int err;
- struct destroyarg da;
dsl_sync_task_t *dst;
spa_t *spa;
+ nvpair_t *pair;
+ dsl_sync_task_group_t *dstg;
- err = spa_open(fsname, &spa, FTAG);
+ pair = nvlist_next_nvpair(snaps, NULL);
+ if (pair == NULL)
+ return (0);
+
+ err = spa_open(nvpair_name(pair), &spa, FTAG);
if (err)
return (err);
- da.dstg = dsl_sync_task_group_create(spa_get_dsl(spa));
- da.snapname = snapname;
- da.failed = fsname;
- da.defer = defer;
+ dstg = dsl_sync_task_group_create(spa_get_dsl(spa));
- err = dmu_objset_find(fsname,
- dsl_snapshot_destroy_one, &da, DS_FIND_CHILDREN);
+ for (pair = nvlist_next_nvpair(snaps, NULL); pair != NULL;
+ pair = nvlist_next_nvpair(snaps, pair)) {
+ dsl_dataset_t *ds;
+ int err;
+
+ err = dsl_dataset_own(nvpair_name(pair), B_TRUE, dstg, &ds);
+ if (err == 0) {
+ struct dsl_ds_destroyarg *dsda;
+
+ dsl_dataset_make_exclusive(ds, dstg);
+ dsda = kmem_zalloc(sizeof (struct dsl_ds_destroyarg),
+ KM_SLEEP);
+ dsda->ds = ds;
+ dsda->defer = defer;
+ dsl_sync_task_create(dstg, dsl_dataset_destroy_check,
+ dsl_dataset_destroy_sync, dsda, dstg, 0);
+ } else if (err == ENOENT) {
+ err = 0;
+ } else {
+ (void) strcpy(failed, nvpair_name(pair));
+ break;
+ }
+ }
if (err == 0)
- err = dsl_sync_task_group_wait(da.dstg);
+ err = dsl_sync_task_group_wait(dstg);
- for (dst = list_head(&da.dstg->dstg_tasks); dst;
- dst = list_next(&da.dstg->dstg_tasks, dst)) {
+ for (dst = list_head(&dstg->dstg_tasks); dst;
+ dst = list_next(&dstg->dstg_tasks, dst)) {
struct dsl_ds_destroyarg *dsda = dst->dst_arg1;
dsl_dataset_t *ds = dsda->ds;
@@ -972,17 +959,17 @@ dsl_snapshots_destroy(char *fsname, char *snapname, boolean_t defer)
* Return the file system name that triggered the error
*/
if (dst->dst_err) {
- dsl_dataset_name(ds, fsname);
- *strchr(fsname, '@') = '\0';
+ dsl_dataset_name(ds, failed);
}
ASSERT3P(dsda->rm_origin, ==, NULL);
- dsl_dataset_disown(ds, da.dstg);
+ dsl_dataset_disown(ds, dstg);
kmem_free(dsda, sizeof (struct dsl_ds_destroyarg));
}
- dsl_sync_task_group_destroy(da.dstg);
+ dsl_sync_task_group_destroy(dstg);
spa_close(spa, FTAG);
return (err);
+
}
static boolean_t
@@ -2143,6 +2130,55 @@ dsl_dataset_sync(dsl_dataset_t *ds, zio_t *zio, dmu_tx_t *tx)
dmu_objset_sync(ds->ds_objset, zio, tx);
}
+static void
+get_clones_stat(dsl_dataset_t *ds, nvlist_t *nv)
+{
+ uint64_t count = 0;
+ objset_t *mos = ds->ds_dir->dd_pool->dp_meta_objset;
+ zap_cursor_t zc;
+ zap_attribute_t za;
+ nvlist_t *propval;
+ nvlist_t *val;
+
+ rw_enter(&ds->ds_dir->dd_pool->dp_config_rwlock, RW_READER);
+ VERIFY(nvlist_alloc(&propval, NV_UNIQUE_NAME, KM_SLEEP) == 0);
+ VERIFY(nvlist_alloc(&val, NV_UNIQUE_NAME, KM_SLEEP) == 0);
+
+ /*
+ * There may me missing entries in ds_next_clones_obj
+ * due to a bug in a previous version of the code.
+ * Only trust it if it has the right number of entries.
+ */
+ if (ds->ds_phys->ds_next_clones_obj != 0) {
+ ASSERT3U(0, ==, zap_count(mos, ds->ds_phys->ds_next_clones_obj,
+ &count));
+ }
+ if (count != ds->ds_phys->ds_num_children - 1) {
+ goto fail;
+ }
+ for (zap_cursor_init(&zc, mos, ds->ds_phys->ds_next_clones_obj);
+ zap_cursor_retrieve(&zc, &za) == 0;
+ zap_cursor_advance(&zc)) {
+ dsl_dataset_t *clone;
+ char buf[ZFS_MAXNAMELEN];
+ if (dsl_dataset_hold_obj(ds->ds_dir->dd_pool,
+ za.za_first_integer, FTAG, &clone) != 0) {
+ goto fail;
+ }
+ dsl_dir_name(clone->ds_dir, buf);
+ VERIFY(nvlist_add_boolean(val, buf) == 0);
+ dsl_dataset_rele(clone, FTAG);
+ }
+ zap_cursor_fini(&zc);
+ VERIFY(nvlist_add_nvlist(propval, ZPROP_VALUE, val) == 0);
+ VERIFY(nvlist_add_nvlist(nv, zfs_prop_to_name(ZFS_PROP_CLONES),
+ propval) == 0);
+fail:
+ nvlist_free(val);
+ nvlist_free(propval);
+ rw_exit(&ds->ds_dir->dd_pool->dp_config_rwlock);
+}
+
void
dsl_dataset_stats(dsl_dataset_t *ds, nvlist_t *nv)
{
@@ -2173,6 +2209,26 @@ dsl_dataset_stats(dsl_dataset_t *ds, nvlist_t *nv)
dsl_prop_nvlist_add_uint64(nv, ZFS_PROP_DEFER_DESTROY,
DS_IS_DEFER_DESTROY(ds) ? 1 : 0);
+ if (ds->ds_phys->ds_prev_snap_obj != 0) {
+ uint64_t written, comp, uncomp;
+ dsl_pool_t *dp = ds->ds_dir->dd_pool;
+ dsl_dataset_t *prev;
+
+ rw_enter(&dp->dp_config_rwlock, RW_READER);
+ int err = dsl_dataset_hold_obj(dp,
+ ds->ds_phys->ds_prev_snap_obj, FTAG, &prev);
+ rw_exit(&dp->dp_config_rwlock);
+ if (err == 0) {
+ err = dsl_dataset_space_written(prev, ds, &written,
+ &comp, &uncomp);
+ dsl_dataset_rele(prev, FTAG);
+ if (err == 0) {
+ dsl_prop_nvlist_add_uint64(nv, ZFS_PROP_WRITTEN,
+ written);
+ }
+ }
+ }
+
ratio = ds->ds_phys->ds_compressed_bytes == 0 ? 100 :
(ds->ds_phys->ds_uncompressed_bytes * 100 /
ds->ds_phys->ds_compressed_bytes);
@@ -2186,6 +2242,8 @@ dsl_dataset_stats(dsl_dataset_t *ds, nvlist_t *nv)
dsl_prop_nvlist_add_uint64(nv, ZFS_PROP_USED,
ds->ds_phys->ds_unique_bytes);
dsl_prop_nvlist_add_uint64(nv, ZFS_PROP_COMPRESSRATIO, ratio);
+
+ get_clones_stat(ds, nv);
}
}
@@ -4012,7 +4070,7 @@ dsl_dataset_get_holds(const char *dsname, nvlist_t **nvp)
}
/*
- * Note, this fuction is used as the callback for dmu_objset_find(). We
+ * Note, this function is used as the callback for dmu_objset_find(). We
* always return 0 so that we will continue to find and process
* inconsistent datasets, even if we encounter an error trying to
* process one of them.
@@ -4031,3 +4089,151 @@ dsl_destroy_inconsistent(const char *dsname, void *arg)
}
return (0);
}
+
+/*
+ * Return (in *usedp) the amount of space written in new that is not
+ * present in oldsnap. New may be a snapshot or the head. Old must be
+ * a snapshot before new, in new's filesystem (or its origin). If not then
+ * fail and return EINVAL.
+ *
+ * The written space is calculated by considering two components: First, we
+ * ignore any freed space, and calculate the written as new's used space
+ * minus old's used space. Next, we add in the amount of space that was freed
+ * between the two snapshots, thus reducing new's used space relative to old's.
+ * Specifically, this is the space that was born before old->ds_creation_txg,
+ * and freed before new (ie. on new's deadlist or a previous deadlist).
+ *
+ * space freed [---------------------]
+ * snapshots ---O-------O--------O-------O------
+ * oldsnap new
+ */
+int
+dsl_dataset_space_written(dsl_dataset_t *oldsnap, dsl_dataset_t *new,
+ uint64_t *usedp, uint64_t *compp, uint64_t *uncompp)
+{
+ int err = 0;
+ uint64_t snapobj;
+ dsl_pool_t *dp = new->ds_dir->dd_pool;
+
+ *usedp = 0;
+ *usedp += new->ds_phys->ds_used_bytes;
+ *usedp -= oldsnap->ds_phys->ds_used_bytes;
+
+ *compp = 0;
+ *compp += new->ds_phys->ds_compressed_bytes;
+ *compp -= oldsnap->ds_phys->ds_compressed_bytes;
+
+ *uncompp = 0;
+ *uncompp += new->ds_phys->ds_uncompressed_bytes;
+ *uncompp -= oldsnap->ds_phys->ds_uncompressed_bytes;
+
+ rw_enter(&dp->dp_config_rwlock, RW_READER);
+ snapobj = new->ds_object;
+ while (snapobj != oldsnap->ds_object) {
+ dsl_dataset_t *snap;
+ uint64_t used, comp, uncomp;
+
+ err = dsl_dataset_hold_obj(dp, snapobj, FTAG, &snap);
+ if (err != 0)
+ break;
+
+ if (snap->ds_phys->ds_prev_snap_txg ==
+ oldsnap->ds_phys->ds_creation_txg) {
+ /*
+ * The blocks in the deadlist can not be born after
+ * ds_prev_snap_txg, so get the whole deadlist space,
+ * which is more efficient (especially for old-format
+ * deadlists). Unfortunately the deadlist code
+ * doesn't have enough information to make this
+ * optimization itself.
+ */
+ dsl_deadlist_space(&snap->ds_deadlist,
+ &used, &comp, &uncomp);
+ } else {
+ dsl_deadlist_space_range(&snap->ds_deadlist,
+ 0, oldsnap->ds_phys->ds_creation_txg,
+ &used, &comp, &uncomp);
+ }
+ *usedp += used;
+ *compp += comp;
+ *uncompp += uncomp;
+
+ /*
+ * If we get to the beginning of the chain of snapshots
+ * (ds_prev_snap_obj == 0) before oldsnap, then oldsnap
+ * was not a snapshot of/before new.
+ */
+ snapobj = snap->ds_phys->ds_prev_snap_obj;
+ dsl_dataset_rele(snap, FTAG);
+ if (snapobj == 0) {
+ err = EINVAL;
+ break;
+ }
+
+ }
+ rw_exit(&dp->dp_config_rwlock);
+ return (err);
+}
+
+/*
+ * Return (in *usedp) the amount of space that will be reclaimed if firstsnap,
+ * lastsnap, and all snapshots in between are deleted.
+ *
+ * blocks that would be freed [---------------------------]
+ * snapshots ---O-------O--------O-------O--------O
+ * firstsnap lastsnap
+ *
+ * This is the set of blocks that were born after the snap before firstsnap,
+ * (birth > firstsnap->prev_snap_txg) and died before the snap after the
+ * last snap (ie, is on lastsnap->ds_next->ds_deadlist or an earlier deadlist).
+ * We calculate this by iterating over the relevant deadlists (from the snap
+ * after lastsnap, backward to the snap after firstsnap), summing up the
+ * space on the deadlist that was born after the snap before firstsnap.
+ */
+int
+dsl_dataset_space_wouldfree(dsl_dataset_t *firstsnap,
+ dsl_dataset_t *lastsnap,
+ uint64_t *usedp, uint64_t *compp, uint64_t *uncompp)
+{
+ int err = 0;
+ uint64_t snapobj;
+ dsl_pool_t *dp = firstsnap->ds_dir->dd_pool;
+
+ ASSERT(dsl_dataset_is_snapshot(firstsnap));
+ ASSERT(dsl_dataset_is_snapshot(lastsnap));
+
+ /*
+ * Check that the snapshots are in the same dsl_dir, and firstsnap
+ * is before lastsnap.
+ */
+ if (firstsnap->ds_dir != lastsnap->ds_dir ||
+ firstsnap->ds_phys->ds_creation_txg >
+ lastsnap->ds_phys->ds_creation_txg)
+ return (EINVAL);
+
+ *usedp = *compp = *uncompp = 0;
+
+ rw_enter(&dp->dp_config_rwlock, RW_READER);
+ snapobj = lastsnap->ds_phys->ds_next_snap_obj;
+ while (snapobj != firstsnap->ds_object) {
+ dsl_dataset_t *ds;
+ uint64_t used, comp, uncomp;
+
+ err = dsl_dataset_hold_obj(dp, snapobj, FTAG, &ds);
+ if (err != 0)
+ break;
+
+ dsl_deadlist_space_range(&ds->ds_deadlist,
+ firstsnap->ds_phys->ds_prev_snap_txg, UINT64_MAX,
+ &used, &comp, &uncomp);
+ *usedp += used;
+ *compp += comp;
+ *uncompp += uncomp;
+
+ snapobj = ds->ds_phys->ds_prev_snap_obj;
+ ASSERT3U(snapobj, !=, 0);
+ dsl_dataset_rele(ds, FTAG);
+ }
+ rw_exit(&dp->dp_config_rwlock);
+ return (err);
+}
diff --git a/usr/src/uts/common/fs/zfs/dsl_deadlist.c b/usr/src/uts/common/fs/zfs/dsl_deadlist.c
index 064f8aceb8..dd6db2120b 100644
--- a/usr/src/uts/common/fs/zfs/dsl_deadlist.c
+++ b/usr/src/uts/common/fs/zfs/dsl_deadlist.c
@@ -20,6 +20,7 @@
*/
/*
* Copyright (c) 2010, Oracle and/or its affiliates. All rights reserved.
+ * Copyright (c) 2011 by Delphix. All rights reserved.
*/
#include <sys/dsl_dataset.h>
@@ -29,6 +30,26 @@
#include <sys/zfs_context.h>
#include <sys/dsl_pool.h>
+/*
+ * Deadlist concurrency:
+ *
+ * Deadlists can only be modified from the syncing thread.
+ *
+ * Except for dsl_deadlist_insert(), it can only be modified with the
+ * dp_config_rwlock held with RW_WRITER.
+ *
+ * The accessors (dsl_deadlist_space() and dsl_deadlist_space_range()) can
+ * be called concurrently, from open context, with the dl_config_rwlock held
+ * with RW_READER.
+ *
+ * Therefore, we only need to provide locking between dsl_deadlist_insert() and
+ * the accessors, protecting:
+ * dl_phys->dl_used,comp,uncomp
+ * and protecting the dl_tree from being loaded.
+ * The locking is provided by dl_lock. Note that locking on the bpobj_t
+ * provides its own locking, and dl_oldfmt is immutable.
+ */
+
static int
dsl_deadlist_compare(const void *arg1, const void *arg2)
{
@@ -309,14 +330,14 @@ dsl_deadlist_space(dsl_deadlist_t *dl,
* return space used in the range (mintxg, maxtxg].
* Includes maxtxg, does not include mintxg.
* mintxg and maxtxg must both be keys in the deadlist (unless maxtxg is
- * UINT64_MAX).
+ * larger than any bp in the deadlist (eg. UINT64_MAX)).
*/
void
dsl_deadlist_space_range(dsl_deadlist_t *dl, uint64_t mintxg, uint64_t maxtxg,
uint64_t *usedp, uint64_t *compp, uint64_t *uncompp)
{
- dsl_deadlist_entry_t dle_tofind;
dsl_deadlist_entry_t *dle;
+ dsl_deadlist_entry_t dle_tofind;
avl_index_t where;
if (dl->dl_oldfmt) {
@@ -325,9 +346,10 @@ dsl_deadlist_space_range(dsl_deadlist_t *dl, uint64_t mintxg, uint64_t maxtxg,
return;
}
- dsl_deadlist_load_tree(dl);
*usedp = *compp = *uncompp = 0;
+ mutex_enter(&dl->dl_lock);
+ dsl_deadlist_load_tree(dl);
dle_tofind.dle_mintxg = mintxg;
dle = avl_find(&dl->dl_tree, &dle_tofind, &where);
/*
@@ -336,6 +358,7 @@ dsl_deadlist_space_range(dsl_deadlist_t *dl, uint64_t mintxg, uint64_t maxtxg,
*/
ASSERT(dle != NULL ||
avl_nearest(&dl->dl_tree, where, AVL_AFTER) == NULL);
+
for (; dle && dle->dle_mintxg < maxtxg;
dle = AVL_NEXT(&dl->dl_tree, dle)) {
uint64_t used, comp, uncomp;
@@ -347,6 +370,7 @@ dsl_deadlist_space_range(dsl_deadlist_t *dl, uint64_t mintxg, uint64_t maxtxg,
*compp += comp;
*uncompp += uncomp;
}
+ mutex_exit(&dl->dl_lock);
}
static void
diff --git a/usr/src/uts/common/fs/zfs/dsl_deleg.c b/usr/src/uts/common/fs/zfs/dsl_deleg.c
index 529fb052fa..94026e1c13 100644
--- a/usr/src/uts/common/fs/zfs/dsl_deleg.c
+++ b/usr/src/uts/common/fs/zfs/dsl_deleg.c
@@ -20,6 +20,7 @@
*/
/*
* Copyright (c) 2007, 2010, Oracle and/or its affiliates. All rights reserved.
+ * Copyright (c) 2011 by Delphix. All rights reserved.
*/
/*
@@ -525,10 +526,12 @@ dsl_load_user_sets(objset_t *mos, uint64_t zapobj, avl_tree_t *avl,
}
/*
- * Check if user has requested permission.
+ * Check if user has requested permission. If descendent is set, must have
+ * descendent perms.
*/
int
-dsl_deleg_access_impl(dsl_dataset_t *ds, const char *perm, cred_t *cr)
+dsl_deleg_access_impl(dsl_dataset_t *ds, boolean_t descendent, const char *perm,
+ cred_t *cr)
{
dsl_dir_t *dd;
dsl_pool_t *dp;
@@ -549,7 +552,7 @@ dsl_deleg_access_impl(dsl_dataset_t *ds, const char *perm, cred_t *cr)
SPA_VERSION_DELEGATED_PERMS)
return (EPERM);
- if (dsl_dataset_is_snapshot(ds)) {
+ if (dsl_dataset_is_snapshot(ds) || descendent) {
/*
* Snapshots are treated as descendents only,
* local permissions do not apply.
@@ -642,7 +645,7 @@ dsl_deleg_access(const char *dsname, const char *perm, cred_t *cr)
if (error)
return (error);
- error = dsl_deleg_access_impl(ds, perm, cr);
+ error = dsl_deleg_access_impl(ds, B_FALSE, perm, cr);
dsl_dataset_rele(ds, FTAG);
return (error);
diff --git a/usr/src/uts/common/fs/zfs/dsl_pool.c b/usr/src/uts/common/fs/zfs/dsl_pool.c
index f7fd852139..316b37cebd 100644
--- a/usr/src/uts/common/fs/zfs/dsl_pool.c
+++ b/usr/src/uts/common/fs/zfs/dsl_pool.c
@@ -20,6 +20,7 @@
*/
/*
* Copyright (c) 2005, 2010, Oracle and/or its affiliates. All rights reserved.
+ * Copyright (c) 2011 by Delphix. All rights reserved.
*/
#include <sys/dsl_pool.h>
@@ -292,7 +293,10 @@ static int
deadlist_enqueue_cb(void *arg, const blkptr_t *bp, dmu_tx_t *tx)
{
dsl_deadlist_t *dl = arg;
+ dsl_pool_t *dp = dmu_objset_pool(dl->dl_os);
+ rw_enter(&dp->dp_config_rwlock, RW_READER);
dsl_deadlist_insert(dl, bp, tx);
+ rw_exit(&dp->dp_config_rwlock);
return (0);
}
diff --git a/usr/src/uts/common/fs/zfs/spa.c b/usr/src/uts/common/fs/zfs/spa.c
index 5d9332a70b..198f1d6a3f 100644
--- a/usr/src/uts/common/fs/zfs/spa.c
+++ b/usr/src/uts/common/fs/zfs/spa.c
@@ -21,9 +21,8 @@
/*
* 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.
*/
/*
@@ -206,6 +205,11 @@ spa_prop_get_config(spa_t *spa, nvlist_t **nvp)
spa_prop_add_list(*nvp, ZPOOL_PROP_GUID, NULL, spa_guid(spa), src);
+ if (spa->spa_comment != NULL) {
+ spa_prop_add_list(*nvp, ZPOOL_PROP_COMMENT, spa->spa_comment,
+ 0, ZPROP_SRC_LOCAL);
+ }
+
if (spa->spa_root != NULL)
spa_prop_add_list(*nvp, ZPOOL_PROP_ALTROOT, spa->spa_root,
0, ZPROP_SRC_LOCAL);
@@ -345,7 +349,7 @@ spa_prop_validate(spa_t *spa, nvlist_t *props)
char *propname, *strval;
uint64_t intval;
objset_t *os;
- char *slash;
+ char *slash, *check;
propname = nvpair_name(elem);
@@ -465,6 +469,26 @@ spa_prop_validate(spa_t *spa, nvlist_t *props)
error = EINVAL;
break;
+ case ZPOOL_PROP_COMMENT:
+ if ((error = nvpair_value_string(elem, &strval)) != 0)
+ break;
+ for (check = strval; *check != '\0'; check++) {
+ /*
+ * The kernel doesn't have an easy isprint()
+ * check. For this kernel check, we merely
+ * check ASCII apart from DEL. Fix this if
+ * there is an easy-to-use kernel isprint().
+ */
+ if (*check >= 0x7f) {
+ error = EINVAL;
+ break;
+ }
+ check++;
+ }
+ if (strlen(strval) > ZPROP_MAX_COMMENT)
+ error = E2BIG;
+ break;
+
case ZPOOL_PROP_DEDUPDITTO:
if (spa_version(spa) < SPA_VERSION_DEDUP)
error = ENOTSUP;
@@ -566,6 +590,43 @@ spa_prop_clear_bootfs(spa_t *spa, uint64_t dsobj, dmu_tx_t *tx)
}
/*
+ * 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
+ * the root vdev's guid, our own pool guid, and then mark all of our
+ * vdevs dirty. Note that we must make sure that all our vdevs are
+ * online when we do this, or else any vdevs that weren't present
+ * would be orphaned from our pool. We are also going to issue a
+ * sysevent to update any watchers.
+ */
+int
+spa_change_guid(spa_t *spa)
+{
+ uint64_t oldguid, newguid;
+ uint64_t txg;
+
+ if (!(spa_mode_global & FWRITE))
+ return (EROFS);
+
+ txg = spa_vdev_enter(spa);
+
+ if (spa->spa_root_vdev->vdev_state != VDEV_STATE_HEALTHY)
+ return (spa_vdev_exit(spa, NULL, txg, ENXIO));
+
+ oldguid = spa_guid(spa);
+ newguid = spa_generate_guid(NULL);
+ ASSERT3U(oldguid, !=, newguid);
+
+ 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));
+}
+
+/*
* ==========================================================================
* SPA state manipulation (open/create/destroy/import/export)
* ==========================================================================
@@ -1006,6 +1067,11 @@ spa_unload(spa_t *spa)
spa->spa_async_suspended = 0;
+ if (spa->spa_comment != NULL) {
+ spa_strfree(spa->spa_comment);
+ spa->spa_comment = NULL;
+ }
+
spa_config_exit(spa, SCL_ALL, FTAG);
}
@@ -1721,6 +1787,7 @@ spa_load(spa_t *spa, spa_load_state_t state, spa_import_type_t type,
{
nvlist_t *config = spa->spa_config;
char *ereport = FM_EREPORT_ZFS_POOL;
+ char *comment;
int error;
uint64_t pool_guid;
nvlist_t *nvl;
@@ -1728,6 +1795,10 @@ spa_load(spa_t *spa, spa_load_state_t state, spa_import_type_t type,
if (nvlist_lookup_uint64(config, ZPOOL_CONFIG_POOL_GUID, &pool_guid))
return (EINVAL);
+ ASSERT(spa->spa_comment == NULL);
+ if (nvlist_lookup_string(config, ZPOOL_CONFIG_COMMENT, &comment) == 0)
+ spa->spa_comment = spa_strdup(comment);
+
/*
* Versioning wasn't explicitly added to the label until later, so if
* it's not present treat it as the initial version.
@@ -1743,7 +1814,7 @@ spa_load(spa_t *spa, spa_load_state_t state, spa_import_type_t type,
spa_guid_exists(pool_guid, 0)) {
error = EEXIST;
} else {
- spa->spa_load_guid = pool_guid;
+ spa->spa_config_guid = pool_guid;
if (nvlist_lookup_nvlist(config, ZPOOL_CONFIG_SPLIT,
&nvl) == 0) {
@@ -5335,6 +5406,20 @@ spa_sync_props(void *arg1, void *arg2, dmu_tx_t *tx)
* properties.
*/
break;
+ case ZPOOL_PROP_COMMENT:
+ VERIFY(nvpair_value_string(elem, &strval) == 0);
+ if (spa->spa_comment != NULL)
+ spa_strfree(spa->spa_comment);
+ spa->spa_comment = spa_strdup(strval);
+ /*
+ * We need to dirty the configuration on all the vdevs
+ * so that their labels get updated. It's unnecessary
+ * to do this for pool creation since the vdev's
+ * configuratoin has already been dirtied.
+ */
+ if (tx->tx_txg != TXG_INITIAL)
+ vdev_config_dirty(spa->spa_root_vdev);
+ break;
default:
/*
* Set pool property values in the poolprops mos object.
diff --git a/usr/src/uts/common/fs/zfs/spa_config.c b/usr/src/uts/common/fs/zfs/spa_config.c
index 69d57f66db..8ca195d244 100644
--- a/usr/src/uts/common/fs/zfs/spa_config.c
+++ b/usr/src/uts/common/fs/zfs/spa_config.c
@@ -21,6 +21,8 @@
/*
* 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.
*/
#include <sys/spa.h>
@@ -345,6 +347,10 @@ spa_config_generate(spa_t *spa, vdev_t *vd, uint64_t txg, int getstats)
txg) == 0);
VERIFY(nvlist_add_uint64(config, ZPOOL_CONFIG_POOL_GUID,
spa_guid(spa)) == 0);
+ VERIFY(spa->spa_comment == NULL || nvlist_add_string(config,
+ ZPOOL_CONFIG_COMMENT, spa->spa_comment) == 0);
+
+
#ifdef _KERNEL
hostid = zone_get_hostid(NULL);
#else /* _KERNEL */
diff --git a/usr/src/uts/common/fs/zfs/spa_history.c b/usr/src/uts/common/fs/zfs/spa_history.c
index 212abae5b8..6df8411349 100644
--- a/usr/src/uts/common/fs/zfs/spa_history.c
+++ b/usr/src/uts/common/fs/zfs/spa_history.c
@@ -21,6 +21,7 @@
/*
* Copyright (c) 2006, 2010, Oracle and/or its affiliates. All rights reserved.
+ * Copyright (c) 2011 by Delphix. All rights reserved.
*/
#include <sys/spa.h>
@@ -101,11 +102,11 @@ spa_history_create_obj(spa_t *spa, dmu_tx_t *tx)
/*
* Figure out maximum size of history log. We set it at
- * 1% of pool size, with a max of 32MB and min of 128KB.
+ * 0.1% of pool size, with a max of 1G and min of 128KB.
*/
shpp->sh_phys_max_off =
- metaslab_class_get_dspace(spa_normal_class(spa)) / 100;
- shpp->sh_phys_max_off = MIN(shpp->sh_phys_max_off, 32<<20);
+ metaslab_class_get_dspace(spa_normal_class(spa)) / 1000;
+ shpp->sh_phys_max_off = MIN(shpp->sh_phys_max_off, 1<<30);
shpp->sh_phys_max_off = MAX(shpp->sh_phys_max_off, 128<<10);
dmu_buf_rele(dbp, FTAG);
diff --git a/usr/src/uts/common/fs/zfs/spa_misc.c b/usr/src/uts/common/fs/zfs/spa_misc.c
index 411aba8342..cc77f1bc18 100644
--- a/usr/src/uts/common/fs/zfs/spa_misc.c
+++ b/usr/src/uts/common/fs/zfs/spa_misc.c
@@ -21,6 +21,7 @@
/*
* Copyright (c) 2005, 2010, Oracle and/or its affiliates. All rights reserved.
* Copyright (c) 2011 by Delphix. All rights reserved.
+ * Copyright 2011 Nexenta Systems, Inc. All rights reserved.
*/
#include <sys/zfs_context.h>
@@ -1304,13 +1305,24 @@ spa_guid(spa_t *spa)
/*
* 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_load_guid' to handle
+ * vdev. We stash the original pool guid in 'spa_config_guid' to handle
* this case.
*/
if (spa->spa_root_vdev != NULL)
return (spa->spa_root_vdev->vdev_guid);
else
- return (spa->spa_load_guid);
+ return (spa->spa_config_guid);
+}
+
+uint64_t
+spa_load_guid(spa_t *spa)
+{
+ /*
+ * This is a GUID that exists solely as a reference for the
+ * purposes of the arc. It is generated at load time, and
+ * is never written to persistent storage.
+ */
+ return (spa->spa_load_guid);
}
uint64_t
diff --git a/usr/src/uts/common/fs/zfs/sys/dmu.h b/usr/src/uts/common/fs/zfs/sys/dmu.h
index f8dd73a12b..4476d21b56 100644
--- a/usr/src/uts/common/fs/zfs/sys/dmu.h
+++ b/usr/src/uts/common/fs/zfs/sys/dmu.h
@@ -20,6 +20,7 @@
*/
/*
* Copyright (c) 2005, 2010, Oracle and/or its affiliates. All rights reserved.
+ * Copyright (c) 2011 by Delphix. All rights reserved.
*/
/*
* Copyright 2011 Nexenta Systems, Inc. All rights reserved.
@@ -194,7 +195,7 @@ int dmu_objset_create(const char *name, dmu_objset_type_t type, uint64_t flags,
int dmu_objset_clone(const char *name, struct dsl_dataset *clone_origin,
uint64_t flags);
int dmu_objset_destroy(const char *name, boolean_t defer);
-int dmu_snapshots_destroy(char *fsname, char *snapname, boolean_t defer);
+int dmu_snapshots_destroy_nvl(struct nvlist *snaps, boolean_t defer, char *);
int dmu_objset_snapshot(char *fsname, char *snapname, char *tag,
struct nvlist *props, boolean_t recursive, boolean_t temporary, int fd);
int dmu_objset_rename(const char *name, const char *newname,
@@ -705,6 +706,8 @@ void dmu_traverse_objset(objset_t *os, uint64_t txg_start,
int dmu_sendbackup(objset_t *tosnap, objset_t *fromsnap, boolean_t fromorigin,
struct vnode *vp, offset_t *off);
+int dmu_send_estimate(objset_t *tosnap, objset_t *fromsnap, boolean_t fromorign,
+ uint64_t *sizep);
typedef struct dmu_recv_cookie {
/*
diff --git a/usr/src/uts/common/fs/zfs/sys/dsl_dataset.h b/usr/src/uts/common/fs/zfs/sys/dsl_dataset.h
index 22733d070e..c4530a8f0a 100644
--- a/usr/src/uts/common/fs/zfs/sys/dsl_dataset.h
+++ b/usr/src/uts/common/fs/zfs/sys/dsl_dataset.h
@@ -20,6 +20,7 @@
*/
/*
* Copyright (c) 2005, 2010, Oracle and/or its affiliates. All rights reserved.
+ * Copyright (c) 2011 by Delphix. All rights reserved.
*/
#ifndef _SYS_DSL_DATASET_H
@@ -249,6 +250,10 @@ void dsl_dataset_space(dsl_dataset_t *ds,
uint64_t *refdbytesp, uint64_t *availbytesp,
uint64_t *usedobjsp, uint64_t *availobjsp);
uint64_t dsl_dataset_fsid_guid(dsl_dataset_t *ds);
+int dsl_dataset_space_written(dsl_dataset_t *oldsnap, dsl_dataset_t *new,
+ uint64_t *usedp, uint64_t *compp, uint64_t *uncompp);
+int dsl_dataset_space_wouldfree(dsl_dataset_t *firstsnap, dsl_dataset_t *last,
+ uint64_t *usedp, uint64_t *compp, uint64_t *uncompp);
int dsl_dsobj_to_dsname(char *pname, uint64_t obj, char *buf);
diff --git a/usr/src/uts/common/fs/zfs/sys/dsl_deleg.h b/usr/src/uts/common/fs/zfs/sys/dsl_deleg.h
index 73c43bd238..9db6d07e87 100644
--- a/usr/src/uts/common/fs/zfs/sys/dsl_deleg.h
+++ b/usr/src/uts/common/fs/zfs/sys/dsl_deleg.h
@@ -20,6 +20,7 @@
*/
/*
* Copyright (c) 2007, 2010, Oracle and/or its affiliates. All rights reserved.
+ * Copyright (c) 2011 by Delphix. All rights reserved.
*/
#ifndef _SYS_DSL_DELEG_H
@@ -64,7 +65,8 @@ extern "C" {
int dsl_deleg_get(const char *ddname, nvlist_t **nvp);
int dsl_deleg_set(const char *ddname, nvlist_t *nvp, boolean_t unset);
int dsl_deleg_access(const char *ddname, const char *perm, cred_t *cr);
-int dsl_deleg_access_impl(struct dsl_dataset *ds, const char *perm, cred_t *cr);
+int dsl_deleg_access_impl(struct dsl_dataset *ds, boolean_t descendent,
+ const char *perm, cred_t *cr);
void dsl_deleg_set_create_perms(dsl_dir_t *dd, dmu_tx_t *tx, cred_t *cr);
int dsl_deleg_can_allow(char *ddname, nvlist_t *nvp, cred_t *cr);
int dsl_deleg_can_unallow(char *ddname, nvlist_t *nvp, cred_t *cr);
diff --git a/usr/src/uts/common/fs/zfs/sys/spa.h b/usr/src/uts/common/fs/zfs/sys/spa.h
index 04742559fa..a8e797c3aa 100644
--- a/usr/src/uts/common/fs/zfs/sys/spa.h
+++ b/usr/src/uts/common/fs/zfs/sys/spa.h
@@ -21,6 +21,7 @@
/*
* Copyright (c) 2005, 2010, Oracle and/or its affiliates. All rights reserved.
* Copyright (c) 2011 by Delphix. All rights reserved.
+ * Copyright 2011 Nexenta Systems, Inc. All rights reserved.
*/
#ifndef _SYS_SPA_H
@@ -578,6 +579,7 @@ extern void spa_altroot(spa_t *, char *, size_t);
extern int spa_sync_pass(spa_t *spa);
extern char *spa_name(spa_t *spa);
extern uint64_t spa_guid(spa_t *spa);
+extern uint64_t spa_load_guid(spa_t *spa);
extern uint64_t spa_last_synced_txg(spa_t *spa);
extern uint64_t spa_first_txg(spa_t *spa);
extern uint64_t spa_syncing_txg(spa_t *spa);
@@ -611,6 +613,7 @@ extern uint64_t spa_get_random(uint64_t range);
extern uint64_t spa_generate_guid(spa_t *spa);
extern void sprintf_blkptr(char *buf, const blkptr_t *bp);
extern void spa_freeze(spa_t *spa);
+extern int spa_change_guid(spa_t *spa);
extern void spa_upgrade(spa_t *spa, uint64_t version);
extern void spa_evict_all(void);
extern vdev_t *spa_lookup_by_guid(spa_t *spa, uint64_t guid,
diff --git a/usr/src/uts/common/fs/zfs/sys/spa_impl.h b/usr/src/uts/common/fs/zfs/sys/spa_impl.h
index 3c8caf5357..163efd650c 100644
--- a/usr/src/uts/common/fs/zfs/sys/spa_impl.h
+++ b/usr/src/uts/common/fs/zfs/sys/spa_impl.h
@@ -21,6 +21,7 @@
/*
* Copyright (c) 2005, 2010, Oracle and/or its affiliates. All rights reserved.
* Copyright (c) 2011 by Delphix. All rights reserved.
+ * Copyright 2011 Nexenta Systems, Inc. All rights reserved.
*/
#ifndef _SYS_SPA_IMPL_H
@@ -111,6 +112,7 @@ struct spa {
* Fields protected by spa_namespace_lock.
*/
char spa_name[MAXNAMELEN]; /* pool name */
+ char *spa_comment; /* comment */
avl_node_t spa_avl; /* node in spa_namespace_avl */
nvlist_t *spa_config; /* last synced config */
nvlist_t *spa_config_syncing; /* currently syncing config */
@@ -136,7 +138,8 @@ struct spa {
objset_t *spa_meta_objset; /* copy of dp->dp_meta_objset */
txg_list_t spa_vdev_txg_list; /* per-txg dirty vdev list */
vdev_t *spa_root_vdev; /* top-level vdev container */
- uint64_t spa_load_guid; /* initial guid for spa_load */
+ uint64_t spa_config_guid; /* config pool guid */
+ uint64_t spa_load_guid; /* spa_load initialized 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/usr/src/uts/common/fs/zfs/sys/vdev_disk.h b/usr/src/uts/common/fs/zfs/sys/vdev_disk.h
index b748571ea0..ffca0a7dcb 100644
--- a/usr/src/uts/common/fs/zfs/sys/vdev_disk.h
+++ b/usr/src/uts/common/fs/zfs/sys/vdev_disk.h
@@ -21,13 +21,12 @@
/*
* Copyright 2008 Sun Microsystems, Inc. All rights reserved.
* Use is subject to license terms.
+ * Copyright 2011 Joyent, Inc. All rights reserved.
*/
#ifndef _SYS_VDEV_DISK_H
#define _SYS_VDEV_DISK_H
-#pragma ident "%Z%%M% %I% %E% SMI"
-
#include <sys/vdev.h>
#ifdef _KERNEL
#include <sys/buf.h>
@@ -40,14 +39,22 @@
extern "C" {
#endif
+#ifdef _KERNEL
typedef struct vdev_disk {
ddi_devid_t vd_devid;
char *vd_minor;
ldi_handle_t vd_lh;
} vdev_disk_t;
+#endif
+extern int vdev_disk_physio(vdev_t *, caddr_t, size_t, uint64_t, int);
+
+/*
+ * Since vdev_disk.c is not compiled into libzpool, this function should only be
+ * defined in the zfs kernel module.
+ */
#ifdef _KERNEL
-extern int vdev_disk_physio(ldi_handle_t, caddr_t, size_t, uint64_t, int);
+extern int vdev_disk_ldi_physio(ldi_handle_t, caddr_t, size_t, uint64_t, int);
#endif
#ifdef __cplusplus
}
diff --git a/usr/src/uts/common/fs/zfs/sys/vdev_raidz.h b/usr/src/uts/common/fs/zfs/sys/vdev_raidz.h
new file mode 100644
index 0000000000..496b718bd6
--- /dev/null
+++ b/usr/src/uts/common/fs/zfs/sys/vdev_raidz.h
@@ -0,0 +1,49 @@
+/*
+ * 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 2011 Joyent, Inc. All rights reserved.
+ */
+
+#ifndef _SYS_VDEV_RAIDZ_H
+#define _SYS_VDEV_RAIDZ_H
+
+#include <sys/vdev.h>
+#include <sys/semaphore.h>
+#include <sys/buf.h>
+#ifdef _KERNEL
+#include <sys/ddi.h>
+#include <sys/sunldi.h>
+#include <sys/sunddi.h>
+#endif
+
+#ifdef __cplusplus
+extern "C" {
+#endif
+
+#ifdef _KERNEL
+extern int vdev_raidz_physio(vdev_t *,
+ caddr_t, size_t, uint64_t, uint64_t, boolean_t);
+#endif
+#ifdef __cplusplus
+}
+#endif
+
+#endif /* _SYS_VDEV_RAIDZ_H */
diff --git a/usr/src/uts/common/fs/zfs/sys/zio.h b/usr/src/uts/common/fs/zfs/sys/zio.h
index 7b5abf5d27..e536076caa 100644
--- a/usr/src/uts/common/fs/zfs/sys/zio.h
+++ b/usr/src/uts/common/fs/zfs/sys/zio.h
@@ -24,6 +24,7 @@
*/
/*
* Copyright 2011 Nexenta Systems, Inc. All rights reserved.
+ * Copyright 2011 Joyent, Inc. All rights reserved.
*/
#ifndef _ZIO_H
@@ -79,6 +80,7 @@ enum zio_checksum {
ZIO_CHECKSUM_FLETCHER_4,
ZIO_CHECKSUM_SHA256,
ZIO_CHECKSUM_ZILOG2,
+ ZIO_CHECKSUM_NOPARITY,
ZIO_CHECKSUM_FUNCTIONS
};
diff --git a/usr/src/uts/common/fs/zfs/vdev.c b/usr/src/uts/common/fs/zfs/vdev.c
index bac3e86054..2456ca857c 100644
--- a/usr/src/uts/common/fs/zfs/vdev.c
+++ b/usr/src/uts/common/fs/zfs/vdev.c
@@ -21,6 +21,8 @@
/*
* 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.
*/
#include <sys/zfs_context.h>
@@ -286,6 +288,7 @@ vdev_alloc_common(spa_t *spa, uint_t id, uint64_t guid, vdev_ops_t *ops)
if (spa->spa_root_vdev == NULL) {
ASSERT(ops == &vdev_root_ops);
spa->spa_root_vdev = vd;
+ spa->spa_load_guid = spa_generate_guid(NULL);
}
if (guid == 0 && ops != &vdev_hole_ops) {
diff --git a/usr/src/uts/common/fs/zfs/vdev_disk.c b/usr/src/uts/common/fs/zfs/vdev_disk.c
index b1af4dcff6..f78580d0f1 100644
--- a/usr/src/uts/common/fs/zfs/vdev_disk.c
+++ b/usr/src/uts/common/fs/zfs/vdev_disk.c
@@ -327,8 +327,18 @@ vdev_disk_close(vdev_t *vd)
}
int
-vdev_disk_physio(ldi_handle_t vd_lh, caddr_t data, size_t size,
- uint64_t offset, int flags)
+vdev_disk_physio(vdev_t *vd, caddr_t data,
+ size_t size, uint64_t offset, int flags)
+{
+ vdev_disk_t *dvd = vd->vdev_tsd;
+
+ ASSERT(vd->vdev_ops == &vdev_disk_ops);
+ return (vdev_disk_ldi_physio(dvd->vd_lh, data, size, offset, flags));
+}
+
+int
+vdev_disk_ldi_physio(ldi_handle_t vd_lh, caddr_t data,
+ size_t size, uint64_t offset, int flags)
{
buf_t *bp;
int error = 0;
@@ -580,7 +590,7 @@ vdev_disk_read_rootlabel(char *devpath, char *devid, nvlist_t **config)
/* read vdev label */
offset = vdev_label_offset(size, l, 0);
- if (vdev_disk_physio(vd_lh, (caddr_t)label,
+ if (vdev_disk_ldi_physio(vd_lh, (caddr_t)label,
VDEV_SKIP_SIZE + VDEV_PHYS_SIZE, offset, B_READ) != 0)
continue;
diff --git a/usr/src/uts/common/fs/zfs/vdev_raidz.c b/usr/src/uts/common/fs/zfs/vdev_raidz.c
index 4b0f5602c1..736683b6ef 100644
--- a/usr/src/uts/common/fs/zfs/vdev_raidz.c
+++ b/usr/src/uts/common/fs/zfs/vdev_raidz.c
@@ -21,11 +21,15 @@
/*
* Copyright (c) 2005, 2010, Oracle and/or its affiliates. All rights reserved.
+ * Copyright 2011 Joyent, Inc. All rights reserved.
*/
#include <sys/zfs_context.h>
#include <sys/spa.h>
#include <sys/vdev_impl.h>
+#include <sys/vdev_disk.h>
+#include <sys/vdev_file.h>
+#include <sys/vdev_raidz.h>
#include <sys/zio.h>
#include <sys/zio_checksum.h>
#include <sys/fs/zfs.h>
@@ -152,6 +156,8 @@ typedef struct raidz_map {
VDEV_RAIDZ_64MUL_2((x), mask); \
}
+#define VDEV_LABEL_OFFSET(x) (x + VDEV_LABEL_START_SIZE)
+
/*
* Force reconstruction to use the general purpose method.
*/
@@ -431,12 +437,12 @@ static const zio_vsd_ops_t vdev_raidz_vsd_ops = {
};
static raidz_map_t *
-vdev_raidz_map_alloc(zio_t *zio, uint64_t unit_shift, uint64_t dcols,
- uint64_t nparity)
+vdev_raidz_map_alloc(caddr_t data, uint64_t size, uint64_t offset,
+ uint64_t unit_shift, uint64_t dcols, uint64_t nparity)
{
raidz_map_t *rm;
- uint64_t b = zio->io_offset >> unit_shift;
- uint64_t s = zio->io_size >> unit_shift;
+ uint64_t b = offset >> unit_shift;
+ uint64_t s = size >> unit_shift;
uint64_t f = b % dcols;
uint64_t o = (b / dcols) << unit_shift;
uint64_t q, r, c, bc, col, acols, scols, coff, devidx, asize, tot;
@@ -506,7 +512,7 @@ vdev_raidz_map_alloc(zio_t *zio, uint64_t unit_shift, uint64_t dcols,
for (c = 0; c < rm->rm_firstdatacol; c++)
rm->rm_col[c].rc_data = zio_buf_alloc(rm->rm_col[c].rc_size);
- rm->rm_col[c].rc_data = zio->io_data;
+ rm->rm_col[c].rc_data = data;
for (c = c + 1; c < acols; c++)
rm->rm_col[c].rc_data = (char *)rm->rm_col[c - 1].rc_data +
@@ -535,7 +541,7 @@ vdev_raidz_map_alloc(zio_t *zio, uint64_t unit_shift, uint64_t dcols,
ASSERT(rm->rm_cols >= 2);
ASSERT(rm->rm_col[0].rc_size == rm->rm_col[1].rc_size);
- if (rm->rm_firstdatacol == 1 && (zio->io_offset & (1ULL << 20))) {
+ if (rm->rm_firstdatacol == 1 && (offset & (1ULL << 20))) {
devidx = rm->rm_col[0].rc_devidx;
o = rm->rm_col[0].rc_offset;
rm->rm_col[0].rc_devidx = rm->rm_col[1].rc_devidx;
@@ -547,8 +553,6 @@ vdev_raidz_map_alloc(zio_t *zio, uint64_t unit_shift, uint64_t dcols,
rm->rm_skipstart = 1;
}
- zio->io_vsd = rm;
- zio->io_vsd_ops = &vdev_raidz_vsd_ops;
return (rm);
}
@@ -1491,6 +1495,106 @@ vdev_raidz_close(vdev_t *vd)
vdev_close(vd->vdev_child[c]);
}
+/*
+ * Handle a read or write request to a RAID-Z dump device.
+ *
+ * Unlike the normal RAID-Z codepath in vdev_raidz_io_start(), reads and writes
+ * to the dump zvol are written across a full 128Kb block. As a result, an
+ * individual I/O may not span all columns in the RAID-Z map; moreover, a small
+ * I/O may only span a single column.
+ *
+ * Note that since there are no parity bits calculated or written, this format
+ * remains the same no matter how many parity bits are used in a normal RAID-Z
+ * stripe.
+ */
+int
+vdev_raidz_physio(vdev_t *vd, caddr_t data, size_t size,
+ uint64_t offset, uint64_t origoffset, boolean_t doread)
+{
+ vdev_t *tvd = vd->vdev_top;
+ vdev_t *cvd;
+ raidz_map_t *rm;
+ raidz_col_t *rc;
+ int c, err = 0;
+
+ uint64_t start, end, colstart, colend;
+ uint64_t coloffset, colsize, colskip;
+
+ int flags = doread ? B_READ : B_WRITE;
+
+#ifdef _KERNEL
+
+ /*
+ * Don't write past the end of the block
+ */
+ VERIFY3U(offset + size, <=, origoffset + SPA_MAXBLOCKSIZE);
+
+ /*
+ * Even if this I/O operation doesn't span the full block size, let's
+ * treat the on-disk format as if the only blocks are the complete 128k
+ * size.
+ */
+ start = offset;
+ end = start + size;
+
+ /*
+ * Allocate a RAID-Z map for this block. Note that this block starts
+ * from the "original" offset, this is, the offset of the extent which
+ * contains the requisite offset of the data being read or written.
+ */
+ rm = vdev_raidz_map_alloc(data - (offset - origoffset),
+ SPA_MAXBLOCKSIZE, origoffset, tvd->vdev_ashift, vd->vdev_children,
+ vd->vdev_nparity);
+
+ ASSERT3U(rm->rm_asize, ==, vdev_psize_to_asize(vd, size));
+
+ coloffset = origoffset;
+
+ for (c = rm->rm_firstdatacol; c < rm->rm_cols;
+ c++, coloffset += rc->rc_size) {
+ rc = &rm->rm_col[c];
+ cvd = vd->vdev_child[rc->rc_devidx];
+
+ /*
+ * Find the start and end of this column in the RAID-Z matrix,
+ * keeping in mind that the stated size and offset of the
+ * operation may not fill the entire column for this vdev.
+ *
+ * If any portion of the data being read or written spans this
+ * column, issue the appropriate operation to the child vdev.
+ */
+ if (coloffset + rc->rc_size <= start)
+ continue;
+ if (coloffset >= end)
+ continue;
+
+ colstart = MAX(coloffset, start);
+ colend = MIN(end, coloffset + rc->rc_size);
+ colsize = colend - colstart;
+ colskip = colstart - coloffset;
+
+ VERIFY3U(colsize, <=, rc->rc_size);
+ VERIFY3U(colskip, <=, rc->rc_size);
+
+ /*
+ * Note that the child vdev will have a vdev label at the start
+ * of its range of offsets, hence the need for
+ * VDEV_LABEL_OFFSET(). See zio_vdev_child_io() for another
+ * example of why this calculation is needed.
+ */
+ if ((err = vdev_disk_physio(cvd,
+ ((char *)rc->rc_data) + colskip, colsize,
+ VDEV_LABEL_OFFSET(rc->rc_offset) + colskip,
+ flags)) != 0)
+ break;
+ }
+
+ vdev_raidz_map_free(rm);
+#endif /* KERNEL */
+
+ return (err);
+}
+
static uint64_t
vdev_raidz_asize(vdev_t *vd, uint64_t psize)
{
@@ -1526,9 +1630,13 @@ vdev_raidz_io_start(zio_t *zio)
raidz_col_t *rc;
int c, i;
- rm = vdev_raidz_map_alloc(zio, tvd->vdev_ashift, vd->vdev_children,
+ rm = vdev_raidz_map_alloc(zio->io_data, zio->io_size, zio->io_offset,
+ tvd->vdev_ashift, vd->vdev_children,
vd->vdev_nparity);
+ zio->io_vsd = rm;
+ zio->io_vsd_ops = &vdev_raidz_vsd_ops;
+
ASSERT3U(rm->rm_asize, ==, vdev_psize_to_asize(vd, zio->io_size));
if (zio->io_type == ZIO_TYPE_WRITE) {
@@ -1659,6 +1767,13 @@ raidz_parity_verify(zio_t *zio, raidz_map_t *rm)
int c, ret = 0;
raidz_col_t *rc;
+ blkptr_t *bp = zio->io_bp;
+ uint_t checksum = (bp == NULL ? zio->io_prop.zp_checksum :
+ (BP_IS_GANG(bp) ? ZIO_CHECKSUM_GANG_HEADER : BP_GET_CHECKSUM(bp)));
+
+ if (checksum == ZIO_CHECKSUM_NOPARITY)
+ return (ret);
+
for (c = 0; c < rm->rm_firstdatacol; c++) {
rc = &rm->rm_col[c];
if (!rc->rc_tried || rc->rc_error != 0)
diff --git a/usr/src/uts/common/fs/zfs/zap_micro.c b/usr/src/uts/common/fs/zfs/zap_micro.c
index 2d89c20c47..c148ea14cd 100644
--- a/usr/src/uts/common/fs/zfs/zap_micro.c
+++ b/usr/src/uts/common/fs/zfs/zap_micro.c
@@ -20,6 +20,7 @@
*/
/*
* Copyright (c) 2005, 2010, Oracle and/or its affiliates. All rights reserved.
+ * Copyright (c) 2011 by Delphix. All rights reserved.
*/
#include <sys/zio.h>
@@ -1403,7 +1404,7 @@ zap_count_write(objset_t *os, uint64_t zapobj, const char *name, int add,
}
/*
- * We lock the zap with adding == FALSE. Because, if we pass
+ * We lock the zap with adding == FALSE. Because, if we pass
* the actual value of add, it could trigger a mzap_upgrade().
* At present we are just evaluating the possibility of this operation
* and hence we donot want to trigger an upgrade.
diff --git a/usr/src/uts/common/fs/zfs/zfs_ioctl.c b/usr/src/uts/common/fs/zfs/zfs_ioctl.c
index 486ae9506d..929fc06296 100644
--- a/usr/src/uts/common/fs/zfs/zfs_ioctl.c
+++ b/usr/src/uts/common/fs/zfs/zfs_ioctl.c
@@ -21,6 +21,8 @@
/*
* Copyright (c) 2005, 2010, Oracle and/or its affiliates. All rights reserved.
* Portions Copyright 2011 Martin Matuska
+ * Copyright 2011 Nexenta Systems, Inc. All rights reserved.
+ * Copyright (c) 2011 by Delphix. All rights reserved.
*/
#include <sys/types.h>
@@ -348,17 +350,37 @@ zfs_dozonecheck_ds(const char *dataset, dsl_dataset_t *ds, cred_t *cr)
return (zfs_dozonecheck_impl(dataset, zoned, cr));
}
+/*
+ * If name ends in a '@', then require recursive permissions.
+ */
int
zfs_secpolicy_write_perms(const char *name, const char *perm, cred_t *cr)
{
int error;
+ boolean_t descendent = B_FALSE;
+ dsl_dataset_t *ds;
+ char *at;
- error = zfs_dozonecheck(name, cr);
+ at = strchr(name, '@');
+ if (at != NULL && at[1] == '\0') {
+ *at = '\0';
+ descendent = B_TRUE;
+ }
+
+ error = dsl_dataset_hold(name, FTAG, &ds);
+ if (at != NULL)
+ *at = '@';
+ if (error != 0)
+ return (error);
+
+ error = zfs_dozonecheck_ds(name, ds, cr);
if (error == 0) {
error = secpolicy_zfs(cr);
if (error)
- error = dsl_deleg_access(name, perm, cr);
+ error = dsl_deleg_access_impl(ds, descendent, perm, cr);
}
+
+ dsl_dataset_rele(ds, FTAG);
return (error);
}
@@ -372,7 +394,7 @@ zfs_secpolicy_write_perms_ds(const char *name, dsl_dataset_t *ds,
if (error == 0) {
error = secpolicy_zfs(cr);
if (error)
- error = dsl_deleg_access_impl(ds, perm, cr);
+ error = dsl_deleg_access_impl(ds, B_FALSE, perm, cr);
}
return (error);
}
@@ -679,21 +701,14 @@ zfs_secpolicy_destroy(zfs_cmd_t *zc, cred_t *cr)
/*
* Destroying snapshots with delegated permissions requires
* descendent mount and destroy permissions.
- * Reassemble the full filesystem@snap name so dsl_deleg_access()
- * can do the correct permission check.
- *
- * Since this routine is used when doing a recursive destroy of snapshots
- * and destroying snapshots requires descendent permissions, a successfull
- * check of the top level snapshot applies to snapshots of all descendent
- * datasets as well.
*/
static int
-zfs_secpolicy_destroy_snaps(zfs_cmd_t *zc, cred_t *cr)
+zfs_secpolicy_destroy_recursive(zfs_cmd_t *zc, cred_t *cr)
{
int error;
char *dsname;
- dsname = kmem_asprintf("%s@%s", zc->zc_name, zc->zc_value);
+ dsname = kmem_asprintf("%s@", zc->zc_name);
error = zfs_secpolicy_destroy_perms(dsname, cr);
@@ -1449,6 +1464,20 @@ zfs_ioc_pool_get_history(zfs_cmd_t *zc)
}
static int
+zfs_ioc_pool_reguid(zfs_cmd_t *zc)
+{
+ spa_t *spa;
+ int error;
+
+ error = spa_open(zc->zc_name, &spa, FTAG);
+ if (error == 0) {
+ error = spa_change_guid(spa);
+ spa_close(spa, FTAG);
+ }
+ return (error);
+}
+
+static int
zfs_ioc_dsobj_to_dsname(zfs_cmd_t *zc)
{
int error;
@@ -1745,9 +1774,12 @@ zfs_ioc_objset_stats_impl(zfs_cmd_t *zc, objset_t *os)
* inconsistent. So this is a bit of a workaround...
* XXX reading with out owning
*/
- if (!zc->zc_objset_stats.dds_inconsistent) {
- if (dmu_objset_type(os) == DMU_OST_ZVOL)
- VERIFY(zvol_get_stats(os, nv) == 0);
+ if (!zc->zc_objset_stats.dds_inconsistent &&
+ dmu_objset_type(os) == DMU_OST_ZVOL) {
+ error = zvol_get_stats(os, nv);
+ if (error == EIO)
+ return (error);
+ VERIFY3S(error, ==, 0);
}
error = put_nvlist(zc, nv);
nvlist_free(nv);
@@ -1956,8 +1988,7 @@ top:
NULL, &zc->zc_cookie);
if (error == ENOENT)
error = ESRCH;
- } while (error == 0 && dataset_name_hidden(zc->zc_name) &&
- !(zc->zc_iflags & FKIOCTL));
+ } while (error == 0 && dataset_name_hidden(zc->zc_name));
dmu_objset_rele(os, FTAG);
/*
@@ -2235,6 +2266,8 @@ retry:
if (nvpair_type(propval) !=
DATA_TYPE_UINT64_ARRAY)
err = EINVAL;
+ } else {
+ err = EINVAL;
}
} else if (err == 0) {
if (nvpair_type(propval) == DATA_TYPE_STRING) {
@@ -3101,25 +3134,45 @@ zfs_unmount_snap(const char *name, void *arg)
/*
* inputs:
- * zc_name name of filesystem
- * zc_value short name of snapshot
+ * zc_name name of filesystem, snaps must be under it
+ * zc_nvlist_src[_size] full names of snapshots to destroy
* zc_defer_destroy mark for deferred destroy
*
- * outputs: none
+ * outputs:
+ * zc_name on failure, name of failed snapshot
*/
static int
-zfs_ioc_destroy_snaps(zfs_cmd_t *zc)
+zfs_ioc_destroy_snaps_nvl(zfs_cmd_t *zc)
{
- int err;
+ int err, len;
+ nvlist_t *nvl;
+ nvpair_t *pair;
- if (snapshot_namecheck(zc->zc_value, NULL, NULL) != 0)
- return (EINVAL);
- err = dmu_objset_find(zc->zc_name,
- zfs_unmount_snap, zc->zc_value, DS_FIND_CHILDREN);
- if (err)
+ if ((err = get_nvlist(zc->zc_nvlist_src, zc->zc_nvlist_src_size,
+ zc->zc_iflags, &nvl)) != 0)
return (err);
- return (dmu_snapshots_destroy(zc->zc_name, zc->zc_value,
- zc->zc_defer_destroy));
+
+ len = strlen(zc->zc_name);
+ for (pair = nvlist_next_nvpair(nvl, NULL); pair != NULL;
+ pair = nvlist_next_nvpair(nvl, pair)) {
+ const char *name = nvpair_name(pair);
+ /*
+ * The snap name must be underneath the zc_name. This ensures
+ * that our permission checks were legitimate.
+ */
+ if (strncmp(zc->zc_name, name, len) != 0 ||
+ (name[len] != '@' && name[len] != '/')) {
+ nvlist_free(nvl);
+ return (EINVAL);
+ }
+
+ (void) zfs_unmount_snap(name, NULL);
+ }
+
+ err = dmu_snapshots_destroy_nvl(nvl, zc->zc_defer_destroy,
+ zc->zc_name);
+ nvlist_free(nvl);
+ return (err);
}
/*
@@ -3762,6 +3815,8 @@ out:
* zc_obj fromorigin flag (mutually exclusive with zc_fromobj)
* zc_sendobj objsetid of snapshot to send
* zc_fromobj objsetid of incremental fromsnap (may be zero)
+ * zc_guid if set, estimate size of stream only. zc_cookie is ignored.
+ * output size in zc_objset_type.
*
* outputs: none
*/
@@ -3770,13 +3825,13 @@ zfs_ioc_send(zfs_cmd_t *zc)
{
objset_t *fromsnap = NULL;
objset_t *tosnap;
- file_t *fp;
int error;
offset_t off;
dsl_dataset_t *ds;
dsl_dataset_t *dsfrom = NULL;
spa_t *spa;
dsl_pool_t *dp;
+ boolean_t estimate = (zc->zc_guid != 0);
error = spa_open(zc->zc_name, &spa, FTAG);
if (error)
@@ -3817,20 +3872,26 @@ zfs_ioc_send(zfs_cmd_t *zc)
spa_close(spa, FTAG);
}
- fp = getf(zc->zc_cookie);
- if (fp == NULL) {
- dsl_dataset_rele(ds, FTAG);
- if (dsfrom)
- dsl_dataset_rele(dsfrom, FTAG);
- return (EBADF);
- }
+ if (estimate) {
+ error = dmu_send_estimate(tosnap, fromsnap, zc->zc_obj,
+ &zc->zc_objset_type);
+ } else {
+ file_t *fp = getf(zc->zc_cookie);
+ if (fp == NULL) {
+ dsl_dataset_rele(ds, FTAG);
+ if (dsfrom)
+ dsl_dataset_rele(dsfrom, FTAG);
+ return (EBADF);
+ }
- off = fp->f_offset;
- error = dmu_sendbackup(tosnap, fromsnap, zc->zc_obj, fp->f_vnode, &off);
+ off = fp->f_offset;
+ error = dmu_sendbackup(tosnap, fromsnap, zc->zc_obj,
+ fp->f_vnode, &off);
- if (VOP_SEEK(fp->f_vnode, fp->f_offset, &off, NULL) == 0)
- fp->f_offset = off;
- releasef(zc->zc_cookie);
+ if (VOP_SEEK(fp->f_vnode, fp->f_offset, &off, NULL) == 0)
+ fp->f_offset = off;
+ releasef(zc->zc_cookie);
+ }
if (dsfrom)
dsl_dataset_rele(dsfrom, FTAG);
dsl_dataset_rele(ds, FTAG);
@@ -4625,6 +4686,70 @@ zfs_ioc_get_holds(zfs_cmd_t *zc)
}
/*
+ * inputs:
+ * zc_name name of new filesystem or snapshot
+ * zc_value full name of old snapshot
+ *
+ * outputs:
+ * zc_cookie space in bytes
+ * zc_objset_type compressed space in bytes
+ * zc_perm_action uncompressed space in bytes
+ */
+static int
+zfs_ioc_space_written(zfs_cmd_t *zc)
+{
+ int error;
+ dsl_dataset_t *new, *old;
+
+ error = dsl_dataset_hold(zc->zc_name, FTAG, &new);
+ if (error != 0)
+ return (error);
+ error = dsl_dataset_hold(zc->zc_value, FTAG, &old);
+ if (error != 0) {
+ dsl_dataset_rele(new, FTAG);
+ return (error);
+ }
+
+ error = dsl_dataset_space_written(old, new, &zc->zc_cookie,
+ &zc->zc_objset_type, &zc->zc_perm_action);
+ dsl_dataset_rele(old, FTAG);
+ dsl_dataset_rele(new, FTAG);
+ return (error);
+}
+
+/*
+ * inputs:
+ * zc_name full name of last snapshot
+ * zc_value full name of first snapshot
+ *
+ * outputs:
+ * zc_cookie space in bytes
+ * zc_objset_type compressed space in bytes
+ * zc_perm_action uncompressed space in bytes
+ */
+static int
+zfs_ioc_space_snaps(zfs_cmd_t *zc)
+{
+ int error;
+ dsl_dataset_t *new, *old;
+
+ error = dsl_dataset_hold(zc->zc_name, FTAG, &new);
+ if (error != 0)
+ return (error);
+ error = dsl_dataset_hold(zc->zc_value, FTAG, &old);
+ if (error != 0) {
+ dsl_dataset_rele(new, FTAG);
+ return (error);
+ }
+
+ error = dsl_dataset_space_wouldfree(old, new, &zc->zc_cookie,
+ &zc->zc_objset_type, &zc->zc_perm_action);
+ dsl_dataset_rele(old, FTAG);
+ dsl_dataset_rele(new, FTAG);
+ return (error);
+}
+
+/*
* pool create, destroy, and export don't log the history as part of
* zfsdev_ioctl, but rather zfs_ioc_pool_create, and zfs_ioc_pool_export
* do the logging of those commands.
@@ -4686,7 +4811,7 @@ static zfs_ioc_vec_t zfs_ioc_vec[] = {
POOL_CHECK_SUSPENDED | POOL_CHECK_READONLY },
{ zfs_ioc_recv, zfs_secpolicy_receive, DATASET_NAME, B_TRUE,
POOL_CHECK_SUSPENDED | POOL_CHECK_READONLY },
- { zfs_ioc_send, zfs_secpolicy_send, DATASET_NAME, B_TRUE,
+ { zfs_ioc_send, zfs_secpolicy_send, DATASET_NAME, B_FALSE,
POOL_CHECK_NONE },
{ zfs_ioc_inject_fault, zfs_secpolicy_inject, NO_NAME, B_FALSE,
POOL_CHECK_NONE },
@@ -4700,8 +4825,6 @@ static zfs_ioc_vec_t zfs_ioc_vec[] = {
POOL_CHECK_NONE },
{ zfs_ioc_promote, zfs_secpolicy_promote, DATASET_NAME, B_TRUE,
POOL_CHECK_SUSPENDED | POOL_CHECK_READONLY },
- { zfs_ioc_destroy_snaps, zfs_secpolicy_destroy_snaps, DATASET_NAME,
- B_TRUE, POOL_CHECK_SUSPENDED | POOL_CHECK_READONLY },
{ zfs_ioc_snapshot, zfs_secpolicy_snapshot, DATASET_NAME, B_TRUE,
POOL_CHECK_SUSPENDED | POOL_CHECK_READONLY },
{ zfs_ioc_dsobj_to_dsname, zfs_secpolicy_diff, POOL_NAME, B_FALSE,
@@ -4745,7 +4868,15 @@ static zfs_ioc_vec_t zfs_ioc_vec[] = {
{ zfs_ioc_tmp_snapshot, zfs_secpolicy_tmp_snapshot, DATASET_NAME,
B_FALSE, POOL_CHECK_SUSPENDED | POOL_CHECK_READONLY },
{ zfs_ioc_obj_to_stats, zfs_secpolicy_diff, DATASET_NAME, B_FALSE,
- POOL_CHECK_SUSPENDED }
+ POOL_CHECK_SUSPENDED },
+ { zfs_ioc_space_written, zfs_secpolicy_read, DATASET_NAME, B_FALSE,
+ POOL_CHECK_SUSPENDED },
+ { zfs_ioc_space_snaps, zfs_secpolicy_read, DATASET_NAME, B_FALSE,
+ POOL_CHECK_SUSPENDED },
+ { zfs_ioc_destroy_snaps_nvl, zfs_secpolicy_destroy_recursive,
+ DATASET_NAME, B_TRUE, POOL_CHECK_SUSPENDED | POOL_CHECK_READONLY },
+ { zfs_ioc_pool_reguid, zfs_secpolicy_config, POOL_NAME, B_TRUE,
+ POOL_CHECK_SUSPENDED | POOL_CHECK_READONLY }
};
int
diff --git a/usr/src/uts/common/fs/zfs/zfs_vnops.c b/usr/src/uts/common/fs/zfs/zfs_vnops.c
index 0c39274caf..9fae31fa6b 100644
--- a/usr/src/uts/common/fs/zfs/zfs_vnops.c
+++ b/usr/src/uts/common/fs/zfs/zfs_vnops.c
@@ -25,6 +25,10 @@
/* Portions Copyright 2007 Jeremy Teo */
/* Portions Copyright 2010 Robert Milkowski */
+/*
+ * Copyright (c) 2011, Joyent, Inc. All rights reserved.
+ */
+
#include <sys/types.h>
#include <sys/param.h>
#include <sys/time.h>
@@ -4145,6 +4149,8 @@ top:
&zp->z_pflags, 8);
zfs_tstamp_update_setup(zp, CONTENT_MODIFIED, mtime, ctime,
B_TRUE);
+ err = sa_bulk_update(zp->z_sa_hdl, bulk, count, tx);
+
zfs_log_write(zfsvfs->z_log, tx, TX_WRITE, zp, off, len, 0);
}
dmu_tx_commit(tx);
@@ -4655,27 +4661,6 @@ zfs_addmap(vnode_t *vp, offset_t off, struct as *as, caddr_t addr,
return (0);
}
-/*
- * The reason we push dirty pages as part of zfs_delmap() is so that we get a
- * more accurate mtime for the associated file. Since we don't have a way of
- * detecting when the data was actually modified, we have to resort to
- * heuristics. If an explicit msync() is done, then we mark the mtime when the
- * last page is pushed. The problem occurs when the msync() call is omitted,
- * which by far the most common case:
- *
- * open()
- * mmap()
- * <modify memory>
- * munmap()
- * close()
- * <time lapse>
- * putpage() via fsflush
- *
- * If we wait until fsflush to come along, we can have a modification time that
- * is some arbitrary point in the future. In order to prevent this in the
- * common case, we flush pages whenever a (MAP_SHARED, PROT_WRITE) mapping is
- * torn down.
- */
/* ARGSUSED */
static int
zfs_delmap(vnode_t *vp, offset_t off, struct as *as, caddr_t addr,
@@ -4687,10 +4672,6 @@ zfs_delmap(vnode_t *vp, offset_t off, struct as *as, caddr_t addr,
ASSERT3U(VTOZ(vp)->z_mapcnt, >=, pages);
atomic_add_64(&VTOZ(vp)->z_mapcnt, -pages);
- if ((flags & MAP_SHARED) && (prot & PROT_WRITE) &&
- vn_has_cached_data(vp))
- (void) VOP_PUTPAGE(vp, off, len, B_ASYNC, cr, ct);
-
return (0);
}
diff --git a/usr/src/uts/common/fs/zfs/zio_checksum.c b/usr/src/uts/common/fs/zfs/zio_checksum.c
index c8fe20f2eb..e64d31a248 100644
--- a/usr/src/uts/common/fs/zfs/zio_checksum.c
+++ b/usr/src/uts/common/fs/zfs/zio_checksum.c
@@ -20,6 +20,7 @@
*/
/*
* Copyright (c) 2005, 2010, Oracle and/or its affiliates. All rights reserved.
+ * Copyright 2011 Joyent, Inc. All rights reserved.
*/
#include <sys/zfs_context.h>
@@ -77,6 +78,7 @@ zio_checksum_info_t zio_checksum_table[ZIO_CHECKSUM_FUNCTIONS] = {
{{fletcher_4_native, fletcher_4_byteswap}, 1, 0, 0, "fletcher4"},
{{zio_checksum_SHA256, zio_checksum_SHA256}, 1, 0, 1, "sha256"},
{{fletcher_4_native, fletcher_4_byteswap}, 0, 1, 0, "zilog2"},
+ {{zio_checksum_off, zio_checksum_off}, 0, 0, 0, "noparity"},
};
enum zio_checksum
diff --git a/usr/src/uts/common/fs/zfs/zvol.c b/usr/src/uts/common/fs/zfs/zvol.c
index 178d2d1409..28245e8154 100644
--- a/usr/src/uts/common/fs/zfs/zvol.c
+++ b/usr/src/uts/common/fs/zfs/zvol.c
@@ -76,6 +76,7 @@
#include <sys/zfs_rlock.h>
#include <sys/vdev_disk.h>
#include <sys/vdev_impl.h>
+#include <sys/vdev_raidz.h>
#include <sys/zvol.h>
#include <sys/dumphdr.h>
#include <sys/zil_impl.h>
@@ -1060,27 +1061,28 @@ zvol_log_write(zvol_state_t *zv, dmu_tx_t *tx, offset_t off, ssize_t resid,
}
static int
-zvol_dumpio_vdev(vdev_t *vd, void *addr, uint64_t offset, uint64_t size,
- boolean_t doread, boolean_t isdump)
+zvol_dumpio_vdev(vdev_t *vd, void *addr, uint64_t offset, uint64_t origoffset,
+ uint64_t size, boolean_t doread, boolean_t isdump)
{
vdev_disk_t *dvd;
int c;
int numerrors = 0;
- for (c = 0; c < vd->vdev_children; c++) {
- ASSERT(vd->vdev_ops == &vdev_mirror_ops ||
- vd->vdev_ops == &vdev_replacing_ops ||
- vd->vdev_ops == &vdev_spare_ops);
- int err = zvol_dumpio_vdev(vd->vdev_child[c],
- addr, offset, size, doread, isdump);
- if (err != 0) {
- numerrors++;
- } else if (doread) {
- break;
+ if (vd->vdev_ops == &vdev_mirror_ops ||
+ vd->vdev_ops == &vdev_replacing_ops ||
+ vd->vdev_ops == &vdev_spare_ops) {
+ for (c = 0; c < vd->vdev_children; c++) {
+ int err = zvol_dumpio_vdev(vd->vdev_child[c],
+ addr, offset, origoffset, size, doread, isdump);
+ if (err != 0) {
+ numerrors++;
+ } else if (doread) {
+ break;
+ }
}
}
- if (!vd->vdev_ops->vdev_op_leaf)
+ if (!vd->vdev_ops->vdev_op_leaf && vd->vdev_ops != &vdev_raidz_ops)
return (numerrors < vd->vdev_children ? 0 : EIO);
if (doread && !vdev_readable(vd))
@@ -1088,19 +1090,27 @@ zvol_dumpio_vdev(vdev_t *vd, void *addr, uint64_t offset, uint64_t size,
else if (!doread && !vdev_writeable(vd))
return (EIO);
- dvd = vd->vdev_tsd;
- ASSERT3P(dvd, !=, NULL);
+ if (vd->vdev_ops == &vdev_raidz_ops) {
+ return (vdev_raidz_physio(vd,
+ addr, size, offset, origoffset, doread));
+ }
+
offset += VDEV_LABEL_START_SIZE;
if (ddi_in_panic() || isdump) {
ASSERT(!doread);
if (doread)
return (EIO);
+ dvd = vd->vdev_tsd;
+ ASSERT3P(dvd, !=, NULL);
return (ldi_dump(dvd->vd_lh, addr, lbtodb(offset),
lbtodb(size)));
} else {
- return (vdev_disk_physio(dvd->vd_lh, addr, size, offset,
- doread ? B_READ : B_WRITE));
+ dvd = vd->vdev_tsd;
+ ASSERT3P(dvd, !=, NULL);
+
+ return (vdev_disk_ldi_physio(dvd->vd_lh, addr, size,
+ offset, doread ? B_READ : B_WRITE));
}
}
@@ -1132,7 +1142,8 @@ zvol_dumpio(zvol_state_t *zv, void *addr, uint64_t offset, uint64_t size,
vd = vdev_lookup_top(spa, DVA_GET_VDEV(&ze->ze_dva));
offset += DVA_GET_OFFSET(&ze->ze_dva);
- error = zvol_dumpio_vdev(vd, addr, offset, size, doread, isdump);
+ error = zvol_dumpio_vdev(vd, addr, offset, DVA_GET_OFFSET(&ze->ze_dva),
+ size, doread, isdump);
if (!ddi_in_panic())
spa_config_exit(spa, SCL_STATE, FTAG);
@@ -1865,7 +1876,7 @@ zvol_dump_init(zvol_state_t *zv, boolean_t resize)
ZIO_COMPRESS_OFF) == 0);
VERIFY(nvlist_add_uint64(nv,
zfs_prop_to_name(ZFS_PROP_CHECKSUM),
- ZIO_CHECKSUM_OFF) == 0);
+ ZIO_CHECKSUM_NOPARITY) == 0);
if (version >= SPA_VERSION_DEDUP) {
VERIFY(nvlist_add_uint64(nv,
zfs_prop_to_name(ZFS_PROP_DEDUP),
diff --git a/usr/src/uts/common/inet/ip/ip_ftable.c b/usr/src/uts/common/inet/ip/ip_ftable.c
index 7cb83a2a76..980436b578 100644
--- a/usr/src/uts/common/inet/ip/ip_ftable.c
+++ b/usr/src/uts/common/inet/ip/ip_ftable.c
@@ -815,6 +815,11 @@ ire_round_robin(irb_t *irb_ptr, ire_ftable_args_t *margs, uint_t hash,
rw_enter(&irb_ptr->irb_lock, RW_WRITER);
maxwalk = irb_ptr->irb_ire_cnt; /* Excludes condemned */
+ if (maxwalk == 0) {
+ rw_exit(&irb_ptr->irb_lock);
+ return (NULL);
+ }
+
hash %= maxwalk;
irb_refhold_locked(irb_ptr);
rw_exit(&irb_ptr->irb_lock);
diff --git a/usr/src/uts/common/inet/tcp/tcp_input.c b/usr/src/uts/common/inet/tcp/tcp_input.c
index d8d78e85cb..5bd2be3a7d 100644
--- a/usr/src/uts/common/inet/tcp/tcp_input.c
+++ b/usr/src/uts/common/inet/tcp/tcp_input.c
@@ -3749,6 +3749,13 @@ process_ack:
return;
}
/*
+ * tcp_newconn_notify() changes conn_upcalls and
+ * connp->conn_upper_handle. Fix things now, in case
+ * there's data attached to this ack.
+ */
+ if (connp->conn_upcalls != NULL)
+ sockupcalls = connp->conn_upcalls;
+ /*
* For passive open, trace receipt of final ACK as
* tcp:::accept-established.
*/
diff --git a/usr/src/uts/common/netinet/in.h b/usr/src/uts/common/netinet/in.h
index c1166fc34f..b819f0dd39 100644
--- a/usr/src/uts/common/netinet/in.h
+++ b/usr/src/uts/common/netinet/in.h
@@ -1,6 +1,8 @@
/*
* Copyright 2009 Sun Microsystems, Inc. All rights reserved.
* Use is subject to license terms.
+ *
+ * Copyright 2011 Nexenta Systems, Inc. All rights reserved.
*/
/*
* Copyright (c) 1982, 1986 Regents of the University of California.
@@ -839,6 +841,38 @@ struct sockaddr_in6 {
((addr1)->_S6_un._S6_u32[1] == (addr2)->_S6_un._S6_u32[1]) && \
((addr1)->_S6_un._S6_u32[0] == (addr2)->_S6_un._S6_u32[0]))
+/*
+ * IN6_ARE_PREFIXEDADDR_EQUAL (not defined in RFCs)
+ * Compares if prefixed parts of IPv6 addresses are equal.
+ *
+ * uint32_t IN6_MASK_FROM_PREFIX(int, int);
+ * bool IN6_ARE_PREFIXEDADDR_EQUAL(const struct in6_addr *,
+ * const struct in6_addr *,
+ * int);
+ */
+#define IN6_MASK_FROM_PREFIX(qoctet, prefix) \
+ ((((qoctet) + 1) * 32 < (prefix)) ? 0xFFFFFFFFu : \
+ ((((qoctet) * 32) >= (prefix)) ? 0x00000000u : \
+ 0xFFFFFFFFu << (((qoctet) + 1) * 32 - (prefix))))
+
+#define IN6_ARE_PREFIXEDADDR_EQUAL(addr1, addr2, prefix) \
+ (((ntohl((addr1)->_S6_un._S6_u32[0]) & \
+ IN6_MASK_FROM_PREFIX(0, prefix)) == \
+ (ntohl((addr2)->_S6_un._S6_u32[0]) & \
+ IN6_MASK_FROM_PREFIX(0, prefix))) && \
+ ((ntohl((addr1)->_S6_un._S6_u32[1]) & \
+ IN6_MASK_FROM_PREFIX(1, prefix)) == \
+ (ntohl((addr2)->_S6_un._S6_u32[1]) & \
+ IN6_MASK_FROM_PREFIX(1, prefix))) && \
+ ((ntohl((addr1)->_S6_un._S6_u32[2]) & \
+ IN6_MASK_FROM_PREFIX(2, prefix)) == \
+ (ntohl((addr2)->_S6_un._S6_u32[2]) & \
+ IN6_MASK_FROM_PREFIX(2, prefix))) && \
+ ((ntohl((addr1)->_S6_un._S6_u32[3]) & \
+ IN6_MASK_FROM_PREFIX(3, prefix)) == \
+ (ntohl((addr2)->_S6_un._S6_u32[3]) & \
+ IN6_MASK_FROM_PREFIX(3, prefix))))
+
#endif /* !defined(_XPG4_2) || defined(_XPG6) || defined(__EXTENSIONS__) */
diff --git a/usr/src/uts/common/os/panic.c b/usr/src/uts/common/os/panic.c
index 3985353ff7..fbd9a64b0a 100644
--- a/usr/src/uts/common/os/panic.c
+++ b/usr/src/uts/common/os/panic.c
@@ -23,6 +23,10 @@
*/
/*
+ * Copyright (c) 2011, Joyent, Inc. All rights reserved.
+ */
+
+/*
* When the operating system detects that it is in an invalid state, a panic
* is initiated in order to minimize potential damage to user data and to
* facilitate debugging. There are three major tasks to be performed in
@@ -154,6 +158,7 @@ char panic_stack[PANICSTKSIZE]; /* reserved stack for panic_thread */
kthread_t *panic_thread; /* first thread to call panicsys() */
cpu_t panic_cpu; /* cpu from first call to panicsys() */
label_t panic_regs; /* setjmp label from panic_thread */
+label_t panic_pcb; /* t_pcb at time of panic */
struct regs *panic_reg; /* regs struct from first panicsys() */
char *volatile panicstr; /* format string to first panicsys() */
va_list panicargs; /* arguments to first panicsys() */
@@ -213,6 +218,7 @@ panicsys(const char *format, va_list alist, struct regs *rp, int on_panic_stack)
ushort_t schedflag = t->t_schedflag;
cpu_t *bound_cpu = t->t_bound_cpu;
char preempt = t->t_preempt;
+ label_t pcb = t->t_pcb;
(void) setjmp(&t->t_pcb);
t->t_flag |= T_PANIC;
@@ -290,6 +296,7 @@ panicsys(const char *format, va_list alist, struct regs *rp, int on_panic_stack)
panic_schedflag = schedflag;
panic_bound_cpu = bound_cpu;
panic_preempt = preempt;
+ panic_pcb = pcb;
if (intr_stack != NULL) {
panic_cpu.cpu_intr_stack = intr_stack;
diff --git a/usr/src/uts/common/smbsrv/smb_kproto.h b/usr/src/uts/common/smbsrv/smb_kproto.h
index 89d8e971b0..317a48d000 100644
--- a/usr/src/uts/common/smbsrv/smb_kproto.h
+++ b/usr/src/uts/common/smbsrv/smb_kproto.h
@@ -377,7 +377,6 @@ int smb_server_file_close(smb_ioc_fileid_t *);
int smb_server_sharevp(const char *, vnode_t **);
int smb_server_unshare(const char *);
-void smb_server_reconnection_check(smb_server_t *, smb_session_t *);
void smb_server_get_cfg(smb_server_t *, smb_kmod_cfg_t *);
int smb_server_spooldoc(smb_ioc_spooldoc_t *);
@@ -511,7 +510,6 @@ void smb_request_wait(smb_request_t *);
smb_session_t *smb_session_create(ksocket_t, uint16_t, smb_server_t *, int);
void smb_session_receiver(smb_session_t *);
void smb_session_disconnect(smb_session_t *);
-void smb_session_reconnection_check(smb_llist_t *, smb_session_t *);
void smb_session_timers(smb_llist_t *);
void smb_session_delete(smb_session_t *session);
void smb_session_cancel_requests(smb_session_t *, smb_tree_t *,
@@ -662,8 +660,6 @@ void smb_mbuf_trim(struct mbuf *mhead, int nbytes);
void smb_check_status(void);
int smb_handle_write_raw(smb_session_t *session, smb_request_t *sr);
-void smb_reconnection_check(smb_session_t *);
-
int32_t smb_time_gmt_to_local(smb_request_t *, int32_t);
int32_t smb_time_local_to_gmt(smb_request_t *, int32_t);
int32_t smb_time_dos_to_unix(int16_t, int16_t);
diff --git a/usr/src/uts/common/sys/fs/zfs.h b/usr/src/uts/common/sys/fs/zfs.h
index d5b7899feb..baa201d7a5 100644
--- a/usr/src/uts/common/sys/fs/zfs.h
+++ b/usr/src/uts/common/sys/fs/zfs.h
@@ -22,6 +22,7 @@
/*
* Copyright (c) 2005, 2010, Oracle and/or its affiliates. All rights reserved.
* Copyright (c) 2011 by Delphix. All rights reserved.
+ * Copyright 2011 Nexenta Systems, Inc. All rights reserved.
*/
/* Portions Copyright 2010 Robert Milkowski */
@@ -124,6 +125,8 @@ typedef enum {
ZFS_PROP_MLSLABEL,
ZFS_PROP_SYNC,
ZFS_PROP_REFRATIO,
+ ZFS_PROP_WRITTEN,
+ ZFS_PROP_CLONES,
ZFS_NUM_PROPS
} zfs_prop_t;
@@ -163,9 +166,13 @@ typedef enum {
ZPOOL_PROP_FREE,
ZPOOL_PROP_ALLOCATED,
ZPOOL_PROP_READONLY,
+ ZPOOL_PROP_COMMENT,
ZPOOL_NUM_PROPS
} zpool_prop_t;
+/* Small enough to not hog a whole line of printout in zpool(1M). */
+#define ZPROP_MAX_COMMENT 32
+
#define ZPROP_CONT -2
#define ZPROP_INVAL -1
@@ -220,6 +227,7 @@ const char *zfs_prop_to_name(zfs_prop_t);
zfs_prop_t zfs_name_to_prop(const char *);
boolean_t zfs_prop_user(const char *);
boolean_t zfs_prop_userquota(const char *);
+boolean_t zfs_prop_written(const char *);
int zfs_prop_index_to_string(zfs_prop_t, uint64_t, const char **);
int zfs_prop_string_to_index(zfs_prop_t, const char *, uint64_t *);
uint64_t zfs_prop_random_value(zfs_prop_t, uint64_t seed);
@@ -490,6 +498,7 @@ typedef struct zpool_rewind_policy {
#define ZPOOL_CONFIG_SPLIT_LIST "guid_list"
#define ZPOOL_CONFIG_REMOVING "removing"
#define ZPOOL_CONFIG_RESILVERING "resilvering"
+#define ZPOOL_CONFIG_COMMENT "comment"
#define ZPOOL_CONFIG_SUSPENDED "suspended" /* not stored on disk */
#define ZPOOL_CONFIG_TIMESTAMP "timestamp" /* not stored on disk */
#define ZPOOL_CONFIG_BOOTFS "bootfs" /* not stored on disk */
@@ -754,7 +763,6 @@ typedef enum zfs_ioc {
ZFS_IOC_ERROR_LOG,
ZFS_IOC_CLEAR,
ZFS_IOC_PROMOTE,
- ZFS_IOC_DESTROY_SNAPS,
ZFS_IOC_SNAPSHOT,
ZFS_IOC_DSOBJ_TO_DSNAME,
ZFS_IOC_OBJ_TO_PATH,
@@ -776,7 +784,11 @@ typedef enum zfs_ioc {
ZFS_IOC_NEXT_OBJ,
ZFS_IOC_DIFF,
ZFS_IOC_TMP_SNAPSHOT,
- ZFS_IOC_OBJ_TO_STATS
+ ZFS_IOC_OBJ_TO_STATS,
+ ZFS_IOC_SPACE_WRITTEN,
+ ZFS_IOC_SPACE_SNAPS,
+ ZFS_IOC_DESTROY_SNAPS_NVL,
+ ZFS_IOC_POOL_REGUID
} zfs_ioc_t;
/*
@@ -839,6 +851,7 @@ typedef enum {
* ESC_ZFS_RESILVER_START
* ESC_ZFS_RESILVER_END
* ESC_ZFS_POOL_DESTROY
+ * ESC_ZFS_POOL_REGUID
*
* ZFS_EV_POOL_NAME DATA_TYPE_STRING
* ZFS_EV_POOL_GUID DATA_TYPE_UINT64
diff --git a/usr/src/uts/common/sys/sysevent/eventdefs.h b/usr/src/uts/common/sys/sysevent/eventdefs.h
index 3ed9bb2980..5a75c5d844 100644
--- a/usr/src/uts/common/sys/sysevent/eventdefs.h
+++ b/usr/src/uts/common/sys/sysevent/eventdefs.h
@@ -20,6 +20,7 @@
*/
/*
* Copyright (c) 2005, 2010, Oracle and/or its affiliates. All rights reserved.
+ * Copyright 2011 Nexenta Systems, Inc. All rights reserved.
*/
#ifndef _SYS_SYSEVENT_EVENTDEFS_H
@@ -256,6 +257,7 @@ extern "C" {
#define ESC_ZFS_SCRUB_FINISH "ESC_ZFS_scrub_finish"
#define ESC_ZFS_VDEV_SPARE "ESC_ZFS_vdev_spare"
#define ESC_ZFS_BOOTFS_VDEV_ATTACH "ESC_ZFS_bootfs_vdev_attach"
+#define ESC_ZFS_POOL_REGUID "ESC_ZFS_pool_reguid"
/*
* datalink subclass definitions.