IFC to head to catch up the bhyve branch
Approved by: grehan@
This commit is contained in:
commit
80dbff4e99
Notes:
svn2git
2020-12-20 02:59:44 +00:00
svn path=/projects/bhyve/; revision=229455
@ -4,7 +4,7 @@
|
||||
The compilation of software known as FreeBSD is distributed under the
|
||||
following terms:
|
||||
|
||||
Copyright (c) 1992-2011 The FreeBSD Project. All rights reserved.
|
||||
Copyright (c) 1992-2012 The FreeBSD Project. All rights reserved.
|
||||
|
||||
Redistribution and use in source and binary forms, with or without
|
||||
modification, are permitted provided that the following conditions
|
||||
|
@ -59,8 +59,6 @@ SUBDIR+=games
|
||||
.endif
|
||||
.if ${MK_CDDL} != "no"
|
||||
SUBDIR+=cddl
|
||||
.else
|
||||
NO_CTF=1
|
||||
.endif
|
||||
SUBDIR+=gnu include
|
||||
.if ${MK_KERBEROS} != "no"
|
||||
@ -239,7 +237,7 @@ BMAKE= MAKEOBJDIRPREFIX=${WORLDTMP} \
|
||||
BOOTSTRAPPING=${OSRELDATE} \
|
||||
SSP_CFLAGS= \
|
||||
-DWITHOUT_HTML -DWITHOUT_INFO -DNO_LINT -DWITHOUT_MAN \
|
||||
-DNO_PIC -DWITHOUT_PROFILE -DNO_SHARED \
|
||||
-DNO_PIC -DNO_PROFILE -DNO_SHARED \
|
||||
-DNO_CPU_CFLAGS -DNO_WARNS -DNO_CTF
|
||||
|
||||
# build-tools stage
|
||||
@ -278,7 +276,6 @@ LIB32CPUFLAGS= -march=i686 -mmmx -msse -msse2
|
||||
.else
|
||||
LIB32CPUFLAGS= -march=${TARGET_CPUTYPE}
|
||||
.endif
|
||||
LIB32CPUFLAGS+= -mfancy-math-387
|
||||
LIB32WMAKEENV= MACHINE=i386 MACHINE_ARCH=i386 \
|
||||
MACHINE_CPU="i686 mmx sse sse2" \
|
||||
LD="${LD} -m elf_i386_fbsd -Y P,${LIB32TMP}/usr/lib32" \
|
||||
@ -438,7 +435,7 @@ _libraries:
|
||||
@echo "--------------------------------------------------------------"
|
||||
${_+_}cd ${.CURDIR}; \
|
||||
${WMAKE} -DNO_FSCHG -DWITHOUT_HTML -DWITHOUT_INFO -DNO_LINT \
|
||||
-DWITHOUT_MAN -DWITHOUT_PROFILE libraries
|
||||
-DWITHOUT_MAN -DNO_PROFILE libraries
|
||||
_depend:
|
||||
@echo
|
||||
@echo "--------------------------------------------------------------"
|
||||
@ -1218,6 +1215,9 @@ _startup_libs+= lib/csu/${MACHINE_CPUARCH}
|
||||
_startup_libs+= gnu/lib/libgcc
|
||||
_startup_libs+= lib/libcompiler_rt
|
||||
_startup_libs+= lib/libc
|
||||
.if ${MK_LIBCPLUSPLUS} != "no"
|
||||
_startup_libs+= lib/libcxxrt
|
||||
.endif
|
||||
|
||||
gnu/lib/libgcc__L: lib/libc__L
|
||||
|
||||
@ -1230,13 +1230,12 @@ _prebuild_libs= ${_kerberos5_lib_libasn1} ${_kerberos5_lib_libhdb} \
|
||||
${_lib_libgssapi} ${_lib_libipx} \
|
||||
lib/libkiconv lib/libkvm lib/liblzma lib/libmd \
|
||||
lib/ncurses/ncurses lib/ncurses/ncursesw \
|
||||
lib/libopie ${_lib_libthr} \
|
||||
lib/libopie lib/libpam ${_lib_libthr} \
|
||||
lib/libradius lib/libsbuf lib/libtacplus \
|
||||
${_cddl_lib_libumem} \
|
||||
lib/libutil ${_lib_libypclnt} lib/libz lib/msun \
|
||||
${_secure_lib_libcrypto} ${_secure_lib_libssh} \
|
||||
${_secure_lib_libssl} \
|
||||
lib/libpam
|
||||
${_secure_lib_libssl}
|
||||
|
||||
.if ${MK_LIBTHR} != "no"
|
||||
_lib_libthr= lib/libthr
|
||||
@ -1319,12 +1318,12 @@ ${_lib}__PL: .PHONY
|
||||
cd ${.CURDIR}/${_lib}; \
|
||||
${MAKE} DIRPRFX=${_lib}/ obj; \
|
||||
${MAKE} DIRPRFX=${_lib}/ depend; \
|
||||
${MAKE} -DWITHOUT_PROFILE -DNO_PIC DIRPRFX=${_lib}/ all; \
|
||||
${MAKE} -DWITHOUT_PROFILE -DNO_PIC DIRPRFX=${_lib}/ install
|
||||
${MAKE} -DNO_PROFILE -DNO_PIC DIRPRFX=${_lib}/ all; \
|
||||
${MAKE} -DNO_PROFILE -DNO_PIC DIRPRFX=${_lib}/ install
|
||||
.endif
|
||||
.endfor
|
||||
|
||||
.for _lib in ${_startup_libs} ${_prebuild_libs} ${_generic_libs}
|
||||
.for _lib in ${_startup_libs} ${_prebuild_libs:Nlib/libpam} ${_generic_libs}
|
||||
${_lib}__L: .PHONY
|
||||
.if exists(${.CURDIR}/${_lib})
|
||||
${_+_}@${ECHODIR} "===> ${_lib} (obj,depend,all,install)"; \
|
||||
@ -1336,6 +1335,17 @@ ${_lib}__L: .PHONY
|
||||
.endif
|
||||
.endfor
|
||||
|
||||
# libpam is special: we need to build static PAM modules before
|
||||
# static PAM library, and dynamic PAM library before dynamic PAM
|
||||
# modules.
|
||||
lib/libpam__L: .PHONY
|
||||
${_+_}@${ECHODIR} "===> lib/libpam (obj,depend,all,install)"; \
|
||||
cd ${.CURDIR}/lib/libpam; \
|
||||
${MAKE} DIRPRFX=lib/libpam/ obj; \
|
||||
${MAKE} DIRPRFX=lib/libpam/ depend; \
|
||||
${MAKE} DIRPRFX=lib/libpam/ -D_NO_LIBPAM_SO_YET all; \
|
||||
${MAKE} DIRPRFX=lib/libpam/ -D_NO_LIBPAM_SO_YET install
|
||||
|
||||
_prereq_libs: ${_prereq_libs:S/$/__PL/}
|
||||
_startup_libs: ${_startup_libs:S/$/__L/}
|
||||
_prebuild_libs: ${_prebuild_libs:S/$/__L/}
|
||||
@ -1542,7 +1552,7 @@ XDEV_CPUTYPE?=${TARGET_CPUTYPE}
|
||||
.endif
|
||||
|
||||
NOFUN=-DNO_FSCHG -DWITHOUT_HTML -DWITHOUT_INFO -DNO_LINT \
|
||||
-DWITHOUT_MAN -DWITHOUT_NLS -DWITHOUT_PROFILE \
|
||||
-DWITHOUT_MAN -DWITHOUT_NLS -DNO_PROFILE \
|
||||
-DWITHOUT_KERBEROS -DWITHOUT_RESCUE -DNO_WARNS \
|
||||
TARGET=${XDEV} TARGET_ARCH=${XDEV_ARCH} \
|
||||
CPUTYPE=${XDEV_CPUTYPE}
|
||||
@ -1626,4 +1636,7 @@ _xi-links:
|
||||
ln -sf ../../${XDTP}/usr/bin/$$i \
|
||||
../../../../usr/bin/${XDDIR}${OSREL}-$$i; \
|
||||
done
|
||||
.else
|
||||
xdev xdev-buil xdev-install:
|
||||
@echo "*** Error: Both XDEV and XDEV_ARCH must be defined for \"${.TARGET}\" target"
|
||||
.endif
|
||||
|
@ -38,6 +38,21 @@
|
||||
# xargs -n1 | sort | uniq -d;
|
||||
# done
|
||||
|
||||
# 20111214: eventtimers(7) moved to eventtimers(4)
|
||||
OLD_FILES+=usr/share/man/man7/eventtimers.7.gz
|
||||
# 20111125: amd(4) removed
|
||||
OLD_FILES+=usr/share/man/man4/amd.4.gz
|
||||
# 20111125: libodialog removed
|
||||
OLD_FILES+=usr/lib/libodialog.a
|
||||
OLD_FILES+=usr/lib/libodialog.so
|
||||
OLD_LIBS+=usr/lib/libodialog.so.7
|
||||
OLD_FILES+=usr/lib/libodialog_p.a
|
||||
.if ${TARGET_ARCH} == "amd64" || ${TARGET_ARCH} == "powerpc64"
|
||||
OLD_FILES+=usr/lib32/libodialog.a
|
||||
OLD_FILES+=usr/lib32/libodialog.so
|
||||
OLD_LIBS+=usr/lib32/libodialog.so.7
|
||||
OLD_FILES+=usr/lib32/libodialog_p.a
|
||||
.endif
|
||||
# 20110930: sysinstall removed
|
||||
OLD_FILES+=usr/sbin/sysinstall
|
||||
OLD_FILES+=usr/share/man/man8/sysinstall.8.gz
|
||||
|
15
UPDATING
15
UPDATING
@ -22,6 +22,21 @@ NOTE TO PEOPLE WHO THINK THAT FreeBSD 10.x IS SLOW:
|
||||
machines to maximize performance. (To disable malloc debugging, run
|
||||
ln -s aj /etc/malloc.conf.)
|
||||
|
||||
20111215:
|
||||
The carp(4) facility has been changed significantly. Configuration
|
||||
of the CARP protocol via ifconfig(8) has changed, as well as format
|
||||
of CARP events submitted to devd(8) has changed. See manual pages
|
||||
for more information. The arpbalance feature of carp(4) is currently
|
||||
not supported anymore.
|
||||
|
||||
Size of struct in_aliasreq, struct in6_aliasreq has changed. User
|
||||
utilities using SIOCAIFADDR, SIOCAIFADDR_IN6, e.g. ifconfig(8),
|
||||
need to be recompiled.
|
||||
|
||||
20111122:
|
||||
The acpi_wmi(4) status device /dev/wmistat has been renamed to
|
||||
/dev/wmistat0.
|
||||
|
||||
20111108:
|
||||
The option VFS_ALLOW_NONMPSAFE option has been added in order to
|
||||
explicitely support non-MPSAFE filesystems.
|
||||
|
@ -87,7 +87,7 @@ static int do_voltag(const char *, int, char **);
|
||||
#endif
|
||||
|
||||
/* Valid changer element types. */
|
||||
const struct element_type elements[] = {
|
||||
static const struct element_type elements[] = {
|
||||
{ "drive", CHET_DT },
|
||||
{ "picker", CHET_MT },
|
||||
{ "portal", CHET_IE },
|
||||
@ -97,7 +97,7 @@ const struct element_type elements[] = {
|
||||
};
|
||||
|
||||
/* Valid commands. */
|
||||
const struct changer_command commands[] = {
|
||||
static const struct changer_command commands[] = {
|
||||
{ "exchange", do_exchange },
|
||||
{ "getpicker", do_getpicker },
|
||||
{ "ielem", do_ielem },
|
||||
@ -112,7 +112,7 @@ const struct changer_command commands[] = {
|
||||
};
|
||||
|
||||
/* Valid special words. */
|
||||
const struct special_word specials[] = {
|
||||
static const struct special_word specials[] = {
|
||||
{ "inv", SW_INVERT },
|
||||
{ "inv1", SW_INVERT1 },
|
||||
{ "inv2", SW_INVERT2 },
|
||||
|
@ -53,7 +53,8 @@ read_file(char *fn, long n)
|
||||
errmsg = "cannot close input file";
|
||||
return ERR;
|
||||
}
|
||||
fprintf(stdout, !scripted ? "%lu\n" : "", size);
|
||||
if (!scripted)
|
||||
fprintf(stdout, "%lu\n", size);
|
||||
return current_addr - n;
|
||||
}
|
||||
|
||||
@ -161,7 +162,8 @@ write_file(char *fn, const char *mode, long n, long m)
|
||||
errmsg = "cannot close output file";
|
||||
return ERR;
|
||||
}
|
||||
fprintf(stdout, !scripted ? "%lu\n" : "", size);
|
||||
if (!scripted)
|
||||
fprintf(stdout, "%lu\n", size);
|
||||
return n ? m - n + 1 : 0;
|
||||
}
|
||||
|
||||
|
@ -192,9 +192,10 @@ main(volatile int argc, char ** volatile argv)
|
||||
fputs("?\n", stderr);
|
||||
errmsg = "warning: file modified";
|
||||
if (!isatty(0)) {
|
||||
fprintf(stderr, garrulous ?
|
||||
"script, line %d: %s\n" :
|
||||
"", lineno, errmsg);
|
||||
if (garrulous)
|
||||
fprintf(stderr,
|
||||
"script, line %d: %s\n",
|
||||
lineno, errmsg);
|
||||
quit(2);
|
||||
}
|
||||
clearerr(stdin);
|
||||
@ -225,27 +226,26 @@ main(volatile int argc, char ** volatile argv)
|
||||
fputs("?\n", stderr); /* give warning */
|
||||
errmsg = "warning: file modified";
|
||||
if (!isatty(0)) {
|
||||
fprintf(stderr, garrulous ?
|
||||
"script, line %d: %s\n" :
|
||||
"", lineno, errmsg);
|
||||
if (garrulous)
|
||||
fprintf(stderr, "script, line %d: %s\n",
|
||||
lineno, errmsg);
|
||||
quit(2);
|
||||
}
|
||||
break;
|
||||
case FATAL:
|
||||
if (!isatty(0))
|
||||
fprintf(stderr, garrulous ?
|
||||
"script, line %d: %s\n" : "",
|
||||
lineno, errmsg);
|
||||
else
|
||||
fprintf(stderr, garrulous ? "%s\n" : "",
|
||||
errmsg);
|
||||
if (!isatty(0)) {
|
||||
if (garrulous)
|
||||
fprintf(stderr, "script, line %d: %s\n",
|
||||
lineno, errmsg);
|
||||
} else if (garrulous)
|
||||
fprintf(stderr, "%s\n", errmsg);
|
||||
quit(3);
|
||||
default:
|
||||
fputs("?\n", stderr);
|
||||
if (!isatty(0)) {
|
||||
fprintf(stderr, garrulous ?
|
||||
"script, line %d: %s\n" : "",
|
||||
lineno, errmsg);
|
||||
if (garrulous)
|
||||
fprintf(stderr, "script, line %d: %s\n",
|
||||
lineno, errmsg);
|
||||
quit(2);
|
||||
}
|
||||
break;
|
||||
|
11
bin/ps/ps.1
11
bin/ps/ps.1
@ -29,7 +29,7 @@
|
||||
.\" @(#)ps.1 8.3 (Berkeley) 4/18/94
|
||||
.\" $FreeBSD$
|
||||
.\"
|
||||
.Dd October 30, 2011
|
||||
.Dd November 22, 2011
|
||||
.Dt PS 1
|
||||
.Os
|
||||
.Sh NAME
|
||||
@ -98,12 +98,6 @@ The default output format includes, for each process, the process' ID,
|
||||
controlling terminal, state, CPU time (including both user and system time)
|
||||
and associated command.
|
||||
.Pp
|
||||
The process file system (see
|
||||
.Xr procfs 5 )
|
||||
should be mounted when
|
||||
.Nm
|
||||
is executed, otherwise not all information will be available.
|
||||
.Pp
|
||||
The options are as follows:
|
||||
.Bl -tag -width indent
|
||||
.It Fl a
|
||||
@ -686,9 +680,6 @@ attempts to automatically determine the terminal width.
|
||||
.Bl -tag -width ".Pa /boot/kernel/kernel" -compact
|
||||
.It Pa /boot/kernel/kernel
|
||||
default system namelist
|
||||
.It Pa /proc
|
||||
the mount point of
|
||||
.Xr procfs 5
|
||||
.El
|
||||
.Sh SEE ALSO
|
||||
.Xr kill 1 ,
|
||||
|
21
bin/ps/ps.c
21
bin/ps/ps.c
@ -130,7 +130,6 @@ struct listinfo {
|
||||
} l;
|
||||
};
|
||||
|
||||
static int check_procfs(void);
|
||||
static int addelem_gid(struct listinfo *, const char *);
|
||||
static int addelem_pid(struct listinfo *, const char *);
|
||||
static int addelem_tty(struct listinfo *, const char *);
|
||||
@ -410,14 +409,6 @@ main(int argc, char *argv[])
|
||||
argc -= optind;
|
||||
argv += optind;
|
||||
|
||||
/*
|
||||
* If the user specified ps -e then they want a copy of the process
|
||||
* environment kvm_getenvv(3) attempts to open /proc/<pid>/mem.
|
||||
* Check to make sure that procfs is mounted on /proc, otherwise
|
||||
* print a warning informing the user that output will be incomplete.
|
||||
*/
|
||||
if (needenv == 1 && check_procfs() == 0)
|
||||
warnx("Process environment requires procfs(5)");
|
||||
/*
|
||||
* If there arguments after processing all the options, attempt
|
||||
* to treat them as a list of process ids.
|
||||
@ -1360,18 +1351,6 @@ kludge_oldps_options(const char *optlist, char *origval, const char *nextarg)
|
||||
return (newopts);
|
||||
}
|
||||
|
||||
static int
|
||||
check_procfs(void)
|
||||
{
|
||||
struct statfs mnt;
|
||||
|
||||
if (statfs("/proc", &mnt) < 0)
|
||||
return (0);
|
||||
if (strcmp(mnt.f_fstypename, "procfs") != 0)
|
||||
return (0);
|
||||
return (1);
|
||||
}
|
||||
|
||||
static void
|
||||
usage(void)
|
||||
{
|
||||
|
@ -89,7 +89,7 @@ int oexitstatus; /* saved exit status */
|
||||
|
||||
static void evalloop(union node *, int);
|
||||
static void evalfor(union node *, int);
|
||||
static void evalcase(union node *, int);
|
||||
static union node *evalcase(union node *, int);
|
||||
static void evalsubshell(union node *, int);
|
||||
static void evalredir(union node *, int);
|
||||
static void expredir(union node *);
|
||||
@ -256,7 +256,7 @@ evaltree(union node *n, int flags)
|
||||
evalfor(n, flags & ~EV_EXIT);
|
||||
break;
|
||||
case NCASE:
|
||||
evalcase(n, flags);
|
||||
next = evalcase(n, flags);
|
||||
break;
|
||||
case NDEFUN:
|
||||
defun(n->narg.text, n->narg.next);
|
||||
@ -343,8 +343,6 @@ evalfor(union node *n, int flags)
|
||||
for (argp = n->nfor.args ; argp ; argp = argp->narg.next) {
|
||||
oexitstatus = exitstatus;
|
||||
expandarg(argp, &arglist, EXP_FULL | EXP_TILDE);
|
||||
if (evalskip)
|
||||
goto out;
|
||||
}
|
||||
*arglist.lastp = NULL;
|
||||
|
||||
@ -364,13 +362,12 @@ evalfor(union node *n, int flags)
|
||||
}
|
||||
}
|
||||
loopnest--;
|
||||
out:
|
||||
popstackmark(&smark);
|
||||
}
|
||||
|
||||
|
||||
|
||||
static void
|
||||
static union node *
|
||||
evalcase(union node *n, int flags)
|
||||
{
|
||||
union node *cp;
|
||||
@ -383,26 +380,24 @@ evalcase(union node *n, int flags)
|
||||
oexitstatus = exitstatus;
|
||||
exitstatus = 0;
|
||||
expandarg(n->ncase.expr, &arglist, EXP_TILDE);
|
||||
for (cp = n->ncase.cases ; cp && evalskip == 0 ; cp = cp->nclist.next) {
|
||||
for (cp = n->ncase.cases ; cp ; cp = cp->nclist.next) {
|
||||
for (patp = cp->nclist.pattern ; patp ; patp = patp->narg.next) {
|
||||
if (casematch(patp, arglist.list->text)) {
|
||||
popstackmark(&smark);
|
||||
while (cp->nclist.next &&
|
||||
cp->type == NCLISTFALLTHRU) {
|
||||
if (evalskip != 0)
|
||||
break;
|
||||
evaltree(cp->nclist.body,
|
||||
flags & ~EV_EXIT);
|
||||
if (evalskip != 0)
|
||||
return (NULL);
|
||||
cp = cp->nclist.next;
|
||||
}
|
||||
if (evalskip == 0) {
|
||||
evaltree(cp->nclist.body, flags);
|
||||
}
|
||||
goto out;
|
||||
return (cp->nclist.body);
|
||||
}
|
||||
}
|
||||
}
|
||||
out:
|
||||
popstackmark(&smark);
|
||||
return (NULL);
|
||||
}
|
||||
|
||||
|
||||
@ -983,7 +978,6 @@ evalcommand(union node *cmd, int flags, struct backcmd *backcmd)
|
||||
memout.nextc = memout.buf;
|
||||
memout.bufsize = 64;
|
||||
mode |= REDIR_BACKQ;
|
||||
cmdentry.special = 0;
|
||||
}
|
||||
savecmdname = commandname;
|
||||
savetopfile = getcurrentfile();
|
||||
@ -1004,7 +998,7 @@ evalcommand(union node *cmd, int flags, struct backcmd *backcmd)
|
||||
* If there is no command word, redirection errors should
|
||||
* not be fatal but assignment errors should.
|
||||
*/
|
||||
if (argc == 0 && !(flags & EV_BACKCMD))
|
||||
if (argc == 0)
|
||||
cmdentry.special = 1;
|
||||
listsetvar(cmdenviron, cmdentry.special ? 0 : VNOSET);
|
||||
if (argc > 0)
|
||||
|
@ -100,6 +100,7 @@ static void tryexec(char *, char **, char **);
|
||||
static void printentry(struct tblentry *, int);
|
||||
static struct tblentry *cmdlookup(const char *, int);
|
||||
static void delete_cmd_entry(void);
|
||||
static void addcmdentry(const char *, struct cmdentry *);
|
||||
|
||||
|
||||
|
||||
@ -593,7 +594,7 @@ delete_cmd_entry(void)
|
||||
* the same name.
|
||||
*/
|
||||
|
||||
void
|
||||
static void
|
||||
addcmdentry(const char *name, struct cmdentry *entry)
|
||||
{
|
||||
struct tblentry *cmdp;
|
||||
|
@ -70,7 +70,6 @@ void find_command(const char *, struct cmdentry *, int, const char *);
|
||||
int find_builtin(const char *, int *);
|
||||
void hashcd(void);
|
||||
void changepath(const char *);
|
||||
void addcmdentry(const char *, struct cmdentry *);
|
||||
void defun(const char *, union node *);
|
||||
int unsetfunc(const char *);
|
||||
int typecmd_impl(int, char **, int, const char *);
|
||||
|
120
bin/sh/expand.c
120
bin/sh/expand.c
@ -113,6 +113,7 @@ static void expmeta(char *, char *);
|
||||
static void addfname(char *);
|
||||
static struct strlist *expsort(struct strlist *);
|
||||
static struct strlist *msort(struct strlist *, int);
|
||||
static int patmatch(const char *, const char *, int);
|
||||
static char *cvtnum(int, char *);
|
||||
static int collate_range_cmp(wchar_t, wchar_t);
|
||||
|
||||
@ -1186,6 +1187,7 @@ expmeta(char *enddir, char *name)
|
||||
int atend;
|
||||
int matchdot;
|
||||
int esc;
|
||||
int namlen;
|
||||
|
||||
metaflag = 0;
|
||||
start = name;
|
||||
@ -1284,17 +1286,22 @@ expmeta(char *enddir, char *name)
|
||||
if (dp->d_name[0] == '.' && ! matchdot)
|
||||
continue;
|
||||
if (patmatch(start, dp->d_name, 0)) {
|
||||
if (enddir + dp->d_namlen + 1 > expdir_end)
|
||||
namlen = dp->d_namlen;
|
||||
if (enddir + namlen + 1 > expdir_end)
|
||||
continue;
|
||||
memcpy(enddir, dp->d_name, dp->d_namlen + 1);
|
||||
memcpy(enddir, dp->d_name, namlen + 1);
|
||||
if (atend)
|
||||
addfname(expdir);
|
||||
else {
|
||||
if (enddir + dp->d_namlen + 2 > expdir_end)
|
||||
if (dp->d_type != DT_UNKNOWN &&
|
||||
dp->d_type != DT_DIR &&
|
||||
dp->d_type != DT_LNK)
|
||||
continue;
|
||||
enddir[dp->d_namlen] = '/';
|
||||
enddir[dp->d_namlen + 1] = '\0';
|
||||
expmeta(enddir + dp->d_namlen + 1, endname);
|
||||
if (enddir + namlen + 2 > expdir_end)
|
||||
continue;
|
||||
enddir[namlen] = '/';
|
||||
enddir[namlen + 1] = '\0';
|
||||
expmeta(enddir + namlen + 1, endname);
|
||||
}
|
||||
}
|
||||
}
|
||||
@ -1435,61 +1442,67 @@ match_charclass(const char *p, wchar_t chr, const char **end)
|
||||
* Returns true if the pattern matches the string.
|
||||
*/
|
||||
|
||||
int
|
||||
static int
|
||||
patmatch(const char *pattern, const char *string, int squoted)
|
||||
{
|
||||
const char *p, *q, *end;
|
||||
const char *bt_p, *bt_q;
|
||||
char c;
|
||||
wchar_t wc, wc2;
|
||||
|
||||
p = pattern;
|
||||
q = string;
|
||||
bt_p = NULL;
|
||||
bt_q = NULL;
|
||||
for (;;) {
|
||||
switch (c = *p++) {
|
||||
case '\0':
|
||||
goto breakloop;
|
||||
if (*q != '\0')
|
||||
goto backtrack;
|
||||
return 1;
|
||||
case CTLESC:
|
||||
if (squoted && *q == CTLESC)
|
||||
q++;
|
||||
if (*q++ != *p++)
|
||||
return 0;
|
||||
goto backtrack;
|
||||
break;
|
||||
case CTLQUOTEMARK:
|
||||
continue;
|
||||
case '?':
|
||||
if (squoted && *q == CTLESC)
|
||||
q++;
|
||||
if (localeisutf8)
|
||||
wc = get_wc(&q);
|
||||
else
|
||||
wc = (unsigned char)*q++;
|
||||
if (wc == '\0')
|
||||
if (*q == '\0')
|
||||
return 0;
|
||||
if (localeisutf8) {
|
||||
wc = get_wc(&q);
|
||||
/*
|
||||
* A '?' does not match invalid UTF-8 but a
|
||||
* '*' does, so backtrack.
|
||||
*/
|
||||
if (wc == 0)
|
||||
goto backtrack;
|
||||
} else
|
||||
wc = (unsigned char)*q++;
|
||||
break;
|
||||
case '*':
|
||||
c = *p;
|
||||
while (c == CTLQUOTEMARK || c == '*')
|
||||
c = *++p;
|
||||
if (c != CTLESC && c != CTLQUOTEMARK &&
|
||||
c != '?' && c != '*' && c != '[') {
|
||||
while (*q != c) {
|
||||
if (squoted && *q == CTLESC &&
|
||||
q[1] == c)
|
||||
break;
|
||||
if (*q == '\0')
|
||||
return 0;
|
||||
if (squoted && *q == CTLESC)
|
||||
q++;
|
||||
q++;
|
||||
}
|
||||
}
|
||||
do {
|
||||
if (patmatch(p, q, squoted))
|
||||
return 1;
|
||||
if (squoted && *q == CTLESC)
|
||||
q++;
|
||||
} while (*q++ != '\0');
|
||||
return 0;
|
||||
/*
|
||||
* If the pattern ends here, we know the string
|
||||
* matches without needing to look at the rest of it.
|
||||
*/
|
||||
if (c == '\0')
|
||||
return 1;
|
||||
/*
|
||||
* First try the shortest match for the '*' that
|
||||
* could work. We can forget any earlier '*' since
|
||||
* there is no way having it match more characters
|
||||
* can help us, given that we are already here.
|
||||
*/
|
||||
bt_p = p;
|
||||
bt_q = q;
|
||||
break;
|
||||
case '[': {
|
||||
const char *endp;
|
||||
int invert, found;
|
||||
@ -1501,7 +1514,7 @@ patmatch(const char *pattern, const char *string, int squoted)
|
||||
for (;;) {
|
||||
while (*endp == CTLQUOTEMARK)
|
||||
endp++;
|
||||
if (*endp == '\0')
|
||||
if (*endp == 0)
|
||||
goto dft; /* no matching ] */
|
||||
if (*endp == CTLESC)
|
||||
endp++;
|
||||
@ -1516,12 +1529,14 @@ patmatch(const char *pattern, const char *string, int squoted)
|
||||
found = 0;
|
||||
if (squoted && *q == CTLESC)
|
||||
q++;
|
||||
if (localeisutf8)
|
||||
chr = get_wc(&q);
|
||||
else
|
||||
chr = (unsigned char)*q++;
|
||||
if (chr == '\0')
|
||||
if (*q == '\0')
|
||||
return 0;
|
||||
if (localeisutf8) {
|
||||
chr = get_wc(&q);
|
||||
if (chr == 0)
|
||||
goto backtrack;
|
||||
} else
|
||||
chr = (unsigned char)*q++;
|
||||
c = *p++;
|
||||
do {
|
||||
if (c == CTLQUOTEMARK)
|
||||
@ -1562,21 +1577,34 @@ patmatch(const char *pattern, const char *string, int squoted)
|
||||
}
|
||||
} while ((c = *p++) != ']');
|
||||
if (found == invert)
|
||||
return 0;
|
||||
goto backtrack;
|
||||
break;
|
||||
}
|
||||
dft: default:
|
||||
if (squoted && *q == CTLESC)
|
||||
q++;
|
||||
if (*q++ != c)
|
||||
if (*q == '\0')
|
||||
return 0;
|
||||
if (*q++ == c)
|
||||
break;
|
||||
backtrack:
|
||||
/*
|
||||
* If we have a mismatch (other than hitting the end
|
||||
* of the string), go back to the last '*' seen and
|
||||
* have it match one additional character.
|
||||
*/
|
||||
if (bt_p == NULL)
|
||||
return 0;
|
||||
if (squoted && *bt_q == CTLESC)
|
||||
bt_q++;
|
||||
if (*bt_q == '\0')
|
||||
return 0;
|
||||
bt_q++;
|
||||
p = bt_p;
|
||||
q = bt_q;
|
||||
break;
|
||||
}
|
||||
}
|
||||
breakloop:
|
||||
if (*q != '\0')
|
||||
return 0;
|
||||
return 1;
|
||||
}
|
||||
|
||||
|
||||
|
@ -60,6 +60,5 @@ union node;
|
||||
void expandhere(union node *, int);
|
||||
void expandarg(union node *, struct arglist *, int);
|
||||
void expari(int);
|
||||
int patmatch(const char *, const char *, int);
|
||||
void rmescapes(char *);
|
||||
int casematch(union node *, const char *);
|
||||
|
@ -70,6 +70,8 @@ int displayhist;
|
||||
static FILE *el_in, *el_out, *el_err;
|
||||
|
||||
static char *fc_replace(const char *, char *, char *);
|
||||
static int not_fcnumber(const char *);
|
||||
static int str_to_event(const char *, int);
|
||||
|
||||
/*
|
||||
* Set history and editing status. Called whenever the status may
|
||||
@ -425,7 +427,7 @@ fc_replace(const char *s, char *p, char *r)
|
||||
return (dest);
|
||||
}
|
||||
|
||||
int
|
||||
static int
|
||||
not_fcnumber(const char *s)
|
||||
{
|
||||
if (s == NULL)
|
||||
@ -435,7 +437,7 @@ not_fcnumber(const char *s)
|
||||
return (!is_number(s));
|
||||
}
|
||||
|
||||
int
|
||||
static int
|
||||
str_to_event(const char *str, int last)
|
||||
{
|
||||
HistEvent he;
|
||||
|
@ -106,6 +106,7 @@ EditLine *el; /* cookie for editline package */
|
||||
|
||||
static void pushfile(void);
|
||||
static int preadfd(void);
|
||||
static void popstring(void);
|
||||
|
||||
#ifdef mkinit
|
||||
INCLUDE "input.h"
|
||||
@ -372,7 +373,7 @@ pushstring(char *s, int len, void *ap)
|
||||
INTON;
|
||||
}
|
||||
|
||||
void
|
||||
static void
|
||||
popstring(void)
|
||||
{
|
||||
struct strpush *sp = parsefile->strpush;
|
||||
|
@ -53,7 +53,6 @@ int preadbuffer(void);
|
||||
int preadateof(void);
|
||||
void pungetc(void);
|
||||
void pushstring(char *, int, void *);
|
||||
void popstring(void);
|
||||
void setinputfile(const char *, int);
|
||||
void setinputfd(int, int);
|
||||
void setinputstring(char *, int);
|
||||
|
@ -79,6 +79,7 @@ int rootshell;
|
||||
struct jmploc main_handler;
|
||||
int localeisutf8, initial_localeisutf8;
|
||||
|
||||
static void cmdloop(int);
|
||||
static void read_profile(char *);
|
||||
static char *find_dot_file(char *);
|
||||
|
||||
@ -184,7 +185,7 @@ main(int argc, char *argv[])
|
||||
* loop; it turns on prompting if the shell is interactive.
|
||||
*/
|
||||
|
||||
void
|
||||
static void
|
||||
cmdloop(int top)
|
||||
{
|
||||
union node *n;
|
||||
|
@ -38,4 +38,3 @@ extern int rootshell; /* true if we aren't a child of the main shell */
|
||||
extern struct jmploc main_handler; /* top level exception handler */
|
||||
|
||||
void readcmdfile(const char *);
|
||||
void cmdloop(int);
|
||||
|
@ -219,16 +219,16 @@ main(int argc __unused, char **argv __unused)
|
||||
add("`", "CBQUOTE");
|
||||
add("$", "CVAR");
|
||||
add("}", "CENDVAR");
|
||||
/* ':/' for tilde expansion, '-' for [a\-x] pattern ranges */
|
||||
add("!*?[=~:/-", "CCTL");
|
||||
/* ':/' for tilde expansion, '-^]' for [a\-x] pattern ranges */
|
||||
add("!*?[]=~:/-^", "CCTL");
|
||||
print("dqsyntax");
|
||||
init();
|
||||
fputs("\n/* syntax table used when in single quotes */\n", cfile);
|
||||
add("\n", "CNL");
|
||||
add("\\", "CSBACK");
|
||||
add("'", "CENDQUOTE");
|
||||
/* ':/' for tilde expansion, '-' for [a\-x] pattern ranges */
|
||||
add("!*?[=~:/-", "CCTL");
|
||||
/* ':/' for tilde expansion, '-^]' for [a\-x] pattern ranges */
|
||||
add("!*?[]=~:/-^", "CCTL");
|
||||
print("sqsyntax");
|
||||
init();
|
||||
fputs("\n/* syntax table used when in arithmetic */\n", cfile);
|
||||
|
@ -39,6 +39,4 @@ extern int displayhist;
|
||||
void histedit(void);
|
||||
void sethistsize(const char *);
|
||||
void setterm(const char *);
|
||||
int not_fcnumber(const char *);
|
||||
int str_to_event(const char *, int);
|
||||
|
||||
|
@ -43,7 +43,6 @@ __FBSDID("$FreeBSD$");
|
||||
*
|
||||
* equal(s1, s2) Return true if strings are equal.
|
||||
* scopy(from, to) Copy a string.
|
||||
* scopyn(from, to, n) Like scopy, but checks for overflow.
|
||||
* number(s) Convert a string of digits to an integer.
|
||||
* is_number(s) Return true if s is a string of digits.
|
||||
*/
|
||||
@ -66,24 +65,6 @@ char nullstr[1]; /* zero length string */
|
||||
*/
|
||||
|
||||
|
||||
/*
|
||||
* scopyn - copy a string from "from" to "to", truncating the string
|
||||
* if necessary. "To" is always nul terminated, even if
|
||||
* truncation is performed. "Size" is the size of "to".
|
||||
*/
|
||||
|
||||
void
|
||||
scopyn(const char *from, char *to, int size)
|
||||
{
|
||||
|
||||
while (--size > 0) {
|
||||
if ((*to++ = *from++) == '\0')
|
||||
return;
|
||||
}
|
||||
*to = '\0';
|
||||
}
|
||||
|
||||
|
||||
/*
|
||||
* prefix -- see if pfx is a prefix of string.
|
||||
*/
|
||||
|
@ -35,7 +35,6 @@
|
||||
|
||||
#include <string.h>
|
||||
|
||||
void scopyn(const char *, char *, int);
|
||||
int prefix(const char *, const char *);
|
||||
int number(const char *);
|
||||
int is_number(const char *);
|
||||
|
@ -52,7 +52,7 @@ struct modes {
|
||||
* The code in optlist() depends on minus options following regular
|
||||
* options, i.e. "foo" must immediately precede "-foo".
|
||||
*/
|
||||
struct modes cmodes[] = {
|
||||
static const struct modes cmodes[] = {
|
||||
{ "cs5", CS5, CSIZE },
|
||||
{ "cs6", CS6, CSIZE },
|
||||
{ "cs7", CS7, CSIZE },
|
||||
@ -94,7 +94,7 @@ struct modes cmodes[] = {
|
||||
{ NULL, 0, 0 },
|
||||
};
|
||||
|
||||
struct modes imodes[] = {
|
||||
static const struct modes imodes[] = {
|
||||
{ "ignbrk", IGNBRK, 0 },
|
||||
{ "-ignbrk", 0, IGNBRK },
|
||||
{ "brkint", BRKINT, 0 },
|
||||
@ -130,7 +130,7 @@ struct modes imodes[] = {
|
||||
{ NULL, 0, 0 },
|
||||
};
|
||||
|
||||
struct modes lmodes[] = {
|
||||
static const struct modes lmodes[] = {
|
||||
{ "echo", ECHO, 0 },
|
||||
{ "-echo", 0, ECHO },
|
||||
{ "echoe", ECHOE, 0 },
|
||||
@ -182,7 +182,7 @@ struct modes lmodes[] = {
|
||||
{ NULL, 0, 0 },
|
||||
};
|
||||
|
||||
struct modes omodes[] = {
|
||||
static const struct modes omodes[] = {
|
||||
{ "opost", OPOST, 0 },
|
||||
{ "-opost", 0, OPOST },
|
||||
{ "litout", 0, OPOST },
|
||||
@ -209,7 +209,7 @@ struct modes omodes[] = {
|
||||
int
|
||||
msearch(char ***argvp, struct info *ip)
|
||||
{
|
||||
struct modes *mp;
|
||||
const struct modes *mp;
|
||||
char *name;
|
||||
|
||||
name = **argvp;
|
||||
|
@ -119,7 +119,7 @@ enum token_types {
|
||||
};
|
||||
|
||||
static struct t_op {
|
||||
const char *op_text;
|
||||
char op_text[4];
|
||||
short op_num, op_type;
|
||||
} const ops [] = {
|
||||
{"-r", FILRD, UNOP},
|
||||
@ -162,7 +162,7 @@ static struct t_op {
|
||||
{"-o", BOR, BBINOP},
|
||||
{"(", LPAREN, PAREN},
|
||||
{")", RPAREN, PAREN},
|
||||
{0, 0, 0}
|
||||
{"", 0, 0}
|
||||
};
|
||||
|
||||
static struct t_op const *t_wp_op;
|
||||
@ -427,7 +427,7 @@ t_lex(char *s)
|
||||
t_wp_op = NULL;
|
||||
return EOI;
|
||||
}
|
||||
while (op->op_text) {
|
||||
while (*op->op_text) {
|
||||
if (strcmp(s, op->op_text) == 0) {
|
||||
if (((op->op_type == UNOP || op->op_type == BUNOP)
|
||||
&& isunopoperand()) ||
|
||||
@ -456,7 +456,7 @@ isunopoperand(void)
|
||||
if (nargc == 2)
|
||||
return parenlevel == 1 && strcmp(s, ")") == 0;
|
||||
t = *(t_wp + 2);
|
||||
while (op->op_text) {
|
||||
while (*op->op_text) {
|
||||
if (strcmp(s, op->op_text) == 0)
|
||||
return op->op_type == BINOP &&
|
||||
(parenlevel == 0 || t[0] != ')' || t[1] != '\0');
|
||||
@ -478,7 +478,7 @@ islparenoperand(void)
|
||||
return parenlevel == 1 && strcmp(s, ")") == 0;
|
||||
if (nargc != 3)
|
||||
return 0;
|
||||
while (op->op_text) {
|
||||
while (*op->op_text) {
|
||||
if (strcmp(s, op->op_text) == 0)
|
||||
return op->op_type == BINOP;
|
||||
op++;
|
||||
|
@ -671,9 +671,12 @@ link_prog(dtrace_cmd_t *dcp)
|
||||
p[0] = '\0'; /* strip .d suffix */
|
||||
(void) snprintf(dcp->dc_ofile, sizeof (dcp->dc_ofile),
|
||||
"%s.o", basename(dcp->dc_arg));
|
||||
} else if (g_cmdc > 1) {
|
||||
(void) snprintf(dcp->dc_ofile, sizeof (dcp->dc_ofile),
|
||||
"d.out.%td", dcp - g_cmdv);
|
||||
} else {
|
||||
(void) snprintf(dcp->dc_ofile, sizeof (dcp->dc_ofile),
|
||||
g_cmdc > 1 ? "%s.%d" : "%s", "d.out", (int)(dcp - g_cmdv));
|
||||
"d.out");
|
||||
}
|
||||
|
||||
if (dtrace_program_link(g_dtp, dcp->dc_prog, DTRACE_D_PROBES,
|
||||
|
@ -1,65 +1,79 @@
|
||||
'\" te
|
||||
.\" Copyright (c) 2011, Martin Matuska <mm@FreeBSD.org>.
|
||||
.\" All Rights Reserved.
|
||||
.\"
|
||||
.\" The contents of this file are subject to the terms of the
|
||||
.\" Common Development and Distribution License (the "License").
|
||||
.\" You may not use this file except in compliance with the License.
|
||||
.\"
|
||||
.\" You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE
|
||||
.\" or http://www.opensolaris.org/os/licensing.
|
||||
.\" See the License for the specific language governing permissions
|
||||
.\" and limitations under the License.
|
||||
.\"
|
||||
.\" When distributing Covered Code, include this CDDL HEADER in each
|
||||
.\" file and include the License file at usr/src/OPENSOLARIS.LICENSE.
|
||||
.\" If applicable, add the following below this CDDL HEADER, with the
|
||||
.\" fields enclosed by brackets "[]" replaced with your own identifying
|
||||
.\" information: Portions Copyright [yyyy] [name of copyright owner]
|
||||
.\"
|
||||
.\" Copyright (c) 2004, Sun Microsystems, Inc. All Rights Reserved.
|
||||
.\" The contents of this file are subject to the terms of the Common Development and Distribution License (the "License"). You may not use this file except in compliance with the License.
|
||||
.\" You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE or http://www.opensolaris.org/os/licensing. See the License for the specific language governing permissions and limitations under the License.
|
||||
.\" 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]
|
||||
.\" Portions Copyright 2011 Martin Matuska <mm@FreeBSD.org>
|
||||
.TH ZDB 8 "Oct 31, 2005"
|
||||
.SH NAME
|
||||
zdb \- ZFS debugger
|
||||
.SH SYNOPSIS
|
||||
.LP
|
||||
.nf
|
||||
\fBzdb\fR \fIpool\fR
|
||||
.fi
|
||||
|
||||
.SH DESCRIPTION
|
||||
.sp
|
||||
.LP
|
||||
The \fBzdb\fR command is used by support engineers to diagnose failures and
|
||||
gather statistics. Since the \fBZFS\fR file system is always consistent on disk
|
||||
and is self-repairing, \fBzdb\fR should only be run under the direction by a
|
||||
support engineer.
|
||||
.sp
|
||||
.LP
|
||||
If no arguments are specified, \fBzdb\fR, performs basic consistency checks on
|
||||
the pool and associated datasets, and report any problems detected.
|
||||
.sp
|
||||
.LP
|
||||
.\"
|
||||
.\" $FreeBSD$
|
||||
.\"
|
||||
.Dd November 26, 2011
|
||||
.Dt ZDB 8
|
||||
.Os
|
||||
.Sh NAME
|
||||
.Nm zdb
|
||||
.Nd ZFS debugger
|
||||
.Sh SYNOPSIS
|
||||
.Nm
|
||||
.Ar pool
|
||||
.Sh DESCRIPTION
|
||||
The
|
||||
.Nm
|
||||
command is used by support engineers to diagnose failures and
|
||||
gather statistics. Since the
|
||||
.Tn ZFS
|
||||
file system is always consistent on disk and is self-repairing,
|
||||
.Nm
|
||||
should only be run under the direction by a support engineer.
|
||||
.Pp
|
||||
If no arguments are specified,
|
||||
.Nm
|
||||
performs basic consistency checks on the pool and associated datasets, and
|
||||
report any problems detected.
|
||||
.Nm
|
||||
Any options supported by this command are internal to Sun and subject to change
|
||||
at any time.
|
||||
.SH EXIT STATUS
|
||||
.sp
|
||||
.LP
|
||||
.Sh EXIT STATUS
|
||||
The following exit values are returned:
|
||||
.sp
|
||||
.ne 2
|
||||
.na
|
||||
\fB\fB0\fR\fR
|
||||
.ad
|
||||
.RS 5n
|
||||
.Bl -tag -offset 2n -width 2n
|
||||
.It 0
|
||||
The pool is consistent.
|
||||
.RE
|
||||
|
||||
.sp
|
||||
.ne 2
|
||||
.na
|
||||
\fB\fB1\fR\fR
|
||||
.ad
|
||||
.RS 5n
|
||||
.It 1
|
||||
An error was detected.
|
||||
.RE
|
||||
|
||||
.sp
|
||||
.ne 2
|
||||
.na
|
||||
\fB\fB2\fR\fR
|
||||
.ad
|
||||
.RS 5n
|
||||
.It 2
|
||||
Invalid command line options were specified.
|
||||
.RE
|
||||
|
||||
.SH SEE ALSO
|
||||
.sp
|
||||
.LP
|
||||
zfs(8), zpool(8)
|
||||
.El
|
||||
.Sh SEE ALSO
|
||||
.Xr zfs 8 ,
|
||||
.Xr zpool 8
|
||||
.Sh AUTHORS
|
||||
This manual page is a
|
||||
.Xr mdoc 7
|
||||
reimplementation of the
|
||||
.Tn OpenSolaris
|
||||
manual page
|
||||
.Em zdb(1M) ,
|
||||
modified and customized for
|
||||
.Fx
|
||||
and licensed under the
|
||||
.Tn Common Development and Distribution License
|
||||
.Pq Tn CDDL .
|
||||
.Pp
|
||||
The
|
||||
.Xr mdoc 7
|
||||
implementation of this manual page was initially written by
|
||||
.An Martin Matuska Aq mm@FreeBSD.org .
|
||||
|
File diff suppressed because it is too large
Load Diff
@ -22,8 +22,9 @@
|
||||
/*
|
||||
* Copyright (c) 2005, 2010, Oracle and/or its affiliates. All rights reserved.
|
||||
* Copyright 2011 Nexenta Systems, Inc. All rights reserved.
|
||||
* Copyright (c) 2011 by Delphix. All rights reserved.
|
||||
* Copyright (c) 2011 Pawel Jakub Dawidek <pawel@dawidek.net>.
|
||||
* All rights reserved.
|
||||
* Copyright (c) 2011 Martin Matuska <mm@FreeBSD.org>. All rights reserved.
|
||||
*/
|
||||
|
||||
#include <assert.h>
|
||||
@ -145,7 +146,7 @@ typedef enum {
|
||||
HELP_HOLD,
|
||||
HELP_HOLDS,
|
||||
HELP_RELEASE,
|
||||
HELP_DIFF
|
||||
HELP_DIFF,
|
||||
} zfs_help_t;
|
||||
|
||||
typedef struct zfs_command {
|
||||
@ -220,8 +221,9 @@ get_usage(zfs_help_t idx)
|
||||
"\tcreate [-ps] [-b blocksize] [-o property=value] ... "
|
||||
"-V <size> <volume>\n"));
|
||||
case HELP_DESTROY:
|
||||
return (gettext("\tdestroy [-rRf] <filesystem|volume>\n"
|
||||
"\tdestroy [-rRd] <snapshot>\n"));
|
||||
return (gettext("\tdestroy [-fnpRrv] <filesystem|volume>\n"
|
||||
"\tdestroy [-dnpRrv] "
|
||||
"<snapshot>[%<snapname>][,...]\n"));
|
||||
case HELP_GET:
|
||||
return (gettext("\tget [-rHp] [-d max] "
|
||||
"[-o \"all\" | field[,...]] [-s source[,...]]\n"
|
||||
@ -260,7 +262,8 @@ get_usage(zfs_help_t idx)
|
||||
case HELP_ROLLBACK:
|
||||
return (gettext("\trollback [-rRf] <snapshot>\n"));
|
||||
case HELP_SEND:
|
||||
return (gettext("\tsend [-RDp] [-[iI] snapshot] <snapshot>\n"));
|
||||
return (gettext("\tsend [-DnPpRrv] "
|
||||
"[-i snapshot | -I snapshot] <snapshot>\n"));
|
||||
case HELP_SET:
|
||||
return (gettext("\tset <property=value> "
|
||||
"<filesystem|volume|snapshot> ...\n"));
|
||||
@ -296,11 +299,11 @@ get_usage(zfs_help_t idx)
|
||||
"\tunallow [-r] -s @setname [<perm|@setname>[,...]] "
|
||||
"<filesystem|volume>\n"));
|
||||
case HELP_USERSPACE:
|
||||
return (gettext("\tuserspace [-hniHp] [-o field[,...]] "
|
||||
return (gettext("\tuserspace [-niHp] [-o field[,...]] "
|
||||
"[-sS field] ... [-t type[,...]]\n"
|
||||
"\t <filesystem|snapshot>\n"));
|
||||
case HELP_GROUPSPACE:
|
||||
return (gettext("\tgroupspace [-hniHpU] [-o field[,...]] "
|
||||
return (gettext("\tgroupspace [-niHp] [-o field[,...]] "
|
||||
"[-sS field] ... [-t type[,...]]\n"
|
||||
"\t <filesystem|snapshot>\n"));
|
||||
case HELP_HOLD:
|
||||
@ -439,6 +442,8 @@ usage(boolean_t requested)
|
||||
(void) fprintf(fp, "YES NO <size> | none\n");
|
||||
(void) fprintf(fp, "\t%-15s ", "groupquota@...");
|
||||
(void) fprintf(fp, "YES NO <size> | none\n");
|
||||
(void) fprintf(fp, "\t%-15s ", "written@<snap>");
|
||||
(void) fprintf(fp, " NO NO <size>\n");
|
||||
|
||||
(void) fprintf(fp, gettext("\nSizes are specified in bytes "
|
||||
"with standard units such as K, M, G, etc.\n"));
|
||||
@ -884,15 +889,23 @@ zfs_do_create(int argc, char **argv)
|
||||
*/
|
||||
typedef struct destroy_cbdata {
|
||||
boolean_t cb_first;
|
||||
int cb_force;
|
||||
int cb_recurse;
|
||||
int cb_error;
|
||||
int cb_needforce;
|
||||
int cb_doclones;
|
||||
boolean_t cb_closezhp;
|
||||
boolean_t cb_force;
|
||||
boolean_t cb_recurse;
|
||||
boolean_t cb_error;
|
||||
boolean_t cb_doclones;
|
||||
zfs_handle_t *cb_target;
|
||||
char *cb_snapname;
|
||||
boolean_t cb_defer_destroy;
|
||||
boolean_t cb_verbose;
|
||||
boolean_t cb_parsable;
|
||||
boolean_t cb_dryrun;
|
||||
nvlist_t *cb_nvl;
|
||||
|
||||
/* first snap in contiguous run */
|
||||
zfs_handle_t *cb_firstsnap;
|
||||
/* previous snap in contiguous run */
|
||||
zfs_handle_t *cb_prevsnap;
|
||||
int64_t cb_snapused;
|
||||
char *cb_snapspec;
|
||||
} destroy_cbdata_t;
|
||||
|
||||
/*
|
||||
@ -922,7 +935,7 @@ destroy_check_dependent(zfs_handle_t *zhp, void *data)
|
||||
(void) fprintf(stderr, gettext("use '-r' to destroy "
|
||||
"the following datasets:\n"));
|
||||
cbp->cb_first = B_FALSE;
|
||||
cbp->cb_error = 1;
|
||||
cbp->cb_error = B_TRUE;
|
||||
}
|
||||
|
||||
(void) fprintf(stderr, "%s\n", zfs_get_name(zhp));
|
||||
@ -943,7 +956,8 @@ destroy_check_dependent(zfs_handle_t *zhp, void *data)
|
||||
(void) fprintf(stderr, gettext("use '-R' to destroy "
|
||||
"the following datasets:\n"));
|
||||
cbp->cb_first = B_FALSE;
|
||||
cbp->cb_error = 1;
|
||||
cbp->cb_error = B_TRUE;
|
||||
cbp->cb_dryrun = B_TRUE;
|
||||
}
|
||||
|
||||
(void) fprintf(stderr, "%s\n", zfs_get_name(zhp));
|
||||
@ -957,7 +971,20 @@ destroy_check_dependent(zfs_handle_t *zhp, void *data)
|
||||
static int
|
||||
destroy_callback(zfs_handle_t *zhp, void *data)
|
||||
{
|
||||
destroy_cbdata_t *cbp = data;
|
||||
destroy_cbdata_t *cb = data;
|
||||
const char *name = zfs_get_name(zhp);
|
||||
|
||||
if (cb->cb_verbose) {
|
||||
if (cb->cb_parsable) {
|
||||
(void) printf("destroy\t%s\n", name);
|
||||
} else if (cb->cb_dryrun) {
|
||||
(void) printf(gettext("would destroy %s\n"),
|
||||
name);
|
||||
} else {
|
||||
(void) printf(gettext("will destroy %s\n"),
|
||||
name);
|
||||
}
|
||||
}
|
||||
|
||||
/*
|
||||
* Ignore pools (which we've already flagged as an error before getting
|
||||
@ -969,13 +996,12 @@ destroy_callback(zfs_handle_t *zhp, void *data)
|
||||
return (0);
|
||||
}
|
||||
|
||||
/*
|
||||
* Bail out on the first error.
|
||||
*/
|
||||
if (zfs_unmount(zhp, NULL, cbp->cb_force ? MS_FORCE : 0) != 0 ||
|
||||
zfs_destroy(zhp, cbp->cb_defer_destroy) != 0) {
|
||||
zfs_close(zhp);
|
||||
return (-1);
|
||||
if (!cb->cb_dryrun) {
|
||||
if (zfs_unmount(zhp, NULL, cb->cb_force ? MS_FORCE : 0) != 0 ||
|
||||
zfs_destroy(zhp, cb->cb_defer_destroy) != 0) {
|
||||
zfs_close(zhp);
|
||||
return (-1);
|
||||
}
|
||||
}
|
||||
|
||||
zfs_close(zhp);
|
||||
@ -983,39 +1009,142 @@ destroy_callback(zfs_handle_t *zhp, void *data)
|
||||
}
|
||||
|
||||
static int
|
||||
destroy_snap_clones(zfs_handle_t *zhp, void *arg)
|
||||
destroy_print_cb(zfs_handle_t *zhp, void *arg)
|
||||
{
|
||||
destroy_cbdata_t *cbp = arg;
|
||||
char thissnap[MAXPATHLEN];
|
||||
zfs_handle_t *szhp;
|
||||
boolean_t closezhp = cbp->cb_closezhp;
|
||||
int rv;
|
||||
destroy_cbdata_t *cb = arg;
|
||||
const char *name = zfs_get_name(zhp);
|
||||
int err = 0;
|
||||
|
||||
(void) snprintf(thissnap, sizeof (thissnap),
|
||||
"%s@%s", zfs_get_name(zhp), cbp->cb_snapname);
|
||||
|
||||
libzfs_print_on_error(g_zfs, B_FALSE);
|
||||
szhp = zfs_open(g_zfs, thissnap, ZFS_TYPE_SNAPSHOT);
|
||||
libzfs_print_on_error(g_zfs, B_TRUE);
|
||||
if (szhp) {
|
||||
/*
|
||||
* Destroy any clones of this snapshot
|
||||
*/
|
||||
if (zfs_iter_dependents(szhp, B_FALSE, destroy_callback,
|
||||
cbp) != 0) {
|
||||
zfs_close(szhp);
|
||||
if (closezhp)
|
||||
zfs_close(zhp);
|
||||
return (-1);
|
||||
if (nvlist_exists(cb->cb_nvl, name)) {
|
||||
if (cb->cb_firstsnap == NULL)
|
||||
cb->cb_firstsnap = zfs_handle_dup(zhp);
|
||||
if (cb->cb_prevsnap != NULL)
|
||||
zfs_close(cb->cb_prevsnap);
|
||||
/* this snap continues the current range */
|
||||
cb->cb_prevsnap = zfs_handle_dup(zhp);
|
||||
if (cb->cb_verbose) {
|
||||
if (cb->cb_parsable) {
|
||||
(void) printf("destroy\t%s\n", name);
|
||||
} else if (cb->cb_dryrun) {
|
||||
(void) printf(gettext("would destroy %s\n"),
|
||||
name);
|
||||
} else {
|
||||
(void) printf(gettext("will destroy %s\n"),
|
||||
name);
|
||||
}
|
||||
}
|
||||
zfs_close(szhp);
|
||||
} else if (cb->cb_firstsnap != NULL) {
|
||||
/* end of this range */
|
||||
uint64_t used = 0;
|
||||
err = zfs_get_snapused_int(cb->cb_firstsnap,
|
||||
cb->cb_prevsnap, &used);
|
||||
cb->cb_snapused += used;
|
||||
zfs_close(cb->cb_firstsnap);
|
||||
cb->cb_firstsnap = NULL;
|
||||
zfs_close(cb->cb_prevsnap);
|
||||
cb->cb_prevsnap = NULL;
|
||||
}
|
||||
zfs_close(zhp);
|
||||
return (err);
|
||||
}
|
||||
|
||||
static int
|
||||
destroy_print_snapshots(zfs_handle_t *fs_zhp, destroy_cbdata_t *cb)
|
||||
{
|
||||
int err;
|
||||
assert(cb->cb_firstsnap == NULL);
|
||||
assert(cb->cb_prevsnap == NULL);
|
||||
err = zfs_iter_snapshots_sorted(fs_zhp, destroy_print_cb, cb);
|
||||
if (cb->cb_firstsnap != NULL) {
|
||||
uint64_t used = 0;
|
||||
if (err == 0) {
|
||||
err = zfs_get_snapused_int(cb->cb_firstsnap,
|
||||
cb->cb_prevsnap, &used);
|
||||
}
|
||||
cb->cb_snapused += used;
|
||||
zfs_close(cb->cb_firstsnap);
|
||||
cb->cb_firstsnap = NULL;
|
||||
zfs_close(cb->cb_prevsnap);
|
||||
cb->cb_prevsnap = NULL;
|
||||
}
|
||||
return (err);
|
||||
}
|
||||
|
||||
static int
|
||||
snapshot_to_nvl_cb(zfs_handle_t *zhp, void *arg)
|
||||
{
|
||||
destroy_cbdata_t *cb = arg;
|
||||
int err = 0;
|
||||
|
||||
/* Check for clones. */
|
||||
if (!cb->cb_doclones) {
|
||||
cb->cb_target = zhp;
|
||||
cb->cb_first = B_TRUE;
|
||||
err = zfs_iter_dependents(zhp, B_TRUE,
|
||||
destroy_check_dependent, cb);
|
||||
}
|
||||
|
||||
cbp->cb_closezhp = B_TRUE;
|
||||
rv = zfs_iter_filesystems(zhp, destroy_snap_clones, arg);
|
||||
if (closezhp)
|
||||
zfs_close(zhp);
|
||||
return (rv);
|
||||
if (err == 0) {
|
||||
if (nvlist_add_boolean(cb->cb_nvl, zfs_get_name(zhp)))
|
||||
nomem();
|
||||
}
|
||||
zfs_close(zhp);
|
||||
return (err);
|
||||
}
|
||||
|
||||
static int
|
||||
gather_snapshots(zfs_handle_t *zhp, void *arg)
|
||||
{
|
||||
destroy_cbdata_t *cb = arg;
|
||||
int err = 0;
|
||||
|
||||
err = zfs_iter_snapspec(zhp, cb->cb_snapspec, snapshot_to_nvl_cb, cb);
|
||||
if (err == ENOENT)
|
||||
err = 0;
|
||||
if (err != 0)
|
||||
goto out;
|
||||
|
||||
if (cb->cb_verbose) {
|
||||
err = destroy_print_snapshots(zhp, cb);
|
||||
if (err != 0)
|
||||
goto out;
|
||||
}
|
||||
|
||||
if (cb->cb_recurse)
|
||||
err = zfs_iter_filesystems(zhp, gather_snapshots, cb);
|
||||
|
||||
out:
|
||||
zfs_close(zhp);
|
||||
return (err);
|
||||
}
|
||||
|
||||
static int
|
||||
destroy_clones(destroy_cbdata_t *cb)
|
||||
{
|
||||
nvpair_t *pair;
|
||||
for (pair = nvlist_next_nvpair(cb->cb_nvl, NULL);
|
||||
pair != NULL;
|
||||
pair = nvlist_next_nvpair(cb->cb_nvl, pair)) {
|
||||
zfs_handle_t *zhp = zfs_open(g_zfs, nvpair_name(pair),
|
||||
ZFS_TYPE_SNAPSHOT);
|
||||
if (zhp != NULL) {
|
||||
boolean_t defer = cb->cb_defer_destroy;
|
||||
int err;
|
||||
|
||||
/*
|
||||
* We can't defer destroy non-snapshots, so set it to
|
||||
* false while destroying the clones.
|
||||
*/
|
||||
cb->cb_defer_destroy = B_FALSE;
|
||||
err = zfs_iter_dependents(zhp, B_FALSE,
|
||||
destroy_callback, cb);
|
||||
cb->cb_defer_destroy = defer;
|
||||
zfs_close(zhp);
|
||||
if (err != 0)
|
||||
return (err);
|
||||
}
|
||||
}
|
||||
return (0);
|
||||
}
|
||||
|
||||
static int
|
||||
@ -1024,25 +1153,35 @@ zfs_do_destroy(int argc, char **argv)
|
||||
destroy_cbdata_t cb = { 0 };
|
||||
int c;
|
||||
zfs_handle_t *zhp;
|
||||
char *cp;
|
||||
char *at;
|
||||
zfs_type_t type = ZFS_TYPE_DATASET;
|
||||
|
||||
/* check options */
|
||||
while ((c = getopt(argc, argv, "dfrR")) != -1) {
|
||||
while ((c = getopt(argc, argv, "vpndfrR")) != -1) {
|
||||
switch (c) {
|
||||
case 'v':
|
||||
cb.cb_verbose = B_TRUE;
|
||||
break;
|
||||
case 'p':
|
||||
cb.cb_verbose = B_TRUE;
|
||||
cb.cb_parsable = B_TRUE;
|
||||
break;
|
||||
case 'n':
|
||||
cb.cb_dryrun = B_TRUE;
|
||||
break;
|
||||
case 'd':
|
||||
cb.cb_defer_destroy = B_TRUE;
|
||||
type = ZFS_TYPE_SNAPSHOT;
|
||||
break;
|
||||
case 'f':
|
||||
cb.cb_force = 1;
|
||||
cb.cb_force = B_TRUE;
|
||||
break;
|
||||
case 'r':
|
||||
cb.cb_recurse = 1;
|
||||
cb.cb_recurse = B_TRUE;
|
||||
break;
|
||||
case 'R':
|
||||
cb.cb_recurse = 1;
|
||||
cb.cb_doclones = 1;
|
||||
cb.cb_recurse = B_TRUE;
|
||||
cb.cb_doclones = B_TRUE;
|
||||
break;
|
||||
case '?':
|
||||
default:
|
||||
@ -1057,7 +1196,7 @@ zfs_do_destroy(int argc, char **argv)
|
||||
|
||||
/* check number of arguments */
|
||||
if (argc == 0) {
|
||||
(void) fprintf(stderr, gettext("missing path argument\n"));
|
||||
(void) fprintf(stderr, gettext("missing dataset argument\n"));
|
||||
usage(B_FALSE);
|
||||
}
|
||||
if (argc > 1) {
|
||||
@ -1065,92 +1204,118 @@ zfs_do_destroy(int argc, char **argv)
|
||||
usage(B_FALSE);
|
||||
}
|
||||
|
||||
/*
|
||||
* If we are doing recursive destroy of a snapshot, then the
|
||||
* named snapshot may not exist. Go straight to libzfs.
|
||||
*/
|
||||
if (cb.cb_recurse && (cp = strchr(argv[0], '@'))) {
|
||||
int ret;
|
||||
at = strchr(argv[0], '@');
|
||||
if (at != NULL) {
|
||||
int err;
|
||||
|
||||
*cp = '\0';
|
||||
if ((zhp = zfs_open(g_zfs, argv[0], ZFS_TYPE_DATASET)) == NULL)
|
||||
/* Build the list of snaps to destroy in cb_nvl. */
|
||||
if (nvlist_alloc(&cb.cb_nvl, NV_UNIQUE_NAME, 0) != 0)
|
||||
nomem();
|
||||
|
||||
*at = '\0';
|
||||
zhp = zfs_open(g_zfs, argv[0],
|
||||
ZFS_TYPE_FILESYSTEM | ZFS_TYPE_VOLUME);
|
||||
if (zhp == NULL)
|
||||
return (1);
|
||||
*cp = '@';
|
||||
cp++;
|
||||
|
||||
if (cb.cb_doclones) {
|
||||
boolean_t defer = cb.cb_defer_destroy;
|
||||
cb.cb_snapspec = at + 1;
|
||||
if (gather_snapshots(zfs_handle_dup(zhp), &cb) != 0 ||
|
||||
cb.cb_error) {
|
||||
zfs_close(zhp);
|
||||
nvlist_free(cb.cb_nvl);
|
||||
return (1);
|
||||
}
|
||||
|
||||
/*
|
||||
* Temporarily ignore the defer_destroy setting since
|
||||
* it's not supported for clones.
|
||||
*/
|
||||
cb.cb_defer_destroy = B_FALSE;
|
||||
cb.cb_snapname = cp;
|
||||
if (destroy_snap_clones(zhp, &cb) != 0) {
|
||||
zfs_close(zhp);
|
||||
return (1);
|
||||
if (nvlist_empty(cb.cb_nvl)) {
|
||||
(void) fprintf(stderr, gettext("could not find any "
|
||||
"snapshots to destroy; check snapshot names.\n"));
|
||||
zfs_close(zhp);
|
||||
nvlist_free(cb.cb_nvl);
|
||||
return (1);
|
||||
}
|
||||
|
||||
if (cb.cb_verbose) {
|
||||
char buf[16];
|
||||
zfs_nicenum(cb.cb_snapused, buf, sizeof (buf));
|
||||
if (cb.cb_parsable) {
|
||||
(void) printf("reclaim\t%llu\n",
|
||||
cb.cb_snapused);
|
||||
} else if (cb.cb_dryrun) {
|
||||
(void) printf(gettext("would reclaim %s\n"),
|
||||
buf);
|
||||
} else {
|
||||
(void) printf(gettext("will reclaim %s\n"),
|
||||
buf);
|
||||
}
|
||||
cb.cb_defer_destroy = defer;
|
||||
}
|
||||
|
||||
ret = zfs_destroy_snaps(zhp, cp, cb.cb_defer_destroy);
|
||||
zfs_close(zhp);
|
||||
if (ret) {
|
||||
(void) fprintf(stderr,
|
||||
gettext("no snapshots destroyed\n"));
|
||||
if (!cb.cb_dryrun) {
|
||||
if (cb.cb_doclones)
|
||||
err = destroy_clones(&cb);
|
||||
if (err == 0) {
|
||||
err = zfs_destroy_snaps_nvl(zhp, cb.cb_nvl,
|
||||
cb.cb_defer_destroy);
|
||||
}
|
||||
}
|
||||
return (ret != 0);
|
||||
}
|
||||
|
||||
/* Open the given dataset */
|
||||
if ((zhp = zfs_open(g_zfs, argv[0], type)) == NULL)
|
||||
return (1);
|
||||
|
||||
cb.cb_target = zhp;
|
||||
|
||||
/*
|
||||
* Perform an explicit check for pools before going any further.
|
||||
*/
|
||||
if (!cb.cb_recurse && strchr(zfs_get_name(zhp), '/') == NULL &&
|
||||
zfs_get_type(zhp) == ZFS_TYPE_FILESYSTEM) {
|
||||
(void) fprintf(stderr, gettext("cannot destroy '%s': "
|
||||
"operation does not apply to pools\n"),
|
||||
zfs_get_name(zhp));
|
||||
(void) fprintf(stderr, gettext("use 'zfs destroy -r "
|
||||
"%s' to destroy all datasets in the pool\n"),
|
||||
zfs_get_name(zhp));
|
||||
(void) fprintf(stderr, gettext("use 'zpool destroy %s' "
|
||||
"to destroy the pool itself\n"), zfs_get_name(zhp));
|
||||
zfs_close(zhp);
|
||||
return (1);
|
||||
nvlist_free(cb.cb_nvl);
|
||||
if (err != 0)
|
||||
return (1);
|
||||
} else {
|
||||
/* Open the given dataset */
|
||||
if ((zhp = zfs_open(g_zfs, argv[0], type)) == NULL)
|
||||
return (1);
|
||||
|
||||
cb.cb_target = zhp;
|
||||
|
||||
/*
|
||||
* Perform an explicit check for pools before going any further.
|
||||
*/
|
||||
if (!cb.cb_recurse && strchr(zfs_get_name(zhp), '/') == NULL &&
|
||||
zfs_get_type(zhp) == ZFS_TYPE_FILESYSTEM) {
|
||||
(void) fprintf(stderr, gettext("cannot destroy '%s': "
|
||||
"operation does not apply to pools\n"),
|
||||
zfs_get_name(zhp));
|
||||
(void) fprintf(stderr, gettext("use 'zfs destroy -r "
|
||||
"%s' to destroy all datasets in the pool\n"),
|
||||
zfs_get_name(zhp));
|
||||
(void) fprintf(stderr, gettext("use 'zpool destroy %s' "
|
||||
"to destroy the pool itself\n"), zfs_get_name(zhp));
|
||||
zfs_close(zhp);
|
||||
return (1);
|
||||
}
|
||||
|
||||
/*
|
||||
* Check for any dependents and/or clones.
|
||||
*/
|
||||
cb.cb_first = B_TRUE;
|
||||
if (!cb.cb_doclones &&
|
||||
zfs_iter_dependents(zhp, B_TRUE, destroy_check_dependent,
|
||||
&cb) != 0) {
|
||||
zfs_close(zhp);
|
||||
return (1);
|
||||
}
|
||||
|
||||
if (cb.cb_error) {
|
||||
zfs_close(zhp);
|
||||
return (1);
|
||||
}
|
||||
|
||||
if (zfs_iter_dependents(zhp, B_FALSE, destroy_callback,
|
||||
&cb) != 0) {
|
||||
zfs_close(zhp);
|
||||
return (1);
|
||||
}
|
||||
|
||||
/*
|
||||
* Do the real thing. The callback will close the
|
||||
* handle regardless of whether it succeeds or not.
|
||||
*/
|
||||
if (destroy_callback(zhp, &cb) != 0)
|
||||
return (1);
|
||||
}
|
||||
|
||||
/*
|
||||
* Check for any dependents and/or clones.
|
||||
*/
|
||||
cb.cb_first = B_TRUE;
|
||||
if (!cb.cb_doclones && !cb.cb_defer_destroy &&
|
||||
zfs_iter_dependents(zhp, B_TRUE, destroy_check_dependent,
|
||||
&cb) != 0) {
|
||||
zfs_close(zhp);
|
||||
return (1);
|
||||
}
|
||||
|
||||
if (cb.cb_error || (!cb.cb_defer_destroy &&
|
||||
(zfs_iter_dependents(zhp, B_FALSE, destroy_callback, &cb) != 0))) {
|
||||
zfs_close(zhp);
|
||||
return (1);
|
||||
}
|
||||
|
||||
/*
|
||||
* Do the real thing. The callback will close the handle regardless of
|
||||
* whether it succeeds or not.
|
||||
*/
|
||||
|
||||
if (destroy_callback(zhp, &cb) != 0)
|
||||
return (1);
|
||||
|
||||
return (0);
|
||||
}
|
||||
|
||||
@ -1249,6 +1414,17 @@ get_callback(zfs_handle_t *zhp, void *data)
|
||||
(void) strlcpy(buf, "-", sizeof (buf));
|
||||
}
|
||||
|
||||
zprop_print_one_property(zfs_get_name(zhp), cbp,
|
||||
pl->pl_user_prop, buf, sourcetype, source, NULL);
|
||||
} else if (zfs_prop_written(pl->pl_user_prop)) {
|
||||
sourcetype = ZPROP_SRC_LOCAL;
|
||||
|
||||
if (zfs_prop_get_written(zhp, pl->pl_user_prop,
|
||||
buf, sizeof (buf), cbp->cb_literal) != 0) {
|
||||
sourcetype = ZPROP_SRC_NONE;
|
||||
(void) strlcpy(buf, "-", sizeof (buf));
|
||||
}
|
||||
|
||||
zprop_print_one_property(zfs_get_name(zhp), cbp,
|
||||
pl->pl_user_prop, buf, sourcetype, source, NULL);
|
||||
} else {
|
||||
@ -1795,8 +1971,8 @@ zfs_do_upgrade(int argc, char **argv)
|
||||
"---------------\n");
|
||||
(void) printf(gettext(" 1 Initial ZFS filesystem version\n"));
|
||||
(void) printf(gettext(" 2 Enhanced directory entries\n"));
|
||||
(void) printf(gettext(" 3 Case insensitive and File system "
|
||||
"unique identifier (FUID)\n"));
|
||||
(void) printf(gettext(" 3 Case insensitive and filesystem "
|
||||
"user identifier (FUID)\n"));
|
||||
(void) printf(gettext(" 4 userquota, groupquota "
|
||||
"properties\n"));
|
||||
(void) printf(gettext(" 5 System attributes\n"));
|
||||
@ -2676,6 +2852,13 @@ print_dataset(zfs_handle_t *zhp, zprop_list_t *pl, boolean_t scripted)
|
||||
else
|
||||
propstr = property;
|
||||
right_justify = B_TRUE;
|
||||
} else if (zfs_prop_written(pl->pl_user_prop)) {
|
||||
if (zfs_prop_get_written(zhp, pl->pl_user_prop,
|
||||
property, sizeof (property), B_FALSE) != 0)
|
||||
propstr = "-";
|
||||
else
|
||||
propstr = property;
|
||||
right_justify = B_TRUE;
|
||||
} else {
|
||||
if (nvlist_lookup_nvlist(userprops,
|
||||
pl->pl_user_prop, &propval) != 0)
|
||||
@ -3302,9 +3485,6 @@ zfs_do_snapshot(int argc, char **argv)
|
||||
}
|
||||
|
||||
/*
|
||||
* zfs send [-vDp] -R [-i|-I <@snap>] <fs@snap>
|
||||
* zfs send [-vDp] [-i|-I <@snap>] <fs@snap>
|
||||
*
|
||||
* Send a backup stream to stdout.
|
||||
*/
|
||||
static int
|
||||
@ -3316,11 +3496,11 @@ zfs_do_send(int argc, char **argv)
|
||||
zfs_handle_t *zhp;
|
||||
sendflags_t flags = { 0 };
|
||||
int c, err;
|
||||
nvlist_t *dbgnv;
|
||||
nvlist_t *dbgnv = NULL;
|
||||
boolean_t extraverbose = B_FALSE;
|
||||
|
||||
/* check options */
|
||||
while ((c = getopt(argc, argv, ":i:I:RDpv")) != -1) {
|
||||
while ((c = getopt(argc, argv, ":i:I:RDpvnP")) != -1) {
|
||||
switch (c) {
|
||||
case 'i':
|
||||
if (fromname)
|
||||
@ -3339,6 +3519,10 @@ zfs_do_send(int argc, char **argv)
|
||||
case 'p':
|
||||
flags.props = B_TRUE;
|
||||
break;
|
||||
case 'P':
|
||||
flags.parsable = B_TRUE;
|
||||
flags.verbose = B_TRUE;
|
||||
break;
|
||||
case 'v':
|
||||
if (flags.verbose)
|
||||
extraverbose = B_TRUE;
|
||||
@ -3347,6 +3531,9 @@ zfs_do_send(int argc, char **argv)
|
||||
case 'D':
|
||||
flags.dedup = B_TRUE;
|
||||
break;
|
||||
case 'n':
|
||||
flags.dryrun = B_TRUE;
|
||||
break;
|
||||
case ':':
|
||||
(void) fprintf(stderr, gettext("missing argument for "
|
||||
"'%c' option\n"), optopt);
|
||||
@ -3372,7 +3559,7 @@ zfs_do_send(int argc, char **argv)
|
||||
usage(B_FALSE);
|
||||
}
|
||||
|
||||
if (isatty(STDOUT_FILENO)) {
|
||||
if (!flags.dryrun && isatty(STDOUT_FILENO)) {
|
||||
(void) fprintf(stderr,
|
||||
gettext("Error: Stream can not be written to a terminal.\n"
|
||||
"You must redirect standard output.\n"));
|
||||
@ -3426,10 +3613,10 @@ zfs_do_send(int argc, char **argv)
|
||||
if (flags.replicate && fromname == NULL)
|
||||
flags.doall = B_TRUE;
|
||||
|
||||
err = zfs_send(zhp, fromname, toname, flags, STDOUT_FILENO, NULL, 0,
|
||||
err = zfs_send(zhp, fromname, toname, &flags, STDOUT_FILENO, NULL, 0,
|
||||
extraverbose ? &dbgnv : NULL);
|
||||
|
||||
if (extraverbose) {
|
||||
if (extraverbose && dbgnv != NULL) {
|
||||
/*
|
||||
* dump_nvlist prints to stdout, but that's been
|
||||
* redirected to a file. Make it print to stderr
|
||||
@ -3510,7 +3697,7 @@ zfs_do_receive(int argc, char **argv)
|
||||
return (1);
|
||||
}
|
||||
|
||||
err = zfs_receive(g_zfs, argv[0], flags, STDIN_FILENO, NULL);
|
||||
err = zfs_receive(g_zfs, argv[0], &flags, STDIN_FILENO, NULL);
|
||||
|
||||
return (err != 0);
|
||||
}
|
||||
|
File diff suppressed because it is too large
Load Diff
@ -22,6 +22,8 @@
|
||||
/*
|
||||
* Copyright (c) 2005, 2010, Oracle and/or its affiliates. All rights reserved.
|
||||
* Copyright 2011 Nexenta Systems, Inc. All rights reserved.
|
||||
* Copyright (c) 2011 by Delphix. All rights reserved.
|
||||
* Copyright (c) 2011 Martin Matuska <mm@FreeBSD.org>. All rights reserved.
|
||||
*/
|
||||
|
||||
#include <solaris.h>
|
||||
@ -68,6 +70,8 @@ static int zpool_do_online(int, char **);
|
||||
static int zpool_do_offline(int, char **);
|
||||
static int zpool_do_clear(int, char **);
|
||||
|
||||
static int zpool_do_reguid(int, char **);
|
||||
|
||||
static int zpool_do_attach(int, char **);
|
||||
static int zpool_do_detach(int, char **);
|
||||
static int zpool_do_replace(int, char **);
|
||||
@ -126,7 +130,8 @@ typedef enum {
|
||||
HELP_UPGRADE,
|
||||
HELP_GET,
|
||||
HELP_SET,
|
||||
HELP_SPLIT
|
||||
HELP_SPLIT,
|
||||
HELP_REGUID
|
||||
} zpool_help_t;
|
||||
|
||||
|
||||
@ -172,6 +177,7 @@ static zpool_command_t command_table[] = {
|
||||
{ "import", zpool_do_import, HELP_IMPORT },
|
||||
{ "export", zpool_do_export, HELP_EXPORT },
|
||||
{ "upgrade", zpool_do_upgrade, HELP_UPGRADE },
|
||||
{ "reguid", zpool_do_reguid, HELP_REGUID },
|
||||
{ NULL },
|
||||
{ "history", zpool_do_history, HELP_HISTORY },
|
||||
{ "get", zpool_do_get, HELP_GET },
|
||||
@ -228,7 +234,7 @@ get_usage(zpool_help_t idx) {
|
||||
case HELP_OFFLINE:
|
||||
return (gettext("\toffline [-t] <pool> <device> ...\n"));
|
||||
case HELP_ONLINE:
|
||||
return (gettext("\tonline <pool> <device> ...\n"));
|
||||
return (gettext("\tonline [-e] <pool> <device> ...\n"));
|
||||
case HELP_REPLACE:
|
||||
return (gettext("\treplace [-f] <pool> <device> "
|
||||
"[new-device]\n"));
|
||||
@ -240,8 +246,7 @@ get_usage(zpool_help_t idx) {
|
||||
return (gettext("\tstatus [-vx] [-T d|u] [pool] ... [interval "
|
||||
"[count]]\n"));
|
||||
case HELP_UPGRADE:
|
||||
return (gettext("\tupgrade\n"
|
||||
"\tupgrade -v\n"
|
||||
return (gettext("\tupgrade [-v]\n"
|
||||
"\tupgrade [-V version] <-a | pool ...>\n"));
|
||||
case HELP_GET:
|
||||
return (gettext("\tget <\"all\" | property[,...]> "
|
||||
@ -252,6 +257,8 @@ get_usage(zpool_help_t idx) {
|
||||
return (gettext("\tsplit [-n] [-R altroot] [-o mntopts]\n"
|
||||
"\t [-o property=value] <pool> <newpool> "
|
||||
"[<device> ...]\n"));
|
||||
case HELP_REGUID:
|
||||
return (gettext("\treguid <pool>\n"));
|
||||
}
|
||||
|
||||
abort();
|
||||
@ -1455,6 +1462,7 @@ show_import(nvlist_t *config)
|
||||
const char *health;
|
||||
uint_t vsc;
|
||||
int namewidth;
|
||||
char *comment;
|
||||
|
||||
verify(nvlist_lookup_string(config, ZPOOL_CONFIG_POOL_NAME,
|
||||
&name) == 0);
|
||||
@ -1471,9 +1479,9 @@ show_import(nvlist_t *config)
|
||||
|
||||
reason = zpool_import_status(config, &msgid);
|
||||
|
||||
(void) printf(gettext(" pool: %s\n"), name);
|
||||
(void) printf(gettext(" id: %llu\n"), (u_longlong_t)guid);
|
||||
(void) printf(gettext(" state: %s"), health);
|
||||
(void) printf(gettext(" pool: %s\n"), name);
|
||||
(void) printf(gettext(" id: %llu\n"), (u_longlong_t)guid);
|
||||
(void) printf(gettext(" state: %s"), health);
|
||||
if (pool_state == POOL_STATE_DESTROYED)
|
||||
(void) printf(gettext(" (DESTROYED)"));
|
||||
(void) printf("\n");
|
||||
@ -1482,58 +1490,59 @@ show_import(nvlist_t *config)
|
||||
case ZPOOL_STATUS_MISSING_DEV_R:
|
||||
case ZPOOL_STATUS_MISSING_DEV_NR:
|
||||
case ZPOOL_STATUS_BAD_GUID_SUM:
|
||||
(void) printf(gettext("status: One or more devices are missing "
|
||||
"from the system.\n"));
|
||||
(void) printf(gettext(" status: One or more devices are "
|
||||
"missing from the system.\n"));
|
||||
break;
|
||||
|
||||
case ZPOOL_STATUS_CORRUPT_LABEL_R:
|
||||
case ZPOOL_STATUS_CORRUPT_LABEL_NR:
|
||||
(void) printf(gettext("status: One or more devices contains "
|
||||
(void) printf(gettext(" status: One or more devices contains "
|
||||
"corrupted data.\n"));
|
||||
break;
|
||||
|
||||
case ZPOOL_STATUS_CORRUPT_DATA:
|
||||
(void) printf(gettext("status: The pool data is corrupted.\n"));
|
||||
(void) printf(
|
||||
gettext(" status: The pool data is corrupted.\n"));
|
||||
break;
|
||||
|
||||
case ZPOOL_STATUS_OFFLINE_DEV:
|
||||
(void) printf(gettext("status: One or more devices "
|
||||
(void) printf(gettext(" status: One or more devices "
|
||||
"are offlined.\n"));
|
||||
break;
|
||||
|
||||
case ZPOOL_STATUS_CORRUPT_POOL:
|
||||
(void) printf(gettext("status: The pool metadata is "
|
||||
(void) printf(gettext(" status: The pool metadata is "
|
||||
"corrupted.\n"));
|
||||
break;
|
||||
|
||||
case ZPOOL_STATUS_VERSION_OLDER:
|
||||
(void) printf(gettext("status: The pool is formatted using an "
|
||||
(void) printf(gettext(" status: The pool is formatted using an "
|
||||
"older on-disk version.\n"));
|
||||
break;
|
||||
|
||||
case ZPOOL_STATUS_VERSION_NEWER:
|
||||
(void) printf(gettext("status: The pool is formatted using an "
|
||||
(void) printf(gettext(" status: The pool is formatted using an "
|
||||
"incompatible version.\n"));
|
||||
break;
|
||||
|
||||
case ZPOOL_STATUS_HOSTID_MISMATCH:
|
||||
(void) printf(gettext("status: The pool was last accessed by "
|
||||
(void) printf(gettext(" status: The pool was last accessed by "
|
||||
"another system.\n"));
|
||||
break;
|
||||
|
||||
case ZPOOL_STATUS_FAULTED_DEV_R:
|
||||
case ZPOOL_STATUS_FAULTED_DEV_NR:
|
||||
(void) printf(gettext("status: One or more devices are "
|
||||
(void) printf(gettext(" status: One or more devices are "
|
||||
"faulted.\n"));
|
||||
break;
|
||||
|
||||
case ZPOOL_STATUS_BAD_LOG:
|
||||
(void) printf(gettext("status: An intent log record cannot be "
|
||||
(void) printf(gettext(" status: An intent log record cannot be "
|
||||
"read.\n"));
|
||||
break;
|
||||
|
||||
case ZPOOL_STATUS_RESILVERING:
|
||||
(void) printf(gettext("status: One or more devices were being "
|
||||
(void) printf(gettext(" status: One or more devices were being "
|
||||
"resilvered.\n"));
|
||||
break;
|
||||
|
||||
@ -1549,26 +1558,26 @@ show_import(nvlist_t *config)
|
||||
*/
|
||||
if (vs->vs_state == VDEV_STATE_HEALTHY) {
|
||||
if (reason == ZPOOL_STATUS_VERSION_OLDER)
|
||||
(void) printf(gettext("action: The pool can be "
|
||||
(void) printf(gettext(" action: The pool can be "
|
||||
"imported using its name or numeric identifier, "
|
||||
"though\n\tsome features will not be available "
|
||||
"without an explicit 'zpool upgrade'.\n"));
|
||||
else if (reason == ZPOOL_STATUS_HOSTID_MISMATCH)
|
||||
(void) printf(gettext("action: The pool can be "
|
||||
(void) printf(gettext(" action: The pool can be "
|
||||
"imported using its name or numeric "
|
||||
"identifier and\n\tthe '-f' flag.\n"));
|
||||
else
|
||||
(void) printf(gettext("action: The pool can be "
|
||||
(void) printf(gettext(" action: The pool can be "
|
||||
"imported using its name or numeric "
|
||||
"identifier.\n"));
|
||||
} else if (vs->vs_state == VDEV_STATE_DEGRADED) {
|
||||
(void) printf(gettext("action: The pool can be imported "
|
||||
(void) printf(gettext(" action: The pool can be imported "
|
||||
"despite missing or damaged devices. The\n\tfault "
|
||||
"tolerance of the pool may be compromised if imported.\n"));
|
||||
} else {
|
||||
switch (reason) {
|
||||
case ZPOOL_STATUS_VERSION_NEWER:
|
||||
(void) printf(gettext("action: The pool cannot be "
|
||||
(void) printf(gettext(" action: The pool cannot be "
|
||||
"imported. Access the pool on a system running "
|
||||
"newer\n\tsoftware, or recreate the pool from "
|
||||
"backup.\n"));
|
||||
@ -1576,16 +1585,20 @@ show_import(nvlist_t *config)
|
||||
case ZPOOL_STATUS_MISSING_DEV_R:
|
||||
case ZPOOL_STATUS_MISSING_DEV_NR:
|
||||
case ZPOOL_STATUS_BAD_GUID_SUM:
|
||||
(void) printf(gettext("action: The pool cannot be "
|
||||
(void) printf(gettext(" action: The pool cannot be "
|
||||
"imported. Attach the missing\n\tdevices and try "
|
||||
"again.\n"));
|
||||
break;
|
||||
default:
|
||||
(void) printf(gettext("action: The pool cannot be "
|
||||
(void) printf(gettext(" action: The pool cannot be "
|
||||
"imported due to damaged devices or data.\n"));
|
||||
}
|
||||
}
|
||||
|
||||
/* Print the comment attached to the pool. */
|
||||
if (nvlist_lookup_string(config, ZPOOL_CONFIG_COMMENT, &comment) == 0)
|
||||
(void) printf(gettext("comment: %s\n"), comment);
|
||||
|
||||
/*
|
||||
* If the state is "closed" or "can't open", and the aux state
|
||||
* is "corrupt data":
|
||||
@ -1606,7 +1619,7 @@ show_import(nvlist_t *config)
|
||||
(void) printf(gettext(" see: http://www.sun.com/msg/%s\n"),
|
||||
msgid);
|
||||
|
||||
(void) printf(gettext("config:\n\n"));
|
||||
(void) printf(gettext(" config:\n\n"));
|
||||
|
||||
namewidth = max_width(NULL, nvroot, 0, 0);
|
||||
if (namewidth < 10)
|
||||
@ -3321,6 +3334,52 @@ zpool_do_clear(int argc, char **argv)
|
||||
return (ret);
|
||||
}
|
||||
|
||||
/*
|
||||
* zpool reguid <pool>
|
||||
*/
|
||||
int
|
||||
zpool_do_reguid(int argc, char **argv)
|
||||
{
|
||||
int c;
|
||||
char *poolname;
|
||||
zpool_handle_t *zhp;
|
||||
int ret = 0;
|
||||
|
||||
/* check options */
|
||||
while ((c = getopt(argc, argv, "")) != -1) {
|
||||
switch (c) {
|
||||
case '?':
|
||||
(void) fprintf(stderr, gettext("invalid option '%c'\n"),
|
||||
optopt);
|
||||
usage(B_FALSE);
|
||||
}
|
||||
}
|
||||
|
||||
argc -= optind;
|
||||
argv += optind;
|
||||
|
||||
/* get pool name and check number of arguments */
|
||||
if (argc < 1) {
|
||||
(void) fprintf(stderr, gettext("missing pool name\n"));
|
||||
usage(B_FALSE);
|
||||
}
|
||||
|
||||
if (argc > 1) {
|
||||
(void) fprintf(stderr, gettext("too many arguments\n"));
|
||||
usage(B_FALSE);
|
||||
}
|
||||
|
||||
poolname = argv[0];
|
||||
if ((zhp = zpool_open(g_zfs, poolname)) == NULL)
|
||||
return (1);
|
||||
|
||||
ret = zpool_reguid(zhp);
|
||||
|
||||
zpool_close(zhp);
|
||||
return (ret);
|
||||
}
|
||||
|
||||
|
||||
typedef struct scrub_cbdata {
|
||||
int cb_type;
|
||||
int cb_argc;
|
||||
|
@ -1,49 +1,67 @@
|
||||
'\" te
|
||||
.\" Copyright (c) 2009, Sun Microsystems, Inc. All Rights Reserved
|
||||
.\" The contents of this file are subject to the terms of the Common Development and Distribution License (the "License"). You may not use this file except in compliance with the License. You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE or http://www.opensolaris.org/os/licensing.
|
||||
.\" See the License for the specific language governing permissions and limitations under the License. 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]
|
||||
.\" Portions Copyright 2011 Martin Matuska <mm@FreeBSD.org>
|
||||
.TH ZSTREAMDUMP 1 "Sep 21, 2009"
|
||||
.SH NAME
|
||||
zstreamdump \- filter data in zfs send stream
|
||||
.SH SYNOPSIS
|
||||
.LP
|
||||
.nf
|
||||
\fBzstreamdump\fR [\fB-C\fR] [\fB-v\fR]
|
||||
.fi
|
||||
|
||||
.SH DESCRIPTION
|
||||
.sp
|
||||
.LP
|
||||
The \fBzstreamdump\fR utility reads from the output of the \fBzfs send\fR
|
||||
command, then displays headers and some statistics from that output. See
|
||||
\fBzfs\fR(1M).
|
||||
.SH OPTIONS
|
||||
.sp
|
||||
.LP
|
||||
.\" Copyright (c) 2011, Martin Matuska <mm@FreeBSD.org>.
|
||||
.\" All Rights Reserved.
|
||||
.\"
|
||||
.\" The contents of this file are subject to the terms of the
|
||||
.\" Common Development and Distribution License (the "License").
|
||||
.\" You may not use this file except in compliance with the License.
|
||||
.\"
|
||||
.\" You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE
|
||||
.\" or http://www.opensolaris.org/os/licensing.
|
||||
.\" See the License for the specific language governing permissions
|
||||
.\" and limitations under the License.
|
||||
.\"
|
||||
.\" When distributing Covered Code, include this CDDL HEADER in each
|
||||
.\" file and include the License file at usr/src/OPENSOLARIS.LICENSE.
|
||||
.\" If applicable, add the following below this CDDL HEADER, with the
|
||||
.\" fields enclosed by brackets "[]" replaced with your own identifying
|
||||
.\" information: Portions Copyright [yyyy] [name of copyright owner]
|
||||
.\"
|
||||
.\" Copyright (c) 2009, Sun Microsystems, Inc. All Rights Reserved.
|
||||
.\"
|
||||
.\" $FreeBSD$
|
||||
.\"
|
||||
.Dd November 26, 2011
|
||||
.Dt ZSTREAMDUMP 8
|
||||
.Os
|
||||
.Sh NAME
|
||||
.Nm zdb
|
||||
.Nd filter data in zfs send stream
|
||||
.Sh SYNOPSIS
|
||||
.Nm
|
||||
.Op Fl C
|
||||
.Op Fl v
|
||||
.Sh DESCRIPTION
|
||||
The
|
||||
.Nm
|
||||
utility reads from the output of the
|
||||
.Qq Nm zfs Cm send
|
||||
command, then displays headers and some statistics from that output. See
|
||||
.Xr zfs 8 .
|
||||
.Pp
|
||||
The following options are supported:
|
||||
.sp
|
||||
.ne 2
|
||||
.na
|
||||
\fB\fB-C\fR\fR
|
||||
.ad
|
||||
.sp .6
|
||||
.RS 4n
|
||||
.Bl -tag -width indent
|
||||
.It Fl C
|
||||
Suppress the validation of checksums.
|
||||
.RE
|
||||
|
||||
.sp
|
||||
.ne 2
|
||||
.na
|
||||
\fB\fB-v\fR\fR
|
||||
.ad
|
||||
.sp .6
|
||||
.RS 4n
|
||||
.It Fl v
|
||||
Verbose. Dump all headers, not only begin and end headers.
|
||||
.RE
|
||||
|
||||
.SH SEE ALSO
|
||||
.sp
|
||||
.LP
|
||||
zfs(8)
|
||||
.El
|
||||
.Sh SEE ALSO
|
||||
.Xr zfs 8
|
||||
.Sh AUTHORS
|
||||
This manual page is a
|
||||
.Xr mdoc 7
|
||||
reimplementation of the
|
||||
.Tn OpenSolaris
|
||||
manual page
|
||||
.Em zstreamdump(1M) ,
|
||||
modified and customized for
|
||||
.Fx
|
||||
and licensed under the
|
||||
.Tn Common Development and Distribution License
|
||||
.Pq Tn CDDL .
|
||||
.Pp
|
||||
The
|
||||
.Xr mdoc 7
|
||||
implementation of this manual page was initially written by
|
||||
.An Martin Matuska Aq mm@FreeBSD.org .
|
||||
|
@ -21,6 +21,7 @@
|
||||
/*
|
||||
* Copyright (c) 2005, 2010, Oracle and/or its affiliates. All rights reserved.
|
||||
* Copyright (c) 2011 by Delphix. All rights reserved.
|
||||
* Copyright 2011 Nexenta Systems, Inc. All rights reserved.
|
||||
*/
|
||||
|
||||
/*
|
||||
@ -259,6 +260,7 @@ ztest_func_t ztest_vdev_LUN_growth;
|
||||
ztest_func_t ztest_vdev_add_remove;
|
||||
ztest_func_t ztest_vdev_aux_add_remove;
|
||||
ztest_func_t ztest_split_pool;
|
||||
ztest_func_t ztest_reguid;
|
||||
|
||||
uint64_t zopt_always = 0ULL * NANOSEC; /* all the time */
|
||||
uint64_t zopt_incessant = 1ULL * NANOSEC / 10; /* every 1/10 second */
|
||||
@ -289,6 +291,7 @@ ztest_info_t ztest_info[] = {
|
||||
{ ztest_fault_inject, 1, &zopt_sometimes },
|
||||
{ ztest_ddt_repair, 1, &zopt_sometimes },
|
||||
{ ztest_dmu_snapshot_hold, 1, &zopt_sometimes },
|
||||
{ ztest_reguid, 1, &zopt_sometimes },
|
||||
{ ztest_spa_rename, 1, &zopt_rarely },
|
||||
{ ztest_scrub, 1, &zopt_rarely },
|
||||
{ ztest_dsl_dataset_promote_busy, 1, &zopt_rarely },
|
||||
@ -325,6 +328,7 @@ typedef struct ztest_shared {
|
||||
uint64_t zs_vdev_aux;
|
||||
uint64_t zs_alloc;
|
||||
uint64_t zs_space;
|
||||
uint64_t zs_guid;
|
||||
mutex_t zs_vdev_lock;
|
||||
rwlock_t zs_name_lock;
|
||||
ztest_info_t zs_info[ZTEST_FUNCS];
|
||||
@ -4646,7 +4650,7 @@ ztest_ddt_repair(ztest_ds_t *zd, uint64_t id)
|
||||
|
||||
object = od[0].od_object;
|
||||
blocksize = od[0].od_blocksize;
|
||||
pattern = spa_guid(spa) ^ dmu_objset_fsid_guid(os);
|
||||
pattern = zs->zs_guid ^ dmu_objset_fsid_guid(os);
|
||||
|
||||
ASSERT(object != 0);
|
||||
|
||||
@ -4716,6 +4720,31 @@ ztest_scrub(ztest_ds_t *zd, uint64_t id)
|
||||
(void) spa_scan(spa, POOL_SCAN_SCRUB);
|
||||
}
|
||||
|
||||
/*
|
||||
* Change the guid for the pool.
|
||||
*/
|
||||
/* ARGSUSED */
|
||||
void
|
||||
ztest_reguid(ztest_ds_t *zd, uint64_t id)
|
||||
{
|
||||
ztest_shared_t *zs = ztest_shared;
|
||||
spa_t *spa = zs->zs_spa;
|
||||
uint64_t orig, load;
|
||||
|
||||
orig = spa_guid(spa);
|
||||
load = spa_load_guid(spa);
|
||||
if (spa_change_guid(spa) != 0)
|
||||
return;
|
||||
|
||||
if (zopt_verbose >= 3) {
|
||||
(void) printf("Changed guid old %llu -> %llu\n",
|
||||
(u_longlong_t)orig, (u_longlong_t)spa_guid(spa));
|
||||
}
|
||||
|
||||
VERIFY3U(orig, !=, spa_guid(spa));
|
||||
VERIFY3U(load, ==, spa_load_guid(spa));
|
||||
}
|
||||
|
||||
/*
|
||||
* Rename the pool to a different name and then rename it back.
|
||||
*/
|
||||
@ -5145,6 +5174,7 @@ ztest_run(ztest_shared_t *zs)
|
||||
{
|
||||
thread_t *tid;
|
||||
spa_t *spa;
|
||||
objset_t *os;
|
||||
thread_t resume_tid;
|
||||
int error;
|
||||
|
||||
@ -5176,6 +5206,10 @@ ztest_run(ztest_shared_t *zs)
|
||||
spa->spa_debug = B_TRUE;
|
||||
zs->zs_spa = spa;
|
||||
|
||||
VERIFY3U(0, ==, dmu_objset_hold(zs->zs_pool, FTAG, &os));
|
||||
zs->zs_guid = dmu_objset_fsid_guid(os);
|
||||
dmu_objset_rele(os, FTAG);
|
||||
|
||||
spa->spa_dedup_ditto = 2 * ZIO_DEDUPDITTO_MIN;
|
||||
|
||||
/*
|
||||
|
@ -102,7 +102,7 @@ fixsymbol(Elf *e, Elf_Data *data, size_t idx, int nprobes, char *buf,
|
||||
int ndx;
|
||||
|
||||
while (gelf_getsym(data, j++, &sym) != NULL) {
|
||||
prb = (dof_probe_t *)(buf + sec->dofs_offset);
|
||||
prb = (dof_probe_t *)(void *)(buf + sec->dofs_offset);
|
||||
|
||||
for (ndx = nprobes; ndx; ndx--, prb += 1) {
|
||||
funcname = dofstrtab + prb->dofpr_func;
|
||||
|
@ -873,7 +873,7 @@ dt_print_stack(dtrace_hdl_t *dtp, FILE *fp, const char *format,
|
||||
if (pc > sym.st_value) {
|
||||
(void) snprintf(c, sizeof (c), "%s`%s+0x%llx",
|
||||
dts.dts_object, dts.dts_name,
|
||||
pc - sym.st_value);
|
||||
(u_longlong_t)(pc - sym.st_value));
|
||||
} else {
|
||||
(void) snprintf(c, sizeof (c), "%s`%s",
|
||||
dts.dts_object, dts.dts_name);
|
||||
@ -886,9 +886,10 @@ dt_print_stack(dtrace_hdl_t *dtp, FILE *fp, const char *format,
|
||||
*/
|
||||
if (dtrace_lookup_by_addr(dtp, pc, NULL, &dts) == 0) {
|
||||
(void) snprintf(c, sizeof (c), "%s`0x%llx",
|
||||
dts.dts_object, pc);
|
||||
dts.dts_object, (u_longlong_t)pc);
|
||||
} else {
|
||||
(void) snprintf(c, sizeof (c), "0x%llx", pc);
|
||||
(void) snprintf(c, sizeof (c), "0x%llx",
|
||||
(u_longlong_t)pc);
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -335,7 +335,8 @@ dt_handle_cpudrop(dtrace_hdl_t *dtp, processorid_t cpu,
|
||||
}
|
||||
|
||||
(void) snprintf(s, size, "%llu %sdrop%s on CPU %d\n",
|
||||
howmany, what == DTRACEDROP_PRINCIPAL ? "" : "aggregation ",
|
||||
(u_longlong_t)howmany,
|
||||
what == DTRACEDROP_PRINCIPAL ? "" : "aggregation ",
|
||||
howmany > 1 ? "s" : "", cpu);
|
||||
|
||||
if (dtp->dt_drophdlr == NULL)
|
||||
@ -427,7 +428,8 @@ dt_handle_status(dtrace_hdl_t *dtp, dtrace_status_t *old, dtrace_status_t *new)
|
||||
size = sizeof (str);
|
||||
}
|
||||
|
||||
(void) snprintf(s, size, "%llu %s%s%s\n", nval - oval,
|
||||
(void) snprintf(s, size, "%llu %s%s%s\n",
|
||||
(u_longlong_t)(nval - oval),
|
||||
_dt_droptab[i].dtdrt_str, (nval - oval > 1) ? "s" : "",
|
||||
_dt_droptab[i].dtdrt_msg != NULL ?
|
||||
_dt_droptab[i].dtdrt_msg : "");
|
||||
|
@ -1106,7 +1106,7 @@ process_obj(dtrace_hdl_t *dtp, const char *obj, int *eprobesp)
|
||||
static const char dt_prefix[] = "__dtrace";
|
||||
static const char dt_enabled[] = "enabled";
|
||||
static const char dt_symprefix[] = "$dtrace";
|
||||
static const char dt_symfmt[] = "%s%d.%s";
|
||||
static const char dt_symfmt[] = "%s%ld.%s";
|
||||
int fd, i, ndx, eprobe, mod = 0;
|
||||
Elf *elf = NULL;
|
||||
GElf_Ehdr ehdr;
|
||||
|
@ -27,6 +27,7 @@
|
||||
#if defined(sun)
|
||||
#include <sys/sysmacros.h>
|
||||
#endif
|
||||
#include <sys/isa_defs.h>
|
||||
|
||||
#include <strings.h>
|
||||
#include <unistd.h>
|
||||
|
@ -436,7 +436,7 @@ dt_pid_create_glob_offset_probes(struct ps_prochandle *P, dtrace_hdl_t *dtp,
|
||||
char name[sizeof (i) * 2 + 1];
|
||||
|
||||
for (i = 0; i < end; i += size) {
|
||||
(void) snprintf(name, sizeof (name), "%x", i);
|
||||
(void) snprintf(name, sizeof (name), "%lx", i);
|
||||
if (gmatch(name, pattern))
|
||||
ftp->ftps_offs[ftp->ftps_noffs++] = i;
|
||||
|
||||
|
@ -21,8 +21,8 @@
|
||||
|
||||
/*
|
||||
* Copyright (c) 2005, 2010, Oracle and/or its affiliates. All rights reserved.
|
||||
* Copyright 2010 Nexenta Systems, Inc. All rights reserved.
|
||||
* Copyright (c) 2011 Pawel Jakub Dawidek <pawel@dawidek.net>.
|
||||
* Copyright 2011 Nexenta Systems, Inc. All rights reserved.
|
||||
* Copyright (c) 2011 by Delphix. All rights reserved.
|
||||
* All rights reserved.
|
||||
*/
|
||||
|
||||
@ -233,6 +233,7 @@ typedef struct splitflags {
|
||||
*/
|
||||
extern int zpool_scan(zpool_handle_t *, pool_scan_func_t);
|
||||
extern int zpool_clear(zpool_handle_t *, const char *, nvlist_t *);
|
||||
extern int zpool_reguid(zpool_handle_t *);
|
||||
|
||||
extern int zpool_vdev_online(zpool_handle_t *, const char *, int,
|
||||
vdev_state_t *);
|
||||
@ -384,6 +385,7 @@ extern void zpool_explain_recover(libzfs_handle_t *, const char *, int,
|
||||
* underlying datasets, only the references to them.
|
||||
*/
|
||||
extern zfs_handle_t *zfs_open(libzfs_handle_t *, const char *, int);
|
||||
extern zfs_handle_t *zfs_handle_dup(zfs_handle_t *);
|
||||
extern void zfs_close(zfs_handle_t *);
|
||||
extern zfs_type_t zfs_get_type(const zfs_handle_t *);
|
||||
extern const char *zfs_get_name(const zfs_handle_t *);
|
||||
@ -417,12 +419,20 @@ extern int zfs_prop_get_userquota_int(zfs_handle_t *zhp, const char *propname,
|
||||
uint64_t *propvalue);
|
||||
extern int zfs_prop_get_userquota(zfs_handle_t *zhp, const char *propname,
|
||||
char *propbuf, int proplen, boolean_t literal);
|
||||
extern int zfs_prop_get_written_int(zfs_handle_t *zhp, const char *propname,
|
||||
uint64_t *propvalue);
|
||||
extern int zfs_prop_get_written(zfs_handle_t *zhp, const char *propname,
|
||||
char *propbuf, int proplen, boolean_t literal);
|
||||
extern int zfs_get_snapused_int(zfs_handle_t *firstsnap, zfs_handle_t *lastsnap,
|
||||
uint64_t *usedp);
|
||||
extern uint64_t zfs_prop_get_int(zfs_handle_t *, zfs_prop_t);
|
||||
extern int zfs_prop_inherit(zfs_handle_t *, const char *, boolean_t);
|
||||
extern const char *zfs_prop_values(zfs_prop_t);
|
||||
extern int zfs_prop_is_string(zfs_prop_t prop);
|
||||
extern nvlist_t *zfs_get_user_props(zfs_handle_t *);
|
||||
extern nvlist_t *zfs_get_recvd_props(zfs_handle_t *);
|
||||
extern nvlist_t *zfs_get_clones_nvl(zfs_handle_t *);
|
||||
|
||||
|
||||
typedef struct zprop_list {
|
||||
int pl_prop;
|
||||
@ -497,6 +507,7 @@ extern int zfs_iter_dependents(zfs_handle_t *, boolean_t, zfs_iter_f, void *);
|
||||
extern int zfs_iter_filesystems(zfs_handle_t *, zfs_iter_f, void *);
|
||||
extern int zfs_iter_snapshots(zfs_handle_t *, zfs_iter_f, void *);
|
||||
extern int zfs_iter_snapshots_sorted(zfs_handle_t *, zfs_iter_f, void *);
|
||||
extern int zfs_iter_snapspec(zfs_handle_t *, const char *, zfs_iter_f, void *);
|
||||
|
||||
typedef struct get_all_cb {
|
||||
zfs_handle_t **cb_handles;
|
||||
@ -517,6 +528,7 @@ extern int zfs_create(libzfs_handle_t *, const char *, zfs_type_t,
|
||||
extern int zfs_create_ancestors(libzfs_handle_t *, const char *);
|
||||
extern int zfs_destroy(zfs_handle_t *, boolean_t);
|
||||
extern int zfs_destroy_snaps(zfs_handle_t *, char *, boolean_t);
|
||||
extern int zfs_destroy_snaps_nvl(zfs_handle_t *, nvlist_t *, boolean_t);
|
||||
extern int zfs_clone(zfs_handle_t *, const char *, nvlist_t *);
|
||||
extern int zfs_snapshot(libzfs_handle_t *, const char *, boolean_t, nvlist_t *);
|
||||
extern int zfs_rollback(zfs_handle_t *, zfs_handle_t *, boolean_t);
|
||||
@ -533,29 +545,34 @@ extern int zfs_rename(zfs_handle_t *, const char *, renameflags_t flags);
|
||||
|
||||
typedef struct sendflags {
|
||||
/* print informational messages (ie, -v was specified) */
|
||||
int verbose : 1;
|
||||
boolean_t verbose;
|
||||
|
||||
/* recursive send (ie, -R) */
|
||||
int replicate : 1;
|
||||
boolean_t replicate;
|
||||
|
||||
/* for incrementals, do all intermediate snapshots */
|
||||
int doall : 1; /* (ie, -I) */
|
||||
boolean_t doall;
|
||||
|
||||
/* if dataset is a clone, do incremental from its origin */
|
||||
int fromorigin : 1;
|
||||
boolean_t fromorigin;
|
||||
|
||||
/* do deduplication */
|
||||
int dedup : 1;
|
||||
boolean_t dedup;
|
||||
|
||||
/* send properties (ie, -p) */
|
||||
int props : 1;
|
||||
boolean_t props;
|
||||
|
||||
/* do not send (no-op, ie. -n) */
|
||||
boolean_t dryrun;
|
||||
|
||||
/* parsable verbose output (ie. -P) */
|
||||
boolean_t parsable;
|
||||
} sendflags_t;
|
||||
|
||||
typedef boolean_t (snapfilter_cb_t)(zfs_handle_t *, void *);
|
||||
|
||||
extern int zfs_send(zfs_handle_t *zhp, const char *fromsnap, const char *tosnap,
|
||||
sendflags_t flags, int outfd, snapfilter_cb_t filter_func,
|
||||
void *cb_arg, nvlist_t **debugnvp);
|
||||
extern int zfs_send(zfs_handle_t *, const char *, const char *,
|
||||
sendflags_t *, int, snapfilter_cb_t, void *, nvlist_t **);
|
||||
|
||||
extern int zfs_promote(zfs_handle_t *);
|
||||
extern int zfs_hold(zfs_handle_t *, const char *, const char *, boolean_t,
|
||||
@ -575,34 +592,34 @@ extern int zfs_set_fsacl(zfs_handle_t *, boolean_t, nvlist_t *);
|
||||
|
||||
typedef struct recvflags {
|
||||
/* print informational messages (ie, -v was specified) */
|
||||
int verbose : 1;
|
||||
boolean_t verbose;
|
||||
|
||||
/* the destination is a prefix, not the exact fs (ie, -d) */
|
||||
int isprefix : 1;
|
||||
boolean_t isprefix;
|
||||
|
||||
/*
|
||||
* Only the tail of the sent snapshot path is appended to the
|
||||
* destination to determine the received snapshot name (ie, -e).
|
||||
*/
|
||||
int istail : 1;
|
||||
boolean_t istail;
|
||||
|
||||
/* do not actually do the recv, just check if it would work (ie, -n) */
|
||||
int dryrun : 1;
|
||||
boolean_t dryrun;
|
||||
|
||||
/* rollback/destroy filesystems as necessary (eg, -F) */
|
||||
int force : 1;
|
||||
boolean_t force;
|
||||
|
||||
/* set "canmount=off" on all modified filesystems */
|
||||
int canmountoff : 1;
|
||||
boolean_t canmountoff;
|
||||
|
||||
/* byteswap flag is used internally; callers need not specify */
|
||||
int byteswap : 1;
|
||||
boolean_t byteswap;
|
||||
|
||||
/* do not mount file systems as they are extracted (private) */
|
||||
int nomount : 1;
|
||||
boolean_t nomount;
|
||||
} recvflags_t;
|
||||
|
||||
extern int zfs_receive(libzfs_handle_t *, const char *, recvflags_t,
|
||||
extern int zfs_receive(libzfs_handle_t *, const char *, recvflags_t *,
|
||||
int, avl_tree_t *);
|
||||
|
||||
typedef enum diff_flags {
|
||||
|
@ -496,7 +496,7 @@ make_dataset_handle(libzfs_handle_t *hdl, const char *path)
|
||||
return (zhp);
|
||||
}
|
||||
|
||||
static zfs_handle_t *
|
||||
zfs_handle_t *
|
||||
make_dataset_handle_zc(libzfs_handle_t *hdl, zfs_cmd_t *zc)
|
||||
{
|
||||
zfs_handle_t *zhp = calloc(sizeof (zfs_handle_t), 1);
|
||||
@ -513,6 +513,53 @@ make_dataset_handle_zc(libzfs_handle_t *hdl, zfs_cmd_t *zc)
|
||||
return (zhp);
|
||||
}
|
||||
|
||||
zfs_handle_t *
|
||||
zfs_handle_dup(zfs_handle_t *zhp_orig)
|
||||
{
|
||||
zfs_handle_t *zhp = calloc(sizeof (zfs_handle_t), 1);
|
||||
|
||||
if (zhp == NULL)
|
||||
return (NULL);
|
||||
|
||||
zhp->zfs_hdl = zhp_orig->zfs_hdl;
|
||||
zhp->zpool_hdl = zhp_orig->zpool_hdl;
|
||||
(void) strlcpy(zhp->zfs_name, zhp_orig->zfs_name,
|
||||
sizeof (zhp->zfs_name));
|
||||
zhp->zfs_type = zhp_orig->zfs_type;
|
||||
zhp->zfs_head_type = zhp_orig->zfs_head_type;
|
||||
zhp->zfs_dmustats = zhp_orig->zfs_dmustats;
|
||||
if (zhp_orig->zfs_props != NULL) {
|
||||
if (nvlist_dup(zhp_orig->zfs_props, &zhp->zfs_props, 0) != 0) {
|
||||
(void) no_memory(zhp->zfs_hdl);
|
||||
zfs_close(zhp);
|
||||
return (NULL);
|
||||
}
|
||||
}
|
||||
if (zhp_orig->zfs_user_props != NULL) {
|
||||
if (nvlist_dup(zhp_orig->zfs_user_props,
|
||||
&zhp->zfs_user_props, 0) != 0) {
|
||||
(void) no_memory(zhp->zfs_hdl);
|
||||
zfs_close(zhp);
|
||||
return (NULL);
|
||||
}
|
||||
}
|
||||
if (zhp_orig->zfs_recvd_props != NULL) {
|
||||
if (nvlist_dup(zhp_orig->zfs_recvd_props,
|
||||
&zhp->zfs_recvd_props, 0)) {
|
||||
(void) no_memory(zhp->zfs_hdl);
|
||||
zfs_close(zhp);
|
||||
return (NULL);
|
||||
}
|
||||
}
|
||||
zhp->zfs_mntcheck = zhp_orig->zfs_mntcheck;
|
||||
if (zhp_orig->zfs_mntopts != NULL) {
|
||||
zhp->zfs_mntopts = zfs_strdup(zhp_orig->zfs_hdl,
|
||||
zhp_orig->zfs_mntopts);
|
||||
}
|
||||
zhp->zfs_props_table = zhp_orig->zfs_props_table;
|
||||
return (zhp);
|
||||
}
|
||||
|
||||
/*
|
||||
* Opens the given snapshot, filesystem, or volume. The 'types'
|
||||
* argument is a mask of acceptable types. The function will print an
|
||||
@ -876,6 +923,12 @@ zfs_valid_proplist(libzfs_handle_t *hdl, zfs_type_t type, nvlist_t *nvl,
|
||||
goto error;
|
||||
}
|
||||
continue;
|
||||
} else if (prop == ZPROP_INVAL && zfs_prop_written(propname)) {
|
||||
zfs_error_aux(hdl, dgettext(TEXT_DOMAIN,
|
||||
"'%s' is readonly"),
|
||||
propname);
|
||||
(void) zfs_error(hdl, EZFS_PROPREADONLY, errbuf);
|
||||
goto error;
|
||||
}
|
||||
|
||||
if (prop == ZPROP_INVAL) {
|
||||
@ -1869,8 +1922,6 @@ zfs_prop_get_recvd(zfs_handle_t *zhp, const char *propname, char *propbuf,
|
||||
err = zfs_prop_get(zhp, prop, propbuf, proplen,
|
||||
NULL, NULL, 0, literal);
|
||||
zfs_unset_recvd_props_mode(zhp, &cookie);
|
||||
} else if (zfs_prop_userquota(propname)) {
|
||||
return (-1);
|
||||
} else {
|
||||
nvlist_t *propval;
|
||||
char *recvdval;
|
||||
@ -1885,6 +1936,120 @@ zfs_prop_get_recvd(zfs_handle_t *zhp, const char *propname, char *propbuf,
|
||||
return (err == 0 ? 0 : -1);
|
||||
}
|
||||
|
||||
static int
|
||||
get_clones_string(zfs_handle_t *zhp, char *propbuf, size_t proplen)
|
||||
{
|
||||
nvlist_t *value;
|
||||
nvpair_t *pair;
|
||||
|
||||
value = zfs_get_clones_nvl(zhp);
|
||||
if (value == NULL)
|
||||
return (-1);
|
||||
|
||||
propbuf[0] = '\0';
|
||||
for (pair = nvlist_next_nvpair(value, NULL); pair != NULL;
|
||||
pair = nvlist_next_nvpair(value, pair)) {
|
||||
if (propbuf[0] != '\0')
|
||||
(void) strlcat(propbuf, ",", proplen);
|
||||
(void) strlcat(propbuf, nvpair_name(pair), proplen);
|
||||
}
|
||||
|
||||
return (0);
|
||||
}
|
||||
|
||||
struct get_clones_arg {
|
||||
uint64_t numclones;
|
||||
nvlist_t *value;
|
||||
const char *origin;
|
||||
char buf[ZFS_MAXNAMELEN];
|
||||
};
|
||||
|
||||
int
|
||||
get_clones_cb(zfs_handle_t *zhp, void *arg)
|
||||
{
|
||||
struct get_clones_arg *gca = arg;
|
||||
|
||||
if (gca->numclones == 0) {
|
||||
zfs_close(zhp);
|
||||
return (0);
|
||||
}
|
||||
|
||||
if (zfs_prop_get(zhp, ZFS_PROP_ORIGIN, gca->buf, sizeof (gca->buf),
|
||||
NULL, NULL, 0, B_TRUE) != 0)
|
||||
goto out;
|
||||
if (strcmp(gca->buf, gca->origin) == 0) {
|
||||
if (nvlist_add_boolean(gca->value, zfs_get_name(zhp)) != 0) {
|
||||
zfs_close(zhp);
|
||||
return (no_memory(zhp->zfs_hdl));
|
||||
}
|
||||
gca->numclones--;
|
||||
}
|
||||
|
||||
out:
|
||||
(void) zfs_iter_children(zhp, get_clones_cb, gca);
|
||||
zfs_close(zhp);
|
||||
return (0);
|
||||
}
|
||||
|
||||
nvlist_t *
|
||||
zfs_get_clones_nvl(zfs_handle_t *zhp)
|
||||
{
|
||||
nvlist_t *nv, *value;
|
||||
|
||||
if (nvlist_lookup_nvlist(zhp->zfs_props,
|
||||
zfs_prop_to_name(ZFS_PROP_CLONES), &nv) != 0) {
|
||||
struct get_clones_arg gca;
|
||||
|
||||
/*
|
||||
* if this is a snapshot, then the kernel wasn't able
|
||||
* to get the clones. Do it by slowly iterating.
|
||||
*/
|
||||
if (zhp->zfs_type != ZFS_TYPE_SNAPSHOT)
|
||||
return (NULL);
|
||||
if (nvlist_alloc(&nv, NV_UNIQUE_NAME, 0) != 0)
|
||||
return (NULL);
|
||||
if (nvlist_alloc(&value, NV_UNIQUE_NAME, 0) != 0) {
|
||||
nvlist_free(nv);
|
||||
return (NULL);
|
||||
}
|
||||
|
||||
gca.numclones = zfs_prop_get_int(zhp, ZFS_PROP_NUMCLONES);
|
||||
gca.value = value;
|
||||
gca.origin = zhp->zfs_name;
|
||||
|
||||
if (gca.numclones != 0) {
|
||||
zfs_handle_t *root;
|
||||
char pool[ZFS_MAXNAMELEN];
|
||||
char *cp = pool;
|
||||
|
||||
/* get the pool name */
|
||||
(void) strlcpy(pool, zhp->zfs_name, sizeof (pool));
|
||||
(void) strsep(&cp, "/@");
|
||||
root = zfs_open(zhp->zfs_hdl, pool,
|
||||
ZFS_TYPE_FILESYSTEM);
|
||||
|
||||
(void) get_clones_cb(root, &gca);
|
||||
}
|
||||
|
||||
if (gca.numclones != 0 ||
|
||||
nvlist_add_nvlist(nv, ZPROP_VALUE, value) != 0 ||
|
||||
nvlist_add_nvlist(zhp->zfs_props,
|
||||
zfs_prop_to_name(ZFS_PROP_CLONES), nv) != 0) {
|
||||
nvlist_free(nv);
|
||||
nvlist_free(value);
|
||||
return (NULL);
|
||||
}
|
||||
nvlist_free(nv);
|
||||
nvlist_free(value);
|
||||
verify(0 == nvlist_lookup_nvlist(zhp->zfs_props,
|
||||
zfs_prop_to_name(ZFS_PROP_CLONES), &nv));
|
||||
}
|
||||
|
||||
verify(nvlist_lookup_nvlist(nv, ZPROP_VALUE, &value) == 0);
|
||||
|
||||
return (value);
|
||||
}
|
||||
|
||||
/*
|
||||
* Retrieve a property from the given object. If 'literal' is specified, then
|
||||
* numbers are left as exact values. Otherwise, numbers are converted to a
|
||||
@ -2013,6 +2178,11 @@ zfs_prop_get(zfs_handle_t *zhp, zfs_prop_t prop, char *propbuf, size_t proplen,
|
||||
return (-1);
|
||||
break;
|
||||
|
||||
case ZFS_PROP_CLONES:
|
||||
if (get_clones_string(zhp, propbuf, proplen) != 0)
|
||||
return (-1);
|
||||
break;
|
||||
|
||||
case ZFS_PROP_QUOTA:
|
||||
case ZFS_PROP_REFQUOTA:
|
||||
case ZFS_PROP_RESERVATION:
|
||||
@ -2385,7 +2555,7 @@ zfs_prop_get_userquota_common(zfs_handle_t *zhp, const char *propname,
|
||||
int err;
|
||||
zfs_cmd_t zc = { 0 };
|
||||
|
||||
(void) strncpy(zc.zc_name, zhp->zfs_name, sizeof (zc.zc_name));
|
||||
(void) strlcpy(zc.zc_name, zhp->zfs_name, sizeof (zc.zc_name));
|
||||
|
||||
err = userquota_propname_decode(propname,
|
||||
zfs_prop_get_int(zhp, ZFS_PROP_ZONED),
|
||||
@ -2437,6 +2607,79 @@ zfs_prop_get_userquota(zfs_handle_t *zhp, const char *propname,
|
||||
return (0);
|
||||
}
|
||||
|
||||
int
|
||||
zfs_prop_get_written_int(zfs_handle_t *zhp, const char *propname,
|
||||
uint64_t *propvalue)
|
||||
{
|
||||
int err;
|
||||
zfs_cmd_t zc = { 0 };
|
||||
const char *snapname;
|
||||
|
||||
(void) strlcpy(zc.zc_name, zhp->zfs_name, sizeof (zc.zc_name));
|
||||
|
||||
snapname = strchr(propname, '@') + 1;
|
||||
if (strchr(snapname, '@')) {
|
||||
(void) strlcpy(zc.zc_value, snapname, sizeof (zc.zc_value));
|
||||
} else {
|
||||
/* snapname is the short name, append it to zhp's fsname */
|
||||
char *cp;
|
||||
|
||||
(void) strlcpy(zc.zc_value, zhp->zfs_name,
|
||||
sizeof (zc.zc_value));
|
||||
cp = strchr(zc.zc_value, '@');
|
||||
if (cp != NULL)
|
||||
*cp = '\0';
|
||||
(void) strlcat(zc.zc_value, "@", sizeof (zc.zc_value));
|
||||
(void) strlcat(zc.zc_value, snapname, sizeof (zc.zc_value));
|
||||
}
|
||||
|
||||
err = ioctl(zhp->zfs_hdl->libzfs_fd, ZFS_IOC_SPACE_WRITTEN, &zc);
|
||||
if (err)
|
||||
return (err);
|
||||
|
||||
*propvalue = zc.zc_cookie;
|
||||
return (0);
|
||||
}
|
||||
|
||||
int
|
||||
zfs_prop_get_written(zfs_handle_t *zhp, const char *propname,
|
||||
char *propbuf, int proplen, boolean_t literal)
|
||||
{
|
||||
int err;
|
||||
uint64_t propvalue;
|
||||
|
||||
err = zfs_prop_get_written_int(zhp, propname, &propvalue);
|
||||
|
||||
if (err)
|
||||
return (err);
|
||||
|
||||
if (literal) {
|
||||
(void) snprintf(propbuf, proplen, "%llu", propvalue);
|
||||
} else {
|
||||
zfs_nicenum(propvalue, propbuf, proplen);
|
||||
}
|
||||
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.
|
||||
*/
|
||||
@ -2455,128 +2698,6 @@ zfs_get_type(const zfs_handle_t *zhp)
|
||||
return (zhp->zfs_type);
|
||||
}
|
||||
|
||||
static int
|
||||
zfs_do_list_ioctl(zfs_handle_t *zhp, unsigned long arg, zfs_cmd_t *zc)
|
||||
{
|
||||
int rc;
|
||||
uint64_t orig_cookie;
|
||||
|
||||
orig_cookie = zc->zc_cookie;
|
||||
top:
|
||||
(void) strlcpy(zc->zc_name, zhp->zfs_name, sizeof (zc->zc_name));
|
||||
rc = ioctl(zhp->zfs_hdl->libzfs_fd, arg, zc);
|
||||
|
||||
if (rc == -1) {
|
||||
switch (errno) {
|
||||
case ENOMEM:
|
||||
/* expand nvlist memory and try again */
|
||||
if (zcmd_expand_dst_nvlist(zhp->zfs_hdl, zc) != 0) {
|
||||
zcmd_free_nvlists(zc);
|
||||
return (-1);
|
||||
}
|
||||
zc->zc_cookie = orig_cookie;
|
||||
goto top;
|
||||
/*
|
||||
* An errno value of ESRCH indicates normal completion.
|
||||
* If ENOENT is returned, then the underlying dataset
|
||||
* has been removed since we obtained the handle.
|
||||
*/
|
||||
case ESRCH:
|
||||
case ENOENT:
|
||||
rc = 1;
|
||||
break;
|
||||
default:
|
||||
rc = zfs_standard_error(zhp->zfs_hdl, errno,
|
||||
dgettext(TEXT_DOMAIN,
|
||||
"cannot iterate filesystems"));
|
||||
break;
|
||||
}
|
||||
}
|
||||
return (rc);
|
||||
}
|
||||
|
||||
/*
|
||||
* Iterate over all child filesystems
|
||||
*/
|
||||
int
|
||||
zfs_iter_filesystems(zfs_handle_t *zhp, zfs_iter_f func, void *data)
|
||||
{
|
||||
zfs_cmd_t zc = { 0 };
|
||||
zfs_handle_t *nzhp;
|
||||
int ret;
|
||||
|
||||
if (zhp->zfs_type != ZFS_TYPE_FILESYSTEM)
|
||||
return (0);
|
||||
|
||||
if (zcmd_alloc_dst_nvlist(zhp->zfs_hdl, &zc, 0) != 0)
|
||||
return (-1);
|
||||
|
||||
while ((ret = zfs_do_list_ioctl(zhp, ZFS_IOC_DATASET_LIST_NEXT,
|
||||
&zc)) == 0) {
|
||||
/*
|
||||
* Silently ignore errors, as the only plausible explanation is
|
||||
* that the pool has since been removed.
|
||||
*/
|
||||
if ((nzhp = make_dataset_handle_zc(zhp->zfs_hdl,
|
||||
&zc)) == NULL) {
|
||||
continue;
|
||||
}
|
||||
|
||||
if ((ret = func(nzhp, data)) != 0) {
|
||||
zcmd_free_nvlists(&zc);
|
||||
return (ret);
|
||||
}
|
||||
}
|
||||
zcmd_free_nvlists(&zc);
|
||||
return ((ret < 0) ? ret : 0);
|
||||
}
|
||||
|
||||
/*
|
||||
* Iterate over all snapshots
|
||||
*/
|
||||
int
|
||||
zfs_iter_snapshots(zfs_handle_t *zhp, zfs_iter_f func, void *data)
|
||||
{
|
||||
zfs_cmd_t zc = { 0 };
|
||||
zfs_handle_t *nzhp;
|
||||
int ret;
|
||||
|
||||
if (zhp->zfs_type == ZFS_TYPE_SNAPSHOT)
|
||||
return (0);
|
||||
|
||||
if (zcmd_alloc_dst_nvlist(zhp->zfs_hdl, &zc, 0) != 0)
|
||||
return (-1);
|
||||
while ((ret = zfs_do_list_ioctl(zhp, ZFS_IOC_SNAPSHOT_LIST_NEXT,
|
||||
&zc)) == 0) {
|
||||
|
||||
if ((nzhp = make_dataset_handle_zc(zhp->zfs_hdl,
|
||||
&zc)) == NULL) {
|
||||
continue;
|
||||
}
|
||||
|
||||
if ((ret = func(nzhp, data)) != 0) {
|
||||
zcmd_free_nvlists(&zc);
|
||||
return (ret);
|
||||
}
|
||||
}
|
||||
zcmd_free_nvlists(&zc);
|
||||
return ((ret < 0) ? ret : 0);
|
||||
}
|
||||
|
||||
/*
|
||||
* Iterate over all children, snapshots and filesystems
|
||||
*/
|
||||
int
|
||||
zfs_iter_children(zfs_handle_t *zhp, zfs_iter_f func, void *data)
|
||||
{
|
||||
int ret;
|
||||
|
||||
if ((ret = zfs_iter_filesystems(zhp, func, data)) != 0)
|
||||
return (ret);
|
||||
|
||||
return (zfs_iter_snapshots(zhp, func, data));
|
||||
}
|
||||
|
||||
/*
|
||||
* Is one dataset name a child dataset of another?
|
||||
*
|
||||
@ -2600,18 +2721,19 @@ is_descendant(const char *ds1, const char *ds2)
|
||||
|
||||
/*
|
||||
* Given a complete name, return just the portion that refers to the parent.
|
||||
* Can return NULL if this is a pool.
|
||||
* Will return -1 if there is no parent (path is just the name of the
|
||||
* pool).
|
||||
*/
|
||||
static int
|
||||
parent_name(const char *path, char *buf, size_t buflen)
|
||||
{
|
||||
char *loc;
|
||||
char *slashp;
|
||||
|
||||
if ((loc = strrchr(path, '/')) == NULL)
|
||||
(void) strlcpy(buf, path, buflen);
|
||||
|
||||
if ((slashp = strrchr(buf, '/')) == NULL)
|
||||
return (-1);
|
||||
|
||||
(void) strncpy(buf, path, MIN(buflen, loc - path));
|
||||
buf[loc - path] = '\0';
|
||||
*slashp = '\0';
|
||||
|
||||
return (0);
|
||||
}
|
||||
@ -3010,9 +3132,8 @@ zfs_destroy(zfs_handle_t *zhp, boolean_t defer)
|
||||
}
|
||||
|
||||
struct destroydata {
|
||||
char *snapname;
|
||||
boolean_t gotone;
|
||||
boolean_t closezhp;
|
||||
nvlist_t *nvl;
|
||||
const char *snapname;
|
||||
};
|
||||
|
||||
static int
|
||||
@ -3021,24 +3142,19 @@ zfs_check_snap_cb(zfs_handle_t *zhp, void *arg)
|
||||
struct destroydata *dd = arg;
|
||||
zfs_handle_t *szhp;
|
||||
char name[ZFS_MAXNAMELEN];
|
||||
boolean_t closezhp = dd->closezhp;
|
||||
int rv = 0;
|
||||
|
||||
(void) strlcpy(name, zhp->zfs_name, sizeof (name));
|
||||
(void) strlcat(name, "@", sizeof (name));
|
||||
(void) strlcat(name, dd->snapname, sizeof (name));
|
||||
(void) snprintf(name, sizeof (name),
|
||||
"%s@%s", zhp->zfs_name, dd->snapname);
|
||||
|
||||
szhp = make_dataset_handle(zhp->zfs_hdl, name);
|
||||
if (szhp) {
|
||||
dd->gotone = B_TRUE;
|
||||
verify(nvlist_add_boolean(dd->nvl, name) == 0);
|
||||
zfs_close(szhp);
|
||||
}
|
||||
|
||||
dd->closezhp = B_TRUE;
|
||||
if (!dd->gotone)
|
||||
rv = zfs_iter_filesystems(zhp, zfs_check_snap_cb, arg);
|
||||
if (closezhp)
|
||||
zfs_close(zhp);
|
||||
rv = zfs_iter_filesystems(zhp, zfs_check_snap_cb, dd);
|
||||
zfs_close(zhp);
|
||||
return (rv);
|
||||
}
|
||||
|
||||
@ -3048,29 +3164,45 @@ zfs_check_snap_cb(zfs_handle_t *zhp, void *arg)
|
||||
int
|
||||
zfs_destroy_snaps(zfs_handle_t *zhp, char *snapname, boolean_t defer)
|
||||
{
|
||||
zfs_cmd_t zc = { 0 };
|
||||
int ret;
|
||||
struct destroydata dd = { 0 };
|
||||
|
||||
dd.snapname = snapname;
|
||||
(void) zfs_check_snap_cb(zhp, &dd);
|
||||
verify(nvlist_alloc(&dd.nvl, NV_UNIQUE_NAME, 0) == 0);
|
||||
(void) zfs_check_snap_cb(zfs_handle_dup(zhp), &dd);
|
||||
|
||||
if (!dd.gotone) {
|
||||
return (zfs_standard_error_fmt(zhp->zfs_hdl, ENOENT,
|
||||
if (nvlist_next_nvpair(dd.nvl, NULL) == NULL) {
|
||||
ret = zfs_standard_error_fmt(zhp->zfs_hdl, ENOENT,
|
||||
dgettext(TEXT_DOMAIN, "cannot destroy '%s@%s'"),
|
||||
zhp->zfs_name, snapname));
|
||||
zhp->zfs_name, snapname);
|
||||
} else {
|
||||
ret = zfs_destroy_snaps_nvl(zhp, dd.nvl, defer);
|
||||
}
|
||||
nvlist_free(dd.nvl);
|
||||
return (ret);
|
||||
}
|
||||
|
||||
/*
|
||||
* Destroys all the snapshots named in the nvlist. They must be underneath
|
||||
* the zhp (either snapshots of it, or snapshots of its descendants).
|
||||
*/
|
||||
int
|
||||
zfs_destroy_snaps_nvl(zfs_handle_t *zhp, nvlist_t *snaps, boolean_t defer)
|
||||
{
|
||||
int ret;
|
||||
zfs_cmd_t zc = { 0 };
|
||||
|
||||
(void) strlcpy(zc.zc_name, zhp->zfs_name, sizeof (zc.zc_name));
|
||||
(void) strlcpy(zc.zc_value, snapname, sizeof (zc.zc_value));
|
||||
if (zcmd_write_src_nvlist(zhp->zfs_hdl, &zc, snaps) != 0)
|
||||
return (-1);
|
||||
zc.zc_defer_destroy = defer;
|
||||
|
||||
ret = zfs_ioctl(zhp->zfs_hdl, ZFS_IOC_DESTROY_SNAPS, &zc);
|
||||
ret = zfs_ioctl(zhp->zfs_hdl, ZFS_IOC_DESTROY_SNAPS_NVL, &zc);
|
||||
if (ret != 0) {
|
||||
char errbuf[1024];
|
||||
|
||||
(void) snprintf(errbuf, sizeof (errbuf), dgettext(TEXT_DOMAIN,
|
||||
"cannot destroy '%s@%s'"), zc.zc_name, snapname);
|
||||
"cannot destroy snapshots in %s"), zc.zc_name);
|
||||
|
||||
switch (errno) {
|
||||
case EEXIST:
|
||||
@ -3106,7 +3238,7 @@ zfs_clone(zfs_handle_t *zhp, const char *target, nvlist_t *props)
|
||||
(void) snprintf(errbuf, sizeof (errbuf), dgettext(TEXT_DOMAIN,
|
||||
"cannot create '%s'"), target);
|
||||
|
||||
/* validate the target name */
|
||||
/* validate the target/clone name */
|
||||
if (!zfs_validate_name(hdl, target, ZFS_TYPE_FILESYSTEM, B_TRUE))
|
||||
return (zfs_error(hdl, EZFS_INVALIDNAME, errbuf));
|
||||
|
||||
@ -3442,42 +3574,6 @@ zfs_rollback(zfs_handle_t *zhp, zfs_handle_t *snap, boolean_t force)
|
||||
return (err);
|
||||
}
|
||||
|
||||
/*
|
||||
* Iterate over all dependents for a given dataset. This includes both
|
||||
* hierarchical dependents (children) and data dependents (snapshots and
|
||||
* clones). The bulk of the processing occurs in get_dependents() in
|
||||
* libzfs_graph.c.
|
||||
*/
|
||||
int
|
||||
zfs_iter_dependents(zfs_handle_t *zhp, boolean_t allowrecursion,
|
||||
zfs_iter_f func, void *data)
|
||||
{
|
||||
char **dependents;
|
||||
size_t count;
|
||||
int i;
|
||||
zfs_handle_t *child;
|
||||
int ret = 0;
|
||||
|
||||
if (get_dependents(zhp->zfs_hdl, allowrecursion, zhp->zfs_name,
|
||||
&dependents, &count) != 0)
|
||||
return (-1);
|
||||
|
||||
for (i = 0; i < count; i++) {
|
||||
if ((child = make_dataset_handle(zhp->zfs_hdl,
|
||||
dependents[i])) == NULL)
|
||||
continue;
|
||||
|
||||
if ((ret = func(child, data)) != 0)
|
||||
break;
|
||||
}
|
||||
|
||||
for (i = 0; i < count; i++)
|
||||
free(dependents[i]);
|
||||
free(dependents);
|
||||
|
||||
return (ret);
|
||||
}
|
||||
|
||||
/*
|
||||
* Renames the given dataset.
|
||||
*/
|
||||
@ -3947,7 +4043,7 @@ zfs_userspace(zfs_handle_t *zhp, zfs_userquota_prop_t type,
|
||||
int error;
|
||||
zfs_useracct_t buf[100];
|
||||
|
||||
(void) strncpy(zc.zc_name, zhp->zfs_name, sizeof (zc.zc_name));
|
||||
(void) strlcpy(zc.zc_name, zhp->zfs_name, sizeof (zc.zc_name));
|
||||
|
||||
zc.zc_objset_type = type;
|
||||
zc.zc_nvlist_dst = (uintptr_t)buf;
|
||||
|
@ -1,653 +0,0 @@
|
||||
/*
|
||||
* CDDL HEADER START
|
||||
*
|
||||
* The contents of this file are subject to the terms of the
|
||||
* Common Development and Distribution License (the "License").
|
||||
* You may not use this file except in compliance with the License.
|
||||
*
|
||||
* You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE
|
||||
* or http://www.opensolaris.org/os/licensing.
|
||||
* See the License for the specific language governing permissions
|
||||
* and limitations under the License.
|
||||
*
|
||||
* When distributing Covered Code, include this CDDL HEADER in each
|
||||
* file and include the License file at usr/src/OPENSOLARIS.LICENSE.
|
||||
* If applicable, add the following below this CDDL HEADER, with the
|
||||
* fields enclosed by brackets "[]" replaced with your own identifying
|
||||
* information: Portions Copyright [yyyy] [name of copyright owner]
|
||||
*
|
||||
* CDDL HEADER END
|
||||
*/
|
||||
/*
|
||||
* Copyright 2009 Sun Microsystems, Inc. All rights reserved.
|
||||
* Use is subject to license terms.
|
||||
*/
|
||||
|
||||
/*
|
||||
* Iterate over all children of the current object. This includes the normal
|
||||
* dataset hierarchy, but also arbitrary hierarchies due to clones. We want to
|
||||
* walk all datasets in the pool, and construct a directed graph of the form:
|
||||
*
|
||||
* home
|
||||
* |
|
||||
* +----+----+
|
||||
* | |
|
||||
* v v ws
|
||||
* bar baz |
|
||||
* | |
|
||||
* v v
|
||||
* @yesterday ----> foo
|
||||
*
|
||||
* In order to construct this graph, we have to walk every dataset in the pool,
|
||||
* because the clone parent is stored as a property of the child, not the
|
||||
* parent. The parent only keeps track of the number of clones.
|
||||
*
|
||||
* In the normal case (without clones) this would be rather expensive. To avoid
|
||||
* unnecessary computation, we first try a walk of the subtree hierarchy
|
||||
* starting from the initial node. At each dataset, we construct a node in the
|
||||
* graph and an edge leading from its parent. If we don't see any snapshots
|
||||
* with a non-zero clone count, then we are finished.
|
||||
*
|
||||
* If we do find a cloned snapshot, then we finish the walk of the current
|
||||
* subtree, but indicate that we need to do a complete walk. We then perform a
|
||||
* global walk of all datasets, avoiding the subtree we already processed.
|
||||
*
|
||||
* At the end of this, we'll end up with a directed graph of all relevant (and
|
||||
* possible some irrelevant) datasets in the system. We need to both find our
|
||||
* limiting subgraph and determine a safe ordering in which to destroy the
|
||||
* datasets. We do a topological ordering of our graph starting at our target
|
||||
* dataset, and then walk the results in reverse.
|
||||
*
|
||||
* It's possible for the graph to have cycles if, for example, the user renames
|
||||
* a clone to be the parent of its origin snapshot. The user can request to
|
||||
* generate an error in this case, or ignore the cycle and continue.
|
||||
*
|
||||
* When removing datasets, we want to destroy the snapshots in chronological
|
||||
* order (because this is the most efficient method). In order to accomplish
|
||||
* this, we store the creation transaction group with each vertex and keep each
|
||||
* vertex's edges sorted according to this value. The topological sort will
|
||||
* automatically walk the snapshots in the correct order.
|
||||
*/
|
||||
|
||||
#include <assert.h>
|
||||
#include <libintl.h>
|
||||
#include <stdio.h>
|
||||
#include <stdlib.h>
|
||||
#include <string.h>
|
||||
#include <strings.h>
|
||||
#include <unistd.h>
|
||||
|
||||
#include <libzfs.h>
|
||||
|
||||
#include "libzfs_impl.h"
|
||||
#include "zfs_namecheck.h"
|
||||
|
||||
#define MIN_EDGECOUNT 4
|
||||
|
||||
/*
|
||||
* Vertex structure. Indexed by dataset name, this structure maintains a list
|
||||
* of edges to other vertices.
|
||||
*/
|
||||
struct zfs_edge;
|
||||
typedef struct zfs_vertex {
|
||||
char zv_dataset[ZFS_MAXNAMELEN];
|
||||
struct zfs_vertex *zv_next;
|
||||
int zv_visited;
|
||||
uint64_t zv_txg;
|
||||
struct zfs_edge **zv_edges;
|
||||
int zv_edgecount;
|
||||
int zv_edgealloc;
|
||||
} zfs_vertex_t;
|
||||
|
||||
enum {
|
||||
VISIT_SEEN = 1,
|
||||
VISIT_SORT_PRE,
|
||||
VISIT_SORT_POST
|
||||
};
|
||||
|
||||
/*
|
||||
* Edge structure. Simply maintains a pointer to the destination vertex. There
|
||||
* is no need to store the source vertex, since we only use edges in the context
|
||||
* of the source vertex.
|
||||
*/
|
||||
typedef struct zfs_edge {
|
||||
zfs_vertex_t *ze_dest;
|
||||
struct zfs_edge *ze_next;
|
||||
} zfs_edge_t;
|
||||
|
||||
#define ZFS_GRAPH_SIZE 1027 /* this could be dynamic some day */
|
||||
|
||||
/*
|
||||
* Graph structure. Vertices are maintained in a hash indexed by dataset name.
|
||||
*/
|
||||
typedef struct zfs_graph {
|
||||
zfs_vertex_t **zg_hash;
|
||||
size_t zg_size;
|
||||
size_t zg_nvertex;
|
||||
const char *zg_root;
|
||||
int zg_clone_count;
|
||||
} zfs_graph_t;
|
||||
|
||||
/*
|
||||
* Allocate a new edge pointing to the target vertex.
|
||||
*/
|
||||
static zfs_edge_t *
|
||||
zfs_edge_create(libzfs_handle_t *hdl, zfs_vertex_t *dest)
|
||||
{
|
||||
zfs_edge_t *zep = zfs_alloc(hdl, sizeof (zfs_edge_t));
|
||||
|
||||
if (zep == NULL)
|
||||
return (NULL);
|
||||
|
||||
zep->ze_dest = dest;
|
||||
|
||||
return (zep);
|
||||
}
|
||||
|
||||
/*
|
||||
* Destroy an edge.
|
||||
*/
|
||||
static void
|
||||
zfs_edge_destroy(zfs_edge_t *zep)
|
||||
{
|
||||
free(zep);
|
||||
}
|
||||
|
||||
/*
|
||||
* Allocate a new vertex with the given name.
|
||||
*/
|
||||
static zfs_vertex_t *
|
||||
zfs_vertex_create(libzfs_handle_t *hdl, const char *dataset)
|
||||
{
|
||||
zfs_vertex_t *zvp = zfs_alloc(hdl, sizeof (zfs_vertex_t));
|
||||
|
||||
if (zvp == NULL)
|
||||
return (NULL);
|
||||
|
||||
assert(strlen(dataset) < ZFS_MAXNAMELEN);
|
||||
|
||||
(void) strlcpy(zvp->zv_dataset, dataset, sizeof (zvp->zv_dataset));
|
||||
|
||||
if ((zvp->zv_edges = zfs_alloc(hdl,
|
||||
MIN_EDGECOUNT * sizeof (void *))) == NULL) {
|
||||
free(zvp);
|
||||
return (NULL);
|
||||
}
|
||||
|
||||
zvp->zv_edgealloc = MIN_EDGECOUNT;
|
||||
|
||||
return (zvp);
|
||||
}
|
||||
|
||||
/*
|
||||
* Destroy a vertex. Frees up any associated edges.
|
||||
*/
|
||||
static void
|
||||
zfs_vertex_destroy(zfs_vertex_t *zvp)
|
||||
{
|
||||
int i;
|
||||
|
||||
for (i = 0; i < zvp->zv_edgecount; i++)
|
||||
zfs_edge_destroy(zvp->zv_edges[i]);
|
||||
|
||||
free(zvp->zv_edges);
|
||||
free(zvp);
|
||||
}
|
||||
|
||||
/*
|
||||
* Given a vertex, add an edge to the destination vertex.
|
||||
*/
|
||||
static int
|
||||
zfs_vertex_add_edge(libzfs_handle_t *hdl, zfs_vertex_t *zvp,
|
||||
zfs_vertex_t *dest)
|
||||
{
|
||||
zfs_edge_t *zep = zfs_edge_create(hdl, dest);
|
||||
|
||||
if (zep == NULL)
|
||||
return (-1);
|
||||
|
||||
if (zvp->zv_edgecount == zvp->zv_edgealloc) {
|
||||
void *ptr;
|
||||
|
||||
if ((ptr = zfs_realloc(hdl, zvp->zv_edges,
|
||||
zvp->zv_edgealloc * sizeof (void *),
|
||||
zvp->zv_edgealloc * 2 * sizeof (void *))) == NULL)
|
||||
return (-1);
|
||||
|
||||
zvp->zv_edges = ptr;
|
||||
zvp->zv_edgealloc *= 2;
|
||||
}
|
||||
|
||||
zvp->zv_edges[zvp->zv_edgecount++] = zep;
|
||||
|
||||
return (0);
|
||||
}
|
||||
|
||||
static int
|
||||
zfs_edge_compare(const void *a, const void *b)
|
||||
{
|
||||
const zfs_edge_t *ea = *((zfs_edge_t **)a);
|
||||
const zfs_edge_t *eb = *((zfs_edge_t **)b);
|
||||
|
||||
if (ea->ze_dest->zv_txg < eb->ze_dest->zv_txg)
|
||||
return (-1);
|
||||
if (ea->ze_dest->zv_txg > eb->ze_dest->zv_txg)
|
||||
return (1);
|
||||
return (0);
|
||||
}
|
||||
|
||||
/*
|
||||
* Sort the given vertex edges according to the creation txg of each vertex.
|
||||
*/
|
||||
static void
|
||||
zfs_vertex_sort_edges(zfs_vertex_t *zvp)
|
||||
{
|
||||
if (zvp->zv_edgecount == 0)
|
||||
return;
|
||||
|
||||
qsort(zvp->zv_edges, zvp->zv_edgecount, sizeof (void *),
|
||||
zfs_edge_compare);
|
||||
}
|
||||
|
||||
/*
|
||||
* Construct a new graph object. We allow the size to be specified as a
|
||||
* parameter so in the future we can size the hash according to the number of
|
||||
* datasets in the pool.
|
||||
*/
|
||||
static zfs_graph_t *
|
||||
zfs_graph_create(libzfs_handle_t *hdl, const char *dataset, size_t size)
|
||||
{
|
||||
zfs_graph_t *zgp = zfs_alloc(hdl, sizeof (zfs_graph_t));
|
||||
|
||||
if (zgp == NULL)
|
||||
return (NULL);
|
||||
|
||||
zgp->zg_size = size;
|
||||
if ((zgp->zg_hash = zfs_alloc(hdl,
|
||||
size * sizeof (zfs_vertex_t *))) == NULL) {
|
||||
free(zgp);
|
||||
return (NULL);
|
||||
}
|
||||
|
||||
zgp->zg_root = dataset;
|
||||
zgp->zg_clone_count = 0;
|
||||
|
||||
return (zgp);
|
||||
}
|
||||
|
||||
/*
|
||||
* Destroy a graph object. We have to iterate over all the hash chains,
|
||||
* destroying each vertex in the process.
|
||||
*/
|
||||
static void
|
||||
zfs_graph_destroy(zfs_graph_t *zgp)
|
||||
{
|
||||
int i;
|
||||
zfs_vertex_t *current, *next;
|
||||
|
||||
for (i = 0; i < zgp->zg_size; i++) {
|
||||
current = zgp->zg_hash[i];
|
||||
while (current != NULL) {
|
||||
next = current->zv_next;
|
||||
zfs_vertex_destroy(current);
|
||||
current = next;
|
||||
}
|
||||
}
|
||||
|
||||
free(zgp->zg_hash);
|
||||
free(zgp);
|
||||
}
|
||||
|
||||
/*
|
||||
* Graph hash function. Classic bernstein k=33 hash function, taken from
|
||||
* usr/src/cmd/sgs/tools/common/strhash.c
|
||||
*/
|
||||
static size_t
|
||||
zfs_graph_hash(zfs_graph_t *zgp, const char *str)
|
||||
{
|
||||
size_t hash = 5381;
|
||||
int c;
|
||||
|
||||
while ((c = *str++) != 0)
|
||||
hash = ((hash << 5) + hash) + c; /* hash * 33 + c */
|
||||
|
||||
return (hash % zgp->zg_size);
|
||||
}
|
||||
|
||||
/*
|
||||
* Given a dataset name, finds the associated vertex, creating it if necessary.
|
||||
*/
|
||||
static zfs_vertex_t *
|
||||
zfs_graph_lookup(libzfs_handle_t *hdl, zfs_graph_t *zgp, const char *dataset,
|
||||
uint64_t txg)
|
||||
{
|
||||
size_t idx = zfs_graph_hash(zgp, dataset);
|
||||
zfs_vertex_t *zvp;
|
||||
|
||||
for (zvp = zgp->zg_hash[idx]; zvp != NULL; zvp = zvp->zv_next) {
|
||||
if (strcmp(zvp->zv_dataset, dataset) == 0) {
|
||||
if (zvp->zv_txg == 0)
|
||||
zvp->zv_txg = txg;
|
||||
return (zvp);
|
||||
}
|
||||
}
|
||||
|
||||
if ((zvp = zfs_vertex_create(hdl, dataset)) == NULL)
|
||||
return (NULL);
|
||||
|
||||
zvp->zv_next = zgp->zg_hash[idx];
|
||||
zvp->zv_txg = txg;
|
||||
zgp->zg_hash[idx] = zvp;
|
||||
zgp->zg_nvertex++;
|
||||
|
||||
return (zvp);
|
||||
}
|
||||
|
||||
/*
|
||||
* Given two dataset names, create an edge between them. For the source vertex,
|
||||
* mark 'zv_visited' to indicate that we have seen this vertex, and not simply
|
||||
* created it as a destination of another edge. If 'dest' is NULL, then this
|
||||
* is an individual vertex (i.e. the starting vertex), so don't add an edge.
|
||||
*/
|
||||
static int
|
||||
zfs_graph_add(libzfs_handle_t *hdl, zfs_graph_t *zgp, const char *source,
|
||||
const char *dest, uint64_t txg)
|
||||
{
|
||||
zfs_vertex_t *svp, *dvp;
|
||||
|
||||
if ((svp = zfs_graph_lookup(hdl, zgp, source, 0)) == NULL)
|
||||
return (-1);
|
||||
svp->zv_visited = VISIT_SEEN;
|
||||
if (dest != NULL) {
|
||||
dvp = zfs_graph_lookup(hdl, zgp, dest, txg);
|
||||
if (dvp == NULL)
|
||||
return (-1);
|
||||
if (zfs_vertex_add_edge(hdl, svp, dvp) != 0)
|
||||
return (-1);
|
||||
}
|
||||
|
||||
return (0);
|
||||
}
|
||||
|
||||
/*
|
||||
* Iterate over all children of the given dataset, adding any vertices
|
||||
* as necessary. Returns -1 if there was an error, or 0 otherwise.
|
||||
* This is a simple recursive algorithm - the ZFS namespace typically
|
||||
* is very flat. We manually invoke the necessary ioctl() calls to
|
||||
* avoid the overhead and additional semantics of zfs_open().
|
||||
*/
|
||||
static int
|
||||
iterate_children(libzfs_handle_t *hdl, zfs_graph_t *zgp, const char *dataset)
|
||||
{
|
||||
zfs_cmd_t zc = { 0 };
|
||||
zfs_vertex_t *zvp;
|
||||
|
||||
/*
|
||||
* Look up the source vertex, and avoid it if we've seen it before.
|
||||
*/
|
||||
zvp = zfs_graph_lookup(hdl, zgp, dataset, 0);
|
||||
if (zvp == NULL)
|
||||
return (-1);
|
||||
if (zvp->zv_visited == VISIT_SEEN)
|
||||
return (0);
|
||||
|
||||
/*
|
||||
* Iterate over all children
|
||||
*/
|
||||
for ((void) strlcpy(zc.zc_name, dataset, sizeof (zc.zc_name));
|
||||
ioctl(hdl->libzfs_fd, ZFS_IOC_DATASET_LIST_NEXT, &zc) == 0;
|
||||
(void) strlcpy(zc.zc_name, dataset, sizeof (zc.zc_name))) {
|
||||
/*
|
||||
* Get statistics for this dataset, to determine the type of the
|
||||
* dataset and clone statistics. If this fails, the dataset has
|
||||
* since been removed, and we're pretty much screwed anyway.
|
||||
*/
|
||||
zc.zc_objset_stats.dds_origin[0] = '\0';
|
||||
if (ioctl(hdl->libzfs_fd, ZFS_IOC_OBJSET_STATS, &zc) != 0)
|
||||
continue;
|
||||
|
||||
if (zc.zc_objset_stats.dds_origin[0] != '\0') {
|
||||
if (zfs_graph_add(hdl, zgp,
|
||||
zc.zc_objset_stats.dds_origin, zc.zc_name,
|
||||
zc.zc_objset_stats.dds_creation_txg) != 0)
|
||||
return (-1);
|
||||
/*
|
||||
* Count origins only if they are contained in the graph
|
||||
*/
|
||||
if (isa_child_of(zc.zc_objset_stats.dds_origin,
|
||||
zgp->zg_root))
|
||||
zgp->zg_clone_count--;
|
||||
}
|
||||
|
||||
/*
|
||||
* Add an edge between the parent and the child.
|
||||
*/
|
||||
if (zfs_graph_add(hdl, zgp, dataset, zc.zc_name,
|
||||
zc.zc_objset_stats.dds_creation_txg) != 0)
|
||||
return (-1);
|
||||
|
||||
/*
|
||||
* Recursively visit child
|
||||
*/
|
||||
if (iterate_children(hdl, zgp, zc.zc_name))
|
||||
return (-1);
|
||||
}
|
||||
|
||||
/*
|
||||
* Now iterate over all snapshots.
|
||||
*/
|
||||
bzero(&zc, sizeof (zc));
|
||||
|
||||
for ((void) strlcpy(zc.zc_name, dataset, sizeof (zc.zc_name));
|
||||
ioctl(hdl->libzfs_fd, ZFS_IOC_SNAPSHOT_LIST_NEXT, &zc) == 0;
|
||||
(void) strlcpy(zc.zc_name, dataset, sizeof (zc.zc_name))) {
|
||||
|
||||
/*
|
||||
* Get statistics for this dataset, to determine the type of the
|
||||
* dataset and clone statistics. If this fails, the dataset has
|
||||
* since been removed, and we're pretty much screwed anyway.
|
||||
*/
|
||||
if (ioctl(hdl->libzfs_fd, ZFS_IOC_OBJSET_STATS, &zc) != 0)
|
||||
continue;
|
||||
|
||||
/*
|
||||
* Add an edge between the parent and the child.
|
||||
*/
|
||||
if (zfs_graph_add(hdl, zgp, dataset, zc.zc_name,
|
||||
zc.zc_objset_stats.dds_creation_txg) != 0)
|
||||
return (-1);
|
||||
|
||||
zgp->zg_clone_count += zc.zc_objset_stats.dds_num_clones;
|
||||
}
|
||||
|
||||
zvp->zv_visited = VISIT_SEEN;
|
||||
|
||||
return (0);
|
||||
}
|
||||
|
||||
/*
|
||||
* Returns false if there are no snapshots with dependent clones in this
|
||||
* subtree or if all of those clones are also in this subtree. Returns
|
||||
* true if there is an error or there are external dependents.
|
||||
*/
|
||||
static boolean_t
|
||||
external_dependents(libzfs_handle_t *hdl, zfs_graph_t *zgp, const char *dataset)
|
||||
{
|
||||
zfs_cmd_t zc = { 0 };
|
||||
|
||||
/*
|
||||
* Check whether this dataset is a clone or has clones since
|
||||
* iterate_children() only checks the children.
|
||||
*/
|
||||
(void) strlcpy(zc.zc_name, dataset, sizeof (zc.zc_name));
|
||||
if (ioctl(hdl->libzfs_fd, ZFS_IOC_OBJSET_STATS, &zc) != 0)
|
||||
return (B_TRUE);
|
||||
|
||||
if (zc.zc_objset_stats.dds_origin[0] != '\0') {
|
||||
if (zfs_graph_add(hdl, zgp,
|
||||
zc.zc_objset_stats.dds_origin, zc.zc_name,
|
||||
zc.zc_objset_stats.dds_creation_txg) != 0)
|
||||
return (B_TRUE);
|
||||
if (isa_child_of(zc.zc_objset_stats.dds_origin, dataset))
|
||||
zgp->zg_clone_count--;
|
||||
}
|
||||
|
||||
if ((zc.zc_objset_stats.dds_num_clones) ||
|
||||
iterate_children(hdl, zgp, dataset))
|
||||
return (B_TRUE);
|
||||
|
||||
return (zgp->zg_clone_count != 0);
|
||||
}
|
||||
|
||||
/*
|
||||
* Construct a complete graph of all necessary vertices. First, iterate over
|
||||
* only our object's children. If no cloned snapshots are found, or all of
|
||||
* the cloned snapshots are in this subtree then return a graph of the subtree.
|
||||
* Otherwise, start at the root of the pool and iterate over all datasets.
|
||||
*/
|
||||
static zfs_graph_t *
|
||||
construct_graph(libzfs_handle_t *hdl, const char *dataset)
|
||||
{
|
||||
zfs_graph_t *zgp = zfs_graph_create(hdl, dataset, ZFS_GRAPH_SIZE);
|
||||
int ret = 0;
|
||||
|
||||
if (zgp == NULL)
|
||||
return (zgp);
|
||||
|
||||
if ((strchr(dataset, '/') == NULL) ||
|
||||
(external_dependents(hdl, zgp, dataset))) {
|
||||
/*
|
||||
* Determine pool name and try again.
|
||||
*/
|
||||
int len = strcspn(dataset, "/@") + 1;
|
||||
char *pool = zfs_alloc(hdl, len);
|
||||
|
||||
if (pool == NULL) {
|
||||
zfs_graph_destroy(zgp);
|
||||
return (NULL);
|
||||
}
|
||||
(void) strlcpy(pool, dataset, len);
|
||||
|
||||
if (iterate_children(hdl, zgp, pool) == -1 ||
|
||||
zfs_graph_add(hdl, zgp, pool, NULL, 0) != 0) {
|
||||
free(pool);
|
||||
zfs_graph_destroy(zgp);
|
||||
return (NULL);
|
||||
}
|
||||
free(pool);
|
||||
}
|
||||
|
||||
if (ret == -1 || zfs_graph_add(hdl, zgp, dataset, NULL, 0) != 0) {
|
||||
zfs_graph_destroy(zgp);
|
||||
return (NULL);
|
||||
}
|
||||
|
||||
return (zgp);
|
||||
}
|
||||
|
||||
/*
|
||||
* Given a graph, do a recursive topological sort into the given array. This is
|
||||
* really just a depth first search, so that the deepest nodes appear first.
|
||||
* hijack the 'zv_visited' marker to avoid visiting the same vertex twice.
|
||||
*/
|
||||
static int
|
||||
topo_sort(libzfs_handle_t *hdl, boolean_t allowrecursion, char **result,
|
||||
size_t *idx, zfs_vertex_t *zgv)
|
||||
{
|
||||
int i;
|
||||
|
||||
if (zgv->zv_visited == VISIT_SORT_PRE && !allowrecursion) {
|
||||
/*
|
||||
* If we've already seen this vertex as part of our depth-first
|
||||
* search, then we have a cyclic dependency, and we must return
|
||||
* an error.
|
||||
*/
|
||||
zfs_error_aux(hdl, dgettext(TEXT_DOMAIN,
|
||||
"recursive dependency at '%s'"),
|
||||
zgv->zv_dataset);
|
||||
return (zfs_error(hdl, EZFS_RECURSIVE,
|
||||
dgettext(TEXT_DOMAIN,
|
||||
"cannot determine dependent datasets")));
|
||||
} else if (zgv->zv_visited >= VISIT_SORT_PRE) {
|
||||
/*
|
||||
* If we've already processed this as part of the topological
|
||||
* sort, then don't bother doing so again.
|
||||
*/
|
||||
return (0);
|
||||
}
|
||||
|
||||
zgv->zv_visited = VISIT_SORT_PRE;
|
||||
|
||||
/* avoid doing a search if we don't have to */
|
||||
zfs_vertex_sort_edges(zgv);
|
||||
for (i = 0; i < zgv->zv_edgecount; i++) {
|
||||
if (topo_sort(hdl, allowrecursion, result, idx,
|
||||
zgv->zv_edges[i]->ze_dest) != 0)
|
||||
return (-1);
|
||||
}
|
||||
|
||||
/* we may have visited this in the course of the above */
|
||||
if (zgv->zv_visited == VISIT_SORT_POST)
|
||||
return (0);
|
||||
|
||||
if ((result[*idx] = zfs_alloc(hdl,
|
||||
strlen(zgv->zv_dataset) + 1)) == NULL)
|
||||
return (-1);
|
||||
|
||||
(void) strcpy(result[*idx], zgv->zv_dataset);
|
||||
*idx += 1;
|
||||
zgv->zv_visited = VISIT_SORT_POST;
|
||||
return (0);
|
||||
}
|
||||
|
||||
/*
|
||||
* The only public interface for this file. Do the dirty work of constructing a
|
||||
* child list for the given object. Construct the graph, do the toplogical
|
||||
* sort, and then return the array of strings to the caller.
|
||||
*
|
||||
* The 'allowrecursion' parameter controls behavior when cycles are found. If
|
||||
* it is set, the the cycle is ignored and the results returned as if the cycle
|
||||
* did not exist. If it is not set, then the routine will generate an error if
|
||||
* a cycle is found.
|
||||
*/
|
||||
int
|
||||
get_dependents(libzfs_handle_t *hdl, boolean_t allowrecursion,
|
||||
const char *dataset, char ***result, size_t *count)
|
||||
{
|
||||
zfs_graph_t *zgp;
|
||||
zfs_vertex_t *zvp;
|
||||
|
||||
if ((zgp = construct_graph(hdl, dataset)) == NULL)
|
||||
return (-1);
|
||||
|
||||
if ((*result = zfs_alloc(hdl,
|
||||
zgp->zg_nvertex * sizeof (char *))) == NULL) {
|
||||
zfs_graph_destroy(zgp);
|
||||
return (-1);
|
||||
}
|
||||
|
||||
if ((zvp = zfs_graph_lookup(hdl, zgp, dataset, 0)) == NULL) {
|
||||
free(*result);
|
||||
zfs_graph_destroy(zgp);
|
||||
return (-1);
|
||||
}
|
||||
|
||||
*count = 0;
|
||||
if (topo_sort(hdl, allowrecursion, *result, count, zvp) != 0) {
|
||||
free(*result);
|
||||
zfs_graph_destroy(zgp);
|
||||
return (-1);
|
||||
}
|
||||
|
||||
/*
|
||||
* Get rid of the last entry, which is our starting vertex and not
|
||||
* strictly a dependent.
|
||||
*/
|
||||
assert(*count > 0);
|
||||
free((*result)[*count - 1]);
|
||||
(*count)--;
|
||||
|
||||
zfs_graph_destroy(zgp);
|
||||
|
||||
return (0);
|
||||
}
|
@ -23,6 +23,7 @@
|
||||
* 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.
|
||||
*/
|
||||
|
||||
#ifndef _LIBFS_IMPL_H
|
||||
@ -116,7 +117,7 @@ struct zpool_handle {
|
||||
diskaddr_t zpool_start_block;
|
||||
};
|
||||
|
||||
typedef enum {
|
||||
typedef enum {
|
||||
PROTO_NFS = 0,
|
||||
PROTO_SMB = 1,
|
||||
PROTO_END = 2
|
||||
@ -148,6 +149,7 @@ int zpool_standard_error_fmt(libzfs_handle_t *, int, const char *, ...);
|
||||
|
||||
int get_dependents(libzfs_handle_t *, boolean_t, const char *, char ***,
|
||||
size_t *);
|
||||
zfs_handle_t *make_dataset_handle_zc(libzfs_handle_t *, zfs_cmd_t *);
|
||||
|
||||
|
||||
int zprop_parse_value(libzfs_handle_t *, nvpair_t *, int, zfs_type_t,
|
||||
|
@ -20,6 +20,8 @@
|
||||
*/
|
||||
/*
|
||||
* Copyright (c) 2005, 2010, Oracle and/or its affiliates. All rights reserved.
|
||||
* Copyright 2011 Nexenta Systems, Inc. All rights reserved.
|
||||
* Copyright (c) 2011 by Delphix. All rights reserved.
|
||||
*/
|
||||
|
||||
/*
|
||||
@ -435,7 +437,7 @@ get_configs(libzfs_handle_t *hdl, pool_list_t *pl, boolean_t active_ok)
|
||||
uint_t i, nspares, nl2cache;
|
||||
boolean_t config_seen;
|
||||
uint64_t best_txg;
|
||||
char *name, *hostname;
|
||||
char *name, *hostname, *comment;
|
||||
uint64_t version, guid;
|
||||
uint_t children = 0;
|
||||
nvlist_t **child = NULL;
|
||||
@ -524,6 +526,7 @@ get_configs(libzfs_handle_t *hdl, pool_list_t *pl, boolean_t active_ok)
|
||||
* version
|
||||
* pool guid
|
||||
* name
|
||||
* comment (if available)
|
||||
* pool state
|
||||
* hostid (if available)
|
||||
* hostname (if available)
|
||||
@ -545,11 +548,24 @@ get_configs(libzfs_handle_t *hdl, pool_list_t *pl, boolean_t active_ok)
|
||||
if (nvlist_add_string(config,
|
||||
ZPOOL_CONFIG_POOL_NAME, name) != 0)
|
||||
goto nomem;
|
||||
|
||||
/*
|
||||
* COMMENT is optional, don't bail if it's not
|
||||
* there, instead, set it to NULL.
|
||||
*/
|
||||
if (nvlist_lookup_string(tmp,
|
||||
ZPOOL_CONFIG_COMMENT, &comment) != 0)
|
||||
comment = NULL;
|
||||
else if (nvlist_add_string(config,
|
||||
ZPOOL_CONFIG_COMMENT, comment) != 0)
|
||||
goto nomem;
|
||||
|
||||
verify(nvlist_lookup_uint64(tmp,
|
||||
ZPOOL_CONFIG_POOL_STATE, &state) == 0);
|
||||
if (nvlist_add_uint64(config,
|
||||
ZPOOL_CONFIG_POOL_STATE, state) != 0)
|
||||
goto nomem;
|
||||
|
||||
hostid = 0;
|
||||
if (nvlist_lookup_uint64(tmp,
|
||||
ZPOOL_CONFIG_HOSTID, &hostid) == 0) {
|
||||
|
462
cddl/contrib/opensolaris/lib/libzfs/common/libzfs_iter.c
Normal file
462
cddl/contrib/opensolaris/lib/libzfs/common/libzfs_iter.c
Normal file
@ -0,0 +1,462 @@
|
||||
/*
|
||||
* CDDL HEADER START
|
||||
*
|
||||
* The contents of this file are subject to the terms of the
|
||||
* Common Development and Distribution License (the "License").
|
||||
* You may not use this file except in compliance with the License.
|
||||
*
|
||||
* You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE
|
||||
* or http://www.opensolaris.org/os/licensing.
|
||||
* See the License for the specific language governing permissions
|
||||
* and limitations under the License.
|
||||
*
|
||||
* When distributing Covered Code, include this CDDL HEADER in each
|
||||
* file and include the License file at usr/src/OPENSOLARIS.LICENSE.
|
||||
* If applicable, add the following below this CDDL HEADER, with the
|
||||
* fields enclosed by brackets "[]" replaced with your own identifying
|
||||
* information: Portions Copyright [yyyy] [name of copyright owner]
|
||||
*
|
||||
* CDDL HEADER END
|
||||
*/
|
||||
|
||||
/*
|
||||
* Copyright (c) 2005, 2010, Oracle and/or its affiliates. All rights reserved.
|
||||
* Copyright 2010 Nexenta Systems, Inc. All rights reserved.
|
||||
* Copyright (c) 2011 by Delphix. All rights reserved.
|
||||
*/
|
||||
|
||||
#include <stdio.h>
|
||||
#include <stdlib.h>
|
||||
#include <strings.h>
|
||||
#include <unistd.h>
|
||||
#include <stddef.h>
|
||||
#include <libintl.h>
|
||||
#include <libzfs.h>
|
||||
|
||||
#include "libzfs_impl.h"
|
||||
|
||||
int
|
||||
zfs_iter_clones(zfs_handle_t *zhp, zfs_iter_f func, void *data)
|
||||
{
|
||||
nvlist_t *nvl = zfs_get_clones_nvl(zhp);
|
||||
nvpair_t *pair;
|
||||
|
||||
if (nvl == NULL)
|
||||
return (0);
|
||||
|
||||
for (pair = nvlist_next_nvpair(nvl, NULL); pair != NULL;
|
||||
pair = nvlist_next_nvpair(nvl, pair)) {
|
||||
zfs_handle_t *clone = zfs_open(zhp->zfs_hdl, nvpair_name(pair),
|
||||
ZFS_TYPE_FILESYSTEM | ZFS_TYPE_VOLUME);
|
||||
if (clone != NULL) {
|
||||
int err = func(clone, data);
|
||||
if (err != 0)
|
||||
return (err);
|
||||
}
|
||||
}
|
||||
return (0);
|
||||
}
|
||||
|
||||
static int
|
||||
zfs_do_list_ioctl(zfs_handle_t *zhp, unsigned long arg, zfs_cmd_t *zc)
|
||||
{
|
||||
int rc;
|
||||
uint64_t orig_cookie;
|
||||
|
||||
orig_cookie = zc->zc_cookie;
|
||||
top:
|
||||
(void) strlcpy(zc->zc_name, zhp->zfs_name, sizeof (zc->zc_name));
|
||||
rc = ioctl(zhp->zfs_hdl->libzfs_fd, arg, zc);
|
||||
|
||||
if (rc == -1) {
|
||||
switch (errno) {
|
||||
case ENOMEM:
|
||||
/* expand nvlist memory and try again */
|
||||
if (zcmd_expand_dst_nvlist(zhp->zfs_hdl, zc) != 0) {
|
||||
zcmd_free_nvlists(zc);
|
||||
return (-1);
|
||||
}
|
||||
zc->zc_cookie = orig_cookie;
|
||||
goto top;
|
||||
/*
|
||||
* An errno value of ESRCH indicates normal completion.
|
||||
* If ENOENT is returned, then the underlying dataset
|
||||
* has been removed since we obtained the handle.
|
||||
*/
|
||||
case ESRCH:
|
||||
case ENOENT:
|
||||
rc = 1;
|
||||
break;
|
||||
default:
|
||||
rc = zfs_standard_error(zhp->zfs_hdl, errno,
|
||||
dgettext(TEXT_DOMAIN,
|
||||
"cannot iterate filesystems"));
|
||||
break;
|
||||
}
|
||||
}
|
||||
return (rc);
|
||||
}
|
||||
|
||||
/*
|
||||
* Iterate over all child filesystems
|
||||
*/
|
||||
int
|
||||
zfs_iter_filesystems(zfs_handle_t *zhp, zfs_iter_f func, void *data)
|
||||
{
|
||||
zfs_cmd_t zc = { 0 };
|
||||
zfs_handle_t *nzhp;
|
||||
int ret;
|
||||
|
||||
if (zhp->zfs_type != ZFS_TYPE_FILESYSTEM)
|
||||
return (0);
|
||||
|
||||
if (zcmd_alloc_dst_nvlist(zhp->zfs_hdl, &zc, 0) != 0)
|
||||
return (-1);
|
||||
|
||||
while ((ret = zfs_do_list_ioctl(zhp, ZFS_IOC_DATASET_LIST_NEXT,
|
||||
&zc)) == 0) {
|
||||
/*
|
||||
* Silently ignore errors, as the only plausible explanation is
|
||||
* that the pool has since been removed.
|
||||
*/
|
||||
if ((nzhp = make_dataset_handle_zc(zhp->zfs_hdl,
|
||||
&zc)) == NULL) {
|
||||
continue;
|
||||
}
|
||||
|
||||
if ((ret = func(nzhp, data)) != 0) {
|
||||
zcmd_free_nvlists(&zc);
|
||||
return (ret);
|
||||
}
|
||||
}
|
||||
zcmd_free_nvlists(&zc);
|
||||
return ((ret < 0) ? ret : 0);
|
||||
}
|
||||
|
||||
/*
|
||||
* Iterate over all snapshots
|
||||
*/
|
||||
int
|
||||
zfs_iter_snapshots(zfs_handle_t *zhp, zfs_iter_f func, void *data)
|
||||
{
|
||||
zfs_cmd_t zc = { 0 };
|
||||
zfs_handle_t *nzhp;
|
||||
int ret;
|
||||
|
||||
if (zhp->zfs_type == ZFS_TYPE_SNAPSHOT)
|
||||
return (0);
|
||||
|
||||
if (zcmd_alloc_dst_nvlist(zhp->zfs_hdl, &zc, 0) != 0)
|
||||
return (-1);
|
||||
while ((ret = zfs_do_list_ioctl(zhp, ZFS_IOC_SNAPSHOT_LIST_NEXT,
|
||||
&zc)) == 0) {
|
||||
|
||||
if ((nzhp = make_dataset_handle_zc(zhp->zfs_hdl,
|
||||
&zc)) == NULL) {
|
||||
continue;
|
||||
}
|
||||
|
||||
if ((ret = func(nzhp, data)) != 0) {
|
||||
zcmd_free_nvlists(&zc);
|
||||
return (ret);
|
||||
}
|
||||
}
|
||||
zcmd_free_nvlists(&zc);
|
||||
return ((ret < 0) ? ret : 0);
|
||||
}
|
||||
|
||||
/*
|
||||
* Routines for dealing with the sorted snapshot functionality
|
||||
*/
|
||||
typedef struct zfs_node {
|
||||
zfs_handle_t *zn_handle;
|
||||
avl_node_t zn_avlnode;
|
||||
} zfs_node_t;
|
||||
|
||||
static int
|
||||
zfs_sort_snaps(zfs_handle_t *zhp, void *data)
|
||||
{
|
||||
avl_tree_t *avl = data;
|
||||
zfs_node_t *node;
|
||||
zfs_node_t search;
|
||||
|
||||
search.zn_handle = zhp;
|
||||
node = avl_find(avl, &search, NULL);
|
||||
if (node) {
|
||||
/*
|
||||
* If this snapshot was renamed while we were creating the
|
||||
* AVL tree, it's possible that we already inserted it under
|
||||
* its old name. Remove the old handle before adding the new
|
||||
* one.
|
||||
*/
|
||||
zfs_close(node->zn_handle);
|
||||
avl_remove(avl, node);
|
||||
free(node);
|
||||
}
|
||||
|
||||
node = zfs_alloc(zhp->zfs_hdl, sizeof (zfs_node_t));
|
||||
node->zn_handle = zhp;
|
||||
avl_add(avl, node);
|
||||
|
||||
return (0);
|
||||
}
|
||||
|
||||
static int
|
||||
zfs_snapshot_compare(const void *larg, const void *rarg)
|
||||
{
|
||||
zfs_handle_t *l = ((zfs_node_t *)larg)->zn_handle;
|
||||
zfs_handle_t *r = ((zfs_node_t *)rarg)->zn_handle;
|
||||
uint64_t lcreate, rcreate;
|
||||
|
||||
/*
|
||||
* Sort them according to creation time. We use the hidden
|
||||
* CREATETXG property to get an absolute ordering of snapshots.
|
||||
*/
|
||||
lcreate = zfs_prop_get_int(l, ZFS_PROP_CREATETXG);
|
||||
rcreate = zfs_prop_get_int(r, ZFS_PROP_CREATETXG);
|
||||
|
||||
if (lcreate < rcreate)
|
||||
return (-1);
|
||||
else if (lcreate > rcreate)
|
||||
return (+1);
|
||||
else
|
||||
return (0);
|
||||
}
|
||||
|
||||
int
|
||||
zfs_iter_snapshots_sorted(zfs_handle_t *zhp, zfs_iter_f callback, void *data)
|
||||
{
|
||||
int ret = 0;
|
||||
zfs_node_t *node;
|
||||
avl_tree_t avl;
|
||||
void *cookie = NULL;
|
||||
|
||||
avl_create(&avl, zfs_snapshot_compare,
|
||||
sizeof (zfs_node_t), offsetof(zfs_node_t, zn_avlnode));
|
||||
|
||||
ret = zfs_iter_snapshots(zhp, zfs_sort_snaps, &avl);
|
||||
|
||||
for (node = avl_first(&avl); node != NULL; node = AVL_NEXT(&avl, node))
|
||||
ret |= callback(node->zn_handle, data);
|
||||
|
||||
while ((node = avl_destroy_nodes(&avl, &cookie)) != NULL)
|
||||
free(node);
|
||||
|
||||
avl_destroy(&avl);
|
||||
|
||||
return (ret);
|
||||
}
|
||||
|
||||
typedef struct {
|
||||
char *ssa_first;
|
||||
char *ssa_last;
|
||||
boolean_t ssa_seenfirst;
|
||||
boolean_t ssa_seenlast;
|
||||
zfs_iter_f ssa_func;
|
||||
void *ssa_arg;
|
||||
} snapspec_arg_t;
|
||||
|
||||
static int
|
||||
snapspec_cb(zfs_handle_t *zhp, void *arg) {
|
||||
snapspec_arg_t *ssa = arg;
|
||||
char *shortsnapname;
|
||||
int err = 0;
|
||||
|
||||
if (ssa->ssa_seenlast)
|
||||
return (0);
|
||||
shortsnapname = zfs_strdup(zhp->zfs_hdl,
|
||||
strchr(zfs_get_name(zhp), '@') + 1);
|
||||
|
||||
if (!ssa->ssa_seenfirst && strcmp(shortsnapname, ssa->ssa_first) == 0)
|
||||
ssa->ssa_seenfirst = B_TRUE;
|
||||
|
||||
if (ssa->ssa_seenfirst) {
|
||||
err = ssa->ssa_func(zhp, ssa->ssa_arg);
|
||||
} else {
|
||||
zfs_close(zhp);
|
||||
}
|
||||
|
||||
if (strcmp(shortsnapname, ssa->ssa_last) == 0)
|
||||
ssa->ssa_seenlast = B_TRUE;
|
||||
free(shortsnapname);
|
||||
|
||||
return (err);
|
||||
}
|
||||
|
||||
/*
|
||||
* spec is a string like "A,B%C,D"
|
||||
*
|
||||
* <snaps>, where <snaps> can be:
|
||||
* <snap> (single snapshot)
|
||||
* <snap>%<snap> (range of snapshots, inclusive)
|
||||
* %<snap> (range of snapshots, starting with earliest)
|
||||
* <snap>% (range of snapshots, ending with last)
|
||||
* % (all snapshots)
|
||||
* <snaps>[,...] (comma separated list of the above)
|
||||
*
|
||||
* If a snapshot can not be opened, continue trying to open the others, but
|
||||
* return ENOENT at the end.
|
||||
*/
|
||||
int
|
||||
zfs_iter_snapspec(zfs_handle_t *fs_zhp, const char *spec_orig,
|
||||
zfs_iter_f func, void *arg)
|
||||
{
|
||||
char buf[ZFS_MAXNAMELEN];
|
||||
char *comma_separated, *cp;
|
||||
int err = 0;
|
||||
int ret = 0;
|
||||
|
||||
(void) strlcpy(buf, spec_orig, sizeof (buf));
|
||||
cp = buf;
|
||||
|
||||
while ((comma_separated = strsep(&cp, ",")) != NULL) {
|
||||
char *pct = strchr(comma_separated, '%');
|
||||
if (pct != NULL) {
|
||||
snapspec_arg_t ssa = { 0 };
|
||||
ssa.ssa_func = func;
|
||||
ssa.ssa_arg = arg;
|
||||
|
||||
if (pct == comma_separated)
|
||||
ssa.ssa_seenfirst = B_TRUE;
|
||||
else
|
||||
ssa.ssa_first = comma_separated;
|
||||
*pct = '\0';
|
||||
ssa.ssa_last = pct + 1;
|
||||
|
||||
/*
|
||||
* If there is a lastname specified, make sure it
|
||||
* exists.
|
||||
*/
|
||||
if (ssa.ssa_last[0] != '\0') {
|
||||
char snapname[ZFS_MAXNAMELEN];
|
||||
(void) snprintf(snapname, sizeof (snapname),
|
||||
"%s@%s", zfs_get_name(fs_zhp),
|
||||
ssa.ssa_last);
|
||||
if (!zfs_dataset_exists(fs_zhp->zfs_hdl,
|
||||
snapname, ZFS_TYPE_SNAPSHOT)) {
|
||||
ret = ENOENT;
|
||||
continue;
|
||||
}
|
||||
}
|
||||
|
||||
err = zfs_iter_snapshots_sorted(fs_zhp,
|
||||
snapspec_cb, &ssa);
|
||||
if (ret == 0)
|
||||
ret = err;
|
||||
if (ret == 0 && (!ssa.ssa_seenfirst ||
|
||||
(ssa.ssa_last[0] != '\0' && !ssa.ssa_seenlast))) {
|
||||
ret = ENOENT;
|
||||
}
|
||||
} else {
|
||||
char snapname[ZFS_MAXNAMELEN];
|
||||
zfs_handle_t *snap_zhp;
|
||||
(void) snprintf(snapname, sizeof (snapname), "%s@%s",
|
||||
zfs_get_name(fs_zhp), comma_separated);
|
||||
snap_zhp = make_dataset_handle(fs_zhp->zfs_hdl,
|
||||
snapname);
|
||||
if (snap_zhp == NULL) {
|
||||
ret = ENOENT;
|
||||
continue;
|
||||
}
|
||||
err = func(snap_zhp, arg);
|
||||
if (ret == 0)
|
||||
ret = err;
|
||||
}
|
||||
}
|
||||
|
||||
return (ret);
|
||||
}
|
||||
|
||||
/*
|
||||
* Iterate over all children, snapshots and filesystems
|
||||
*/
|
||||
int
|
||||
zfs_iter_children(zfs_handle_t *zhp, zfs_iter_f func, void *data)
|
||||
{
|
||||
int ret;
|
||||
|
||||
if ((ret = zfs_iter_filesystems(zhp, func, data)) != 0)
|
||||
return (ret);
|
||||
|
||||
return (zfs_iter_snapshots(zhp, func, data));
|
||||
}
|
||||
|
||||
|
||||
typedef struct iter_stack_frame {
|
||||
struct iter_stack_frame *next;
|
||||
zfs_handle_t *zhp;
|
||||
} iter_stack_frame_t;
|
||||
|
||||
typedef struct iter_dependents_arg {
|
||||
boolean_t first;
|
||||
boolean_t allowrecursion;
|
||||
iter_stack_frame_t *stack;
|
||||
zfs_iter_f func;
|
||||
void *data;
|
||||
} iter_dependents_arg_t;
|
||||
|
||||
static int
|
||||
iter_dependents_cb(zfs_handle_t *zhp, void *arg)
|
||||
{
|
||||
iter_dependents_arg_t *ida = arg;
|
||||
int err;
|
||||
boolean_t first = ida->first;
|
||||
ida->first = B_FALSE;
|
||||
|
||||
if (zhp->zfs_type == ZFS_TYPE_SNAPSHOT) {
|
||||
err = zfs_iter_clones(zhp, iter_dependents_cb, ida);
|
||||
} else {
|
||||
iter_stack_frame_t isf;
|
||||
iter_stack_frame_t *f;
|
||||
|
||||
/*
|
||||
* check if there is a cycle by seeing if this fs is already
|
||||
* on the stack.
|
||||
*/
|
||||
for (f = ida->stack; f != NULL; f = f->next) {
|
||||
if (f->zhp->zfs_dmustats.dds_guid ==
|
||||
zhp->zfs_dmustats.dds_guid) {
|
||||
if (ida->allowrecursion) {
|
||||
zfs_close(zhp);
|
||||
return (0);
|
||||
} else {
|
||||
zfs_error_aux(zhp->zfs_hdl,
|
||||
dgettext(TEXT_DOMAIN,
|
||||
"recursive dependency at '%s'"),
|
||||
zfs_get_name(zhp));
|
||||
err = zfs_error(zhp->zfs_hdl,
|
||||
EZFS_RECURSIVE,
|
||||
dgettext(TEXT_DOMAIN,
|
||||
"cannot determine dependent "
|
||||
"datasets"));
|
||||
zfs_close(zhp);
|
||||
return (err);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
isf.zhp = zhp;
|
||||
isf.next = ida->stack;
|
||||
ida->stack = &isf;
|
||||
err = zfs_iter_filesystems(zhp, iter_dependents_cb, ida);
|
||||
if (err == 0)
|
||||
err = zfs_iter_snapshots(zhp, iter_dependents_cb, ida);
|
||||
ida->stack = isf.next;
|
||||
}
|
||||
if (!first && err == 0)
|
||||
err = ida->func(zhp, ida->data);
|
||||
return (err);
|
||||
}
|
||||
|
||||
int
|
||||
zfs_iter_dependents(zfs_handle_t *zhp, boolean_t allowrecursion,
|
||||
zfs_iter_f func, void *data)
|
||||
{
|
||||
iter_dependents_arg_t ida;
|
||||
ida.allowrecursion = allowrecursion;
|
||||
ida.stack = NULL;
|
||||
ida.func = func;
|
||||
ida.data = data;
|
||||
ida.first = B_TRUE;
|
||||
return (iter_dependents_cb(zfs_handle_dup(zhp), &ida));
|
||||
}
|
@ -21,6 +21,8 @@
|
||||
|
||||
/*
|
||||
* Copyright (c) 2005, 2010, Oracle and/or its affiliates. All rights reserved.
|
||||
* Copyright 2011 Nexenta Systems, Inc. All rights reserved.
|
||||
* Copyright (c) 2011 by Delphix. All rights reserved.
|
||||
*/
|
||||
|
||||
#include <sys/types.h>
|
||||
@ -261,6 +263,7 @@ zpool_get_prop(zpool_handle_t *zhp, zpool_prop_t prop, char *buf, size_t len,
|
||||
|
||||
case ZPOOL_PROP_ALTROOT:
|
||||
case ZPOOL_PROP_CACHEFILE:
|
||||
case ZPOOL_PROP_COMMENT:
|
||||
if (zhp->zpool_props != NULL ||
|
||||
zpool_get_all_props(zhp) == 0) {
|
||||
(void) strlcpy(buf,
|
||||
@ -412,7 +415,7 @@ zpool_valid_proplist(libzfs_handle_t *hdl, const char *poolname,
|
||||
zpool_prop_t prop;
|
||||
char *strval;
|
||||
uint64_t intval;
|
||||
char *slash;
|
||||
char *slash, *check;
|
||||
struct stat64 statbuf;
|
||||
zpool_handle_t *zhp;
|
||||
nvlist_t *nvroot;
|
||||
@ -573,6 +576,26 @@ zpool_valid_proplist(libzfs_handle_t *hdl, const char *poolname,
|
||||
*slash = '/';
|
||||
break;
|
||||
|
||||
case ZPOOL_PROP_COMMENT:
|
||||
for (check = strval; *check != '\0'; check++) {
|
||||
if (!isprint(*check)) {
|
||||
zfs_error_aux(hdl,
|
||||
dgettext(TEXT_DOMAIN,
|
||||
"comment may only have printable "
|
||||
"characters"));
|
||||
(void) zfs_error(hdl, EZFS_BADPROP,
|
||||
errbuf);
|
||||
goto error;
|
||||
}
|
||||
}
|
||||
if (strlen(strval) > ZPROP_MAX_COMMENT) {
|
||||
zfs_error_aux(hdl, dgettext(TEXT_DOMAIN,
|
||||
"comment must not exceed %d characters"),
|
||||
ZPROP_MAX_COMMENT);
|
||||
(void) zfs_error(hdl, EZFS_BADPROP, errbuf);
|
||||
goto error;
|
||||
}
|
||||
break;
|
||||
case ZPOOL_PROP_READONLY:
|
||||
if (!flags.import) {
|
||||
zfs_error_aux(hdl, dgettext(TEXT_DOMAIN,
|
||||
@ -3010,6 +3033,26 @@ zpool_vdev_clear(zpool_handle_t *zhp, uint64_t guid)
|
||||
return (zpool_standard_error(hdl, errno, msg));
|
||||
}
|
||||
|
||||
/*
|
||||
* Change the GUID for a pool.
|
||||
*/
|
||||
int
|
||||
zpool_reguid(zpool_handle_t *zhp)
|
||||
{
|
||||
char msg[1024];
|
||||
libzfs_handle_t *hdl = zhp->zpool_hdl;
|
||||
zfs_cmd_t zc = { 0 };
|
||||
|
||||
(void) snprintf(msg, sizeof (msg),
|
||||
dgettext(TEXT_DOMAIN, "cannot reguid '%s'"), zhp->zpool_name);
|
||||
|
||||
(void) strlcpy(zc.zc_name, zhp->zpool_name, sizeof (zc.zc_name));
|
||||
if (zfs_ioctl(hdl, ZFS_IOC_POOL_REGUID, &zc) == 0)
|
||||
return (0);
|
||||
|
||||
return (zpool_standard_error(hdl, errno, msg));
|
||||
}
|
||||
|
||||
/*
|
||||
* Convert from a devid string to a path.
|
||||
*/
|
||||
|
File diff suppressed because it is too large
Load Diff
@ -20,6 +20,7 @@
|
||||
*/
|
||||
/*
|
||||
* Copyright (c) 2005, 2010, Oracle and/or its affiliates. All rights reserved.
|
||||
* Copyright (c) 2011 by Delphix. All rights reserved.
|
||||
*/
|
||||
|
||||
/*
|
||||
@ -351,6 +352,7 @@ zfs_standard_error_fmt(libzfs_handle_t *hdl, int error, const char *fmt, ...)
|
||||
switch (error) {
|
||||
case ENXIO:
|
||||
case ENODEV:
|
||||
case EPIPE:
|
||||
zfs_verror(hdl, EZFS_IO, fmt, ap);
|
||||
break;
|
||||
|
||||
@ -1324,7 +1326,8 @@ addlist(libzfs_handle_t *hdl, char *propname, zprop_list_t **listp,
|
||||
* dataset property,
|
||||
*/
|
||||
if (prop == ZPROP_INVAL && (type == ZFS_TYPE_POOL ||
|
||||
(!zfs_prop_user(propname) && !zfs_prop_userquota(propname)))) {
|
||||
(!zfs_prop_user(propname) && !zfs_prop_userquota(propname) &&
|
||||
!zfs_prop_written(propname)))) {
|
||||
zfs_error_aux(hdl, dgettext(TEXT_DOMAIN,
|
||||
"invalid property '%s'"), propname);
|
||||
return (zfs_error(hdl, EZFS_BADPROP,
|
||||
|
@ -228,7 +228,7 @@ usage(void)
|
||||
"\n"
|
||||
" Note: if -L labelenv is specified and labelenv is not set in\n"
|
||||
" the environment, a default value is used.\n",
|
||||
progname, progname, strlen(progname), " ",
|
||||
progname, progname, (int)strlen(progname), " ",
|
||||
progname, progname);
|
||||
}
|
||||
|
||||
|
@ -18,4 +18,4 @@ CFLAGS+= -I${.CURDIR}/../../../sys/cddl/compat/opensolaris \
|
||||
-I${OPENSOLARIS_SYS_DISTDIR}/uts/common \
|
||||
-DPIC ${PICFLAG}
|
||||
|
||||
.include <bsd.prog.mk>
|
||||
.include <bsd.lib.mk>
|
||||
|
@ -20,8 +20,8 @@ SRCS+= libzfs_changelist.c \
|
||||
libzfs_config.c \
|
||||
libzfs_dataset.c \
|
||||
libzfs_diff.c \
|
||||
libzfs_graph.c \
|
||||
libzfs_import.c \
|
||||
libzfs_iter.c \
|
||||
libzfs_mount.c \
|
||||
libzfs_pool.c \
|
||||
libzfs_sendrecv.c \
|
||||
|
@ -941,7 +941,7 @@ handle_rtmsg(struct rt_msghdr *rtm)
|
||||
{
|
||||
struct sockaddr *addrs[RTAX_MAX];
|
||||
struct if_msghdr *ifm;
|
||||
struct ifa_msghdr *ifam;
|
||||
struct ifa_msghdr ifam;
|
||||
struct ifma_msghdr *ifmam;
|
||||
#ifdef RTM_IFANNOUNCE
|
||||
struct if_announcemsghdr *ifan;
|
||||
@ -961,17 +961,17 @@ handle_rtmsg(struct rt_msghdr *rtm)
|
||||
switch (rtm->rtm_type) {
|
||||
|
||||
case RTM_NEWADDR:
|
||||
ifam = (struct ifa_msghdr *)rtm;
|
||||
mib_extract_addrs(ifam->ifam_addrs, (u_char *)(ifam + 1), addrs);
|
||||
memcpy(&ifam, rtm, sizeof(ifam));
|
||||
mib_extract_addrs(ifam.ifam_addrs, (u_char *)(&ifam + 1), addrs);
|
||||
if (addrs[RTAX_IFA] == NULL || addrs[RTAX_NETMASK] == NULL)
|
||||
break;
|
||||
|
||||
sa = (struct sockaddr_in *)(void *)addrs[RTAX_IFA];
|
||||
if ((ifa = mib_find_ifa(sa->sin_addr)) == NULL) {
|
||||
/* unknown address */
|
||||
if ((ifp = mib_find_if_sys(ifam->ifam_index)) == NULL) {
|
||||
if ((ifp = mib_find_if_sys(ifam.ifam_index)) == NULL) {
|
||||
syslog(LOG_WARNING, "RTM_NEWADDR for unknown "
|
||||
"interface %u", ifam->ifam_index);
|
||||
"interface %u", ifam.ifam_index);
|
||||
break;
|
||||
}
|
||||
if ((ifa = alloc_ifa(ifp->index, sa->sin_addr)) == NULL)
|
||||
@ -988,8 +988,8 @@ handle_rtmsg(struct rt_msghdr *rtm)
|
||||
break;
|
||||
|
||||
case RTM_DELADDR:
|
||||
ifam = (struct ifa_msghdr *)rtm;
|
||||
mib_extract_addrs(ifam->ifam_addrs, (u_char *)(ifam + 1), addrs);
|
||||
memcpy(&ifam, rtm, sizeof(ifam));
|
||||
mib_extract_addrs(ifam.ifam_addrs, (u_char *)(&ifam + 1), addrs);
|
||||
if (addrs[RTAX_IFA] == NULL)
|
||||
break;
|
||||
|
||||
|
@ -40,6 +40,7 @@
|
||||
#define snmpmod_h_
|
||||
|
||||
#include <sys/types.h>
|
||||
#include <sys/queue.h>
|
||||
#include <sys/socket.h>
|
||||
#include <net/if.h>
|
||||
#include <netinet/in.h>
|
||||
|
@ -37,7 +37,7 @@
|
||||
*/
|
||||
#ifdef __GNUC__
|
||||
typedef unsigned long long int MaybeUInt64;
|
||||
# define MaybeUInt64_FMT "%Lu"
|
||||
# define MaybeUInt64_FMT "%llu"
|
||||
#else
|
||||
#ifdef _MSC_VER
|
||||
typedef unsigned __int64 MaybeUInt64;
|
||||
|
@ -14,7 +14,7 @@ Full text of the relevant licenses is included below.
|
||||
University of Illinois/NCSA
|
||||
Open Source License
|
||||
|
||||
Copyright (c) 2009-2010 by the contributors listed in CREDITS.TXT
|
||||
Copyright (c) 2009-2012 by the contributors listed in CREDITS.TXT
|
||||
|
||||
All rights reserved.
|
||||
|
||||
@ -55,7 +55,7 @@ SOFTWARE.
|
||||
|
||||
==============================================================================
|
||||
|
||||
Copyright (c) 2009-2010 by the contributors listed in CREDITS.TXT
|
||||
Copyright (c) 2009-2012 by the contributors listed in CREDITS.TXT
|
||||
|
||||
Permission is hereby granted, free of charge, to any person obtaining a copy
|
||||
of this software and associated documentation files (the "Software"), to deal
|
||||
@ -74,3 +74,25 @@ AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
||||
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
|
||||
OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
|
||||
THE SOFTWARE.
|
||||
|
||||
==============================================================================
|
||||
Copyrights and Licenses for Third Party Software Distributed with LLVM:
|
||||
==============================================================================
|
||||
The LLVM software contains code written by third parties. Such software will
|
||||
have its own individual LICENSE.TXT file in the directory in which it appears.
|
||||
This file will describe the copyrights, license, and restrictions which apply
|
||||
to that code.
|
||||
|
||||
The disclaimer of warranty in the University of Illinois Open Source License
|
||||
applies to all code in the LLVM Distribution, and nothing in any of the
|
||||
other licenses gives permission to use the names of the LLVM Team or the
|
||||
University of Illinois to endorse or promote products derived from this
|
||||
Software.
|
||||
|
||||
The following pieces of software have additional or alternate copyrights,
|
||||
licenses, and/or restrictions:
|
||||
|
||||
Program Directory
|
||||
------- ---------
|
||||
sysinfo lib/asan/sysinfo
|
||||
mach_override lib/asan/mach_override
|
||||
|
@ -106,6 +106,15 @@ si_int __mulvsi3(si_int a, si_int b); // a * b
|
||||
di_int __mulvdi3(di_int a, di_int b); // a * b
|
||||
ti_int __mulvti3(ti_int a, ti_int b); // a * b
|
||||
|
||||
|
||||
// Integral arithmetic which returns if overflow
|
||||
|
||||
si_int __mulosi4(si_int a, si_int b, int* overflow); // a * b, overflow set to one if result not in signed range
|
||||
di_int __mulodi4(di_int a, di_int b, int* overflow); // a * b, overflow set to one if result not in signed range
|
||||
ti_int __muloti4(ti_int a, ti_int b, int* overflow); // a * b, overflow set to
|
||||
one if result not in signed range
|
||||
|
||||
|
||||
// Integral comparison: a < b -> 0
|
||||
// a == b -> 1
|
||||
// a > b -> 2
|
||||
|
@ -1,23 +0,0 @@
|
||||
/* ===------ abi.h - configuration header for compiler-rt -----------------===
|
||||
*
|
||||
* The LLVM Compiler Infrastructure
|
||||
*
|
||||
* This file is dual licensed under the MIT and the University of Illinois Open
|
||||
* Source Licenses. See LICENSE.TXT for details.
|
||||
*
|
||||
* ===----------------------------------------------------------------------===
|
||||
*
|
||||
* This file is a configuration header for compiler-rt.
|
||||
* This file is not part of the interface of this library.
|
||||
*
|
||||
* ===----------------------------------------------------------------------===
|
||||
*/
|
||||
|
||||
#if __ARM_EABI__
|
||||
# define ARM_EABI_FNALIAS(aeabi_name, name) \
|
||||
void __aeabi_##aeabi_name() __attribute__((alias("__" #name)));
|
||||
# define COMPILER_RT_ABI __attribute__((pcs("aapcs")))
|
||||
#else
|
||||
# define ARM_EABI_FNALIAS(aeabi_name, name)
|
||||
# define COMPILER_RT_ABI
|
||||
#endif
|
@ -11,10 +11,8 @@
|
||||
*
|
||||
*===----------------------------------------------------------------------===
|
||||
*/
|
||||
#include "abi.h"
|
||||
|
||||
#include "int_lib.h"
|
||||
#include <stdlib.h>
|
||||
|
||||
/* Returns: absolute value */
|
||||
|
||||
|
@ -11,10 +11,8 @@
|
||||
*
|
||||
* ===----------------------------------------------------------------------===
|
||||
*/
|
||||
#include "abi.h"
|
||||
|
||||
#include "int_lib.h"
|
||||
#include <stdlib.h>
|
||||
|
||||
/* Returns: absolute value */
|
||||
|
||||
|
@ -15,7 +15,6 @@
|
||||
#if __x86_64
|
||||
|
||||
#include "int_lib.h"
|
||||
#include <stdlib.h>
|
||||
|
||||
/* Returns: absolute value */
|
||||
|
||||
|
@ -12,8 +12,6 @@
|
||||
//
|
||||
//===----------------------------------------------------------------------===//
|
||||
|
||||
#include "abi.h"
|
||||
|
||||
#define DOUBLE_PRECISION
|
||||
#include "fp_lib.h"
|
||||
|
||||
|
@ -12,8 +12,6 @@
|
||||
//
|
||||
//===----------------------------------------------------------------------===//
|
||||
|
||||
#include "abi.h"
|
||||
|
||||
#define SINGLE_PRECISION
|
||||
#include "fp_lib.h"
|
||||
|
||||
|
@ -11,10 +11,8 @@
|
||||
*
|
||||
* ===----------------------------------------------------------------------===
|
||||
*/
|
||||
#include "abi.h"
|
||||
|
||||
#include "int_lib.h"
|
||||
#include <stdlib.h>
|
||||
|
||||
/* Returns: a + b */
|
||||
|
||||
|
@ -11,10 +11,8 @@
|
||||
*
|
||||
* ===----------------------------------------------------------------------===
|
||||
*/
|
||||
#include "abi.h"
|
||||
|
||||
#include "int_lib.h"
|
||||
#include <stdlib.h>
|
||||
|
||||
/* Returns: a + b */
|
||||
|
||||
|
@ -15,7 +15,6 @@
|
||||
#if __x86_64
|
||||
|
||||
#include "int_lib.h"
|
||||
#include <stdlib.h>
|
||||
|
||||
/* Returns: a + b */
|
||||
|
||||
|
@ -1,291 +0,0 @@
|
||||
/* ===-- apple_versioning.c - Adds versioning symbols for ld ---------------===
|
||||
*
|
||||
* The LLVM Compiler Infrastructure
|
||||
*
|
||||
* This file is dual licensed under the MIT and the University of Illinois Open
|
||||
* Source Licenses. See LICENSE.TXT for details.
|
||||
*
|
||||
* ===----------------------------------------------------------------------===
|
||||
*/
|
||||
|
||||
|
||||
|
||||
#if __APPLE__
|
||||
#if __arm__
|
||||
#define NOT_HERE_BEFORE_10_6(sym)
|
||||
#elif __ppc__
|
||||
#define NOT_HERE_BEFORE_10_6(sym) \
|
||||
extern const char sym##_tmp3 __asm("$ld$hide$os10.3$_" #sym ); \
|
||||
__attribute__((visibility("default"))) const char sym##_tmp3 = 0; \
|
||||
extern const char sym##_tmp4 __asm("$ld$hide$os10.4$_" #sym ); \
|
||||
__attribute__((visibility("default"))) const char sym##_tmp4 = 0; \
|
||||
extern const char sym##_tmp5 __asm("$ld$hide$os10.5$_" #sym ); \
|
||||
__attribute__((visibility("default"))) const char sym##_tmp5 = 0;
|
||||
#else
|
||||
#define NOT_HERE_BEFORE_10_6(sym) \
|
||||
extern const char sym##_tmp4 __asm("$ld$hide$os10.4$_" #sym ); \
|
||||
__attribute__((visibility("default"))) const char sym##_tmp4 = 0; \
|
||||
extern const char sym##_tmp5 __asm("$ld$hide$os10.5$_" #sym ); \
|
||||
__attribute__((visibility("default"))) const char sym##_tmp5 = 0;
|
||||
#endif /* __ppc__ */
|
||||
|
||||
|
||||
/* Symbols in libSystem.dylib in 10.6 and later,
|
||||
* but are in libgcc_s.dylib in earlier versions
|
||||
*/
|
||||
|
||||
NOT_HERE_BEFORE_10_6(__absvdi2)
|
||||
NOT_HERE_BEFORE_10_6(__absvsi2)
|
||||
NOT_HERE_BEFORE_10_6(__absvti2)
|
||||
NOT_HERE_BEFORE_10_6(__addvdi3)
|
||||
NOT_HERE_BEFORE_10_6(__addvsi3)
|
||||
NOT_HERE_BEFORE_10_6(__addvti3)
|
||||
NOT_HERE_BEFORE_10_6(__ashldi3)
|
||||
NOT_HERE_BEFORE_10_6(__ashlti3)
|
||||
NOT_HERE_BEFORE_10_6(__ashrdi3)
|
||||
NOT_HERE_BEFORE_10_6(__ashrti3)
|
||||
NOT_HERE_BEFORE_10_6(__clear_cache)
|
||||
NOT_HERE_BEFORE_10_6(__clzdi2)
|
||||
NOT_HERE_BEFORE_10_6(__clzsi2)
|
||||
NOT_HERE_BEFORE_10_6(__clzti2)
|
||||
NOT_HERE_BEFORE_10_6(__cmpdi2)
|
||||
NOT_HERE_BEFORE_10_6(__cmpti2)
|
||||
NOT_HERE_BEFORE_10_6(__ctzdi2)
|
||||
NOT_HERE_BEFORE_10_6(__ctzsi2)
|
||||
NOT_HERE_BEFORE_10_6(__ctzti2)
|
||||
NOT_HERE_BEFORE_10_6(__divdc3)
|
||||
NOT_HERE_BEFORE_10_6(__divdi3)
|
||||
NOT_HERE_BEFORE_10_6(__divsc3)
|
||||
NOT_HERE_BEFORE_10_6(__divtc3)
|
||||
NOT_HERE_BEFORE_10_6(__divti3)
|
||||
NOT_HERE_BEFORE_10_6(__divxc3)
|
||||
NOT_HERE_BEFORE_10_6(__enable_execute_stack)
|
||||
NOT_HERE_BEFORE_10_6(__ffsdi2)
|
||||
NOT_HERE_BEFORE_10_6(__ffsti2)
|
||||
NOT_HERE_BEFORE_10_6(__fixdfdi)
|
||||
NOT_HERE_BEFORE_10_6(__fixdfti)
|
||||
NOT_HERE_BEFORE_10_6(__fixsfdi)
|
||||
NOT_HERE_BEFORE_10_6(__fixsfti)
|
||||
NOT_HERE_BEFORE_10_6(__fixtfdi)
|
||||
NOT_HERE_BEFORE_10_6(__fixunsdfdi)
|
||||
NOT_HERE_BEFORE_10_6(__fixunsdfsi)
|
||||
NOT_HERE_BEFORE_10_6(__fixunsdfti)
|
||||
NOT_HERE_BEFORE_10_6(__fixunssfdi)
|
||||
NOT_HERE_BEFORE_10_6(__fixunssfsi)
|
||||
NOT_HERE_BEFORE_10_6(__fixunssfti)
|
||||
NOT_HERE_BEFORE_10_6(__fixunstfdi)
|
||||
NOT_HERE_BEFORE_10_6(__fixunsxfdi)
|
||||
NOT_HERE_BEFORE_10_6(__fixunsxfsi)
|
||||
NOT_HERE_BEFORE_10_6(__fixunsxfti)
|
||||
NOT_HERE_BEFORE_10_6(__fixxfdi)
|
||||
NOT_HERE_BEFORE_10_6(__fixxfti)
|
||||
NOT_HERE_BEFORE_10_6(__floatdidf)
|
||||
NOT_HERE_BEFORE_10_6(__floatdisf)
|
||||
NOT_HERE_BEFORE_10_6(__floatditf)
|
||||
NOT_HERE_BEFORE_10_6(__floatdixf)
|
||||
NOT_HERE_BEFORE_10_6(__floattidf)
|
||||
NOT_HERE_BEFORE_10_6(__floattisf)
|
||||
NOT_HERE_BEFORE_10_6(__floattixf)
|
||||
NOT_HERE_BEFORE_10_6(__floatundidf)
|
||||
NOT_HERE_BEFORE_10_6(__floatundisf)
|
||||
NOT_HERE_BEFORE_10_6(__floatunditf)
|
||||
NOT_HERE_BEFORE_10_6(__floatundixf)
|
||||
NOT_HERE_BEFORE_10_6(__floatuntidf)
|
||||
NOT_HERE_BEFORE_10_6(__floatuntisf)
|
||||
NOT_HERE_BEFORE_10_6(__floatuntixf)
|
||||
NOT_HERE_BEFORE_10_6(__gcc_personality_v0)
|
||||
NOT_HERE_BEFORE_10_6(__lshrdi3)
|
||||
NOT_HERE_BEFORE_10_6(__lshrti3)
|
||||
NOT_HERE_BEFORE_10_6(__moddi3)
|
||||
NOT_HERE_BEFORE_10_6(__modti3)
|
||||
NOT_HERE_BEFORE_10_6(__muldc3)
|
||||
NOT_HERE_BEFORE_10_6(__muldi3)
|
||||
NOT_HERE_BEFORE_10_6(__mulsc3)
|
||||
NOT_HERE_BEFORE_10_6(__multc3)
|
||||
NOT_HERE_BEFORE_10_6(__multi3)
|
||||
NOT_HERE_BEFORE_10_6(__mulvdi3)
|
||||
NOT_HERE_BEFORE_10_6(__mulvsi3)
|
||||
NOT_HERE_BEFORE_10_6(__mulvti3)
|
||||
NOT_HERE_BEFORE_10_6(__mulxc3)
|
||||
NOT_HERE_BEFORE_10_6(__negdi2)
|
||||
NOT_HERE_BEFORE_10_6(__negti2)
|
||||
NOT_HERE_BEFORE_10_6(__negvdi2)
|
||||
NOT_HERE_BEFORE_10_6(__negvsi2)
|
||||
NOT_HERE_BEFORE_10_6(__negvti2)
|
||||
NOT_HERE_BEFORE_10_6(__paritydi2)
|
||||
NOT_HERE_BEFORE_10_6(__paritysi2)
|
||||
NOT_HERE_BEFORE_10_6(__parityti2)
|
||||
NOT_HERE_BEFORE_10_6(__popcountdi2)
|
||||
NOT_HERE_BEFORE_10_6(__popcountsi2)
|
||||
NOT_HERE_BEFORE_10_6(__popcountti2)
|
||||
NOT_HERE_BEFORE_10_6(__powidf2)
|
||||
NOT_HERE_BEFORE_10_6(__powisf2)
|
||||
NOT_HERE_BEFORE_10_6(__powitf2)
|
||||
NOT_HERE_BEFORE_10_6(__powixf2)
|
||||
NOT_HERE_BEFORE_10_6(__subvdi3)
|
||||
NOT_HERE_BEFORE_10_6(__subvsi3)
|
||||
NOT_HERE_BEFORE_10_6(__subvti3)
|
||||
NOT_HERE_BEFORE_10_6(__ucmpdi2)
|
||||
NOT_HERE_BEFORE_10_6(__ucmpti2)
|
||||
NOT_HERE_BEFORE_10_6(__udivdi3)
|
||||
NOT_HERE_BEFORE_10_6(__udivmoddi4)
|
||||
NOT_HERE_BEFORE_10_6(__udivmodti4)
|
||||
NOT_HERE_BEFORE_10_6(__udivti3)
|
||||
NOT_HERE_BEFORE_10_6(__umoddi3)
|
||||
NOT_HERE_BEFORE_10_6(__umodti3)
|
||||
|
||||
|
||||
#if __ppc__
|
||||
NOT_HERE_BEFORE_10_6(__gcc_qadd)
|
||||
NOT_HERE_BEFORE_10_6(__gcc_qdiv)
|
||||
NOT_HERE_BEFORE_10_6(__gcc_qmul)
|
||||
NOT_HERE_BEFORE_10_6(__gcc_qsub)
|
||||
NOT_HERE_BEFORE_10_6(__trampoline_setup)
|
||||
#endif /* __ppc__ */
|
||||
|
||||
#if __arm__ && __DYNAMIC__
|
||||
#define NOT_HERE_UNTIL_AFTER_4_3(sym) \
|
||||
extern const char sym##_tmp1 __asm("$ld$hide$os3.0$_" #sym ); \
|
||||
__attribute__((visibility("default"))) const char sym##_tmp1 = 0; \
|
||||
extern const char sym##_tmp2 __asm("$ld$hide$os3.1$_" #sym ); \
|
||||
__attribute__((visibility("default"))) const char sym##_tmp2 = 0; \
|
||||
extern const char sym##_tmp3 __asm("$ld$hide$os3.2$_" #sym ); \
|
||||
__attribute__((visibility("default"))) const char sym##_tmp3 = 0; \
|
||||
extern const char sym##_tmp4 __asm("$ld$hide$os4.0$_" #sym ); \
|
||||
__attribute__((visibility("default"))) const char sym##_tmp4 = 0; \
|
||||
extern const char sym##_tmp5 __asm("$ld$hide$os4.1$_" #sym ); \
|
||||
__attribute__((visibility("default"))) const char sym##_tmp5 = 0; \
|
||||
extern const char sym##_tmp6 __asm("$ld$hide$os4.2$_" #sym ); \
|
||||
__attribute__((visibility("default"))) const char sym##_tmp6 = 0; \
|
||||
extern const char sym##_tmp7 __asm("$ld$hide$os4.3$_" #sym ); \
|
||||
__attribute__((visibility("default"))) const char sym##_tmp7 = 0;
|
||||
|
||||
NOT_HERE_UNTIL_AFTER_4_3(__absvdi2)
|
||||
NOT_HERE_UNTIL_AFTER_4_3(__absvsi2)
|
||||
NOT_HERE_UNTIL_AFTER_4_3(__adddf3)
|
||||
NOT_HERE_UNTIL_AFTER_4_3(__adddf3vfp)
|
||||
NOT_HERE_UNTIL_AFTER_4_3(__addsf3)
|
||||
NOT_HERE_UNTIL_AFTER_4_3(__addsf3vfp)
|
||||
NOT_HERE_UNTIL_AFTER_4_3(__addvdi3)
|
||||
NOT_HERE_UNTIL_AFTER_4_3(__addvsi3)
|
||||
NOT_HERE_UNTIL_AFTER_4_3(__ashldi3)
|
||||
NOT_HERE_UNTIL_AFTER_4_3(__ashrdi3)
|
||||
NOT_HERE_UNTIL_AFTER_4_3(__bswapdi2)
|
||||
NOT_HERE_UNTIL_AFTER_4_3(__bswapsi2)
|
||||
NOT_HERE_UNTIL_AFTER_4_3(__clzdi2)
|
||||
NOT_HERE_UNTIL_AFTER_4_3(__clzsi2)
|
||||
NOT_HERE_UNTIL_AFTER_4_3(__cmpdi2)
|
||||
NOT_HERE_UNTIL_AFTER_4_3(__ctzdi2)
|
||||
NOT_HERE_UNTIL_AFTER_4_3(__ctzsi2)
|
||||
NOT_HERE_UNTIL_AFTER_4_3(__divdc3)
|
||||
NOT_HERE_UNTIL_AFTER_4_3(__divdf3)
|
||||
NOT_HERE_UNTIL_AFTER_4_3(__divdf3vfp)
|
||||
NOT_HERE_UNTIL_AFTER_4_3(__divdi3)
|
||||
NOT_HERE_UNTIL_AFTER_4_3(__divsc3)
|
||||
NOT_HERE_UNTIL_AFTER_4_3(__divsf3)
|
||||
NOT_HERE_UNTIL_AFTER_4_3(__divsf3vfp)
|
||||
NOT_HERE_UNTIL_AFTER_4_3(__divsi3)
|
||||
NOT_HERE_UNTIL_AFTER_4_3(__eqdf2)
|
||||
NOT_HERE_UNTIL_AFTER_4_3(__eqdf2vfp)
|
||||
NOT_HERE_UNTIL_AFTER_4_3(__eqsf2)
|
||||
NOT_HERE_UNTIL_AFTER_4_3(__eqsf2vfp)
|
||||
NOT_HERE_UNTIL_AFTER_4_3(__extendsfdf2)
|
||||
NOT_HERE_UNTIL_AFTER_4_3(__extendsfdf2vfp)
|
||||
NOT_HERE_UNTIL_AFTER_4_3(__ffsdi2)
|
||||
NOT_HERE_UNTIL_AFTER_4_3(__fixdfdi)
|
||||
NOT_HERE_UNTIL_AFTER_4_3(__fixdfsi)
|
||||
NOT_HERE_UNTIL_AFTER_4_3(__fixdfsivfp)
|
||||
NOT_HERE_UNTIL_AFTER_4_3(__fixsfdi)
|
||||
NOT_HERE_UNTIL_AFTER_4_3(__fixsfsi)
|
||||
NOT_HERE_UNTIL_AFTER_4_3(__fixsfsivfp)
|
||||
NOT_HERE_UNTIL_AFTER_4_3(__fixunsdfdi)
|
||||
NOT_HERE_UNTIL_AFTER_4_3(__fixunsdfsi)
|
||||
NOT_HERE_UNTIL_AFTER_4_3(__fixunsdfsivfp)
|
||||
NOT_HERE_UNTIL_AFTER_4_3(__fixunssfdi)
|
||||
NOT_HERE_UNTIL_AFTER_4_3(__fixunssfsi)
|
||||
NOT_HERE_UNTIL_AFTER_4_3(__fixunssfsivfp)
|
||||
NOT_HERE_UNTIL_AFTER_4_3(__floatdidf)
|
||||
NOT_HERE_UNTIL_AFTER_4_3(__floatdisf)
|
||||
NOT_HERE_UNTIL_AFTER_4_3(__floatsidf)
|
||||
NOT_HERE_UNTIL_AFTER_4_3(__floatsidfvfp)
|
||||
NOT_HERE_UNTIL_AFTER_4_3(__floatsisf)
|
||||
NOT_HERE_UNTIL_AFTER_4_3(__floatsisfvfp)
|
||||
NOT_HERE_UNTIL_AFTER_4_3(__floatundidf)
|
||||
NOT_HERE_UNTIL_AFTER_4_3(__floatundisf)
|
||||
NOT_HERE_UNTIL_AFTER_4_3(__floatunsidf)
|
||||
NOT_HERE_UNTIL_AFTER_4_3(__floatunsisf)
|
||||
NOT_HERE_UNTIL_AFTER_4_3(__floatunssidfvfp)
|
||||
NOT_HERE_UNTIL_AFTER_4_3(__floatunssisfvfp)
|
||||
NOT_HERE_UNTIL_AFTER_4_3(__gedf2)
|
||||
NOT_HERE_UNTIL_AFTER_4_3(__gedf2vfp)
|
||||
NOT_HERE_UNTIL_AFTER_4_3(__gesf2)
|
||||
NOT_HERE_UNTIL_AFTER_4_3(__gesf2vfp)
|
||||
NOT_HERE_UNTIL_AFTER_4_3(__gtdf2)
|
||||
NOT_HERE_UNTIL_AFTER_4_3(__gtdf2vfp)
|
||||
NOT_HERE_UNTIL_AFTER_4_3(__gtsf2)
|
||||
NOT_HERE_UNTIL_AFTER_4_3(__gtsf2vfp)
|
||||
NOT_HERE_UNTIL_AFTER_4_3(__ledf2)
|
||||
NOT_HERE_UNTIL_AFTER_4_3(__ledf2vfp)
|
||||
NOT_HERE_UNTIL_AFTER_4_3(__lesf2)
|
||||
NOT_HERE_UNTIL_AFTER_4_3(__lesf2vfp)
|
||||
NOT_HERE_UNTIL_AFTER_4_3(__lshrdi3)
|
||||
NOT_HERE_UNTIL_AFTER_4_3(__ltdf2)
|
||||
NOT_HERE_UNTIL_AFTER_4_3(__ltdf2vfp)
|
||||
NOT_HERE_UNTIL_AFTER_4_3(__ltsf2)
|
||||
NOT_HERE_UNTIL_AFTER_4_3(__ltsf2vfp)
|
||||
NOT_HERE_UNTIL_AFTER_4_3(__moddi3)
|
||||
NOT_HERE_UNTIL_AFTER_4_3(__modsi3)
|
||||
NOT_HERE_UNTIL_AFTER_4_3(__muldc3)
|
||||
NOT_HERE_UNTIL_AFTER_4_3(__muldf3)
|
||||
NOT_HERE_UNTIL_AFTER_4_3(__muldf3vfp)
|
||||
NOT_HERE_UNTIL_AFTER_4_3(__muldi3)
|
||||
NOT_HERE_UNTIL_AFTER_4_3(__mulsc3)
|
||||
NOT_HERE_UNTIL_AFTER_4_3(__mulsf3)
|
||||
NOT_HERE_UNTIL_AFTER_4_3(__mulsf3vfp)
|
||||
NOT_HERE_UNTIL_AFTER_4_3(__mulvdi3)
|
||||
NOT_HERE_UNTIL_AFTER_4_3(__mulvsi3)
|
||||
NOT_HERE_UNTIL_AFTER_4_3(__nedf2)
|
||||
NOT_HERE_UNTIL_AFTER_4_3(__nedf2vfp)
|
||||
NOT_HERE_UNTIL_AFTER_4_3(__negdi2)
|
||||
NOT_HERE_UNTIL_AFTER_4_3(__negvdi2)
|
||||
NOT_HERE_UNTIL_AFTER_4_3(__negvsi2)
|
||||
NOT_HERE_UNTIL_AFTER_4_3(__nesf2)
|
||||
NOT_HERE_UNTIL_AFTER_4_3(__nesf2vfp)
|
||||
NOT_HERE_UNTIL_AFTER_4_3(__paritydi2)
|
||||
NOT_HERE_UNTIL_AFTER_4_3(__paritysi2)
|
||||
NOT_HERE_UNTIL_AFTER_4_3(__popcountdi2)
|
||||
NOT_HERE_UNTIL_AFTER_4_3(__popcountsi2)
|
||||
NOT_HERE_UNTIL_AFTER_4_3(__powidf2)
|
||||
NOT_HERE_UNTIL_AFTER_4_3(__powisf2)
|
||||
NOT_HERE_UNTIL_AFTER_4_3(__subdf3)
|
||||
NOT_HERE_UNTIL_AFTER_4_3(__subdf3vfp)
|
||||
NOT_HERE_UNTIL_AFTER_4_3(__subsf3)
|
||||
NOT_HERE_UNTIL_AFTER_4_3(__subsf3vfp)
|
||||
NOT_HERE_UNTIL_AFTER_4_3(__subvdi3)
|
||||
NOT_HERE_UNTIL_AFTER_4_3(__subvsi3)
|
||||
NOT_HERE_UNTIL_AFTER_4_3(__truncdfsf2)
|
||||
NOT_HERE_UNTIL_AFTER_4_3(__truncdfsf2vfp)
|
||||
NOT_HERE_UNTIL_AFTER_4_3(__ucmpdi2)
|
||||
NOT_HERE_UNTIL_AFTER_4_3(__udivdi3)
|
||||
NOT_HERE_UNTIL_AFTER_4_3(__udivmoddi4)
|
||||
NOT_HERE_UNTIL_AFTER_4_3(__udivsi3)
|
||||
NOT_HERE_UNTIL_AFTER_4_3(__umoddi3)
|
||||
NOT_HERE_UNTIL_AFTER_4_3(__umodsi3)
|
||||
NOT_HERE_UNTIL_AFTER_4_3(__unorddf2)
|
||||
NOT_HERE_UNTIL_AFTER_4_3(__unorddf2vfp)
|
||||
NOT_HERE_UNTIL_AFTER_4_3(__unordsf2)
|
||||
NOT_HERE_UNTIL_AFTER_4_3(__unordsf2vfp)
|
||||
|
||||
NOT_HERE_UNTIL_AFTER_4_3(__divmodsi4)
|
||||
NOT_HERE_UNTIL_AFTER_4_3(__udivmodsi4)
|
||||
#endif // __arm__ && __DYNAMIC__
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
#else /* !__APPLE__ */
|
||||
|
||||
extern int avoid_empty_file;
|
||||
|
||||
#endif /* !__APPLE__*/
|
@ -15,10 +15,11 @@
|
||||
// Adds two double precision floating point numbers using the Darwin
|
||||
// calling convention where double arguments are passsed in GPR pairs
|
||||
//
|
||||
.syntax unified
|
||||
.align 2
|
||||
DEFINE_COMPILERRT_FUNCTION(__adddf3vfp)
|
||||
fmdrr d6, r0, r1 // move first param from r0/r1 pair into d6
|
||||
fmdrr d7, r2, r3 // move second param from r2/r3 pair into d7
|
||||
faddd d6, d6, d7
|
||||
fmrrd r0, r1, d6 // move result back to r0/r1 pair
|
||||
vmov d6, r0, r1 // move first param from r0/r1 pair into d6
|
||||
vmov d7, r2, r3 // move second param from r2/r3 pair into d7
|
||||
vadd.f64 d6, d6, d7
|
||||
vmov r0, r1, d6 // move result back to r0/r1 pair
|
||||
bx lr
|
||||
|
@ -15,10 +15,11 @@
|
||||
// Adds two single precision floating point numbers using the Darwin
|
||||
// calling convention where single arguments are passsed in GPRs
|
||||
//
|
||||
.syntax unified
|
||||
.align 2
|
||||
DEFINE_COMPILERRT_FUNCTION(__addsf3vfp)
|
||||
fmsr s14, r0 // move first param from r0 into float register
|
||||
fmsr s15, r1 // move second param from r1 into float register
|
||||
fadds s14, s14, s15
|
||||
fmrs r0, s14 // move result back to r0
|
||||
vmov s14, r0 // move first param from r0 into float register
|
||||
vmov s15, r1 // move second param from r1 into float register
|
||||
vadd.f32 s14, s14, s15
|
||||
vmov r0, s14 // move result back to r0
|
||||
bx lr
|
||||
|
@ -15,10 +15,11 @@
|
||||
// Divides two double precision floating point numbers using the Darwin
|
||||
// calling convention where double arguments are passsed in GPR pairs
|
||||
//
|
||||
.syntax unified
|
||||
.align 2
|
||||
DEFINE_COMPILERRT_FUNCTION(__divdf3vfp)
|
||||
fmdrr d6, r0, r1 // move first param from r0/r1 pair into d6
|
||||
fmdrr d7, r2, r3 // move second param from r2/r3 pair into d7
|
||||
fdivd d5, d6, d7
|
||||
fmrrd r0, r1, d5 // move result back to r0/r1 pair
|
||||
vmov d6, r0, r1 // move first param from r0/r1 pair into d6
|
||||
vmov d7, r2, r3 // move second param from r2/r3 pair into d7
|
||||
vdiv.f64 d5, d6, d7
|
||||
vmov r0, r1, d5 // move result back to r0/r1 pair
|
||||
bx lr
|
||||
|
@ -15,10 +15,11 @@
|
||||
// Divides two single precision floating point numbers using the Darwin
|
||||
// calling convention where single arguments are passsed like 32-bit ints.
|
||||
//
|
||||
.syntax unified
|
||||
.align 2
|
||||
DEFINE_COMPILERRT_FUNCTION(__divsf3vfp)
|
||||
fmsr s14, r0 // move first param from r0 into float register
|
||||
fmsr s15, r1 // move second param from r1 into float register
|
||||
fdivs s13, s14, s15
|
||||
fmrs r0, s13 // move result back to r0
|
||||
vmov s14, r0 // move first param from r0 into float register
|
||||
vmov s15, r1 // move second param from r1 into float register
|
||||
vdiv.f32 s13, s14, s15
|
||||
vmov r0, s13 // move result back to r0
|
||||
bx lr
|
||||
|
@ -16,12 +16,13 @@
|
||||
// Uses Darwin calling convention where double precision arguments are passsed
|
||||
// like in GPR pairs.
|
||||
//
|
||||
.syntax unified
|
||||
.align 2
|
||||
DEFINE_COMPILERRT_FUNCTION(__eqdf2vfp)
|
||||
fmdrr d6, r0, r1 // load r0/r1 pair in double register
|
||||
fmdrr d7, r2, r3 // load r2/r3 pair in double register
|
||||
fcmpd d6, d7
|
||||
fmstat
|
||||
vmov d6, r0, r1 // load r0/r1 pair in double register
|
||||
vmov d7, r2, r3 // load r2/r3 pair in double register
|
||||
vcmp.f64 d6, d7
|
||||
vmrs apsr_nzcv, fpscr
|
||||
moveq r0, #1 // set result register to 1 if equal
|
||||
movne r0, #0
|
||||
bx lr
|
||||
|
@ -16,12 +16,13 @@
|
||||
// Uses Darwin calling convention where single precision arguments are passsed
|
||||
// like 32-bit ints
|
||||
//
|
||||
.syntax unified
|
||||
.align 2
|
||||
DEFINE_COMPILERRT_FUNCTION(__eqsf2vfp)
|
||||
fmsr s14, r0 // move from GPR 0 to float register
|
||||
fmsr s15, r1 // move from GPR 1 to float register
|
||||
fcmps s14, s15
|
||||
fmstat
|
||||
vmov s14, r0 // move from GPR 0 to float register
|
||||
vmov s15, r1 // move from GPR 1 to float register
|
||||
vcmp.f32 s14, s15
|
||||
vmrs apsr_nzcv, fpscr
|
||||
moveq r0, #1 // set result register to 1 if equal
|
||||
movne r0, #0
|
||||
bx lr
|
||||
|
@ -16,9 +16,10 @@
|
||||
// Uses Darwin calling convention where a single precision parameter is
|
||||
// passed in a GPR and a double precision result is returned in R0/R1 pair.
|
||||
//
|
||||
.syntax unified
|
||||
.align 2
|
||||
DEFINE_COMPILERRT_FUNCTION(__extendsfdf2vfp)
|
||||
fmsr s15, r0 // load float register from R0
|
||||
fcvtds d7, s15 // convert single to double
|
||||
fmrrd r0, r1, d7 // return result in r0/r1 pair
|
||||
vmov s15, r0 // load float register from R0
|
||||
vcvt.f64.f32 d7, s15 // convert single to double
|
||||
vmov r0, r1, d7 // return result in r0/r1 pair
|
||||
bx lr
|
||||
|
@ -16,9 +16,10 @@
|
||||
// Uses Darwin calling convention where a double precision parameter is
|
||||
// passed in GPR register pair.
|
||||
//
|
||||
.syntax unified
|
||||
.align 2
|
||||
DEFINE_COMPILERRT_FUNCTION(__fixdfsivfp)
|
||||
fmdrr d7, r0, r1 // load double register from R0/R1
|
||||
ftosizd s15, d7 // convert double to 32-bit int into s15
|
||||
fmrs r0, s15 // move s15 to result register
|
||||
vmov d7, r0, r1 // load double register from R0/R1
|
||||
vcvt.s32.f64 s15, d7 // convert double to 32-bit int into s15
|
||||
vmov r0, s15 // move s15 to result register
|
||||
bx lr
|
||||
|
@ -16,9 +16,10 @@
|
||||
// Uses Darwin calling convention where a single precision parameter is
|
||||
// passed in a GPR..
|
||||
//
|
||||
.syntax unified
|
||||
.align 2
|
||||
DEFINE_COMPILERRT_FUNCTION(__fixsfsivfp)
|
||||
fmsr s15, r0 // load float register from R0
|
||||
ftosizs s15, s15 // convert single to 32-bit int into s15
|
||||
fmrs r0, s15 // move s15 to result register
|
||||
vmov s15, r0 // load float register from R0
|
||||
vcvt.s32.f32 s15, s15 // convert single to 32-bit int into s15
|
||||
vmov r0, s15 // move s15 to result register
|
||||
bx lr
|
||||
|
@ -17,9 +17,10 @@
|
||||
// Uses Darwin calling convention where a double precision parameter is
|
||||
// passed in GPR register pair.
|
||||
//
|
||||
.syntax unified
|
||||
.align 2
|
||||
DEFINE_COMPILERRT_FUNCTION(__fixunsdfsivfp)
|
||||
fmdrr d7, r0, r1 // load double register from R0/R1
|
||||
ftouizd s15, d7 // convert double to 32-bit int into s15
|
||||
fmrs r0, s15 // move s15 to result register
|
||||
vmov d7, r0, r1 // load double register from R0/R1
|
||||
vcvt.u32.f64 s15, d7 // convert double to 32-bit int into s15
|
||||
vmov r0, s15 // move s15 to result register
|
||||
bx lr
|
||||
|
@ -17,9 +17,10 @@
|
||||
// Uses Darwin calling convention where a single precision parameter is
|
||||
// passed in a GPR..
|
||||
//
|
||||
.syntax unified
|
||||
.align 2
|
||||
DEFINE_COMPILERRT_FUNCTION(__fixunssfsivfp)
|
||||
fmsr s15, r0 // load float register from R0
|
||||
ftouizs s15, s15 // convert single to 32-bit unsigned into s15
|
||||
fmrs r0, s15 // move s15 to result register
|
||||
vmov s15, r0 // load float register from R0
|
||||
vcvt.u32.f32 s15, s15 // convert single to 32-bit unsigned into s15
|
||||
vmov r0, s15 // move s15 to result register
|
||||
bx lr
|
||||
|
@ -16,9 +16,10 @@
|
||||
// Uses Darwin calling convention where a double precision result is
|
||||
// return in GPR register pair.
|
||||
//
|
||||
.syntax unified
|
||||
.align 2
|
||||
DEFINE_COMPILERRT_FUNCTION(__floatsidfvfp)
|
||||
fmsr s15, r0 // move int to float register s15
|
||||
fsitod d7, s15 // convert 32-bit int in s15 to double in d7
|
||||
fmrrd r0, r1, d7 // move d7 to result register pair r0/r1
|
||||
vmov s15, r0 // move int to float register s15
|
||||
vcvt.f64.s32 d7, s15 // convert 32-bit int in s15 to double in d7
|
||||
vmov r0, r1, d7 // move d7 to result register pair r0/r1
|
||||
bx lr
|
||||
|
@ -16,9 +16,10 @@
|
||||
// Uses Darwin calling convention where a single precision result is
|
||||
// return in a GPR..
|
||||
//
|
||||
.syntax unified
|
||||
.align 2
|
||||
DEFINE_COMPILERRT_FUNCTION(__floatsisfvfp)
|
||||
fmsr s15, r0 // move int to float register s15
|
||||
fsitos s15, s15 // convert 32-bit int in s15 to float in s15
|
||||
fmrs r0, s15 // move s15 to result register
|
||||
vmov s15, r0 // move int to float register s15
|
||||
vcvt.f32.s32 s15, s15 // convert 32-bit int in s15 to float in s15
|
||||
vmov r0, s15 // move s15 to result register
|
||||
bx lr
|
||||
|
@ -16,9 +16,10 @@
|
||||
// Uses Darwin calling convention where a double precision result is
|
||||
// return in GPR register pair.
|
||||
//
|
||||
.syntax unified
|
||||
.align 2
|
||||
DEFINE_COMPILERRT_FUNCTION(__floatunssidfvfp)
|
||||
fmsr s15, r0 // move int to float register s15
|
||||
fuitod d7, s15 // convert 32-bit int in s15 to double in d7
|
||||
fmrrd r0, r1, d7 // move d7 to result register pair r0/r1
|
||||
vmov s15, r0 // move int to float register s15
|
||||
vcvt.f64.u32 d7, s15 // convert 32-bit int in s15 to double in d7
|
||||
vmov r0, r1, d7 // move d7 to result register pair r0/r1
|
||||
bx lr
|
||||
|
@ -16,9 +16,10 @@
|
||||
// Uses Darwin calling convention where a single precision result is
|
||||
// return in a GPR..
|
||||
//
|
||||
.syntax unified
|
||||
.align 2
|
||||
DEFINE_COMPILERRT_FUNCTION(__floatunssisfvfp)
|
||||
fmsr s15, r0 // move int to float register s15
|
||||
fuitos s15, s15 // convert 32-bit int in s15 to float in s15
|
||||
fmrs r0, s15 // move s15 to result register
|
||||
vmov s15, r0 // move int to float register s15
|
||||
vcvt.f32.u32 s15, s15 // convert 32-bit int in s15 to float in s15
|
||||
vmov r0, s15 // move s15 to result register
|
||||
bx lr
|
||||
|
@ -16,12 +16,13 @@
|
||||
// Uses Darwin calling convention where double precision arguments are passsed
|
||||
// like in GPR pairs.
|
||||
//
|
||||
.syntax unified
|
||||
.align 2
|
||||
DEFINE_COMPILERRT_FUNCTION(__gedf2vfp)
|
||||
fmdrr d6, r0, r1 // load r0/r1 pair in double register
|
||||
fmdrr d7, r2, r3 // load r2/r3 pair in double register
|
||||
fcmpd d6, d7
|
||||
fmstat
|
||||
vmov d6, r0, r1 // load r0/r1 pair in double register
|
||||
vmov d7, r2, r3 // load r2/r3 pair in double register
|
||||
vcmp.f64 d6, d7
|
||||
vmrs apsr_nzcv, fpscr
|
||||
movge r0, #1 // set result register to 1 if greater than or equal
|
||||
movlt r0, #0
|
||||
bx lr
|
||||
|
@ -16,12 +16,13 @@
|
||||
// Uses Darwin calling convention where single precision arguments are passsed
|
||||
// like 32-bit ints
|
||||
//
|
||||
.syntax unified
|
||||
.align 2
|
||||
DEFINE_COMPILERRT_FUNCTION(__gesf2vfp)
|
||||
fmsr s14, r0 // move from GPR 0 to float register
|
||||
fmsr s15, r1 // move from GPR 1 to float register
|
||||
fcmps s14, s15
|
||||
fmstat
|
||||
vmov s14, r0 // move from GPR 0 to float register
|
||||
vmov s15, r1 // move from GPR 1 to float register
|
||||
vcmp.f32 s14, s15
|
||||
vmrs apsr_nzcv, fpscr
|
||||
movge r0, #1 // set result register to 1 if greater than or equal
|
||||
movlt r0, #0
|
||||
bx lr
|
||||
|
@ -16,12 +16,13 @@
|
||||
// Uses Darwin calling convention where double precision arguments are passsed
|
||||
// like in GPR pairs.
|
||||
//
|
||||
.syntax unified
|
||||
.align 2
|
||||
DEFINE_COMPILERRT_FUNCTION(__gtdf2vfp)
|
||||
fmdrr d6, r0, r1 // load r0/r1 pair in double register
|
||||
fmdrr d7, r2, r3 // load r2/r3 pair in double register
|
||||
fcmpd d6, d7
|
||||
fmstat
|
||||
vmov d6, r0, r1 // load r0/r1 pair in double register
|
||||
vmov d7, r2, r3 // load r2/r3 pair in double register
|
||||
vcmp.f64 d6, d7
|
||||
vmrs apsr_nzcv, fpscr
|
||||
movgt r0, #1 // set result register to 1 if equal
|
||||
movle r0, #0
|
||||
bx lr
|
||||
|
@ -16,12 +16,13 @@
|
||||
// Uses Darwin calling convention where single precision arguments are passsed
|
||||
// like 32-bit ints
|
||||
//
|
||||
.syntax unified
|
||||
.align 2
|
||||
DEFINE_COMPILERRT_FUNCTION(__gtsf2vfp)
|
||||
fmsr s14, r0 // move from GPR 0 to float register
|
||||
fmsr s15, r1 // move from GPR 1 to float register
|
||||
fcmps s14, s15
|
||||
fmstat
|
||||
vmov s14, r0 // move from GPR 0 to float register
|
||||
vmov s15, r1 // move from GPR 1 to float register
|
||||
vcmp.f32 s14, s15
|
||||
vmrs apsr_nzcv, fpscr
|
||||
movgt r0, #1 // set result register to 1 if equal
|
||||
movle r0, #0
|
||||
bx lr
|
||||
|
@ -16,12 +16,13 @@
|
||||
// Uses Darwin calling convention where double precision arguments are passsed
|
||||
// like in GPR pairs.
|
||||
//
|
||||
.syntax unified
|
||||
.align 2
|
||||
DEFINE_COMPILERRT_FUNCTION(__ledf2vfp)
|
||||
fmdrr d6, r0, r1 // load r0/r1 pair in double register
|
||||
fmdrr d7, r2, r3 // load r2/r3 pair in double register
|
||||
fcmpd d6, d7
|
||||
fmstat
|
||||
vmov d6, r0, r1 // load r0/r1 pair in double register
|
||||
vmov d7, r2, r3 // load r2/r3 pair in double register
|
||||
vcmp.f64 d6, d7
|
||||
vmrs apsr_nzcv, fpscr
|
||||
movls r0, #1 // set result register to 1 if equal
|
||||
movhi r0, #0
|
||||
bx lr
|
||||
|
@ -16,12 +16,13 @@
|
||||
// Uses Darwin calling convention where single precision arguments are passsed
|
||||
// like 32-bit ints
|
||||
//
|
||||
.syntax unified
|
||||
.align 2
|
||||
DEFINE_COMPILERRT_FUNCTION(__lesf2vfp)
|
||||
fmsr s14, r0 // move from GPR 0 to float register
|
||||
fmsr s15, r1 // move from GPR 1 to float register
|
||||
fcmps s14, s15
|
||||
fmstat
|
||||
vmov s14, r0 // move from GPR 0 to float register
|
||||
vmov s15, r1 // move from GPR 1 to float register
|
||||
vcmp.f32 s14, s15
|
||||
vmrs apsr_nzcv, fpscr
|
||||
movls r0, #1 // set result register to 1 if equal
|
||||
movhi r0, #0
|
||||
bx lr
|
||||
|
@ -16,12 +16,13 @@
|
||||
// Uses Darwin calling convention where double precision arguments are passsed
|
||||
// like in GPR pairs.
|
||||
//
|
||||
.syntax unified
|
||||
.align 2
|
||||
DEFINE_COMPILERRT_FUNCTION(__ltdf2vfp)
|
||||
fmdrr d6, r0, r1 // load r0/r1 pair in double register
|
||||
fmdrr d7, r2, r3 // load r2/r3 pair in double register
|
||||
fcmpd d6, d7
|
||||
fmstat
|
||||
vmov d6, r0, r1 // load r0/r1 pair in double register
|
||||
vmov d7, r2, r3 // load r2/r3 pair in double register
|
||||
vcmp.f64 d6, d7
|
||||
vmrs apsr_nzcv, fpscr
|
||||
movmi r0, #1 // set result register to 1 if equal
|
||||
movpl r0, #0
|
||||
bx lr
|
||||
|
@ -16,12 +16,13 @@
|
||||
// Uses Darwin calling convention where single precision arguments are passsed
|
||||
// like 32-bit ints
|
||||
//
|
||||
.syntax unified
|
||||
.align 2
|
||||
DEFINE_COMPILERRT_FUNCTION(__ltsf2vfp)
|
||||
fmsr s14, r0 // move from GPR 0 to float register
|
||||
fmsr s15, r1 // move from GPR 1 to float register
|
||||
fcmps s14, s15
|
||||
fmstat
|
||||
vmov s14, r0 // move from GPR 0 to float register
|
||||
vmov s15, r1 // move from GPR 1 to float register
|
||||
vcmp.f32 s14, s15
|
||||
vmrs apsr_nzcv, fpscr
|
||||
movmi r0, #1 // set result register to 1 if equal
|
||||
movpl r0, #0
|
||||
bx lr
|
||||
|
@ -15,10 +15,11 @@
|
||||
// Multiplies two double precision floating point numbers using the Darwin
|
||||
// calling convention where double arguments are passsed in GPR pairs
|
||||
//
|
||||
.syntax unified
|
||||
.align 2
|
||||
DEFINE_COMPILERRT_FUNCTION(__muldf3vfp)
|
||||
fmdrr d6, r0, r1 // move first param from r0/r1 pair into d6
|
||||
fmdrr d7, r2, r3 // move second param from r2/r3 pair into d7
|
||||
fmuld d6, d6, d7
|
||||
fmrrd r0, r1, d6 // move result back to r0/r1 pair
|
||||
vmov d6, r0, r1 // move first param from r0/r1 pair into d6
|
||||
vmov d7, r2, r3 // move second param from r2/r3 pair into d7
|
||||
vmul.f64 d6, d6, d7
|
||||
vmov r0, r1, d6 // move result back to r0/r1 pair
|
||||
bx lr
|
||||
|
@ -15,10 +15,11 @@
|
||||
// Multiplies two single precision floating point numbers using the Darwin
|
||||
// calling convention where single arguments are passsed like 32-bit ints.
|
||||
//
|
||||
.syntax unified
|
||||
.align 2
|
||||
DEFINE_COMPILERRT_FUNCTION(__mulsf3vfp)
|
||||
fmsr s14, r0 // move first param from r0 into float register
|
||||
fmsr s15, r1 // move second param from r1 into float register
|
||||
fmuls s13, s14, s15
|
||||
fmrs r0, s13 // move result back to r0
|
||||
vmov s14, r0 // move first param from r0 into float register
|
||||
vmov s15, r1 // move second param from r1 into float register
|
||||
vmul.f32 s13, s14, s15
|
||||
vmov r0, s13 // move result back to r0
|
||||
bx lr
|
||||
|
@ -16,12 +16,13 @@
|
||||
// Uses Darwin calling convention where double precision arguments are passsed
|
||||
// like in GPR pairs.
|
||||
//
|
||||
.syntax unified
|
||||
.align 2
|
||||
DEFINE_COMPILERRT_FUNCTION(__nedf2vfp)
|
||||
fmdrr d6, r0, r1 // load r0/r1 pair in double register
|
||||
fmdrr d7, r2, r3 // load r2/r3 pair in double register
|
||||
fcmpd d6, d7
|
||||
fmstat
|
||||
vmov d6, r0, r1 // load r0/r1 pair in double register
|
||||
vmov d7, r2, r3 // load r2/r3 pair in double register
|
||||
vcmp.f64 d6, d7
|
||||
vmrs apsr_nzcv, fpscr
|
||||
movne r0, #1 // set result register to 0 if unequal
|
||||
moveq r0, #0
|
||||
bx lr
|
||||
|
@ -15,6 +15,7 @@
|
||||
// Returns the negation a double precision floating point numbers using the
|
||||
// Darwin calling convention where double arguments are passsed in GPR pairs.
|
||||
//
|
||||
.syntax unified
|
||||
.align 2
|
||||
DEFINE_COMPILERRT_FUNCTION(__negdf2vfp)
|
||||
eor r1, r1, #-2147483648 // flip sign bit on double in r0/r1 pair
|
||||
|
@ -15,6 +15,7 @@
|
||||
// Returns the negation of a single precision floating point numbers using the
|
||||
// Darwin calling convention where single arguments are passsed like 32-bit ints
|
||||
//
|
||||
.syntax unified
|
||||
.align 2
|
||||
DEFINE_COMPILERRT_FUNCTION(__negsf2vfp)
|
||||
eor r0, r0, #-2147483648 // flip sign bit on float in r0
|
||||
|
@ -16,12 +16,13 @@
|
||||
// Uses Darwin calling convention where single precision arguments are passsed
|
||||
// like 32-bit ints
|
||||
//
|
||||
.syntax unified
|
||||
.align 2
|
||||
DEFINE_COMPILERRT_FUNCTION(__nesf2vfp)
|
||||
fmsr s14, r0 // move from GPR 0 to float register
|
||||
fmsr s15, r1 // move from GPR 1 to float register
|
||||
fcmps s14, s15
|
||||
fmstat
|
||||
vmov s14, r0 // move from GPR 0 to float register
|
||||
vmov s15, r1 // move from GPR 1 to float register
|
||||
vcmp.f32 s14, s15
|
||||
vmrs apsr_nzcv, fpscr
|
||||
movne r0, #1 // set result register to 1 if unequal
|
||||
moveq r0, #0
|
||||
bx lr
|
||||
|
@ -15,10 +15,11 @@
|
||||
// Returns difference between two double precision floating point numbers using
|
||||
// the Darwin calling convention where double arguments are passsed in GPR pairs
|
||||
//
|
||||
.syntax unified
|
||||
.align 2
|
||||
DEFINE_COMPILERRT_FUNCTION(__subdf3vfp)
|
||||
fmdrr d6, r0, r1 // move first param from r0/r1 pair into d6
|
||||
fmdrr d7, r2, r3 // move second param from r2/r3 pair into d7
|
||||
fsubd d6, d6, d7
|
||||
fmrrd r0, r1, d6 // move result back to r0/r1 pair
|
||||
vmov d6, r0, r1 // move first param from r0/r1 pair into d6
|
||||
vmov d7, r2, r3 // move second param from r2/r3 pair into d7
|
||||
vsub.f64 d6, d6, d7
|
||||
vmov r0, r1, d6 // move result back to r0/r1 pair
|
||||
bx lr
|
||||
|
@ -16,10 +16,11 @@
|
||||
// using the Darwin calling convention where single arguments are passsed
|
||||
// like 32-bit ints.
|
||||
//
|
||||
.syntax unified
|
||||
.align 2
|
||||
DEFINE_COMPILERRT_FUNCTION(__subsf3vfp)
|
||||
fmsr s14, r0 // move first param from r0 into float register
|
||||
fmsr s15, r1 // move second param from r1 into float register
|
||||
fsubs s14, s14, s15
|
||||
fmrs r0, s14 // move result back to r0
|
||||
vmov s14, r0 // move first param from r0 into float register
|
||||
vmov s15, r1 // move second param from r1 into float register
|
||||
vsub.f32 s14, s14, s15
|
||||
vmov r0, s14 // move result back to r0
|
||||
bx lr
|
||||
|
@ -16,9 +16,10 @@
|
||||
// Uses Darwin calling convention where a double precision parameter is
|
||||
// passed in a R0/R1 pair and a signle precision result is returned in R0.
|
||||
//
|
||||
.syntax unified
|
||||
.align 2
|
||||
DEFINE_COMPILERRT_FUNCTION(__truncdfsf2vfp)
|
||||
fmdrr d7, r0, r1 // load double from r0/r1 pair
|
||||
fcvtsd s15, d7 // convert double to single (trucate precision)
|
||||
fmrs r0, s15 // return result in r0
|
||||
vmov d7, r0, r1 // load double from r0/r1 pair
|
||||
vcvt.f32.f64 s15, d7 // convert double to single (trucate precision)
|
||||
vmov r0, s15 // return result in r0
|
||||
bx lr
|
||||
|
@ -16,12 +16,13 @@
|
||||
// Uses Darwin calling convention where double precision arguments are passsed
|
||||
// like in GPR pairs.
|
||||
//
|
||||
.syntax unified
|
||||
.align 2
|
||||
DEFINE_COMPILERRT_FUNCTION(__unorddf2vfp)
|
||||
fmdrr d6, r0, r1 // load r0/r1 pair in double register
|
||||
fmdrr d7, r2, r3 // load r2/r3 pair in double register
|
||||
fcmpd d6, d7
|
||||
fmstat
|
||||
vmov d6, r0, r1 // load r0/r1 pair in double register
|
||||
vmov d7, r2, r3 // load r2/r3 pair in double register
|
||||
vcmp.f64 d6, d7
|
||||
vmrs apsr_nzcv, fpscr
|
||||
movvs r0, #1 // set result register to 1 if "overflow" (any NaNs)
|
||||
movvc r0, #0
|
||||
bx lr
|
||||
|
@ -16,12 +16,13 @@
|
||||
// Uses Darwin calling convention where single precision arguments are passsed
|
||||
// like 32-bit ints
|
||||
//
|
||||
.syntax unified
|
||||
.align 2
|
||||
DEFINE_COMPILERRT_FUNCTION(__unordsf2vfp)
|
||||
fmsr s14, r0 // move from GPR 0 to float register
|
||||
fmsr s15, r1 // move from GPR 1 to float register
|
||||
fcmps s14, s15
|
||||
fmstat
|
||||
vmov s14, r0 // move from GPR 0 to float register
|
||||
vmov s15, r1 // move from GPR 1 to float register
|
||||
vcmp.f32 s14, s15
|
||||
vmrs apsr_nzcv, fpscr
|
||||
movvs r0, #1 // set result register to 1 if "overflow" (any NaNs)
|
||||
movvc r0, #0
|
||||
bx lr
|
||||
|
Some files were not shown because too many files have changed in this diff Show More
Loading…
Reference in New Issue
Block a user