MFC@r248830

Approved by:	ed (project owner)
This commit is contained in:
ray 2013-03-28 20:27:01 +00:00
commit 3625eb7f3d
2417 changed files with 208474 additions and 220087 deletions

View File

@ -30,7 +30,8 @@ contrib/openbsm rwatson Pre-commit review requested.
sys/security/audit rwatson Pre-commit review requested.
ahc(4) gibbs Pre-commit review requested.
ahd(4) gibbs Pre-commit review requested.
NEWCARD imp Pre-commit review requested.
PC Card imp Pre-commit review requested.
CardBus imp Pre-commit review requested.
pci bus imp,jhb Pre-commit review requested.
cdboot jhb Pre-commit review requested.
pxeboot jhb Pre-commit review requested.
@ -124,3 +125,6 @@ isci(4) jimharris Pre-commit review requested.
cmx daniel@roe.ch Pre-commit review preferred.
filemon obrien Pre-commit review preferred.
sysdoc trhodes Pre-commit review preferred.
sh(1) jilles Pre-commit review requested. This also applies
to kill(1), printf(1) and test(1) which are
compiled in as builtins.

View File

@ -1132,7 +1132,8 @@ _lex= usr.bin/lex
.endif
.if ${BOOTSTRAPPING} < 1000013
_yacc= usr.bin/yacc
_yacc= lib/liby \
usr.bin/yacc
.endif
.if ${BOOTSTRAPPING} < 1000026
@ -1388,6 +1389,7 @@ _prebuild_libs= ${_kerberos5_lib_libasn1} \
lib/libopie lib/libpam ${_lib_libthr} \
lib/libradius lib/libsbuf lib/libtacplus \
${_cddl_lib_libumem} ${_cddl_lib_libnvpair} \
${_cddl_lib_libzfs_core} \
lib/libutil ${_lib_libypclnt} lib/libz lib/msun \
${_secure_lib_libcrypto} ${_secure_lib_libssh} \
${_secure_lib_libssl}
@ -1416,7 +1418,9 @@ lib/libopie__L lib/libtacplus__L: lib/libmd__L
.if ${MK_CDDL} != "no"
_cddl_lib_libumem= cddl/lib/libumem
_cddl_lib_libnvpair= cddl/lib/libnvpair
_cddl_lib_libzfs_core= cddl/lib/libzfs_core
_cddl_lib= cddl/lib
cddl/lib/libzfs_core__L: cddl/lib/libnvpair__L
.endif
.if ${MK_CRYPT} != "no"
@ -1815,6 +1819,6 @@ _xi-links:
../../../../usr/bin/${XDDIR}${OSREL}-$$i; \
done
.else
xdev xdev-buil xdev-install:
xdev xdev-build xdev-install:
@echo "*** Error: Both XDEV and XDEV_ARCH must be defined for \"${.TARGET}\" target"
.endif

View File

@ -38,6 +38,85 @@
# xargs -n1 | sort | uniq -d;
# done
# 20130316: vinum.4 removed
OLD_FILES+=usr/share/man/man4/vinum.4.gz
# 20130312: fortunes-o removed
OLD_FILES+=usr/share/games/fortune/fortunes-o
OLD_FILES+=usr/share/games/fortune/fortunes-o.dat
# 20130311: Ports are no more available via cvsup
OLD_FILES+=usr/share/examples/cvsup/ports-supfile
OLD_FILES+=usr/share/examples/cvsup/refuse
OLD_FILES+=usr/share/examples/cvsup/refuse.README
# 20130309: NWFS and NCP supports removed
OLD_FILES+=usr/bin/ncplist
OLD_FILES+=usr/bin/ncplogin
OLD_FILES+=usr/bin/ncplogout
OLD_FILES+=usr/include/fs/nwfs/nwfs.h
OLD_FILES+=usr/include/fs/nwfs/nwfs_mount.h
OLD_FILES+=usr/include/fs/nwfs/nwfs_node.h
OLD_FILES+=usr/include/fs/nwfs/nwfs_subr.h
OLD_DIRS+=usr/include/fs/nwfs
OLD_FILES+=usr/include/netncp/ncp.h
OLD_FILES+=usr/include/netncp/ncp_cfg.h
OLD_FILES+=usr/include/netncp/ncp_conn.h
OLD_FILES+=usr/include/netncp/ncp_file.h
OLD_FILES+=usr/include/netncp/ncp_lib.h
OLD_FILES+=usr/include/netncp/ncp_ncp.h
OLD_FILES+=usr/include/netncp/ncp_nls.h
OLD_FILES+=usr/include/netncp/ncp_rcfile.h
OLD_FILES+=usr/include/netncp/ncp_rq.h
OLD_FILES+=usr/include/netncp/ncp_sock.h
OLD_FILES+=usr/include/netncp/ncp_subr.h
OLD_FILES+=usr/include/netncp/ncp_user.h
OLD_FILES+=usr/include/netncp/ncpio.h
OLD_FILES+=usr/include/netncp/nwerror.h
OLD_DIRS+=usr/include/netncp
OLD_FILES+=usr/lib/libncp.a
OLD_FILES+=usr/lib/libncp.so
OLD_LIBS+=usr/lib/libncp.so.4
OLD_FILES+=usr/lib/libncp_p.a
OLD_FILES+=usr/lib32/libncp.a
OLD_FILES+=usr/lib32/libncp.so
OLD_LIBS+=usr/lib32/libncp.so.4
OLD_FILES+=usr/lib32/libncp_p.a
OLD_FILES+=usr/sbin/mount_nwfs
OLD_FILES+=usr/share/examples/nwclient/dot.nwfsrc
OLD_FILES+=usr/share/examples/nwclient/nwfs.sh.sample
OLD_DIRS+=usr/share/examples/nwclient
OLD_FILES+=usr/share/man/man1/ncplist.1.gz
OLD_FILES+=usr/share/man/man1/ncplogin.1.gz
OLD_FILES+=usr/share/man/man1/ncplogout.1.gz
OLD_FILES+=usr/share/man/man8/mount_nwfs.8.gz
# 20130302: NTFS support removed
OLD_FILES+=rescue/mount_ntfs
OLD_FILES+=sbin/mount_ntfs
OLD_FILES+=usr/include/fs/ntfs/ntfs.h
OLD_FILES+=usr/include/fs/ntfs/ntfs_compr.h
OLD_FILES+=usr/include/fs/ntfs/ntfs_ihash.h
OLD_FILES+=usr/include/fs/ntfs/ntfs_inode.h
OLD_FILES+=usr/include/fs/ntfs/ntfs_subr.h
OLD_FILES+=usr/include/fs/ntfs/ntfs_vfsops.h
OLD_FILES+=usr/include/fs/ntfs/ntfsmount.h
OLD_DIRS+=usr/include/fs/ntfs
OLD_FILES+=usr/share/man/man8/mount_ntfs.8.gz
# 20130302: PORTALFS support removed
OLD_FILES+=usr/include/fs/portalfs/portal.h
OLD_DIRS+=usr/include/fs/portalfs
OLD_FILES+=usr/sbin/mount_portalfs
OLD_FILES+=usr/share/examples/portal/README
OLD_FILES+=usr/share/examples/portal/portal.conf
OLD_DIRS+=usr/share/examples/portal
OLD_FILES+=usr/share/man/man8/mount_portalfs.8.gz
# 20130302: CODAFS support removed
OLD_FILES+=usr/share/man/man4/coda.4.gz
# 20130302: XFS support removed
OLD_FILES+=usr/share/man/man5/xfs.5.gz
# 20130302: Capsicum overhaul
OLD_FILES+=usr/share/man/man2/cap_getrights.2.gz
OLD_FILES+=usr/share/man/man2/cap_new.2.gz
# 20130213: OpenSSL 1.0.1e import
OLD_FILES+=usr/share/openssl/man/man3/EVP_PKEY_verifyrecover.3.gz
OLD_FILES+=usr/share/openssl/man/man3/EVP_PKEY_verifyrecover_init.3.gz
# 20130116: removed long unused directories for .1aout section manpages
OLD_FILES+=usr/share/man/en.ISO8859-1/man1aout
OLD_FILES+=usr/share/man/en.UTF-8/man1aout
@ -58,9 +137,10 @@ OLD_DIRS+=var/remote
# 20121114: zpool-features manual page moved from section 5 to 7
OLD_FILES+=usr/share/man/man5/zpool-features.5.gz
# 20121022: remove harp, hfa and idt man page
OLD_FILES+=share/man/man4/harp.4
OLD_FILES+=share/man/man4/hfa.4
OLD_FILES+=share/man/man4/idt.4
OLD_FILES+=usr/share/man/man4/harp.4.gz
OLD_FILES+=usr/share/man/man4/hfa.4.gz
OLD_FILES+=usr/share/man/man4/idt.4.gz
OLD_FILES+=usr/share/man/man4/if_idt.4.gz
# 20121022: VFS_LOCK_GIANT elimination
OLD_FILES+=usr/share/man/man9/VFS_LOCK_GIANT.9.gz
OLD_FILES+=usr/share/man/man9/VFS_UNLOCK_GIANT.9.gz

View File

@ -26,6 +26,37 @@ NOTE TO PEOPLE WHO THINK THAT FreeBSD 10.x IS SLOW:
disable the most expensive debugging functionality run
"ln -s 'abort:false,junk:false' /etc/malloc.conf".)
20130308:
CTL_DISABLE has also been added to the sparc64 GENERIC (for further
information, see the respective 20130304 entry).
20130304:
Recent commits to callout(9) changed the size of struct callout,
so the KBI is probably heavily disturbed. Also, some functions
in callout(9)/sleep(9)/sleepqueue(9)/condvar(9) KPIs were replaced
by macros. Every kernel module using it won't load, so rebuild
is requested.
The ctl device has been re-enabled in GENERIC for i386 and amd64,
but does not initialize by default (because of the new CTL_DISABLE
option) to save memory. To re-enable it, remove the CTL_DISABLE
option from the kernel config file or set kern.cam.ctl.disable=0
in /boot/loader.conf.
20130301:
The ctl device has been disabled in GENERIC for i386 and amd64.
This was done due to the extra memory being allocated at system
initialisation time by the ctl driver which was only used if
a CAM target device was created. This makes a FreeBSD system
unusable on 128MB or less of RAM.
20130208:
A new compression method (lz4) has been merged to -HEAD. Please
refer to zpool-features(7) for more information.
Please refer to the "ZFS notes" section of this file for information
on upgrading boot ZFS pools.
20130129:
A BSD-licensed patch(1) variant has been added and is installed
as bsdpatch, being the GNU version the default patch.
@ -39,8 +70,8 @@ NOTE TO PEOPLE WHO THINK THAT FreeBSD 10.x IS SLOW:
unlikely event that -M was the last option on the command line
and the command line contained at least two files and a target
directory the first file will have logs appended to it. The -M
option served little practical purpose in the last decade so it's
used expected to be extremely rare.
option served little practical purpose in the last decade so its
use is expected to be extremely rare.
20121223:
After switching to Clang as the default compiler some users of ZFS

View File

@ -117,11 +117,7 @@ main(int argc, char *argv[])
} else
fts_options = hflag ? FTS_PHYSICAL : FTS_LOGICAL;
/* XXX: Why don't chflags and lchflags have compatible prototypes? */
if (hflag)
change_flags = (int (*)(const char *, unsigned long))lchflags;
else
change_flags = chflags;
change_flags = hflag ? lchflags : chflags;
flags = *argv;
if (*flags >= '0' && *flags <= '7') {

View File

@ -32,7 +32,7 @@
.\" @(#)cp.1 8.3 (Berkeley) 4/18/94
.\" $FreeBSD$
.\"
.Dd September 4, 2012
.Dd March 15, 2013
.Dt CP 1
.Os
.Sh NAME
@ -251,6 +251,27 @@ signal, the current input and output file and the percentage complete
will be written to the standard output.
.Sh EXIT STATUS
.Ex -std
.Sh EXAMPLES
Make a copy of file
.Pa foo
named
.Pa bar :
.Pp
.Dl $ cp foo bar
.Pp
Copy a group of files to the
.Pa /tmp
directory:
.Pp
.Dl $ cp *.txt /tmp
.Pp
Copy the directory
.Pa junk
and all of its contents (including any subdirectories) to the
.Pa /tmp
directory:
.Pp
.Dl $ cp -R junk /tmp
.Sh COMPATIBILITY
Historic versions of the
.Nm

View File

@ -71,7 +71,6 @@ __FBSDID("$FreeBSD$");
#ifdef DES
static DES_cblock ivec; /* initialization vector */
static DES_cblock pvec; /* padding vector */
#endif
static char bits[] = { /* used to extract bits from a char */
'\200', '\100', '\040', '\020', '\010', '\004', '\002', '\001'
@ -79,13 +78,12 @@ static char bits[] = { /* used to extract bits from a char */
static int pflag; /* 1 to preserve parity bits */
#ifdef DES
static DES_key_schedule schedule; /* expanded DES key */
#endif
static unsigned char des_buf[8];/* shared buffer for get_des_char/put_des_char */
static int des_ct = 0; /* count for get_des_char/put_des_char */
static int des_n = 0; /* index for put_des_char/get_des_char */
#endif
/* init_des_cipher: initialize DES */
void

View File

@ -32,7 +32,7 @@
.\" @(#)ls.1 8.7 (Berkeley) 7/29/94
.\" $FreeBSD$
.\"
.Dd November 8, 2012
.Dd March 15, 2013
.Dt LS 1
.Os
.Sh NAME
@ -718,6 +718,24 @@ for more information.
.El
.Sh EXIT STATUS
.Ex -std
.Sh EXAMPLES
List the contents of the current working directory in long format:
.Pp
.Dl $ ls -l
.Pp
In addition to listing the contents of the current working directory in
long format, show inode numbers, file flags (see
.Xr chflags 1 ) ,
and suffix each filename with a symbol representing its file type:
.Pp
.Dl $ ls -lioF
.Pp
List the files in
.Pa /var/log ,
sorting the output such that the mostly recently modified entries are
printed first:
.Pp
.Dl $ ls -lt /var/log
.Sh COMPATIBILITY
The group field is now automatically included in the long listing for
files in order to be compatible with the

View File

@ -32,7 +32,7 @@
.\" @(#)mkdir.1 8.2 (Berkeley) 1/25/94
.\" $FreeBSD$
.\"
.Dd January 25, 1994
.Dd March 15, 2013
.Dt MKDIR 1
.Os
.Sh NAME
@ -87,6 +87,23 @@ Be verbose when creating directories, listing them as they are created.
The user must have write permission in the parent directory.
.Sh EXIT STATUS
.Ex -std
.Sh EXAMPLES
Create a directory named
.Pa foobar :
.Pp
.Dl $ mkdir foobar
.Pp
Create a directory named
.Pa foobar
and set its file mode to 700:
.Pp
.Dl $ mkdir -m 700 foobar
.Pp
Create a directory named
.Pa cow/horse/monkey ,
creating any non-existent intermediate directories as necessary:
.Pp
.Dl $ mkdir -p cow/horse/monkey
.Sh COMPATIBILITY
The
.Fl v

View File

@ -32,7 +32,7 @@
.\" @(#)mv.1 8.1 (Berkeley) 5/31/93
.\" $FreeBSD$
.\"
.Dd August 28, 2012
.Dd March 15, 2013
.Dt MV 1
.Os
.Sh NAME
@ -155,6 +155,16 @@ rm -rf source_file
.Ed
.Sh EXIT STATUS
.Ex -std
.Sh EXAMPLES
Rename file
.Pa foo
to
.Pa bar ,
overwriting
.Pa bar
if it already exists:
.Pp
.Dl $ mv -f foo bar
.Sh COMPATIBILITY
The
.Fl h ,

View File

@ -337,7 +337,7 @@ err: if (unlink(to))
* on a file that we copied, i.e., that we didn't create.)
*/
errno = 0;
if (fchflags(to_fd, (u_long)sbp->st_flags))
if (fchflags(to_fd, sbp->st_flags))
if (errno != EOPNOTSUPP || sbp->st_flags != 0)
warn("%s: set flags (was: 0%07o)", to, sbp->st_flags);

View File

@ -29,7 +29,7 @@
.\" @(#)ps.1 8.3 (Berkeley) 4/18/94
.\" $FreeBSD$
.\"
.Dd February 7, 2013
.Dd March 15, 2013
.Dt PS 1
.Os
.Sh NAME
@ -689,6 +689,10 @@ attempts to automatically determine the terminal width.
.It Pa /boot/kernel/kernel
default system namelist
.El
.Sh EXAMPLES
Display information on all system processes:
.Pp
.Dl $ ps -auxw
.Sh SEE ALSO
.Xr kill 1 ,
.Xr pgrep 1 ,

View File

@ -32,7 +32,7 @@
.\" @(#)rm.1 8.5 (Berkeley) 12/5/94
.\" $FreeBSD$
.\"
.Dd October 31, 2010
.Dd March 15, 2013
.Dt RM 1
.Os
.Sh NAME
@ -193,6 +193,19 @@ When
is specified with
.Fl f
the file will be overwritten and removed even if it has hard links.
.Sh EXAMPLES
Recursively remove all files contained within the
.Pa foobar
directory hierarchy:
.Pp
.Dl $ rm -rf foobar
.Pp
Either of these commands will remove the file
.Pa -f :
.Bd -literal -offset indent
$ rm -- -f
$ rm ./-f
.Ed
.Sh COMPATIBILITY
The
.Nm

View File

@ -32,7 +32,7 @@
.\" @(#)rmdir.1 8.1 (Berkeley) 5/31/93
.\" $FreeBSD$
.\"
.Dd March 21, 2004
.Dd March 15, 2013
.Dt RMDIR 1
.Os
.Sh NAME
@ -86,6 +86,18 @@ successfully.
.It Li >0
An error occurred.
.El
.Sh EXAMPLES
Remove the directory
.Pa foobar ,
if it is empty:
.Pp
.Dl $ rmdir foobar
.Pp
Remove all directories up to and including
.Pa cow ,
stopping at the first non-empty directory (if any):
.Pp
.Dl $ rmdir -p cow/horse/monkey
.Sh SEE ALSO
.Xr rm 1
.Sh STANDARDS

View File

@ -301,7 +301,7 @@ evaltree(union node *n, int flags)
} while (n != NULL);
out:
popstackmark(&smark);
if (pendingsigs)
if (pendingsig)
dotrap();
if (eflag && exitstatus != 0 && do_etest)
exitshell(exitstatus);

View File

@ -458,14 +458,15 @@ freejob(struct job *jp)
int
waitcmd(int argc, char **argv)
waitcmd(int argc __unused, char **argv __unused)
{
struct job *job;
int status, retval;
struct job *jp;
if (argc > 1) {
job = getjob(argv[1]);
nextopt("");
if (*argptr != NULL) {
job = getjob(*argptr);
} else {
job = NULL;
}
@ -521,7 +522,7 @@ waitcmd(int argc, char **argv)
} while (dowait(DOWAIT_BLOCK | DOWAIT_SIG, (struct job *)NULL) != -1);
in_waitcmd--;
return 0;
return pendingsig + 128;
}

View File

@ -196,7 +196,7 @@ cmdloop(int top)
TRACE(("cmdloop(%d) called\n", top));
setstackmark(&smark);
for (;;) {
if (pendingsigs)
if (pendingsig)
dotrap();
inter = 0;
if (iflag && top) {

View File

@ -32,7 +32,7 @@
.\" from: @(#)sh.1 8.6 (Berkeley) 5/4/95
.\" $FreeBSD$
.\"
.Dd January 22, 2013
.Dd March 24, 2013
.Dt SH 1
.Os
.Sh NAME
@ -1061,6 +1061,9 @@ A subshell environment may be implemented as a child process or differently.
If job control is enabled in an interactive shell,
commands grouped in parentheses can be suspended and continued as a unit.
.Pp
For compatibility with other shells,
two open parentheses in sequence should be separated by whitespace.
.Pp
The second form never forks another shell,
so it is slightly more efficient.
Grouping commands together this way allows the user to
@ -1618,6 +1621,16 @@ and
.Ic times
returns information about the same process
if they are the only command in a command substitution.
.Pp
If a command substitution of the
.Li $(
form begins with a subshell,
the
.Li $(
and
.Li (
must be separated by whitespace
to avoid ambiguity with arithmetic expansion.
.Ss Arithmetic Expansion
Arithmetic expansion provides a mechanism for evaluating an arithmetic
expression and substituting its value.

View File

@ -73,7 +73,7 @@ __FBSDID("$FreeBSD$");
MKINIT char sigmode[NSIG]; /* current value of signal */
int pendingsigs; /* indicates some signal received */
volatile sig_atomic_t pendingsig; /* indicates some signal received */
int in_dotrap; /* do we execute in a trap handler? */
static char *volatile trap[NSIG]; /* trap handler commands */
static volatile sig_atomic_t gotsig[NSIG];
@ -388,22 +388,25 @@ onsig(int signo)
return;
}
if (signo != SIGCHLD || !ignore_sigchld)
gotsig[signo] = 1;
pendingsigs++;
/* If we are currently in a wait builtin, prepare to break it */
if ((signo == SIGINT || signo == SIGQUIT) && in_waitcmd != 0)
breakwaitcmd = 1;
/*
* If a trap is set, not ignored and not the null command, we need
* to make sure traps are executed even when a child blocks signals.
*/
if (Tflag &&
trap[signo] != NULL &&
! (trap[signo][0] == '\0') &&
! (trap[signo][0] == ':' && trap[signo][1] == '\0'))
if ((signo == SIGINT || signo == SIGQUIT) && in_waitcmd != 0) {
breakwaitcmd = 1;
pendingsig = signo;
}
if (trap[signo] != NULL && trap[signo][0] != '\0' &&
(signo != SIGCHLD || !ignore_sigchld)) {
gotsig[signo] = 1;
pendingsig = signo;
/*
* If a trap is set, not ignored and not the null command, we
* need to make sure traps are executed even when a child
* blocks signals.
*/
if (Tflag && !(trap[signo][0] == ':' && trap[signo][1] == '\0'))
breakwaitcmd = 1;
}
#ifndef NO_HISTORY
if (signo == SIGWINCH)
@ -424,7 +427,7 @@ dotrap(void)
in_dotrap++;
for (;;) {
pendingsigs = 0;
pendingsig = 0;
for (i = 1; i < NSIG; i++) {
if (gotsig[i]) {
gotsig[i] = 0;
@ -452,7 +455,6 @@ dotrap(void)
last_trapsig = i;
savestatus = exitstatus;
evalstring(trap[i], 0);
exitstatus = savestatus;
/*
* If such a command was not
@ -461,9 +463,11 @@ dotrap(void)
* trap action to have an effect
* outside of it.
*/
if (prev_evalskip != 0) {
if (evalskip == 0 ||
prev_evalskip != 0) {
evalskip = prev_evalskip;
skipcount = prev_skipcount;
exitstatus = savestatus;
}
if (i == SIGCHLD)

View File

@ -33,7 +33,7 @@
* $FreeBSD$
*/
extern int pendingsigs;
extern volatile sig_atomic_t pendingsig;
extern int in_dotrap;
extern volatile sig_atomic_t gotwinch;

View File

@ -169,15 +169,65 @@ True if
.Ar file
exists and is a socket.
.It Ar file1 Fl nt Ar file2
True if
True if both
.Ar file1
exists and is newer than
and
.Ar file2
exist and
.Ar file1
is newer than
.Ar file2 .
.It Ar file1 Fl nt Ns Ar X Ns Ar Y Ar file2
True if both
.Ar file1
and
.Ar file2
exist and
.Ar file1
has a more recent last access time
.Pq Ar X Ns = Ns Cm a ,
inode creation time
.Pq Ar X Ns = Ns Cm b ,
change time
.Pq Ar X Ns = Ns Cm c ,
or modification time
.Pq Ar X Ns = Ns Cm m
than the last access time
.Pq Ar Y Ns = Ns Cm a ,
inode creation time
.Pq Ar Y Ns = Ns Cm b ,
change time
.Pq Ar Y Ns = Ns Cm c ,
or modification time
.Pq Ar Y Ns = Ns Cm m
of
.Ar file2 .
Note that
.Ic -ntmm
is equivalent to
.Ic -nt .
.It Ar file1 Fl ot Ar file2
True if
True if both
.Ar file1
exists and is older than
and
.Ar file2
exist and
.Ar file1
is older than
.Ar file2 .
Note that
.Ar file1
.Ic -ot
.Ar file2
is equivalent to
.Ar file2
.Ic -nt
.Ar file1
.It Ar file1 Fl ot Ns Ar X Ns Ar Y Ar file2
Equivalent to
.Ar file2
.Ic -nt Ns Ar Y Ns Ar X
.Ar file1 .
.It Ar file1 Fl ef Ar file2
True if
.Ar file1

View File

@ -63,7 +63,7 @@ error(const char *msg, ...)
"-u"|"-g"|"-k"|"-s"|"-t"|"-z"|"-n"|"-o"|"-O"|"-G"|"-L"|"-S";
binary-operator ::= "="|"!="|"-eq"|"-ne"|"-ge"|"-gt"|"-le"|"-lt"|
"-nt"|"-ot"|"-ef";
"-nt"|"-nt[abcm][abcm]"|"-ot"|"-ot[abcm][abcm])"|"-ef";
operand ::= <any legal UNIX file name>
*/
@ -85,8 +85,38 @@ enum token {
FILSUID,
FILSGID,
FILSTCK,
FILNT,
FILOT,
FILNTAA,
FILNTAB,
FILNTAC,
FILNTAM,
FILNTBA,
FILNTBB,
FILNTBC,
FILNTBM,
FILNTCA,
FILNTCB,
FILNTCC,
FILNTCM,
FILNTMA,
FILNTMB,
FILNTMC,
FILNTMM,
FILOTAA,
FILOTAB,
FILOTAC,
FILOTAM,
FILOTBA,
FILOTBB,
FILOTBC,
FILOTBM,
FILOTCA,
FILOTCB,
FILOTCC,
FILOTCM,
FILOTMA,
FILOTMB,
FILOTMC,
FILOTMM,
FILEQ,
FILUID,
FILGID,
@ -118,9 +148,16 @@ enum token_types {
PAREN
};
enum time_types {
ATIME,
BTIME,
CTIME,
MTIME
};
static struct t_op {
char op_text[4];
short op_num, op_type;
char op_text[6];
char op_num, op_type;
} const ops [] = {
{"-r", FILRD, UNOP},
{"-w", FILWR, UNOP},
@ -154,8 +191,40 @@ static struct t_op {
{"-gt", INTGT, BINOP},
{"-le", INTLE, BINOP},
{"-lt", INTLT, BINOP},
{"-nt", FILNT, BINOP},
{"-ot", FILOT, BINOP},
{"-nt", FILNTMM, BINOP},
{"-ntaa", FILNTAA, BINOP},
{"-ntab", FILNTAB, BINOP},
{"-ntac", FILNTAC, BINOP},
{"-ntam", FILNTAM, BINOP},
{"-ntba", FILNTBA, BINOP},
{"-ntbb", FILNTBB, BINOP},
{"-ntbc", FILNTBC, BINOP},
{"-ntbm", FILNTBM, BINOP},
{"-ntca", FILNTCA, BINOP},
{"-ntcb", FILNTCB, BINOP},
{"-ntcc", FILNTCC, BINOP},
{"-ntcm", FILNTCM, BINOP},
{"-ntma", FILNTMA, BINOP},
{"-ntmb", FILNTMB, BINOP},
{"-ntmc", FILNTMC, BINOP},
{"-ntmm", FILNTMM, BINOP},
{"-ot", FILOTMM, BINOP},
{"-otaa", FILOTAA, BINOP},
{"-otab", FILOTBB, BINOP},
{"-otac", FILOTAC, BINOP},
{"-otam", FILOTAM, BINOP},
{"-otba", FILOTBA, BINOP},
{"-otbb", FILOTBB, BINOP},
{"-otbc", FILOTBC, BINOP},
{"-otbm", FILOTBM, BINOP},
{"-otca", FILOTCA, BINOP},
{"-otcb", FILOTCB, BINOP},
{"-otcc", FILOTCC, BINOP},
{"-otcm", FILOTCM, BINOP},
{"-otma", FILOTMA, BINOP},
{"-otmb", FILOTMB, BINOP},
{"-otmc", FILOTMC, BINOP},
{"-otmm", FILOTMM, BINOP},
{"-ef", FILEQ, BINOP},
{"!", UNOT, BUNOP},
{"-a", BAND, BBINOP},
@ -180,10 +249,10 @@ static int intcmp(const char *, const char *);
static int isunopoperand(void);
static int islparenoperand(void);
static int isrparenoperand(void);
static int newerf(const char *, const char *);
static int newerf(const char *, const char *, enum time_types,
enum time_types);
static int nexpr(enum token);
static int oexpr(enum token);
static int olderf(const char *, const char *);
static int primary(enum token);
static void syntax(const char *, const char *);
static enum token t_lex(char *);
@ -353,10 +422,70 @@ binop(void)
return intcmp(opnd1, opnd2) <= 0;
case INTLT:
return intcmp(opnd1, opnd2) < 0;
case FILNT:
return newerf (opnd1, opnd2);
case FILOT:
return olderf (opnd1, opnd2);
case FILNTAA:
return newerf(opnd1, opnd2, ATIME, ATIME);
case FILNTAB:
return newerf(opnd1, opnd2, ATIME, BTIME);
case FILNTAC:
return newerf(opnd1, opnd2, ATIME, CTIME);
case FILNTAM:
return newerf(opnd1, opnd2, ATIME, MTIME);
case FILNTBA:
return newerf(opnd1, opnd2, BTIME, ATIME);
case FILNTBB:
return newerf(opnd1, opnd2, BTIME, BTIME);
case FILNTBC:
return newerf(opnd1, opnd2, BTIME, CTIME);
case FILNTBM:
return newerf(opnd1, opnd2, BTIME, MTIME);
case FILNTCA:
return newerf(opnd1, opnd2, CTIME, ATIME);
case FILNTCB:
return newerf(opnd1, opnd2, CTIME, BTIME);
case FILNTCC:
return newerf(opnd1, opnd2, CTIME, CTIME);
case FILNTCM:
return newerf(opnd1, opnd2, CTIME, MTIME);
case FILNTMA:
return newerf(opnd1, opnd2, MTIME, ATIME);
case FILNTMB:
return newerf(opnd1, opnd2, MTIME, BTIME);
case FILNTMC:
return newerf(opnd1, opnd2, MTIME, CTIME);
case FILNTMM:
return newerf(opnd1, opnd2, MTIME, MTIME);
case FILOTAA:
return newerf(opnd2, opnd1, ATIME, ATIME);
case FILOTAB:
return newerf(opnd2, opnd1, BTIME, ATIME);
case FILOTAC:
return newerf(opnd2, opnd1, CTIME, ATIME);
case FILOTAM:
return newerf(opnd2, opnd1, MTIME, ATIME);
case FILOTBA:
return newerf(opnd2, opnd1, ATIME, BTIME);
case FILOTBB:
return newerf(opnd2, opnd1, BTIME, BTIME);
case FILOTBC:
return newerf(opnd2, opnd1, CTIME, BTIME);
case FILOTBM:
return newerf(opnd2, opnd1, MTIME, BTIME);
case FILOTCA:
return newerf(opnd2, opnd1, ATIME, CTIME);
case FILOTCB:
return newerf(opnd2, opnd1, BTIME, CTIME);
case FILOTCC:
return newerf(opnd2, opnd1, CTIME, CTIME);
case FILOTCM:
return newerf(opnd2, opnd1, MTIME, CTIME);
case FILOTMA:
return newerf(opnd2, opnd1, ATIME, MTIME);
case FILOTMB:
return newerf(opnd2, opnd1, BTIME, MTIME);
case FILOTMC:
return newerf(opnd2, opnd1, CTIME, MTIME);
case FILOTMM:
return newerf(opnd2, opnd1, MTIME, MTIME);
case FILEQ:
return equalf (opnd1, opnd2);
default:
@ -570,25 +699,34 @@ intcmp (const char *s1, const char *s2)
}
static int
newerf (const char *f1, const char *f2)
newerf (const char *f1, const char *f2, enum time_types t1, enum time_types t2)
{
struct stat b1, b2;
struct timespec *ts1, *ts2;
if (stat(f1, &b1) != 0 || stat(f2, &b2) != 0)
return 0;
if (b1.st_mtim.tv_sec > b2.st_mtim.tv_sec)
switch (t1) {
case ATIME: ts1 = &b1.st_atim; break;
case BTIME: ts1 = &b1.st_birthtim; break;
case CTIME: ts1 = &b1.st_ctim; break;
default: ts1 = &b1.st_mtim; break;
}
switch (t2) {
case ATIME: ts2 = &b2.st_atim; break;
case BTIME: ts2 = &b2.st_birthtim; break;
case CTIME: ts2 = &b2.st_ctim; break;
default: ts2 = &b2.st_mtim; break;
}
if (ts1->tv_sec > ts2->tv_sec)
return 1;
if (b1.st_mtim.tv_sec < b2.st_mtim.tv_sec)
if (ts1->tv_sec < ts2->tv_sec)
return 0;
return (b1.st_mtim.tv_nsec > b2.st_mtim.tv_nsec);
}
static int
olderf (const char *f1, const char *f2)
{
return (newerf(f2, f1));
return (ts1->tv_nsec > ts2->tv_nsec);
}
static int

View File

@ -195,6 +195,13 @@ fatal(const char *fmt, ...)
verror(fmt, ap);
va_end(ap);
/*
* Close the DTrace handle to ensure that any controlled processes are
* correctly restored and continued.
*/
if (g_dtp)
dtrace_close(g_dtp);
exit(E_ERROR);
}

View File

@ -0,0 +1,30 @@
/*
* 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, Joyent, Inc. All rights reserved.
*/
BEGIN
{
trace(tolower(2152006));
exit(1);
}

View File

@ -0,0 +1,30 @@
/*
* 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, Joyent, Inc. All rights reserved.
*/
BEGIN
{
trace(toupper(timestamp));
exit(1);
}

View File

@ -0,0 +1,30 @@
/*
* 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, Joyent, Inc. All rights reserved.
*/
BEGIN
{
trace(tolower());
exit(1);
}

View File

@ -0,0 +1,30 @@
/*
* 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, Joyent, Inc. All rights reserved.
*/
BEGIN
{
trace(tolower("dory", "eel", "roughy"));
exit(1);
}

View File

@ -0,0 +1,30 @@
/*
* 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, Joyent, Inc. All rights reserved.
*/
BEGIN
{
trace(toupper());
exit(1);
}

View File

@ -0,0 +1,30 @@
/*
* 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, Joyent, Inc. All rights reserved.
*/
BEGIN
{
trace(tolower("haino", "tylo"));
exit(1);
}

View File

@ -0,0 +1,80 @@
/*
* 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, Joyent, Inc. All rights reserved.
*/
#pragma D option quiet
int64_t val[int];
BEGIN
{
base = -2;
i = 0;
val[i++] = -10;
val[i++] = -1;
val[i++] = 0;
val[i++] = 10;
val[i++] = 100;
val[i++] = 1000;
val[i++] = (1LL << 62);
maxval = i;
i = 0;
}
tick-1ms
/i < maxval/
{
printf("base %2d of %20d: ", base, val[i]);
}
tick-1ms
/i < maxval/
{
printf(" %s\n", lltostr(val[i], base));
}
ERROR
{
printf(" <error>\n");
}
tick-1ms
/i < maxval/
{
i++;
}
tick-1ms
/i == maxval/
{
i = 0;
base++;
}
tick-1ms
/base > 40/
{
exit(0);
}

View File

@ -0,0 +1,302 @@
base -2 of -10: <error>
base -2 of -1: <error>
base -2 of 0: <error>
base -2 of 10: <error>
base -2 of 100: <error>
base -2 of 1000: <error>
base -2 of 4611686018427387904: <error>
base -1 of -10: <error>
base -1 of -1: <error>
base -1 of 0: <error>
base -1 of 10: <error>
base -1 of 100: <error>
base -1 of 1000: <error>
base -1 of 4611686018427387904: <error>
base 0 of -10: <error>
base 0 of -1: <error>
base 0 of 0: <error>
base 0 of 10: <error>
base 0 of 100: <error>
base 0 of 1000: <error>
base 0 of 4611686018427387904: <error>
base 1 of -10: <error>
base 1 of -1: <error>
base 1 of 0: <error>
base 1 of 10: <error>
base 1 of 100: <error>
base 1 of 1000: <error>
base 1 of 4611686018427387904: <error>
base 2 of -10: 1111111111111111111111111111111111111111111111111111111111110110
base 2 of -1: 1111111111111111111111111111111111111111111111111111111111111111
base 2 of 0: 0
base 2 of 10: 1010
base 2 of 100: 1100100
base 2 of 1000: 1111101000
base 2 of 4611686018427387904: 100000000000000000000000000000000000000000000000000000000000000
base 3 of -10: 11112220022122120101211020120210210211120
base 3 of -1: 11112220022122120101211020120210210211220
base 3 of 0: 0
base 3 of 10: 101
base 3 of 100: 10201
base 3 of 1000: 1101001
base 3 of 4611686018427387904: 1010201120122220002201001122110012110111
base 4 of -10: 33333333333333333333333333333312
base 4 of -1: 33333333333333333333333333333333
base 4 of 0: 0
base 4 of 10: 22
base 4 of 100: 1210
base 4 of 1000: 33220
base 4 of 4611686018427387904: 10000000000000000000000000000000
base 5 of -10: 2214220303114400424121122411
base 5 of -1: 2214220303114400424121122430
base 5 of 0: 0
base 5 of 10: 20
base 5 of 100: 400
base 5 of 1000: 13000
base 5 of 4611686018427387904: 302141200402211214402403104
base 6 of -10: 3520522010102100444244410
base 6 of -1: 3520522010102100444244423
base 6 of 0: 0
base 6 of 10: 14
base 6 of 100: 244
base 6 of 1000: 4344
base 6 of 4611686018427387904: 550120301313313111041104
base 7 of -10: 45012021522523134134556
base 7 of -1: 45012021522523134134601
base 7 of 0: 0
base 7 of 10: 13
base 7 of 100: 202
base 7 of 1000: 2626
base 7 of 4611686018427387904: 11154003640456024361134
base 8 of -10: 01777777777777777777766
base 8 of -1: 01777777777777777777777
base 8 of 0: 0
base 8 of 10: 012
base 8 of 100: 0144
base 8 of 1000: 01750
base 8 of 4611686018427387904: 0400000000000000000000
base 9 of -10: 145808576354216723746
base 9 of -1: 145808576354216723756
base 9 of 0: 0
base 9 of 10: 11
base 9 of 100: 121
base 9 of 1000: 1331
base 9 of 4611686018427387904: 33646586081048405414
base 10 of -10: -10
base 10 of -1: -1
base 10 of 0: 0
base 10 of 10: 10
base 10 of 100: 100
base 10 of 1000: 1000
base 10 of 4611686018427387904: 4611686018427387904
base 11 of -10: 335500516a429071276
base 11 of -1: 335500516a429071284
base 11 of 0: 0
base 11 of 10: a
base 11 of 100: 91
base 11 of 1000: 82a
base 11 of 4611686018427387904: 9140013181078458a4
base 12 of -10: 839365134a2a240706
base 12 of -1: 839365134a2a240713
base 12 of 0: 0
base 12 of 10: a
base 12 of 100: 84
base 12 of 1000: 6b4
base 12 of 4611686018427387904: 20b3a733a268670194
base 13 of -10: 219505a9511a867b66
base 13 of -1: 219505a9511a867b72
base 13 of 0: 0
base 13 of 10: a
base 13 of 100: 79
base 13 of 1000: 5bc
base 13 of 4611686018427387904: 6c1349246a2881c84
base 14 of -10: 8681049adb03db166
base 14 of -1: 8681049adb03db171
base 14 of 0: 0
base 14 of 10: a
base 14 of 100: 72
base 14 of 1000: 516
base 14 of 4611686018427387904: 219038263637dd3c4
base 15 of -10: 2c1d56b648c6cd106
base 15 of -1: 2c1d56b648c6cd110
base 15 of 0: 0
base 15 of 10: a
base 15 of 100: 6a
base 15 of 1000: 46a
base 15 of 4611686018427387904: a7e8ce189a933404
base 16 of -10: 0xfffffffffffffff6
base 16 of -1: 0xffffffffffffffff
base 16 of 0: 0x0
base 16 of 10: 0xa
base 16 of 100: 0x64
base 16 of 1000: 0x3e8
base 16 of 4611686018427387904: 0x4000000000000000
base 17 of -10: 67979g60f5428008
base 17 of -1: 67979g60f5428010
base 17 of 0: 0
base 17 of 10: a
base 17 of 100: 5f
base 17 of 1000: 37e
base 17 of 4611686018427387904: 1a6a6ca03e10a88d
base 18 of -10: 2d3fgb0b9cg4bd26
base 18 of -1: 2d3fgb0b9cg4bd2f
base 18 of 0: 0
base 18 of 10: a
base 18 of 100: 5a
base 18 of 1000: 31a
base 18 of 4611686018427387904: c588bdbfgd12ge4
base 19 of -10: 141c8786h1ccaag7
base 19 of -1: 141c8786h1ccaagg
base 19 of 0: 0
base 19 of 10: a
base 19 of 100: 55
base 19 of 1000: 2ec
base 19 of 4611686018427387904: 5ecbb6fi9h7ggi9
base 20 of -10: b53bjh07be4dj06
base 20 of -1: b53bjh07be4dj0f
base 20 of 0: 0
base 20 of 10: a
base 20 of 100: 50
base 20 of 1000: 2a0
base 20 of 4611686018427387904: 2g5hjj51hib39f4
base 21 of -10: 5e8g4ggg7g56di6
base 21 of -1: 5e8g4ggg7g56dif
base 21 of 0: 0
base 21 of 10: a
base 21 of 100: 4g
base 21 of 1000: 25d
base 21 of 4611686018427387904: 18hjgjjjhebh8f4
base 22 of -10: 2l4lf104353j8k6
base 22 of -1: 2l4lf104353j8kf
base 22 of 0: 0
base 22 of 10: a
base 22 of 100: 4c
base 22 of 1000: 21a
base 22 of 4611686018427387904: g6g95gc0hha7g4
base 23 of -10: 1ddh88h2782i50j
base 23 of -1: 1ddh88h2782i515
base 23 of 0: 0
base 23 of 10: a
base 23 of 100: 48
base 23 of 1000: 1kb
base 23 of 4611686018427387904: 93a22467dc4chd
base 24 of -10: l12ee5fn0ji1i6
base 24 of -1: l12ee5fn0ji1if
base 24 of 0: 0
base 24 of 10: a
base 24 of 100: 44
base 24 of 1000: 1hg
base 24 of 4611686018427387904: 566ffd9ni4mcag
base 25 of -10: c9c336o0mlb7e6
base 25 of -1: c9c336o0mlb7ef
base 25 of 0: 0
base 25 of 10: a
base 25 of 100: 40
base 25 of 1000: 1f0
base 25 of 4611686018427387904: 32970kc6bo2kg4
base 26 of -10: 7b7n2pcniokcg6
base 26 of -1: 7b7n2pcniokcgf
base 26 of 0: 0
base 26 of 10: a
base 26 of 100: 3m
base 26 of 1000: 1cc
base 26 of 4611686018427387904: 1m8c769io65344
base 27 of -10: 4eo8hfam6fllmf
base 27 of -1: 4eo8hfam6fllmo
base 27 of 0: 0
base 27 of 10: a
base 27 of 100: 3j
base 27 of 1000: 1a1
base 27 of 4611686018427387904: 13jfho2j1hc5cd
base 28 of -10: 2nc6j26l66rho6
base 28 of -1: 2nc6j26l66rhof
base 28 of 0: 0
base 28 of 10: a
base 28 of 100: 3g
base 28 of 1000: 17k
base 28 of 4611686018427387904: jo1ilfj8fkpd4
base 29 of -10: 1n3rsh11f098re
base 29 of -1: 1n3rsh11f098rn
base 29 of 0: 0
base 29 of 10: a
base 29 of 100: 3d
base 29 of 1000: 15e
base 29 of 4611686018427387904: d0slim0b029e6
base 30 of -10: 14l9lkmo30o406
base 30 of -1: 14l9lkmo30o40f
base 30 of 0: 0
base 30 of 10: a
base 30 of 100: 3a
base 30 of 1000: 13a
base 30 of 4611686018427387904: 8k9rrkl0ml104
base 31 of -10: nd075ib45k866
base 31 of -1: nd075ib45k86f
base 31 of 0: 0
base 31 of 10: a
base 31 of 100: 37
base 31 of 1000: 118
base 31 of 4611686018427387904: 5qfh94i8okhh4
base 32 of -10: fvvvvvvvvvvvm
base 32 of -1: fvvvvvvvvvvvv
base 32 of 0: 0
base 32 of 10: a
base 32 of 100: 34
base 32 of 1000: v8
base 32 of 4611686018427387904: 4000000000000
base 33 of -10: b1w8p7j5q9r66
base 33 of -1: b1w8p7j5q9r6f
base 33 of 0: 0
base 33 of 10: a
base 33 of 100: 31
base 33 of 1000: ua
base 33 of 4611686018427387904: 2p826a4q6ivi4
base 34 of -10: 7orp63sh4dph8
base 34 of -1: 7orp63sh4dphh
base 34 of 0: 0
base 34 of 10: a
base 34 of 100: 2w
base 34 of 1000: te
base 34 of 4611686018427387904: 1vnvr0wl9ketu
base 35 of -10: 5g24a25twkwf6
base 35 of -1: 5g24a25twkwff
base 35 of 0: 0
base 35 of 10: a
base 35 of 100: 2u
base 35 of 1000: sk
base 35 of 4611686018427387904: 1cqrb9a7gvgu4
base 36 of -10: 3w5e11264sgs6
base 36 of -1: 3w5e11264sgsf
base 36 of 0: 0
base 36 of 10: a
base 36 of 100: 2s
base 36 of 1000: rs
base 36 of 4611686018427387904: z1ci99jj7474
base 37 of -10: <error>
base 37 of -1: <error>
base 37 of 0: <error>
base 37 of 10: <error>
base 37 of 100: <error>
base 37 of 1000: <error>
base 37 of 4611686018427387904: <error>
base 38 of -10: <error>
base 38 of -1: <error>
base 38 of 0: <error>
base 38 of 10: <error>
base 38 of 100: <error>
base 38 of 1000: <error>
base 38 of 4611686018427387904: <error>
base 39 of -10: <error>
base 39 of -1: <error>
base 39 of 0: <error>
base 39 of 10: <error>
base 39 of 100: <error>
base 39 of 1000: <error>
base 39 of 4611686018427387904: <error>
base 40 of -10: <error>
base 40 of -1: <error>
base 40 of 0: <error>
base 40 of 10: <error>
base 40 of 100: <error>
base 40 of 1000: <error>
base 40 of 4611686018427387904: <error>

View File

@ -0,0 +1,66 @@
/*
* 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, Joyent, Inc. All rights reserved.
*/
#pragma D option quiet
BEGIN
{
i = 0;
input[i] = "ahi";
expected[i++] = "ahi";
input[i] = "MaHi!";
expected[i++] = "mahi!";
input[i] = " Nase-5";
expected[i++] = " nase-5";
input[i] = "!@#$%";
expected[i++] = "!@#$%";
i = 0;
}
tick-1ms
/input[i] != NULL && (this->out = tolower(input[i])) != expected[i]/
{
printf("expected tolower(\"%s\") to be \"%s\"; found \"%s\"\n",
input[i], expected[i], this->out);
exit(1);
}
tick-1ms
/input[i] != NULL/
{
printf("tolower(\"%s\") is \"%s\", as expected\n",
input[i], expected[i]);
}
tick-1ms
/input[i++] == NULL/
{
exit(0);
}

View File

@ -0,0 +1,66 @@
/*
* 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, Joyent, Inc. All rights reserved.
*/
#pragma D option quiet
BEGIN
{
i = 0;
input[i] = "ahi";
expected[i++] = "AHI";
input[i] = "MaHi!";
expected[i++] = "MAHI!";
input[i] = " dace-9";
expected[i++] = " DACE-9";
input[i] = "!@#$%";
expected[i++] = "!@#$%";
i = 0;
}
tick-1ms
/input[i] != NULL && (this->out = toupper(input[i])) != expected[i]/
{
printf("expected toupper(\"%s\") to be \"%s\"; found \"%s\"\n",
input[i], expected[i], this->out);
exit(1);
}
tick-1ms
/input[i] != NULL/
{
printf("toupper(\"%s\") is \"%s\", as expected\n",
input[i], expected[i]);
}
tick-1ms
/input[i++] == NULL/
{
exit(0);
}

View File

@ -24,7 +24,9 @@
* Use is subject to license terms.
*/
#pragma ident "%Z%%M% %I% %E% SMI"
/*
* Copyright (c) 2012 by Delphix. All rights reserved.
*/
/*
* ASSERTION:
@ -32,44 +34,51 @@
* a runtime error.
*
* SECTION: Pointers and Arrays/Generic Pointers
*
* NOTES:
* This test doesn't apply to x86; for the time being, we're working
* around this with the preprocessor.
*/
#pragma D option quiet
int array[3];
uintptr_t uptr;
#if defined(__i386) || defined(__amd64)
#define __x86 1
#endif
int array[2];
char *ptr;
int *p;
int *q;
int *r;
BEGIN
{
#ifdef __i386
array[0] = 0x12345678;
array[1] = 0xabcdefff;
ptr = (char *) &array[0];
p = (int *) (ptr);
q = (int *) (ptr + 2);
r = (int *) (ptr + 3);
printf("*p: 0x%x\n", *p);
printf("*q: 0x%x\n", *q);
printf("*r: 0x%x\n", *r);
/*
* On x86, the above unaligned memory accesses are allowed and should
* not result in the ERROR probe firing.
*/
#ifdef __x86
exit(1);
#else
array[0] = 20;
array[1] = 40;
array[2] = 80;
uptr = (uintptr_t) &array[0];
p = (int *) (uptr);
q = (int *) (uptr + 2);
r = (int *) (uptr + 3);
printf("array[0]: %d\t*p: %d\n", array[0], *p);
printf("array[1]: %d\t*q: %d\n", array[1], *q);
printf("array[2]: %d\t*r: %d\n", array[2], *r);
exit(0);
#endif
}
ERROR
{
#ifdef __x86
exit(0);
#else
exit(1);
#endif
}

View File

@ -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);
}

View File

@ -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);
}

View File

@ -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();
}

View File

@ -0,0 +1,62 @@
/*
* CDDL HEADER START
*
* The contents of this file are subject to the terms of the
* Common Development and Distribution License (the "License").
* You may not use this file except in compliance with the License.
*
* You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE
* or http://www.opensolaris.org/os/licensing.
* See the License for the specific language governing permissions
* and limitations under the License.
*
* When distributing Covered Code, include this CDDL HEADER in each
* file and include the License file at usr/src/OPENSOLARIS.LICENSE.
* If applicable, add the following below this CDDL HEADER, with the
* fields enclosed by brackets "[]" replaced with your own identifying
* information: Portions Copyright [yyyy] [name of copyright owner]
*
* CDDL HEADER END
*/
/*
* Copyright (c) 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);
}

View File

@ -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' ]
}

View File

@ -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);
}

View File

@ -0,0 +1,6 @@
foo_t {
int a :4 = 0x1
int b :7 = 0x5
int c :1 = 0
int d :2 = 0x2
}

View File

@ -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);
}

View File

@ -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"

View File

@ -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);
}

View File

@ -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
}

View File

@ -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, Joyent, Inc. All rights reserved.
*/
BEGIN
{
tracemem(`dtrace_zero, 256, 0, "fishpong");
}

View File

@ -0,0 +1,30 @@
/*
* 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, Joyent, Inc. All rights reserved.
*/
BEGIN
{
tracemem(`dtrace_zero, 256, "fishpong");
exit(0);
}

View File

@ -20,20 +20,26 @@
*/
/*
* Copyright 2006 Sun Microsystems, Inc. All rights reserved.
* Use is subject to license terms.
* Copyright (c) 2011, Joyent, Inc. All rights reserved.
*/
#pragma ident "%Z%%M% %I% %E% SMI"
/*
* ASSERTION:
* Test tracemem() with too many arguments.
*
* SECTION: Actions and Subroutines/tracemem()
*/
#pragma D option quiet
BEGIN
{
tracemem(123, 456, 789);
i = -10;
}
tick-10ms
/i++ < 150/
{
printf("%d:", i);
tracemem(`dtrace_zero, 128, i);
printf("\n");
}
tick-10ms
/i >= 150/
{
exit(0);
}

File diff suppressed because it is too large Load Diff

View File

@ -57,6 +57,7 @@
#include <sys/arc.h>
#include <sys/ddt.h>
#include <sys/zfeature.h>
#include <zfs_comutil.h>
#undef ZFS_MAXNAMELEN
#undef verify
#include <libzfs.h>
@ -206,6 +207,27 @@ dump_packed_nvlist(objset_t *os, uint64_t object, void *data, size_t size)
nvlist_free(nv);
}
/* ARGSUSED */
static void
dump_history_offsets(objset_t *os, uint64_t object, void *data, size_t size)
{
spa_history_phys_t *shp = data;
if (shp == NULL)
return;
(void) printf("\t\tpool_create_len = %llu\n",
(u_longlong_t)shp->sh_pool_create_len);
(void) printf("\t\tphys_max_off = %llu\n",
(u_longlong_t)shp->sh_phys_max_off);
(void) printf("\t\tbof = %llu\n",
(u_longlong_t)shp->sh_bof);
(void) printf("\t\teof = %llu\n",
(u_longlong_t)shp->sh_eof);
(void) printf("\t\trecords_lost = %llu\n",
(u_longlong_t)shp->sh_records_lost);
}
static void
zdb_nicenum(uint64_t num, char *buf)
{
@ -545,7 +567,7 @@ static void
dump_metaslab_stats(metaslab_t *msp)
{
char maxbuf[32];
space_map_t *sm = &msp->ms_map;
space_map_t *sm = msp->ms_map;
avl_tree_t *t = sm->sm_pp_root;
int free_pct = sm->sm_space * 100 / sm->sm_size;
@ -561,7 +583,7 @@ dump_metaslab(metaslab_t *msp)
{
vdev_t *vd = msp->ms_group->mg_vd;
spa_t *spa = vd->vdev_spa;
space_map_t *sm = &msp->ms_map;
space_map_t *sm = msp->ms_map;
space_map_obj_t *smo = &msp->ms_smo;
char freebuf[32];
@ -857,21 +879,22 @@ dump_history(spa_t *spa)
for (int i = 0; i < num; i++) {
uint64_t time, txg, ievent;
char *cmd, *intstr;
boolean_t printed = B_FALSE;
if (nvlist_lookup_uint64(events[i], ZPOOL_HIST_TIME,
&time) != 0)
continue;
goto next;
if (nvlist_lookup_string(events[i], ZPOOL_HIST_CMD,
&cmd) != 0) {
if (nvlist_lookup_uint64(events[i],
ZPOOL_HIST_INT_EVENT, &ievent) != 0)
continue;
goto next;
verify(nvlist_lookup_uint64(events[i],
ZPOOL_HIST_TXG, &txg) == 0);
verify(nvlist_lookup_string(events[i],
ZPOOL_HIST_INT_STR, &intstr) == 0);
if (ievent >= LOG_END)
continue;
if (ievent >= ZFS_NUM_LEGACY_HISTORY_EVENTS)
goto next;
(void) snprintf(internalstr,
sizeof (internalstr),
@ -884,6 +907,14 @@ dump_history(spa_t *spa)
(void) localtime_r(&tsec, &t);
(void) strftime(tbuf, sizeof (tbuf), "%F.%T", &t);
(void) printf("%s %s\n", tbuf, cmd);
printed = B_TRUE;
next:
if (dump_opt['h'] > 1) {
if (!printed)
(void) printf("unrecognized record:\n");
dump_nvlist(events[i], 2);
}
}
}
@ -1189,7 +1220,7 @@ dump_bpobj_cb(void *arg, const blkptr_t *bp, dmu_tx_t *tx)
}
static void
dump_bpobj(bpobj_t *bpo, char *name)
dump_bpobj(bpobj_t *bpo, char *name, int indent)
{
char bytes[32];
char comp[32];
@ -1199,31 +1230,57 @@ dump_bpobj(bpobj_t *bpo, char *name)
return;
zdb_nicenum(bpo->bpo_phys->bpo_bytes, bytes);
if (bpo->bpo_havesubobj) {
if (bpo->bpo_havesubobj && bpo->bpo_phys->bpo_subobjs != 0) {
zdb_nicenum(bpo->bpo_phys->bpo_comp, comp);
zdb_nicenum(bpo->bpo_phys->bpo_uncomp, uncomp);
(void) printf("\n %s: %llu local blkptrs, %llu subobjs, "
"%s (%s/%s comp)\n",
name, (u_longlong_t)bpo->bpo_phys->bpo_num_blkptrs,
(void) printf(" %*s: object %llu, %llu local blkptrs, "
"%llu subobjs, %s (%s/%s comp)\n",
indent * 8, name,
(u_longlong_t)bpo->bpo_object,
(u_longlong_t)bpo->bpo_phys->bpo_num_blkptrs,
(u_longlong_t)bpo->bpo_phys->bpo_num_subobjs,
bytes, comp, uncomp);
for (uint64_t i = 0; i < bpo->bpo_phys->bpo_num_subobjs; i++) {
uint64_t subobj;
bpobj_t subbpo;
int error;
VERIFY0(dmu_read(bpo->bpo_os,
bpo->bpo_phys->bpo_subobjs,
i * sizeof (subobj), sizeof (subobj), &subobj, 0));
error = bpobj_open(&subbpo, bpo->bpo_os, subobj);
if (error != 0) {
(void) printf("ERROR %u while trying to open "
"subobj id %llu\n",
error, (u_longlong_t)subobj);
continue;
}
dump_bpobj(&subbpo, "subobj", indent + 1);
bpobj_close(&subbpo);
}
} else {
(void) printf("\n %s: %llu blkptrs, %s\n",
name, (u_longlong_t)bpo->bpo_phys->bpo_num_blkptrs, bytes);
(void) printf(" %*s: object %llu, %llu blkptrs, %s\n",
indent * 8, name,
(u_longlong_t)bpo->bpo_object,
(u_longlong_t)bpo->bpo_phys->bpo_num_blkptrs,
bytes);
}
if (dump_opt['d'] < 5)
return;
(void) printf("\n");
(void) bpobj_iterate_nofree(bpo, dump_bpobj_cb, NULL, NULL);
if (indent == 0) {
(void) bpobj_iterate_nofree(bpo, dump_bpobj_cb, NULL, NULL);
(void) printf("\n");
}
}
static void
dump_deadlist(dsl_deadlist_t *dl)
{
dsl_deadlist_entry_t *dle;
uint64_t unused;
char bytes[32];
char comp[32];
char uncomp[32];
@ -1242,14 +1299,24 @@ dump_deadlist(dsl_deadlist_t *dl)
(void) printf("\n");
/* force the tree to be loaded */
dsl_deadlist_space_range(dl, 0, UINT64_MAX, &unused, &unused, &unused);
for (dle = avl_first(&dl->dl_tree); dle;
dle = AVL_NEXT(&dl->dl_tree, dle)) {
(void) printf(" mintxg %llu -> obj %llu\n",
(longlong_t)dle->dle_mintxg,
(longlong_t)dle->dle_bpobj.bpo_object);
if (dump_opt['d'] >= 5) {
char buf[128];
(void) snprintf(buf, sizeof (buf), "mintxg %llu -> ",
(longlong_t)dle->dle_mintxg,
(longlong_t)dle->dle_bpobj.bpo_object);
if (dump_opt['d'] >= 5)
dump_bpobj(&dle->dle_bpobj, "");
dump_bpobj(&dle->dle_bpobj, buf, 0);
} else {
(void) printf("mintxg %llu -> obj %llu\n",
(longlong_t)dle->dle_mintxg,
(longlong_t)dle->dle_bpobj.bpo_object);
}
}
}
@ -1272,7 +1339,7 @@ fuid_table_destroy()
* print uid or gid information.
* For normal POSIX id just the id is printed in decimal format.
* For CIFS files with FUID the fuid is printed in hex followed by
* the doman-rid string.
* the domain-rid string.
*/
static void
print_idstr(uint64_t id, const char *id_type)
@ -1460,7 +1527,7 @@ static object_viewer_t *object_viewer[DMU_OT_NUMTYPES + 1] = {
dump_zap, /* other ZAP */
dump_zap, /* persistent error log */
dump_uint8, /* SPA history */
dump_uint64, /* SPA history offsets */
dump_history_offsets, /* SPA history offsets */
dump_zap, /* Pool properties */
dump_zap, /* DSL permissions */
dump_acl, /* ZFS ACL */
@ -1625,7 +1692,9 @@ dump_dir(objset_t *os)
int print_header = 1;
int i, error;
dsl_pool_config_enter(dmu_objset_pool(os), FTAG);
dmu_objset_fast_stat(os, &dds);
dsl_pool_config_exit(dmu_objset_pool(os), FTAG);
if (dds.dds_type < DMU_OST_NUMTYPES)
type = objset_types[dds.dds_type];
@ -2034,7 +2103,6 @@ zdb_blkptr_cb(spa_t *spa, zilog_t *zilog, const blkptr_t *bp,
NULL, NULL, ZIO_PRIORITY_ASYNC_READ, flags, zb));
free(data);
if (ioerr && !(flags & ZIO_FLAG_SPECULATIVE)) {
zcb->zcb_haderrors = 1;
zcb->zcb_errors[ioerr]++;
@ -2160,11 +2228,11 @@ zdb_leak_init(spa_t *spa, zdb_cb_t *zcb)
for (int m = 0; m < vd->vdev_ms_count; m++) {
metaslab_t *msp = vd->vdev_ms[m];
mutex_enter(&msp->ms_lock);
space_map_unload(&msp->ms_map);
VERIFY(space_map_load(&msp->ms_map,
space_map_unload(msp->ms_map);
VERIFY(space_map_load(msp->ms_map,
&zdb_space_map_ops, SM_ALLOC, &msp->ms_smo,
spa->spa_meta_objset) == 0);
msp->ms_map.sm_ppd = vd;
msp->ms_map->sm_ppd = vd;
mutex_exit(&msp->ms_lock);
}
}
@ -2187,7 +2255,7 @@ zdb_leak_fini(spa_t *spa)
for (int m = 0; m < vd->vdev_ms_count; m++) {
metaslab_t *msp = vd->vdev_ms[m];
mutex_enter(&msp->ms_lock);
space_map_unload(&msp->ms_map);
space_map_unload(msp->ms_map);
mutex_exit(&msp->ms_lock);
}
}
@ -2529,10 +2597,11 @@ dump_zpool(spa_t *spa)
if (dump_opt['d'] || dump_opt['i']) {
dump_dir(dp->dp_meta_objset);
if (dump_opt['d'] >= 3) {
dump_bpobj(&spa->spa_deferred_bpobj, "Deferred frees");
dump_bpobj(&spa->spa_deferred_bpobj,
"Deferred frees", 0);
if (spa_version(spa) >= SPA_VERSION_DEADLISTS) {
dump_bpobj(&spa->spa_dsl_pool->dp_free_bpobj,
"Pool snapshot frees");
"Pool snapshot frees", 0);
}
if (spa_feature_is_active(spa,

View File

@ -28,7 +28,7 @@
.\"
.\" $FreeBSD$
.\"
.Dd February 10, 2013
.Dd March 21, 2013
.Dt ZFS 8
.Os
.Sh NAME
@ -65,6 +65,7 @@
.Op Fl r
.Oo Fl o Ar property Ns = Ns Ar value Oc Ns ...
.Ar filesystem@snapname Ns | Ns Ar volume@snapname
.Ar filesystem@snapname Ns | Ns Ar volume@snapname Ns ...
.Nm
.Cm rollback
.Op Fl rRf
@ -526,6 +527,39 @@ if the snapshot has been marked for deferred destroy by using the
.Qq Nm Cm destroy -d
command. Otherwise, the property is
.Cm off .
.It Sy logicalreferenced
The amount of space that is
.Qq logically
accessible by this dataset.
See the
.Sy referenced
property.
The logical space ignores the effect of the
.Sy compression
and
.Sy copies
properties, giving a quantity closer to the amount of data that applications
see.
However, it does include space consumed by metadata.
.Pp
This property can also be referred to by its shortened column name,
.Sy lrefer .
.It Sy logicalused
The amount of space that is
.Qq logically
consumed by this dataset and all its descendents.
See the
.Sy used
property.
The logical space ignores the effect of the
.Sy compression
and
.Sy copies
properties, giving a quantity closer to the amount of data that applications
see.
.Pp
This property can also be referred to by its shortened column name,
.Sy lused .
.It Sy mounted
For file systems, indicates whether the file system is currently mounted. This
property can be either
@ -1584,7 +1618,11 @@ multiple snapshots.
Destroy (or mark for deferred deletion) all snapshots with this name in
descendent file systems.
.It Fl R
Recursively destroy all dependents.
Recursively destroy all clones of these snapshots, including the clones,
snapshots, and children.
If this flag is specified, the
.Op fl d
flag will have no effect.
.It Fl n
Do a dry-run ("No-op") deletion. No data will be deleted. This is useful in
conjunction with the
@ -1612,17 +1650,18 @@ behavior for mounted file systems in use.
.Op Fl r
.Oo Fl o Ar property Ns = Ns Ar value Oc Ns ...
.Ar filesystem@snapname Ns | Ns volume@snapname
.Ar filesystem@snapname Ns | Ns volume@snapname Ns ...
.Xc
.Pp
Creates a snapshot with the given name. All previous modifications by
successful system calls to the file system are part of the snapshot. See the
Creates snapshots with the given names. All previous modifications by
successful system calls to the file system are part of the snapshots.
Snapshots are taken atomically, so that all snapshots correspond to the same
moment in time. See the
.Qq Sx Snapshots
section for details.
.Bl -tag -width indent
.It Fl r
Recursively create snapshots of all descendent datasets. Snapshots are taken
atomically, so that all recursive snapshots correspond to the same moment in
time.
Recursively create snapshots of all descendent datasets
.It Fl o Ar property Ns = Ns Ar value
Sets the specified property; see
.Qq Nm Cm create

View File

@ -58,6 +58,7 @@
#include <time.h>
#include <libzfs.h>
#include <libzfs_core.h>
#include <zfs_prop.h>
#include <zfs_deleg.h>
#include <libuutil.h>
@ -74,6 +75,7 @@ libzfs_handle_t *g_zfs;
static FILE *mnttab_file;
static char history_str[HIS_MAX_RECORD_LEN];
static boolean_t log_history = B_TRUE;
static int zfs_do_clone(int argc, char **argv);
static int zfs_do_create(int argc, char **argv);
@ -276,7 +278,7 @@ get_usage(zfs_help_t idx)
return (gettext("\tshare <-a | filesystem>\n"));
case HELP_SNAPSHOT:
return (gettext("\tsnapshot [-r] [-o property=value] ... "
"<filesystem@snapname|volume@snapname>\n"));
"<filesystem@snapname|volume@snapname> ...\n"));
case HELP_UNMOUNT:
return (gettext("\tunmount [-f] "
"<-a | filesystem|mountpoint>\n"));
@ -914,11 +916,12 @@ typedef struct destroy_cbdata {
boolean_t cb_parsable;
boolean_t cb_dryrun;
nvlist_t *cb_nvl;
nvlist_t *cb_batchedsnaps;
/* first snap in contiguous run */
zfs_handle_t *cb_firstsnap;
char *cb_firstsnap;
/* previous snap in contiguous run */
zfs_handle_t *cb_prevsnap;
char *cb_prevsnap;
int64_t cb_snapused;
char *cb_snapspec;
} destroy_cbdata_t;
@ -1010,9 +1013,27 @@ destroy_callback(zfs_handle_t *zhp, void *data)
zfs_close(zhp);
return (0);
}
if (cb->cb_dryrun) {
zfs_close(zhp);
return (0);
}
if (!cb->cb_dryrun) {
if (zfs_unmount(zhp, NULL, cb->cb_force ? MS_FORCE : 0) != 0 ||
/*
* We batch up all contiguous snapshots (even of different
* filesystems) and destroy them with one ioctl. We can't
* simply do all snap deletions and then all fs deletions,
* because we must delete a clone before its origin.
*/
if (zfs_get_type(zhp) == ZFS_TYPE_SNAPSHOT) {
fnvlist_add_boolean(cb->cb_batchedsnaps, name);
} else {
int error = zfs_destroy_snaps_nvl(g_zfs,
cb->cb_batchedsnaps, B_FALSE);
fnvlist_free(cb->cb_batchedsnaps);
cb->cb_batchedsnaps = fnvlist_alloc();
if (error != 0 ||
zfs_unmount(zhp, NULL, cb->cb_force ? MS_FORCE : 0) != 0 ||
zfs_destroy(zhp, cb->cb_defer_destroy) != 0) {
zfs_close(zhp);
return (-1);
@ -1032,11 +1053,13 @@ destroy_print_cb(zfs_handle_t *zhp, void *arg)
if (nvlist_exists(cb->cb_nvl, name)) {
if (cb->cb_firstsnap == NULL)
cb->cb_firstsnap = zfs_handle_dup(zhp);
cb->cb_firstsnap = strdup(name);
if (cb->cb_prevsnap != NULL)
zfs_close(cb->cb_prevsnap);
free(cb->cb_prevsnap);
/* this snap continues the current range */
cb->cb_prevsnap = zfs_handle_dup(zhp);
cb->cb_prevsnap = strdup(name);
if (cb->cb_firstsnap == NULL || cb->cb_prevsnap == NULL)
nomem();
if (cb->cb_verbose) {
if (cb->cb_parsable) {
(void) printf("destroy\t%s\n", name);
@ -1051,12 +1074,12 @@ destroy_print_cb(zfs_handle_t *zhp, void *arg)
} else if (cb->cb_firstsnap != NULL) {
/* end of this range */
uint64_t used = 0;
err = zfs_get_snapused_int(cb->cb_firstsnap,
err = lzc_snaprange_space(cb->cb_firstsnap,
cb->cb_prevsnap, &used);
cb->cb_snapused += used;
zfs_close(cb->cb_firstsnap);
free(cb->cb_firstsnap);
cb->cb_firstsnap = NULL;
zfs_close(cb->cb_prevsnap);
free(cb->cb_prevsnap);
cb->cb_prevsnap = NULL;
}
zfs_close(zhp);
@ -1073,13 +1096,13 @@ destroy_print_snapshots(zfs_handle_t *fs_zhp, destroy_cbdata_t *cb)
if (cb->cb_firstsnap != NULL) {
uint64_t used = 0;
if (err == 0) {
err = zfs_get_snapused_int(cb->cb_firstsnap,
err = lzc_snaprange_space(cb->cb_firstsnap,
cb->cb_prevsnap, &used);
}
cb->cb_snapused += used;
zfs_close(cb->cb_firstsnap);
free(cb->cb_firstsnap);
cb->cb_firstsnap = NULL;
zfs_close(cb->cb_prevsnap);
free(cb->cb_prevsnap);
cb->cb_prevsnap = NULL;
}
return (err);
@ -1166,8 +1189,10 @@ static int
zfs_do_destroy(int argc, char **argv)
{
destroy_cbdata_t cb = { 0 };
int rv = 0;
int err = 0;
int c;
zfs_handle_t *zhp;
zfs_handle_t *zhp = NULL;
char *at;
zfs_type_t type = ZFS_TYPE_DATASET;
@ -1221,11 +1246,9 @@ zfs_do_destroy(int argc, char **argv)
at = strchr(argv[0], '@');
if (at != NULL) {
int err = 0;
/* Build the list of snaps to destroy in cb_nvl. */
if (nvlist_alloc(&cb.cb_nvl, NV_UNIQUE_NAME, 0) != 0)
nomem();
cb.cb_nvl = fnvlist_alloc();
*at = '\0';
zhp = zfs_open(g_zfs, argv[0],
@ -1236,17 +1259,15 @@ zfs_do_destroy(int argc, char **argv)
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);
rv = 1;
goto out;
}
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);
rv = 1;
goto out;
}
if (cb.cb_verbose) {
@ -1265,18 +1286,26 @@ zfs_do_destroy(int argc, char **argv)
}
if (!cb.cb_dryrun) {
if (cb.cb_doclones)
if (cb.cb_doclones) {
cb.cb_batchedsnaps = fnvlist_alloc();
err = destroy_clones(&cb);
if (err == 0) {
err = zfs_destroy_snaps_nvl(g_zfs,
cb.cb_batchedsnaps, B_FALSE);
}
if (err != 0) {
rv = 1;
goto out;
}
}
if (err == 0) {
err = zfs_destroy_snaps_nvl(zhp, cb.cb_nvl,
err = zfs_destroy_snaps_nvl(g_zfs, cb.cb_nvl,
cb.cb_defer_destroy);
}
}
zfs_close(zhp);
nvlist_free(cb.cb_nvl);
if (err != 0)
return (1);
rv = 1;
} else {
/* Open the given dataset */
if ((zhp = zfs_open(g_zfs, argv[0], type)) == NULL)
@ -1297,8 +1326,8 @@ zfs_do_destroy(int argc, char **argv)
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);
rv = 1;
goto out;
}
/*
@ -1308,30 +1337,42 @@ zfs_do_destroy(int argc, char **argv)
if (!cb.cb_doclones &&
zfs_iter_dependents(zhp, B_TRUE, destroy_check_dependent,
&cb) != 0) {
zfs_close(zhp);
return (1);
rv = 1;
goto out;
}
if (cb.cb_error) {
zfs_close(zhp);
return (1);
rv = 1;
goto out;
}
cb.cb_batchedsnaps = fnvlist_alloc();
if (zfs_iter_dependents(zhp, B_FALSE, destroy_callback,
&cb) != 0) {
zfs_close(zhp);
return (1);
rv = 1;
goto out;
}
/*
* 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);
err = destroy_callback(zhp, &cb);
zhp = NULL;
if (err == 0) {
err = zfs_destroy_snaps_nvl(g_zfs,
cb.cb_batchedsnaps, cb.cb_defer_destroy);
}
if (err != 0)
rv = 1;
}
return (0);
out:
fnvlist_free(cb.cb_batchedsnaps);
fnvlist_free(cb.cb_nvl);
if (zhp != NULL)
zfs_close(zhp);
return (rv);
}
static boolean_t
@ -1932,9 +1973,11 @@ upgrade_set_callback(zfs_handle_t *zhp, void *data)
/*
* If they did "zfs upgrade -a", then we could
* be doing ioctls to different pools. We need
* to log this history once to each pool.
* to log this history once to each pool, and bypass
* the normal history logging that happens in main().
*/
verify(zpool_stage_history(g_zfs, history_str) == 0);
(void) zpool_log_history(g_zfs, history_str);
log_history = B_FALSE;
}
if (zfs_prop_set(zhp, "version", verstr) == 0)
cb->cb_numupgraded++;
@ -3472,6 +3515,32 @@ zfs_do_set(int argc, char **argv)
return (ret);
}
typedef struct snap_cbdata {
nvlist_t *sd_nvl;
boolean_t sd_recursive;
const char *sd_snapname;
} snap_cbdata_t;
static int
zfs_snapshot_cb(zfs_handle_t *zhp, void *arg)
{
snap_cbdata_t *sd = arg;
char *name;
int rv = 0;
int error;
error = asprintf(&name, "%s@%s", zfs_get_name(zhp), sd->sd_snapname);
if (error == -1)
nomem();
fnvlist_add_boolean(sd->sd_nvl, name);
free(name);
if (sd->sd_recursive)
rv = zfs_iter_filesystems(zhp, zfs_snapshot_cb, sd);
zfs_close(zhp);
return (rv);
}
/*
* zfs snapshot [-r] [-o prop=value] ... <fs@snap>
*
@ -3481,13 +3550,16 @@ zfs_do_set(int argc, char **argv)
static int
zfs_do_snapshot(int argc, char **argv)
{
boolean_t recursive = B_FALSE;
int ret = 0;
char c;
nvlist_t *props;
snap_cbdata_t sd = { 0 };
boolean_t multiple_snaps = B_FALSE;
if (nvlist_alloc(&props, NV_UNIQUE_NAME, 0) != 0)
nomem();
if (nvlist_alloc(&sd.sd_nvl, NV_UNIQUE_NAME, 0) != 0)
nomem();
/* check options */
while ((c = getopt(argc, argv, "ro:")) != -1) {
@ -3497,7 +3569,8 @@ zfs_do_snapshot(int argc, char **argv)
return (1);
break;
case 'r':
recursive = B_TRUE;
sd.sd_recursive = B_TRUE;
multiple_snaps = B_TRUE;
break;
case '?':
(void) fprintf(stderr, gettext("invalid option '%c'\n"),
@ -3514,18 +3587,35 @@ zfs_do_snapshot(int argc, char **argv)
(void) fprintf(stderr, gettext("missing snapshot argument\n"));
goto usage;
}
if (argc > 1) {
(void) fprintf(stderr, gettext("too many arguments\n"));
goto usage;
if (argc > 1)
multiple_snaps = B_TRUE;
for (; argc > 0; argc--, argv++) {
char *atp;
zfs_handle_t *zhp;
atp = strchr(argv[0], '@');
if (atp == NULL)
goto usage;
*atp = '\0';
sd.sd_snapname = atp + 1;
zhp = zfs_open(g_zfs, argv[0],
ZFS_TYPE_FILESYSTEM | ZFS_TYPE_VOLUME);
if (zhp == NULL)
goto usage;
if (zfs_snapshot_cb(zhp, &sd) != 0)
goto usage;
}
ret = zfs_snapshot(g_zfs, argv[0], recursive, props);
ret = zfs_snapshot_nvl(g_zfs, sd.sd_nvl, props);
nvlist_free(sd.sd_nvl);
nvlist_free(props);
if (ret && recursive)
if (ret != 0 && multiple_snaps)
(void) fprintf(stderr, gettext("no snapshots were created\n"));
return (ret != 0);
usage:
nvlist_free(sd.sd_nvl);
nvlist_free(props);
usage(B_FALSE);
return (-1);
@ -5068,28 +5158,12 @@ cleanup2:
return (error);
}
/*
* zfs allow [-r] [-t] <tag> <snap> ...
*
* -r Recursively hold
* -t Temporary hold (hidden option)
*
* Apply a user-hold with the given tag to the list of snapshots.
*/
static int
zfs_do_allow(int argc, char **argv)
{
return (zfs_do_allow_unallow_impl(argc, argv, B_FALSE));
}
/*
* zfs unallow [-r] [-t] <tag> <snap> ...
*
* -r Recursively hold
* -t Temporary hold (hidden option)
*
* Apply a user-hold with the given tag to the list of snapshots.
*/
static int
zfs_do_unallow(int argc, char **argv)
{
@ -5103,7 +5177,6 @@ zfs_do_hold_rele_impl(int argc, char **argv, boolean_t holding)
int i;
const char *tag;
boolean_t recursive = B_FALSE;
boolean_t temphold = B_FALSE;
const char *opts = holding ? "rt" : "r";
int c;
@ -5113,9 +5186,6 @@ zfs_do_hold_rele_impl(int argc, char **argv, boolean_t holding)
case 'r':
recursive = B_TRUE;
break;
case 't':
temphold = B_TRUE;
break;
case '?':
(void) fprintf(stderr, gettext("invalid option '%c'\n"),
optopt);
@ -5164,7 +5234,7 @@ zfs_do_hold_rele_impl(int argc, char **argv, boolean_t holding)
}
if (holding) {
if (zfs_hold(zhp, delim+1, tag, recursive,
temphold, B_FALSE, -1, 0, 0) != 0)
B_FALSE, -1) != 0)
++errors;
} else {
if (zfs_release(zhp, delim+1, tag, recursive) != 0)
@ -5180,7 +5250,6 @@ zfs_do_hold_rele_impl(int argc, char **argv, boolean_t holding)
* zfs hold [-r] [-t] <tag> <snap> ...
*
* -r Recursively hold
* -t Temporary hold (hidden option)
*
* Apply a user-hold with the given tag to the list of snapshots.
*/
@ -6602,8 +6671,7 @@ main(int argc, char **argv)
return (1);
}
zpool_set_history_str("zfs", argc, argv, history_str);
verify(zpool_stage_history(g_zfs, history_str) == 0);
zfs_save_arguments(argc, argv, history_str, sizeof (history_str));
libzfs_print_on_error(g_zfs, B_TRUE);
@ -6672,6 +6740,9 @@ main(int argc, char **argv)
(void) fclose(mnttab_file);
if (ret == 0 && log_history)
(void) zpool_log_history(g_zfs, history_str);
libzfs_fini(g_zfs);
/*

View File

@ -46,6 +46,7 @@
#include <sys/zio_checksum.h>
#include <sys/zio_compress.h>
#include <sys/zfeature.h>
#include <sys/dmu_tx.h>
#undef ZFS_MAXNAMELEN
#undef verify
#include <libzfs.h>
@ -273,12 +274,15 @@ zhack_do_feature_stat(int argc, char **argv)
}
static void
feature_enable_sync(void *arg1, void *arg2, dmu_tx_t *tx)
feature_enable_sync(void *arg, dmu_tx_t *tx)
{
spa_t *spa = arg1;
zfeature_info_t *feature = arg2;
spa_t *spa = dmu_tx_pool(tx)->dp_spa;
zfeature_info_t *feature = arg;
spa_feature_enable(spa, feature, tx);
spa_history_log_internal(spa, "zhack enable feature", tx,
"name=%s can_readonly=%u",
feature->fi_guid, feature->fi_can_readonly);
}
static void
@ -341,8 +345,8 @@ zhack_do_feature_enable(int argc, char **argv)
if (0 == zap_contains(mos, spa->spa_feat_desc_obj, feature.fi_guid))
fatal("feature already enabled: %s", feature.fi_guid);
VERIFY3U(0, ==, dsl_sync_task_do(spa->spa_dsl_pool, NULL,
feature_enable_sync, spa, &feature, 5));
VERIFY0(dsl_sync_task(spa_name(spa), NULL,
feature_enable_sync, &feature, 5));
spa_close(spa, FTAG);
@ -350,21 +354,25 @@ zhack_do_feature_enable(int argc, char **argv)
}
static void
feature_incr_sync(void *arg1, void *arg2, dmu_tx_t *tx)
feature_incr_sync(void *arg, dmu_tx_t *tx)
{
spa_t *spa = arg1;
zfeature_info_t *feature = arg2;
spa_t *spa = dmu_tx_pool(tx)->dp_spa;
zfeature_info_t *feature = arg;
spa_feature_incr(spa, feature, tx);
spa_history_log_internal(spa, "zhack feature incr", tx,
"name=%s", feature->fi_guid);
}
static void
feature_decr_sync(void *arg1, void *arg2, dmu_tx_t *tx)
feature_decr_sync(void *arg, dmu_tx_t *tx)
{
spa_t *spa = arg1;
zfeature_info_t *feature = arg2;
spa_t *spa = dmu_tx_pool(tx)->dp_spa;
zfeature_info_t *feature = arg;
spa_feature_decr(spa, feature, tx);
spa_history_log_internal(spa, "zhack feature decr", tx,
"name=%s", feature->fi_guid);
}
static void
@ -435,8 +443,8 @@ zhack_do_feature_ref(int argc, char **argv)
if (decr && !spa_feature_is_active(spa, &feature))
fatal("feature refcount already 0: %s", feature.fi_guid);
VERIFY3U(0, ==, dsl_sync_task_do(spa->spa_dsl_pool, NULL,
decr ? feature_decr_sync : feature_incr_sync, spa, &feature, 5));
VERIFY0(dsl_sync_task(spa_name(spa), NULL,
decr ? feature_decr_sync : feature_incr_sync, &feature, 5));
spa_close(spa, FTAG);
}

View File

@ -20,6 +20,7 @@
*/
/*
* Copyright (c) 2006, 2010, Oracle and/or its affiliates. All rights reserved.
* Copyright (c) 2012 by Delphix. All rights reserved.
*/
#include <libzfs.h>
@ -455,6 +456,20 @@ translate_device(const char *pool, const char *device, err_type_t label_type,
&record->zi_guid) == 0);
}
/*
* Device faults can take on three different forms:
* 1). delayed or hanging I/O
* 2). zfs label faults
* 3). generic disk faults
*/
if (record->zi_timer != 0) {
record->zi_cmd = ZINJECT_DELAY_IO;
} else if (label_type != TYPE_INVAL) {
record->zi_cmd = ZINJECT_LABEL_FAULT;
} else {
record->zi_cmd = ZINJECT_DEVICE_FAULT;
}
switch (label_type) {
case TYPE_LABEL_UBERBLOCK:
record->zi_start = offsetof(vdev_label_t, vl_uberblock[0]);

View File

@ -20,6 +20,7 @@
*/
/*
* Copyright (c) 2005, 2010, Oracle and/or its affiliates. All rights reserved.
* Copyright (c) 2012 by Delphix. All rights reserved.
*/
/*
@ -603,7 +604,7 @@ main(int argc, char **argv)
}
while ((c = getopt(argc, argv,
":aA:b:d:f:Fg:qhIc:t:T:l:mr:s:e:uL:p:")) != -1) {
":aA:b:d:D:f:Fg:qhIc:t:T:l:mr:s:e:uL:p:")) != -1) {
switch (c) {
case 'a':
flags |= ZINJECT_FLUSH_ARC;
@ -629,6 +630,15 @@ main(int argc, char **argv)
case 'd':
device = optarg;
break;
case 'D':
record.zi_timer = strtoull(optarg, &end, 10);
if (errno != 0 || *end != '\0') {
(void) fprintf(stderr, "invalid i/o delay "
"value: '%s'\n", optarg);
usage();
return (1);
}
break;
case 'e':
if (strcasecmp(optarg, "io") == 0) {
error = EIO;
@ -693,6 +703,7 @@ main(int argc, char **argv)
case 'p':
(void) strlcpy(record.zi_func, optarg,
sizeof (record.zi_func));
record.zi_cmd = ZINJECT_PANIC;
break;
case 'q':
quiet = 1;
@ -766,13 +777,15 @@ main(int argc, char **argv)
argc -= optind;
argv += optind;
if (record.zi_duration != 0)
record.zi_cmd = ZINJECT_IGNORED_WRITES;
if (cancel != NULL) {
/*
* '-c' is invalid with any other options.
*/
if (raw != NULL || range != NULL || type != TYPE_INVAL ||
level != 0 || record.zi_func[0] != '\0' ||
record.zi_duration != 0) {
level != 0 || record.zi_cmd != ZINJECT_UNINITIALIZED) {
(void) fprintf(stderr, "cancel (-c) incompatible with "
"any other options\n");
usage();
@ -804,8 +817,7 @@ main(int argc, char **argv)
* for doing injection, so handle it separately here.
*/
if (raw != NULL || range != NULL || type != TYPE_INVAL ||
level != 0 || record.zi_func[0] != '\0' ||
record.zi_duration != 0) {
level != 0 || record.zi_cmd != ZINJECT_UNINITIALIZED) {
(void) fprintf(stderr, "device (-d) incompatible with "
"data error injection\n");
usage();
@ -839,7 +851,7 @@ main(int argc, char **argv)
} else if (raw != NULL) {
if (range != NULL || type != TYPE_INVAL || level != 0 ||
record.zi_func[0] != '\0' || record.zi_duration != 0) {
record.zi_cmd != ZINJECT_UNINITIALIZED) {
(void) fprintf(stderr, "raw (-b) format with "
"any other options\n");
usage();
@ -862,13 +874,14 @@ main(int argc, char **argv)
return (1);
}
record.zi_cmd = ZINJECT_DATA_FAULT;
if (translate_raw(raw, &record) != 0)
return (1);
if (!error)
error = EIO;
} else if (record.zi_func[0] != '\0') {
} else if (record.zi_cmd == ZINJECT_PANIC) {
if (raw != NULL || range != NULL || type != TYPE_INVAL ||
level != 0 || device != NULL || record.zi_duration != 0) {
level != 0 || device != NULL) {
(void) fprintf(stderr, "panic (-p) incompatible with "
"other options\n");
usage();
@ -886,7 +899,7 @@ main(int argc, char **argv)
if (argv[1] != NULL)
record.zi_type = atoi(argv[1]);
dataset[0] = '\0';
} else if (record.zi_duration != 0) {
} else if (record.zi_cmd == ZINJECT_IGNORED_WRITES) {
if (nowrites == 0) {
(void) fprintf(stderr, "-s or -g meaningless "
"without -I (ignore writes)\n");
@ -940,6 +953,7 @@ main(int argc, char **argv)
return (1);
}
record.zi_cmd = ZINJECT_DATA_FAULT;
if (translate_record(type, argv[0], range, level, &record, pool,
dataset) != 0)
return (1);

View File

@ -25,7 +25,7 @@
.\"
.\" $FreeBSD$
.\"
.Dd November 15, 2012
.Dd March 14, 2013
.Dt ZPOOL 8
.Os
.Sh NAME
@ -1608,14 +1608,15 @@ is specified, the command exits after
.Ar count
reports are printed.
.Pp
If a scrub or resilver is in progress, this command reports the percentage done
and the estimated time to completion. Both of these are only approximate,
If a scrub or resilver is in progress, this command reports the percentage
done and the estimated time to completion. Both of these are only approximate,
because the amount of data in the pool and the other workloads on the system
can change.
.Bl -tag -width indent
.It Fl x
Only display status for pools that are exhibiting errors or are otherwise
unavailable.
Warnings about pools not using the latest on-disk format will not be included.
.It Fl v
Displays verbose data error information, printing out a complete list of all
data errors since the last complete pool scrub.

View File

@ -192,9 +192,9 @@ static zpool_command_t command_table[] = {
#define NCOMMAND (sizeof (command_table) / sizeof (command_table[0]))
zpool_command_t *current_command;
static zpool_command_t *current_command;
static char history_str[HIS_MAX_RECORD_LEN];
static boolean_t log_history = B_TRUE;
static uint_t timestamp_fmt = NODATE;
static const char *
@ -1093,7 +1093,10 @@ zpool_do_destroy(int argc, char **argv)
return (1);
}
ret = (zpool_destroy(zhp) != 0);
/* The history must be logged as part of the export */
log_history = B_FALSE;
ret = (zpool_destroy(zhp, history_str) != 0);
zpool_close(zhp);
@ -1157,10 +1160,13 @@ zpool_do_export(int argc, char **argv)
continue;
}
/* The history must be logged as part of the export */
log_history = B_FALSE;
if (hardforce) {
if (zpool_export_force(zhp) != 0)
if (zpool_export_force(zhp, history_str) != 0)
ret = 1;
} else if (zpool_export(zhp, force) != 0) {
} else if (zpool_export(zhp, force, history_str) != 0) {
ret = 1;
}
@ -4031,7 +4037,10 @@ status_callback(zpool_handle_t *zhp, void *data)
* If we were given 'zpool status -x', only report those pools with
* problems.
*/
if (reason == ZPOOL_STATUS_OK && cbp->cb_explain) {
if (cbp->cb_explain &&
(reason == ZPOOL_STATUS_OK ||
reason == ZPOOL_STATUS_VERSION_OLDER ||
reason == ZPOOL_STATUS_FEAT_DISABLED)) {
if (!cbp->cb_allpools) {
(void) printf(gettext("pool '%s' is healthy\n"),
zpool_get_name(zhp));
@ -4560,6 +4569,14 @@ upgrade_cb(zpool_handle_t *zhp, void *arg)
if (count > 0) {
cbp->cb_first = B_FALSE;
printnl = B_TRUE;
/*
* If they did "zpool upgrade -a", then we could
* be doing ioctls to different pools. We need
* to log this history once to each pool, and bypass
* the normal history logging that happens in main().
*/
(void) zpool_log_history(g_zfs, history_str);
log_history = B_FALSE;
}
}
@ -4921,8 +4938,8 @@ zpool_do_upgrade(int argc, char **argv)
typedef struct hist_cbdata {
boolean_t first;
int longfmt;
int internal;
boolean_t longfmt;
boolean_t internal;
} hist_cbdata_t;
/*
@ -4934,21 +4951,8 @@ get_history_one(zpool_handle_t *zhp, void *data)
nvlist_t *nvhis;
nvlist_t **records;
uint_t numrecords;
char *cmdstr;
char *pathstr;
uint64_t dst_time;
time_t tsec;
struct tm t;
char tbuf[30];
int ret, i;
uint64_t who;
struct passwd *pwd;
char *hostname;
char *zonename;
char internalstr[MAXPATHLEN];
hist_cbdata_t *cb = (hist_cbdata_t *)data;
uint64_t txg;
uint64_t ievent;
cb->first = B_FALSE;
@ -4960,64 +4964,94 @@ get_history_one(zpool_handle_t *zhp, void *data)
verify(nvlist_lookup_nvlist_array(nvhis, ZPOOL_HIST_RECORD,
&records, &numrecords) == 0);
for (i = 0; i < numrecords; i++) {
if (nvlist_lookup_uint64(records[i], ZPOOL_HIST_TIME,
&dst_time) != 0)
continue;
nvlist_t *rec = records[i];
char tbuf[30] = "";
/* is it an internal event or a standard event? */
if (nvlist_lookup_string(records[i], ZPOOL_HIST_CMD,
&cmdstr) != 0) {
if (cb->internal == 0)
continue;
if (nvlist_exists(rec, ZPOOL_HIST_TIME)) {
time_t tsec;
struct tm t;
if (nvlist_lookup_uint64(records[i],
ZPOOL_HIST_INT_EVENT, &ievent) != 0)
continue;
verify(nvlist_lookup_uint64(records[i],
ZPOOL_HIST_TXG, &txg) == 0);
verify(nvlist_lookup_string(records[i],
ZPOOL_HIST_INT_STR, &pathstr) == 0);
if (ievent >= LOG_END)
continue;
(void) snprintf(internalstr,
sizeof (internalstr),
"[internal %s txg:%lld] %s",
zfs_history_event_names[ievent], txg,
pathstr);
cmdstr = internalstr;
tsec = fnvlist_lookup_uint64(records[i],
ZPOOL_HIST_TIME);
(void) localtime_r(&tsec, &t);
(void) strftime(tbuf, sizeof (tbuf), "%F.%T", &t);
}
if (nvlist_exists(rec, ZPOOL_HIST_CMD)) {
(void) printf("%s %s", tbuf,
fnvlist_lookup_string(rec, ZPOOL_HIST_CMD));
} else if (nvlist_exists(rec, ZPOOL_HIST_INT_EVENT)) {
int ievent =
fnvlist_lookup_uint64(rec, ZPOOL_HIST_INT_EVENT);
if (!cb->internal)
continue;
if (ievent >= ZFS_NUM_LEGACY_HISTORY_EVENTS) {
(void) printf("%s unrecognized record:\n",
tbuf);
dump_nvlist(rec, 4);
continue;
}
(void) printf("%s [internal %s txg:%lld] %s", tbuf,
zfs_history_event_names[ievent],
fnvlist_lookup_uint64(rec, ZPOOL_HIST_TXG),
fnvlist_lookup_string(rec, ZPOOL_HIST_INT_STR));
} else if (nvlist_exists(rec, ZPOOL_HIST_INT_NAME)) {
if (!cb->internal)
continue;
(void) printf("%s [txg:%lld] %s", tbuf,
fnvlist_lookup_uint64(rec, ZPOOL_HIST_TXG),
fnvlist_lookup_string(rec, ZPOOL_HIST_INT_NAME));
if (nvlist_exists(rec, ZPOOL_HIST_DSNAME)) {
(void) printf(" %s (%llu)",
fnvlist_lookup_string(rec,
ZPOOL_HIST_DSNAME),
fnvlist_lookup_uint64(rec,
ZPOOL_HIST_DSID));
}
(void) printf(" %s", fnvlist_lookup_string(rec,
ZPOOL_HIST_INT_STR));
} else if (nvlist_exists(rec, ZPOOL_HIST_IOCTL)) {
if (!cb->internal)
continue;
(void) printf("%s ioctl %s\n", tbuf,
fnvlist_lookup_string(rec, ZPOOL_HIST_IOCTL));
if (nvlist_exists(rec, ZPOOL_HIST_INPUT_NVL)) {
(void) printf(" input:\n");
dump_nvlist(fnvlist_lookup_nvlist(rec,
ZPOOL_HIST_INPUT_NVL), 8);
}
if (nvlist_exists(rec, ZPOOL_HIST_OUTPUT_NVL)) {
(void) printf(" output:\n");
dump_nvlist(fnvlist_lookup_nvlist(rec,
ZPOOL_HIST_OUTPUT_NVL), 8);
}
} else {
if (!cb->internal)
continue;
(void) printf("%s unrecognized record:\n", tbuf);
dump_nvlist(rec, 4);
}
tsec = dst_time;
(void) localtime_r(&tsec, &t);
(void) strftime(tbuf, sizeof (tbuf), "%F.%T", &t);
(void) printf("%s %s", tbuf, cmdstr);
if (!cb->longfmt) {
(void) printf("\n");
continue;
}
(void) printf(" [");
if (nvlist_lookup_uint64(records[i],
ZPOOL_HIST_WHO, &who) == 0) {
pwd = getpwuid((uid_t)who);
if (pwd)
(void) printf("user %s on",
pwd->pw_name);
else
(void) printf("user %d on",
(int)who);
} else {
(void) printf(gettext("no info]\n"));
continue;
if (nvlist_exists(rec, ZPOOL_HIST_WHO)) {
uid_t who = fnvlist_lookup_uint64(rec, ZPOOL_HIST_WHO);
struct passwd *pwd = getpwuid(who);
(void) printf("user %d ", (int)who);
if (pwd != NULL)
(void) printf("(%s) ", pwd->pw_name);
}
if (nvlist_lookup_string(records[i],
ZPOOL_HIST_HOST, &hostname) == 0) {
(void) printf(" %s", hostname);
if (nvlist_exists(rec, ZPOOL_HIST_HOST)) {
(void) printf("on %s",
fnvlist_lookup_string(rec, ZPOOL_HIST_HOST));
}
if (nvlist_lookup_string(records[i],
ZPOOL_HIST_ZONE, &zonename) == 0) {
(void) printf(":%s", zonename);
if (nvlist_exists(rec, ZPOOL_HIST_ZONE)) {
(void) printf(":%s",
fnvlist_lookup_string(rec, ZPOOL_HIST_ZONE));
}
(void) printf("]");
(void) printf("\n");
}
@ -5032,8 +5066,6 @@ get_history_one(zpool_handle_t *zhp, void *data)
*
* Displays the history of commands that modified pools.
*/
int
zpool_do_history(int argc, char **argv)
{
@ -5046,10 +5078,10 @@ zpool_do_history(int argc, char **argv)
while ((c = getopt(argc, argv, "li")) != -1) {
switch (c) {
case 'l':
cbdata.longfmt = 1;
cbdata.longfmt = B_TRUE;
break;
case 'i':
cbdata.internal = 1;
cbdata.internal = B_TRUE;
break;
case '?':
(void) fprintf(stderr, gettext("invalid option '%c'\n"),
@ -5274,8 +5306,7 @@ main(int argc, char **argv)
if (strcmp(cmdname, "-?") == 0)
usage(B_TRUE);
zpool_set_history_str("zpool", argc, argv, history_str);
verify(zpool_stage_history(g_zfs, history_str) == 0);
zfs_save_arguments(argc, argv, history_str, sizeof (history_str));
/*
* Run the appropriate command.
@ -5302,6 +5333,9 @@ main(int argc, char **argv)
usage(B_FALSE);
}
if (ret == 0 && log_history)
(void) zpool_log_history(g_zfs, history_str);
libzfs_fini(g_zfs);
/*

View File

@ -104,10 +104,12 @@
#include <sys/metaslab_impl.h>
#include <sys/dsl_prop.h>
#include <sys/dsl_dataset.h>
#include <sys/dsl_destroy.h>
#include <sys/dsl_scan.h>
#include <sys/zio_checksum.h>
#include <sys/refcount.h>
#include <sys/zfeature.h>
#include <sys/dsl_userhold.h>
#include <stdio.h>
#include <stdio_ext.h>
#include <stdlib.h>
@ -367,7 +369,7 @@ ztest_info_t ztest_info[] = {
{ ztest_scrub, 1, &zopt_rarely },
{ ztest_spa_upgrade, 1, &zopt_rarely },
{ ztest_dsl_dataset_promote_busy, 1, &zopt_rarely },
{ ztest_vdev_attach_detach, 1, &zopt_rarely },
{ ztest_vdev_attach_detach, 1, &zopt_sometimes },
{ ztest_vdev_LUN_growth, 1, &zopt_rarely },
{ ztest_vdev_add_remove, 1,
&ztest_opts.zo_vdevtime },
@ -1008,9 +1010,8 @@ ztest_dsl_prop_set_uint64(char *osname, zfs_prop_t prop, uint64_t value,
uint64_t curval;
int error;
error = dsl_prop_set(osname, propname,
(inherit ? ZPROP_SRC_NONE : ZPROP_SRC_LOCAL),
sizeof (value), 1, &value);
error = dsl_prop_set_int(osname, propname,
(inherit ? ZPROP_SRC_NONE : ZPROP_SRC_LOCAL), value);
if (error == ENOSPC) {
ztest_record_enospc(FTAG);
@ -1018,8 +1019,7 @@ ztest_dsl_prop_set_uint64(char *osname, zfs_prop_t prop, uint64_t value,
}
ASSERT0(error);
VERIFY3U(dsl_prop_get(osname, propname, sizeof (curval),
1, &curval, setpoint), ==, 0);
VERIFY0(dsl_prop_get_integer(osname, propname, &curval, setpoint));
if (ztest_opts.zo_verbose >= 6) {
VERIFY(zfs_prop_index_to_string(prop, curval, &valname) == 0);
@ -2332,7 +2332,7 @@ ztest_spa_create_destroy(ztest_ds_t *zd, uint64_t id)
*/
nvroot = make_vdev_root("/dev/bogus", NULL, NULL, 0, 0, 0, 0, 0, 1);
VERIFY3U(ENOENT, ==,
spa_create("ztest_bad_file", nvroot, NULL, NULL, NULL));
spa_create("ztest_bad_file", nvroot, NULL, NULL));
nvlist_free(nvroot);
/*
@ -2340,7 +2340,7 @@ ztest_spa_create_destroy(ztest_ds_t *zd, uint64_t id)
*/
nvroot = make_vdev_root("/dev/bogus", NULL, NULL, 0, 0, 0, 0, 2, 1);
VERIFY3U(ENOENT, ==,
spa_create("ztest_bad_mirror", nvroot, NULL, NULL, NULL));
spa_create("ztest_bad_mirror", nvroot, NULL, NULL));
nvlist_free(nvroot);
/*
@ -2349,7 +2349,7 @@ ztest_spa_create_destroy(ztest_ds_t *zd, uint64_t id)
*/
(void) rw_rdlock(&ztest_name_lock);
nvroot = make_vdev_root("/dev/bogus", NULL, NULL, 0, 0, 0, 0, 0, 1);
VERIFY3U(EEXIST, ==, spa_create(zo->zo_pool, nvroot, NULL, NULL, NULL));
VERIFY3U(EEXIST, ==, spa_create(zo->zo_pool, nvroot, NULL, NULL));
nvlist_free(nvroot);
VERIFY3U(0, ==, spa_open(zo->zo_pool, &spa, FTAG));
VERIFY3U(EBUSY, ==, spa_destroy(zo->zo_pool));
@ -2407,7 +2407,7 @@ ztest_spa_upgrade(ztest_ds_t *zd, uint64_t id)
props = fnvlist_alloc();
fnvlist_add_uint64(props,
zpool_prop_to_name(ZPOOL_PROP_VERSION), version);
VERIFY0(spa_create(name, nvroot, props, NULL, NULL));
VERIFY0(spa_create(name, nvroot, props, NULL));
fnvlist_free(nvroot);
fnvlist_free(props);
@ -2481,8 +2481,7 @@ ztest_vdev_add_remove(ztest_ds_t *zd, uint64_t id)
int error;
VERIFY(mutex_lock(&ztest_vdev_lock) == 0);
leaves =
MAX(zs->zs_mirrors + zs->zs_splits, 1) * ztest_opts.zo_raidz;
leaves = MAX(zs->zs_mirrors + zs->zs_splits, 1) * ztest_opts.zo_raidz;
spa_config_enter(spa, SCL_VDEV, FTAG, RW_READER);
@ -3182,7 +3181,7 @@ ztest_objset_destroy_cb(const char *name, void *arg)
/*
* Verify that the dataset contains a directory object.
*/
VERIFY3U(0, ==, dmu_objset_hold(name, FTAG, &os));
VERIFY0(dmu_objset_own(name, DMU_OST_OTHER, B_TRUE, FTAG, &os));
error = dmu_object_info(os, ZTEST_DIROBJ, &doi);
if (error != ENOENT) {
/* We could have crashed in the middle of destroying it */
@ -3190,12 +3189,16 @@ ztest_objset_destroy_cb(const char *name, void *arg)
ASSERT3U(doi.doi_type, ==, DMU_OT_ZAP_OTHER);
ASSERT3S(doi.doi_physical_blocks_512, >=, 0);
}
dmu_objset_rele(os, FTAG);
dmu_objset_disown(os, FTAG);
/*
* Destroy the dataset.
*/
VERIFY3U(0, ==, dmu_objset_destroy(name, B_FALSE));
if (strchr(name, '@') != NULL) {
VERIFY0(dsl_destroy_snapshot(name, B_FALSE));
} else {
VERIFY0(dsl_destroy_head(name));
}
return (0);
}
@ -3205,17 +3208,17 @@ ztest_snapshot_create(char *osname, uint64_t id)
char snapname[MAXNAMELEN];
int error;
(void) snprintf(snapname, MAXNAMELEN, "%s@%llu", osname,
(u_longlong_t)id);
(void) snprintf(snapname, sizeof (snapname), "%llu", (u_longlong_t)id);
error = dmu_objset_snapshot(osname, strchr(snapname, '@') + 1,
NULL, NULL, B_FALSE, B_FALSE, -1);
error = dmu_objset_snapshot_one(osname, snapname);
if (error == ENOSPC) {
ztest_record_enospc(FTAG);
return (B_FALSE);
}
if (error != 0 && error != EEXIST)
fatal(0, "ztest_snapshot_create(%s) = %d", snapname, error);
if (error != 0 && error != EEXIST) {
fatal(0, "ztest_snapshot_create(%s@%s) = %d", osname,
snapname, error);
}
return (B_TRUE);
}
@ -3228,7 +3231,7 @@ ztest_snapshot_destroy(char *osname, uint64_t id)
(void) snprintf(snapname, MAXNAMELEN, "%s@%llu", osname,
(u_longlong_t)id);
error = dmu_objset_destroy(snapname, B_FALSE);
error = dsl_destroy_snapshot(snapname, B_FALSE);
if (error != 0 && error != ENOENT)
fatal(0, "ztest_snapshot_destroy(%s) = %d", snapname, error);
return (B_TRUE);
@ -3274,7 +3277,8 @@ ztest_dmu_objset_create_destroy(ztest_ds_t *zd, uint64_t id)
/*
* Verify that the destroyed dataset is no longer in the namespace.
*/
VERIFY3U(ENOENT, ==, dmu_objset_hold(name, FTAG, &os));
VERIFY3U(ENOENT, ==, dmu_objset_own(name, DMU_OST_OTHER, B_TRUE,
FTAG, &os));
/*
* Verify that we can create a new dataset.
@ -3289,8 +3293,7 @@ ztest_dmu_objset_create_destroy(ztest_ds_t *zd, uint64_t id)
fatal(0, "dmu_objset_create(%s) = %d", name, error);
}
VERIFY3U(0, ==,
dmu_objset_own(name, DMU_OST_OTHER, B_FALSE, FTAG, &os));
VERIFY0(dmu_objset_own(name, DMU_OST_OTHER, B_FALSE, FTAG, &os));
ztest_zd_init(&zdtmp, NULL, os);
@ -3366,21 +3369,21 @@ ztest_dsl_dataset_cleanup(char *osname, uint64_t id)
(void) snprintf(clone2name, MAXNAMELEN, "%s/c2_%llu", osname, id);
(void) snprintf(snap3name, MAXNAMELEN, "%s@s3_%llu", clone1name, id);
error = dmu_objset_destroy(clone2name, B_FALSE);
error = dsl_destroy_head(clone2name);
if (error && error != ENOENT)
fatal(0, "dmu_objset_destroy(%s) = %d", clone2name, error);
error = dmu_objset_destroy(snap3name, B_FALSE);
fatal(0, "dsl_destroy_head(%s) = %d", clone2name, error);
error = dsl_destroy_snapshot(snap3name, B_FALSE);
if (error && error != ENOENT)
fatal(0, "dmu_objset_destroy(%s) = %d", snap3name, error);
error = dmu_objset_destroy(snap2name, B_FALSE);
fatal(0, "dsl_destroy_snapshot(%s) = %d", snap3name, error);
error = dsl_destroy_snapshot(snap2name, B_FALSE);
if (error && error != ENOENT)
fatal(0, "dmu_objset_destroy(%s) = %d", snap2name, error);
error = dmu_objset_destroy(clone1name, B_FALSE);
fatal(0, "dsl_destroy_snapshot(%s) = %d", snap2name, error);
error = dsl_destroy_head(clone1name);
if (error && error != ENOENT)
fatal(0, "dmu_objset_destroy(%s) = %d", clone1name, error);
error = dmu_objset_destroy(snap1name, B_FALSE);
fatal(0, "dsl_destroy_head(%s) = %d", clone1name, error);
error = dsl_destroy_snapshot(snap1name, B_FALSE);
if (error && error != ENOENT)
fatal(0, "dmu_objset_destroy(%s) = %d", snap1name, error);
fatal(0, "dsl_destroy_snapshot(%s) = %d", snap1name, error);
}
/*
@ -3389,8 +3392,7 @@ ztest_dsl_dataset_cleanup(char *osname, uint64_t id)
void
ztest_dsl_dataset_promote_busy(ztest_ds_t *zd, uint64_t id)
{
objset_t *clone;
dsl_dataset_t *ds;
objset_t *os;
char snap1name[MAXNAMELEN];
char clone1name[MAXNAMELEN];
char snap2name[MAXNAMELEN];
@ -3409,8 +3411,7 @@ ztest_dsl_dataset_promote_busy(ztest_ds_t *zd, uint64_t id)
(void) snprintf(clone2name, MAXNAMELEN, "%s/c2_%llu", osname, id);
(void) snprintf(snap3name, MAXNAMELEN, "%s@s3_%llu", clone1name, id);
error = dmu_objset_snapshot(osname, strchr(snap1name, '@')+1,
NULL, NULL, B_FALSE, B_FALSE, -1);
error = dmu_objset_snapshot_one(osname, strchr(snap1name, '@') + 1);
if (error && error != EEXIST) {
if (error == ENOSPC) {
ztest_record_enospc(FTAG);
@ -3419,12 +3420,7 @@ ztest_dsl_dataset_promote_busy(ztest_ds_t *zd, uint64_t id)
fatal(0, "dmu_take_snapshot(%s) = %d", snap1name, error);
}
error = dmu_objset_hold(snap1name, FTAG, &clone);
if (error)
fatal(0, "dmu_open_snapshot(%s) = %d", snap1name, error);
error = dmu_objset_clone(clone1name, dmu_objset_ds(clone), 0);
dmu_objset_rele(clone, FTAG);
error = dmu_objset_clone(clone1name, snap1name);
if (error) {
if (error == ENOSPC) {
ztest_record_enospc(FTAG);
@ -3433,8 +3429,7 @@ ztest_dsl_dataset_promote_busy(ztest_ds_t *zd, uint64_t id)
fatal(0, "dmu_objset_create(%s) = %d", clone1name, error);
}
error = dmu_objset_snapshot(clone1name, strchr(snap2name, '@')+1,
NULL, NULL, B_FALSE, B_FALSE, -1);
error = dmu_objset_snapshot_one(clone1name, strchr(snap2name, '@') + 1);
if (error && error != EEXIST) {
if (error == ENOSPC) {
ztest_record_enospc(FTAG);
@ -3443,8 +3438,7 @@ ztest_dsl_dataset_promote_busy(ztest_ds_t *zd, uint64_t id)
fatal(0, "dmu_open_snapshot(%s) = %d", snap2name, error);
}
error = dmu_objset_snapshot(clone1name, strchr(snap3name, '@')+1,
NULL, NULL, B_FALSE, B_FALSE, -1);
error = dmu_objset_snapshot_one(clone1name, strchr(snap3name, '@') + 1);
if (error && error != EEXIST) {
if (error == ENOSPC) {
ztest_record_enospc(FTAG);
@ -3453,12 +3447,7 @@ ztest_dsl_dataset_promote_busy(ztest_ds_t *zd, uint64_t id)
fatal(0, "dmu_open_snapshot(%s) = %d", snap3name, error);
}
error = dmu_objset_hold(snap3name, FTAG, &clone);
if (error)
fatal(0, "dmu_open_snapshot(%s) = %d", snap3name, error);
error = dmu_objset_clone(clone2name, dmu_objset_ds(clone), 0);
dmu_objset_rele(clone, FTAG);
error = dmu_objset_clone(clone2name, snap3name);
if (error) {
if (error == ENOSPC) {
ztest_record_enospc(FTAG);
@ -3467,14 +3456,14 @@ ztest_dsl_dataset_promote_busy(ztest_ds_t *zd, uint64_t id)
fatal(0, "dmu_objset_create(%s) = %d", clone2name, error);
}
error = dsl_dataset_own(snap2name, B_FALSE, FTAG, &ds);
error = dmu_objset_own(snap2name, DMU_OST_ANY, B_TRUE, FTAG, &os);
if (error)
fatal(0, "dsl_dataset_own(%s) = %d", snap2name, error);
fatal(0, "dmu_objset_own(%s) = %d", snap2name, error);
error = dsl_dataset_promote(clone2name, NULL);
if (error != EBUSY)
fatal(0, "dsl_dataset_promote(%s), %d, not EBUSY", clone2name,
error);
dsl_dataset_disown(ds, FTAG);
dmu_objset_disown(os, FTAG);
out:
ztest_dsl_dataset_cleanup(osname, id);
@ -4286,7 +4275,7 @@ ztest_zap_parallel(ztest_ds_t *zd, uint64_t id)
}
count = -1ULL;
VERIFY(zap_count(os, object, &count) == 0);
VERIFY0(zap_count(os, object, &count));
ASSERT(count != -1ULL);
/*
@ -4597,6 +4586,22 @@ ztest_spa_prop_get_set(ztest_ds_t *zd, uint64_t id)
(void) rw_unlock(&ztest_name_lock);
}
static int
user_release_one(const char *snapname, const char *holdname)
{
nvlist_t *snaps, *holds;
int error;
snaps = fnvlist_alloc();
holds = fnvlist_alloc();
fnvlist_add_boolean(holds, holdname);
fnvlist_add_nvlist(snaps, snapname, holds);
fnvlist_free(holds);
error = dsl_dataset_user_release(snaps, NULL);
fnvlist_free(snaps);
return (error);
}
/*
* Test snapshot hold/release and deferred destroy.
*/
@ -4611,29 +4616,36 @@ ztest_dmu_snapshot_hold(ztest_ds_t *zd, uint64_t id)
char clonename[100];
char tag[100];
char osname[MAXNAMELEN];
nvlist_t *holds;
(void) rw_rdlock(&ztest_name_lock);
dmu_objset_name(os, osname);
(void) snprintf(snapname, 100, "sh1_%llu", id);
(void) snprintf(fullname, 100, "%s@%s", osname, snapname);
(void) snprintf(clonename, 100, "%s/ch1_%llu", osname, id);
(void) snprintf(tag, 100, "%tag_%llu", id);
(void) snprintf(snapname, sizeof (snapname), "sh1_%llu", id);
(void) snprintf(fullname, sizeof (fullname), "%s@%s", osname, snapname);
(void) snprintf(clonename, sizeof (clonename),
"%s/ch1_%llu", osname, id);
(void) snprintf(tag, sizeof (tag), "tag_%llu", id);
/*
* Clean up from any previous run.
*/
(void) dmu_objset_destroy(clonename, B_FALSE);
(void) dsl_dataset_user_release(osname, snapname, tag, B_FALSE);
(void) dmu_objset_destroy(fullname, B_FALSE);
error = dsl_destroy_head(clonename);
if (error != ENOENT)
ASSERT0(error);
error = user_release_one(fullname, tag);
if (error != ESRCH && error != ENOENT)
ASSERT0(error);
error = dsl_destroy_snapshot(fullname, B_FALSE);
if (error != ENOENT)
ASSERT0(error);
/*
* Create snapshot, clone it, mark snap for deferred destroy,
* destroy clone, verify snap was also destroyed.
*/
error = dmu_objset_snapshot(osname, snapname, NULL, NULL, FALSE,
FALSE, -1);
error = dmu_objset_snapshot_one(osname, snapname);
if (error) {
if (error == ENOSPC) {
ztest_record_enospc("dmu_objset_snapshot");
@ -4642,12 +4654,7 @@ ztest_dmu_snapshot_hold(ztest_ds_t *zd, uint64_t id)
fatal(0, "dmu_objset_snapshot(%s) = %d", fullname, error);
}
error = dmu_objset_hold(fullname, FTAG, &origin);
if (error)
fatal(0, "dmu_objset_hold(%s) = %d", fullname, error);
error = dmu_objset_clone(clonename, dmu_objset_ds(origin), 0);
dmu_objset_rele(origin, FTAG);
error = dmu_objset_clone(clonename, fullname);
if (error) {
if (error == ENOSPC) {
ztest_record_enospc("dmu_objset_clone");
@ -4656,15 +4663,15 @@ ztest_dmu_snapshot_hold(ztest_ds_t *zd, uint64_t id)
fatal(0, "dmu_objset_clone(%s) = %d", clonename, error);
}
error = dmu_objset_destroy(fullname, B_TRUE);
error = dsl_destroy_snapshot(fullname, B_TRUE);
if (error) {
fatal(0, "dmu_objset_destroy(%s, B_TRUE) = %d",
fatal(0, "dsl_destroy_snapshot(%s, B_TRUE) = %d",
fullname, error);
}
error = dmu_objset_destroy(clonename, B_FALSE);
error = dsl_destroy_head(clonename);
if (error)
fatal(0, "dmu_objset_destroy(%s) = %d", clonename, error);
fatal(0, "dsl_destroy_head(%s) = %d", clonename, error);
error = dmu_objset_hold(fullname, FTAG, &origin);
if (error != ENOENT)
@ -4675,8 +4682,7 @@ ztest_dmu_snapshot_hold(ztest_ds_t *zd, uint64_t id)
* destroy a held snapshot, mark for deferred destroy,
* release hold, verify snapshot was destroyed.
*/
error = dmu_objset_snapshot(osname, snapname, NULL, NULL, FALSE,
FALSE, -1);
error = dmu_objset_snapshot_one(osname, snapname);
if (error) {
if (error == ENOSPC) {
ztest_record_enospc("dmu_objset_snapshot");
@ -4685,28 +4691,31 @@ ztest_dmu_snapshot_hold(ztest_ds_t *zd, uint64_t id)
fatal(0, "dmu_objset_snapshot(%s) = %d", fullname, error);
}
error = dsl_dataset_user_hold(osname, snapname, tag, B_FALSE,
B_TRUE, -1);
holds = fnvlist_alloc();
fnvlist_add_string(holds, fullname, tag);
error = dsl_dataset_user_hold(holds, 0, NULL);
fnvlist_free(holds);
if (error)
fatal(0, "dsl_dataset_user_hold(%s)", fullname, tag);
error = dmu_objset_destroy(fullname, B_FALSE);
error = dsl_destroy_snapshot(fullname, B_FALSE);
if (error != EBUSY) {
fatal(0, "dmu_objset_destroy(%s, B_FALSE) = %d",
fatal(0, "dsl_destroy_snapshot(%s, B_FALSE) = %d",
fullname, error);
}
error = dmu_objset_destroy(fullname, B_TRUE);
error = dsl_destroy_snapshot(fullname, B_TRUE);
if (error) {
fatal(0, "dmu_objset_destroy(%s, B_TRUE) = %d",
fatal(0, "dsl_destroy_snapshot(%s, B_TRUE) = %d",
fullname, error);
}
error = dsl_dataset_user_release(osname, snapname, tag, B_FALSE);
error = user_release_one(fullname, tag);
if (error)
fatal(0, "dsl_dataset_user_release(%s)", fullname, tag);
fatal(0, "user_release_one(%s)", fullname, tag);
VERIFY(dmu_objset_hold(fullname, FTAG, &origin) == ENOENT);
VERIFY3U(dmu_objset_hold(fullname, FTAG, &origin), ==, ENOENT);
out:
(void) rw_unlock(&ztest_name_lock);
@ -4960,8 +4969,12 @@ ztest_ddt_repair(ztest_ds_t *zd, uint64_t id)
*/
for (int i = 0; i < copies; i++) {
uint64_t offset = i * blocksize;
VERIFY0(dmu_buf_hold(os, object, offset, FTAG, &db,
DMU_READ_NO_PREFETCH));
int error = dmu_buf_hold(os, object, offset, FTAG, &db,
DMU_READ_NO_PREFETCH);
if (error != 0) {
fatal(B_FALSE, "dmu_buf_hold(%p, %llu, %llu) = %u",
os, (long long)object, (long long) offset, error);
}
ASSERT(db->db_offset == offset);
ASSERT(db->db_size == blocksize);
ASSERT(ztest_pattern_match(db->db_data, db->db_size, pattern) ||
@ -5172,6 +5185,7 @@ ztest_spa_import_export(char *oldname, char *newname)
nvlist_t *config, *newconfig;
uint64_t pool_guid;
spa_t *spa;
int error;
if (ztest_opts.zo_verbose >= 4) {
(void) printf("import/export: old = %s, new = %s\n",
@ -5216,7 +5230,12 @@ ztest_spa_import_export(char *oldname, char *newname)
/*
* Import it under the new name.
*/
VERIFY3U(0, ==, spa_import(newname, config, NULL, 0));
error = spa_import(newname, config, NULL, 0);
if (error != 0) {
dump_nvlist(config, 0);
fatal(B_FALSE, "couldn't import pool %s as %s: error %u",
oldname, newname, error);
}
ztest_walk_pool_directory("pools after import");
@ -5423,7 +5442,7 @@ ztest_dataset_open(int d)
}
ASSERT(error == 0 || error == EEXIST);
VERIFY0(dmu_objset_hold(name, zd, &os));
VERIFY0(dmu_objset_own(name, DMU_OST_OTHER, B_FALSE, zd, &os));
(void) rw_unlock(&ztest_name_lock);
ztest_zd_init(zd, ZTEST_GET_SHARED_DS(d), os);
@ -5464,7 +5483,7 @@ ztest_dataset_close(int d)
ztest_ds_t *zd = &ztest_ds[d];
zil_close(zd->zd_zilog);
dmu_objset_rele(zd->zd_os, zd);
dmu_objset_disown(zd->zd_os, zd);
ztest_zd_fini(zd);
}
@ -5508,13 +5527,14 @@ ztest_run(ztest_shared_t *zs)
* Open our pool.
*/
kernel_init(FREAD | FWRITE);
VERIFY(spa_open(ztest_opts.zo_pool, &spa, FTAG) == 0);
VERIFY0(spa_open(ztest_opts.zo_pool, &spa, FTAG));
spa->spa_debug = B_TRUE;
ztest_spa = spa;
VERIFY3U(0, ==, dmu_objset_hold(ztest_opts.zo_pool, FTAG, &os));
VERIFY0(dmu_objset_own(ztest_opts.zo_pool,
DMU_OST_ANY, B_TRUE, FTAG, &os));
zs->zs_guid = dmu_objset_fsid_guid(os);
dmu_objset_rele(os, FTAG);
dmu_objset_disown(os, FTAG);
spa->spa_dedup_ditto = 2 * ZIO_DEDUPDITTO_MIN;
@ -5791,8 +5811,7 @@ ztest_init(ztest_shared_t *zs)
spa_feature_table[i].fi_uname);
VERIFY3U(0, ==, nvlist_add_uint64(props, buf, 0));
}
VERIFY3U(0, ==, spa_create(ztest_opts.zo_pool, nvroot, props,
NULL, NULL));
VERIFY3U(0, ==, spa_create(ztest_opts.zo_pool, nvroot, props, NULL));
nvlist_free(nvroot);
VERIFY3U(0, ==, spa_open(ztest_opts.zo_pool, &spa, FTAG));

View File

@ -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.
*/
/*
@ -679,13 +680,59 @@ 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`%ld", 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`%ld", dmp->dm_name,
dret->dn_type);
ap->dtad_difo = dt_as(yypcb);
ap->dtad_kind = DTRACEACT_DIFEXPR;
}
static void
dt_action_tracemem(dtrace_hdl_t *dtp, dt_node_t *dnp, dtrace_stmtdesc_t *sdp)
{
dtrace_actdesc_t *ap = dt_stmt_action(dtp, sdp);
dt_node_t *addr = dnp->dn_args;
dt_node_t *size = dnp->dn_args->dn_list;
dt_node_t *max = dnp->dn_args->dn_list;
dt_node_t *size;
char n[DT_TYPE_NAMELEN];
@ -697,17 +744,37 @@ dt_action_tracemem(dtrace_hdl_t *dtp, dt_node_t *dnp, dtrace_stmtdesc_t *sdp)
dt_node_type_name(addr, n, sizeof (n)));
}
if (dt_node_is_posconst(size) == 0) {
dnerror(size, D_TRACEMEM_SIZE, "tracemem( ) argument #2 must "
if (dt_node_is_posconst(max) == 0) {
dnerror(max, D_TRACEMEM_SIZE, "tracemem( ) argument #2 must "
"be a non-zero positive integral constant expression\n");
}
if ((size = max->dn_list) != NULL) {
if (size->dn_list != NULL) {
dnerror(size, D_TRACEMEM_ARGS, "tracemem ( ) prototype "
"mismatch: expected at most 3 args\n");
}
if (!dt_node_is_scalar(size)) {
dnerror(size, D_TRACEMEM_DYNSIZE, "tracemem ( ) "
"dynamic size (argument #3) must be of "
"scalar type\n");
}
dt_cg(yypcb, size);
ap->dtad_difo = dt_as(yypcb);
ap->dtad_difo->dtdo_rtype = dt_int_rtype;
ap->dtad_kind = DTRACEACT_TRACEMEM_DYNSIZE;
ap = dt_stmt_action(dtp, sdp);
}
dt_cg(yypcb, addr);
ap->dtad_difo = dt_as(yypcb);
ap->dtad_kind = DTRACEACT_DIFEXPR;
ap->dtad_kind = DTRACEACT_TRACEMEM;
ap->dtad_difo->dtdo_rtype.dtdt_flags |= DIF_TF_BYREF;
ap->dtad_difo->dtdo_rtype.dtdt_size = size->dn_value;
ap->dtad_difo->dtdo_rtype.dtdt_size = max->dn_value;
}
static void
@ -1114,6 +1181,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;

View File

@ -25,6 +25,7 @@
/*
* Copyright (c) 2011, Joyent, Inc. All rights reserved.
* Copyright (c) 2011 by Delphix. All rights reserved.
*/
#include <stdlib.h>
@ -832,7 +833,7 @@ dt_print_stddev(dtrace_hdl_t *dtp, FILE *fp, caddr_t addr,
/*ARGSUSED*/
int
dt_print_bytes(dtrace_hdl_t *dtp, FILE *fp, caddr_t addr,
size_t nbytes, int width, int quiet, int raw)
size_t nbytes, int width, int quiet, int forceraw)
{
/*
* If the byte stream is a series of printable characters, followed by
@ -845,7 +846,10 @@ dt_print_bytes(dtrace_hdl_t *dtp, FILE *fp, caddr_t addr,
if (nbytes == 0)
return (0);
if (raw || dtp->dt_options[DTRACEOPT_RAWBYTES] != DTRACEOPT_UNSET)
if (forceraw)
goto raw;
if (dtp->dt_options[DTRACEOPT_RAWBYTES] != DTRACEOPT_UNSET)
goto raw;
for (i = 0; i < nbytes; i++) {
@ -2019,6 +2023,7 @@ dt_consume_cpu(dtrace_hdl_t *dtp, FILE *fp, int cpu, dtrace_bufdesc_t *buf,
int quiet = (dtp->dt_options[DTRACEOPT_QUIET] != DTRACEOPT_UNSET);
int rval, i, n;
dtrace_epid_t last = DTRACE_EPIDNONE;
uint64_t tracememsize = 0;
dtrace_probedata_t data;
uint64_t drops;
caddr_t addr;
@ -2187,6 +2192,13 @@ again:
}
}
if (act == DTRACEACT_TRACEMEM_DYNSIZE &&
rec->dtrd_size == sizeof (uint64_t)) {
/* LINTED - alignment */
tracememsize = *((unsigned long long *)addr);
continue;
}
rval = (*rfunc)(&data, rec, arg);
if (rval == DTRACE_CONSUME_NEXT)
@ -2290,6 +2302,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;
@ -2358,6 +2399,23 @@ nofmt:
goto nextrec;
}
if (act == DTRACEACT_TRACEMEM) {
if (tracememsize == 0 ||
tracememsize > rec->dtrd_size) {
tracememsize = rec->dtrd_size;
}
n = dt_print_bytes(dtp, fp, addr,
tracememsize, 33, quiet, 1);
tracememsize = 0;
if (n < 0)
return (-1);
goto nextrec;
}
switch (rec->dtrd_size) {
case sizeof (uint64_t):
n = dt_printf(dtp, fp,

View File

@ -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>
@ -758,16 +759,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;

View File

@ -24,11 +24,14 @@
* Use is subject to license terms.
*/
/*
* Copyright (c) 2011, Joyent, Inc. All rights reserved.
* Copyright (c) 2011 by Delphix. All rights reserved.
*/
#ifndef _DT_ERRTAGS_H
#define _DT_ERRTAGS_H
#pragma ident "%Z%%M% %I% %E% SMI"
#ifdef __cplusplus
extern "C" {
#endif
@ -187,8 +190,12 @@ typedef enum {
D_PRINTA_AGGPROTO, /* printa() aggregation mismatch */
D_TRACE_VOID, /* trace() argument has void type */
D_TRACE_DYN, /* trace() argument has dynamic type */
D_PRINT_VOID, /* print() argument has void type */
D_PRINT_DYN, /* print() argument has dynamic type */
D_TRACEMEM_ADDR, /* tracemem() address bad type */
D_TRACEMEM_SIZE, /* tracemem() size bad type */
D_TRACEMEM_ARGS, /* tracemem() illegal number of args */
D_TRACEMEM_DYNSIZE, /* tracemem() dynamic size bad type */
D_STACK_PROTO, /* stack() prototype mismatch */
D_STACK_SIZE, /* stack() size argument bad type */
D_USTACK_FRAMES, /* ustack() frames arg bad type */

View File

@ -26,6 +26,7 @@
/*
* Copyright (c) 2011, Joyent, Inc. All rights reserved.
* Copyright (c) 2011 by Delphix. All rights reserved.
*/
#ifndef _DT_IMPL_H
@ -253,6 +254,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 */
@ -438,8 +441,9 @@ 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_PRINTM DT_ACT(29) /* printm() action */
#define DT_ACT_PRINTT DT_ACT(30) /* printt() action */
#define DT_ACT_PRINT DT_ACT(29) /* print() action */
#define DT_ACT_PRINTM DT_ACT(30) /* printm() action */
#define DT_ACT_PRINTT DT_ACT(31) /* printt() action */
/*
* Sentinel to tell freopen() to restore the saved stdout. This must not
@ -641,6 +645,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 *,

View File

@ -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>
@ -34,11 +36,82 @@
#include <dt_impl.h>
#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;
@ -132,71 +205,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;
@ -440,3 +465,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;
}

View File

@ -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>
@ -116,8 +117,12 @@
#define DT_VERS_1_6_2 DT_VERSION_NUMBER(1, 6, 2)
#define DT_VERS_1_6_3 DT_VERSION_NUMBER(1, 6, 3)
#define DT_VERS_1_7 DT_VERSION_NUMBER(1, 7, 0)
#define DT_VERS_LATEST DT_VERS_1_7
#define DT_VERS_STRING "Sun D 1.7"
#define DT_VERS_1_7_1 DT_VERSION_NUMBER(1, 7, 1)
#define DT_VERS_1_8 DT_VERSION_NUMBER(1, 8, 0)
#define DT_VERS_1_8_1 DT_VERSION_NUMBER(1, 8, 1)
#define DT_VERS_1_9 DT_VERSION_NUMBER(1, 9, 0)
#define DT_VERS_LATEST DT_VERS_1_9
#define DT_VERS_STRING "Sun D 1.9"
const dt_version_t _dtrace_versions[] = {
DT_VERS_1_0, /* D API 1.0.0 (PSARC 2001/466) Solaris 10 FCS */
@ -134,6 +139,10 @@ const dt_version_t _dtrace_versions[] = {
DT_VERS_1_6_2, /* D API 1.6.2 */
DT_VERS_1_6_3, /* D API 1.6.3 */
DT_VERS_1_7, /* D API 1.7 */
DT_VERS_1_7_1, /* D API 1.7.1 */
DT_VERS_1_8, /* D API 1.8 */
DT_VERS_1_8_1, /* D API 1.8.1 */
DT_VERS_1_9, /* D API 1.9 */
0
};
@ -289,7 +298,7 @@ static const dt_ident_t _dtrace_globals[] = {
{ "jstack", DT_IDENT_ACTFUNC, 0, DT_ACT_JSTACK, DT_ATTR_STABCMN, DT_VERS_1_0,
&dt_idops_func, "stack(...)" },
{ "lltostr", DT_IDENT_FUNC, 0, DIF_SUBR_LLTOSTR, DT_ATTR_STABCMN, DT_VERS_1_0,
&dt_idops_func, "string(int64_t)" },
&dt_idops_func, "string(int64_t, [int])" },
{ "llquantize", DT_IDENT_AGGFUNC, 0, DTRACEAGG_LLQUANTIZE, DT_ATTR_STABCMN,
DT_VERS_1_7, &dt_idops_func,
"void(@, int32_t, int32_t, int32_t, int32_t, ...)" },
@ -351,6 +360,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,
@ -457,11 +468,15 @@ static const dt_ident_t _dtrace_globals[] = {
{ "timestamp", DT_IDENT_SCALAR, 0, DIF_VAR_TIMESTAMP,
DT_ATTR_STABCMN, DT_VERS_1_0,
&dt_idops_type, "uint64_t" },
{ "tolower", DT_IDENT_FUNC, 0, DIF_SUBR_TOLOWER, DT_ATTR_STABCMN, DT_VERS_1_8,
&dt_idops_func, "string(const char *)" },
{ "toupper", DT_IDENT_FUNC, 0, DIF_SUBR_TOUPPER, DT_ATTR_STABCMN, DT_VERS_1_8,
&dt_idops_func, "string(const char *)" },
{ "trace", DT_IDENT_ACTFUNC, 0, DT_ACT_TRACE, DT_ATTR_STABCMN, DT_VERS_1_0,
&dt_idops_func, "void(@)" },
{ "tracemem", DT_IDENT_ACTFUNC, 0, DT_ACT_TRACEMEM,
DT_ATTR_STABCMN, DT_VERS_1_0,
&dt_idops_func, "void(@, size_t)" },
&dt_idops_func, "void(@, size_t, ...)" },
{ "trunc", DT_IDENT_ACTFUNC, 0, DT_ACT_TRUNC, DT_ATTR_STABCMN,
DT_VERS_1_0, &dt_idops_func, "void(...)" },
{ "typeref", DT_IDENT_FUNC, 0, DIF_SUBR_TYPEREF, DT_ATTR_STABCMN, DT_VERS_1_1,
@ -1115,7 +1130,7 @@ alloc:
#if defined(sun)
dtp->dt_prcmode = DT_PROC_STOP_PREINIT;
#else
dtp->dt_prcmode = DT_PROC_STOP_MAIN;
dtp->dt_prcmode = DT_PROC_STOP_POSTINIT;
#endif
dtp->dt_linkmode = DT_LINK_KERNEL;
dtp->dt_linktype = DT_LTYP_ELF;
@ -1612,6 +1627,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);

View File

@ -0,0 +1,648 @@
/*
* CDDL HEADER START
*
* The contents of this file are subject to the terms of the
* Common Development and Distribution License (the "License").
* You may not use this file except in compliance with the License.
*
* You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE
* or http://www.opensolaris.org/os/licensing.
* See the License for the specific language governing permissions
* and limitations under the License.
*
* When distributing Covered Code, include this CDDL HEADER in each
* file and include the License file at usr/src/OPENSOLARIS.LICENSE.
* If applicable, add the following below this CDDL HEADER, with the
* fields enclosed by brackets "[]" replaced with your own identifying
* information: Portions Copyright [yyyy] [name of copyright owner]
*
* CDDL HEADER END
*/
/*
* Copyright 2009 Sun Microsystems, Inc. All rights reserved.
* Use is subject to license terms.
*/
/*
* Copyright (c) 2011 by Delphix. All rights reserved.
*/
/*
* DTrace print() action
*
* This file contains the post-processing logic for the print() action. The
* print action behaves identically to trace() in that it generates a
* DTRACEACT_DIFEXPR action, but the action argument field refers to a CTF type
* string stored in the DOF string table (similar to printf formats). We
* take the result of the trace action and post-process it in the fashion of
* MDB's ::print dcmd.
*
* This implementation differs from MDB's in the following ways:
*
* - We do not expose any options or flags. The behavior of print() is
* equivalent to "::print -tn".
*
* - MDB will display "holes" in structures (unused padding between
* members).
*
* - When printing arrays of structures, MDB will leave a trailing ','
* after the last element.
*
* - MDB will print time_t types as date and time.
*
* - MDB will detect when an enum is actually the OR of several flags,
* and print it out with the constituent flags separated.
*
* - For large arrays, MDB will print the first few members and then
* print a "..." continuation line.
*
* - MDB will break and wrap arrays at 80 columns.
*
* - MDB prints out floats and doubles by hand, as it must run in kmdb
* context. We're able to leverage the printf() format strings,
* but the result is a slightly different format.
*/
#include <sys/sysmacros.h>
#include <strings.h>
#include <stdlib.h>
#include <alloca.h>
#include <assert.h>
#include <ctype.h>
#include <errno.h>
#include <limits.h>
#include <sys/socket.h>
#include <netdb.h>
#include <netinet/in.h>
#include <arpa/inet.h>
#include <arpa/nameser.h>
#include <dt_module.h>
#include <dt_printf.h>
#include <dt_string.h>
#include <dt_impl.h>
/* determines whether the given integer CTF encoding is a character */
#define CTF_IS_CHAR(e) \
(((e).cte_format & (CTF_INT_CHAR | CTF_INT_SIGNED)) == \
(CTF_INT_CHAR | CTF_INT_SIGNED) && (e).cte_bits == NBBY)
/* determines whether the given CTF kind is a struct or union */
#define CTF_IS_STRUCTLIKE(k) \
((k) == CTF_K_STRUCT || (k) == CTF_K_UNION)
/*
* Print structure passed down recursively through printing algorithm.
*/
typedef struct dt_printarg {
caddr_t pa_addr; /* base address of trace data */
ctf_file_t *pa_ctfp; /* CTF container */
int pa_depth; /* member depth */
int pa_nest; /* nested array depth */
FILE *pa_file; /* output file */
} dt_printarg_t;
static int dt_print_member(const char *, ctf_id_t, ulong_t, int, void *);
/*
* Safe version of ctf_type_name() that will fall back to just "<ctfid>" if it
* can't resolve the type.
*/
static void
dt_print_type_name(ctf_file_t *ctfp, ctf_id_t id, char *buf, size_t buflen)
{
if (ctf_type_name(ctfp, id, buf, buflen) == NULL)
(void) snprintf(buf, buflen, "<%ld>", id);
}
/*
* Print any necessary trailing braces for structures or unions. We don't get
* invoked when a struct or union ends, so we infer the need to print braces
* based on the depth the last time we printed something and the new depth.
*/
static void
dt_print_trailing_braces(dt_printarg_t *pap, int depth)
{
int d;
for (d = pap->pa_depth; d > depth; d--) {
(void) fprintf(pap->pa_file, "%*s}%s",
(d + pap->pa_nest - 1) * 4, "",
d == depth + 1 ? "" : "\n");
}
}
/*
* Print the appropriate amount of indentation given the current depth and
* array nesting.
*/
static void
dt_print_indent(dt_printarg_t *pap)
{
(void) fprintf(pap->pa_file, "%*s",
(pap->pa_depth + pap->pa_nest) * 4, "");
}
/*
* Print a bitfield. It's worth noting that the D compiler support for
* bitfields is currently broken; printing "D`user_desc_t" (pulled in by the
* various D provider files) will produce incorrect results compared to
* "genunix`user_desc_t".
*/
static void
print_bitfield(dt_printarg_t *pap, ulong_t off, ctf_encoding_t *ep)
{
FILE *fp = pap->pa_file;
caddr_t addr = pap->pa_addr + off / NBBY;
uint64_t mask = (1ULL << ep->cte_bits) - 1;
uint64_t value = 0;
size_t size = (ep->cte_bits + (NBBY - 1)) / NBBY;
uint8_t *buf = (uint8_t *)&value;
uint8_t shift;
/*
* On big-endian machines, we need to adjust the buf pointer to refer
* to the lowest 'size' bytes in 'value', and we need to shift based on
* the offset from the end of the data, not the offset of the start.
*/
#ifdef _BIG_ENDIAN
buf += sizeof (value) - size;
off += ep->cte_bits;
#endif
bcopy(addr, buf, size);
shift = off % NBBY;
/*
* Offsets are counted from opposite ends on little- and
* big-endian machines.
*/
#ifdef _BIG_ENDIAN
shift = NBBY - shift;
#endif
/*
* If the bits we want do not begin on a byte boundary, shift the data
* right so that the value is in the lowest 'cte_bits' of 'value'.
*/
if (off % NBBY != 0)
value >>= shift;
value &= mask;
(void) fprintf(fp, "%#llx", (u_longlong_t)value);
}
/*
* Dump the contents of memory as a fixed-size integer in hex.
*/
static void
dt_print_hex(FILE *fp, caddr_t addr, size_t size)
{
switch (size) {
case sizeof (uint8_t):
(void) fprintf(fp, "%#x", *(uint8_t *)addr);
break;
case sizeof (uint16_t):
/* LINTED - alignment */
(void) fprintf(fp, "%#x", *(uint16_t *)addr);
break;
case sizeof (uint32_t):
/* LINTED - alignment */
(void) fprintf(fp, "%#x", *(uint32_t *)addr);
break;
case sizeof (uint64_t):
(void) fprintf(fp, "%#llx",
/* LINTED - alignment */
(unsigned long long)*(uint64_t *)addr);
break;
default:
(void) fprintf(fp, "<invalid size %u>", (uint_t)size);
}
}
/*
* Print an integer type. Before dumping the contents via dt_print_hex(), we
* first check the encoding to see if it's part of a bitfield or a character.
*/
static void
dt_print_int(ctf_id_t base, ulong_t off, dt_printarg_t *pap)
{
FILE *fp = pap->pa_file;
ctf_file_t *ctfp = pap->pa_ctfp;
ctf_encoding_t e;
size_t size;
caddr_t addr = pap->pa_addr + off / NBBY;
if (ctf_type_encoding(ctfp, base, &e) == CTF_ERR) {
(void) fprintf(fp, "<unknown encoding>");
return;
}
/*
* This comes from MDB - it's not clear under what circumstances this
* would be found.
*/
if (e.cte_format & CTF_INT_VARARGS) {
(void) fprintf(fp, "...");
return;
}
/*
* We print this as a bitfield if the bit encoding indicates it's not
* an even power of two byte size, or is larger than 8 bytes.
*/
size = e.cte_bits / NBBY;
if (size > 8 || (e.cte_bits % NBBY) != 0 || (size & (size - 1)) != 0) {
print_bitfield(pap, off, &e);
return;
}
/*
* If this is a character, print it out as such.
*/
if (CTF_IS_CHAR(e)) {
char c = *(char *)addr;
if (isprint(c))
(void) fprintf(fp, "'%c'", c);
else if (c == 0)
(void) fprintf(fp, "'\\0'");
else
(void) fprintf(fp, "'\\%03o'", c);
return;
}
dt_print_hex(fp, addr, size);
}
/*
* Print a floating point (float, double, long double) value.
*/
/* ARGSUSED */
static void
dt_print_float(ctf_id_t base, ulong_t off, dt_printarg_t *pap)
{
FILE *fp = pap->pa_file;
ctf_file_t *ctfp = pap->pa_ctfp;
ctf_encoding_t e;
caddr_t addr = pap->pa_addr + off / NBBY;
if (ctf_type_encoding(ctfp, base, &e) == 0) {
if (e.cte_format == CTF_FP_SINGLE &&
e.cte_bits == sizeof (float) * NBBY) {
/* LINTED - alignment */
(void) fprintf(fp, "%+.7e", *((float *)addr));
} else if (e.cte_format == CTF_FP_DOUBLE &&
e.cte_bits == sizeof (double) * NBBY) {
/* LINTED - alignment */
(void) fprintf(fp, "%+.7e", *((double *)addr));
} else if (e.cte_format == CTF_FP_LDOUBLE &&
e.cte_bits == sizeof (long double) * NBBY) {
/* LINTED - alignment */
(void) fprintf(fp, "%+.16LE", *((long double *)addr));
} else {
(void) fprintf(fp, "<unknown encoding>");
}
}
}
/*
* A pointer is printed as a fixed-size integer. This is used both for
* pointers and functions.
*/
static void
dt_print_ptr(ctf_id_t base, ulong_t off, dt_printarg_t *pap)
{
FILE *fp = pap->pa_file;
ctf_file_t *ctfp = pap->pa_ctfp;
caddr_t addr = pap->pa_addr + off / NBBY;
size_t size = ctf_type_size(ctfp, base);
dt_print_hex(fp, addr, size);
}
/*
* Print out an array. This is somewhat complex, as we must manually visit
* each member, and recursively invoke ctf_type_visit() for each member. If
* the members are non-structs, then we print them out directly:
*
* [ 0x14, 0x2e, 0 ]
*
* If they are structs, then we print out the necessary leading and trailing
* braces, to end up with:
*
* [
* type {
* ...
* },
* type {
* ...
* }
* ]
*
* We also use a heuristic to detect whether the array looks like a character
* array. If the encoding indicates it's a character, and we have all
* printable characters followed by a null byte, then we display it as a
* string:
*
* [ "string" ]
*/
static void
dt_print_array(ctf_id_t base, ulong_t off, dt_printarg_t *pap)
{
FILE *fp = pap->pa_file;
ctf_file_t *ctfp = pap->pa_ctfp;
caddr_t addr = pap->pa_addr + off / NBBY;
ctf_arinfo_t car;
ssize_t eltsize;
ctf_encoding_t e;
int i;
boolean_t isstring;
int kind;
ctf_id_t rtype;
if (ctf_array_info(ctfp, base, &car) == CTF_ERR) {
(void) fprintf(fp, "0x%p", (void *)addr);
return;
}
if ((eltsize = ctf_type_size(ctfp, car.ctr_contents)) < 0 ||
(rtype = ctf_type_resolve(ctfp, car.ctr_contents)) == CTF_ERR ||
(kind = ctf_type_kind(ctfp, rtype)) == CTF_ERR) {
(void) fprintf(fp, "<invalid type %lu>", car.ctr_contents);
return;
}
/* see if this looks like a string */
isstring = B_FALSE;
if (kind == CTF_K_INTEGER &&
ctf_type_encoding(ctfp, rtype, &e) != CTF_ERR && CTF_IS_CHAR(e)) {
char c;
for (i = 0; i < car.ctr_nelems; i++) {
c = *((char *)addr + eltsize * i);
if (!isprint(c) || c == '\0')
break;
}
if (i != car.ctr_nelems && c == '\0')
isstring = B_TRUE;
}
/*
* As a slight aesthetic optimization, if we are a top-level type, then
* don't bother printing out the brackets. This lets print("foo") look
* like:
*
* string "foo"
*
* As D will internally represent this as a char[256] array.
*/
if (!isstring || pap->pa_depth != 0)
(void) fprintf(fp, "[ ");
if (isstring)
(void) fprintf(fp, "\"");
for (i = 0; i < car.ctr_nelems; i++) {
if (isstring) {
char c = *((char *)addr + eltsize * i);
if (c == '\0')
break;
(void) fprintf(fp, "%c", c);
} else {
/*
* Recursively invoke ctf_type_visit() on each member.
* We setup a new printarg struct with 'pa_nest' set to
* indicate that we are within a nested array.
*/
dt_printarg_t pa = *pap;
pa.pa_nest += pap->pa_depth + 1;
pa.pa_depth = 0;
pa.pa_addr = addr + eltsize * i;
(void) ctf_type_visit(ctfp, car.ctr_contents,
dt_print_member, &pa);
dt_print_trailing_braces(&pa, 0);
if (i != car.ctr_nelems - 1)
(void) fprintf(fp, ", ");
else if (CTF_IS_STRUCTLIKE(kind))
(void) fprintf(fp, "\n");
}
}
if (isstring)
(void) fprintf(fp, "\"");
if (!isstring || pap->pa_depth != 0) {
if (CTF_IS_STRUCTLIKE(kind))
dt_print_indent(pap);
else
(void) fprintf(fp, " ");
(void) fprintf(fp, "]");
}
}
/*
* This isued by both structs and unions to print the leading brace.
*/
/* ARGSUSED */
static void
dt_print_structlike(ctf_id_t id, ulong_t off, dt_printarg_t *pap)
{
(void) fprintf(pap->pa_file, "{");
}
/*
* For enums, we try to print the enum name, and fall back to the value if it
* can't be determined. We do not do any fancy flag processing like mdb.
*/
/* ARGSUSED */
static void
dt_print_enum(ctf_id_t base, ulong_t off, dt_printarg_t *pap)
{
FILE *fp = pap->pa_file;
ctf_file_t *ctfp = pap->pa_ctfp;
const char *ename;
int value = 0;
if ((ename = ctf_enum_name(ctfp, base, value)) != NULL)
(void) fprintf(fp, "%s", ename);
else
(void) fprintf(fp, "%d", value);
}
/*
* Forward declaration. There's not much to do here without the complete
* type information, so just print out this fact and drive on.
*/
/* ARGSUSED */
static void
dt_print_tag(ctf_id_t base, ulong_t off, dt_printarg_t *pap)
{
(void) fprintf(pap->pa_file, "<forward decl>");
}
typedef void dt_printarg_f(ctf_id_t, ulong_t, dt_printarg_t *);
static dt_printarg_f *const dt_printfuncs[] = {
dt_print_int, /* CTF_K_INTEGER */
dt_print_float, /* CTF_K_FLOAT */
dt_print_ptr, /* CTF_K_POINTER */
dt_print_array, /* CTF_K_ARRAY */
dt_print_ptr, /* CTF_K_FUNCTION */
dt_print_structlike, /* CTF_K_STRUCT */
dt_print_structlike, /* CTF_K_UNION */
dt_print_enum, /* CTF_K_ENUM */
dt_print_tag /* CTF_K_FORWARD */
};
/*
* Print one member of a structure. This callback is invoked from
* ctf_type_visit() recursively.
*/
static int
dt_print_member(const char *name, ctf_id_t id, ulong_t off, int depth,
void *data)
{
char type[DT_TYPE_NAMELEN];
int kind;
dt_printarg_t *pap = data;
FILE *fp = pap->pa_file;
ctf_file_t *ctfp = pap->pa_ctfp;
boolean_t arraymember;
boolean_t brief;
ctf_encoding_t e;
ctf_id_t rtype;
dt_print_trailing_braces(pap, depth);
/*
* dt_print_trailing_braces() doesn't include the trailing newline; add
* it here if necessary.
*/
if (depth < pap->pa_depth)
(void) fprintf(fp, "\n");
pap->pa_depth = depth;
if ((rtype = ctf_type_resolve(ctfp, id)) == CTF_ERR ||
(kind = ctf_type_kind(ctfp, rtype)) == CTF_ERR ||
kind < CTF_K_INTEGER || kind > CTF_K_FORWARD) {
dt_print_indent(pap);
(void) fprintf(fp, "%s = <invalid type %lu>", name, id);
return (0);
}
dt_print_type_name(ctfp, id, type, sizeof (type));
arraymember = (pap->pa_nest != 0 && depth == 0);
brief = (arraymember && !CTF_IS_STRUCTLIKE(kind));
if (!brief) {
/*
* If this is a direct array member and a struct (otherwise
* brief would be true), then print a trailing newline, as the
* array printing code doesn't include it because it might be a
* simple type.
*/
if (arraymember)
(void) fprintf(fp, "\n");
dt_print_indent(pap);
/* always print the type */
(void) fprintf(fp, "%s", type);
if (name[0] != '\0') {
/*
* For aesthetics, we don't include a space between the
* type name and member name if the type is a pointer.
* This will give us "void *foo =" instead of "void *
* foo =". Unions also have the odd behavior that the
* type name is returned as "union ", with a trailing
* space, so we also avoid printing a space if the type
* name already ends with a space.
*/
if (type[strlen(type) - 1] != '*' &&
type[strlen(type) -1] != ' ') {
(void) fprintf(fp, " ");
}
(void) fprintf(fp, "%s", name);
/*
* If this looks like a bitfield, or is an integer not
* aligned on a byte boundary, print the number of
* bits after the name.
*/
if (kind == CTF_K_INTEGER &&
ctf_type_encoding(ctfp, id, &e) == 0) {
ulong_t bits = e.cte_bits;
ulong_t size = bits / NBBY;
if (bits % NBBY != 0 ||
off % NBBY != 0 ||
size > 8 ||
size != ctf_type_size(ctfp, id)) {
(void) fprintf(fp, " :%lu", bits);
}
}
(void) fprintf(fp, " =");
}
(void) fprintf(fp, " ");
}
dt_printfuncs[kind - 1](rtype, off, pap);
/* direct simple array members are not separated by newlines */
if (!brief)
(void) fprintf(fp, "\n");
return (0);
}
/*
* Main print function invoked by dt_consume_cpu().
*/
int
dtrace_print(dtrace_hdl_t *dtp, FILE *fp, const char *typename,
caddr_t addr, size_t len)
{
const char *s;
char *object;
dt_printarg_t pa;
ctf_id_t id;
dt_module_t *dmp;
/*
* Split the fully-qualified type ID (module`id). This should
* always be the format, but if for some reason we don't find the
* expected value, return 0 to fall back to the generic trace()
* behavior.
*/
for (s = typename; *s != '\0' && *s != '`'; s++)
;
if (*s != '`')
return (0);
object = alloca(s - typename + 1);
bcopy(typename, object, s - typename);
object[s - typename] = '\0';
id = atoi(s + 1);
/*
* Try to get the CTF kind for this id. If something has gone horribly
* wrong and we can't resolve the ID, bail out and let trace() do the
* work.
*/
dmp = dt_module_lookup_by_name(dtp, object);
if (dmp == NULL || ctf_type_kind(dt_module_getctf(dtp, dmp),
id) == CTF_ERR) {
return (0);
}
/* setup the print structure and kick off the main print routine */
pa.pa_addr = addr;
pa.pa_ctfp = dt_module_getctf(dtp, dmp);
pa.pa_nest = 0;
pa.pa_depth = 0;
pa.pa_file = fp;
(void) ctf_type_visit(pa.pa_ctfp, id, dt_print_member, &pa);
dt_print_trailing_braces(&pa, 0);
return (len);
}

View File

@ -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 <unistd.h>
@ -352,6 +353,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);

View File

@ -154,6 +154,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)(void); /* callback function for EPID */
void *dtsd_data; /* callback data pointer */
dtrace_attribute_t dtsd_descattr; /* probedesc attributes */
@ -245,6 +246,18 @@ extern int dtrace_freopen(dtrace_hdl_t *, FILE *, void *,
const dtrace_probedata_t *, const dtrace_recdesc_t *, uint_t,
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
*/

View File

@ -57,7 +57,8 @@ extern "C" {
/*
* libzfs errors
*/
enum {
typedef enum zfs_error {
EZFS_SUCCESS = 0, /* no error -- success */
EZFS_NOMEM = 2000, /* out of memory */
EZFS_BADPROP, /* invalid property value */
EZFS_PROPREADONLY, /* cannot set readonly property */
@ -129,7 +130,7 @@ enum {
EZFS_DIFFDATA, /* bad zfs diff data */
EZFS_POOLREADONLY, /* pool is in read-only mode */
EZFS_UNKNOWN
};
} zfs_error_t;
/*
* The following data structures are all part
@ -185,6 +186,9 @@ extern libzfs_handle_t *zfs_get_handle(zfs_handle_t *);
extern void libzfs_print_on_error(libzfs_handle_t *, boolean_t);
extern void zfs_save_arguments(int argc, char **, char *, int);
extern int zpool_log_history(libzfs_handle_t *, const char *);
extern int libzfs_errno(libzfs_handle_t *);
extern const char *libzfs_error_action(libzfs_handle_t *);
extern const char *libzfs_error_description(libzfs_handle_t *);
@ -220,7 +224,7 @@ extern int zpool_iter(libzfs_handle_t *, zpool_iter_f, void *);
*/
extern int zpool_create(libzfs_handle_t *, const char *, nvlist_t *,
nvlist_t *, nvlist_t *);
extern int zpool_destroy(zpool_handle_t *);
extern int zpool_destroy(zpool_handle_t *, const char *);
extern int zpool_add(zpool_handle_t *, nvlist_t *);
typedef struct splitflags {
@ -343,8 +347,8 @@ extern int zpool_get_errlog(zpool_handle_t *, nvlist_t **);
/*
* Import and export functions
*/
extern int zpool_export(zpool_handle_t *, boolean_t);
extern int zpool_export_force(zpool_handle_t *);
extern int zpool_export(zpool_handle_t *, boolean_t, const char *);
extern int zpool_export_force(zpool_handle_t *, const char *);
extern int zpool_import(libzfs_handle_t *, nvlist_t *, const char *,
char *altroot);
extern int zpool_import_props(libzfs_handle_t *, nvlist_t *, const char *,
@ -378,7 +382,7 @@ extern nvlist_t *zpool_find_import_cached(libzfs_handle_t *, const char *,
*/
struct zfs_cmd;
extern const char *zfs_history_event_names[LOG_END];
extern const char *zfs_history_event_names[];
extern char *zpool_vdev_name(libzfs_handle_t *, zpool_handle_t *, nvlist_t *,
boolean_t verbose);
@ -386,12 +390,9 @@ extern int zpool_upgrade(zpool_handle_t *, uint64_t);
extern int zpool_get_history(zpool_handle_t *, nvlist_t **);
extern int zpool_history_unpack(char *, uint64_t, uint64_t *,
nvlist_t ***, uint_t *);
extern void zpool_set_history_str(const char *subcommand, int argc,
char **argv, char *history_str);
extern int zpool_stage_history(libzfs_handle_t *, const char *);
extern void zpool_obj_to_path(zpool_handle_t *, uint64_t, uint64_t, char *,
size_t len);
extern int zfs_ioctl(libzfs_handle_t *, unsigned long, struct zfs_cmd *);
extern int zfs_ioctl(libzfs_handle_t *, int request, struct zfs_cmd *);
extern int zpool_get_physpath(zpool_handle_t *, char *, size_t);
extern void zpool_explain_recover(libzfs_handle_t *, const char *, int,
nvlist_t *);
@ -441,8 +442,6 @@ extern int zfs_prop_get_written(zfs_handle_t *zhp, const char *propname,
char *propbuf, int proplen, boolean_t literal);
extern int zfs_prop_get_feature(zfs_handle_t *zhp, const char *propname,
char *buf, size_t len);
extern 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);
@ -555,9 +554,11 @@ 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_destroy_snaps_nvl(libzfs_handle_t *, nvlist_t *, boolean_t);
extern int zfs_clone(zfs_handle_t *, const char *, nvlist_t *);
extern int zfs_snapshot(libzfs_handle_t *, const char *, boolean_t, nvlist_t *);
extern int zfs_snapshot_nvl(libzfs_handle_t *hdl, nvlist_t *snaps,
nvlist_t *props);
extern int zfs_rollback(zfs_handle_t *, zfs_handle_t *, boolean_t);
typedef struct renameflags {
@ -609,8 +610,8 @@ 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,
boolean_t, boolean_t, int, uint64_t, uint64_t);
extern int zfs_hold(zfs_handle_t *, const char *, const char *,
boolean_t, boolean_t, int);
extern int zfs_release(zfs_handle_t *, const char *, const char *, boolean_t);
extern int zfs_get_holds(zfs_handle_t *, nvlist_t **);
extern uint64_t zvol_volsize_to_reservation(uint64_t, nvlist_t *);

View File

@ -0,0 +1,103 @@
/*
* CDDL HEADER SART
*
* 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) 2013 Martin Matuska <mm@FreeBSD.org>. All rights reserved.
*/
#include "libzfs_compat.h"
int zfs_ioctl_version = ZFS_IOCVER_UNDEF;
static int zfs_spa_version = -1;
/*
* Get zfs_ioctl_version
*/
int
get_zfs_ioctl_version(void)
{
size_t ver_size;
int ver = ZFS_IOCVER_NONE;
ver_size = sizeof(ver);
sysctlbyname("vfs.zfs.version.ioctl", &ver, &ver_size, NULL, 0);
return (ver);
}
/*
* Get the SPA version
*/
static int
get_zfs_spa_version(void)
{
size_t ver_size;
int ver = 0;
ver_size = sizeof(ver);
sysctlbyname("vfs.zfs.version.spa", &ver, &ver_size, NULL, 0);
return (ver);
}
/*
* This is FreeBSD version of ioctl, because Solaris' ioctl() updates
* zc_nvlist_dst_size even if an error is returned, on FreeBSD if an
* error is returned zc_nvlist_dst_size won't be updated.
*/
int
zcmd_ioctl(int fd, int request, zfs_cmd_t *zc)
{
size_t oldsize;
int ret, cflag = ZFS_CMD_COMPAT_NONE;
if (zfs_ioctl_version == ZFS_IOCVER_UNDEF)
zfs_ioctl_version = get_zfs_ioctl_version();
if (zfs_ioctl_version == ZFS_IOCVER_DEADMAN)
cflag = ZFS_CMD_COMPAT_DEADMAN;
/*
* If vfs.zfs.version.ioctl is not defined, assume we have v28
* compatible binaries and use vfs.zfs.version.spa to test for v15
*/
if (zfs_ioctl_version < ZFS_IOCVER_DEADMAN) {
cflag = ZFS_CMD_COMPAT_V28;
if (zfs_spa_version < 0)
zfs_spa_version = get_zfs_spa_version();
if (zfs_spa_version == SPA_VERSION_15 ||
zfs_spa_version == SPA_VERSION_14 ||
zfs_spa_version == SPA_VERSION_13)
cflag = ZFS_CMD_COMPAT_V15;
}
oldsize = zc->zc_nvlist_dst_size;
ret = zcmd_ioctl_compat(fd, request, zc, cflag);
if (ret == 0 && oldsize < zc->zc_nvlist_dst_size) {
ret = -1;
errno = ENOMEM;
}
return (ret);
}

View File

@ -0,0 +1,44 @@
/*
* CDDL HEADER SART
*
* 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) 2013 Martin Matuska <mm@FreeBSD.org>. All rights reserved.
*/
#ifndef _LIBZFS_COMPAT_H
#define _LIBZFS_COMPAT_H
#include <zfs_ioctl_compat.h>
#ifdef __cplusplus
extern "C" {
#endif
int get_zfs_ioctl_version(void);
int zcmd_ioctl(int fd, int request, zfs_cmd_t *zc);
#define ioctl(fd, ioc, zc) zcmd_ioctl((fd), (ioc), (zc))
#ifdef __cplusplus
}
#endif
#endif /* _LIBZFS_COMPAT_H */

View File

@ -1447,7 +1447,6 @@ zfs_prop_set(zfs_handle_t *zhp, const char *propname, const char *propval)
nvlist_t *nvl = NULL, *realprops;
zfs_prop_t prop;
boolean_t do_prefix = B_TRUE;
uint64_t idx;
int added_resv;
(void) snprintf(errbuf, sizeof (errbuf),
@ -2017,10 +2016,7 @@ get_clones_cb(zfs_handle_t *zhp, void *arg)
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));
}
fnvlist_add_boolean(gca->value, zfs_get_name(zhp));
gca->numclones--;
}
@ -2711,25 +2707,6 @@ zfs_prop_get_written(zfs_handle_t *zhp, const char *propname,
return (0);
}
int
zfs_get_snapused_int(zfs_handle_t *firstsnap, zfs_handle_t *lastsnap,
uint64_t *usedp)
{
int err;
zfs_cmd_t zc = { 0 };
(void) strlcpy(zc.zc_name, lastsnap->zfs_name, sizeof (zc.zc_name));
(void) strlcpy(zc.zc_value, firstsnap->zfs_name, sizeof (zc.zc_value));
err = ioctl(lastsnap->zfs_hdl->libzfs_fd, ZFS_IOC_SPACE_SNAPS, &zc);
if (err)
return (err);
*usedp = zc.zc_cookie;
return (0);
}
/*
* Returns the name of the given zfs handle.
*/
@ -2930,7 +2907,6 @@ create_parents(libzfs_handle_t *hdl, char *target, int prefixlen)
*/
for (cp = target + prefixlen + 1;
cp = strchr(cp, '/'); *cp = '/', cp++) {
char *logstr;
*cp = '\0';
@ -2941,16 +2917,12 @@ create_parents(libzfs_handle_t *hdl, char *target, int prefixlen)
continue;
}
logstr = hdl->libzfs_log_str;
hdl->libzfs_log_str = NULL;
if (zfs_create(hdl, target, ZFS_TYPE_FILESYSTEM,
NULL) != 0) {
hdl->libzfs_log_str = logstr;
opname = dgettext(TEXT_DOMAIN, "create");
goto ancestorerr;
}
hdl->libzfs_log_str = logstr;
h = zfs_open(hdl, target, ZFS_TYPE_FILESYSTEM);
if (h == NULL) {
opname = dgettext(TEXT_DOMAIN, "open");
@ -3008,12 +2980,12 @@ int
zfs_create(libzfs_handle_t *hdl, const char *path, zfs_type_t type,
nvlist_t *props)
{
zfs_cmd_t zc = { 0 };
int ret;
uint64_t size = 0;
uint64_t blocksize = zfs_prop_default_numeric(ZFS_PROP_VOLBLOCKSIZE);
char errbuf[1024];
uint64_t zoned;
dmu_objset_type_t ost;
(void) snprintf(errbuf, sizeof (errbuf), dgettext(TEXT_DOMAIN,
"cannot create '%s'"), path);
@ -3033,17 +3005,16 @@ zfs_create(libzfs_handle_t *hdl, const char *path, zfs_type_t type,
* will return ENOENT, not EEXIST. To prevent this from happening, we
* first try to see if the dataset exists.
*/
(void) strlcpy(zc.zc_name, path, sizeof (zc.zc_name));
if (zfs_dataset_exists(hdl, zc.zc_name, ZFS_TYPE_DATASET)) {
if (zfs_dataset_exists(hdl, path, ZFS_TYPE_DATASET)) {
zfs_error_aux(hdl, dgettext(TEXT_DOMAIN,
"dataset already exists"));
return (zfs_error(hdl, EZFS_EXISTS, errbuf));
}
if (type == ZFS_TYPE_VOLUME)
zc.zc_objset_type = DMU_OST_ZVOL;
ost = DMU_OST_ZVOL;
else
zc.zc_objset_type = DMU_OST_ZFS;
ost = DMU_OST_ZFS;
if (props && (props = zfs_valid_proplist(hdl, type, props,
zoned, NULL, errbuf)) == 0)
@ -3095,14 +3066,9 @@ zfs_create(libzfs_handle_t *hdl, const char *path, zfs_type_t type,
}
}
if (props && zcmd_write_src_nvlist(hdl, &zc, props) != 0)
return (-1);
nvlist_free(props);
/* create the dataset */
ret = zfs_ioctl(hdl, ZFS_IOC_CREATE, &zc);
zcmd_free_nvlists(&zc);
ret = lzc_create(path, ost, props);
nvlist_free(props);
/* check for failure */
if (ret != 0) {
@ -3228,47 +3194,53 @@ zfs_destroy_snaps(zfs_handle_t *zhp, char *snapname, boolean_t defer)
dgettext(TEXT_DOMAIN, "cannot destroy '%s@%s'"),
zhp->zfs_name, snapname);
} else {
ret = zfs_destroy_snaps_nvl(zhp, dd.nvl, defer);
ret = zfs_destroy_snaps_nvl(zhp->zfs_hdl, 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).
* Destroys all the snapshots named in the nvlist.
*/
int
zfs_destroy_snaps_nvl(zfs_handle_t *zhp, nvlist_t *snaps, boolean_t defer)
zfs_destroy_snaps_nvl(libzfs_handle_t *hdl, nvlist_t *snaps, boolean_t defer)
{
int ret;
zfs_cmd_t zc = { 0 };
nvlist_t *errlist;
(void) strlcpy(zc.zc_name, zhp->zfs_name, sizeof (zc.zc_name));
if (zcmd_write_src_nvlist(zhp->zfs_hdl, &zc, snaps) != 0)
return (-1);
zc.zc_defer_destroy = defer;
ret = lzc_destroy_snaps(snaps, defer, &errlist);
ret = zfs_ioctl(zhp->zfs_hdl, ZFS_IOC_DESTROY_SNAPS_NVL, &zc);
if (ret != 0) {
if (ret == 0)
return (0);
if (nvlist_next_nvpair(errlist, NULL) == NULL) {
char errbuf[1024];
(void) snprintf(errbuf, sizeof (errbuf),
dgettext(TEXT_DOMAIN, "cannot destroy snapshots"));
(void) snprintf(errbuf, sizeof (errbuf), dgettext(TEXT_DOMAIN,
"cannot destroy snapshots in %s"), zc.zc_name);
ret = zfs_standard_error(hdl, ret, errbuf);
}
for (nvpair_t *pair = nvlist_next_nvpair(errlist, NULL);
pair != NULL; pair = nvlist_next_nvpair(errlist, pair)) {
char errbuf[1024];
(void) snprintf(errbuf, sizeof (errbuf),
dgettext(TEXT_DOMAIN, "cannot destroy snapshot %s"),
nvpair_name(pair));
switch (errno) {
switch (fnvpair_value_int32(pair)) {
case EEXIST:
zfs_error_aux(zhp->zfs_hdl, dgettext(TEXT_DOMAIN,
"snapshot is cloned"));
return (zfs_error(zhp->zfs_hdl, EZFS_EXISTS, errbuf));
zfs_error_aux(hdl,
dgettext(TEXT_DOMAIN, "snapshot is cloned"));
ret = zfs_error(hdl, EZFS_EXISTS, errbuf);
break;
default:
return (zfs_standard_error(zhp->zfs_hdl, errno,
errbuf));
ret = zfs_standard_error(hdl, errno, errbuf);
break;
}
}
return (0);
return (ret);
}
/*
@ -3277,12 +3249,10 @@ zfs_destroy_snaps_nvl(zfs_handle_t *zhp, nvlist_t *snaps, boolean_t defer)
int
zfs_clone(zfs_handle_t *zhp, const char *target, nvlist_t *props)
{
zfs_cmd_t zc = { 0 };
char parent[ZFS_MAXNAMELEN];
int ret;
char errbuf[1024];
libzfs_handle_t *hdl = zhp->zfs_hdl;
zfs_type_t type;
uint64_t zoned;
assert(zhp->zfs_type == ZFS_TYPE_SNAPSHOT);
@ -3301,32 +3271,21 @@ zfs_clone(zfs_handle_t *zhp, const char *target, nvlist_t *props)
(void) parent_name(target, parent, sizeof (parent));
/* do the clone */
if (ZFS_IS_VOLUME(zhp)) {
zc.zc_objset_type = DMU_OST_ZVOL;
type = ZFS_TYPE_VOLUME;
} else {
zc.zc_objset_type = DMU_OST_ZFS;
type = ZFS_TYPE_FILESYSTEM;
}
if (props) {
zfs_type_t type;
if (ZFS_IS_VOLUME(zhp)) {
type = ZFS_TYPE_VOLUME;
} else {
type = ZFS_TYPE_FILESYSTEM;
}
if ((props = zfs_valid_proplist(hdl, type, props, zoned,
zhp, errbuf)) == NULL)
return (-1);
if (zcmd_write_src_nvlist(hdl, &zc, props) != 0) {
nvlist_free(props);
return (-1);
}
nvlist_free(props);
}
(void) strlcpy(zc.zc_name, target, sizeof (zc.zc_name));
(void) strlcpy(zc.zc_value, zhp->zfs_name, sizeof (zc.zc_value));
ret = zfs_ioctl(zhp->zfs_hdl, ZFS_IOC_CREATE, &zc);
zcmd_free_nvlists(&zc);
ret = lzc_clone(target, zhp->zfs_name, props);
nvlist_free(props);
if (ret != 0) {
switch (errno) {
@ -3411,74 +3370,134 @@ zfs_promote(zfs_handle_t *zhp)
return (ret);
}
typedef struct snapdata {
nvlist_t *sd_nvl;
const char *sd_snapname;
} snapdata_t;
static int
zfs_snapshot_cb(zfs_handle_t *zhp, void *arg)
{
snapdata_t *sd = arg;
char name[ZFS_MAXNAMELEN];
int rv = 0;
(void) snprintf(name, sizeof (name),
"%s@%s", zfs_get_name(zhp), sd->sd_snapname);
fnvlist_add_boolean(sd->sd_nvl, name);
rv = zfs_iter_filesystems(zhp, zfs_snapshot_cb, sd);
zfs_close(zhp);
return (rv);
}
/*
* Takes a snapshot of the given dataset.
* Creates snapshots. The keys in the snaps nvlist are the snapshots to be
* created.
*/
int
zfs_snapshot_nvl(libzfs_handle_t *hdl, nvlist_t *snaps, nvlist_t *props)
{
int ret;
char errbuf[1024];
nvpair_t *elem;
nvlist_t *errors;
(void) snprintf(errbuf, sizeof (errbuf), dgettext(TEXT_DOMAIN,
"cannot create snapshots "));
elem = NULL;
while ((elem = nvlist_next_nvpair(snaps, elem)) != NULL) {
const char *snapname = nvpair_name(elem);
/* validate the target name */
if (!zfs_validate_name(hdl, snapname, ZFS_TYPE_SNAPSHOT,
B_TRUE)) {
(void) snprintf(errbuf, sizeof (errbuf),
dgettext(TEXT_DOMAIN,
"cannot create snapshot '%s'"), snapname);
return (zfs_error(hdl, EZFS_INVALIDNAME, errbuf));
}
}
if (props != NULL &&
(props = zfs_valid_proplist(hdl, ZFS_TYPE_SNAPSHOT,
props, B_FALSE, NULL, errbuf)) == NULL) {
return (-1);
}
ret = lzc_snapshot(snaps, props, &errors);
if (ret != 0) {
boolean_t printed = B_FALSE;
for (elem = nvlist_next_nvpair(errors, NULL);
elem != NULL;
elem = nvlist_next_nvpair(errors, elem)) {
(void) snprintf(errbuf, sizeof (errbuf),
dgettext(TEXT_DOMAIN,
"cannot create snapshot '%s'"), nvpair_name(elem));
(void) zfs_standard_error(hdl,
fnvpair_value_int32(elem), errbuf);
printed = B_TRUE;
}
if (!printed) {
switch (ret) {
case EXDEV:
zfs_error_aux(hdl, dgettext(TEXT_DOMAIN,
"multiple snapshots of same "
"fs not allowed"));
(void) zfs_error(hdl, EZFS_EXISTS, errbuf);
break;
default:
(void) zfs_standard_error(hdl, ret, errbuf);
}
}
}
nvlist_free(props);
nvlist_free(errors);
return (ret);
}
int
zfs_snapshot(libzfs_handle_t *hdl, const char *path, boolean_t recursive,
nvlist_t *props)
{
const char *delim;
char parent[ZFS_MAXNAMELEN];
zfs_handle_t *zhp;
zfs_cmd_t zc = { 0 };
int ret;
snapdata_t sd = { 0 };
char fsname[ZFS_MAXNAMELEN];
char *cp;
zfs_handle_t *zhp;
char errbuf[1024];
(void) snprintf(errbuf, sizeof (errbuf), dgettext(TEXT_DOMAIN,
"cannot snapshot '%s'"), path);
"cannot snapshot %s"), path);
/* validate the target name */
if (!zfs_validate_name(hdl, path, ZFS_TYPE_SNAPSHOT, B_TRUE))
return (zfs_error(hdl, EZFS_INVALIDNAME, errbuf));
if (props) {
if ((props = zfs_valid_proplist(hdl, ZFS_TYPE_SNAPSHOT,
props, B_FALSE, NULL, errbuf)) == NULL)
return (-1);
(void) strlcpy(fsname, path, sizeof (fsname));
cp = strchr(fsname, '@');
*cp = '\0';
sd.sd_snapname = cp + 1;
if (zcmd_write_src_nvlist(hdl, &zc, props) != 0) {
nvlist_free(props);
return (-1);
}
nvlist_free(props);
}
/* make sure the parent exists and is of the appropriate type */
delim = strchr(path, '@');
(void) strncpy(parent, path, delim - path);
parent[delim - path] = '\0';
if ((zhp = zfs_open(hdl, parent, ZFS_TYPE_FILESYSTEM |
if ((zhp = zfs_open(hdl, fsname, ZFS_TYPE_FILESYSTEM |
ZFS_TYPE_VOLUME)) == NULL) {
zcmd_free_nvlists(&zc);
return (-1);
}
(void) strlcpy(zc.zc_name, zhp->zfs_name, sizeof (zc.zc_name));
(void) strlcpy(zc.zc_value, delim+1, sizeof (zc.zc_value));
if (ZFS_IS_VOLUME(zhp))
zc.zc_objset_type = DMU_OST_ZVOL;
else
zc.zc_objset_type = DMU_OST_ZFS;
zc.zc_cookie = recursive;
ret = zfs_ioctl(zhp->zfs_hdl, ZFS_IOC_SNAPSHOT, &zc);
zcmd_free_nvlists(&zc);
/*
* if it was recursive, the one that actually failed will be in
* zc.zc_name.
*/
if (ret != 0) {
(void) snprintf(errbuf, sizeof (errbuf), dgettext(TEXT_DOMAIN,
"cannot create snapshot '%s@%s'"), zc.zc_name, zc.zc_value);
(void) zfs_standard_error(hdl, errno, errbuf);
verify(nvlist_alloc(&sd.sd_nvl, NV_UNIQUE_NAME, 0) == 0);
if (recursive) {
(void) zfs_snapshot_cb(zfs_handle_dup(zhp), &sd);
} else {
fnvlist_add_boolean(sd.sd_nvl, path);
}
ret = zfs_snapshot_nvl(hdl, sd.sd_nvl, props);
nvlist_free(sd.sd_nvl);
zfs_close(zhp);
return (ret);
}
@ -3506,17 +3525,13 @@ rollback_destroy(zfs_handle_t *zhp, void *data)
zfs_get_type(zhp) == ZFS_TYPE_SNAPSHOT &&
zfs_prop_get_int(zhp, ZFS_PROP_CREATETXG) >
cbp->cb_create) {
char *logstr;
cbp->cb_dependent = B_TRUE;
cbp->cb_error |= zfs_iter_dependents(zhp, B_FALSE,
rollback_destroy, cbp);
cbp->cb_dependent = B_FALSE;
logstr = zhp->zfs_hdl->libzfs_log_str;
zhp->zfs_hdl->libzfs_log_str = NULL;
cbp->cb_error |= zfs_destroy(zhp, B_FALSE);
zhp->zfs_hdl->libzfs_log_str = logstr;
}
} else {
/* We must destroy this clone; first unmount it */
@ -4120,7 +4135,7 @@ zfs_userspace(zfs_handle_t *zhp, zfs_userquota_prop_t type,
zc.zc_nvlist_dst_size = sizeof (buf);
if (zfs_ioctl(hdl, ZFS_IOC_USERSPACE_MANY, &zc) != 0) {
char errbuf[ZFS_MAXNAMELEN + 32];
char errbuf[1024];
(void) snprintf(errbuf, sizeof (errbuf),
dgettext(TEXT_DOMAIN,
@ -4142,37 +4157,83 @@ zfs_userspace(zfs_handle_t *zhp, zfs_userquota_prop_t type,
return (0);
}
struct holdarg {
nvlist_t *nvl;
const char *snapname;
const char *tag;
boolean_t recursive;
};
static int
zfs_hold_one(zfs_handle_t *zhp, void *arg)
{
struct holdarg *ha = arg;
zfs_handle_t *szhp;
char name[ZFS_MAXNAMELEN];
int rv = 0;
(void) snprintf(name, sizeof (name),
"%s@%s", zhp->zfs_name, ha->snapname);
szhp = make_dataset_handle(zhp->zfs_hdl, name);
if (szhp) {
fnvlist_add_string(ha->nvl, name, ha->tag);
zfs_close(szhp);
}
if (ha->recursive)
rv = zfs_iter_filesystems(zhp, zfs_hold_one, ha);
zfs_close(zhp);
return (rv);
}
int
zfs_hold(zfs_handle_t *zhp, const char *snapname, const char *tag,
boolean_t recursive, boolean_t temphold, boolean_t enoent_ok,
int cleanup_fd, uint64_t dsobj, uint64_t createtxg)
boolean_t recursive, boolean_t enoent_ok, int cleanup_fd)
{
zfs_cmd_t zc = { 0 };
int ret;
struct holdarg ha;
nvlist_t *errors;
libzfs_handle_t *hdl = zhp->zfs_hdl;
char errbuf[1024];
nvpair_t *elem;
ASSERT(!recursive || dsobj == 0);
ha.nvl = fnvlist_alloc();
ha.snapname = snapname;
ha.tag = tag;
ha.recursive = recursive;
(void) zfs_hold_one(zfs_handle_dup(zhp), &ha);
ret = lzc_hold(ha.nvl, cleanup_fd, &errors);
fnvlist_free(ha.nvl);
(void) strlcpy(zc.zc_name, zhp->zfs_name, sizeof (zc.zc_name));
(void) strlcpy(zc.zc_value, snapname, sizeof (zc.zc_value));
if (strlcpy(zc.zc_string, tag, sizeof (zc.zc_string))
>= sizeof (zc.zc_string))
return (zfs_error(hdl, EZFS_TAGTOOLONG, tag));
zc.zc_cookie = recursive;
zc.zc_temphold = temphold;
zc.zc_cleanup_fd = cleanup_fd;
zc.zc_sendobj = dsobj;
zc.zc_createtxg = createtxg;
if (ret == 0)
return (0);
if (zfs_ioctl(hdl, ZFS_IOC_HOLD, &zc) != 0) {
char errbuf[ZFS_MAXNAMELEN+32];
if (nvlist_next_nvpair(errors, NULL) == NULL) {
/* no hold-specific errors */
(void) snprintf(errbuf, sizeof (errbuf),
dgettext(TEXT_DOMAIN, "cannot hold"));
switch (ret) {
case ENOTSUP:
zfs_error_aux(hdl, dgettext(TEXT_DOMAIN,
"pool must be upgraded"));
(void) zfs_error(hdl, EZFS_BADVERSION, errbuf);
break;
case EINVAL:
(void) zfs_error(hdl, EZFS_BADTYPE, errbuf);
break;
default:
(void) zfs_standard_error(hdl, ret, errbuf);
}
}
/*
* if it was recursive, the one that actually failed will be in
* zc.zc_name.
*/
(void) snprintf(errbuf, sizeof (errbuf), dgettext(TEXT_DOMAIN,
"cannot hold '%s@%s'"), zc.zc_name, snapname);
switch (errno) {
for (elem = nvlist_next_nvpair(errors, NULL);
elem != NULL;
elem = nvlist_next_nvpair(errors, elem)) {
(void) snprintf(errbuf, sizeof (errbuf),
dgettext(TEXT_DOMAIN,
"cannot hold snapshot '%s'"), nvpair_name(elem));
switch (fnvpair_value_int32(elem)) {
case E2BIG:
/*
* Temporary tags wind up having the ds object id
@ -4180,66 +4241,122 @@ zfs_hold(zfs_handle_t *zhp, const char *snapname, const char *tag,
* above, it's still possible for the tag to wind
* up being slightly too long.
*/
return (zfs_error(hdl, EZFS_TAGTOOLONG, errbuf));
case ENOTSUP:
zfs_error_aux(hdl, dgettext(TEXT_DOMAIN,
"pool must be upgraded"));
return (zfs_error(hdl, EZFS_BADVERSION, errbuf));
(void) zfs_error(hdl, EZFS_TAGTOOLONG, errbuf);
break;
case EINVAL:
return (zfs_error(hdl, EZFS_BADTYPE, errbuf));
(void) zfs_error(hdl, EZFS_BADTYPE, errbuf);
break;
case EEXIST:
return (zfs_error(hdl, EZFS_REFTAG_HOLD, errbuf));
(void) zfs_error(hdl, EZFS_REFTAG_HOLD, errbuf);
break;
case ENOENT:
if (enoent_ok)
return (ENOENT);
/* FALLTHROUGH */
default:
return (zfs_standard_error_fmt(hdl, errno, errbuf));
(void) zfs_standard_error(hdl,
fnvpair_value_int32(elem), errbuf);
}
}
return (0);
fnvlist_free(errors);
return (ret);
}
struct releasearg {
nvlist_t *nvl;
const char *snapname;
const char *tag;
boolean_t recursive;
};
static int
zfs_release_one(zfs_handle_t *zhp, void *arg)
{
struct holdarg *ha = arg;
zfs_handle_t *szhp;
char name[ZFS_MAXNAMELEN];
int rv = 0;
(void) snprintf(name, sizeof (name),
"%s@%s", zhp->zfs_name, ha->snapname);
szhp = make_dataset_handle(zhp->zfs_hdl, name);
if (szhp) {
nvlist_t *holds = fnvlist_alloc();
fnvlist_add_boolean(holds, ha->tag);
fnvlist_add_nvlist(ha->nvl, name, holds);
zfs_close(szhp);
}
if (ha->recursive)
rv = zfs_iter_filesystems(zhp, zfs_release_one, ha);
zfs_close(zhp);
return (rv);
}
int
zfs_release(zfs_handle_t *zhp, const char *snapname, const char *tag,
boolean_t recursive)
{
zfs_cmd_t zc = { 0 };
int ret;
struct holdarg ha;
nvlist_t *errors;
nvpair_t *elem;
libzfs_handle_t *hdl = zhp->zfs_hdl;
(void) strlcpy(zc.zc_name, zhp->zfs_name, sizeof (zc.zc_name));
(void) strlcpy(zc.zc_value, snapname, sizeof (zc.zc_value));
if (strlcpy(zc.zc_string, tag, sizeof (zc.zc_string))
>= sizeof (zc.zc_string))
return (zfs_error(hdl, EZFS_TAGTOOLONG, tag));
zc.zc_cookie = recursive;
ha.nvl = fnvlist_alloc();
ha.snapname = snapname;
ha.tag = tag;
ha.recursive = recursive;
(void) zfs_release_one(zfs_handle_dup(zhp), &ha);
ret = lzc_release(ha.nvl, &errors);
fnvlist_free(ha.nvl);
if (zfs_ioctl(hdl, ZFS_IOC_RELEASE, &zc) != 0) {
char errbuf[ZFS_MAXNAMELEN+32];
if (ret == 0)
return (0);
if (nvlist_next_nvpair(errors, NULL) == NULL) {
/* no hold-specific errors */
char errbuf[1024];
/*
* if it was recursive, the one that actually failed will be in
* zc.zc_name.
*/
(void) snprintf(errbuf, sizeof (errbuf), dgettext(TEXT_DOMAIN,
"cannot release '%s' from '%s@%s'"), tag, zc.zc_name,
snapname);
"cannot release"));
switch (errno) {
case ESRCH:
return (zfs_error(hdl, EZFS_REFTAG_RELE, errbuf));
case ENOTSUP:
zfs_error_aux(hdl, dgettext(TEXT_DOMAIN,
"pool must be upgraded"));
return (zfs_error(hdl, EZFS_BADVERSION, errbuf));
case EINVAL:
return (zfs_error(hdl, EZFS_BADTYPE, errbuf));
(void) zfs_error(hdl, EZFS_BADVERSION, errbuf);
break;
default:
return (zfs_standard_error_fmt(hdl, errno, errbuf));
(void) zfs_standard_error_fmt(hdl, errno, errbuf);
}
}
return (0);
for (elem = nvlist_next_nvpair(errors, NULL);
elem != NULL;
elem = nvlist_next_nvpair(errors, elem)) {
char errbuf[1024];
(void) snprintf(errbuf, sizeof (errbuf),
dgettext(TEXT_DOMAIN,
"cannot release hold from snapshot '%s'"),
nvpair_name(elem));
switch (fnvpair_value_int32(elem)) {
case ESRCH:
(void) zfs_error(hdl, EZFS_REFTAG_RELE, errbuf);
break;
case EINVAL:
(void) zfs_error(hdl, EZFS_BADTYPE, errbuf);
break;
default:
(void) zfs_standard_error_fmt(hdl,
fnvpair_value_int32(elem), errbuf);
}
}
fnvlist_free(errors);
return (ret);
}
int
@ -4250,7 +4367,7 @@ zfs_get_fsacl(zfs_handle_t *zhp, nvlist_t **nvl)
int nvsz = 2048;
void *nvbuf;
int err = 0;
char errbuf[ZFS_MAXNAMELEN+32];
char errbuf[1024];
assert(zhp->zfs_type == ZFS_TYPE_VOLUME ||
zhp->zfs_type == ZFS_TYPE_FILESYSTEM);
@ -4315,7 +4432,7 @@ zfs_set_fsacl(zfs_handle_t *zhp, boolean_t un, nvlist_t *nvl)
zfs_cmd_t zc = { 0 };
libzfs_handle_t *hdl = zhp->zfs_hdl;
char *nvbuf;
char errbuf[ZFS_MAXNAMELEN+32];
char errbuf[1024];
size_t nvsz;
int err;
@ -4366,38 +4483,18 @@ zfs_set_fsacl(zfs_handle_t *zhp, boolean_t un, nvlist_t *nvl)
int
zfs_get_holds(zfs_handle_t *zhp, nvlist_t **nvl)
{
zfs_cmd_t zc = { 0 };
libzfs_handle_t *hdl = zhp->zfs_hdl;
int nvsz = 2048;
void *nvbuf;
int err = 0;
char errbuf[ZFS_MAXNAMELEN+32];
int err;
char errbuf[1024];
assert(zhp->zfs_type == ZFS_TYPE_SNAPSHOT);
err = lzc_get_holds(zhp->zfs_name, nvl);
tryagain:
if (err != 0) {
libzfs_handle_t *hdl = zhp->zfs_hdl;
nvbuf = malloc(nvsz);
if (nvbuf == NULL) {
err = (zfs_error(hdl, EZFS_NOMEM, strerror(errno)));
goto out;
}
zc.zc_nvlist_dst_size = nvsz;
zc.zc_nvlist_dst = (uintptr_t)nvbuf;
(void) strlcpy(zc.zc_name, zhp->zfs_name, ZFS_MAXNAMELEN);
if (zfs_ioctl(hdl, ZFS_IOC_GET_HOLDS, &zc) != 0) {
(void) snprintf(errbuf, sizeof (errbuf),
dgettext(TEXT_DOMAIN, "cannot get holds for '%s'"),
zc.zc_name);
switch (errno) {
case ENOMEM:
free(nvbuf);
nvsz = zc.zc_nvlist_dst_size;
goto tryagain;
zhp->zfs_name);
switch (err) {
case ENOTSUP:
zfs_error_aux(hdl, dgettext(TEXT_DOMAIN,
"pool must be upgraded"));
@ -4413,19 +4510,8 @@ tryagain:
err = zfs_standard_error_fmt(hdl, errno, errbuf);
break;
}
} else {
/* success */
int rc = nvlist_unpack(nvbuf, zc.zc_nvlist_dst_size, nvl, 0);
if (rc) {
(void) snprintf(errbuf, sizeof (errbuf),
dgettext(TEXT_DOMAIN, "cannot get holds for '%s'"),
zc.zc_name);
err = zfs_standard_error_fmt(hdl, rc, errbuf);
}
}
free(nvbuf);
out:
return (err);
}

View File

@ -23,11 +23,12 @@
* Copyright (c) 2005, 2010, Oracle and/or its affiliates. All rights reserved.
* Copyright (c) 2011 Pawel Jakub Dawidek <pawel@dawidek.net>.
* All rights reserved.
* Copyright (c) 2011 by Delphix. All rights reserved.
* Copyright (c) 2012 by Delphix. All rights reserved.
* Copyright (c) 2013 Martin Matuska <mm@FreeBSD.org>. All rights reserved.
*/
#ifndef _LIBFS_IMPL_H
#define _LIBFS_IMPL_H
#ifndef _LIBZFS_IMPL_H
#define _LIBZFS_IMPL_H
#include <sys/dmu.h>
#include <sys/fs/zfs.h>
@ -38,8 +39,8 @@
#include <libshare.h>
#include <libuutil.h>
#include <libzfs.h>
#include "zfs_ioctl_compat.h"
#include <libzfs_core.h>
#include <libzfs_compat.h>
#ifdef __cplusplus
extern "C" {
@ -69,7 +70,6 @@ struct libzfs_handle {
int libzfs_desc_active;
char libzfs_action[1024];
char libzfs_desc[1024];
char *libzfs_log_str;
int libzfs_printerr;
int libzfs_storeerr; /* stuff error messages into buffer */
void *libzfs_sharehdl; /* libshare handle */
@ -214,46 +214,8 @@ extern int zfs_unshare_proto(zfs_handle_t *,
extern void libzfs_fru_clear(libzfs_handle_t *, boolean_t);
#ifndef sun
static int zfs_kernel_version = 0;
/*
* This is FreeBSD version of ioctl, because Solaris' ioctl() updates
* zc_nvlist_dst_size even if an error is returned, on FreeBSD if an
* error is returned zc_nvlist_dst_size won't be updated.
*/
static __inline int
zcmd_ioctl(int fd, unsigned long cmd, zfs_cmd_t *zc)
{
size_t oldsize, zfs_kernel_version_size;
int version, ret, cflag = ZFS_CMD_COMPAT_NONE;
zfs_kernel_version_size = sizeof(zfs_kernel_version);
if (zfs_kernel_version == 0) {
sysctlbyname("vfs.zfs.version.spa", &zfs_kernel_version,
&zfs_kernel_version_size, NULL, 0);
}
if (zfs_kernel_version == SPA_VERSION_15 ||
zfs_kernel_version == SPA_VERSION_14 ||
zfs_kernel_version == SPA_VERSION_13)
cflag = ZFS_CMD_COMPAT_V15;
oldsize = zc->zc_nvlist_dst_size;
ret = zcmd_ioctl_compat(fd, cmd, zc, cflag);
if (ret == 0 && oldsize < zc->zc_nvlist_dst_size) {
ret = -1;
errno = ENOMEM;
}
return (ret);
}
#define ioctl(fd, cmd, zc) zcmd_ioctl((fd), (cmd), (zc))
#endif /* !sun */
#ifdef __cplusplus
}
#endif
#endif /* _LIBFS_IMPL_H */
#endif /* _LIBZFS_IMPL_H */

View File

@ -22,7 +22,7 @@
/*
* 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.
* Copyright (c) 2012 by Delphix. All rights reserved.
* Copyright (c) 2012 Pawel Jakub Dawidek <pawel@dawidek.net>.
* All rights reserved.
*/
@ -308,12 +308,11 @@ 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;
char *buf, *comma_separated, *cp;
int err = 0;
int ret = 0;
(void) strlcpy(buf, spec_orig, sizeof (buf));
buf = zfs_strdup(fs_zhp->zfs_hdl, spec_orig);
cp = buf;
while ((comma_separated = strsep(&cp, ",")) != NULL) {
@ -371,6 +370,7 @@ zfs_iter_snapspec(zfs_handle_t *fs_zhp, const char *spec_orig,
}
}
free(buf);
return (ret);
}

View File

@ -36,6 +36,7 @@
#include <stdlib.h>
#include <strings.h>
#include <unistd.h>
#include <libgen.h>
#include <sys/zfs_ioctl.h>
#include <dlfcn.h>
@ -1237,7 +1238,7 @@ create_failed:
* datasets left in the pool.
*/
int
zpool_destroy(zpool_handle_t *zhp)
zpool_destroy(zpool_handle_t *zhp, const char *log_str)
{
zfs_cmd_t zc = { 0 };
zfs_handle_t *zfp = NULL;
@ -1249,6 +1250,7 @@ zpool_destroy(zpool_handle_t *zhp)
return (-1);
(void) strlcpy(zc.zc_name, zhp->zpool_name, sizeof (zc.zc_name));
zc.zc_history = (uint64_t)(uintptr_t)log_str;
if (zfs_ioctl(hdl, ZFS_IOC_POOL_DESTROY, &zc) != 0) {
(void) snprintf(msg, sizeof (msg), dgettext(TEXT_DOMAIN,
@ -1403,8 +1405,9 @@ zpool_add(zpool_handle_t *zhp, nvlist_t *nvroot)
* Exports the pool from the system. The caller must ensure that there are no
* mounted datasets in the pool.
*/
int
zpool_export_common(zpool_handle_t *zhp, boolean_t force, boolean_t hardforce)
static int
zpool_export_common(zpool_handle_t *zhp, boolean_t force, boolean_t hardforce,
const char *log_str)
{
zfs_cmd_t zc = { 0 };
char msg[1024];
@ -1415,6 +1418,7 @@ zpool_export_common(zpool_handle_t *zhp, boolean_t force, boolean_t hardforce)
(void) strlcpy(zc.zc_name, zhp->zpool_name, sizeof (zc.zc_name));
zc.zc_cookie = force;
zc.zc_guid = hardforce;
zc.zc_history = (uint64_t)(uintptr_t)log_str;
if (zfs_ioctl(zhp->zpool_hdl, ZFS_IOC_POOL_EXPORT, &zc) != 0) {
switch (errno) {
@ -1436,15 +1440,15 @@ zpool_export_common(zpool_handle_t *zhp, boolean_t force, boolean_t hardforce)
}
int
zpool_export(zpool_handle_t *zhp, boolean_t force)
zpool_export(zpool_handle_t *zhp, boolean_t force, const char *log_str)
{
return (zpool_export_common(zhp, force, B_FALSE));
return (zpool_export_common(zhp, force, B_FALSE, log_str));
}
int
zpool_export_force(zpool_handle_t *zhp)
zpool_export_force(zpool_handle_t *zhp, const char *log_str)
{
return (zpool_export_common(zhp, B_TRUE, B_TRUE));
return (zpool_export_common(zhp, B_TRUE, B_TRUE, log_str));
}
static void
@ -3632,40 +3636,30 @@ zpool_upgrade(zpool_handle_t *zhp, uint64_t new_version)
}
void
zpool_set_history_str(const char *subcommand, int argc, char **argv,
char *history_str)
zfs_save_arguments(int argc, char **argv, char *string, int len)
{
int i;
(void) strlcpy(history_str, subcommand, HIS_MAX_RECORD_LEN);
for (i = 1; i < argc; i++) {
if (strlen(history_str) + 1 + strlen(argv[i]) >
HIS_MAX_RECORD_LEN)
break;
(void) strlcat(history_str, " ", HIS_MAX_RECORD_LEN);
(void) strlcat(history_str, argv[i], HIS_MAX_RECORD_LEN);
(void) strlcpy(string, basename(argv[0]), len);
for (int i = 1; i < argc; i++) {
(void) strlcat(string, " ", len);
(void) strlcat(string, argv[i], len);
}
}
/*
* Stage command history for logging.
*/
int
zpool_stage_history(libzfs_handle_t *hdl, const char *history_str)
zpool_log_history(libzfs_handle_t *hdl, const char *message)
{
if (history_str == NULL)
return (EINVAL);
zfs_cmd_t zc = { 0 };
nvlist_t *args;
int err;
if (strlen(history_str) > HIS_MAX_RECORD_LEN)
return (EINVAL);
if (hdl->libzfs_log_str != NULL)
free(hdl->libzfs_log_str);
if ((hdl->libzfs_log_str = strdup(history_str)) == NULL)
return (no_memory(hdl));
return (0);
args = fnvlist_alloc();
fnvlist_add_string(args, "message", message);
err = zcmd_write_src_nvlist(hdl, &zc, args);
if (err == 0)
err = ioctl(hdl->libzfs_fd, ZFS_IOC_LOG_HISTORY, &zc);
nvlist_free(args);
zcmd_free_nvlists(&zc);
return (err);
}
/*

View File

@ -53,6 +53,10 @@
#include <sys/zio_checksum.h>
#include <sys/ddt.h>
#ifdef __FreeBSD__
extern int zfs_ioctl_version;
#endif
/* in libzfs_dataset.c */
extern void zfs_setprop_error(libzfs_handle_t *, zfs_prop_t, int, char *);
/* We need to use something for ENODATA. */
@ -978,9 +982,7 @@ hold_for_send(zfs_handle_t *zhp, send_dump_data_t *sdd)
*/
if (pzhp) {
error = zfs_hold(pzhp, thissnap, sdd->holdtag,
B_FALSE, B_TRUE, B_TRUE, sdd->cleanup_fd,
zfs_prop_get_int(zhp, ZFS_PROP_OBJSETID),
zfs_prop_get_int(zhp, ZFS_PROP_CREATETXG));
B_FALSE, B_TRUE, sdd->cleanup_fd);
zfs_close(pzhp);
}
@ -1719,12 +1721,11 @@ recv_rename(libzfs_handle_t *hdl, const char *name, const char *tryname,
err = ENOENT;
}
if (err != 0 && strncmp(name+baselen, "recv-", 5) != 0) {
if (err != 0 && strncmp(name + baselen, "recv-", 5) != 0) {
seq++;
(void) strncpy(newname, name, baselen);
(void) snprintf(newname+baselen, ZFS_MAXNAMELEN-baselen,
"recv-%u-%u", getpid(), seq);
(void) snprintf(newname, ZFS_MAXNAMELEN, "%.*srecv-%u-%u",
baselen, name, getpid(), seq);
(void) strlcpy(zc.zc_value, newname, sizeof (zc.zc_value));
if (flags->verbose) {
@ -2676,9 +2677,17 @@ zfs_receive_one(libzfs_handle_t *hdl, int infd, const char *tosnap,
/*
* Determine name of destination snapshot, store in zc_value.
*/
(void) strcpy(zc.zc_top_ds, tosnap);
(void) strcpy(zc.zc_value, tosnap);
(void) strncat(zc.zc_value, chopprefix, sizeof (zc.zc_value));
#ifdef __FreeBSD__
if (zfs_ioctl_version == ZFS_IOCVER_UNDEF)
zfs_ioctl_version = get_zfs_ioctl_version();
/*
* For forward compatibility hide tosnap in zc_value
*/
if (zfs_ioctl_version < ZFS_IOCVER_LZC)
(void) strcpy(zc.zc_value + strlen(zc.zc_value) + 1, tosnap);
#endif
free(cp);
if (!zfs_name_valid(zc.zc_value, ZFS_TYPE_SNAPSHOT)) {
zcmd_free_nvlists(&zc);

View File

@ -48,6 +48,7 @@
#include <sys/types.h>
#include <libzfs.h>
#include <libzfs_core.h>
#include "libzfs_impl.h"
#include "zfs_prop.h"
@ -659,6 +660,14 @@ libzfs_init(void)
hdl->libzfs_sharetab = fopen(ZFS_EXPORTS_PATH, "r");
if (libzfs_core_init() != 0) {
(void) close(hdl->libzfs_fd);
(void) fclose(hdl->libzfs_mnttab);
(void) fclose(hdl->libzfs_sharetab);
free(hdl);
return (NULL);
}
zfs_prop_init();
zpool_prop_init();
zpool_feature_init();
@ -676,14 +685,13 @@ libzfs_fini(libzfs_handle_t *hdl)
if (hdl->libzfs_sharetab)
(void) fclose(hdl->libzfs_sharetab);
zfs_uninit_libshare(hdl);
if (hdl->libzfs_log_str)
(void) free(hdl->libzfs_log_str);
zpool_free_handles(hdl);
#ifdef sun
libzfs_fru_clear(hdl, B_TRUE);
#endif
namespace_clear(hdl);
libzfs_mnttab_fini(hdl);
libzfs_core_fini();
free(hdl);
}
@ -857,19 +865,9 @@ zcmd_read_dst_nvlist(libzfs_handle_t *hdl, zfs_cmd_t *zc, nvlist_t **nvlp)
}
int
zfs_ioctl(libzfs_handle_t *hdl, unsigned long request, zfs_cmd_t *zc)
zfs_ioctl(libzfs_handle_t *hdl, int request, zfs_cmd_t *zc)
{
int error;
zc->zc_history = (uint64_t)(uintptr_t)hdl->libzfs_log_str;
error = ioctl(hdl->libzfs_fd, request, zc);
if (hdl->libzfs_log_str) {
free(hdl->libzfs_log_str);
hdl->libzfs_log_str = NULL;
}
zc->zc_history = 0;
return (error);
return (ioctl(hdl->libzfs_fd, request, zc));
}
/*

View File

@ -0,0 +1,618 @@
/*
* CDDL HEADER START
*
* The contents of this file are subject to the terms of the
* Common Development and Distribution License (the "License").
* You may not use this file except in compliance with the License.
*
* You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE
* or http://www.opensolaris.org/os/licensing.
* See the License for the specific language governing permissions
* and limitations under the License.
*
* When distributing Covered Code, include this CDDL HEADER in each
* file and include the License file at usr/src/OPENSOLARIS.LICENSE.
* If applicable, add the following below this CDDL HEADER, with the
* fields enclosed by brackets "[]" replaced with your own identifying
* information: Portions Copyright [yyyy] [name of copyright owner]
*
* CDDL HEADER END
*/
/*
* Copyright (c) 2012 by Delphix. All rights reserved.
*/
/*
* LibZFS_Core (lzc) is intended to replace most functionality in libzfs.
* It has the following characteristics:
*
* - Thread Safe. libzfs_core is accessible concurrently from multiple
* threads. This is accomplished primarily by avoiding global data
* (e.g. caching). Since it's thread-safe, there is no reason for a
* process to have multiple libzfs "instances". Therefore, we store
* our few pieces of data (e.g. the file descriptor) in global
* variables. The fd is reference-counted so that the libzfs_core
* library can be "initialized" multiple times (e.g. by different
* consumers within the same process).
*
* - Committed Interface. The libzfs_core interface will be committed,
* therefore consumers can compile against it and be confident that
* their code will continue to work on future releases of this code.
* Currently, the interface is Evolving (not Committed), but we intend
* to commit to it once it is more complete and we determine that it
* meets the needs of all consumers.
*
* - Programatic Error Handling. libzfs_core communicates errors with
* defined error numbers, and doesn't print anything to stdout/stderr.
*
* - Thin Layer. libzfs_core is a thin layer, marshaling arguments
* to/from the kernel ioctls. There is generally a 1:1 correspondence
* between libzfs_core functions and ioctls to /dev/zfs.
*
* - Clear Atomicity. Because libzfs_core functions are generally 1:1
* with kernel ioctls, and kernel ioctls are general atomic, each
* libzfs_core function is atomic. For example, creating multiple
* snapshots with a single call to lzc_snapshot() is atomic -- it
* can't fail with only some of the requested snapshots created, even
* in the event of power loss or system crash.
*
* - Continued libzfs Support. Some higher-level operations (e.g.
* support for "zfs send -R") are too complicated to fit the scope of
* libzfs_core. This functionality will continue to live in libzfs.
* Where appropriate, libzfs will use the underlying atomic operations
* of libzfs_core. For example, libzfs may implement "zfs send -R |
* zfs receive" by using individual "send one snapshot", rename,
* destroy, and "receive one snapshot" operations in libzfs_core.
* /sbin/zfs and /zbin/zpool will link with both libzfs and
* libzfs_core. Other consumers should aim to use only libzfs_core,
* since that will be the supported, stable interface going forwards.
*/
#define _IN_LIBZFS_CORE_
#include <libzfs_core.h>
#include <ctype.h>
#include <unistd.h>
#include <stdlib.h>
#include <string.h>
#include <errno.h>
#include <fcntl.h>
#include <pthread.h>
#include <sys/nvpair.h>
#include <sys/param.h>
#include <sys/types.h>
#include <sys/stat.h>
#include <sys/zfs_ioctl.h>
#include "libzfs_core_compat.h"
#include "libzfs_compat.h"
#ifdef __FreeBSD__
extern int zfs_ioctl_version;
#endif
static int g_fd;
static pthread_mutex_t g_lock = PTHREAD_MUTEX_INITIALIZER;
static int g_refcount;
int
libzfs_core_init(void)
{
(void) pthread_mutex_lock(&g_lock);
if (g_refcount == 0) {
g_fd = open("/dev/zfs", O_RDWR);
if (g_fd < 0) {
(void) pthread_mutex_unlock(&g_lock);
return (errno);
}
}
g_refcount++;
(void) pthread_mutex_unlock(&g_lock);
return (0);
}
void
libzfs_core_fini(void)
{
(void) pthread_mutex_lock(&g_lock);
ASSERT3S(g_refcount, >, 0);
g_refcount--;
if (g_refcount == 0)
(void) close(g_fd);
(void) pthread_mutex_unlock(&g_lock);
}
static int
lzc_ioctl(zfs_ioc_t ioc, const char *name,
nvlist_t *source, nvlist_t **resultp)
{
zfs_cmd_t zc = { 0 };
int error = 0;
char *packed;
#ifdef __FreeBSD__
nvlist_t *oldsource;
#endif
size_t size;
ASSERT3S(g_refcount, >, 0);
(void) strlcpy(zc.zc_name, name, sizeof (zc.zc_name));
#ifdef __FreeBSD__
if (zfs_ioctl_version == ZFS_IOCVER_UNDEF)
zfs_ioctl_version = get_zfs_ioctl_version();
if (zfs_ioctl_version < ZFS_IOCVER_LZC) {
oldsource = source;
error = lzc_compat_pre(&zc, &ioc, &source);
if (error)
return (error);
}
#endif
packed = fnvlist_pack(source, &size);
zc.zc_nvlist_src = (uint64_t)(uintptr_t)packed;
zc.zc_nvlist_src_size = size;
if (resultp != NULL) {
*resultp = NULL;
zc.zc_nvlist_dst_size = MAX(size * 2, 128 * 1024);
zc.zc_nvlist_dst = (uint64_t)(uintptr_t)
malloc(zc.zc_nvlist_dst_size);
#ifdef illumos
if (zc.zc_nvlist_dst == NULL) {
#else
if (zc.zc_nvlist_dst == 0) {
#endif
error = ENOMEM;
goto out;
}
}
while (ioctl(g_fd, ioc, &zc) != 0) {
if (errno == ENOMEM && resultp != NULL) {
free((void *)(uintptr_t)zc.zc_nvlist_dst);
zc.zc_nvlist_dst_size *= 2;
zc.zc_nvlist_dst = (uint64_t)(uintptr_t)
malloc(zc.zc_nvlist_dst_size);
#ifdef illumos
if (zc.zc_nvlist_dst == NULL) {
#else
if (zc.zc_nvlist_dst == 0) {
#endif
error = ENOMEM;
goto out;
}
} else {
error = errno;
break;
}
}
#ifdef __FreeBSD__
if (zfs_ioctl_version < ZFS_IOCVER_LZC)
lzc_compat_post(&zc, ioc);
#endif
if (zc.zc_nvlist_dst_filled) {
*resultp = fnvlist_unpack((void *)(uintptr_t)zc.zc_nvlist_dst,
zc.zc_nvlist_dst_size);
}
#ifdef __FreeBSD__
if (zfs_ioctl_version < ZFS_IOCVER_LZC)
lzc_compat_outnvl(&zc, ioc, resultp);
#endif
out:
#ifdef __FreeBSD__
if (zfs_ioctl_version < ZFS_IOCVER_LZC) {
if (source != oldsource)
nvlist_free(source);
source = oldsource;
}
#endif
fnvlist_pack_free(packed, size);
free((void *)(uintptr_t)zc.zc_nvlist_dst);
return (error);
}
int
lzc_create(const char *fsname, dmu_objset_type_t type, nvlist_t *props)
{
int error;
nvlist_t *args = fnvlist_alloc();
fnvlist_add_int32(args, "type", type);
if (props != NULL)
fnvlist_add_nvlist(args, "props", props);
error = lzc_ioctl(ZFS_IOC_CREATE, fsname, args, NULL);
nvlist_free(args);
return (error);
}
int
lzc_clone(const char *fsname, const char *origin,
nvlist_t *props)
{
int error;
nvlist_t *args = fnvlist_alloc();
fnvlist_add_string(args, "origin", origin);
if (props != NULL)
fnvlist_add_nvlist(args, "props", props);
error = lzc_ioctl(ZFS_IOC_CLONE, fsname, args, NULL);
nvlist_free(args);
return (error);
}
/*
* Creates snapshots.
*
* The keys in the snaps nvlist are the snapshots to be created.
* They must all be in the same pool.
*
* The props nvlist is properties to set. Currently only user properties
* are supported. { user:prop_name -> string value }
*
* The returned results nvlist will have an entry for each snapshot that failed.
* The value will be the (int32) error code.
*
* The return value will be 0 if all snapshots were created, otherwise it will
* be the errno of a (unspecified) snapshot that failed.
*/
int
lzc_snapshot(nvlist_t *snaps, nvlist_t *props, nvlist_t **errlist)
{
nvpair_t *elem;
nvlist_t *args;
int error;
char pool[MAXNAMELEN];
*errlist = NULL;
/* determine the pool name */
elem = nvlist_next_nvpair(snaps, NULL);
if (elem == NULL)
return (0);
(void) strlcpy(pool, nvpair_name(elem), sizeof (pool));
pool[strcspn(pool, "/@")] = '\0';
args = fnvlist_alloc();
fnvlist_add_nvlist(args, "snaps", snaps);
if (props != NULL)
fnvlist_add_nvlist(args, "props", props);
error = lzc_ioctl(ZFS_IOC_SNAPSHOT, pool, args, errlist);
nvlist_free(args);
return (error);
}
/*
* Destroys snapshots.
*
* The keys in the snaps nvlist are the snapshots to be destroyed.
* They must all be in the same pool.
*
* Snapshots that do not exist will be silently ignored.
*
* If 'defer' is not set, and a snapshot has user holds or clones, the
* destroy operation will fail and none of the snapshots will be
* destroyed.
*
* If 'defer' is set, and a snapshot has user holds or clones, it will be
* marked for deferred destruction, and will be destroyed when the last hold
* or clone is removed/destroyed.
*
* The return value will be 0 if all snapshots were destroyed (or marked for
* later destruction if 'defer' is set) or didn't exist to begin with.
*
* Otherwise the return value will be the errno of a (unspecified) snapshot
* that failed, no snapshots will be destroyed, and the errlist will have an
* entry for each snapshot that failed. The value in the errlist will be
* the (int32) error code.
*/
int
lzc_destroy_snaps(nvlist_t *snaps, boolean_t defer, nvlist_t **errlist)
{
nvpair_t *elem;
nvlist_t *args;
int error;
char pool[MAXNAMELEN];
/* determine the pool name */
elem = nvlist_next_nvpair(snaps, NULL);
if (elem == NULL)
return (0);
(void) strlcpy(pool, nvpair_name(elem), sizeof (pool));
pool[strcspn(pool, "/@")] = '\0';
args = fnvlist_alloc();
fnvlist_add_nvlist(args, "snaps", snaps);
if (defer)
fnvlist_add_boolean(args, "defer");
error = lzc_ioctl(ZFS_IOC_DESTROY_SNAPS, pool, args, errlist);
nvlist_free(args);
return (error);
}
int
lzc_snaprange_space(const char *firstsnap, const char *lastsnap,
uint64_t *usedp)
{
nvlist_t *args;
nvlist_t *result;
int err;
char fs[MAXNAMELEN];
char *atp;
/* determine the fs name */
(void) strlcpy(fs, firstsnap, sizeof (fs));
atp = strchr(fs, '@');
if (atp == NULL)
return (EINVAL);
*atp = '\0';
args = fnvlist_alloc();
fnvlist_add_string(args, "firstsnap", firstsnap);
err = lzc_ioctl(ZFS_IOC_SPACE_SNAPS, lastsnap, args, &result);
nvlist_free(args);
if (err == 0)
*usedp = fnvlist_lookup_uint64(result, "used");
fnvlist_free(result);
return (err);
}
boolean_t
lzc_exists(const char *dataset)
{
/*
* The objset_stats ioctl is still legacy, so we need to construct our
* own zfs_cmd_t rather than using zfsc_ioctl().
*/
zfs_cmd_t zc = { 0 };
(void) strlcpy(zc.zc_name, dataset, sizeof (zc.zc_name));
return (ioctl(g_fd, ZFS_IOC_OBJSET_STATS, &zc) == 0);
}
/*
* Create "user holds" on snapshots. If there is a hold on a snapshot,
* the snapshot can not be destroyed. (However, it can be marked for deletion
* by lzc_destroy_snaps(defer=B_TRUE).)
*
* The keys in the nvlist are snapshot names.
* The snapshots must all be in the same pool.
* The value is the name of the hold (string type).
*
* If cleanup_fd is not -1, it must be the result of open("/dev/zfs", O_EXCL).
* In this case, when the cleanup_fd is closed (including on process
* termination), the holds will be released. If the system is shut down
* uncleanly, the holds will be released when the pool is next opened
* or imported.
*
* The return value will be 0 if all holds were created. Otherwise the return
* value will be the errno of a (unspecified) hold that failed, no holds will
* be created, and the errlist will have an entry for each hold that
* failed (name = snapshot). The value in the errlist will be the error
* code (int32).
*/
int
lzc_hold(nvlist_t *holds, int cleanup_fd, nvlist_t **errlist)
{
char pool[MAXNAMELEN];
nvlist_t *args;
nvpair_t *elem;
int error;
/* determine the pool name */
elem = nvlist_next_nvpair(holds, NULL);
if (elem == NULL)
return (0);
(void) strlcpy(pool, nvpair_name(elem), sizeof (pool));
pool[strcspn(pool, "/@")] = '\0';
args = fnvlist_alloc();
fnvlist_add_nvlist(args, "holds", holds);
if (cleanup_fd != -1)
fnvlist_add_int32(args, "cleanup_fd", cleanup_fd);
error = lzc_ioctl(ZFS_IOC_HOLD, pool, args, errlist);
nvlist_free(args);
return (error);
}
/*
* Release "user holds" on snapshots. If the snapshot has been marked for
* deferred destroy (by lzc_destroy_snaps(defer=B_TRUE)), it does not have
* any clones, and all the user holds are removed, then the snapshot will be
* destroyed.
*
* The keys in the nvlist are snapshot names.
* The snapshots must all be in the same pool.
* The value is a nvlist whose keys are the holds to remove.
*
* The return value will be 0 if all holds were removed.
* Otherwise the return value will be the errno of a (unspecified) release
* that failed, no holds will be released, and the errlist will have an
* entry for each snapshot that has failed releases (name = snapshot).
* The value in the errlist will be the error code (int32) of a failed release.
*/
int
lzc_release(nvlist_t *holds, nvlist_t **errlist)
{
char pool[MAXNAMELEN];
nvpair_t *elem;
/* determine the pool name */
elem = nvlist_next_nvpair(holds, NULL);
if (elem == NULL)
return (0);
(void) strlcpy(pool, nvpair_name(elem), sizeof (pool));
pool[strcspn(pool, "/@")] = '\0';
return (lzc_ioctl(ZFS_IOC_RELEASE, pool, holds, errlist));
}
/*
* Retrieve list of user holds on the specified snapshot.
*
* On success, *holdsp will be set to a nvlist which the caller must free.
* The keys are the names of the holds, and the value is the creation time
* of the hold (uint64) in seconds since the epoch.
*/
int
lzc_get_holds(const char *snapname, nvlist_t **holdsp)
{
int error;
nvlist_t *innvl = fnvlist_alloc();
error = lzc_ioctl(ZFS_IOC_GET_HOLDS, snapname, innvl, holdsp);
fnvlist_free(innvl);
return (error);
}
/*
* If fromsnap is NULL, a full (non-incremental) stream will be sent.
*/
int
lzc_send(const char *snapname, const char *fromsnap, int fd)
{
nvlist_t *args;
int err;
args = fnvlist_alloc();
fnvlist_add_int32(args, "fd", fd);
if (fromsnap != NULL)
fnvlist_add_string(args, "fromsnap", fromsnap);
err = lzc_ioctl(ZFS_IOC_SEND_NEW, snapname, args, NULL);
nvlist_free(args);
return (err);
}
/*
* If fromsnap is NULL, a full (non-incremental) stream will be estimated.
*/
int
lzc_send_space(const char *snapname, const char *fromsnap, uint64_t *spacep)
{
nvlist_t *args;
nvlist_t *result;
int err;
args = fnvlist_alloc();
if (fromsnap != NULL)
fnvlist_add_string(args, "fromsnap", fromsnap);
err = lzc_ioctl(ZFS_IOC_SEND_SPACE, snapname, args, &result);
nvlist_free(args);
if (err == 0)
*spacep = fnvlist_lookup_uint64(result, "space");
nvlist_free(result);
return (err);
}
static int
recv_read(int fd, void *buf, int ilen)
{
char *cp = buf;
int rv;
int len = ilen;
do {
rv = read(fd, cp, len);
cp += rv;
len -= rv;
} while (rv > 0);
if (rv < 0 || len != 0)
return (EIO);
return (0);
}
/*
* The simplest receive case: receive from the specified fd, creating the
* specified snapshot. Apply the specified properties a "received" properties
* (which can be overridden by locally-set properties). If the stream is a
* clone, its origin snapshot must be specified by 'origin'. The 'force'
* flag will cause the target filesystem to be rolled back or destroyed if
* necessary to receive.
*
* Return 0 on success or an errno on failure.
*
* Note: this interface does not work on dedup'd streams
* (those with DMU_BACKUP_FEATURE_DEDUP).
*/
int
lzc_receive(const char *snapname, nvlist_t *props, const char *origin,
boolean_t force, int fd)
{
/*
* The receive ioctl is still legacy, so we need to construct our own
* zfs_cmd_t rather than using zfsc_ioctl().
*/
zfs_cmd_t zc = { 0 };
char *atp;
char *packed = NULL;
size_t size;
dmu_replay_record_t drr;
int error;
ASSERT3S(g_refcount, >, 0);
/* zc_name is name of containing filesystem */
(void) strlcpy(zc.zc_name, snapname, sizeof (zc.zc_name));
atp = strchr(zc.zc_name, '@');
if (atp == NULL)
return (EINVAL);
*atp = '\0';
/* if the fs does not exist, try its parent. */
if (!lzc_exists(zc.zc_name)) {
char *slashp = strrchr(zc.zc_name, '/');
if (slashp == NULL)
return (ENOENT);
*slashp = '\0';
}
/* zc_value is full name of the snapshot to create */
(void) strlcpy(zc.zc_value, snapname, sizeof (zc.zc_value));
if (props != NULL) {
/* zc_nvlist_src is props to set */
packed = fnvlist_pack(props, &size);
zc.zc_nvlist_src = (uint64_t)(uintptr_t)packed;
zc.zc_nvlist_src_size = size;
}
/* zc_string is name of clone origin (if DRR_FLAG_CLONE) */
if (origin != NULL)
(void) strlcpy(zc.zc_string, origin, sizeof (zc.zc_string));
/* zc_begin_record is non-byteswapped BEGIN record */
error = recv_read(fd, &drr, sizeof (drr));
if (error != 0)
goto out;
zc.zc_begin_record = drr.drr_u.drr_begin;
/* zc_cookie is fd to read from */
zc.zc_cookie = fd;
/* zc guid is force flag */
zc.zc_guid = force;
/* zc_cleanup_fd is unused */
zc.zc_cleanup_fd = -1;
error = ioctl(g_fd, ZFS_IOC_RECV, &zc);
if (error != 0)
error = errno;
out:
if (packed != NULL)
fnvlist_pack_free(packed, size);
free((void*)(uintptr_t)zc.zc_nvlist_dst);
return (error);
}

View File

@ -0,0 +1,67 @@
/*
* CDDL HEADER START
*
* The contents of this file are subject to the terms of the
* Common Development and Distribution License (the "License").
* You may not use this file except in compliance with the License.
*
* You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE
* or http://www.opensolaris.org/os/licensing.
* See the License for the specific language governing permissions
* and limitations under the License.
*
* When distributing Covered Code, include this CDDL HEADER in each
* file and include the License file at usr/src/OPENSOLARIS.LICENSE.
* If applicable, add the following below this CDDL HEADER, with the
* fields enclosed by brackets "[]" replaced with your own identifying
* information: Portions Copyright [yyyy] [name of copyright owner]
*
* CDDL HEADER END
*/
/*
* Copyright (c) 2012 by Delphix. All rights reserved.
* Copyright (c) 2013 by Martin Matuska <mm@FreeBSD.org>. All rights reserved.
*/
#ifndef _LIBZFS_CORE_H
#define _LIBZFS_CORE_H
#include <libnvpair.h>
#include <sys/param.h>
#include <sys/types.h>
#include <sys/fs/zfs.h>
#ifdef __cplusplus
extern "C" {
#endif
int libzfs_core_init(void);
void libzfs_core_fini(void);
int lzc_snapshot(nvlist_t *snaps, nvlist_t *props, nvlist_t **errlist);
int lzc_create(const char *fsname, dmu_objset_type_t type, nvlist_t *props);
int lzc_clone(const char *fsname, const char *origin, nvlist_t *props);
int lzc_destroy_snaps(nvlist_t *snaps, boolean_t defer, nvlist_t **errlist);
int lzc_snaprange_space(const char *firstsnap, const char *lastsnap,
uint64_t *usedp);
int lzc_hold(nvlist_t *holds, int cleanup_fd, nvlist_t **errlist);
int lzc_release(nvlist_t *holds, nvlist_t **errlist);
int lzc_get_holds(const char *snapname, nvlist_t **holdsp);
int lzc_send(const char *snapname, const char *fromsnap, int fd);
int lzc_receive(const char *snapname, nvlist_t *props, const char *origin,
boolean_t force, int fd);
int lzc_send_space(const char *snapname, const char *fromsnap,
uint64_t *result);
boolean_t lzc_exists(const char *dataset);
#ifdef __cplusplus
}
#endif
#endif /* _LIBZFS_CORE_H */

View File

@ -0,0 +1,189 @@
/*
* 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) 2013 Martin Matuska <mm@FreeBSD.org>. All rights reserved.
*/
#include <sys/zfs_ioctl.h>
#include <zfs_ioctl_compat.h>
#include "libzfs_core_compat.h"
extern int zfs_ioctl_version;
int
lzc_compat_pre(zfs_cmd_t *zc, zfs_ioc_t *ioc, nvlist_t **source)
{
nvlist_t *nvl = NULL;
nvpair_t *pair, *hpair;
char *buf, *val;
zfs_ioc_t vecnum;
uint32_t type32;
int32_t cleanup_fd;
int error = 0;
int pos;
if (zfs_ioctl_version >= ZFS_IOCVER_LZC)
return (0);
vecnum = *ioc;
switch (vecnum) {
case ZFS_IOC_CREATE:
type32 = fnvlist_lookup_int32(*source, "type");
zc->zc_objset_type = (uint64_t)type32;
nvlist_lookup_nvlist(*source, "props", &nvl);
*source = nvl;
break;
case ZFS_IOC_CLONE:
buf = fnvlist_lookup_string(*source, "origin");
strlcpy(zc->zc_value, buf, MAXPATHLEN);
nvlist_lookup_nvlist(*source, "props", &nvl);
*ioc = ZFS_IOC_CREATE;
*source = nvl;
break;
case ZFS_IOC_SNAPSHOT:
nvl = fnvlist_lookup_nvlist(*source, "snaps");
pair = nvlist_next_nvpair(nvl, NULL);
if (pair != NULL) {
buf = nvpair_name(pair);
pos = strcspn(buf, "@");
strlcpy(zc->zc_name, buf, pos + 1);
strlcpy(zc->zc_value, buf + pos + 1, MAXPATHLEN);
} else
error = EINVAL;
/* old kernel cannot create multiple snapshots */
if (!error && nvlist_next_nvpair(nvl, pair) != NULL)
error = EOPNOTSUPP;
nvlist_free(nvl);
nvl = NULL;
nvlist_lookup_nvlist(*source, "props", &nvl);
*source = nvl;
break;
case ZFS_IOC_SPACE_SNAPS:
buf = fnvlist_lookup_string(*source, "firstsnap");
strlcpy(zc->zc_value, buf, MAXPATHLEN);
break;
case ZFS_IOC_DESTROY_SNAPS:
nvl = fnvlist_lookup_nvlist(*source, "snaps");
pair = nvlist_next_nvpair(nvl, NULL);
if (pair != NULL) {
buf = nvpair_name(pair);
pos = strcspn(buf, "@");
strlcpy(zc->zc_name, buf, pos + 1);
} else
error = EINVAL;
/* old kernel cannot atomically destroy multiple snaps */
if (!error && nvlist_next_nvpair(nvl, pair) != NULL)
error = EOPNOTSUPP;
*source = nvl;
break;
case ZFS_IOC_HOLD:
nvl = fnvlist_lookup_nvlist(*source, "holds");
pair = nvlist_next_nvpair(nvl, NULL);
if (pair != NULL) {
buf = nvpair_name(pair);
pos = strcspn(buf, "@");
strlcpy(zc->zc_name, buf, pos + 1);
strlcpy(zc->zc_value, buf + pos + 1, MAXPATHLEN);
if (nvpair_value_string(pair, &val) == 0)
strlcpy(zc->zc_string, val, MAXNAMELEN);
else
error = EINVAL;
} else
error = EINVAL;
/* old kernel cannot atomically create multiple holds */
if (!error && nvlist_next_nvpair(nvl, pair) != NULL)
error = EOPNOTSUPP;
nvlist_free(nvl);
if (nvlist_lookup_int32(*source, "cleanup_fd",
&cleanup_fd) == 0)
zc->zc_cleanup_fd = cleanup_fd;
else
zc->zc_cleanup_fd = -1;
break;
case ZFS_IOC_RELEASE:
pair = nvlist_next_nvpair(*source, NULL);
if (pair != NULL) {
buf = nvpair_name(pair);
pos = strcspn(buf, "@");
strlcpy(zc->zc_name, buf, pos + 1);
strlcpy(zc->zc_value, buf + pos + 1, MAXPATHLEN);
if (nvpair_value_nvlist(pair, &nvl) == 0) {
hpair = nvlist_next_nvpair(nvl, NULL);
if (hpair != NULL)
strlcpy(zc->zc_string,
nvpair_name(hpair), MAXNAMELEN);
else
error = EINVAL;
if (!error && nvlist_next_nvpair(nvl,
hpair) != NULL)
error = EOPNOTSUPP;
} else
error = EINVAL;
} else
error = EINVAL;
/* old kernel cannot atomically release multiple holds */
if (!error && nvlist_next_nvpair(nvl, pair) != NULL)
error = EOPNOTSUPP;
break;
}
return (error);
}
void
lzc_compat_post(zfs_cmd_t *zc, const zfs_ioc_t ioc)
{
if (zfs_ioctl_version >= ZFS_IOCVER_LZC)
return;
switch (ioc) {
case ZFS_IOC_CREATE:
case ZFS_IOC_CLONE:
case ZFS_IOC_SNAPSHOT:
case ZFS_IOC_SPACE_SNAPS:
case ZFS_IOC_DESTROY_SNAPS:
zc->zc_nvlist_dst_filled = B_FALSE;
break;
}
}
int
lzc_compat_outnvl(zfs_cmd_t *zc, const zfs_ioc_t ioc, nvlist_t **outnvl)
{
nvlist_t *nvl;
if (zfs_ioctl_version >= ZFS_IOCVER_LZC)
return (0);
switch (ioc) {
case ZFS_IOC_SPACE_SNAPS:
nvl = fnvlist_alloc();
fnvlist_add_uint64(nvl, "used", zc->zc_cookie);
fnvlist_add_uint64(nvl, "compressed", zc->zc_objset_type);
fnvlist_add_uint64(nvl, "uncompressed", zc->zc_perm_action);
*outnvl = nvl;
break;
}
return (0);
}

View File

@ -0,0 +1,47 @@
/*
* 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) 2013 by Martin Matuska <mm@FreeBSD.org>. All rights reserved.
*/
#ifndef _LIBZFS_CORE_COMPAT_H
#define _LIBZFS_CORE_COMPAT_H
#include <libnvpair.h>
#include <sys/param.h>
#include <sys/types.h>
#include <sys/fs/zfs.h>
#include <sys/zfs_ioctl.h>
#ifdef __cplusplus
extern "C" {
#endif
int lzc_compat_pre(zfs_cmd_t *, zfs_ioc_t *, nvlist_t **);
void lzc_compat_post(zfs_cmd_t *, const zfs_ioc_t);
int lzc_compat_outnvl(zfs_cmd_t *, const zfs_ioc_t, nvlist_t **);
#ifdef __cplusplus
}
#endif
#endif /* _LIBZFS_CORE_COMPAT_H */

View File

@ -33,6 +33,7 @@
#include <sys/stat.h>
#include <sys/processor.h>
#include <sys/zfs_context.h>
#include <sys/rrwlock.h>
#include <sys/zmod.h>
#include <sys/utsname.h>
#include <sys/systeminfo.h>
@ -45,6 +46,9 @@ int aok;
uint64_t physmem;
vnode_t *rootdir = (vnode_t *)0xabcd1234;
char hw_serial[HW_HOSTID_LEN];
#ifdef illumos
kmutex_t cpu_lock;
#endif
struct utsname utsname = {
"userland", "libzpool", "1", "1", "na"
@ -842,6 +846,28 @@ ddi_strtoull(const char *str, char **nptr, int base, u_longlong_t *result)
return (0);
}
#ifdef illumos
/* ARGSUSED */
cyclic_id_t
cyclic_add(cyc_handler_t *hdlr, cyc_time_t *when)
{
return (1);
}
/* ARGSUSED */
void
cyclic_remove(cyclic_id_t id)
{
}
/* ARGSUSED */
int
cyclic_reprogram(cyclic_id_t id, hrtime_t expiration)
{
return (1);
}
#endif
/*
* =========================================================================
* kernel emulation setup & teardown
@ -860,6 +886,8 @@ umem_out_of_memory(void)
void
kernel_init(int mode)
{
extern uint_t rrw_tsd_key;
umem_nofail_callback(umem_out_of_memory);
physmem = sysconf(_SC_PHYS_PAGES);
@ -875,7 +903,13 @@ kernel_init(int mode)
system_taskq_init();
#ifdef illumos
mutex_init(&cpu_lock, NULL, MUTEX_DEFAULT, NULL);
#endif
spa_init(mode);
tsd_create(&rrw_tsd_key, rrw_tsd_destroy);
}
void
@ -923,6 +957,12 @@ crgetuid(cred_t *cr)
return (0);
}
uid_t
crgetruid(cred_t *cr)
{
return (0);
}
gid_t
crgetgid(cred_t *cr)
{

View File

@ -60,6 +60,8 @@ extern "C" {
#include <umem.h>
#include <inttypes.h>
#include <fsshare.h>
#include <pthread.h>
#include <sys/debug.h>
#include <sys/note.h>
#include <sys/types.h>
#include <sys/cred.h>
@ -242,6 +244,9 @@ typedef int krw_t;
#define RW_WRITE_HELD(x) ((x)->rw_owner == curthread)
#define RW_LOCK_HELD(x) rw_lock_held(x)
#undef RW_LOCK_HELD
#define RW_LOCK_HELD(x) (RW_READ_HELD(x) || RW_WRITE_HELD(x))
extern void rw_init(krwlock_t *rwlp, char *name, int type, void *arg);
extern void rw_destroy(krwlock_t *rwlp);
extern void rw_enter(krwlock_t *rwlp, krw_t rw);
@ -252,6 +257,7 @@ extern int rw_lock_held(krwlock_t *rwlp);
#define rw_downgrade(rwlp) do { } while (0)
extern uid_t crgetuid(cred_t *cr);
extern uid_t crgetruid(cred_t *cr);
extern gid_t crgetgid(cred_t *cr);
extern int crgetngroups(cred_t *cr);
extern gid_t *crgetgroups(cred_t *cr);
@ -270,6 +276,14 @@ extern clock_t cv_timedwait(kcondvar_t *cv, kmutex_t *mp, clock_t abstime);
extern void cv_signal(kcondvar_t *cv);
extern void cv_broadcast(kcondvar_t *cv);
/*
* Thread-specific data
*/
#define tsd_get(k) pthread_getspecific(k)
#define tsd_set(k, v) pthread_setspecific(k, v)
#define tsd_create(kp, d) pthread_key_create(kp, d)
#define tsd_destroy(kp) /* nothing */
/*
* Kernel memory
*/
@ -457,6 +471,9 @@ extern vnode_t *rootdir;
extern void delay(clock_t ticks);
#define SEC_TO_TICK(sec) ((sec) * hz)
#define NSEC_TO_TICK(usec) ((usec) / (NANOSEC / hz))
#define gethrestime_sec() time(NULL)
#define gethrestime(t) \
do {\
@ -516,7 +533,7 @@ typedef struct callb_cpr {
#define INGLOBALZONE(z) (1)
extern char *kmem_asprintf(const char *fmt, ...);
#define strfree(str) kmem_free((str), strlen(str)+1)
#define strfree(str) kmem_free((str), strlen(str) + 1)
/*
* Hostname information
@ -624,6 +641,36 @@ typedef uint32_t idmap_rid_t;
#define ERESTART (-1)
#endif
#ifdef illumos
/*
* Cyclic information
*/
extern kmutex_t cpu_lock;
typedef uintptr_t cyclic_id_t;
typedef uint16_t cyc_level_t;
typedef void (*cyc_func_t)(void *);
#define CY_LOW_LEVEL 0
#define CY_INFINITY INT64_MAX
#define CYCLIC_NONE ((cyclic_id_t)0)
typedef struct cyc_time {
hrtime_t cyt_when;
hrtime_t cyt_interval;
} cyc_time_t;
typedef struct cyc_handler {
cyc_func_t cyh_func;
void *cyh_arg;
cyc_level_t cyh_level;
} cyc_handler_t;
extern cyclic_id_t cyclic_add(cyc_handler_t *, cyc_time_t *);
extern void cyclic_remove(cyclic_id_t);
extern int cyclic_reprogram(cyclic_id_t, hrtime_t);
#endif /* illumos */
#ifdef __cplusplus
}
#endif

View File

@ -363,6 +363,7 @@ sort_iidescs(Elf *elf, const char *file, tdata_t *td, int fuzzymatch,
for (i = 0; i < nent; i++) {
GElf_Sym sym;
char *bname;
iidesc_t **tolist;
GElf_Sym ssym;
iidesc_match_t smatch;
@ -377,7 +378,8 @@ sort_iidescs(Elf *elf, const char *file, tdata_t *td, int fuzzymatch,
switch (GELF_ST_TYPE(sym.st_info)) {
case STT_FILE:
match.iim_file = match.iim_name;
bname = strrchr(match.iim_name, '/');
match.iim_file = bname == NULL ? match.iim_name : bname + 1;
continue;
case STT_OBJECT:
tolist = iiburst->iib_objts;

View File

@ -9,10 +9,12 @@ SUBDIR= ${_drti} \
libnvpair \
libumem \
libuutil \
${_libzfs_core} \
${_libzfs} \
${_libzpool}
.if ${MK_ZFS} != "no"
_libzfs_core= libzfs_core
_libzfs= libzfs
.if ${MK_LIBTHR} != "no"
_libzpool= libzpool

View File

@ -32,6 +32,7 @@ SRCS= dt_aggregate.c \
dt_pcb.c \
dt_pid.c \
dt_pragma.c \
dt_print.c \
dt_printf.c \
dt_proc.c \
dt_program.c \

View File

@ -6,8 +6,9 @@
.PATH: ${.CURDIR}/../../../cddl/contrib/opensolaris/lib/libzfs/common
LIB= zfs
DPADD= ${LIBMD} ${LIBPTHREAD} ${LIBUMEM} ${LIBUTIL} ${LIBM} ${LIBNVPAIR}
LDADD= -lmd -lpthread -lumem -lutil -lm -lnvpair
DPADD= ${LIBMD} ${LIBPTHREAD} ${LIBUMEM} ${LIBUTIL} ${LIBM} ${LIBNVPAIR} \
${LIBZFS_CORE}
LDADD= -lmd -lpthread -lumem -lutil -lm -lnvpair -lzfs_core
SRCS= deviceid.c \
fsshare.c \
@ -17,6 +18,7 @@ SRCS= deviceid.c \
zone.c
SRCS+= libzfs_changelist.c \
libzfs_compat.c \
libzfs_config.c \
libzfs_dataset.c \
libzfs_diff.c \
@ -54,5 +56,6 @@ CFLAGS+= -I${.CURDIR}/../../../sys/cddl/contrib/opensolaris/uts/common
CFLAGS+= -I${.CURDIR}/../../../cddl/contrib/opensolaris/lib/libnvpair
CFLAGS+= -I${.CURDIR}/../../../cddl/contrib/opensolaris/lib/libuutil/common
CFLAGS+= -I${.CURDIR}/../../../cddl/contrib/opensolaris/lib/libzfs/common
CFLAGS+= -I${.CURDIR}/../../../cddl/contrib/opensolaris/lib/libzfs_core/common
.include <bsd.lib.mk>

View File

@ -0,0 +1,37 @@
# $FreeBSD$
.PATH: ${.CURDIR}/../../../cddl/compat/opensolaris/misc
.PATH: ${.CURDIR}/../../../sys/cddl/contrib/opensolaris/common/zfs
.PATH: ${.CURDIR}/../../../sys/cddl/contrib/opensolaris/uts/common/fs/zfs
.PATH: ${.CURDIR}/../../../cddl/contrib/opensolaris/lib/libzfs_core/common
.PATH: ${.CURDIR}/../../../cddl/contrib/opensolaris/lib/libzfs/common
LIB= zfs_core
DPADD= ${LIBNVPAIR}
LDADD= -lnvpair
SRCS= libzfs_core.c \
libzfs_core_compat.c
SRCS+= libzfs_compat.c
WARNS?= 0
CSTD= c99
CFLAGS+= -DZFS_NO_ACL
CFLAGS+= -I${.CURDIR}/../../../sbin/mount
CFLAGS+= -I${.CURDIR}/../../../cddl/lib/libumem
CFLAGS+= -I${.CURDIR}/../../../sys/cddl/compat/opensolaris
CFLAGS+= -I${.CURDIR}/../../../cddl/compat/opensolaris/include
CFLAGS+= -I${.CURDIR}/../../../cddl/compat/opensolaris/lib/libumem
CFLAGS+= -I${.CURDIR}/../../../cddl/contrib/opensolaris/lib/libzpool/common
CFLAGS+= -I${.CURDIR}/../../../sys/cddl/contrib/opensolaris/common/zfs
CFLAGS+= -I${.CURDIR}/../../../sys/cddl/contrib/opensolaris/uts/common/fs/zfs
CFLAGS+= -I${.CURDIR}/../../../sys/cddl/contrib/opensolaris/uts/common/sys
CFLAGS+= -I${.CURDIR}/../../../cddl/contrib/opensolaris/head
CFLAGS+= -I${.CURDIR}/../../../sys/cddl/contrib/opensolaris/uts/common
CFLAGS+= -I${.CURDIR}/../../../cddl/contrib/opensolaris/lib/libnvpair
CFLAGS+= -I${.CURDIR}/../../../cddl/contrib/opensolaris/lib/libuutil/common
CFLAGS+= -I${.CURDIR}/../../../cddl/contrib/opensolaris/lib/libzfs_core/common
CFLAGS+= -I${.CURDIR}/../../../cddl/contrib/opensolaris/lib/libzfs/common
.include <bsd.lib.mk>

View File

@ -14,6 +14,7 @@ CFLAGS+= -I${.CURDIR}/../../../sys/cddl/compat/opensolaris
CFLAGS+= -I${.CURDIR}/../../../cddl/contrib/opensolaris/head
CFLAGS+= -I${.CURDIR}/../../../cddl/contrib/opensolaris/lib/libuutil/common
CFLAGS+= -I${.CURDIR}/../../../cddl/contrib/opensolaris/lib/libzfs/common
CFLAGS+= -I${.CURDIR}/../../../cddl/contrib/opensolaris/lib/libzfs_core/common
CFLAGS+= -I${.CURDIR}/../../../cddl/contrib/opensolaris/lib/libumem/common
CFLAGS+= -I${.CURDIR}/../../../cddl/contrib/opensolaris/lib/libnvpair
CFLAGS+= -I${.CURDIR}/../../../sys/cddl/contrib/opensolaris/uts/common
@ -22,7 +23,7 @@ CFLAGS+= -I${.CURDIR}/../../../sys/cddl/contrib/opensolaris/uts/common/sys
CFLAGS+= -I${.CURDIR}/../../../sys/cddl/contrib/opensolaris/common/zfs
DPADD= ${LIBGEOM} ${LIBJAIL} ${LIBNVPAIR} ${LIBUMEM} \
${LIBUTIL} ${LIBUUTIL} ${LIBZFS}
LDADD= -lgeom -ljail -lnvpair -lumem -lutil -luutil -lzfs
${LIBUTIL} ${LIBUUTIL} ${LIBZFS_CORE} ${LIBZFS}
LDADD= -lgeom -ljail -lnvpair -lumem -lutil -luutil -lzfs_core -lzfs
.include <bsd.prog.mk>

View File

@ -27,7 +27,7 @@ CFLAGS+= -I${.CURDIR}/../../../cddl/contrib/opensolaris/lib/libzpool/common
CFLAGS+= -I${.CURDIR}/../../../cddl/contrib/opensolaris/cmd/stat/common
DPADD= ${LIBAVL} ${LIBGEOM} ${LIBNVPAIR} \
${LIBUMEM} ${LIBUTIL} ${LIBUUTIL} ${LIBZFS}
LDADD= -lavl -lgeom -lnvpair -lumem -lutil -luutil -lzfs
${LIBUMEM} ${LIBUTIL} ${LIBUUTIL} ${LIBZFS_CORE} ${LIBZFS}
LDADD= -lavl -lgeom -lnvpair -lumem -lutil -luutil -lzfs_core -lzfs
.include <bsd.prog.mk>

View File

@ -20,7 +20,7 @@ CFLAGS+= -I${.CURDIR}/../../contrib/opensolaris/head
CFLAGS+= -I${.CURDIR}/../../lib/libumem
DPADD= ${LIBGEOM} ${LIBM} ${LIBNVPAIR} ${LIBUMEM} ${LIBUUTIL} \
${LIBZFS} ${LIBZPOOL}
LDADD= -lgeom -lm -lnvpair -lumem -luutil -lzfs -lzpool
${LIBZFS_CORE} ${LIBZFS} ${LIBZPOOL}
LDADD= -lgeom -lm -lnvpair -lumem -luutil -lzfs_core -lzfs -lzpool
.include <bsd.prog.mk>

View File

@ -19,8 +19,9 @@ CFLAGS+= -I${.CURDIR}/../../contrib/opensolaris/head
CFLAGS+= -I${.CURDIR}/../../lib/libumem
DPADD= ${LIBGEOM} ${LIBM} ${LIBNVPAIR} ${LIBUMEM} ${LIBZPOOL} \
${LIBPTHREAD} ${LIBAVL} ${LIBZFS} ${LIBUUTIL}
LDADD= -lgeom -lm -lnvpair -lumem -lzpool -lpthread -lavl -lzfs -luutil
${LIBPTHREAD} ${LIBAVL} ${LIBZFS_CORE} ${LIBZFS} ${LIBUUTIL}
LDADD= -lgeom -lm -lnvpair -lumem -lzpool -lpthread -lavl -lzfs_core -lzfs \
-luutil
CSTD= c99

View File

@ -24,8 +24,8 @@ CFLAGS+= -I${.CURDIR}/../../../cddl/contrib/opensolaris/head
CFLAGS+= -I${.CURDIR}/../../lib/libumem
DPADD= ${LIBGEOM} ${LIBM} ${LIBNVPAIR} ${LIBPTHREAD} ${LIBUMEM} \
${LIBUUTIL} ${LIBZFS} ${LIBZPOOL}
LDADD= -lgeom -lm -lnvpair -lpthread -lumem -luutil -lzfs -lzpool
${LIBUUTIL} ${LIBZFS_CORE} ${LIBZFS} ${LIBZPOOL}
LDADD= -lgeom -lm -lnvpair -lpthread -lumem -luutil -lzfs_core -lzfs -lzpool
CFLAGS+= -DDEBUG=1
#DEBUG_FLAGS+= -g

View File

@ -23,8 +23,8 @@ CFLAGS+= -I${.CURDIR}/../../../cddl/contrib/opensolaris/head
CFLAGS+= -I${.CURDIR}/../../lib/libumem
DPADD= ${LIBGEOM} ${LIBM} ${LIBNVPAIR} ${LIBPTHREAD} ${LIBUMEM} \
${LIBUUTIL} ${LIBZFS} ${LIBZPOOL}
LDADD= -lgeom -lm -lnvpair -lpthread -lumem -luutil -lzfs -lzpool
${LIBUUTIL} ${LIBZFS_CORE} ${LIBZFS} ${LIBZPOOL}
LDADD= -lgeom -lm -lnvpair -lpthread -lumem -luutil -lzfs_core -lzfs -lzpool
CFLAGS+= -DDEBUG=1
#DEBUG_FLAGS+= -g

View File

@ -1,3 +1,10 @@
--- 9.8.4-P2 released ---
3516. [security] Removed the check for regex.h in configure in order
to disable regex syntax checking, as it exposes
BIND to a critical flaw in libregex on some
platforms. [RT #32688]
--- 9.8.4-P1 released ---
3407. [security] Named could die on specific queries with dns64 enabled.

View File

@ -286,9 +286,6 @@ int sigwait(const unsigned int *set, int *sig);
/* Define if your OpenSSL version supports GOST. */
#undef HAVE_OPENSSL_GOST
/* Define to 1 if you have the <regex.h> header file. */
#undef HAVE_REGEX_H
/* Define to 1 if you have the `setegid' function. */
#undef HAVE_SETEGID

View File

@ -298,7 +298,7 @@ esac
AC_HEADER_STDC
AC_CHECK_HEADERS(fcntl.h regex.h sys/time.h unistd.h sys/sockio.h sys/select.h sys/param.h sys/sysctl.h net/if6.h,,,
AC_CHECK_HEADERS(fcntl.h sys/time.h unistd.h sys/sockio.h sys/select.h sys/param.h sys/sysctl.h net/if6.h,,,
[$ac_includes_default
#ifdef HAVE_SYS_PARAM_H
# include <sys/param.h>

View File

@ -7,4 +7,4 @@ MAJORVER=9
MINORVER=8
PATCHVER=4
RELEASETYPE=-P
RELEASEVER=1
RELEASEVER=2

View File

@ -633,6 +633,9 @@ read_attribute_value (struct attribute *attr,
attr->u.val = read_1_byte (abfd, info_ptr);
info_ptr += 1;
break;
case DW_FORM_flag_present:
attr->u.val = 1;
break;
case DW_FORM_sdata:
attr->u.sval = read_signed_leb128 (abfd, info_ptr, &bytes_read);
info_ptr += bytes_read;

View File

@ -557,6 +557,7 @@ get_FORM_name (unsigned long form)
case DW_FORM_ref8: return "DW_FORM_ref8";
case DW_FORM_ref_udata: return "DW_FORM_ref_udata";
case DW_FORM_indirect: return "DW_FORM_indirect";
case DW_FORM_flag_present: return "DW_FORM_flag_present";
default:
{
static char buffer[100];
@ -969,6 +970,10 @@ read_and_display_attr_value (unsigned long attribute,
data += offset_size;
break;
case DW_FORM_flag_present:
uvalue = 1;
break;
case DW_FORM_ref1:
case DW_FORM_flag:
case DW_FORM_data1:
@ -1030,6 +1035,7 @@ read_and_display_attr_value (unsigned long attribute,
printf (" %#lx", uvalue);
break;
case DW_FORM_flag_present:
case DW_FORM_flag:
case DW_FORM_data1:
case DW_FORM_data2:

Some files were not shown because too many files have changed in this diff Show More