summaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorRenato Botelho <renato@netgate.com>2016-08-17 15:23:38 -0300
committerRenato Botelho <renato@netgate.com>2016-08-17 15:23:38 -0300
commit75cd8d40056c799f03b759475d9bfd10ba266a6c (patch)
tree60433235501684bffeab90e65139a8285fcf46a9
parent99990a0d149f0eae805aa1f49d4a61be30c3b000 (diff)
parentad413762f28e3be343987e707b9cf4f10f963693 (diff)
downloadFreeBSD-src-75cd8d40056c799f03b759475d9bfd10ba266a6c.zip
FreeBSD-src-75cd8d40056c799f03b759475d9bfd10ba266a6c.tar.gz
Merge remote-tracking branch 'origin/stable/10' into devel
-rw-r--r--bin/ps/ps.14
-rw-r--r--cddl/contrib/opensolaris/cmd/zdb/zdb.811
-rw-r--r--cddl/contrib/opensolaris/cmd/zdb/zdb.c28
-rw-r--r--lib/libc/gen/glob.320
-rw-r--r--lib/libc/gen/glob.c528
-rw-r--r--lib/libc/sys/ptrace.2212
-rw-r--r--release/doc/share/xml/errata.xml56
-rwxr-xr-xrelease/release.sh8
-rw-r--r--sbin/pfctl/parse.y6
-rw-r--r--share/mk/bsd.README1
-rw-r--r--share/mk/bsd.progs.mk4
-rw-r--r--sys/amd64/amd64/initcpu.c14
-rw-r--r--sys/amd64/amd64/trap.c4
-rw-r--r--sys/cddl/contrib/opensolaris/uts/common/fs/zfs/arc.c20
-rw-r--r--sys/cddl/contrib/opensolaris/uts/common/fs/zfs/dbuf.c148
-rw-r--r--sys/cddl/contrib/opensolaris/uts/common/fs/zfs/dmu.c15
-rw-r--r--sys/cddl/contrib/opensolaris/uts/common/fs/zfs/dmu_objset.c8
-rw-r--r--sys/cddl/contrib/opensolaris/uts/common/fs/zfs/dnode_sync.c24
-rw-r--r--sys/cddl/contrib/opensolaris/uts/common/fs/zfs/dsl_scan.c24
-rw-r--r--sys/cddl/contrib/opensolaris/uts/common/fs/zfs/sys/arc.h10
-rw-r--r--sys/cddl/contrib/opensolaris/uts/common/fs/zfs/sys/dbuf.h3
-rw-r--r--sys/cddl/contrib/opensolaris/uts/common/fs/zfs/sys/zio.h10
-rw-r--r--sys/cddl/contrib/opensolaris/uts/common/fs/zfs/zfs_vfsops.c211
-rw-r--r--sys/cddl/contrib/opensolaris/uts/common/fs/zfs/zfs_vnops.c1
-rw-r--r--sys/cddl/contrib/opensolaris/uts/common/fs/zfs/zio.c31
-rw-r--r--sys/dev/mlx5/mlx5_en/mlx5_en_main.c7
-rw-r--r--sys/dev/usb/input/ukbd.c12
-rw-r--r--sys/dev/usb/usbdevs1
-rw-r--r--sys/dev/virtio/network/if_vtnet.c61
-rw-r--r--sys/dev/virtio/network/if_vtnetvar.h1
-rw-r--r--sys/fs/tmpfs/tmpfs_subr.c11
-rw-r--r--sys/i386/i386/trap.c4
-rw-r--r--sys/i386/linux/linux_ptrace.c4
-rw-r--r--sys/kern/kern_exec.c4
-rw-r--r--sys/kern/kern_exit.c9
-rw-r--r--sys/kern/kern_fork.c19
-rw-r--r--sys/kern/kern_kthread.c11
-rw-r--r--sys/kern/kern_sig.c56
-rw-r--r--sys/kern/kern_thr.c64
-rw-r--r--sys/kern/subr_syscall.c4
-rw-r--r--sys/kern/sys_process.c114
-rw-r--r--sys/netpfil/pf/pf_ioctl.c16
-rw-r--r--sys/sys/proc.h9
-rw-r--r--sys/sys/ptrace.h23
-rw-r--r--sys/vm/uma_core.c5
-rw-r--r--sys/vm/vm_page.c2
-rw-r--r--sys/vm/vm_pageout.c38
-rw-r--r--tests/sys/kern/ptrace_test.c391
-rw-r--r--usr.bin/getconf/getconf.14
-rw-r--r--usr.bin/getconf/progenv.gperf2
-rw-r--r--usr.bin/truss/syscalls.c2
51 files changed, 1716 insertions, 559 deletions
diff --git a/bin/ps/ps.1 b/bin/ps/ps.1
index 17bfa41..fdb4f1e 100644
--- a/bin/ps/ps.1
+++ b/bin/ps/ps.1
@@ -29,7 +29,7 @@
.\" @(#)ps.1 8.3 (Berkeley) 4/18/94
.\" $FreeBSD$
.\"
-.Dd December 9, 2014
+.Dd August 12, 2016
.Dt PS 1
.Os
.Sh NAME
@@ -310,7 +310,6 @@ the include file
.It Dv "P_ADVLOCK" Ta No "0x00001" Ta "Process may hold a POSIX advisory lock"
.It Dv "P_CONTROLT" Ta No "0x00002" Ta "Has a controlling terminal"
.It Dv "P_KTHREAD" Ta No "0x00004" Ta "Kernel thread"
-.It Dv "P_FOLLOWFORK" Ta No "0x00008" Ta "Attach debugger to new children"
.It Dv "P_PPWAIT" Ta No "0x00010" Ta "Parent is waiting for child to exec/exit"
.It Dv "P_PROFIL" Ta No "0x00020" Ta "Has started profiling"
.It Dv "P_STOPPROF" Ta No "0x00040" Ta "Has thread in requesting to stop prof"
@@ -348,6 +347,7 @@ the include file
.In sys/proc.h :
.Bl -column P2_INHERIT_PROTECTED 0x00000001
.It Dv "P2_INHERIT_PROTECTED" Ta No "0x00000001" Ta "New children get P_PROTECTED"
+.It Dv "P2_PTRACE_FSTP" Ta No "0x00000010" Ta "SIGSTOP from PT_ATTACH not yet handled"
.El
.It Cm label
The MAC label of the process.
diff --git a/cddl/contrib/opensolaris/cmd/zdb/zdb.8 b/cddl/contrib/opensolaris/cmd/zdb/zdb.8
index 4ef437e..6ae25c3 100644
--- a/cddl/contrib/opensolaris/cmd/zdb/zdb.8
+++ b/cddl/contrib/opensolaris/cmd/zdb/zdb.8
@@ -86,6 +86,17 @@ pool, and is inherently unstable.
The precise output of most invocations is not documented, a knowledge of ZFS
internals is assumed.
.Pp
+If the
+.Ar dataset
+argument does not contain any
+.Sy /
+or
+.Sy @
+characters, it is interpreted as a pool name.
+The root dataset can be specified as
+.Pa pool Ns Sy /
+(pool name followed by a slash).
+.Pp
When operating on an imported and active pool it is possible, though unlikely,
that zdb may interpret inconsistent pool data and behave erratically.
.Sh OPTIONS
diff --git a/cddl/contrib/opensolaris/cmd/zdb/zdb.c b/cddl/contrib/opensolaris/cmd/zdb/zdb.c
index 7c08c5f..c97cd36 100644
--- a/cddl/contrib/opensolaris/cmd/zdb/zdb.c
+++ b/cddl/contrib/opensolaris/cmd/zdb/zdb.c
@@ -3559,12 +3559,23 @@ main(int argc, char **argv)
nvlist_t *policy = NULL;
uint64_t max_txg = UINT64_MAX;
int rewind = ZPOOL_NEVER_REWIND;
+ char *spa_config_path_env;
+ boolean_t target_is_spa = B_TRUE;
(void) setrlimit(RLIMIT_NOFILE, &rl);
(void) enable_extended_FILE_stdio(-1, -1);
dprintf_setup(&argc, argv);
+ /*
+ * If there is an environment variable SPA_CONFIG_PATH it overrides
+ * default spa_config_path setting. If -U flag is specified it will
+ * override this environment variable settings once again.
+ */
+ spa_config_path_env = getenv("SPA_CONFIG_PATH");
+ if (spa_config_path_env != NULL)
+ spa_config_path = spa_config_path_env;
+
while ((c = getopt(argc, argv,
"bcdhilmMI:suCDRSAFLXx:evp:t:U:P")) != -1) {
switch (c) {
@@ -3729,8 +3740,23 @@ main(int argc, char **argv)
}
}
+ if (strpbrk(target, "/@") != NULL) {
+ size_t targetlen;
+
+ target_is_spa = B_FALSE;
+ /*
+ * Remove any trailing slash. Later code would get confused
+ * by it, but we want to allow it so that "pool/" can
+ * indicate that we want to dump the topmost filesystem,
+ * rather than the whole pool.
+ */
+ targetlen = strlen(target);
+ if (targetlen != 0 && target[targetlen - 1] == '/')
+ target[targetlen - 1] = '\0';
+ }
+
if (error == 0) {
- if (strpbrk(target, "/@") == NULL || dump_opt['R']) {
+ if (target_is_spa || dump_opt['R']) {
error = spa_open_rewind(target, &spa, FTAG, policy,
NULL);
if (error) {
diff --git a/lib/libc/gen/glob.3 b/lib/libc/gen/glob.3
index 468a73b..398c14b 100644
--- a/lib/libc/gen/glob.3
+++ b/lib/libc/gen/glob.3
@@ -275,24 +275,10 @@ is
.Pf non- Dv NULL ,
.Fn glob
calls
-.Fa \*(lp*errfunc\*(rp Ns ( Fa path , errno ) .
-This may be unintuitive: a pattern like
-.Ql */Makefile
-will try to
-.Xr stat 2
-.Ql foo/Makefile
-even if
-.Ql foo
-is not a directory, resulting in a
-call to
-.Fa errfunc .
-The error routine can suppress this action by testing for
-.Er ENOENT
-and
-.Er ENOTDIR ;
+.Fa \*(lp*errfunc\*(rp Ns ( Fa path , errno ) ,
however, the
.Dv GLOB_ERR
-flag will still cause an immediate
+flag will cause an immediate
return when this happens.
.Pp
If
@@ -377,7 +363,7 @@ file
.It Dv GLOB_NOSPACE
An attempt to allocate memory failed, or if
.Fa errno
-was 0
+was E2BIG,
.Dv GLOB_LIMIT
was specified in the flags and
.Fa pglob\->gl_matchc
diff --git a/lib/libc/gen/glob.c b/lib/libc/gen/glob.c
index 6c86297..5df0b74 100644
--- a/lib/libc/gen/glob.c
+++ b/lib/libc/gen/glob.c
@@ -71,7 +71,7 @@ __FBSDID("$FreeBSD$");
* 1. Patterns with illegal byte sequences match nothing - even if
* GLOB_NOCHECK is specified.
* 2. Illegal byte sequences in filenames are handled by treating them as
- * single-byte characters with a value of the first byte of the sequence
+ * single-byte characters with a values of such bytes of the sequence
* cast to wchar_t.
* 3. State-dependent encodings are not currently supported.
*/
@@ -113,25 +113,20 @@ struct glob_limit {
size_t l_string_cnt;
};
-#define DOLLAR '$'
-#define DOT '.'
-#define EOS '\0'
-#define LBRACKET '['
-#define NOT '!'
-#define QUESTION '?'
-#define QUOTE '\\'
-#define RANGE '-'
-#define RBRACKET ']'
-#define SEP '/'
-#define STAR '*'
-#define TILDE '~'
-#define UNDERSCORE '_'
-#define LBRACE '{'
-#define RBRACE '}'
-#define SLASH '/'
-#define COMMA ','
-
-#ifndef DEBUG
+#define DOT L'.'
+#define EOS L'\0'
+#define LBRACKET L'['
+#define NOT L'!'
+#define QUESTION L'?'
+#define QUOTE L'\\'
+#define RANGE L'-'
+#define RBRACKET L']'
+#define SEP L'/'
+#define STAR L'*'
+#define TILDE L'~'
+#define LBRACE L'{'
+#define RBRACE L'}'
+#define COMMA L','
#define M_QUOTE 0x8000000000ULL
#define M_PROTECT 0x4000000000ULL
@@ -140,28 +135,19 @@ struct glob_limit {
typedef uint_fast64_t Char;
-#else
-
-#define M_QUOTE 0x80
-#define M_PROTECT 0x40
-#define M_MASK 0xff
-#define M_CHAR 0x7f
-
-typedef char Char;
-
-#endif
-
-
#define CHAR(c) ((Char)((c)&M_CHAR))
#define META(c) ((Char)((c)|M_QUOTE))
-#define M_ALL META('*')
-#define M_END META(']')
-#define M_NOT META('!')
-#define M_ONE META('?')
-#define M_RNG META('-')
-#define M_SET META('[')
+#define UNPROT(c) ((c) & ~M_PROTECT)
+#define M_ALL META(L'*')
+#define M_END META(L']')
+#define M_NOT META(L'!')
+#define M_ONE META(L'?')
+#define M_RNG META(L'-')
+#define M_SET META(L'[')
#define ismeta(c) (((c)&M_QUOTE) != 0)
-
+#ifdef DEBUG
+#define isprot(c) (((c)&M_PROTECT) != 0)
+#endif
static int compare(const void *, const void *);
static int g_Ctoc(const Char *, char *, size_t);
@@ -172,19 +158,27 @@ static const Char *g_strchr(const Char *, wchar_t);
static Char *g_strcat(Char *, const Char *);
#endif
static int g_stat(Char *, struct stat *, glob_t *);
-static int glob0(const Char *, glob_t *, struct glob_limit *);
+static int glob0(const Char *, glob_t *, struct glob_limit *,
+ const char *);
static int glob1(Char *, glob_t *, struct glob_limit *);
static int glob2(Char *, Char *, Char *, Char *, glob_t *,
struct glob_limit *);
static int glob3(Char *, Char *, Char *, Char *, Char *, glob_t *,
struct glob_limit *);
-static int globextend(const Char *, glob_t *, struct glob_limit *);
+static int globextend(const Char *, glob_t *, struct glob_limit *,
+ const char *);
static const Char *
globtilde(const Char *, Char *, size_t, glob_t *);
+static int globexp0(const Char *, glob_t *, struct glob_limit *,
+ const char *);
static int globexp1(const Char *, glob_t *, struct glob_limit *);
-static int globexp2(const Char *, const Char *, glob_t *, int *,
+static int globexp2(const Char *, const Char *, glob_t *,
struct glob_limit *);
+static int globfinal(glob_t *, struct glob_limit *, size_t,
+ const char *);
static int match(Char *, Char *, Char *);
+static int err_nomatch(glob_t *, struct glob_limit *, const char *);
+static int err_aborted(glob_t *, int, char *);
#ifdef DEBUG
static void qprintf(const char *, Char *);
#endif
@@ -199,6 +193,7 @@ glob(const char * __restrict pattern, int flags,
mbstate_t mbs;
wchar_t wc;
size_t clen;
+ int too_long;
patnext = pattern;
if (!(flags & GLOB_APPEND)) {
@@ -218,24 +213,27 @@ glob(const char * __restrict pattern, int flags,
bufnext = patbuf;
bufend = bufnext + MAXPATHLEN - 1;
+ too_long = 1;
if (flags & GLOB_NOESCAPE) {
memset(&mbs, 0, sizeof(mbs));
- while (bufend - bufnext >= MB_CUR_MAX) {
+ while (bufnext <= bufend) {
clen = mbrtowc(&wc, patnext, MB_LEN_MAX, &mbs);
if (clen == (size_t)-1 || clen == (size_t)-2)
- return (GLOB_NOMATCH);
- else if (clen == 0)
+ return (err_nomatch(pglob, &limit, pattern));
+ else if (clen == 0) {
+ too_long = 0;
break;
+ }
*bufnext++ = wc;
patnext += clen;
}
} else {
/* Protect the quoted characters. */
memset(&mbs, 0, sizeof(mbs));
- while (bufend - bufnext >= MB_CUR_MAX) {
- if (*patnext == QUOTE) {
- if (*++patnext == EOS) {
- *bufnext++ = QUOTE | M_PROTECT;
+ while (bufnext <= bufend) {
+ if (*patnext == '\\') {
+ if (*++patnext == '\0') {
+ *bufnext++ = QUOTE;
continue;
}
prot = M_PROTECT;
@@ -243,19 +241,47 @@ glob(const char * __restrict pattern, int flags,
prot = 0;
clen = mbrtowc(&wc, patnext, MB_LEN_MAX, &mbs);
if (clen == (size_t)-1 || clen == (size_t)-2)
- return (GLOB_NOMATCH);
- else if (clen == 0)
+ return (err_nomatch(pglob, &limit, pattern));
+ else if (clen == 0) {
+ too_long = 0;
break;
+ }
*bufnext++ = wc | prot;
patnext += clen;
}
}
+ if (too_long)
+ return (err_nomatch(pglob, &limit, pattern));
*bufnext = EOS;
if (flags & GLOB_BRACE)
- return (globexp1(patbuf, pglob, &limit));
+ return (globexp0(patbuf, pglob, &limit, pattern));
else
- return (glob0(patbuf, pglob, &limit));
+ return (glob0(patbuf, pglob, &limit, pattern));
+}
+
+static int
+globexp0(const Char *pattern, glob_t *pglob, struct glob_limit *limit,
+ const char *origpat) {
+ int rv;
+ size_t oldpathc;
+
+ /* Protect a single {}, for find(1), like csh */
+ if (pattern[0] == LBRACE && pattern[1] == RBRACE && pattern[2] == EOS) {
+ if ((pglob->gl_flags & GLOB_LIMIT) &&
+ limit->l_brace_cnt++ >= GLOB_LIMIT_BRACE) {
+ errno = E2BIG;
+ return (GLOB_NOSPACE);
+ }
+ return (glob0(pattern, pglob, limit, origpat));
+ }
+
+ oldpathc = pglob->gl_pathc;
+
+ if ((rv = globexp1(pattern, pglob, limit)) != 0)
+ return rv;
+
+ return (globfinal(pglob, limit, oldpathc, origpat));
}
/*
@@ -266,24 +292,18 @@ glob(const char * __restrict pattern, int flags,
static int
globexp1(const Char *pattern, glob_t *pglob, struct glob_limit *limit)
{
- const Char* ptr = pattern;
- int rv;
+ const Char* ptr;
- if ((pglob->gl_flags & GLOB_LIMIT) &&
- limit->l_brace_cnt++ >= GLOB_LIMIT_BRACE) {
- errno = 0;
- return (GLOB_NOSPACE);
+ if ((ptr = g_strchr(pattern, LBRACE)) != NULL) {
+ if ((pglob->gl_flags & GLOB_LIMIT) &&
+ limit->l_brace_cnt++ >= GLOB_LIMIT_BRACE) {
+ errno = E2BIG;
+ return (GLOB_NOSPACE);
+ }
+ return (globexp2(ptr, pattern, pglob, limit));
}
- /* Protect a single {}, for find(1), like csh */
- if (pattern[0] == LBRACE && pattern[1] == RBRACE && pattern[2] == EOS)
- return glob0(pattern, pglob, limit);
-
- while ((ptr = g_strchr(ptr, LBRACE)) != NULL)
- if (!globexp2(ptr, pattern, pglob, &rv, limit))
- return rv;
-
- return glob0(pattern, pglob, limit);
+ return (glob0(pattern, pglob, limit, NULL));
}
@@ -293,10 +313,10 @@ globexp1(const Char *pattern, glob_t *pglob, struct glob_limit *limit)
* If it fails then it tries to glob the rest of the pattern and returns.
*/
static int
-globexp2(const Char *ptr, const Char *pattern, glob_t *pglob, int *rv,
+globexp2(const Char *ptr, const Char *pattern, glob_t *pglob,
struct glob_limit *limit)
{
- int i;
+ int i, rv;
Char *lm, *ls;
const Char *pe, *pm, *pm1, *pl;
Char patbuf[MAXPATHLEN];
@@ -308,7 +328,7 @@ globexp2(const Char *ptr, const Char *pattern, glob_t *pglob, int *rv,
ls = lm;
/* Find the balanced brace */
- for (i = 0, pe = ++ptr; *pe; pe++)
+ for (i = 0, pe = ++ptr; *pe != EOS; pe++)
if (*pe == LBRACKET) {
/* Ignore everything between [] */
for (pm = pe++; *pe != RBRACKET && *pe != EOS; pe++)
@@ -330,10 +350,8 @@ globexp2(const Char *ptr, const Char *pattern, glob_t *pglob, int *rv,
}
/* Non matching braces; just glob the pattern */
- if (i != 0 || *pe == EOS) {
- *rv = glob0(patbuf, pglob, limit);
- return (0);
- }
+ if (i != 0 || *pe == EOS)
+ return (glob0(pattern, pglob, limit, NULL));
for (i = 0, pl = pm = ptr; pm <= pe; pm++)
switch (*pm) {
@@ -378,7 +396,9 @@ globexp2(const Char *ptr, const Char *pattern, glob_t *pglob, int *rv,
#ifdef DEBUG
qprintf("globexp2:", patbuf);
#endif
- *rv = globexp1(patbuf, pglob, limit);
+ rv = globexp1(patbuf, pglob, limit);
+ if (rv)
+ return (rv);
/* move after the comma, to the next string */
pl = pm + 1;
@@ -388,7 +408,6 @@ globexp2(const Char *ptr, const Char *pattern, glob_t *pglob, int *rv,
default:
break;
}
- *rv = 0;
return (0);
}
@@ -401,9 +420,15 @@ static const Char *
globtilde(const Char *pattern, Char *patbuf, size_t patbuf_len, glob_t *pglob)
{
struct passwd *pwd;
- char *h;
+ char *h, *sc;
const Char *p;
Char *b, *eb;
+ wchar_t wc;
+ wchar_t wbuf[MAXPATHLEN];
+ wchar_t *wbufend, *dc;
+ size_t clen;
+ mbstate_t mbs;
+ int too_long;
if (*pattern != TILDE || !(pglob->gl_flags & GLOB_TILDE))
return (pattern);
@@ -412,13 +437,17 @@ globtilde(const Char *pattern, Char *patbuf, size_t patbuf_len, glob_t *pglob)
* Copy up to the end of the string or /
*/
eb = &patbuf[patbuf_len - 1];
- for (p = pattern + 1, h = (char *) patbuf;
- h < (char *)eb && *p && *p != SLASH; *h++ = *p++)
+ for (p = pattern + 1, b = patbuf;
+ b < eb && *p != EOS && UNPROT(*p) != SEP; *b++ = *p++)
continue;
- *h = EOS;
+ if (*p != EOS && UNPROT(*p) != SEP)
+ return (NULL);
+
+ *b = EOS;
+ h = NULL;
- if (((char *) patbuf)[0] == EOS) {
+ if (patbuf[0] == EOS) {
/*
* handle a plain ~ or ~/ by expanding $HOME first (iff
* we're not running setuid or setgid) and then trying
@@ -438,20 +467,56 @@ globtilde(const Char *pattern, Char *patbuf, size_t patbuf_len, glob_t *pglob)
/*
* Expand a ~user
*/
- if ((pwd = getpwnam((char*) patbuf)) == NULL)
+ if (g_Ctoc(patbuf, (char *)wbuf, sizeof(wbuf)))
+ return (NULL);
+ if ((pwd = getpwnam((char *)wbuf)) == NULL)
return (pattern);
else
h = pwd->pw_dir;
}
/* Copy the home directory */
- for (b = patbuf; b < eb && *h; *b++ = *h++)
+ dc = wbuf;
+ sc = h;
+ wbufend = wbuf + MAXPATHLEN - 1;
+ too_long = 1;
+ memset(&mbs, 0, sizeof(mbs));
+ while (dc <= wbufend) {
+ clen = mbrtowc(&wc, sc, MB_LEN_MAX, &mbs);
+ if (clen == (size_t)-1 || clen == (size_t)-2) {
+ /* XXX See initial comment #2. */
+ wc = (unsigned char)*sc;
+ clen = 1;
+ memset(&mbs, 0, sizeof(mbs));
+ }
+ if ((*dc++ = wc) == EOS) {
+ too_long = 0;
+ break;
+ }
+ sc += clen;
+ }
+ if (too_long)
+ return (NULL);
+
+ dc = wbuf;
+ for (b = patbuf; b < eb && *dc != EOS; *b++ = *dc++ | M_PROTECT)
continue;
+ if (*dc != EOS)
+ return (NULL);
/* Append the rest of the pattern */
- while (b < eb && (*b++ = *p++) != EOS)
- continue;
- *b = EOS;
+ if (*p != EOS) {
+ too_long = 1;
+ while (b <= eb) {
+ if ((*b++ = *p++) == EOS) {
+ too_long = 0;
+ break;
+ }
+ }
+ if (too_long)
+ return (NULL);
+ } else
+ *b = EOS;
return (patbuf);
}
@@ -464,14 +529,18 @@ globtilde(const Char *pattern, Char *patbuf, size_t patbuf_len, glob_t *pglob)
* if things went well, nonzero if errors occurred.
*/
static int
-glob0(const Char *pattern, glob_t *pglob, struct glob_limit *limit)
-{
+glob0(const Char *pattern, glob_t *pglob, struct glob_limit *limit,
+ const char *origpat) {
const Char *qpatnext;
int err;
size_t oldpathc;
Char *bufnext, c, patbuf[MAXPATHLEN];
qpatnext = globtilde(pattern, patbuf, MAXPATHLEN, pglob);
+ if (qpatnext == NULL) {
+ errno = E2BIG;
+ return (GLOB_NOSPACE);
+ }
oldpathc = pglob->gl_pathc;
bufnext = patbuf;
@@ -530,30 +599,29 @@ glob0(const Char *pattern, glob_t *pglob, struct glob_limit *limit)
if ((err = glob1(patbuf, pglob, limit)) != 0)
return(err);
- /*
- * If there was no match we are going to append the pattern
- * if GLOB_NOCHECK was specified or if GLOB_NOMAGIC was specified
- * and the pattern did not contain any magic characters
- * GLOB_NOMAGIC is there just for compatibility with csh.
- */
- if (pglob->gl_pathc == oldpathc) {
- if (((pglob->gl_flags & GLOB_NOCHECK) ||
- ((pglob->gl_flags & GLOB_NOMAGIC) &&
- !(pglob->gl_flags & GLOB_MAGCHAR))))
- return (globextend(pattern, pglob, limit));
- else
- return (GLOB_NOMATCH);
- }
+ if (origpat != NULL)
+ return (globfinal(pglob, limit, oldpathc, origpat));
+
+ return (0);
+}
+
+static int
+globfinal(glob_t *pglob, struct glob_limit *limit, size_t oldpathc,
+ const char *origpat) {
+ if (pglob->gl_pathc == oldpathc)
+ return (err_nomatch(pglob, limit, origpat));
+
if (!(pglob->gl_flags & GLOB_NOSORT))
qsort(pglob->gl_pathv + pglob->gl_offs + oldpathc,
pglob->gl_pathc - oldpathc, sizeof(char *), compare);
+
return (0);
}
static int
compare(const void *p, const void *q)
{
- return (strcmp(*(char **)p, *(char **)q));
+ return (strcoll(*(char **)p, *(char **)q));
}
static int
@@ -593,44 +661,47 @@ glob2(Char *pathbuf, Char *pathend, Char *pathend_last, Char *pattern,
if ((pglob->gl_flags & GLOB_LIMIT) &&
limit->l_stat_cnt++ >= GLOB_LIMIT_STAT) {
- errno = 0;
- if (pathend + 1 > pathend_last)
- return (GLOB_ABORTED);
- *pathend++ = SEP;
- *pathend = EOS;
+ errno = E2BIG;
return (GLOB_NOSPACE);
}
- if (((pglob->gl_flags & GLOB_MARK) &&
- pathend[-1] != SEP) && (S_ISDIR(sb.st_mode)
- || (S_ISLNK(sb.st_mode) &&
- (g_stat(pathbuf, &sb, pglob) == 0) &&
+ if ((pglob->gl_flags & GLOB_MARK) &&
+ UNPROT(pathend[-1]) != SEP &&
+ (S_ISDIR(sb.st_mode) ||
+ (S_ISLNK(sb.st_mode) &&
+ g_stat(pathbuf, &sb, pglob) == 0 &&
S_ISDIR(sb.st_mode)))) {
- if (pathend + 1 > pathend_last)
- return (GLOB_ABORTED);
+ if (pathend + 1 > pathend_last) {
+ errno = E2BIG;
+ return (GLOB_NOSPACE);
+ }
*pathend++ = SEP;
*pathend = EOS;
}
++pglob->gl_matchc;
- return (globextend(pathbuf, pglob, limit));
+ return (globextend(pathbuf, pglob, limit, NULL));
}
/* Find end of next segment, copy tentatively to pathend. */
q = pathend;
p = pattern;
- while (*p != EOS && *p != SEP) {
+ while (*p != EOS && UNPROT(*p) != SEP) {
if (ismeta(*p))
anymeta = 1;
- if (q + 1 > pathend_last)
- return (GLOB_ABORTED);
+ if (q + 1 > pathend_last) {
+ errno = E2BIG;
+ return (GLOB_NOSPACE);
+ }
*q++ = *p++;
}
if (!anymeta) { /* No expansion, do next segment. */
pathend = q;
pattern = p;
- while (*pattern == SEP) {
- if (pathend + 1 > pathend_last)
- return (GLOB_ABORTED);
+ while (UNPROT(*pattern) == SEP) {
+ if (pathend + 1 > pathend_last) {
+ errno = E2BIG;
+ return (GLOB_NOSPACE);
+ }
*pathend++ = *pattern++;
}
} else /* Need expansion, recurse. */
@@ -647,42 +718,44 @@ glob3(Char *pathbuf, Char *pathend, Char *pathend_last,
{
struct dirent *dp;
DIR *dirp;
- int err;
- char buf[MAXPATHLEN];
+ int err, too_long, saverrno, saverrno2;
+ char buf[MAXPATHLEN + MB_LEN_MAX - 1];
- /*
- * The readdirfunc declaration can't be prototyped, because it is
- * assigned, below, to two functions which are prototyped in glob.h
- * and dirent.h as taking pointers to differently typed opaque
- * structures.
- */
- struct dirent *(*readdirfunc)();
+ struct dirent *(*readdirfunc)(DIR *);
- if (pathend > pathend_last)
- return (GLOB_ABORTED);
+ if (pathend > pathend_last) {
+ errno = E2BIG;
+ return (GLOB_NOSPACE);
+ }
*pathend = EOS;
- errno = 0;
+ if (pglob->gl_errfunc != NULL &&
+ g_Ctoc(pathbuf, buf, sizeof(buf))) {
+ errno = E2BIG;
+ return (GLOB_NOSPACE);
+ }
+ saverrno = errno;
+ errno = 0;
if ((dirp = g_opendir(pathbuf, pglob)) == NULL) {
- /* TODO: don't call for ENOENT or ENOTDIR? */
- if (pglob->gl_errfunc) {
- if (g_Ctoc(pathbuf, buf, sizeof(buf)))
- return (GLOB_ABORTED);
- if (pglob->gl_errfunc(buf, errno) ||
- pglob->gl_flags & GLOB_ERR)
- return (GLOB_ABORTED);
- }
- return (0);
+ if (errno == ENOENT || errno == ENOTDIR)
+ return (0);
+ err = err_aborted(pglob, errno, buf);
+ if (errno == 0)
+ errno = saverrno;
+ return (err);
}
err = 0;
- /* Search directory for matching names. */
+ /* pglob->gl_readdir takes a void *, fix this manually */
if (pglob->gl_flags & GLOB_ALTDIRFUNC)
- readdirfunc = pglob->gl_readdir;
+ readdirfunc = (struct dirent *(*)(DIR *))pglob->gl_readdir;
else
readdirfunc = readdir;
- while ((dp = (*readdirfunc)(dirp))) {
+
+ errno = 0;
+ /* Search directory for matching names. */
+ while ((dp = (*readdirfunc)(dirp)) != NULL) {
char *sc;
Char *dc;
wchar_t wc;
@@ -691,49 +764,70 @@ glob3(Char *pathbuf, Char *pathend, Char *pathend_last,
if ((pglob->gl_flags & GLOB_LIMIT) &&
limit->l_readdir_cnt++ >= GLOB_LIMIT_READDIR) {
- errno = 0;
- if (pathend + 1 > pathend_last)
- err = GLOB_ABORTED;
- else {
- *pathend++ = SEP;
- *pathend = EOS;
- err = GLOB_NOSPACE;
- }
+ errno = E2BIG;
+ err = GLOB_NOSPACE;
break;
}
/* Initial DOT must be matched literally. */
- if (dp->d_name[0] == DOT && *pattern != DOT)
+ if (dp->d_name[0] == '.' && UNPROT(*pattern) != DOT) {
+ errno = 0;
continue;
+ }
memset(&mbs, 0, sizeof(mbs));
dc = pathend;
sc = dp->d_name;
- while (dc < pathend_last) {
+ too_long = 1;
+ while (dc <= pathend_last) {
clen = mbrtowc(&wc, sc, MB_LEN_MAX, &mbs);
if (clen == (size_t)-1 || clen == (size_t)-2) {
- wc = *sc;
+ /* XXX See initial comment #2. */
+ wc = (unsigned char)*sc;
clen = 1;
memset(&mbs, 0, sizeof(mbs));
}
- if ((*dc++ = wc) == EOS)
+ if ((*dc++ = wc) == EOS) {
+ too_long = 0;
break;
+ }
sc += clen;
}
- if (!match(pathend, pattern, restpattern)) {
+ if (too_long && (err = err_aborted(pglob, ENAMETOOLONG,
+ buf))) {
+ errno = ENAMETOOLONG;
+ break;
+ }
+ if (too_long || !match(pathend, pattern, restpattern)) {
*pathend = EOS;
+ errno = 0;
continue;
}
+ if (errno == 0)
+ errno = saverrno;
err = glob2(pathbuf, --dc, pathend_last, restpattern,
pglob, limit);
if (err)
break;
+ errno = 0;
}
+ saverrno2 = errno;
if (pglob->gl_flags & GLOB_ALTDIRFUNC)
(*pglob->gl_closedir)(dirp);
else
closedir(dirp);
- return (err);
+ errno = saverrno2;
+
+ if (err)
+ return (err);
+
+ if (dp == NULL && errno != 0 &&
+ (err = err_aborted(pglob, errno, buf)))
+ return (err);
+
+ if (errno == 0)
+ errno = saverrno;
+ return (0);
}
@@ -752,7 +846,8 @@ glob3(Char *pathbuf, Char *pathend, Char *pathend_last,
* gl_pathv points to (gl_offs + gl_pathc + 1) items.
*/
static int
-globextend(const Char *path, glob_t *pglob, struct glob_limit *limit)
+globextend(const Char *path, glob_t *pglob, struct glob_limit *limit,
+ const char *origpat)
{
char **pathv;
size_t i, newsize, len;
@@ -761,7 +856,7 @@ globextend(const Char *path, glob_t *pglob, struct glob_limit *limit)
if ((pglob->gl_flags & GLOB_LIMIT) &&
pglob->gl_matchc > limit->l_path_lim) {
- errno = 0;
+ errno = E2BIG;
return (GLOB_NOSPACE);
}
@@ -779,18 +874,26 @@ globextend(const Char *path, glob_t *pglob, struct glob_limit *limit)
}
pglob->gl_pathv = pathv;
- for (p = path; *p++;)
- continue;
- len = MB_CUR_MAX * (size_t)(p - path); /* XXX overallocation */
- limit->l_string_cnt += len;
- if ((pglob->gl_flags & GLOB_LIMIT) &&
- limit->l_string_cnt >= GLOB_LIMIT_STRING) {
- errno = 0;
- return (GLOB_NOSPACE);
+ if (origpat != NULL)
+ copy = strdup(origpat);
+ else {
+ for (p = path; *p++ != EOS;)
+ continue;
+ len = MB_CUR_MAX * (size_t)(p - path); /* XXX overallocation */
+ if ((copy = malloc(len)) != NULL) {
+ if (g_Ctoc(path, copy, len)) {
+ free(copy);
+ errno = E2BIG;
+ return (GLOB_NOSPACE);
+ }
+ }
}
- if ((copy = malloc(len)) != NULL) {
- if (g_Ctoc(path, copy, len)) {
+ if (copy != NULL) {
+ limit->l_string_cnt += strlen(copy) + 1;
+ if ((pglob->gl_flags & GLOB_LIMIT) &&
+ limit->l_string_cnt >= GLOB_LIMIT_STRING) {
free(copy);
+ errno = E2BIG;
return (GLOB_NOSPACE);
}
pathv[pglob->gl_offs + pglob->gl_pathc++] = copy;
@@ -830,15 +933,17 @@ match(Char *name, Char *pat, Char *patend)
ok = 0;
if ((k = *name++) == EOS)
return (0);
- if ((negate_range = ((*pat & M_MASK) == M_NOT)) != EOS)
+ if ((negate_range = ((*pat & M_MASK) == M_NOT)) != 0)
++pat;
while (((c = *pat++) & M_MASK) != M_END)
if ((*pat & M_MASK) == M_RNG) {
if (table->__collate_load_error ?
- CHAR(c) <= CHAR(k) && CHAR(k) <= CHAR(pat[1]) :
- __wcollate_range_cmp(CHAR(c), CHAR(k)) <= 0
- && __wcollate_range_cmp(CHAR(k), CHAR(pat[1])) <= 0
- )
+ CHAR(c) <= CHAR(k) &&
+ CHAR(k) <= CHAR(pat[1]) :
+ __wcollate_range_cmp(CHAR(c),
+ CHAR(k)) <= 0 &&
+ __wcollate_range_cmp(CHAR(k),
+ CHAR(pat[1])) <= 0)
ok = 1;
pat += 2;
} else if (c == k)
@@ -875,13 +980,15 @@ globfree(glob_t *pglob)
static DIR *
g_opendir(Char *str, glob_t *pglob)
{
- char buf[MAXPATHLEN];
+ char buf[MAXPATHLEN + MB_LEN_MAX - 1];
- if (!*str)
+ if (*str == EOS)
strcpy(buf, ".");
else {
- if (g_Ctoc(str, buf, sizeof(buf)))
+ if (g_Ctoc(str, buf, sizeof(buf))) {
+ errno = ENAMETOOLONG;
return (NULL);
+ }
}
if (pglob->gl_flags & GLOB_ALTDIRFUNC)
@@ -893,7 +1000,7 @@ g_opendir(Char *str, glob_t *pglob)
static int
g_lstat(Char *fn, struct stat *sb, glob_t *pglob)
{
- char buf[MAXPATHLEN];
+ char buf[MAXPATHLEN + MB_LEN_MAX - 1];
if (g_Ctoc(fn, buf, sizeof(buf))) {
errno = ENAMETOOLONG;
@@ -907,7 +1014,7 @@ g_lstat(Char *fn, struct stat *sb, glob_t *pglob)
static int
g_stat(Char *fn, struct stat *sb, glob_t *pglob)
{
- char buf[MAXPATHLEN];
+ char buf[MAXPATHLEN + MB_LEN_MAX - 1];
if (g_Ctoc(fn, buf, sizeof(buf))) {
errno = ENAMETOOLONG;
@@ -937,10 +1044,14 @@ g_Ctoc(const Char *str, char *buf, size_t len)
memset(&mbs, 0, sizeof(mbs));
while (len >= MB_CUR_MAX) {
- clen = wcrtomb(buf, *str, &mbs);
- if (clen == (size_t)-1)
- return (1);
- if (*str == L'\0')
+ clen = wcrtomb(buf, CHAR(*str), &mbs);
+ if (clen == (size_t)-1) {
+ /* XXX See initial comment #2. */
+ *buf = (char)CHAR(*str);
+ clen = 1;
+ memset(&mbs, 0, sizeof(mbs));
+ }
+ if (CHAR(*str) == EOS)
return (0);
str++;
buf += clen;
@@ -949,21 +1060,46 @@ g_Ctoc(const Char *str, char *buf, size_t len)
return (1);
}
+static int
+err_nomatch(glob_t *pglob, struct glob_limit *limit, const char *origpat) {
+ /*
+ * If there was no match we are going to append the origpat
+ * if GLOB_NOCHECK was specified or if GLOB_NOMAGIC was specified
+ * and the origpat did not contain any magic characters
+ * GLOB_NOMAGIC is there just for compatibility with csh.
+ */
+ if ((pglob->gl_flags & GLOB_NOCHECK) ||
+ ((pglob->gl_flags & GLOB_NOMAGIC) &&
+ !(pglob->gl_flags & GLOB_MAGCHAR)))
+ return (globextend(NULL, pglob, limit, origpat));
+ return (GLOB_NOMATCH);
+}
+
+static int
+err_aborted(glob_t *pglob, int err, char *buf) {
+ if ((pglob->gl_errfunc != NULL && pglob->gl_errfunc(buf, err)) ||
+ (pglob->gl_flags & GLOB_ERR))
+ return (GLOB_ABORTED);
+ return (0);
+}
+
#ifdef DEBUG
static void
qprintf(const char *str, Char *s)
{
Char *p;
- (void)printf("%s:\n", str);
- for (p = s; *p; p++)
- (void)printf("%c", CHAR(*p));
- (void)printf("\n");
- for (p = s; *p; p++)
- (void)printf("%c", *p & M_PROTECT ? '"' : ' ');
- (void)printf("\n");
- for (p = s; *p; p++)
- (void)printf("%c", ismeta(*p) ? '_' : ' ');
- (void)printf("\n");
+ (void)printf("%s\n", str);
+ if (s != NULL) {
+ for (p = s; *p != EOS; p++)
+ (void)printf("%c", (char)CHAR(*p));
+ (void)printf("\n");
+ for (p = s; *p != EOS; p++)
+ (void)printf("%c", (isprot(*p) ? '\\' : ' '));
+ (void)printf("\n");
+ for (p = s; *p != EOS; p++)
+ (void)printf("%c", (ismeta(*p) ? '_' : ' '));
+ (void)printf("\n");
+ }
}
#endif
diff --git a/lib/libc/sys/ptrace.2 b/lib/libc/sys/ptrace.2
index a94e314..fc5c0ea 100644
--- a/lib/libc/sys/ptrace.2
+++ b/lib/libc/sys/ptrace.2
@@ -2,7 +2,7 @@
.\" $NetBSD: ptrace.2,v 1.2 1995/02/27 12:35:37 cgd Exp $
.\"
.\" This file is in the public domain.
-.Dd October 20, 2015
+.Dd July 28, 2016
.Dt PTRACE 2
.Os
.Sh NAME
@@ -58,8 +58,9 @@ The signal may be a normal process signal, generated as a result of
traced process behavior, or use of the
.Xr kill 2
system call; alternatively, it may be generated by the tracing facility
-as a result of attaching, system calls, or stepping by the tracing
-process.
+as a result of attaching, stepping by the tracing
+process,
+or an event in the traced process.
The tracing process may choose to intercept the signal, using it to
observe process behavior (such as
.Dv SIGTRAP ) ,
@@ -69,6 +70,121 @@ The
system call
is the mechanism by which all this happens.
.Pp
+A traced process may report additional signal stops corresponding to
+events in the traced process.
+These additional signal stops are reported as
+.Dv SIGTRAP
+or
+.Dv SIGSTOP
+signals.
+The tracing process can use the
+.Dv PT_LWPINFO
+request to determine which events are associated with a
+.Dv SIGTRAP
+or
+.Dv SIGSTOP
+signal.
+Note that multiple events may be associated with a single signal.
+For example, events indicated by the
+.Dv PL_FLAG_BORN ,
+.Dv PL_FLAG_FORKED ,
+and
+.Dv PL_FLAG_EXEC
+flags are also reported as a system call exit event
+.Pq Dv PL_FLAG_SCX .
+The signal stop for a new child process enabled via
+.Dv PTRACE_FORK
+will report a
+.Dv SIGSTOP
+signal.
+All other additional signal stops use
+.Dv SIGTRAP .
+.Pp
+Each traced process has a tracing event mask.
+An event in the traced process only reports a
+signal stop if the corresponding flag is set in the tracing event mask.
+The current set of tracing event flags include:
+.Bl -tag -width ".Dv PTRACE_SYSCALL"
+.It Dv PTRACE_EXEC
+Report a stop for a successful invocation of
+.Xr execve 2 .
+This event is indicated by the
+.Dv PL_FLAG_EXEC
+flag in the
+.Va pl_flags
+member of
+.Vt "struct ptrace_lwpinfo" .
+.It Dv PTRACE_SCE
+Report a stop on each system call entry.
+This event is indicated by the
+.Dv PL_FLAG_SCE
+flag in the
+.Va pl_flags
+member of
+.Vt "struct ptrace_lwpinfo" .
+.It Dv PTRACE_SCX
+Report a stop on each system call exit.
+This event is indicated by the
+.Dv PL_FLAG_SCX
+flag in the
+.Va pl_flags
+member of
+.Vt "struct ptrace_lwpinfo" .
+.It Dv PTRACE_SYSCALL
+Report stops for both system call entry and exit.
+.It Dv PTRACE_FORK
+This event flag controls tracing for new child processes of a traced process.
+.Pp
+When this event flag is enabled,
+new child processes will enable tracing and stop before executing their
+first instruction.
+The new child process will include the
+.Dv PL_FLAG_CHILD
+flag in the
+.Va pl_flags
+member of
+.Vt "struct ptrace_lwpinfo" .
+The traced process will report a stop that includes the
+.Dv PL_FLAG_FORKED
+flag.
+The process ID of the new child process will also be present in the
+.Va pl_child_pid
+member of
+.Vt "struct ptrace_lwpinfo" .
+Note that new child processes will be attached with the default
+tracing event mask;
+they do not inherit the event mask of the traced process.
+.Pp
+When this event flag is not enabled,
+new child processes will execute without tracing enabled.
+.It Dv PTRACE_LWP
+This event flag controls tracing of LWP
+.Pq kernel thread
+creation and destruction.
+When this event is enabled,
+new LWPs will stop and report an event with
+.Dv PL_FLAG_BORN
+set before executing their first instruction,
+and exiting LWPs will stop and report an event with
+.Dv PL_FLAG_EXITED
+set before completing their termination.
+.Pp
+Note that new processes do not report an event for the creation of their
+initial thread,
+and exiting processes do not report an event for the termination of the
+last thread.
+.El
+.Pp
+The default tracing event mask when attaching to a process via
+.Dv PT_ATTACH ,
+.Dv PT_TRACE_ME ,
+or
+.Dv PTRACE_FORK
+includes only
+.Dv PTRACE_EXEC
+events.
+All other event flags are disabled.
+.Pp
The
.Fa request
argument specifies what operation is being performed; the meaning of
@@ -368,10 +484,23 @@ The process identifier of the new process is available in the
member of
.Vt "struct ptrace_lwpinfo" .
.It PL_FLAG_CHILD
-The flag is set for first event reported from a new child, which is
-automatically attached due to
-.Dv PT_FOLLOW_FORK
-enabled.
+The flag is set for first event reported from a new child which is
+automatically attached when
+.Dv PTRACE_FORK
+is enabled.
+.It PL_FLAG_BORN
+This flag is set for the first event reported from a new LWP when
+.Dv PTRACE_LWP
+is enabled.
+It is reported along with
+.Dv PL_FLAG_SCX .
+.It PL_FLAG_EXITED
+This flag is set for the last event reported by an exiting LWP when
+.Dv PTRACE_LWP
+is enabled.
+Note that this event is not reported when the last LWP in a process exits.
+The termination of the last thread is reported via a normal process exit
+event.
.El
.It pl_sigmask
The current signal mask of the LWP
@@ -442,27 +571,72 @@ This request will suspend the specified thread.
.It PT_RESUME
This request will resume the specified thread.
.It PT_TO_SCE
-This request will trace the specified process on each system call entry.
+This request will set the
+.Dv PTRACE_SCE
+event flag to trace all future system call entries and continue the process.
+The
+.Fa addr
+and
+.Fa data
+arguments are used the same as for
+.Dv PT_CONTINUE.
.It PT_TO_SCX
-This request will trace the specified process on each system call exit.
+This request will set the
+.Dv PTRACE_SCX
+event flag to trace all future system call exits and continue the process.
+The
+.Fa addr
+and
+.Fa data
+arguments are used the same as for
+.Dv PT_CONTINUE.
.It PT_SYSCALL
-This request will trace the specified process
-on each system call entry and exit.
+This request will set the
+.Dv PTRACE_SYSCALL
+event flag to trace all future system call entries and exits and continue
+the process.
+The
+.Fa addr
+and
+.Fa data
+arguments are used the same as for
+.Dv PT_CONTINUE.
.It PT_FOLLOW_FORK
This request controls tracing for new child processes of a traced process.
If
.Fa data
is non-zero,
-then new child processes will enable tracing and stop before executing their
-first instruction.
+.Dv PTRACE_FORK
+is set in the traced process's event tracing mask.
If
.Fa data
-is zero, then new child processes will execute without tracing enabled.
-By default, tracing is not enabled for new child processes.
-Child processes do not inherit this property.
-The traced process will set the
-.Dv PL_FLAG_FORKED
-flag upon exit from a system call that creates a new process.
+is zero,
+.Dv PTRACE_FORK
+is cleared from the traced process's event tracing mask.
+.It PT_LWP_EVENTS
+This request controls tracing of LWP creation and destruction.
+If
+.Fa data
+is non-zero,
+.Dv PTRACE_LWP
+is set in the traced process's event tracing mask.
+If
+.Fa data
+is zero,
+.Dv PTRACE_LWP
+is cleared from the traced process's event tracing mask.
+.It PT_GET_EVENT_MASK
+This request reads the traced process's event tracing mask into the
+integer pointed to by
+.Fa addr .
+The size of the integer must be passed in
+.Fa data .
+.It PT_SET_EVENT_MASK
+This request sets the traced process's event tracing mask from the
+integer pointed to by
+.Fa addr .
+The size of the integer must be passed in
+.Fa data .
.It PT_VM_TIMESTAMP
This request returns the generation number or timestamp of the memory map of
the traced process as the return value from
diff --git a/release/doc/share/xml/errata.xml b/release/doc/share/xml/errata.xml
index f5c93bc..a1453e9 100644
--- a/release/doc/share/xml/errata.xml
+++ b/release/doc/share/xml/errata.xml
@@ -48,6 +48,62 @@
<entry><para>Fix &man.freebsd-update.8; support of
&os;&nbsp;11.0-RELEASE</para></entry>
</row>
+
+ <row>
+ <entry><link
+ xlink:href="&security.url;/FreeBSD-EN-16:10.dhclient.asc">FreeBSD-EN-16:10.dhclient</link></entry>
+ <entry>11&nbsp;August&nbsp;2016</entry>
+ <entry><para>Better handle unknown options received from
+ aDHCP server</para></entry>
+ </row>
+
+ <row>
+ <entry><link
+ xlink:href="&security.url;/FreeBSD-EN-16:11.vmbus.asc">FreeBSD-EN-16:11.vmbus</link></entry>
+ <entry>11&nbsp;August&nbsp;2016</entry>
+ <entry><para>Avoid using spin locks for channel message
+ locks</para></entry>
+ </row>
+
+ <row>
+ <entry><link
+ xlink:href="&security.url;/FreeBSD-EN-16:12.hv_storvsc.asc">FreeBSD-EN-16:12.hv_storvsc</link></entry>
+ <entry>11&nbsp;August&nbsp;2016</entry>
+ <entry><para>Enable INQUIRY result check only on
+ Windows&nbsp;10 host systems</para></entry>
+ </row>
+
+ <row>
+ <entry><link
+ xlink:href="&security.url;/FreeBSD-EN-16:13.vmbus.asc">FreeBSD-EN-16:13.vmbus</link></entry>
+ <entry>11&nbsp;August&nbsp;2016</entry>
+ <entry><para>Register time counter early enough for TSC freq
+ calibration</para></entry>
+ </row>
+
+ <row>
+ <entry><link
+ xlink:href="&security.url;/FreeBSD-EN-16:14.hv_storvsc.asc">FreeBSD-EN-16:14.hv_storvsc</link></entry>
+ <entry>11&nbsp;August&nbsp;2016</entry>
+ <entry><para>Disable incorrect callout in
+ &man.hv.storvsc.4;</para></entry>
+ </row>
+
+ <row>
+ <entry><link
+ xlink:href="&security.url;/FreeBSD-EN-16:15.vmbus.asc">FreeBSD-EN-16:15.vmbus</link></entry>
+ <entry>11&nbsp;August&nbsp;2016</entry>
+ <entry><para>Better handle the GPADL setup failure in
+ Hyper-V</para></entry>
+ </row>
+
+ <row>
+ <entry><link
+ xlink:href="&security.url;/FreeBSD-EN-16:16.hv_storvsc.asc">FreeBSD-EN-16:16.hv_storvsc</link></entry>
+ <entry>11&nbsp;August&nbsp;2016</entry>
+ <entry><para>Fix SCSI INQUIRY checks and error
+ handling</para></entry>
+ </row>
</tbody>
</tgroup>
</informaltable>
diff --git a/release/release.sh b/release/release.sh
index caa6f26..6dc4a28 100755
--- a/release/release.sh
+++ b/release/release.sh
@@ -281,9 +281,15 @@ extra_chroot_setup() {
fi
if [ ! -z "${EMBEDDEDPORTS}" ]; then
+ _OSVERSION=$(chroot ${CHROOTDIR} /usr/bin/uname -U)
+ REVISION=$(chroot ${CHROOTDIR} make -C /usr/src/release -V REVISION)
+ BRANCH=$(chroot ${CHROOTDIR} make -C /usr/src/release -V BRANCH)
+ PBUILD_FLAGS="OSVERSION=${_OSVERSION} BATCH=yes"
+ PBUILD_FLAGS="${PBUILD_FLAGS} UNAME_r=${UNAME_r}"
+ PBUILD_FLAGS="${PBUILD_FLAGS} OSREL=${REVISION}"
for _PORT in ${EMBEDDEDPORTS}; do
eval chroot ${CHROOTDIR} make -C /usr/ports/${_PORT} \
- BATCH=1 FORCE_PKG_REGISTER=1 install clean distclean
+ FORCE_PKG_REGISTER=1 ${PBUILD_FLAGS} install clean distclean
done
fi
diff --git a/sbin/pfctl/parse.y b/sbin/pfctl/parse.y
index 16c7847..5c0becd 100644
--- a/sbin/pfctl/parse.y
+++ b/sbin/pfctl/parse.y
@@ -3718,8 +3718,8 @@ tos : STRING {
else if ($1[0] == '0' && $1[1] == 'x')
$$ = strtoul($1, NULL, 16);
else
- $$ = 0; /* flag bad argument */
- if (!$$ || $$ > 255) {
+ $$ = 256; /* flag bad argument */
+ if ($$ < 0 || $$ > 255) {
yyerror("illegal tos value %s", $1);
free($1);
YYERROR;
@@ -3728,7 +3728,7 @@ tos : STRING {
}
| NUMBER {
$$ = $1;
- if (!$$ || $$ > 255) {
+ if ($$ < 0 || $$ > 255) {
yyerror("illegal tos value %s", $1);
YYERROR;
}
diff --git a/share/mk/bsd.README b/share/mk/bsd.README
index 6872a6b..df973d5 100644
--- a/share/mk/bsd.README
+++ b/share/mk/bsd.README
@@ -272,6 +272,7 @@ PROGS_CXX PROG and PROGS_CXX in one Makefile. To define
- DEBUG_FLAGS
- DPADD
- DPSRCS
+ - INTERNALPROG (no installation)
- LDADD
- LDFLAGS
- LINKS
diff --git a/share/mk/bsd.progs.mk b/share/mk/bsd.progs.mk
index 69cb1bf..4bf5324 100644
--- a/share/mk/bsd.progs.mk
+++ b/share/mk/bsd.progs.mk
@@ -35,8 +35,8 @@ UPDATE_DEPENDFILE_PROG?= no
# just one of many
PROG_OVERRIDE_VARS += BINDIR BINGRP BINOWN BINMODE DPSRCS MAN NO_WERROR \
PROGNAME SRCS STRIP WARNS
-PROG_VARS += CFLAGS CXXFLAGS DEBUG_FLAGS DPADD LDADD LIBADD LINKS \
- LDFLAGS MLINKS ${PROG_OVERRIDE_VARS}
+PROG_VARS += CFLAGS CXXFLAGS DEBUG_FLAGS DPADD INTERNALPROG LDADD LIBADD \
+ LINKS LDFLAGS MLINKS ${PROG_OVERRIDE_VARS}
.for v in ${PROG_VARS:O:u}
.if empty(${PROG_OVERRIDE_VARS:M$v})
.if defined(${v}.${PROG})
diff --git a/sys/amd64/amd64/initcpu.c b/sys/amd64/amd64/initcpu.c
index 8868cd3..e20a271 100644
--- a/sys/amd64/amd64/initcpu.c
+++ b/sys/amd64/amd64/initcpu.c
@@ -125,6 +125,20 @@ init_amd(void)
wrmsr(MSR_NB_CFG1, msr);
}
}
+
+ /*
+ * BIOS may configure Family 10h processors to convert WC+ cache type
+ * to CD. That can hurt performance of guest VMs using nested paging.
+ * The relevant MSR bit is not documented in the BKDG,
+ * the fix is borrowed from Linux.
+ */
+ if (CPUID_TO_FAMILY(cpu_id) == 0x10) {
+ if ((cpu_feature2 & CPUID2_HV) == 0) {
+ msr = rdmsr(0xc001102a);
+ msr &= ~((uint64_t)1 << 24);
+ wrmsr(0xc001102a, msr);
+ }
+ }
}
/*
diff --git a/sys/amd64/amd64/trap.c b/sys/amd64/amd64/trap.c
index 218c8cf..f487c44 100644
--- a/sys/amd64/amd64/trap.c
+++ b/sys/amd64/amd64/trap.c
@@ -448,8 +448,8 @@ trap(struct trapframe *frame)
goto out;
case T_DNA:
- KASSERT(!PCB_USER_FPU(td->td_pcb),
- ("Unregistered use of FPU in kernel"));
+ if (PCB_USER_FPU(td->td_pcb))
+ panic("Unregistered use of FPU in kernel");
fpudna();
goto out;
diff --git a/sys/cddl/contrib/opensolaris/uts/common/fs/zfs/arc.c b/sys/cddl/contrib/opensolaris/uts/common/fs/zfs/arc.c
index 9430037..1700194 100644
--- a/sys/cddl/contrib/opensolaris/uts/common/fs/zfs/arc.c
+++ b/sys/cddl/contrib/opensolaris/uts/common/fs/zfs/arc.c
@@ -21,7 +21,7 @@
/*
* Copyright (c) 2005, 2010, Oracle and/or its affiliates. All rights reserved.
* Copyright (c) 2012, Joyent, Inc. All rights reserved.
- * Copyright (c) 2011, 2015 by Delphix. All rights reserved.
+ * Copyright (c) 2011, 2016 by Delphix. All rights reserved.
* Copyright (c) 2014 by Saso Kiselkov. All rights reserved.
* Copyright 2015 Nexenta Systems, Inc. All rights reserved.
*/
@@ -782,6 +782,7 @@ typedef struct arc_write_callback arc_write_callback_t;
struct arc_write_callback {
void *awcb_private;
arc_done_func_t *awcb_ready;
+ arc_done_func_t *awcb_children_ready;
arc_done_func_t *awcb_physdone;
arc_done_func_t *awcb_done;
arc_buf_t *awcb_buf;
@@ -5045,6 +5046,15 @@ arc_write_ready(zio_t *zio)
hdr->b_flags |= ARC_FLAG_IO_IN_PROGRESS;
}
+static void
+arc_write_children_ready(zio_t *zio)
+{
+ arc_write_callback_t *callback = zio->io_private;
+ arc_buf_t *buf = callback->awcb_buf;
+
+ callback->awcb_children_ready(zio, buf, callback->awcb_private);
+}
+
/*
* The SPA calls this callback for each physical write that happens on behalf
* of a logical write. See the comment in dbuf_write_physdone() for details.
@@ -5141,7 +5151,8 @@ arc_write_done(zio_t *zio)
zio_t *
arc_write(zio_t *pio, spa_t *spa, uint64_t txg,
blkptr_t *bp, arc_buf_t *buf, boolean_t l2arc, boolean_t l2arc_compress,
- const zio_prop_t *zp, arc_done_func_t *ready, arc_done_func_t *physdone,
+ const zio_prop_t *zp, arc_done_func_t *ready,
+ arc_done_func_t *children_ready, arc_done_func_t *physdone,
arc_done_func_t *done, void *private, zio_priority_t priority,
int zio_flags, const zbookmark_phys_t *zb)
{
@@ -5161,13 +5172,16 @@ arc_write(zio_t *pio, spa_t *spa, uint64_t txg,
hdr->b_flags |= ARC_FLAG_L2COMPRESS;
callback = kmem_zalloc(sizeof (arc_write_callback_t), KM_SLEEP);
callback->awcb_ready = ready;
+ callback->awcb_children_ready = children_ready;
callback->awcb_physdone = physdone;
callback->awcb_done = done;
callback->awcb_private = private;
callback->awcb_buf = buf;
zio = zio_write(pio, spa, txg, bp, buf->b_data, hdr->b_size, zp,
- arc_write_ready, arc_write_physdone, arc_write_done, callback,
+ arc_write_ready,
+ (children_ready != NULL) ? arc_write_children_ready : NULL,
+ arc_write_physdone, arc_write_done, callback,
priority, zio_flags, zb);
return (zio);
diff --git a/sys/cddl/contrib/opensolaris/uts/common/fs/zfs/dbuf.c b/sys/cddl/contrib/opensolaris/uts/common/fs/zfs/dbuf.c
index 2f26e9fb..9d5c398 100644
--- a/sys/cddl/contrib/opensolaris/uts/common/fs/zfs/dbuf.c
+++ b/sys/cddl/contrib/opensolaris/uts/common/fs/zfs/dbuf.c
@@ -481,13 +481,49 @@ dbuf_verify(dmu_buf_impl_t *db)
* If the blkptr isn't set but they have nonzero data,
* it had better be dirty, otherwise we'll lose that
* data when we evict this buffer.
+ *
+ * There is an exception to this rule for indirect blocks; in
+ * this case, if the indirect block is a hole, we fill in a few
+ * fields on each of the child blocks (importantly, birth time)
+ * to prevent hole birth times from being lost when you
+ * partially fill in a hole.
*/
if (db->db_dirtycnt == 0) {
- uint64_t *buf = db->db.db_data;
- int i;
+ if (db->db_level == 0) {
+ uint64_t *buf = db->db.db_data;
+ int i;
- for (i = 0; i < db->db.db_size >> 3; i++) {
- ASSERT(buf[i] == 0);
+ for (i = 0; i < db->db.db_size >> 3; i++) {
+ ASSERT(buf[i] == 0);
+ }
+ } else {
+ blkptr_t *bps = db->db.db_data;
+ ASSERT3U(1 << DB_DNODE(db)->dn_indblkshift, ==,
+ db->db.db_size);
+ /*
+ * We want to verify that all the blkptrs in the
+ * indirect block are holes, but we may have
+ * automatically set up a few fields for them.
+ * We iterate through each blkptr and verify
+ * they only have those fields set.
+ */
+ for (int i = 0;
+ i < db->db.db_size / sizeof (blkptr_t);
+ i++) {
+ blkptr_t *bp = &bps[i];
+ ASSERT(ZIO_CHECKSUM_IS_ZERO(
+ &bp->blk_cksum));
+ ASSERT(
+ DVA_IS_EMPTY(&bp->blk_dva[0]) &&
+ DVA_IS_EMPTY(&bp->blk_dva[1]) &&
+ DVA_IS_EMPTY(&bp->blk_dva[2]));
+ ASSERT0(bp->blk_fill);
+ ASSERT0(bp->blk_pad[0]);
+ ASSERT0(bp->blk_pad[1]);
+ ASSERT(!BP_IS_EMBEDDED(bp));
+ ASSERT(BP_IS_HOLE(bp));
+ ASSERT0(bp->blk_phys_birth);
+ }
}
}
}
@@ -655,10 +691,31 @@ dbuf_read_impl(dmu_buf_impl_t *db, zio_t *zio, uint32_t flags)
BP_IS_HOLE(db->db_blkptr)))) {
arc_buf_contents_t type = DBUF_GET_BUFC_TYPE(db);
- DB_DNODE_EXIT(db);
dbuf_set_data(db, arc_buf_alloc(db->db_objset->os_spa,
db->db.db_size, db, type));
bzero(db->db.db_data, db->db.db_size);
+
+ if (db->db_blkptr != NULL && db->db_level > 0 &&
+ BP_IS_HOLE(db->db_blkptr) &&
+ db->db_blkptr->blk_birth != 0) {
+ blkptr_t *bps = db->db.db_data;
+ for (int i = 0; i < ((1 <<
+ DB_DNODE(db)->dn_indblkshift) / sizeof (blkptr_t));
+ i++) {
+ blkptr_t *bp = &bps[i];
+ ASSERT3U(BP_GET_LSIZE(db->db_blkptr), ==,
+ 1 << dn->dn_indblkshift);
+ BP_SET_LSIZE(bp,
+ BP_GET_LEVEL(db->db_blkptr) == 1 ?
+ dn->dn_datablksz :
+ BP_GET_LSIZE(db->db_blkptr));
+ BP_SET_TYPE(bp, BP_GET_TYPE(db->db_blkptr));
+ BP_SET_LEVEL(bp,
+ BP_GET_LEVEL(db->db_blkptr) - 1);
+ BP_SET_BIRTH(bp, db->db_blkptr->blk_birth, 0);
+ }
+ }
+ DB_DNODE_EXIT(db);
db->db_state = DB_CACHED;
mutex_exit(&db->db_mtx);
return;
@@ -2876,7 +2933,8 @@ dbuf_write_ready(zio_t *zio, arc_buf_t *buf, void *vdb)
uint64_t fill = 0;
int i;
- ASSERT3P(db->db_blkptr, ==, bp);
+ ASSERT3P(db->db_blkptr, !=, NULL);
+ ASSERT3P(&db->db_data_pending->dr_bp_copy, ==, bp);
DB_DNODE_ENTER(db);
dn = DB_DNODE(db);
@@ -2898,7 +2956,7 @@ dbuf_write_ready(zio_t *zio, arc_buf_t *buf, void *vdb)
#ifdef ZFS_DEBUG
if (db->db_blkid == DMU_SPILL_BLKID) {
ASSERT(dn->dn_phys->dn_flags & DNODE_FLAG_SPILL_BLKPTR);
- ASSERT(!(BP_IS_HOLE(db->db_blkptr)) &&
+ ASSERT(!(BP_IS_HOLE(bp)) &&
db->db_blkptr == &dn->dn_phys->dn_spill);
}
#endif
@@ -2939,6 +2997,49 @@ dbuf_write_ready(zio_t *zio, arc_buf_t *buf, void *vdb)
bp->blk_fill = fill;
mutex_exit(&db->db_mtx);
+
+ rw_enter(&dn->dn_struct_rwlock, RW_WRITER);
+ *db->db_blkptr = *bp;
+ rw_exit(&dn->dn_struct_rwlock);
+}
+
+/* ARGSUSED */
+/*
+ * This function gets called just prior to running through the compression
+ * stage of the zio pipeline. If we're an indirect block comprised of only
+ * holes, then we want this indirect to be compressed away to a hole. In
+ * order to do that we must zero out any information about the holes that
+ * this indirect points to prior to before we try to compress it.
+ */
+static void
+dbuf_write_children_ready(zio_t *zio, arc_buf_t *buf, void *vdb)
+{
+ dmu_buf_impl_t *db = vdb;
+ dnode_t *dn;
+ blkptr_t *bp;
+ uint64_t i;
+ int epbs;
+
+ ASSERT3U(db->db_level, >, 0);
+ DB_DNODE_ENTER(db);
+ dn = DB_DNODE(db);
+ epbs = dn->dn_phys->dn_indblkshift - SPA_BLKPTRSHIFT;
+
+ /* Determine if all our children are holes */
+ for (i = 0, bp = db->db.db_data; i < 1 << epbs; i++, bp++) {
+ if (!BP_IS_HOLE(bp))
+ break;
+ }
+
+ /*
+ * If all the children are holes, then zero them all out so that
+ * we may get compressed away.
+ */
+ if (i == 1 << epbs) {
+ /* didn't find any non-holes */
+ bzero(db->db.db_data, db->db.db_size);
+ }
+ DB_DNODE_EXIT(db);
}
/*
@@ -3117,6 +3218,8 @@ dbuf_write(dbuf_dirty_record_t *dr, arc_buf_t *data, dmu_tx_t *tx)
zio_t *zio;
int wp_flag = 0;
+ ASSERT(dmu_tx_is_syncing(tx));
+
DB_DNODE_ENTER(db);
dn = DB_DNODE(db);
os = dn->dn_objset;
@@ -3175,6 +3278,14 @@ dbuf_write(dbuf_dirty_record_t *dr, arc_buf_t *data, dmu_tx_t *tx)
dmu_write_policy(os, dn, db->db_level, wp_flag, &zp);
DB_DNODE_EXIT(db);
+ /*
+ * We copy the blkptr now (rather than when we instantiate the dirty
+ * record), because its value can change between open context and
+ * syncing context. We do not need to hold dn_struct_rwlock to read
+ * db_blkptr because we are in syncing context.
+ */
+ dr->dr_bp_copy = *db->db_blkptr;
+
if (db->db_level == 0 &&
dr->dt.dl.dr_override_state == DR_OVERRIDDEN) {
/*
@@ -3184,8 +3295,9 @@ dbuf_write(dbuf_dirty_record_t *dr, arc_buf_t *data, dmu_tx_t *tx)
void *contents = (data != NULL) ? data->b_data : NULL;
dr->dr_zio = zio_write(zio, os->os_spa, txg,
- db->db_blkptr, contents, db->db.db_size, &zp,
- dbuf_write_override_ready, NULL, dbuf_write_override_done,
+ &dr->dr_bp_copy, contents, db->db.db_size, &zp,
+ dbuf_write_override_ready, NULL, NULL,
+ dbuf_write_override_done,
dr, ZIO_PRIORITY_ASYNC_WRITE, ZIO_FLAG_MUSTSUCCEED, &zb);
mutex_enter(&db->db_mtx);
dr->dt.dl.dr_override_state = DR_NOT_OVERRIDDEN;
@@ -3196,15 +3308,27 @@ dbuf_write(dbuf_dirty_record_t *dr, arc_buf_t *data, dmu_tx_t *tx)
ASSERT(zp.zp_checksum == ZIO_CHECKSUM_OFF ||
zp.zp_checksum == ZIO_CHECKSUM_NOPARITY);
dr->dr_zio = zio_write(zio, os->os_spa, txg,
- db->db_blkptr, NULL, db->db.db_size, &zp,
- dbuf_write_nofill_ready, NULL, dbuf_write_nofill_done, db,
+ &dr->dr_bp_copy, NULL, db->db.db_size, &zp,
+ dbuf_write_nofill_ready, NULL, NULL,
+ dbuf_write_nofill_done, db,
ZIO_PRIORITY_ASYNC_WRITE,
ZIO_FLAG_MUSTSUCCEED | ZIO_FLAG_NODATA, &zb);
} else {
ASSERT(arc_released(data));
+
+ /*
+ * For indirect blocks, we want to setup the children
+ * ready callback so that we can properly handle an indirect
+ * block that only contains holes.
+ */
+ arc_done_func_t *children_ready_cb = NULL;
+ if (db->db_level != 0)
+ children_ready_cb = dbuf_write_children_ready;
+
dr->dr_zio = arc_write(zio, os->os_spa, txg,
- db->db_blkptr, data, DBUF_IS_L2CACHEABLE(db),
+ &dr->dr_bp_copy, data, DBUF_IS_L2CACHEABLE(db),
DBUF_IS_L2COMPRESSIBLE(db), &zp, dbuf_write_ready,
+ children_ready_cb,
dbuf_write_physdone, dbuf_write_done, db,
ZIO_PRIORITY_ASYNC_WRITE, ZIO_FLAG_MUSTSUCCEED, &zb);
}
diff --git a/sys/cddl/contrib/opensolaris/uts/common/fs/zfs/dmu.c b/sys/cddl/contrib/opensolaris/uts/common/fs/zfs/dmu.c
index d8d186c..9ce9665 100644
--- a/sys/cddl/contrib/opensolaris/uts/common/fs/zfs/dmu.c
+++ b/sys/cddl/contrib/opensolaris/uts/common/fs/zfs/dmu.c
@@ -20,7 +20,7 @@
*/
/*
* Copyright (c) 2005, 2010, Oracle and/or its affiliates. All rights reserved.
- * Copyright (c) 2011, 2015 by Delphix. All rights reserved.
+ * Copyright (c) 2011, 2016 by Delphix. All rights reserved.
*/
/* Copyright (c) 2013 by Saso Kiselkov. All rights reserved. */
/* Copyright (c) 2013, Joyent, Inc. All rights reserved. */
@@ -1590,10 +1590,11 @@ dmu_sync_late_arrival(zio_t *pio, objset_t *os, dmu_sync_cb_t *done, zgd_t *zgd,
dsa->dsa_zgd = zgd;
dsa->dsa_tx = tx;
- zio_nowait(zio_write(pio, os->os_spa, dmu_tx_get_txg(tx), zgd->zgd_bp,
- zgd->zgd_db->db_data, zgd->zgd_db->db_size, zp,
- dmu_sync_late_arrival_ready, NULL, dmu_sync_late_arrival_done, dsa,
- ZIO_PRIORITY_SYNC_WRITE, ZIO_FLAG_CANFAIL, zb));
+ zio_nowait(zio_write(pio, os->os_spa, dmu_tx_get_txg(tx),
+ zgd->zgd_bp, zgd->zgd_db->db_data, zgd->zgd_db->db_size,
+ zp, dmu_sync_late_arrival_ready, NULL,
+ NULL, dmu_sync_late_arrival_done, dsa, ZIO_PRIORITY_SYNC_WRITE,
+ ZIO_FLAG_CANFAIL, zb));
return (0);
}
@@ -1746,8 +1747,8 @@ dmu_sync(zio_t *pio, uint64_t txg, dmu_sync_cb_t *done, zgd_t *zgd)
zio_nowait(arc_write(pio, os->os_spa, txg,
bp, dr->dt.dl.dr_data, DBUF_IS_L2CACHEABLE(db),
DBUF_IS_L2COMPRESSIBLE(db), &zp, dmu_sync_ready,
- NULL, dmu_sync_done, dsa, ZIO_PRIORITY_SYNC_WRITE,
- ZIO_FLAG_CANFAIL, &zb));
+ NULL, NULL, dmu_sync_done, dsa,
+ ZIO_PRIORITY_SYNC_WRITE, ZIO_FLAG_CANFAIL, &zb));
return (0);
}
diff --git a/sys/cddl/contrib/opensolaris/uts/common/fs/zfs/dmu_objset.c b/sys/cddl/contrib/opensolaris/uts/common/fs/zfs/dmu_objset.c
index 367dbcb..82c5854 100644
--- a/sys/cddl/contrib/opensolaris/uts/common/fs/zfs/dmu_objset.c
+++ b/sys/cddl/contrib/opensolaris/uts/common/fs/zfs/dmu_objset.c
@@ -20,7 +20,7 @@
*/
/*
* Copyright (c) 2005, 2010, Oracle and/or its affiliates. All rights reserved.
- * Copyright (c) 2012, 2014 by Delphix. All rights reserved.
+ * Copyright (c) 2012, 2016 by Delphix. All rights reserved.
* Copyright (c) 2013 by Saso Kiselkov. All rights reserved.
* Copyright (c) 2013, Joyent, Inc. All rights reserved.
* Copyright (c) 2014 Spectra Logic Corporation, All rights reserved.
@@ -1116,9 +1116,9 @@ dmu_objset_sync(objset_t *os, zio_t *pio, dmu_tx_t *tx)
zio = arc_write(pio, os->os_spa, tx->tx_txg,
os->os_rootbp, os->os_phys_buf, DMU_OS_IS_L2CACHEABLE(os),
- DMU_OS_IS_L2COMPRESSIBLE(os), &zp, dmu_objset_write_ready,
- NULL, dmu_objset_write_done, os, ZIO_PRIORITY_ASYNC_WRITE,
- ZIO_FLAG_MUSTSUCCEED, &zb);
+ DMU_OS_IS_L2COMPRESSIBLE(os),
+ &zp, dmu_objset_write_ready, NULL, NULL, dmu_objset_write_done,
+ os, ZIO_PRIORITY_ASYNC_WRITE, ZIO_FLAG_MUSTSUCCEED, &zb);
/*
* Sync special dnodes - the parent IO for the sync is the root block
diff --git a/sys/cddl/contrib/opensolaris/uts/common/fs/zfs/dnode_sync.c b/sys/cddl/contrib/opensolaris/uts/common/fs/zfs/dnode_sync.c
index 9aee513..7179c41 100644
--- a/sys/cddl/contrib/opensolaris/uts/common/fs/zfs/dnode_sync.c
+++ b/sys/cddl/contrib/opensolaris/uts/common/fs/zfs/dnode_sync.c
@@ -21,7 +21,7 @@
/*
* Copyright (c) 2005, 2010, Oracle and/or its affiliates. All rights reserved.
- * Copyright (c) 2012, 2015 by Delphix. All rights reserved.
+ * Copyright (c) 2012, 2016 by Delphix. All rights reserved.
* Copyright (c) 2014 Spectra Logic Corporation, All rights reserved.
*/
@@ -60,20 +60,14 @@ dnode_increase_indirection(dnode_t *dn, dmu_tx_t *tx)
dprintf("os=%p obj=%llu, increase to %d\n", dn->dn_objset,
dn->dn_object, dn->dn_phys->dn_nlevels);
- /* check for existing blkptrs in the dnode */
- for (i = 0; i < nblkptr; i++)
- if (!BP_IS_HOLE(&dn->dn_phys->dn_blkptr[i]))
- break;
- if (i != nblkptr) {
- /* transfer dnode's block pointers to new indirect block */
- (void) dbuf_read(db, NULL, DB_RF_MUST_SUCCEED|DB_RF_HAVESTRUCT);
- ASSERT(db->db.db_data);
- ASSERT(arc_released(db->db_buf));
- ASSERT3U(sizeof (blkptr_t) * nblkptr, <=, db->db.db_size);
- bcopy(dn->dn_phys->dn_blkptr, db->db.db_data,
- sizeof (blkptr_t) * nblkptr);
- arc_buf_freeze(db->db_buf);
- }
+ /* transfer dnode's block pointers to new indirect block */
+ (void) dbuf_read(db, NULL, DB_RF_MUST_SUCCEED|DB_RF_HAVESTRUCT);
+ ASSERT(db->db.db_data);
+ ASSERT(arc_released(db->db_buf));
+ ASSERT3U(sizeof (blkptr_t) * nblkptr, <=, db->db.db_size);
+ bcopy(dn->dn_phys->dn_blkptr, db->db.db_data,
+ sizeof (blkptr_t) * nblkptr);
+ arc_buf_freeze(db->db_buf);
/* set dbuf's parent pointers to new indirect buf */
for (i = 0; i < nblkptr; i++) {
diff --git a/sys/cddl/contrib/opensolaris/uts/common/fs/zfs/dsl_scan.c b/sys/cddl/contrib/opensolaris/uts/common/fs/zfs/dsl_scan.c
index a157dfe..9880de9 100644
--- a/sys/cddl/contrib/opensolaris/uts/common/fs/zfs/dsl_scan.c
+++ b/sys/cddl/contrib/opensolaris/uts/common/fs/zfs/dsl_scan.c
@@ -56,7 +56,8 @@ typedef int (scan_cb_t)(dsl_pool_t *, const blkptr_t *,
static scan_cb_t dsl_scan_scrub_cb;
static void dsl_scan_cancel_sync(void *, dmu_tx_t *);
-static void dsl_scan_sync_state(dsl_scan_t *, dmu_tx_t *tx);
+static void dsl_scan_sync_state(dsl_scan_t *, dmu_tx_t *);
+static boolean_t dsl_scan_restarting(dsl_scan_t *, dmu_tx_t *);
unsigned int zfs_top_maxinflight = 32; /* maximum I/Os per top-level */
unsigned int zfs_resilver_delay = 2; /* number of ticks to delay resilver */
@@ -329,8 +330,15 @@ dsl_scan_done(dsl_scan_t *scn, boolean_t complete, dmu_tx_t *tx)
else
scn->scn_phys.scn_state = DSS_CANCELED;
- spa_history_log_internal(spa, "scan done", tx,
- "complete=%u", complete);
+ if (dsl_scan_restarting(scn, tx))
+ spa_history_log_internal(spa, "scan aborted, restarting", tx,
+ "errors=%llu", spa_get_errlog_size(spa));
+ else if (!complete)
+ spa_history_log_internal(spa, "scan cancelled", tx,
+ "errors=%llu", spa_get_errlog_size(spa));
+ else
+ spa_history_log_internal(spa, "scan done", tx,
+ "errors=%llu", spa_get_errlog_size(spa));
if (DSL_SCAN_IS_SCRUB_RESILVER(scn)) {
mutex_enter(&spa->spa_scrub_lock);
@@ -1485,8 +1493,7 @@ dsl_scan_sync(dsl_pool_t *dp, dmu_tx_t *tx)
* that we can restart an old-style scan while the pool is being
* imported (see dsl_scan_init).
*/
- if (scn->scn_restart_txg != 0 &&
- scn->scn_restart_txg <= tx->tx_txg) {
+ if (dsl_scan_restarting(scn, tx)) {
pool_scan_func_t func = POOL_SCAN_SCRUB;
dsl_scan_done(scn, B_FALSE, tx);
if (vdev_resilver_needed(spa->spa_root_vdev, NULL, NULL))
@@ -1913,3 +1920,10 @@ dsl_scan(dsl_pool_t *dp, pool_scan_func_t func)
return (dsl_sync_task(spa_name(spa), dsl_scan_setup_check,
dsl_scan_setup_sync, &func, 0, ZFS_SPACE_CHECK_NONE));
}
+
+static boolean_t
+dsl_scan_restarting(dsl_scan_t *scn, dmu_tx_t *tx)
+{
+ return (scn->scn_restart_txg != 0 &&
+ scn->scn_restart_txg <= tx->tx_txg);
+}
diff --git a/sys/cddl/contrib/opensolaris/uts/common/fs/zfs/sys/arc.h b/sys/cddl/contrib/opensolaris/uts/common/fs/zfs/sys/arc.h
index 04a80f7..714c528 100644
--- a/sys/cddl/contrib/opensolaris/uts/common/fs/zfs/sys/arc.h
+++ b/sys/cddl/contrib/opensolaris/uts/common/fs/zfs/sys/arc.h
@@ -20,7 +20,7 @@
*/
/*
* Copyright (c) 2005, 2010, Oracle and/or its affiliates. All rights reserved.
- * Copyright (c) 2012, 2014 by Delphix. All rights reserved.
+ * Copyright (c) 2012, 2016 by Delphix. All rights reserved.
* Copyright (c) 2013 by Saso Kiselkov. All rights reserved.
*/
@@ -141,9 +141,11 @@ int arc_read(zio_t *pio, spa_t *spa, const blkptr_t *bp,
arc_flags_t *arc_flags, const zbookmark_phys_t *zb);
zio_t *arc_write(zio_t *pio, spa_t *spa, uint64_t txg,
blkptr_t *bp, arc_buf_t *buf, boolean_t l2arc, boolean_t l2arc_compress,
- const zio_prop_t *zp, arc_done_func_t *ready, arc_done_func_t *physdone,
- arc_done_func_t *done, void *priv, zio_priority_t priority,
- int zio_flags, const zbookmark_phys_t *zb);
+ const zio_prop_t *zp,
+ arc_done_func_t *ready, arc_done_func_t *child_ready,
+ arc_done_func_t *physdone, arc_done_func_t *done,
+ void *priv, zio_priority_t priority, int zio_flags,
+ const zbookmark_phys_t *zb);
void arc_freed(spa_t *spa, const blkptr_t *bp);
void arc_set_callback(arc_buf_t *buf, arc_evict_func_t *func, void *priv);
diff --git a/sys/cddl/contrib/opensolaris/uts/common/fs/zfs/sys/dbuf.h b/sys/cddl/contrib/opensolaris/uts/common/fs/zfs/sys/dbuf.h
index 233d541..4964126 100644
--- a/sys/cddl/contrib/opensolaris/uts/common/fs/zfs/sys/dbuf.h
+++ b/sys/cddl/contrib/opensolaris/uts/common/fs/zfs/sys/dbuf.h
@@ -121,6 +121,9 @@ typedef struct dbuf_dirty_record {
/* How much space was changed to dsl_pool_dirty_space() for this? */
unsigned int dr_accounted;
+ /* A copy of the bp that points to us */
+ blkptr_t dr_bp_copy;
+
union dirty_types {
struct dirty_indirect {
diff --git a/sys/cddl/contrib/opensolaris/uts/common/fs/zfs/sys/zio.h b/sys/cddl/contrib/opensolaris/uts/common/fs/zfs/sys/zio.h
index 56c821a..fc7be5b 100644
--- a/sys/cddl/contrib/opensolaris/uts/common/fs/zfs/sys/zio.h
+++ b/sys/cddl/contrib/opensolaris/uts/common/fs/zfs/sys/zio.h
@@ -22,7 +22,7 @@
/*
* Copyright (c) 2005, 2010, Oracle and/or its affiliates. All rights reserved.
* Copyright 2011 Nexenta Systems, Inc. All rights reserved.
- * Copyright (c) 2012, 2014 by Delphix. All rights reserved.
+ * Copyright (c) 2012, 2016 by Delphix. All rights reserved.
* Copyright (c) 2013 by Saso Kiselkov. All rights reserved.
*/
@@ -436,6 +436,7 @@ struct zio {
/* Callback info */
zio_done_func_t *io_ready;
+ zio_done_func_t *io_children_ready;
zio_done_func_t *io_physdone;
zio_done_func_t *io_done;
void *io_private;
@@ -503,9 +504,10 @@ extern zio_t *zio_read(zio_t *pio, spa_t *spa, const blkptr_t *bp, void *data,
extern zio_t *zio_write(zio_t *pio, spa_t *spa, uint64_t txg, blkptr_t *bp,
void *data, uint64_t size, const zio_prop_t *zp,
- zio_done_func_t *ready, zio_done_func_t *physdone, zio_done_func_t *done,
- void *priv,
- zio_priority_t priority, enum zio_flag flags, const zbookmark_phys_t *zb);
+ zio_done_func_t *ready, zio_done_func_t *children_ready,
+ zio_done_func_t *physdone, zio_done_func_t *done,
+ void *priv, zio_priority_t priority, enum zio_flag flags,
+ const zbookmark_phys_t *zb);
extern zio_t *zio_rewrite(zio_t *pio, spa_t *spa, uint64_t txg, blkptr_t *bp,
void *data, uint64_t size, zio_done_func_t *done, void *priv,
diff --git a/sys/cddl/contrib/opensolaris/uts/common/fs/zfs/zfs_vfsops.c b/sys/cddl/contrib/opensolaris/uts/common/fs/zfs/zfs_vfsops.c
index 9bb6091..8523bc4 100644
--- a/sys/cddl/contrib/opensolaris/uts/common/fs/zfs/zfs_vfsops.c
+++ b/sys/cddl/contrib/opensolaris/uts/common/fs/zfs/zfs_vfsops.c
@@ -22,7 +22,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) 2012, 2014 by Delphix. All rights reserved.
+ * Copyright (c) 2012, 2015 by Delphix. All rights reserved.
* Copyright (c) 2014 Integros [integros.com]
*/
@@ -847,72 +847,46 @@ zfs_owner_overquota(zfsvfs_t *zfsvfs, znode_t *zp, boolean_t isgroup)
return (zfs_fuid_overquota(zfsvfs, isgroup, fuid));
}
-int
-zfsvfs_create(const char *osname, zfsvfs_t **zfvp)
+/*
+ * Associate this zfsvfs with the given objset, which must be owned.
+ * This will cache a bunch of on-disk state from the objset in the
+ * zfsvfs.
+ */
+static int
+zfsvfs_init(zfsvfs_t *zfsvfs, objset_t *os)
{
- objset_t *os;
- zfsvfs_t *zfsvfs;
- uint64_t zval;
- int i, error;
- uint64_t sa_obj;
-
- /*
- * XXX: Fix struct statfs so this isn't necessary!
- *
- * The 'osname' is used as the filesystem's special node, which means
- * it must fit in statfs.f_mntfromname, or else it can't be
- * enumerated, so libzfs_mnttab_find() returns NULL, which causes
- * 'zfs unmount' to think it's not mounted when it is.
- */
- if (strlen(osname) >= MNAMELEN)
- return (SET_ERROR(ENAMETOOLONG));
-
- zfsvfs = kmem_zalloc(sizeof (zfsvfs_t), KM_SLEEP);
-
- /*
- * We claim to always be readonly so we can open snapshots;
- * other ZPL code will prevent us from writing to snapshots.
- */
- error = dmu_objset_own(osname, DMU_OST_ZFS, B_TRUE, zfsvfs, &os);
- if (error) {
- kmem_free(zfsvfs, sizeof (zfsvfs_t));
- return (error);
- }
+ int error;
+ uint64_t val;
- /*
- * Initialize the zfs-specific filesystem structure.
- * Should probably make this a kmem cache, shuffle fields,
- * and just bzero up to z_hold_mtx[].
- */
- zfsvfs->z_vfs = NULL;
- zfsvfs->z_parent = zfsvfs;
zfsvfs->z_max_blksz = SPA_OLD_MAXBLOCKSIZE;
zfsvfs->z_show_ctldir = ZFS_SNAPDIR_VISIBLE;
zfsvfs->z_os = os;
error = zfs_get_zplprop(os, ZFS_PROP_VERSION, &zfsvfs->z_version);
- if (error) {
- goto out;
- } else if (zfsvfs->z_version >
+ if (error != 0)
+ return (error);
+ if (zfsvfs->z_version >
zfs_zpl_version_map(spa_version(dmu_objset_spa(os)))) {
(void) printf("Can't mount a version %lld file system "
"on a version %lld pool\n. Pool must be upgraded to mount "
"this file system.", (u_longlong_t)zfsvfs->z_version,
(u_longlong_t)spa_version(dmu_objset_spa(os)));
- error = SET_ERROR(ENOTSUP);
- goto out;
+ return (SET_ERROR(ENOTSUP));
}
- if ((error = zfs_get_zplprop(os, ZFS_PROP_NORMALIZE, &zval)) != 0)
- goto out;
- zfsvfs->z_norm = (int)zval;
+ error = zfs_get_zplprop(os, ZFS_PROP_NORMALIZE, &val);
+ if (error != 0)
+ return (error);
+ zfsvfs->z_norm = (int)val;
- if ((error = zfs_get_zplprop(os, ZFS_PROP_UTF8ONLY, &zval)) != 0)
- goto out;
- zfsvfs->z_utf8 = (zval != 0);
+ error = zfs_get_zplprop(os, ZFS_PROP_UTF8ONLY, &val);
+ if (error != 0)
+ return (error);
+ zfsvfs->z_utf8 = (val != 0);
- if ((error = zfs_get_zplprop(os, ZFS_PROP_CASE, &zval)) != 0)
- goto out;
- zfsvfs->z_case = (uint_t)zval;
+ error = zfs_get_zplprop(os, ZFS_PROP_CASE, &val);
+ if (error != 0)
+ return (error);
+ zfsvfs->z_case = (uint_t)val;
/*
* Fold case on file systems that are always or sometimes case
@@ -925,60 +899,99 @@ zfsvfs_create(const char *osname, zfsvfs_t **zfvp)
zfsvfs->z_use_fuids = USE_FUIDS(zfsvfs->z_version, zfsvfs->z_os);
zfsvfs->z_use_sa = USE_SA(zfsvfs->z_version, zfsvfs->z_os);
+ uint64_t sa_obj = 0;
if (zfsvfs->z_use_sa) {
/* should either have both of these objects or none */
error = zap_lookup(os, MASTER_NODE_OBJ, ZFS_SA_ATTRS, 8, 1,
&sa_obj);
- if (error)
- goto out;
- } else {
- /*
- * Pre SA versions file systems should never touch
- * either the attribute registration or layout objects.
- */
- sa_obj = 0;
+ if (error != 0)
+ return (error);
}
error = sa_setup(os, sa_obj, zfs_attr_table, ZPL_END,
&zfsvfs->z_attr_table);
- if (error)
- goto out;
+ if (error != 0)
+ return (error);
if (zfsvfs->z_version >= ZPL_VERSION_SA)
sa_register_update_callback(os, zfs_sa_upgrade);
error = zap_lookup(os, MASTER_NODE_OBJ, ZFS_ROOT_OBJ, 8, 1,
&zfsvfs->z_root);
- if (error)
- goto out;
+ if (error != 0)
+ return (error);
ASSERT(zfsvfs->z_root != 0);
error = zap_lookup(os, MASTER_NODE_OBJ, ZFS_UNLINKED_SET, 8, 1,
&zfsvfs->z_unlinkedobj);
- if (error)
- goto out;
+ if (error != 0)
+ return (error);
error = zap_lookup(os, MASTER_NODE_OBJ,
zfs_userquota_prop_prefixes[ZFS_PROP_USERQUOTA],
8, 1, &zfsvfs->z_userquota_obj);
- if (error && error != ENOENT)
- goto out;
+ if (error == ENOENT)
+ zfsvfs->z_userquota_obj = 0;
+ else if (error != 0)
+ return (error);
error = zap_lookup(os, MASTER_NODE_OBJ,
zfs_userquota_prop_prefixes[ZFS_PROP_GROUPQUOTA],
8, 1, &zfsvfs->z_groupquota_obj);
- if (error && error != ENOENT)
- goto out;
+ if (error == ENOENT)
+ zfsvfs->z_groupquota_obj = 0;
+ else if (error != 0)
+ return (error);
error = zap_lookup(os, MASTER_NODE_OBJ, ZFS_FUID_TABLES, 8, 1,
&zfsvfs->z_fuid_obj);
- if (error && error != ENOENT)
- goto out;
+ if (error == ENOENT)
+ zfsvfs->z_fuid_obj = 0;
+ else if (error != 0)
+ return (error);
error = zap_lookup(os, MASTER_NODE_OBJ, ZFS_SHARES_DIR, 8, 1,
&zfsvfs->z_shares_dir);
- if (error && error != ENOENT)
- goto out;
+ if (error == ENOENT)
+ zfsvfs->z_shares_dir = 0;
+ else if (error != 0)
+ return (error);
+
+ return (0);
+}
+
+int
+zfsvfs_create(const char *osname, zfsvfs_t **zfvp)
+{
+ objset_t *os;
+ zfsvfs_t *zfsvfs;
+ int error;
+
+ /*
+ * XXX: Fix struct statfs so this isn't necessary!
+ *
+ * The 'osname' is used as the filesystem's special node, which means
+ * it must fit in statfs.f_mntfromname, or else it can't be
+ * enumerated, so libzfs_mnttab_find() returns NULL, which causes
+ * 'zfs unmount' to think it's not mounted when it is.
+ */
+ if (strlen(osname) >= MNAMELEN)
+ return (SET_ERROR(ENAMETOOLONG));
+
+ zfsvfs = kmem_zalloc(sizeof (zfsvfs_t), KM_SLEEP);
+
+ /*
+ * We claim to always be readonly so we can open snapshots;
+ * other ZPL code will prevent us from writing to snapshots.
+ */
+ error = dmu_objset_own(osname, DMU_OST_ZFS, B_TRUE, zfsvfs, &os);
+ if (error) {
+ kmem_free(zfsvfs, sizeof (zfsvfs_t));
+ return (error);
+ }
+
+ zfsvfs->z_vfs = NULL;
+ zfsvfs->z_parent = zfsvfs;
mutex_init(&zfsvfs->z_znodes_lock, NULL, MUTEX_DEFAULT, NULL);
mutex_init(&zfsvfs->z_lock, NULL, MUTEX_DEFAULT, NULL);
@@ -987,17 +1000,19 @@ zfsvfs_create(const char *osname, zfsvfs_t **zfvp)
rrm_init(&zfsvfs->z_teardown_lock, B_FALSE);
rw_init(&zfsvfs->z_teardown_inactive_lock, NULL, RW_DEFAULT, NULL);
rw_init(&zfsvfs->z_fuid_lock, NULL, RW_DEFAULT, NULL);
- for (i = 0; i != ZFS_OBJ_MTX_SZ; i++)
+ for (int i = 0; i != ZFS_OBJ_MTX_SZ; i++)
mutex_init(&zfsvfs->z_hold_mtx[i], NULL, MUTEX_DEFAULT, NULL);
+ error = zfsvfs_init(zfsvfs, os);
+ if (error != 0) {
+ dmu_objset_disown(os, zfsvfs);
+ *zfvp = NULL;
+ kmem_free(zfsvfs, sizeof (zfsvfs_t));
+ return (error);
+ }
+
*zfvp = zfsvfs;
return (0);
-
-out:
- dmu_objset_disown(os, zfsvfs);
- *zfvp = NULL;
- kmem_free(zfsvfs, sizeof (zfsvfs_t));
- return (error);
}
static int
@@ -2199,7 +2214,6 @@ zfs_resume_fs(zfsvfs_t *zfsvfs, const char *osname)
{
int err;
znode_t *zp;
- uint64_t sa_obj = 0;
ASSERT(RRM_WRITE_HELD(&zfsvfs->z_teardown_lock));
ASSERT(RW_WRITE_HELD(&zfsvfs->z_teardown_inactive_lock));
@@ -2208,35 +2222,16 @@ zfs_resume_fs(zfsvfs_t *zfsvfs, const char *osname)
* We already own this, so just hold and rele it to update the
* objset_t, as the one we had before may have been evicted.
*/
- VERIFY0(dmu_objset_hold(osname, zfsvfs, &zfsvfs->z_os));
- VERIFY3P(zfsvfs->z_os->os_dsl_dataset->ds_owner, ==, zfsvfs);
- VERIFY(dsl_dataset_long_held(zfsvfs->z_os->os_dsl_dataset));
- dmu_objset_rele(zfsvfs->z_os, zfsvfs);
-
- /*
- * Make sure version hasn't changed
- */
-
- err = zfs_get_zplprop(zfsvfs->z_os, ZFS_PROP_VERSION,
- &zfsvfs->z_version);
-
- if (err)
- goto bail;
-
- err = zap_lookup(zfsvfs->z_os, MASTER_NODE_OBJ,
- ZFS_SA_ATTRS, 8, 1, &sa_obj);
-
- if (err && zfsvfs->z_version >= ZPL_VERSION_SA)
- goto bail;
+ objset_t *os;
+ VERIFY0(dmu_objset_hold(osname, zfsvfs, &os));
+ VERIFY3P(os->os_dsl_dataset->ds_owner, ==, zfsvfs);
+ VERIFY(dsl_dataset_long_held(os->os_dsl_dataset));
+ dmu_objset_rele(os, zfsvfs);
- if ((err = sa_setup(zfsvfs->z_os, sa_obj,
- zfs_attr_table, ZPL_END, &zfsvfs->z_attr_table)) != 0)
+ err = zfsvfs_init(zfsvfs, os);
+ if (err != 0)
goto bail;
- if (zfsvfs->z_version >= ZPL_VERSION_SA)
- sa_register_update_callback(zfsvfs->z_os,
- zfs_sa_upgrade);
-
VERIFY(zfsvfs_setup(zfsvfs, B_FALSE) == 0);
zfs_set_fuid_feature(zfsvfs);
diff --git a/sys/cddl/contrib/opensolaris/uts/common/fs/zfs/zfs_vnops.c b/sys/cddl/contrib/opensolaris/uts/common/fs/zfs/zfs_vnops.c
index b0f11ac..17179f6 100644
--- a/sys/cddl/contrib/opensolaris/uts/common/fs/zfs/zfs_vnops.c
+++ b/sys/cddl/contrib/opensolaris/uts/common/fs/zfs/zfs_vnops.c
@@ -2438,6 +2438,7 @@ top:
dmu_tx_hold_zap(tx, zfsvfs->z_unlinkedobj, FALSE, NULL);
zfs_sa_upgrade_txholds(tx, zp);
zfs_sa_upgrade_txholds(tx, dzp);
+ dmu_tx_mark_netfree(tx);
error = dmu_tx_assign(tx, waited ? TXG_WAITED : TXG_NOWAIT);
if (error) {
rw_exit(&zp->z_parent_lock);
diff --git a/sys/cddl/contrib/opensolaris/uts/common/fs/zfs/zio.c b/sys/cddl/contrib/opensolaris/uts/common/fs/zfs/zio.c
index 616aa79..98fd449 100644
--- a/sys/cddl/contrib/opensolaris/uts/common/fs/zfs/zio.c
+++ b/sys/cddl/contrib/opensolaris/uts/common/fs/zfs/zio.c
@@ -20,7 +20,7 @@
*/
/*
* Copyright (c) 2005, 2010, Oracle and/or its affiliates. All rights reserved.
- * Copyright (c) 2011, 2015 by Delphix. All rights reserved.
+ * Copyright (c) 2011, 2016 by Delphix. All rights reserved.
* Copyright (c) 2011 Nexenta Systems, Inc. All rights reserved.
* Copyright (c) 2014 Integros [integros.com]
*/
@@ -771,9 +771,10 @@ zio_read(zio_t *pio, spa_t *spa, const blkptr_t *bp,
zio_t *
zio_write(zio_t *pio, spa_t *spa, uint64_t txg, blkptr_t *bp,
void *data, uint64_t size, const zio_prop_t *zp,
- zio_done_func_t *ready, zio_done_func_t *physdone, zio_done_func_t *done,
- void *private,
- zio_priority_t priority, enum zio_flag flags, const zbookmark_phys_t *zb)
+ zio_done_func_t *ready, zio_done_func_t *children_ready,
+ zio_done_func_t *physdone, zio_done_func_t *done,
+ void *private, zio_priority_t priority, enum zio_flag flags,
+ const zbookmark_phys_t *zb)
{
zio_t *zio;
@@ -792,6 +793,7 @@ zio_write(zio_t *pio, spa_t *spa, uint64_t txg, blkptr_t *bp,
ZIO_DDT_CHILD_WRITE_PIPELINE : ZIO_WRITE_PIPELINE);
zio->io_ready = ready;
+ zio->io_children_ready = children_ready;
zio->io_physdone = physdone;
zio->io_prop = *zp;
@@ -1189,6 +1191,16 @@ zio_write_bp_init(zio_t *zio)
if (!IO_IS_ALLOCATING(zio))
return (ZIO_PIPELINE_CONTINUE);
+ if (zio->io_children_ready != NULL) {
+ /*
+ * Now that all our children are ready, run the callback
+ * associated with this zio in case it wants to modify the
+ * data to be written.
+ */
+ ASSERT3U(zp->zp_level, >, 0);
+ zio->io_children_ready(zio);
+ }
+
ASSERT(zio->io_child_type != ZIO_CHILD_DDT);
if (zio->io_bp_override) {
@@ -2118,9 +2130,9 @@ zio_write_gang_block(zio_t *pio)
zio_nowait(zio_write(zio, spa, txg, &gbh->zg_blkptr[g],
(char *)pio->io_data + (pio->io_size - resid), lsize, &zp,
- zio_write_gang_member_ready, NULL, NULL, &gn->gn_child[g],
- pio->io_priority, ZIO_GANG_CHILD_FLAGS(pio),
- &pio->io_bookmark));
+ zio_write_gang_member_ready, NULL, NULL, NULL,
+ &gn->gn_child[g], pio->io_priority,
+ ZIO_GANG_CHILD_FLAGS(pio), &pio->io_bookmark));
}
/*
@@ -2509,7 +2521,7 @@ zio_ddt_write(zio_t *zio)
dio = zio_write(zio, spa, txg, bp, zio->io_orig_data,
zio->io_orig_size, &czp, NULL, NULL,
- zio_ddt_ditto_write_done, dde, zio->io_priority,
+ NULL, zio_ddt_ditto_write_done, dde, zio->io_priority,
ZIO_DDT_CHILD_FLAGS(zio), &zio->io_bookmark);
zio_push_transform(dio, zio->io_data, zio->io_size, 0, NULL);
@@ -2530,7 +2542,8 @@ zio_ddt_write(zio_t *zio)
ddt_phys_addref(ddp);
} else {
cio = zio_write(zio, spa, txg, bp, zio->io_orig_data,
- zio->io_orig_size, zp, zio_ddt_child_write_ready, NULL,
+ zio->io_orig_size, zp,
+ zio_ddt_child_write_ready, NULL, NULL,
zio_ddt_child_write_done, dde, zio->io_priority,
ZIO_DDT_CHILD_FLAGS(zio), &zio->io_bookmark);
diff --git a/sys/dev/mlx5/mlx5_en/mlx5_en_main.c b/sys/dev/mlx5/mlx5_en/mlx5_en_main.c
index 4a8029b..03d9c15 100644
--- a/sys/dev/mlx5/mlx5_en/mlx5_en_main.c
+++ b/sys/dev/mlx5/mlx5_en/mlx5_en_main.c
@@ -3114,6 +3114,13 @@ mlx5e_destroy_ifp(struct mlx5_core_dev *mdev, void *vpriv)
/* don't allow more IOCTLs */
priv->gone = 1;
+ /*
+ * Clear the device description to avoid use after free,
+ * because the bsddev is not destroyed when this module is
+ * unloaded:
+ */
+ device_set_desc(mdev->pdev->dev.bsddev, NULL);
+
/* XXX wait a bit to allow IOCTL handlers to complete */
pause("W", hz);
diff --git a/sys/dev/usb/input/ukbd.c b/sys/dev/usb/input/ukbd.c
index 3ee6b8bf..506ee45 100644
--- a/sys/dev/usb/input/ukbd.c
+++ b/sys/dev/usb/input/ukbd.c
@@ -201,6 +201,7 @@ struct ukbd_softc {
int sc_mode; /* input mode (K_XLATE,K_RAW,K_CODE) */
int sc_state; /* shift/lock key state */
int sc_accents; /* accent key index (> 0) */
+ int sc_polling; /* polling recursion count */
int sc_led_size;
int sc_kbd_size;
@@ -1986,7 +1987,16 @@ ukbd_poll(keyboard_t *kbd, int on)
struct ukbd_softc *sc = kbd->kb_data;
UKBD_LOCK();
- if (on) {
+ /*
+ * Keep a reference count on polling to allow recursive
+ * cngrab() during a panic for example.
+ */
+ if (on)
+ sc->sc_polling++;
+ else
+ sc->sc_polling--;
+
+ if (sc->sc_polling != 0) {
sc->sc_flags |= UKBD_FLAG_POLLING;
sc->sc_poll_thread = curthread;
} else {
diff --git a/sys/dev/usb/usbdevs b/sys/dev/usb/usbdevs
index a53e15b..84db769 100644
--- a/sys/dev/usb/usbdevs
+++ b/sys/dev/usb/usbdevs
@@ -2726,6 +2726,7 @@ product LOGITECH BB13 0xc401 USB-PS/2 Trackball
product LOGITECH RK53 0xc501 Cordless mouse
product LOGITECH RB6 0xc503 Cordless keyboard
product LOGITECH MX700 0xc506 Cordless optical mouse
+product LOGITECH UNIFYING 0xc52b Logitech Unifying Receiver
product LOGITECH QUICKCAMPRO2 0xd001 QuickCam Pro
/* Logitec Corp. products */
diff --git a/sys/dev/virtio/network/if_vtnet.c b/sys/dev/virtio/network/if_vtnet.c
index a5e6383..8474edb 100644
--- a/sys/dev/virtio/network/if_vtnet.c
+++ b/sys/dev/virtio/network/if_vtnet.c
@@ -228,18 +228,32 @@ static void vtnet_disable_interrupts(struct vtnet_softc *);
static int vtnet_tunable_int(struct vtnet_softc *, const char *, int);
/* Tunables. */
+static SYSCTL_NODE(_hw, OID_AUTO, vtnet, CTLFLAG_RD, 0, "VNET driver parameters");
static int vtnet_csum_disable = 0;
TUNABLE_INT("hw.vtnet.csum_disable", &vtnet_csum_disable);
+SYSCTL_INT(_hw_vtnet, OID_AUTO, csum_disable, CTLFLAG_RDTUN,
+ &vtnet_csum_disable, 0, "Disables receive and send checksum offload");
static int vtnet_tso_disable = 0;
TUNABLE_INT("hw.vtnet.tso_disable", &vtnet_tso_disable);
+SYSCTL_INT(_hw_vtnet, OID_AUTO, tso_disable, CTLFLAG_RDTUN, &vtnet_tso_disable,
+ 0, "Disables TCP Segmentation Offload");
static int vtnet_lro_disable = 0;
TUNABLE_INT("hw.vtnet.lro_disable", &vtnet_lro_disable);
+SYSCTL_INT(_hw_vtnet, OID_AUTO, lro_disable, CTLFLAG_RDTUN, &vtnet_lro_disable,
+ 0, "Disables TCP Large Receive Offload");
static int vtnet_mq_disable = 0;
TUNABLE_INT("hw.vtnet.mq_disable", &vtnet_mq_disable);
-static int vtnet_mq_max_pairs = 0;
+SYSCTL_INT(_hw_vtnet, OID_AUTO, mq_disable, CTLFLAG_RDTUN, &vtnet_mq_disable,
+ 0, "Disables Multi Queue support");
+static int vtnet_mq_max_pairs = VTNET_MAX_QUEUE_PAIRS;
TUNABLE_INT("hw.vtnet.mq_max_pairs", &vtnet_mq_max_pairs);
+SYSCTL_INT(_hw_vtnet, OID_AUTO, mq_max_pairs, CTLFLAG_RDTUN,
+ &vtnet_mq_max_pairs, 0, "Sets the maximum number of Multi Queue pairs");
static int vtnet_rx_process_limit = 512;
TUNABLE_INT("hw.vtnet.rx_process_limit", &vtnet_rx_process_limit);
+SYSCTL_INT(_hw_vtnet, OID_AUTO, rx_process_limit, CTLFLAG_RDTUN,
+ &vtnet_rx_process_limit, 0,
+ "Limits the number RX segments processed in a single pass");
static uma_zone_t vtnet_tx_header_zone;
@@ -589,7 +603,6 @@ static void
vtnet_setup_features(struct vtnet_softc *sc)
{
device_t dev;
- int max_pairs, max;
dev = sc->vtnet_dev;
@@ -638,32 +651,31 @@ vtnet_setup_features(struct vtnet_softc *sc)
if (virtio_with_feature(dev, VIRTIO_NET_F_MQ) &&
sc->vtnet_flags & VTNET_FLAG_CTRL_VQ) {
- max_pairs = virtio_read_dev_config_2(dev,
+ sc->vtnet_max_vq_pairs = virtio_read_dev_config_2(dev,
offsetof(struct virtio_net_config, max_virtqueue_pairs));
- if (max_pairs < VIRTIO_NET_CTRL_MQ_VQ_PAIRS_MIN ||
- max_pairs > VIRTIO_NET_CTRL_MQ_VQ_PAIRS_MAX)
- max_pairs = 1;
} else
- max_pairs = 1;
+ sc->vtnet_max_vq_pairs = 1;
- if (max_pairs > 1) {
+ if (sc->vtnet_max_vq_pairs > 1) {
/*
- * Limit the maximum number of queue pairs to the number of
- * CPUs or the configured maximum. The actual number of
- * queues that get used may be less.
+ * Limit the maximum number of queue pairs to the lower of
+ * the number of CPUs and the configured maximum.
+ * The actual number of queues that get used may be less.
*/
+ int max;
+
max = vtnet_tunable_int(sc, "mq_max_pairs", vtnet_mq_max_pairs);
- if (max > 0 && max_pairs > max)
- max_pairs = max;
- if (max_pairs > mp_ncpus)
- max_pairs = mp_ncpus;
- if (max_pairs > VTNET_MAX_QUEUE_PAIRS)
- max_pairs = VTNET_MAX_QUEUE_PAIRS;
- if (max_pairs > 1)
- sc->vtnet_flags |= VTNET_FLAG_MULTIQ;
+ if (max > VIRTIO_NET_CTRL_MQ_VQ_PAIRS_MIN) {
+ if (max > mp_ncpus)
+ max = mp_ncpus;
+ if (max > VIRTIO_NET_CTRL_MQ_VQ_PAIRS_MAX)
+ max = VIRTIO_NET_CTRL_MQ_VQ_PAIRS_MAX;
+ if (max > 1) {
+ sc->vtnet_requested_vq_pairs = max;
+ sc->vtnet_flags |= VTNET_FLAG_MULTIQ;
+ }
+ }
}
-
- sc->vtnet_max_vq_pairs = max_pairs;
}
static int
@@ -2989,13 +3001,11 @@ vtnet_set_active_vq_pairs(struct vtnet_softc *sc)
dev = sc->vtnet_dev;
if ((sc->vtnet_flags & VTNET_FLAG_MULTIQ) == 0) {
- MPASS(sc->vtnet_max_vq_pairs == 1);
sc->vtnet_act_vq_pairs = 1;
return;
}
- /* BMV: Just use the maximum configured for now. */
- npairs = sc->vtnet_max_vq_pairs;
+ npairs = sc->vtnet_requested_vq_pairs;
if (vtnet_ctrl_mq_cmd(sc, npairs) != 0) {
device_printf(dev,
@@ -3851,6 +3861,9 @@ vtnet_setup_sysctl(struct vtnet_softc *sc)
SYSCTL_ADD_INT(ctx, child, OID_AUTO, "max_vq_pairs",
CTLFLAG_RD, &sc->vtnet_max_vq_pairs, 0,
"Maximum number of supported virtqueue pairs");
+ SYSCTL_ADD_INT(ctx, child, OID_AUTO, "requested_vq_pairs",
+ CTLFLAG_RD, &sc->vtnet_requested_vq_pairs, 0,
+ "Requested number of virtqueue pairs");
SYSCTL_ADD_INT(ctx, child, OID_AUTO, "act_vq_pairs",
CTLFLAG_RD, &sc->vtnet_act_vq_pairs, 0,
"Number of active virtqueue pairs");
diff --git a/sys/dev/virtio/network/if_vtnetvar.h b/sys/dev/virtio/network/if_vtnetvar.h
index f89f6b1..15436d9 100644
--- a/sys/dev/virtio/network/if_vtnetvar.h
+++ b/sys/dev/virtio/network/if_vtnetvar.h
@@ -155,6 +155,7 @@ struct vtnet_softc {
int vtnet_if_flags;
int vtnet_act_vq_pairs;
int vtnet_max_vq_pairs;
+ int vtnet_requested_vq_pairs;
struct virtqueue *vtnet_ctrl_vq;
struct vtnet_mac_filter *vtnet_mac_filter;
diff --git a/sys/fs/tmpfs/tmpfs_subr.c b/sys/fs/tmpfs/tmpfs_subr.c
index f06958e..9781b2c 100644
--- a/sys/fs/tmpfs/tmpfs_subr.c
+++ b/sys/fs/tmpfs/tmpfs_subr.c
@@ -818,10 +818,13 @@ tmpfs_dir_lookup_cookie(struct tmpfs_node *node, off_t cookie,
goto out;
}
- MPASS((cookie & TMPFS_DIRCOOKIE_MASK) == cookie);
- dekey.td_hash = cookie;
- /* Recover if direntry for cookie was removed */
- de = RB_NFIND(tmpfs_dir, dirhead, &dekey);
+ if ((cookie & TMPFS_DIRCOOKIE_MASK) != cookie) {
+ de = NULL;
+ } else {
+ dekey.td_hash = cookie;
+ /* Recover if direntry for cookie was removed */
+ de = RB_NFIND(tmpfs_dir, dirhead, &dekey);
+ }
dc->tdc_tree = de;
dc->tdc_current = de;
if (de != NULL && tmpfs_dirent_duphead(de)) {
diff --git a/sys/i386/i386/trap.c b/sys/i386/i386/trap.c
index 2fcf690..a186ff5 100644
--- a/sys/i386/i386/trap.c
+++ b/sys/i386/i386/trap.c
@@ -534,8 +534,8 @@ trap(struct trapframe *frame)
case T_DNA:
#ifdef DEV_NPX
- KASSERT(!PCB_USER_FPU(td->td_pcb),
- ("Unregistered use of FPU in kernel"));
+ if (PCB_USER_FPU(td->td_pcb))
+ panic("Unregistered use of FPU in kernel");
if (npxdna())
goto out;
#endif
diff --git a/sys/i386/linux/linux_ptrace.c b/sys/i386/linux/linux_ptrace.c
index 2925e6b..fbe66b4 100644
--- a/sys/i386/linux/linux_ptrace.c
+++ b/sys/i386/linux/linux_ptrace.c
@@ -69,7 +69,7 @@ __FBSDID("$FreeBSD$");
#define PTRACE_ATTACH 16
#define PTRACE_DETACH 17
-#define PTRACE_SYSCALL 24
+#define LINUX_PTRACE_SYSCALL 24
#define PTRACE_GETREGS 12
#define PTRACE_SETREGS 13
@@ -473,7 +473,7 @@ linux_ptrace(struct thread *td, struct linux_ptrace_args *uap)
break;
}
- case PTRACE_SYSCALL:
+ case LINUX_PTRACE_SYSCALL:
/* fall through */
default:
printf("linux: ptrace(%u, ...) not implemented\n",
diff --git a/sys/kern/kern_exec.c b/sys/kern/kern_exec.c
index 8357ab8..6b34066 100644
--- a/sys/kern/kern_exec.c
+++ b/sys/kern/kern_exec.c
@@ -55,6 +55,7 @@ __FBSDID("$FreeBSD$");
#include <sys/priv.h>
#include <sys/proc.h>
#include <sys/pioctl.h>
+#include <sys/ptrace.h>
#include <sys/namei.h>
#include <sys/resourcevar.h>
#include <sys/rwlock.h>
@@ -899,7 +900,8 @@ exec_fail_dealloc:
if (error == 0) {
PROC_LOCK(p);
- td->td_dbgflags |= TDB_EXEC;
+ if (p->p_ptevents & PTRACE_EXEC)
+ td->td_dbgflags |= TDB_EXEC;
PROC_UNLOCK(p);
/*
diff --git a/sys/kern/kern_exit.c b/sys/kern/kern_exit.c
index f9244af..c362530 100644
--- a/sys/kern/kern_exit.c
+++ b/sys/kern/kern_exit.c
@@ -336,6 +336,7 @@ exit1(struct thread *td, int rv)
rv = p->p_xstat; /* Event handler could change exit status */
stopprofclock(p);
p->p_flag &= ~(P_TRACED | P_PPWAIT | P_PPTRACE);
+ p->p_ptevents = 0;
/*
* Stop the real interval timer. If the handler is currently
@@ -519,8 +520,12 @@ exit1(struct thread *td, int rv)
*/
clear_orphan(q);
q->p_flag &= ~(P_TRACED | P_STOPPED_TRACE);
- FOREACH_THREAD_IN_PROC(q, tdt)
- tdt->td_dbgflags &= ~TDB_SUSPEND;
+ q->p_flag2 &= ~P2_PTRACE_FSTP;
+ q->p_ptevents = 0;
+ FOREACH_THREAD_IN_PROC(q, tdt) {
+ tdt->td_dbgflags &= ~(TDB_SUSPEND | TDB_XSIG |
+ TDB_FSTP);
+ }
kern_psignal(q, SIGKILL);
}
PROC_UNLOCK(q);
diff --git a/sys/kern/kern_fork.c b/sys/kern/kern_fork.c
index a84b619..4d96840 100644
--- a/sys/kern/kern_fork.c
+++ b/sys/kern/kern_fork.c
@@ -411,6 +411,7 @@ do_fork(struct thread *td, int flags, struct proc *p2, struct thread *td2,
__rangeof(struct proc, p_startzero, p_endzero));
p2->p_treeflag = 0;
p2->p_filemon = NULL;
+ p2->p_ptevents = 0;
/* Tell the prison that we exist. */
prison_proc_hold(p2->p_ucred->cr_prison);
@@ -710,8 +711,7 @@ do_fork(struct thread *td, int flags, struct proc *p2, struct thread *td2,
if ((flags & RFMEM) == 0 && dtrace_fasttrap_fork)
dtrace_fasttrap_fork(p1, p2);
#endif
- if ((p1->p_flag & (P_TRACED | P_FOLLOWFORK)) == (P_TRACED |
- P_FOLLOWFORK)) {
+ if (p1->p_ptevents & PTRACE_FORK) {
/*
* Arrange for debugger to receive the fork event.
*
@@ -1057,21 +1057,19 @@ fork_return(struct thread *td, struct trapframe *frame)
if (td->td_dbgflags & TDB_STOPATFORK) {
sx_xlock(&proctree_lock);
PROC_LOCK(p);
- if ((p->p_pptr->p_flag & (P_TRACED | P_FOLLOWFORK)) ==
- (P_TRACED | P_FOLLOWFORK)) {
+ if (p->p_pptr->p_ptevents & PTRACE_FORK) {
/*
* If debugger still wants auto-attach for the
* parent's children, do it now.
*/
dbg = p->p_pptr->p_pptr;
- p->p_flag |= P_TRACED;
- p->p_oppid = p->p_pptr->p_pid;
+ proc_set_traced(p);
CTR2(KTR_PTRACE,
"fork_return: attaching to new child pid %d: oppid %d",
p->p_pid, p->p_oppid);
proc_reparent(p, dbg);
sx_xunlock(&proctree_lock);
- td->td_dbgflags |= TDB_CHILD | TDB_SCX;
+ td->td_dbgflags |= TDB_CHILD | TDB_SCX | TDB_FSTP;
ptracestop(td, SIGSTOP);
td->td_dbgflags &= ~(TDB_CHILD | TDB_SCX);
} else {
@@ -1083,7 +1081,7 @@ fork_return(struct thread *td, struct trapframe *frame)
cv_broadcast(&p->p_dbgwait);
}
PROC_UNLOCK(p);
- } else if (p->p_flag & P_TRACED) {
+ } else if (p->p_flag & P_TRACED || td->td_dbgflags & TDB_BORN) {
/*
* This is the start of a new thread in a traced
* process. Report a system call exit event.
@@ -1091,9 +1089,10 @@ fork_return(struct thread *td, struct trapframe *frame)
PROC_LOCK(p);
td->td_dbgflags |= TDB_SCX;
_STOPEVENT(p, S_SCX, td->td_dbg_sc_code);
- if ((p->p_stops & S_PT_SCX) != 0)
+ if ((p->p_ptevents & PTRACE_SCX) != 0 ||
+ (td->td_dbgflags & TDB_BORN) != 0)
ptracestop(td, SIGTRAP);
- td->td_dbgflags &= ~TDB_SCX;
+ td->td_dbgflags &= ~(TDB_SCX | TDB_BORN);
PROC_UNLOCK(p);
}
diff --git a/sys/kern/kern_kthread.c b/sys/kern/kern_kthread.c
index 70d95fa..fb46025 100644
--- a/sys/kern/kern_kthread.c
+++ b/sys/kern/kern_kthread.c
@@ -322,11 +322,13 @@ void
kthread_exit(void)
{
struct proc *p;
+ struct thread *td;
- p = curthread->td_proc;
+ td = curthread;
+ p = td->td_proc;
/* A module may be waiting for us to exit. */
- wakeup(curthread);
+ wakeup(td);
/*
* The last exiting thread in a kernel process must tear down
@@ -339,9 +341,10 @@ kthread_exit(void)
rw_wunlock(&tidhash_lock);
kproc_exit(0);
}
- LIST_REMOVE(curthread, td_hash);
+ LIST_REMOVE(td, td_hash);
rw_wunlock(&tidhash_lock);
- umtx_thread_exit(curthread);
+ umtx_thread_exit(td);
+ tdsigcleanup(td);
PROC_SLOCK(p);
thread_exit();
}
diff --git a/sys/kern/kern_sig.c b/sys/kern/kern_sig.c
index 29783f8..2c37d76 100644
--- a/sys/kern/kern_sig.c
+++ b/sys/kern/kern_sig.c
@@ -2175,9 +2175,10 @@ tdsendsignal(struct proc *p, struct thread *td, int sig, ksiginfo_t *ksi)
!((prop & SA_CONT) && (p->p_flag & P_STOPPED_SIG)))
return (ret);
/*
- * SIGKILL: Remove procfs STOPEVENTs.
+ * SIGKILL: Remove procfs STOPEVENTs and ptrace events.
*/
if (sig == SIGKILL) {
+ p->p_ptevents = 0;
/* from procfs_ioctl.c: PIOCBIC */
p->p_stops = 0;
/* from procfs_ioctl.c: PIOCCONT */
@@ -2488,19 +2489,36 @@ ptracestop(struct thread *td, int sig)
td->td_tid, p->p_pid, td->td_dbgflags, sig);
PROC_SLOCK(p);
while ((p->p_flag & P_TRACED) && (td->td_dbgflags & TDB_XSIG)) {
- if (p->p_flag & P_SINGLE_EXIT) {
+ if (p->p_flag & P_SINGLE_EXIT &&
+ !(td->td_dbgflags & TDB_EXIT)) {
+ /*
+ * Ignore ptrace stops except for thread exit
+ * events when the process exits.
+ */
td->td_dbgflags &= ~TDB_XSIG;
PROC_SUNLOCK(p);
return (sig);
}
+
/*
- * Just make wait() to work, the last stopped thread
- * will win.
+ * Make wait(2) work. Ensure that right after the
+ * attach, the thread which was decided to become the
+ * leader of attach gets reported to the waiter.
+ * Otherwise, just avoid overwriting another thread's
+ * assignment to p_xthread. If another thread has
+ * already set p_xthread, the current thread will get
+ * a chance to report itself upon the next iteration.
*/
- p->p_xstat = sig;
- p->p_xthread = td;
- p->p_flag |= (P_STOPPED_SIG|P_STOPPED_TRACE);
- sig_suspend_threads(td, p, 0);
+ if ((td->td_dbgflags & TDB_FSTP) != 0 ||
+ ((p->p_flag & P2_PTRACE_FSTP) == 0 &&
+ p->p_xthread == NULL)) {
+ p->p_xstat = sig;
+ p->p_xthread = td;
+ td->td_dbgflags &= ~TDB_FSTP;
+ p->p_flag2 &= ~P2_PTRACE_FSTP;
+ p->p_flag |= P_STOPPED_SIG | P_STOPPED_TRACE;
+ sig_suspend_threads(td, p, 0);
+ }
if ((td->td_dbgflags & TDB_STOPATFORK) != 0) {
td->td_dbgflags &= ~TDB_STOPATFORK;
cv_broadcast(&p->p_dbgwait);
@@ -2651,7 +2669,20 @@ issignal(struct thread *td)
SIG_STOPSIGMASK(sigpending);
if (SIGISEMPTY(sigpending)) /* no signal to send */
return (0);
- sig = sig_ffs(&sigpending);
+ if ((p->p_flag & (P_TRACED | P_PPTRACE)) == P_TRACED &&
+ (p->p_flag2 & P2_PTRACE_FSTP) != 0 &&
+ SIGISMEMBER(sigpending, SIGSTOP)) {
+ /*
+ * If debugger just attached, always consume
+ * SIGSTOP from ptrace(PT_ATTACH) first, to
+ * execute the debugger attach ritual in
+ * order.
+ */
+ sig = SIGSTOP;
+ td->td_dbgflags |= TDB_FSTP;
+ } else {
+ sig = sig_ffs(&sigpending);
+ }
if (p->p_stops & S_SIG) {
mtx_unlock(&ps->ps_mtx);
@@ -2668,7 +2699,7 @@ issignal(struct thread *td)
sigqueue_delete(&p->p_sigqueue, sig);
continue;
}
- if (p->p_flag & P_TRACED && (p->p_flag & P_PPTRACE) == 0) {
+ if ((p->p_flag & (P_TRACED | P_PPTRACE)) == P_TRACED) {
/*
* If traced, always stop.
* Remove old signal from queue before the stop.
@@ -2766,6 +2797,8 @@ issignal(struct thread *td)
mtx_unlock(&ps->ps_mtx);
WITNESS_WARN(WARN_GIANTOK | WARN_SLEEPOK,
&p->p_mtx.lock_object, "Catching SIGSTOP");
+ sigqueue_delete(&td->td_sigqueue, sig);
+ sigqueue_delete(&p->p_sigqueue, sig);
p->p_flag |= P_STOPPED_SIG;
p->p_xstat = sig;
PROC_SLOCK(p);
@@ -2773,7 +2806,7 @@ issignal(struct thread *td)
thread_suspend_switch(td, p);
PROC_SUNLOCK(p);
mtx_lock(&ps->ps_mtx);
- break;
+ goto next;
} else if (prop & SA_IGNORE) {
/*
* Except for SIGCONT, shouldn't get here.
@@ -2804,6 +2837,7 @@ issignal(struct thread *td)
}
sigqueue_delete(&td->td_sigqueue, sig); /* take the signal! */
sigqueue_delete(&p->p_sigqueue, sig);
+next:;
}
/* NOTREACHED */
}
diff --git a/sys/kern/kern_thr.c b/sys/kern/kern_thr.c
index 98965b1..b01aecb 100644
--- a/sys/kern/kern_thr.c
+++ b/sys/kern/kern_thr.c
@@ -36,6 +36,7 @@ __FBSDID("$FreeBSD$");
#include <sys/priv.h>
#include <sys/proc.h>
#include <sys/posix4.h>
+#include <sys/ptrace.h>
#include <sys/racct.h>
#include <sys/resourcevar.h>
#include <sys/rwlock.h>
@@ -252,6 +253,8 @@ thread_create(struct thread *td, struct rtprio *rtp,
thread_unlock(td);
if (P_SHOULDSTOP(p))
newtd->td_flags |= TDF_ASTPENDING | TDF_NEEDSUSPCHK;
+ if (p->p_ptevents & PTRACE_LWP)
+ newtd->td_dbgflags |= TDB_BORN;
PROC_UNLOCK(p);
tidhash_add(newtd);
@@ -314,29 +317,54 @@ kern_thr_exit(struct thread *td)
p = td->td_proc;
- rw_wlock(&tidhash_lock);
+ /*
+ * If all of the threads in a process call this routine to
+ * exit (e.g. all threads call pthread_exit()), exactly one
+ * thread should return to the caller to terminate the process
+ * instead of the thread.
+ *
+ * Checking p_numthreads alone is not sufficient since threads
+ * might be committed to terminating while the PROC_LOCK is
+ * dropped in either ptracestop() or while removing this thread
+ * from the tidhash. Instead, the p_pendingexits field holds
+ * the count of threads in either of those states and a thread
+ * is considered the "last" thread if all of the other threads
+ * in a process are already terminating.
+ */
PROC_LOCK(p);
-
- if (p->p_numthreads != 1) {
- racct_sub(p, RACCT_NTHR, 1);
- LIST_REMOVE(td, td_hash);
- rw_wunlock(&tidhash_lock);
- tdsigcleanup(td);
- umtx_thread_exit(td);
- PROC_SLOCK(p);
- thread_stopped(p);
- thread_exit();
- /* NOTREACHED */
+ if (p->p_numthreads == p->p_pendingexits + 1) {
+ /*
+ * Ignore attempts to shut down last thread in the
+ * proc. This will actually call _exit(2) in the
+ * usermode trampoline when it returns.
+ */
+ PROC_UNLOCK(p);
+ return (0);
}
+ p->p_pendingexits++;
+ td->td_dbgflags |= TDB_EXIT;
+ if (p->p_ptevents & PTRACE_LWP)
+ ptracestop(td, SIGTRAP);
+ PROC_UNLOCK(p);
+ tidhash_remove(td);
+ PROC_LOCK(p);
+ p->p_pendingexits--;
+
/*
- * Ignore attempts to shut down last thread in the proc. This
- * will actually call _exit(2) in the usermode trampoline when
- * it returns.
+ * The check above should prevent all other threads from this
+ * process from exiting while the PROC_LOCK is dropped, so
+ * there must be at least one other thread other than the
+ * current thread.
*/
- PROC_UNLOCK(p);
- rw_wunlock(&tidhash_lock);
- return (0);
+ KASSERT(p->p_numthreads > 1, ("too few threads"));
+ racct_sub(p, RACCT_NTHR, 1);
+ tdsigcleanup(td);
+ umtx_thread_exit(td);
+ PROC_SLOCK(p);
+ thread_stopped(p);
+ thread_exit();
+ /* NOTREACHED */
}
int
diff --git a/sys/kern/subr_syscall.c b/sys/kern/subr_syscall.c
index 1ad7dd0..f2b83f0 100644
--- a/sys/kern/subr_syscall.c
+++ b/sys/kern/subr_syscall.c
@@ -88,7 +88,7 @@ syscallenter(struct thread *td, struct syscall_args *sa)
PROC_LOCK(p);
td->td_dbg_sc_code = sa->code;
td->td_dbg_sc_narg = sa->narg;
- if (p->p_stops & S_PT_SCE)
+ if (p->p_ptevents & PTRACE_SCE)
ptracestop((td), SIGTRAP);
PROC_UNLOCK(p);
}
@@ -215,7 +215,7 @@ syscallret(struct thread *td, int error, struct syscall_args *sa __unused)
*/
if (traced &&
((td->td_dbgflags & (TDB_FORK | TDB_EXEC)) != 0 ||
- (p->p_stops & S_PT_SCX) != 0))
+ (p->p_ptevents & PTRACE_SCX) != 0))
ptracestop(td, SIGTRAP);
td->td_dbgflags &= ~(TDB_SCX | TDB_EXEC | TDB_FORK);
PROC_UNLOCK(p);
diff --git a/sys/kern/sys_process.c b/sys/kern/sys_process.c
index 96e0181..c4533ce 100644
--- a/sys/kern/sys_process.c
+++ b/sys/kern/sys_process.c
@@ -542,6 +542,7 @@ sys_ptrace(struct thread *td, struct ptrace_args *uap)
struct ptrace_lwpinfo32 pl32;
struct ptrace_vm_entry32 pve32;
#endif
+ int ptevents;
} r;
void *addr;
int error = 0;
@@ -556,6 +557,7 @@ sys_ptrace(struct thread *td, struct ptrace_args *uap)
AUDIT_ARG_VALUE(uap->data);
addr = &r;
switch (uap->req) {
+ case PT_GET_EVENT_MASK:
case PT_GETREGS:
case PT_GETFPREGS:
case PT_GETDBREGS:
@@ -570,6 +572,12 @@ sys_ptrace(struct thread *td, struct ptrace_args *uap)
case PT_SETDBREGS:
error = COPYIN(uap->addr, &r.dbreg, sizeof r.dbreg);
break;
+ case PT_SET_EVENT_MASK:
+ if (uap->data != sizeof(r.ptevents))
+ error = EINVAL;
+ else
+ error = copyin(uap->addr, &r.ptevents, uap->data);
+ break;
case PT_IO:
error = COPYIN(uap->addr, &r.piod, sizeof r.piod);
break;
@@ -603,7 +611,12 @@ sys_ptrace(struct thread *td, struct ptrace_args *uap)
case PT_GETDBREGS:
error = COPYOUT(&r.dbreg, uap->addr, sizeof r.dbreg);
break;
+ case PT_GET_EVENT_MASK:
+ /* NB: The size in uap->data is validated in kern_ptrace(). */
+ error = copyout(&r.ptevents, uap->addr, uap->data);
+ break;
case PT_LWPINFO:
+ /* NB: The size in uap->data is validated in kern_ptrace(). */
error = copyout(&r.pl, uap->addr, uap->data);
break;
}
@@ -635,6 +648,17 @@ sys_ptrace(struct thread *td, struct ptrace_args *uap)
#define PROC_WRITE(w, t, a) proc_write_ ## w (t, a)
#endif
+void
+proc_set_traced(struct proc *p)
+{
+
+ PROC_LOCK_ASSERT(p, MA_OWNED);
+ p->p_flag |= P_TRACED;
+ p->p_flag2 |= P2_PTRACE_FSTP;
+ p->p_ptevents = PTRACE_DEFAULT;
+ p->p_oppid = p->p_pptr->p_pid;
+}
+
int
kern_ptrace(struct thread *td, int req, pid_t pid, void *addr, int data)
{
@@ -666,6 +690,9 @@ kern_ptrace(struct thread *td, int req, pid_t pid, void *addr, int data)
case PT_TO_SCX:
case PT_SYSCALL:
case PT_FOLLOW_FORK:
+ case PT_LWP_EVENTS:
+ case PT_GET_EVENT_MASK:
+ case PT_SET_EVENT_MASK:
case PT_DETACH:
sx_xlock(&proctree_lock);
proctree_locked = 1;
@@ -840,10 +867,9 @@ kern_ptrace(struct thread *td, int req, pid_t pid, void *addr, int data)
switch (req) {
case PT_TRACE_ME:
/* set my trace flag and "owner" so it can read/write me */
- p->p_flag |= P_TRACED;
+ proc_set_traced(p);
if (p->p_flag & P_PPWAIT)
p->p_flag |= P_PPTRACE;
- p->p_oppid = p->p_pptr->p_pid;
CTR1(KTR_PTRACE, "PT_TRACE_ME: pid %d", p->p_pid);
break;
@@ -858,8 +884,7 @@ kern_ptrace(struct thread *td, int req, pid_t pid, void *addr, int data)
* The old parent is remembered so we can put things back
* on a "detach".
*/
- p->p_flag |= P_TRACED;
- p->p_oppid = p->p_pptr->p_pid;
+ proc_set_traced(p);
if (p->p_pptr != td->td_proc) {
proc_reparent(p, td->td_proc);
}
@@ -897,14 +922,50 @@ kern_ptrace(struct thread *td, int req, pid_t pid, void *addr, int data)
case PT_FOLLOW_FORK:
CTR3(KTR_PTRACE, "PT_FOLLOW_FORK: pid %d %s -> %s", p->p_pid,
- p->p_flag & P_FOLLOWFORK ? "enabled" : "disabled",
+ p->p_ptevents & PTRACE_FORK ? "enabled" : "disabled",
+ data ? "enabled" : "disabled");
+ if (data)
+ p->p_ptevents |= PTRACE_FORK;
+ else
+ p->p_ptevents &= ~PTRACE_FORK;
+ break;
+
+ case PT_LWP_EVENTS:
+ CTR3(KTR_PTRACE, "PT_LWP_EVENTS: pid %d %s -> %s", p->p_pid,
+ p->p_ptevents & PTRACE_LWP ? "enabled" : "disabled",
data ? "enabled" : "disabled");
if (data)
- p->p_flag |= P_FOLLOWFORK;
+ p->p_ptevents |= PTRACE_LWP;
else
- p->p_flag &= ~P_FOLLOWFORK;
+ p->p_ptevents &= ~PTRACE_LWP;
break;
+ case PT_GET_EVENT_MASK:
+ if (data != sizeof(p->p_ptevents)) {
+ error = EINVAL;
+ break;
+ }
+ CTR2(KTR_PTRACE, "PT_GET_EVENT_MASK: pid %d mask %#x", p->p_pid,
+ p->p_ptevents);
+ *(int *)addr = p->p_ptevents;
+ break;
+
+ case PT_SET_EVENT_MASK:
+ if (data != sizeof(p->p_ptevents)) {
+ error = EINVAL;
+ break;
+ }
+ tmp = *(int *)addr;
+ if ((tmp & ~(PTRACE_EXEC | PTRACE_SCE | PTRACE_SCX |
+ PTRACE_FORK | PTRACE_LWP)) != 0) {
+ error = EINVAL;
+ break;
+ }
+ CTR3(KTR_PTRACE, "PT_SET_EVENT_MASK: pid %d mask %#x -> %#x",
+ p->p_pid, p->p_ptevents, tmp);
+ p->p_ptevents = tmp;
+ break;
+
case PT_STEP:
case PT_CONTINUE:
case PT_TO_SCE:
@@ -937,24 +998,24 @@ kern_ptrace(struct thread *td, int req, pid_t pid, void *addr, int data)
}
switch (req) {
case PT_TO_SCE:
- p->p_stops |= S_PT_SCE;
+ p->p_ptevents |= PTRACE_SCE;
CTR4(KTR_PTRACE,
- "PT_TO_SCE: pid %d, stops = %#x, PC = %#lx, sig = %d",
- p->p_pid, p->p_stops,
+ "PT_TO_SCE: pid %d, events = %#x, PC = %#lx, sig = %d",
+ p->p_pid, p->p_ptevents,
(u_long)(uintfptr_t)addr, data);
break;
case PT_TO_SCX:
- p->p_stops |= S_PT_SCX;
+ p->p_ptevents |= PTRACE_SCX;
CTR4(KTR_PTRACE,
- "PT_TO_SCX: pid %d, stops = %#x, PC = %#lx, sig = %d",
- p->p_pid, p->p_stops,
+ "PT_TO_SCX: pid %d, events = %#x, PC = %#lx, sig = %d",
+ p->p_pid, p->p_ptevents,
(u_long)(uintfptr_t)addr, data);
break;
case PT_SYSCALL:
- p->p_stops |= S_PT_SCE | S_PT_SCX;
+ p->p_ptevents |= PTRACE_SYSCALL;
CTR4(KTR_PTRACE,
- "PT_SYSCALL: pid %d, stops = %#x, PC = %#lx, sig = %d",
- p->p_pid, p->p_stops,
+ "PT_SYSCALL: pid %d, events = %#x, PC = %#lx, sig = %d",
+ p->p_pid, p->p_ptevents,
(u_long)(uintfptr_t)addr, data);
break;
case PT_CONTINUE:
@@ -973,7 +1034,7 @@ kern_ptrace(struct thread *td, int req, pid_t pid, void *addr, int data)
* parent. Otherwise the debugee will be set
* as an orphan of the debugger.
*/
- p->p_flag &= ~(P_TRACED | P_WAITED | P_FOLLOWFORK);
+ p->p_flag &= ~(P_TRACED | P_WAITED);
if (p->p_oppid != p->p_pptr->p_pid) {
PROC_LOCK(p->p_pptr);
sigqueue_take(p->p_ksi);
@@ -990,7 +1051,18 @@ kern_ptrace(struct thread *td, int req, pid_t pid, void *addr, int data)
CTR2(KTR_PTRACE, "PT_DETACH: pid %d, sig %d",
p->p_pid, data);
p->p_oppid = 0;
- p->p_stops = 0;
+ p->p_ptevents = 0;
+ FOREACH_THREAD_IN_PROC(p, td3) {
+ if ((td3->td_dbgflags & TDB_FSTP) != 0) {
+ sigqueue_delete(&td3->td_sigqueue,
+ SIGSTOP);
+ }
+ td3->td_dbgflags &= ~(TDB_XSIG | TDB_FSTP);
+ }
+ if ((p->p_flag2 & P2_PTRACE_FSTP) != 0) {
+ sigqueue_delete(&p->p_sigqueue, SIGSTOP);
+ p->p_flag2 &= ~P2_PTRACE_FSTP;
+ }
/* should we send SIGCHLD? */
/* childproc_continued(p); */
@@ -1011,7 +1083,7 @@ kern_ptrace(struct thread *td, int req, pid_t pid, void *addr, int data)
if (req == PT_DETACH) {
FOREACH_THREAD_IN_PROC(p, td3)
- td3->td_dbgflags &= ~TDB_SUSPEND;
+ td3->td_dbgflags &= ~TDB_SUSPEND;
}
/*
* unsuspend all threads, to not let a thread run,
@@ -1227,6 +1299,10 @@ kern_ptrace(struct thread *td, int req, pid_t pid, void *addr, int data)
}
if (td2->td_dbgflags & TDB_CHILD)
pl->pl_flags |= PL_FLAG_CHILD;
+ if (td2->td_dbgflags & TDB_BORN)
+ pl->pl_flags |= PL_FLAG_BORN;
+ if (td2->td_dbgflags & TDB_EXIT)
+ pl->pl_flags |= PL_FLAG_EXITED;
pl->pl_sigmask = td2->td_sigmask;
pl->pl_siglist = td2->td_siglist;
strcpy(pl->pl_tdname, td2->td_name);
diff --git a/sys/netpfil/pf/pf_ioctl.c b/sys/netpfil/pf/pf_ioctl.c
index b00952c..2543879 100644
--- a/sys/netpfil/pf/pf_ioctl.c
+++ b/sys/netpfil/pf/pf_ioctl.c
@@ -3626,7 +3626,9 @@ pf_check_in(void *arg, struct mbuf **m, struct ifnet *ifp, int dir,
*m = NULL;
}
- return (chk);
+ if (chk != PF_PASS)
+ return (EACCES);
+ return (0);
}
static int
@@ -3641,7 +3643,9 @@ pf_check_out(void *arg, struct mbuf **m, struct ifnet *ifp, int dir,
*m = NULL;
}
- return (chk);
+ if (chk != PF_PASS)
+ return (EACCES);
+ return (0);
}
#endif
@@ -3664,7 +3668,9 @@ pf_check6_in(void *arg, struct mbuf **m, struct ifnet *ifp, int dir,
m_freem(*m);
*m = NULL;
}
- return chk;
+ if (chk != PF_PASS)
+ return (EACCES);
+ return (0);
}
static int
@@ -3680,7 +3686,9 @@ pf_check6_out(void *arg, struct mbuf **m, struct ifnet *ifp, int dir,
m_freem(*m);
*m = NULL;
}
- return chk;
+ if (chk != PF_PASS)
+ return (EACCES);
+ return (0);
}
#endif /* INET6 */
diff --git a/sys/sys/proc.h b/sys/sys/proc.h
index b2de02d..1b8bda5 100644
--- a/sys/sys/proc.h
+++ b/sys/sys/proc.h
@@ -396,6 +396,9 @@ do { \
#define TDB_STOPATFORK 0x00000080 /* Stop at the return from fork (child
only) */
#define TDB_CHILD 0x00000100 /* New child indicator for ptrace() */
+#define TDB_BORN 0x00000200 /* New LWP indicator for ptrace() */
+#define TDB_EXIT 0x00000400 /* Exiting LWP indicator for ptrace() */
+#define TDB_FSTP 0x00001000 /* The thread is PT_ATTACH leader */
/*
* "Private" flags kept in td_pflags:
@@ -551,6 +554,7 @@ struct proc {
int p_pendingcnt; /* how many signals are pending */
struct itimers *p_itimers; /* (c) POSIX interval timers. */
struct procdesc *p_procdesc; /* (e) Process descriptor, if any. */
+ int p_pendingexits; /* (c) Count of pending thread exits. */
/* End area that is zeroed on creation. */
#define p_endzero p_magic
@@ -608,6 +612,7 @@ struct proc {
our subtree. */
struct pgrp *p_pgrp; /* (c + e) Pointer to process group. */
struct filemon *p_filemon; /* (c) filemon-specific data. */
+ u_int p_ptevents; /* (c) ptrace() event mask. */
};
#define p_session p_pgrp->pg_session
@@ -635,7 +640,7 @@ struct proc {
#define P_ADVLOCK 0x00001 /* Process may hold a POSIX advisory lock. */
#define P_CONTROLT 0x00002 /* Has a controlling terminal. */
#define P_KTHREAD 0x00004 /* Kernel thread (*). */
-#define P_FOLLOWFORK 0x00008 /* Attach parent debugger to children. */
+#define P_UNUSED3 0x00008 /* --available-- */
#define P_PPWAIT 0x00010 /* Parent is waiting for child to exec/exit. */
#define P_PROFIL 0x00020 /* Has started profiling. */
#define P_STOPPROF 0x00040 /* Has thread requesting to stop profiling. */
@@ -674,6 +679,7 @@ struct proc {
#define P2_NOTRACE 0x00000002 /* No ptrace(2) attach or coredumps. */
#define P2_NOTRACE_EXEC 0x00000004 /* Keep P2_NOPTRACE on exec(2). */
#define P2_AST_SU 0x00000008 /* Handles SU ast for kthreads. */
+#define P2_PTRACE_FSTP 0x00000010 /* SIGSTOP from PT_ATTACH not yet handled. */
/* Flags protected by proctree_lock, kept in p_treeflags. */
#define P_TREE_ORPHANED 0x00000001 /* Reparented, on orphan list */
@@ -926,6 +932,7 @@ void proc_linkup(struct proc *p, struct thread *td);
struct proc *proc_realparent(struct proc *child);
void proc_reap(struct thread *td, struct proc *p, int *status, int options);
void proc_reparent(struct proc *child, struct proc *newparent);
+void proc_set_traced(struct proc *p);
struct pstats *pstats_alloc(void);
void pstats_fork(struct pstats *src, struct pstats *dst);
void pstats_free(struct pstats *ps);
diff --git a/sys/sys/ptrace.h b/sys/sys/ptrace.h
index 7135767..e2b6a5f 100644
--- a/sys/sys/ptrace.h
+++ b/sys/sys/ptrace.h
@@ -64,6 +64,10 @@
#define PT_SYSCALL 22
#define PT_FOLLOW_FORK 23
+#define PT_LWP_EVENTS 24 /* report LWP birth and exit */
+
+#define PT_GET_EVENT_MASK 25 /* get mask of optional events */
+#define PT_SET_EVENT_MASK 26 /* set mask of optional events */
#define PT_GETREGS 33 /* get general-purpose registers */
#define PT_SETREGS 34 /* set general-purpose registers */
@@ -78,6 +82,16 @@
#define PT_FIRSTMACH 64 /* for machine-specific requests */
#include <machine/ptrace.h> /* machine-specific requests, if any */
+/* Events used with PT_GET_EVENT_MASK and PT_SET_EVENT_MASK */
+#define PTRACE_EXEC 0x0001
+#define PTRACE_SCE 0x0002
+#define PTRACE_SCX 0x0004
+#define PTRACE_SYSCALL (PTRACE_SCE | PTRACE_SCX)
+#define PTRACE_FORK 0x0008
+#define PTRACE_LWP 0x0010
+
+#define PTRACE_DEFAULT (PTRACE_EXEC)
+
struct ptrace_io_desc {
int piod_op; /* I/O operation */
void *piod_offs; /* child offset */
@@ -108,6 +122,8 @@ struct ptrace_lwpinfo {
#define PL_FLAG_SI 0x20 /* siginfo is valid */
#define PL_FLAG_FORKED 0x40 /* new child */
#define PL_FLAG_CHILD 0x80 /* I am from child */
+#define PL_FLAG_BORN 0x100 /* new LWP */
+#define PL_FLAG_EXITED 0x200 /* exiting LWP */
sigset_t pl_sigmask; /* LWP signal mask */
sigset_t pl_siglist; /* LWP pending signal */
struct __siginfo pl_siginfo; /* siginfo for signal */
@@ -133,13 +149,6 @@ struct ptrace_vm_entry {
#ifdef _KERNEL
-/*
- * The flags below are used for ptrace(2) tracing and have no relation
- * to procfs. They are stored in struct proc's p_stops member.
- */
-#define S_PT_SCE 0x000010000
-#define S_PT_SCX 0x000020000
-
int ptrace_set_pc(struct thread *_td, unsigned long _addr);
int ptrace_single_step(struct thread *_td);
int ptrace_clear_single_step(struct thread *_td);
diff --git a/sys/vm/uma_core.c b/sys/vm/uma_core.c
index ee0b207..11dceeb 100644
--- a/sys/vm/uma_core.c
+++ b/sys/vm/uma_core.c
@@ -2770,6 +2770,8 @@ zfree_start:
goto zfree_start;
}
cache->uc_freebucket = NULL;
+ /* We are no longer associated with this CPU. */
+ critical_exit();
/* Can we throw this on the zone full list? */
if (bucket != NULL) {
@@ -2782,9 +2784,6 @@ zfree_start:
LIST_INSERT_HEAD(&zone->uz_buckets, bucket, ub_link);
}
- /* We are no longer associated with this CPU. */
- critical_exit();
-
/*
* We bump the uz count when the cache size is insufficient to
* handle the working set.
diff --git a/sys/vm/vm_page.c b/sys/vm/vm_page.c
index 7010580..433c875 100644
--- a/sys/vm/vm_page.c
+++ b/sys/vm/vm_page.c
@@ -2651,7 +2651,7 @@ vm_page_advise(vm_page_t m, int advice)
* But we do make the page as freeable as we can without
* actually taking the step of unmapping it.
*/
- m->dirty = 0;
+ vm_page_undirty(m);
else if (advice != MADV_DONTNEED)
return;
diff --git a/sys/vm/vm_pageout.c b/sys/vm/vm_pageout.c
index 0d81be4..c9c1271 100644
--- a/sys/vm/vm_pageout.c
+++ b/sys/vm/vm_pageout.c
@@ -262,7 +262,7 @@ vm_pageout_init_marker(vm_page_t marker, u_short queue)
*
* Lock vm object currently associated with `m'. VM_OBJECT_TRYWLOCK is
* known to have failed and page queue must be either PQ_ACTIVE or
- * PQ_INACTIVE. To avoid lock order violation, unlock the page queues
+ * PQ_INACTIVE. To avoid lock order violation, unlock the page queue
* while locking the vm object. Use marker page to detect page queue
* changes and maintain notion of next page on page queue. Return
* TRUE if no changes were detected, FALSE otherwise. vm object is
@@ -950,7 +950,7 @@ vm_pageout_scan(struct vm_domain *vmd, int pass)
int vnodes_skipped = 0;
int maxlaunder, scan_tick, scanned, starting_page_shortage;
int lockmode;
- boolean_t queues_locked;
+ boolean_t queue_locked;
/*
* If we need to reclaim memory ask kernel caches to return
@@ -1015,12 +1015,12 @@ vm_pageout_scan(struct vm_domain *vmd, int pass)
pq = &vmd->vmd_pagequeues[PQ_INACTIVE];
maxscan = pq->pq_cnt;
vm_pagequeue_lock(pq);
- queues_locked = TRUE;
+ queue_locked = TRUE;
for (m = TAILQ_FIRST(&pq->pq_pl);
m != NULL && maxscan-- > 0 && page_shortage > 0;
m = next) {
vm_pagequeue_assert_locked(pq);
- KASSERT(queues_locked, ("unlocked queues"));
+ KASSERT(queue_locked, ("unlocked inactive queue"));
KASSERT(m->queue == PQ_INACTIVE, ("Inactive queue %p", m));
PCPU_INC(cnt.v_pdpages);
@@ -1076,7 +1076,7 @@ vm_pageout_scan(struct vm_domain *vmd, int pass)
*/
TAILQ_INSERT_AFTER(&pq->pq_pl, m, &vmd->vmd_marker, plinks.q);
vm_pagequeue_unlock(pq);
- queues_locked = FALSE;
+ queue_locked = FALSE;
/*
* We bump the activation count if the page has been
@@ -1109,12 +1109,12 @@ vm_pageout_scan(struct vm_domain *vmd, int pass)
m->act_count += act_delta + ACT_ADVANCE;
} else {
vm_pagequeue_lock(pq);
- queues_locked = TRUE;
+ queue_locked = TRUE;
vm_page_requeue_locked(m);
}
VM_OBJECT_WUNLOCK(object);
vm_page_unlock(m);
- goto relock_queues;
+ goto relock_queue;
}
if (m->hold_count != 0) {
@@ -1129,7 +1129,7 @@ vm_pageout_scan(struct vm_domain *vmd, int pass)
* loop over the active queue below.
*/
addl_page_shortage++;
- goto relock_queues;
+ goto relock_queue;
}
/*
@@ -1175,7 +1175,7 @@ vm_pageout_scan(struct vm_domain *vmd, int pass)
*/
m->flags |= PG_WINATCFLS;
vm_pagequeue_lock(pq);
- queues_locked = TRUE;
+ queue_locked = TRUE;
vm_page_requeue_locked(m);
} else if (maxlaunder > 0) {
/*
@@ -1206,9 +1206,9 @@ vm_pageout_scan(struct vm_domain *vmd, int pass)
vm_pagequeue_lock(pq);
vm_page_unlock(m);
VM_OBJECT_WUNLOCK(object);
- queues_locked = TRUE;
+ queue_locked = TRUE;
vm_page_requeue_locked(m);
- goto relock_queues;
+ goto relock_queue;
}
/*
@@ -1263,7 +1263,7 @@ vm_pageout_scan(struct vm_domain *vmd, int pass)
VM_OBJECT_WLOCK(object);
vm_page_lock(m);
vm_pagequeue_lock(pq);
- queues_locked = TRUE;
+ queue_locked = TRUE;
/*
* The page might have been moved to another
* queue during potential blocking in vget()
@@ -1303,7 +1303,7 @@ vm_pageout_scan(struct vm_domain *vmd, int pass)
goto unlock_and_continue;
}
vm_pagequeue_unlock(pq);
- queues_locked = FALSE;
+ queue_locked = FALSE;
}
/*
@@ -1324,9 +1324,9 @@ unlock_and_continue:
vm_page_lock_assert(m, MA_NOTOWNED);
VM_OBJECT_WUNLOCK(object);
if (mp != NULL) {
- if (queues_locked) {
+ if (queue_locked) {
vm_pagequeue_unlock(pq);
- queues_locked = FALSE;
+ queue_locked = FALSE;
}
if (vp != NULL)
vput(vp);
@@ -1334,14 +1334,14 @@ unlock_and_continue:
vn_finished_write(mp);
}
vm_page_lock_assert(m, MA_NOTOWNED);
- goto relock_queues;
+ goto relock_queue;
}
vm_page_unlock(m);
VM_OBJECT_WUNLOCK(object);
-relock_queues:
- if (!queues_locked) {
+relock_queue:
+ if (!queue_locked) {
vm_pagequeue_lock(pq);
- queues_locked = TRUE;
+ queue_locked = TRUE;
}
next = TAILQ_NEXT(&vmd->vmd_marker, plinks.q);
TAILQ_REMOVE(&pq->pq_pl, &vmd->vmd_marker, plinks.q);
diff --git a/tests/sys/kern/ptrace_test.c b/tests/sys/kern/ptrace_test.c
index 1be1144..44ab15b 100644
--- a/tests/sys/kern/ptrace_test.c
+++ b/tests/sys/kern/ptrace_test.c
@@ -1008,6 +1008,16 @@ simple_thread(void *arg __unused)
pthread_exit(NULL);
}
+static __dead2 void
+simple_thread_main(void)
+{
+ pthread_t thread;
+
+ CHILD_REQUIRE(pthread_create(&thread, NULL, simple_thread, NULL) == 0);
+ CHILD_REQUIRE(pthread_join(thread, NULL) == 0);
+ exit(1);
+}
+
/*
* Verify that pl_syscall_code in struct ptrace_lwpinfo for a new
* thread reports the correct value.
@@ -1022,14 +1032,8 @@ ATF_TC_BODY(ptrace__new_child_pl_syscall_code_thread, tc)
ATF_REQUIRE((fpid = fork()) != -1);
if (fpid == 0) {
- pthread_t thread;
-
trace_me();
-
- CHILD_REQUIRE(pthread_create(&thread, NULL, simple_thread,
- NULL) == 0);
- CHILD_REQUIRE(pthread_join(thread, NULL) == 0);
- exit(1);
+ simple_thread_main();
}
/* The first wait() should report the stop from SIGSTOP. */
@@ -1092,6 +1096,373 @@ ATF_TC_BODY(ptrace__new_child_pl_syscall_code_thread, tc)
ATF_REQUIRE(errno == ECHILD);
}
+/*
+ * Verify that the expected LWP events are reported for a child thread.
+ */
+ATF_TC_WITHOUT_HEAD(ptrace__lwp_events);
+ATF_TC_BODY(ptrace__lwp_events, tc)
+{
+ struct ptrace_lwpinfo pl;
+ pid_t fpid, wpid;
+ lwpid_t lwps[2];
+ int status;
+
+ ATF_REQUIRE((fpid = fork()) != -1);
+ if (fpid == 0) {
+ trace_me();
+ simple_thread_main();
+ }
+
+ /* The first wait() should report the stop from SIGSTOP. */
+ wpid = waitpid(fpid, &status, 0);
+ ATF_REQUIRE(wpid == fpid);
+ ATF_REQUIRE(WIFSTOPPED(status));
+ ATF_REQUIRE(WSTOPSIG(status) == SIGSTOP);
+
+ ATF_REQUIRE(ptrace(PT_LWPINFO, wpid, (caddr_t)&pl,
+ sizeof(pl)) != -1);
+ lwps[0] = pl.pl_lwpid;
+
+ ATF_REQUIRE(ptrace(PT_LWP_EVENTS, wpid, NULL, 1) == 0);
+
+ /* Continue the child ignoring the SIGSTOP. */
+ ATF_REQUIRE(ptrace(PT_CONTINUE, fpid, (caddr_t)1, 0) == 0);
+
+ /* The first event should be for the child thread's birth. */
+ wpid = waitpid(fpid, &status, 0);
+ ATF_REQUIRE(wpid == fpid);
+ ATF_REQUIRE(WIFSTOPPED(status));
+ ATF_REQUIRE(WSTOPSIG(status) == SIGTRAP);
+
+ ATF_REQUIRE(ptrace(PT_LWPINFO, wpid, (caddr_t)&pl, sizeof(pl)) != -1);
+ ATF_REQUIRE((pl.pl_flags & (PL_FLAG_BORN | PL_FLAG_SCX)) ==
+ (PL_FLAG_BORN | PL_FLAG_SCX));
+ ATF_REQUIRE(pl.pl_lwpid != lwps[0]);
+ lwps[1] = pl.pl_lwpid;
+
+ ATF_REQUIRE(ptrace(PT_CONTINUE, fpid, (caddr_t)1, 0) == 0);
+
+ /* The next event should be for the child thread's death. */
+ wpid = waitpid(fpid, &status, 0);
+ ATF_REQUIRE(wpid == fpid);
+ ATF_REQUIRE(WIFSTOPPED(status));
+ ATF_REQUIRE(WSTOPSIG(status) == SIGTRAP);
+
+ ATF_REQUIRE(ptrace(PT_LWPINFO, wpid, (caddr_t)&pl, sizeof(pl)) != -1);
+ ATF_REQUIRE((pl.pl_flags & (PL_FLAG_EXITED | PL_FLAG_SCE)) ==
+ (PL_FLAG_EXITED | PL_FLAG_SCE));
+ ATF_REQUIRE(pl.pl_lwpid == lwps[1]);
+
+ ATF_REQUIRE(ptrace(PT_CONTINUE, fpid, (caddr_t)1, 0) == 0);
+
+ /* The last event should be for the child process's exit. */
+ wpid = waitpid(fpid, &status, 0);
+ ATF_REQUIRE(WIFEXITED(status));
+ ATF_REQUIRE(WEXITSTATUS(status) == 1);
+
+ wpid = wait(&status);
+ ATF_REQUIRE(wpid == -1);
+ ATF_REQUIRE(errno == ECHILD);
+}
+
+static void *
+exec_thread(void *arg __unused)
+{
+
+ execl("/usr/bin/true", "true", NULL);
+ exit(127);
+}
+
+static __dead2 void
+exec_thread_main(void)
+{
+ pthread_t thread;
+
+ CHILD_REQUIRE(pthread_create(&thread, NULL, exec_thread, NULL) == 0);
+ for (;;)
+ sleep(60);
+ exit(1);
+}
+
+/*
+ * Verify that the expected LWP events are reported for a multithreaded
+ * process that calls execve(2).
+ */
+ATF_TC_WITHOUT_HEAD(ptrace__lwp_events_exec);
+ATF_TC_BODY(ptrace__lwp_events_exec, tc)
+{
+ struct ptrace_lwpinfo pl;
+ pid_t fpid, wpid;
+ lwpid_t lwps[2];
+ int status;
+
+ ATF_REQUIRE((fpid = fork()) != -1);
+ if (fpid == 0) {
+ trace_me();
+ exec_thread_main();
+ }
+
+ /* The first wait() should report the stop from SIGSTOP. */
+ wpid = waitpid(fpid, &status, 0);
+ ATF_REQUIRE(wpid == fpid);
+ ATF_REQUIRE(WIFSTOPPED(status));
+ ATF_REQUIRE(WSTOPSIG(status) == SIGSTOP);
+
+ ATF_REQUIRE(ptrace(PT_LWPINFO, wpid, (caddr_t)&pl,
+ sizeof(pl)) != -1);
+ lwps[0] = pl.pl_lwpid;
+
+ ATF_REQUIRE(ptrace(PT_LWP_EVENTS, wpid, NULL, 1) == 0);
+
+ /* Continue the child ignoring the SIGSTOP. */
+ ATF_REQUIRE(ptrace(PT_CONTINUE, fpid, (caddr_t)1, 0) == 0);
+
+ /* The first event should be for the child thread's birth. */
+ wpid = waitpid(fpid, &status, 0);
+ ATF_REQUIRE(wpid == fpid);
+ ATF_REQUIRE(WIFSTOPPED(status));
+ ATF_REQUIRE(WSTOPSIG(status) == SIGTRAP);
+
+ ATF_REQUIRE(ptrace(PT_LWPINFO, wpid, (caddr_t)&pl, sizeof(pl)) != -1);
+ ATF_REQUIRE((pl.pl_flags & (PL_FLAG_BORN | PL_FLAG_SCX)) ==
+ (PL_FLAG_BORN | PL_FLAG_SCX));
+ ATF_REQUIRE(pl.pl_lwpid != lwps[0]);
+ lwps[1] = pl.pl_lwpid;
+
+ ATF_REQUIRE(ptrace(PT_CONTINUE, fpid, (caddr_t)1, 0) == 0);
+
+ /*
+ * The next event should be for the main thread's death due to
+ * single threading from execve().
+ */
+ wpid = waitpid(fpid, &status, 0);
+ ATF_REQUIRE(wpid == fpid);
+ ATF_REQUIRE(WIFSTOPPED(status));
+ ATF_REQUIRE(WSTOPSIG(status) == SIGTRAP);
+
+ ATF_REQUIRE(ptrace(PT_LWPINFO, wpid, (caddr_t)&pl, sizeof(pl)) != -1);
+ ATF_REQUIRE((pl.pl_flags & (PL_FLAG_EXITED | PL_FLAG_SCE)) ==
+ (PL_FLAG_EXITED));
+ ATF_REQUIRE(pl.pl_lwpid == lwps[0]);
+
+ ATF_REQUIRE(ptrace(PT_CONTINUE, fpid, (caddr_t)1, 0) == 0);
+
+ /* The next event should be for the child process's exec. */
+ wpid = waitpid(fpid, &status, 0);
+ ATF_REQUIRE(WIFSTOPPED(status));
+ ATF_REQUIRE(WSTOPSIG(status) == SIGTRAP);
+
+ ATF_REQUIRE(ptrace(PT_LWPINFO, wpid, (caddr_t)&pl, sizeof(pl)) != -1);
+ ATF_REQUIRE((pl.pl_flags & (PL_FLAG_EXEC | PL_FLAG_SCX)) ==
+ (PL_FLAG_EXEC | PL_FLAG_SCX));
+ ATF_REQUIRE(pl.pl_lwpid == lwps[1]);
+
+ ATF_REQUIRE(ptrace(PT_CONTINUE, fpid, (caddr_t)1, 0) == 0);
+
+ /* The last event should be for the child process's exit. */
+ wpid = waitpid(fpid, &status, 0);
+ ATF_REQUIRE(WIFEXITED(status));
+ ATF_REQUIRE(WEXITSTATUS(status) == 0);
+
+ wpid = wait(&status);
+ ATF_REQUIRE(wpid == -1);
+ ATF_REQUIRE(errno == ECHILD);
+}
+
+static void
+handler(int sig __unused)
+{
+}
+
+static void
+signal_main(void)
+{
+
+ signal(SIGINFO, handler);
+ raise(SIGINFO);
+ exit(0);
+}
+
+/*
+ * Verify that the expected ptrace event is reported for a signal.
+ */
+ATF_TC_WITHOUT_HEAD(ptrace__siginfo);
+ATF_TC_BODY(ptrace__siginfo, tc)
+{
+ struct ptrace_lwpinfo pl;
+ pid_t fpid, wpid;
+ int status;
+
+ ATF_REQUIRE((fpid = fork()) != -1);
+ if (fpid == 0) {
+ trace_me();
+ signal_main();
+ }
+
+ /* The first wait() should report the stop from SIGSTOP. */
+ wpid = waitpid(fpid, &status, 0);
+ ATF_REQUIRE(wpid == fpid);
+ ATF_REQUIRE(WIFSTOPPED(status));
+ ATF_REQUIRE(WSTOPSIG(status) == SIGSTOP);
+
+ ATF_REQUIRE(ptrace(PT_CONTINUE, fpid, (caddr_t)1, 0) == 0);
+
+ /* The next event should be for the SIGINFO. */
+ wpid = waitpid(fpid, &status, 0);
+ ATF_REQUIRE(WIFSTOPPED(status));
+ ATF_REQUIRE(WSTOPSIG(status) == SIGINFO);
+
+ ATF_REQUIRE(ptrace(PT_LWPINFO, wpid, (caddr_t)&pl, sizeof(pl)) != -1);
+ ATF_REQUIRE(pl.pl_event == PL_EVENT_SIGNAL);
+ ATF_REQUIRE(pl.pl_flags & PL_FLAG_SI);
+ ATF_REQUIRE(pl.pl_siginfo.si_code == SI_LWP);
+ ATF_REQUIRE(pl.pl_siginfo.si_pid == wpid);
+
+ ATF_REQUIRE(ptrace(PT_CONTINUE, fpid, (caddr_t)1, 0) == 0);
+
+ /* The last event should be for the child process's exit. */
+ wpid = waitpid(fpid, &status, 0);
+ ATF_REQUIRE(WIFEXITED(status));
+ ATF_REQUIRE(WEXITSTATUS(status) == 0);
+
+ wpid = wait(&status);
+ ATF_REQUIRE(wpid == -1);
+ ATF_REQUIRE(errno == ECHILD);
+}
+
+/*
+ * Verify that the expected ptrace events are reported for PTRACE_EXEC.
+ */
+ATF_TC_WITHOUT_HEAD(ptrace__ptrace_exec_disable);
+ATF_TC_BODY(ptrace__ptrace_exec_disable, tc)
+{
+ pid_t fpid, wpid;
+ int events, status;
+
+ ATF_REQUIRE((fpid = fork()) != -1);
+ if (fpid == 0) {
+ trace_me();
+ exec_thread(NULL);
+ }
+
+ /* The first wait() should report the stop from SIGSTOP. */
+ wpid = waitpid(fpid, &status, 0);
+ ATF_REQUIRE(wpid == fpid);
+ ATF_REQUIRE(WIFSTOPPED(status));
+ ATF_REQUIRE(WSTOPSIG(status) == SIGSTOP);
+
+ events = 0;
+ ATF_REQUIRE(ptrace(PT_SET_EVENT_MASK, fpid, (caddr_t)&events,
+ sizeof(events)) == 0);
+
+ ATF_REQUIRE(ptrace(PT_CONTINUE, fpid, (caddr_t)1, 0) == 0);
+
+ /* Should get one event at exit. */
+ wpid = waitpid(fpid, &status, 0);
+ ATF_REQUIRE(WIFEXITED(status));
+ ATF_REQUIRE(WEXITSTATUS(status) == 0);
+
+ wpid = wait(&status);
+ ATF_REQUIRE(wpid == -1);
+ ATF_REQUIRE(errno == ECHILD);
+}
+
+ATF_TC_WITHOUT_HEAD(ptrace__ptrace_exec_enable);
+ATF_TC_BODY(ptrace__ptrace_exec_enable, tc)
+{
+ struct ptrace_lwpinfo pl;
+ pid_t fpid, wpid;
+ int events, status;
+
+ ATF_REQUIRE((fpid = fork()) != -1);
+ if (fpid == 0) {
+ trace_me();
+ exec_thread(NULL);
+ }
+
+ /* The first wait() should report the stop from SIGSTOP. */
+ wpid = waitpid(fpid, &status, 0);
+ ATF_REQUIRE(wpid == fpid);
+ ATF_REQUIRE(WIFSTOPPED(status));
+ ATF_REQUIRE(WSTOPSIG(status) == SIGSTOP);
+
+ events = PTRACE_EXEC;
+ ATF_REQUIRE(ptrace(PT_SET_EVENT_MASK, fpid, (caddr_t)&events,
+ sizeof(events)) == 0);
+
+ ATF_REQUIRE(ptrace(PT_CONTINUE, fpid, (caddr_t)1, 0) == 0);
+
+ /* The next event should be for the child process's exec. */
+ wpid = waitpid(fpid, &status, 0);
+ ATF_REQUIRE(WIFSTOPPED(status));
+ ATF_REQUIRE(WSTOPSIG(status) == SIGTRAP);
+
+ ATF_REQUIRE(ptrace(PT_LWPINFO, wpid, (caddr_t)&pl, sizeof(pl)) != -1);
+ ATF_REQUIRE((pl.pl_flags & (PL_FLAG_EXEC | PL_FLAG_SCX)) ==
+ (PL_FLAG_EXEC | PL_FLAG_SCX));
+
+ ATF_REQUIRE(ptrace(PT_CONTINUE, fpid, (caddr_t)1, 0) == 0);
+
+ /* The last event should be for the child process's exit. */
+ wpid = waitpid(fpid, &status, 0);
+ ATF_REQUIRE(WIFEXITED(status));
+ ATF_REQUIRE(WEXITSTATUS(status) == 0);
+
+ wpid = wait(&status);
+ ATF_REQUIRE(wpid == -1);
+ ATF_REQUIRE(errno == ECHILD);
+}
+
+ATF_TC_WITHOUT_HEAD(ptrace__event_mask);
+ATF_TC_BODY(ptrace__event_mask, tc)
+{
+ pid_t fpid, wpid;
+ int events, status;
+
+ ATF_REQUIRE((fpid = fork()) != -1);
+ if (fpid == 0) {
+ trace_me();
+ exit(0);
+ }
+
+ /* The first wait() should report the stop from SIGSTOP. */
+ wpid = waitpid(fpid, &status, 0);
+ ATF_REQUIRE(wpid == fpid);
+ ATF_REQUIRE(WIFSTOPPED(status));
+ ATF_REQUIRE(WSTOPSIG(status) == SIGSTOP);
+
+ /* PT_FOLLOW_FORK should toggle the state of PTRACE_FORK. */
+ ATF_REQUIRE(ptrace(PT_FOLLOW_FORK, fpid, NULL, 1) != -1);
+ ATF_REQUIRE(ptrace(PT_GET_EVENT_MASK, fpid, (caddr_t)&events,
+ sizeof(events)) == 0);
+ ATF_REQUIRE(events & PTRACE_FORK);
+ ATF_REQUIRE(ptrace(PT_FOLLOW_FORK, fpid, NULL, 0) != -1);
+ ATF_REQUIRE(ptrace(PT_GET_EVENT_MASK, fpid, (caddr_t)&events,
+ sizeof(events)) == 0);
+ ATF_REQUIRE(!(events & PTRACE_FORK));
+
+ /* PT_LWP_EVENTS should toggle the state of PTRACE_LWP. */
+ ATF_REQUIRE(ptrace(PT_LWP_EVENTS, fpid, NULL, 1) != -1);
+ ATF_REQUIRE(ptrace(PT_GET_EVENT_MASK, fpid, (caddr_t)&events,
+ sizeof(events)) == 0);
+ ATF_REQUIRE(events & PTRACE_LWP);
+ ATF_REQUIRE(ptrace(PT_LWP_EVENTS, fpid, NULL, 0) != -1);
+ ATF_REQUIRE(ptrace(PT_GET_EVENT_MASK, fpid, (caddr_t)&events,
+ sizeof(events)) == 0);
+ ATF_REQUIRE(!(events & PTRACE_LWP));
+
+ ATF_REQUIRE(ptrace(PT_CONTINUE, fpid, (caddr_t)1, 0) == 0);
+
+ /* Should get one event at exit. */
+ wpid = waitpid(fpid, &status, 0);
+ ATF_REQUIRE(WIFEXITED(status));
+ ATF_REQUIRE(WEXITSTATUS(status) == 0);
+
+ wpid = wait(&status);
+ ATF_REQUIRE(wpid == -1);
+ ATF_REQUIRE(errno == ECHILD);
+}
+
ATF_TP_ADD_TCS(tp)
{
@@ -1110,6 +1481,12 @@ ATF_TP_ADD_TCS(tp)
ATF_TP_ADD_TC(tp, ptrace__new_child_pl_syscall_code_fork);
ATF_TP_ADD_TC(tp, ptrace__new_child_pl_syscall_code_vfork);
ATF_TP_ADD_TC(tp, ptrace__new_child_pl_syscall_code_thread);
+ ATF_TP_ADD_TC(tp, ptrace__lwp_events);
+ ATF_TP_ADD_TC(tp, ptrace__lwp_events_exec);
+ ATF_TP_ADD_TC(tp, ptrace__siginfo);
+ ATF_TP_ADD_TC(tp, ptrace__ptrace_exec_disable);
+ ATF_TP_ADD_TC(tp, ptrace__ptrace_exec_enable);
+ ATF_TP_ADD_TC(tp, ptrace__event_mask);
return (atf_no_error());
}
diff --git a/usr.bin/getconf/getconf.1 b/usr.bin/getconf/getconf.1
index c3baed9..529c666 100644
--- a/usr.bin/getconf/getconf.1
+++ b/usr.bin/getconf/getconf.1
@@ -28,7 +28,7 @@
.\"
.\" $FreeBSD$
.\"
-.Dd September 18, 2002
+.Dd August 8, 2016
.Dt GETCONF 1
.Os
.Sh NAME
@@ -122,7 +122,7 @@ Exactly 32-bit integer, long, and pointer; at least 64-bit file offset.
.It Li POSIX_V6_LP64_OFF64
Exactly 32-bit integer; exactly 64-bit long, pointer, and file offset.
.Sy Supported platforms :
-.Tn Alpha ,
+.Tn AMD64 ,
.Tn SPARC64 .
.It Li POSIX_V6_LPBIG_OFFBIG
At least 32-bit integer; at least 64-bit long, pointer, and file offset.
diff --git a/usr.bin/getconf/progenv.gperf b/usr.bin/getconf/progenv.gperf
index 40ce16a..4810553 100644
--- a/usr.bin/getconf/progenv.gperf
+++ b/usr.bin/getconf/progenv.gperf
@@ -30,7 +30,7 @@ static const struct map *in_word_set(const char *str);
* be updated. (We cheat here and define the supported environments
* statically.)
*/
-#if defined(__alpha__) || defined(__sparc64__) || defined(__amd64__)
+#if defined(__sparc64__) || defined(__amd64__)
#define have_LP64_OFF64 NULL
#endif
diff --git a/usr.bin/truss/syscalls.c b/usr.bin/truss/syscalls.c
index 985a074..dfbbbac 100644
--- a/usr.bin/truss/syscalls.c
+++ b/usr.bin/truss/syscalls.c
@@ -283,6 +283,8 @@ static struct syscall decoded_syscalls[] = {
.args = { { Atfd, 0 }, { Name, 1 }, { Atfd, 2 }, { Name, 3 } } },
{ .name = "rfork", .ret_type = 1, .nargs = 1,
.args = { { Rforkflags, 0 } } },
+ { .name = "rmdir", .ret_type = 1, .nargs = 1,
+ .args = { { Name, 0 } } },
{ .name = "select", .ret_type = 1, .nargs = 5,
.args = { { Int, 0 }, { Fd_set, 1 }, { Fd_set, 2 }, { Fd_set, 3 },
{ Timeval, 4 } } },
OpenPOWER on IntegriCloud