[Midnightbsd-cvs] src [9956] trunk/sys/kern: sync with freebsd
laffer1 at midnightbsd.org
laffer1 at midnightbsd.org
Sat May 26 10:27:13 EDT 2018
Revision: 9956
http://svnweb.midnightbsd.org/src/?rev=9956
Author: laffer1
Date: 2018-05-26 10:27:13 -0400 (Sat, 26 May 2018)
Log Message:
-----------
sync with freebsd
Modified Paths:
--------------
trunk/sys/kern/subr_acl_posix1e.c
trunk/sys/kern/subr_autoconf.c
trunk/sys/kern/subr_param.c
trunk/sys/kern/subr_pcpu.c
trunk/sys/kern/subr_power.c
trunk/sys/kern/subr_prf.c
trunk/sys/kern/subr_prof.c
trunk/sys/kern/subr_rman.c
trunk/sys/kern/subr_rtc.c
trunk/sys/kern/subr_sbuf.c
trunk/sys/kern/subr_scanf.c
trunk/sys/kern/subr_sglist.c
trunk/sys/kern/subr_sleepqueue.c
trunk/sys/kern/subr_smp.c
trunk/sys/kern/subr_stack.c
trunk/sys/kern/subr_syscall.c
trunk/sys/kern/subr_taskqueue.c
trunk/sys/kern/subr_trap.c
trunk/sys/kern/subr_turnstile.c
trunk/sys/kern/subr_uio.c
trunk/sys/kern/subr_unit.c
trunk/sys/kern/subr_witness.c
Added Paths:
-----------
trunk/sys/kern/subr_terminal.c
Modified: trunk/sys/kern/subr_acl_posix1e.c
===================================================================
--- trunk/sys/kern/subr_acl_posix1e.c 2018-05-26 14:26:33 UTC (rev 9955)
+++ trunk/sys/kern/subr_acl_posix1e.c 2018-05-26 14:27:13 UTC (rev 9956)
@@ -1,3 +1,4 @@
+/* $MidnightBSD$ */
/*-
* Copyright (c) 1999-2006 Robert N. M. Watson
* All rights reserved.
@@ -34,9 +35,11 @@
*/
#include <sys/cdefs.h>
-__FBSDID("$MidnightBSD$");
+__FBSDID("$FreeBSD: stable/10/sys/kern/subr_acl_posix1e.c 232936 2012-03-13 20:27:48Z adrian $");
#include <sys/param.h>
+#include <sys/kernel.h>
+#include <sys/module.h>
#include <sys/systm.h>
#include <sys/mount.h>
#include <sys/priv.h>
@@ -648,3 +651,42 @@
return (mode);
}
+
+
+static int
+acl_posix1e_modload(module_t mod, int what, void *arg)
+{
+ int ret;
+
+ ret = 0;
+
+ switch (what) {
+ case MOD_LOAD:
+ case MOD_SHUTDOWN:
+ break;
+
+ case MOD_QUIESCE:
+ /* XXX TODO */
+ ret = 0;
+ break;
+
+ case MOD_UNLOAD:
+ /* XXX TODO */
+ ret = 0;
+ break;
+ default:
+ ret = EINVAL;
+ break;
+ }
+
+ return (ret);
+}
+
+static moduledata_t acl_posix1e_mod = {
+ "acl_posix1e",
+ acl_posix1e_modload,
+ NULL
+};
+
+DECLARE_MODULE(acl_posix1e, acl_posix1e_mod, SI_SUB_VFS, SI_ORDER_FIRST);
+MODULE_VERSION(acl_posix1e, 1);
Modified: trunk/sys/kern/subr_autoconf.c
===================================================================
--- trunk/sys/kern/subr_autoconf.c 2018-05-26 14:26:33 UTC (rev 9955)
+++ trunk/sys/kern/subr_autoconf.c 2018-05-26 14:27:13 UTC (rev 9956)
@@ -1,3 +1,4 @@
+/* $MidnightBSD$ */
/*-
* Copyright (c) 1992, 1993
* The Regents of the University of California. All rights reserved.
@@ -35,7 +36,7 @@
*/
#include <sys/cdefs.h>
-__FBSDID("$MidnightBSD$");
+__FBSDID("$FreeBSD: stable/10/sys/kern/subr_autoconf.c 217075 2011-01-06 22:09:37Z jhb $");
#include "opt_ddb.h"
Modified: trunk/sys/kern/subr_param.c
===================================================================
--- trunk/sys/kern/subr_param.c 2018-05-26 14:26:33 UTC (rev 9955)
+++ trunk/sys/kern/subr_param.c 2018-05-26 14:27:13 UTC (rev 9956)
@@ -1,3 +1,4 @@
+/* $MidnightBSD$ */
/*-
* Copyright (c) 1980, 1986, 1989, 1993
* The Regents of the University of California. All rights reserved.
@@ -35,7 +36,7 @@
*/
#include <sys/cdefs.h>
-__FBSDID("$MidnightBSD$");
+__FBSDID("$FreeBSD: stable/10/sys/kern/subr_param.c 288690 2015-10-05 05:33:30Z kib $");
#include "opt_param.h"
#include "opt_msgbuf.h"
@@ -76,13 +77,15 @@
#define NBUF 0
#endif
#ifndef MAXFILES
-#define MAXFILES (maxproc * 2)
+#define MAXFILES (40 + 32 * maxusers)
#endif
static int sysctl_kern_vm_guest(SYSCTL_HANDLER_ARGS);
-int hz;
-int tick;
+int hz; /* system clock's frequency */
+int tick; /* usec per tick (1000000 / hz) */
+struct bintime tick_bt; /* bintime per tick (1s / hz) */
+sbintime_t tick_sbt;
int maxusers; /* base tunable */
int maxproc; /* maximum # of processes */
int maxprocperuid; /* max # of procs per user */
@@ -89,8 +92,8 @@
int maxfiles; /* sys. wide open files limit */
int maxfilesperproc; /* per-proc open files limit */
int msgbufsize; /* size of kernel message buffer */
-int ncallout; /* maximum # of timer events */
int nbuf;
+int bio_transient_maxcnt;
int ngroups_max; /* max # groups per process */
int nswbuf;
pid_t pid_max = PID_MAX;
@@ -97,7 +100,11 @@
long maxswzone; /* max swmeta KVA storage */
long maxbcache; /* max buffer cache KVA storage */
long maxpipekva; /* Limit on pipe KVA */
-int vm_guest; /* Running as virtual machine guest? */
+#ifdef XEN
+int vm_guest = VM_GUEST_XEN;
+#else
+int vm_guest = VM_GUEST_NO; /* Running as virtual machine guest? */
+#endif
u_long maxtsiz; /* max text size */
u_long dfldsiz; /* initial data size limit */
u_long maxdsiz; /* max data size */
@@ -107,8 +114,6 @@
SYSCTL_INT(_kern, OID_AUTO, hz, CTLFLAG_RDTUN, &hz, 0,
"Number of clock ticks per second");
-SYSCTL_INT(_kern, OID_AUTO, ncallout, CTLFLAG_RDTUN, &ncallout, 0,
- "Number of pre-allocated timer events");
SYSCTL_INT(_kern, OID_AUTO, nbuf, CTLFLAG_RDTUN, &nbuf, 0,
"Number of buffers in the buffer cache");
SYSCTL_INT(_kern, OID_AUTO, nswbuf, CTLFLAG_RDTUN, &nswbuf, 0,
@@ -119,6 +124,9 @@
"Maximum memory for swap metadata");
SYSCTL_LONG(_kern, OID_AUTO, maxbcache, CTLFLAG_RDTUN, &maxbcache, 0,
"Maximum value of vfs.maxbufspace");
+SYSCTL_INT(_kern, OID_AUTO, bio_transient_maxcnt, CTLFLAG_RDTUN,
+ &bio_transient_maxcnt, 0,
+ "Maximum number of transient BIOs mappings");
SYSCTL_ULONG(_kern, OID_AUTO, maxtsiz, CTLFLAG_RW | CTLFLAG_TUN, &maxtsiz, 0,
"Maximum text size");
SYSCTL_ULONG(_kern, OID_AUTO, dfldsiz, CTLFLAG_RW | CTLFLAG_TUN, &dfldsiz, 0,
@@ -133,7 +141,7 @@
"Amount to grow stack on a stack fault");
SYSCTL_PROC(_kern, OID_AUTO, vm_guest, CTLFLAG_RD | CTLTYPE_STRING,
NULL, 0, sysctl_kern_vm_guest, "A",
- "Virtual machine guest detected? (none|generic|xen)");
+ "Virtual machine guest detected?");
/*
* These have to be allocated somewhere; allocating
@@ -150,76 +158,26 @@
"none",
"generic",
"xen",
+ "hv",
+ "vmware",
NULL
};
+CTASSERT(nitems(vm_guest_sysctl_names) - 1 == VM_LAST);
-#ifndef XEN
-static const char *const vm_bnames[] = {
- "QEMU", /* QEMU */
- "Plex86", /* Plex86 */
- "Bochs", /* Bochs */
- "Xen", /* Xen */
- "Seabios", /* KVM */
- NULL
-};
-
-static const char *const vm_pnames[] = {
- "VMware Virtual Platform", /* VMWare VM */
- "Virtual Machine", /* Microsoft VirtualPC */
- "VirtualBox", /* Sun xVM VirtualBox */
- "Parallels Virtual Platform", /* Parallels VM */
- "KVM", /* KVM */
- NULL
-};
-
-
/*
- * Detect known Virtual Machine hosts by inspecting the emulated BIOS.
- */
-static enum VM_GUEST
-detect_virtual(void)
-{
- char *sysenv;
- int i;
-
- sysenv = getenv("smbios.bios.vendor");
- if (sysenv != NULL) {
- for (i = 0; vm_bnames[i] != NULL; i++)
- if (strcmp(sysenv, vm_bnames[i]) == 0) {
- freeenv(sysenv);
- return (VM_GUEST_VM);
- }
- freeenv(sysenv);
- }
- sysenv = getenv("smbios.system.product");
- if (sysenv != NULL) {
- for (i = 0; vm_pnames[i] != NULL; i++)
- if (strcmp(sysenv, vm_pnames[i]) == 0) {
- freeenv(sysenv);
- return (VM_GUEST_VM);
- }
- freeenv(sysenv);
- }
- return (VM_GUEST_NO);
-}
-#endif
-
-/*
* Boot time overrides that are not scaled against main memory
*/
void
init_param1(void)
{
-#ifndef XEN
- vm_guest = detect_virtual();
-#else
- vm_guest = VM_GUEST_XEN;
-#endif
+
hz = -1;
TUNABLE_INT_FETCH("kern.hz", &hz);
if (hz == -1)
hz = vm_guest > VM_GUEST_NO ? HZ_VM : HZ;
tick = 1000000 / hz;
+ tick_sbt = SBT_1S / hz;
+ tick_bt = sbttobt(tick_sbt);
#ifdef VM_SWZONE_SIZE_MAX
maxswzone = VM_SWZONE_SIZE_MAX;
@@ -264,6 +222,8 @@
pid_max = PID_MAX;
else if (pid_max < 300)
pid_max = 300;
+
+ TUNABLE_INT_FETCH("vfs.unmapped_buf_allowed", &unmapped_buf_allowed);
}
/*
@@ -280,26 +240,42 @@
maxusers = physpages / (2 * 1024 * 1024 / PAGE_SIZE);
if (maxusers < 32)
maxusers = 32;
- if (maxusers > 384)
- maxusers = 384;
- }
+#ifdef VM_MAX_AUTOTUNE_MAXUSERS
+ if (maxusers > VM_MAX_AUTOTUNE_MAXUSERS)
+ maxusers = VM_MAX_AUTOTUNE_MAXUSERS;
+#endif
+ /*
+ * Scales down the function in which maxusers grows once
+ * we hit 384.
+ */
+ if (maxusers > 384)
+ maxusers = 384 + ((maxusers - 384) / 8);
+ }
/*
* The following can be overridden after boot via sysctl. Note:
* unless overriden, these macros are ultimately based on maxusers.
+ * Limit maxproc so that kmap entries cannot be exhausted by
+ * processes.
*/
maxproc = NPROC;
TUNABLE_INT_FETCH("kern.maxproc", &maxproc);
+ if (maxproc > (physpages / 12))
+ maxproc = physpages / 12;
+ if (maxproc > pid_max)
+ maxproc = pid_max;
+ maxprocperuid = (maxproc * 9) / 10;
+
/*
- * Limit maxproc so that kmap entries cannot be exhausted by
- * processes.
+ * The default limit for maxfiles is 1/12 of the number of
+ * physical page but not less than 16 times maxusers.
+ * At most it can be 1/6 the number of physical pages.
*/
- if (maxproc > (physpages / 12))
- maxproc = physpages / 12;
- maxfiles = MAXFILES;
+ maxfiles = imax(MAXFILES, physpages / 8);
TUNABLE_INT_FETCH("kern.maxfiles", &maxfiles);
- maxprocperuid = (maxproc * 9) / 10;
- maxfilesperproc = (maxfiles * 9) / 10;
+ if (maxfiles > (physpages / 4))
+ maxfiles = physpages / 4;
+ maxfilesperproc = (maxfiles / 10) * 9;
/*
* Cannot be changed after boot.
@@ -306,25 +282,23 @@
*/
nbuf = NBUF;
TUNABLE_INT_FETCH("kern.nbuf", &nbuf);
+ TUNABLE_INT_FETCH("kern.bio_transient_maxcnt", &bio_transient_maxcnt);
- ncallout = 16 + maxproc + maxfiles;
- TUNABLE_INT_FETCH("kern.ncallout", &ncallout);
-
/*
* The default for maxpipekva is min(1/64 of the kernel address space,
* max(1/64 of main memory, 512KB)). See sys_pipe.c for more details.
*/
maxpipekva = (physpages / 64) * PAGE_SIZE;
+ TUNABLE_LONG_FETCH("kern.ipc.maxpipekva", &maxpipekva);
if (maxpipekva < 512 * 1024)
maxpipekva = 512 * 1024;
if (maxpipekva > (VM_MAX_KERNEL_ADDRESS - VM_MIN_KERNEL_ADDRESS) / 64)
maxpipekva = (VM_MAX_KERNEL_ADDRESS - VM_MIN_KERNEL_ADDRESS) /
64;
- TUNABLE_LONG_FETCH("kern.ipc.maxpipekva", &maxpipekva);
}
/*
- * Sysctl stringiying handler for kern.vm_guest.
+ * Sysctl stringifying handler for kern.vm_guest.
*/
static int
sysctl_kern_vm_guest(SYSCTL_HANDLER_ARGS)
Modified: trunk/sys/kern/subr_pcpu.c
===================================================================
--- trunk/sys/kern/subr_pcpu.c 2018-05-26 14:26:33 UTC (rev 9955)
+++ trunk/sys/kern/subr_pcpu.c 2018-05-26 14:27:13 UTC (rev 9956)
@@ -1,3 +1,4 @@
+/* $MidnightBSD$ */
/*-
* Copyright (c) 2001 Wind River Systems, Inc.
* All rights reserved.
@@ -46,7 +47,7 @@
*/
#include <sys/cdefs.h>
-__MBSDID("$MidnightBSD$");
+__FBSDID("$FreeBSD: stable/10/sys/kern/subr_pcpu.c 262739 2014-03-04 14:46:30Z glebius $");
#include "opt_ddb.h"
@@ -59,6 +60,7 @@
#include <sys/proc.h>
#include <sys/smp.h>
#include <sys/sx.h>
+#include <vm/uma.h>
#include <ddb/ddb.h>
static MALLOC_DEFINE(M_PCPU, "Per-cpu", "Per-cpu resource accouting.");
@@ -127,6 +129,30 @@
SYSINIT(dpcpu, SI_SUB_KLD, SI_ORDER_FIRST, dpcpu_startup, 0);
/*
+ * UMA_PCPU_ZONE zones, that are available for all kernel
+ * consumers. Right now 64 bit zone is used for counter(9)
+ * and pointer zone is used by flowtable.
+ */
+
+uma_zone_t pcpu_zone_64;
+uma_zone_t pcpu_zone_ptr;
+
+static void
+pcpu_zones_startup(void)
+{
+
+ pcpu_zone_64 = uma_zcreate("64 pcpu", sizeof(uint64_t),
+ NULL, NULL, NULL, NULL, UMA_ALIGN_PTR, UMA_ZONE_PCPU);
+
+ if (sizeof(uint64_t) == sizeof(void *))
+ pcpu_zone_ptr = pcpu_zone_64;
+ else
+ pcpu_zone_ptr = uma_zcreate("ptr pcpu", sizeof(void *),
+ NULL, NULL, NULL, NULL, UMA_ALIGN_PTR, UMA_ZONE_PCPU);
+}
+SYSINIT(pcpu_zones, SI_SUB_KMEM, SI_ORDER_ANY, pcpu_zones_startup, NULL);
+
+/*
* First-fit extent based allocator for allocating space in the per-cpu
* region reserved for modules. This is only intended for use by the
* kernel linkers to place module linker sets.
Modified: trunk/sys/kern/subr_power.c
===================================================================
--- trunk/sys/kern/subr_power.c 2018-05-26 14:26:33 UTC (rev 9955)
+++ trunk/sys/kern/subr_power.c 2018-05-26 14:27:13 UTC (rev 9956)
@@ -1,3 +1,4 @@
+/* $MidnightBSD$ */
/*-
* Copyright (c) 2001 Mitsuru IWASAKI
* All rights reserved.
@@ -25,7 +26,7 @@
*/
#include <sys/cdefs.h>
-__FBSDID("$MidnightBSD$");
+__FBSDID("$FreeBSD: stable/10/sys/kern/subr_power.c 152248 2005-11-09 16:22:56Z imp $");
#include <sys/param.h>
#include <sys/systm.h>
Modified: trunk/sys/kern/subr_prf.c
===================================================================
--- trunk/sys/kern/subr_prf.c 2018-05-26 14:26:33 UTC (rev 9955)
+++ trunk/sys/kern/subr_prf.c 2018-05-26 14:27:13 UTC (rev 9956)
@@ -1,3 +1,4 @@
+/* $MidnightBSD$ */
/*-
* Copyright (c) 1986, 1988, 1991, 1993
* The Regents of the University of California. All rights reserved.
@@ -35,12 +36,15 @@
*/
#include <sys/cdefs.h>
-__FBSDID("$MidnightBSD$");
+__FBSDID("$FreeBSD: stable/10/sys/kern/subr_prf.c 321108 2017-07-18 06:45:41Z ngie $");
+#ifdef _KERNEL
#include "opt_ddb.h"
#include "opt_printf.h"
+#endif /* _KERNEL */
#include <sys/param.h>
+#ifdef _KERNEL
#include <sys/systm.h>
#include <sys/lock.h>
#include <sys/kdb.h>
@@ -57,7 +61,9 @@
#include <sys/syslog.h>
#include <sys/cons.h>
#include <sys/uio.h>
+#endif
#include <sys/ctype.h>
+#include <sys/sbuf.h>
#ifdef DDB
#include <ddb/ddb.h>
@@ -67,8 +73,22 @@
* Note that stdarg.h and the ANSI style va_start macro is used for both
* ANSI and traditional C compilers.
*/
+#ifdef _KERNEL
#include <machine/stdarg.h>
+#else
+#include <stdarg.h>
+#endif
+/*
+ * This is needed for sbuf_putbuf() when compiled into userland. Due to the
+ * shared nature of this file, it's the only place to put it.
+ */
+#ifndef _KERNEL
+#include <stdio.h>
+#endif
+
+#ifdef _KERNEL
+
#define TOCONS 0x01
#define TOTTY 0x02
#define TOLOG 0x04
@@ -151,8 +171,8 @@
PROC_LOCK(p);
if ((p->p_flag & P_CONTROLT) == 0) {
PROC_UNLOCK(p);
- retval = 0;
- goto out;
+ sx_sunlock(&proctree_lock);
+ return (0);
}
SESS_LOCK(p->p_session);
pca.tty = p->p_session->s_ttyp;
@@ -159,31 +179,39 @@
SESS_UNLOCK(p->p_session);
PROC_UNLOCK(p);
if (pca.tty == NULL) {
- retval = 0;
- goto out;
+ sx_sunlock(&proctree_lock);
+ return (0);
}
pca.flags = TOTTY;
pca.p_bufr = NULL;
va_start(ap, fmt);
tty_lock(pca.tty);
+ sx_sunlock(&proctree_lock);
retval = kvprintf(fmt, putchar, &pca, 10, ap);
tty_unlock(pca.tty);
va_end(ap);
-out:
- sx_sunlock(&proctree_lock);
return (retval);
}
/*
- * tprintf prints on the controlling terminal associated with the given
- * session, possibly to the log as well.
+ * tprintf and vtprintf print on the controlling terminal associated with the
+ * given session, possibly to the log as well.
*/
void
tprintf(struct proc *p, int pri, const char *fmt, ...)
{
+ va_list ap;
+
+ va_start(ap, fmt);
+ vtprintf(p, pri, fmt, ap);
+ va_end(ap);
+}
+
+void
+vtprintf(struct proc *p, int pri, const char *fmt, va_list ap)
+{
struct tty *tp = NULL;
int flags = 0;
- va_list ap;
struct putchar_arg pca;
struct session *sess = NULL;
@@ -208,17 +236,15 @@
pca.tty = tp;
pca.flags = flags;
pca.p_bufr = NULL;
- va_start(ap, fmt);
if (pca.tty != NULL)
tty_lock(pca.tty);
+ sx_sunlock(&proctree_lock);
kvprintf(fmt, putchar, &pca, 10, ap);
if (pca.tty != NULL)
tty_unlock(pca.tty);
- va_end(ap);
if (sess != NULL)
sess_release(sess);
msgbuftrigger = 1;
- sx_sunlock(&proctree_lock);
}
/*
@@ -242,16 +268,11 @@
return (retval);
}
-/*
- * Log writes to the log buffer, and guarantees not to sleep (so can be
- * called by interrupt routines). If there is no process reading the
- * log yet, it writes to the console also.
- */
-void
-log(int level, const char *fmt, ...)
+static int
+_vprintf(int level, int flags, const char *fmt, va_list ap)
{
- va_list ap;
struct putchar_arg pca;
+ int retval;
#ifdef PRINTF_BUFR_SIZE
char bufr[PRINTF_BUFR_SIZE];
#endif
@@ -258,7 +279,7 @@
pca.tty = NULL;
pca.pri = level;
- pca.flags = log_open ? TOLOG : TOCONS;
+ pca.flags = flags;
#ifdef PRINTF_BUFR_SIZE
pca.p_bufr = bufr;
pca.p_next = pca.p_bufr;
@@ -266,12 +287,11 @@
pca.remain = sizeof(bufr);
*pca.p_next = '\0';
#else
+ /* Don't buffer console output. */
pca.p_bufr = NULL;
#endif
- va_start(ap, fmt);
- kvprintf(fmt, putchar, &pca, 10, ap);
- va_end(ap);
+ retval = kvprintf(fmt, putchar, &pca, 10, ap);
#ifdef PRINTF_BUFR_SIZE
/* Write any buffered console/log output: */
@@ -283,6 +303,24 @@
cnputs(pca.p_bufr);
}
#endif
+
+ return (retval);
+}
+
+/*
+ * Log writes to the log buffer, and guarantees not to sleep (so can be
+ * called by interrupt routines). If there is no process reading the
+ * log yet, it writes to the console also.
+ */
+void
+log(int level, const char *fmt, ...)
+{
+ va_list ap;
+
+ va_start(ap, fmt);
+ (void)_vprintf(level, log_open ? TOLOG : TOCONS | TOLOG, fmt, ap);
+ va_end(ap);
+
msgbuftrigger = 1;
}
@@ -349,7 +387,6 @@
msgbuftrigger = 1;
free(uio, M_IOV);
free(consbuffer, M_TEMP);
- return;
}
int
@@ -368,36 +405,10 @@
int
vprintf(const char *fmt, va_list ap)
{
- struct putchar_arg pca;
int retval;
-#ifdef PRINTF_BUFR_SIZE
- char bufr[PRINTF_BUFR_SIZE];
-#endif
- pca.tty = NULL;
- pca.flags = TOCONS | TOLOG;
- pca.pri = -1;
-#ifdef PRINTF_BUFR_SIZE
- pca.p_bufr = bufr;
- pca.p_next = pca.p_bufr;
- pca.n_bufr = sizeof(bufr);
- pca.remain = sizeof(bufr);
- *pca.p_next = '\0';
-#else
- /* Don't buffer console output. */
- pca.p_bufr = NULL;
-#endif
+ retval = _vprintf(-1, TOCONS | TOLOG, fmt, ap);
- retval = kvprintf(fmt, putchar, &pca, 10, ap);
-
-#ifdef PRINTF_BUFR_SIZE
- /* Write any buffered console/log output: */
- if (*pca.p_bufr != '\0') {
- cnputs(pca.p_bufr);
- msglogstr(pca.p_bufr, pca.pri, /*filter_cr*/ 1);
- }
-#endif
-
if (!panicstr)
msgbuftrigger = 1;
@@ -405,6 +416,23 @@
}
static void
+prf_putbuf(char *bufr, int flags, int pri)
+{
+
+ if (flags & TOLOG)
+ msglogstr(bufr, pri, /*filter_cr*/1);
+
+ if (flags & TOCONS) {
+ if ((panicstr == NULL) && (constty != NULL))
+ msgbuf_addstr(&consmsgbuf, -1,
+ bufr, /*filter_cr*/ 0);
+
+ if ((constty == NULL) ||(always_console_output))
+ cnputs(bufr);
+ }
+}
+
+static void
putbuf(int c, struct putchar_arg *ap)
{
/* Check if no console output buffer was provided. */
@@ -425,19 +453,8 @@
/* Check if the buffer needs to be flushed. */
if (ap->remain == 2 || c == '\n') {
+ prf_putbuf(ap->p_bufr, ap->flags, ap->pri);
- if (ap->flags & TOLOG)
- msglogstr(ap->p_bufr, ap->pri, /*filter_cr*/1);
-
- if (ap->flags & TOCONS) {
- if ((panicstr == NULL) && (constty != NULL))
- msgbuf_addstr(&consmsgbuf, -1,
- ap->p_bufr, /*filter_cr*/ 0);
-
- if ((constty == NULL) ||(always_console_output))
- cnputs(ap->p_bufr);
- }
-
ap->p_next = ap->p_bufr;
ap->remain = ap->n_bufr;
*ap->p_next = '\0';
@@ -467,25 +484,19 @@
struct putchar_arg *ap = (struct putchar_arg*) arg;
struct tty *tp = ap->tty;
int flags = ap->flags;
- int putbuf_done = 0;
/* Don't use the tty code after a panic or while in ddb. */
if (kdb_active) {
if (c != '\0')
cnputc(c);
- } else {
- if ((panicstr == NULL) && (flags & TOTTY) && (tp != NULL))
- tty_putchar(tp, c);
+ return;
+ }
- if (flags & TOCONS) {
- putbuf(c, ap);
- putbuf_done = 1;
- }
- }
- if ((flags & TOLOG) && (putbuf_done == 0)) {
- if (c != '\0')
- putbuf(c, ap);
- }
+ if ((flags & TOTTY) && tp != NULL && panicstr == NULL)
+ tty_putchar(tp, c);
+
+ if ((flags & (TOCONS | TOLOG)) && c != '\0')
+ putbuf(c, ap);
}
/*
@@ -928,7 +939,7 @@
while (percent < fmt)
PCHAR(*percent++);
/*
- * Since we ignore an formatting argument it is no
+ * Since we ignore a formatting argument it is no
* longer safe to obey the remaining formatting
* arguments as the arguments will no longer match
* the format specs.
@@ -1136,4 +1147,96 @@
printf("\n");
}
}
+#endif /* _KERNEL */
+void
+sbuf_hexdump(struct sbuf *sb, const void *ptr, int length, const char *hdr,
+ int flags)
+{
+ int i, j, k;
+ int cols;
+ const unsigned char *cp;
+ char delim;
+
+ if ((flags & HD_DELIM_MASK) != 0)
+ delim = (flags & HD_DELIM_MASK) >> 8;
+ else
+ delim = ' ';
+
+ if ((flags & HD_COLUMN_MASK) != 0)
+ cols = flags & HD_COLUMN_MASK;
+ else
+ cols = 16;
+
+ cp = ptr;
+ for (i = 0; i < length; i+= cols) {
+ if (hdr != NULL)
+ sbuf_printf(sb, "%s", hdr);
+
+ if ((flags & HD_OMIT_COUNT) == 0)
+ sbuf_printf(sb, "%04x ", i);
+
+ if ((flags & HD_OMIT_HEX) == 0) {
+ for (j = 0; j < cols; j++) {
+ k = i + j;
+ if (k < length)
+ sbuf_printf(sb, "%c%02x", delim, cp[k]);
+ else
+ sbuf_printf(sb, " ");
+ }
+ }
+
+ if ((flags & HD_OMIT_CHARS) == 0) {
+ sbuf_printf(sb, " |");
+ for (j = 0; j < cols; j++) {
+ k = i + j;
+ if (k >= length)
+ sbuf_printf(sb, " ");
+ else if (cp[k] >= ' ' && cp[k] <= '~')
+ sbuf_printf(sb, "%c", cp[k]);
+ else
+ sbuf_printf(sb, ".");
+ }
+ sbuf_printf(sb, "|");
+ }
+ sbuf_printf(sb, "\n");
+ }
+}
+
+#ifdef _KERNEL
+void
+counted_warning(unsigned *counter, const char *msg)
+{
+ struct thread *td;
+ unsigned c;
+
+ for (;;) {
+ c = *counter;
+ if (c == 0)
+ break;
+ if (atomic_cmpset_int(counter, c, c - 1)) {
+ td = curthread;
+ log(LOG_INFO, "pid %d (%s) %s%s\n",
+ td->td_proc->p_pid, td->td_name, msg,
+ c > 1 ? "" : " - not logging anymore");
+ break;
+ }
+ }
+}
+#endif
+
+#ifdef _KERNEL
+void
+sbuf_putbuf(struct sbuf *sb)
+{
+
+ prf_putbuf(sbuf_data(sb), TOLOG | TOCONS, -1);
+}
+#else
+void
+sbuf_putbuf(struct sbuf *sb)
+{
+
+ printf("%s", sbuf_data(sb));
+}
+#endif
Modified: trunk/sys/kern/subr_prof.c
===================================================================
--- trunk/sys/kern/subr_prof.c 2018-05-26 14:26:33 UTC (rev 9955)
+++ trunk/sys/kern/subr_prof.c 2018-05-26 14:27:13 UTC (rev 9956)
@@ -1,3 +1,4 @@
+/* $MidnightBSD$ */
/*-
* Copyright (c) 1982, 1986, 1993
* The Regents of the University of California. All rights reserved.
@@ -30,7 +31,7 @@
*/
#include <sys/cdefs.h>
-__FBSDID("$MidnightBSD$");
+__FBSDID("$FreeBSD: stable/10/sys/kern/subr_prof.c 302234 2016-06-27 21:50:30Z bdrewery $");
#include <sys/param.h>
#include <sys/systm.h>
@@ -269,7 +270,7 @@
* without much risk of reducing the profiling times below what they
* would be when profiling is not configured. Abbreviate:
* ab = minimum time between MC1 and MC3
- * a = minumum time between MC1 and MC2
+ * a = minimum time between MC1 and MC2
* b = minimum time between MC2 and MC3
* cd = minimum time between ME1 and ME3
* c = minimum time between ME1 and ME2
@@ -421,12 +422,12 @@
}
PROC_LOCK(p);
upp = &td->td_proc->p_stats->p_prof;
- PROC_SLOCK(p);
+ PROC_PROFLOCK(p);
upp->pr_off = uap->offset;
upp->pr_scale = uap->scale;
upp->pr_base = uap->samples;
upp->pr_size = uap->size;
- PROC_SUNLOCK(p);
+ PROC_PROFUNLOCK(p);
startprofclock(p);
PROC_UNLOCK(p);
@@ -466,15 +467,15 @@
if (ticks == 0)
return;
prof = &td->td_proc->p_stats->p_prof;
- PROC_SLOCK(td->td_proc);
+ PROC_PROFLOCK(td->td_proc);
if (pc < prof->pr_off ||
(i = PC_TO_INDEX(pc, prof)) >= prof->pr_size) {
- PROC_SUNLOCK(td->td_proc);
+ PROC_PROFUNLOCK(td->td_proc);
return; /* out of range; ignore */
}
addr = prof->pr_base + i;
- PROC_SUNLOCK(td->td_proc);
+ PROC_PROFUNLOCK(td->td_proc);
if ((v = fuswintr(addr)) == -1 || suswintr(addr, v + ticks) == -1) {
td->td_profil_addr = pc;
td->td_profil_ticks = ticks;
@@ -509,15 +510,15 @@
}
p->p_profthreads++;
prof = &p->p_stats->p_prof;
- PROC_SLOCK(p);
+ PROC_PROFLOCK(p);
if (pc < prof->pr_off ||
(i = PC_TO_INDEX(pc, prof)) >= prof->pr_size) {
- PROC_SUNLOCK(p);
+ PROC_PROFUNLOCK(p);
goto out;
}
addr = prof->pr_base + i;
- PROC_SUNLOCK(p);
+ PROC_PROFUNLOCK(p);
PROC_UNLOCK(p);
if (copyin(addr, &v, sizeof(v)) == 0) {
v += ticks;
@@ -533,6 +534,7 @@
if (--p->p_profthreads == 0) {
if (p->p_flag & P_STOPPROF) {
wakeup(&p->p_profthreads);
+ p->p_flag &= ~P_STOPPROF;
stop = 0;
}
}
Modified: trunk/sys/kern/subr_rman.c
===================================================================
--- trunk/sys/kern/subr_rman.c 2018-05-26 14:26:33 UTC (rev 9955)
+++ trunk/sys/kern/subr_rman.c 2018-05-26 14:27:13 UTC (rev 9956)
@@ -1,3 +1,4 @@
+/* $MidnightBSD$ */
/*-
* Copyright 1998 Massachusetts Institute of Technology
*
@@ -58,7 +59,7 @@
#include "opt_ddb.h"
#include <sys/cdefs.h>
-__FBSDID("$MidnightBSD$");
+__FBSDID("$FreeBSD: stable/10/sys/kern/subr_rman.c 292417 2015-12-18 00:40:19Z jhb $");
#include <sys/param.h>
#include <sys/systm.h>
@@ -94,12 +95,12 @@
u_long r_end; /* index of the last entry (inclusive) */
u_int r_flags;
void *r_virtual; /* virtual address of this resource */
- struct device *r_dev; /* device which has allocated this resource */
- struct rman *r_rm; /* resource manager from whence this came */
+ struct device *r_dev; /* device which has allocated this resource */
+ struct rman *r_rm; /* resource manager from whence this came */
int r_rid; /* optional rid for this resource. */
};
-static int rman_debug = 0;
+static int rman_debug = 0;
TUNABLE_INT("debug.rman_debug", &rman_debug);
SYSCTL_INT(_debug, OID_AUTO, rman_debug, CTLFLAG_RW,
&rman_debug, 0, "rman debug");
@@ -108,12 +109,9 @@
static MALLOC_DEFINE(M_RMAN, "rman", "Resource manager");
-struct rman_head rman_head;
-static struct mtx rman_mtx; /* mutex to protect rman_head */
-static int int_rman_activate_resource(struct rman *rm, struct resource_i *r,
- struct resource_i **whohas);
-static int int_rman_deactivate_resource(struct resource_i *r);
-static int int_rman_release_resource(struct rman *rm, struct resource_i *r);
+struct rman_head rman_head;
+static struct mtx rman_mtx; /* mutex to protect rman_head */
+static int int_rman_release_resource(struct rman *rm, struct resource_i *r);
static __inline struct resource_i *
int_alloc_resource(int malloc_flag)
@@ -161,6 +159,7 @@
rman_manage_region(struct rman *rm, u_long start, u_long end)
{
struct resource_i *r, *s, *t;
+ int rv = 0;
DPRINTF(("rman_manage_region: <%s> request: start %#lx, end %#lx\n",
rm->rm_descr, start, end));
@@ -188,13 +187,17 @@
TAILQ_INSERT_TAIL(&rm->rm_list, r, r_link);
} else {
/* Check for any overlap with the current region. */
- if (r->r_start <= s->r_end && r->r_end >= s->r_start)
- return EBUSY;
+ if (r->r_start <= s->r_end && r->r_end >= s->r_start) {
+ rv = EBUSY;
+ goto out;
+ }
/* Check for any overlap with the next region. */
t = TAILQ_NEXT(s, r_link);
- if (t && r->r_start <= t->r_end && r->r_end >= t->r_start)
- return EBUSY;
+ if (t && r->r_start <= t->r_end && r->r_end >= t->r_start) {
+ rv = EBUSY;
+ goto out;
+ }
/*
* See if this region can be merged with the next region. If
@@ -225,9 +228,9 @@
TAILQ_INSERT_BEFORE(s, r, r_link);
}
}
-
+out:
mtx_unlock(rm->rm_mtx);
- return 0;
+ return rv;
}
int
@@ -312,12 +315,12 @@
int
rman_adjust_resource(struct resource *rr, u_long start, u_long end)
{
- struct resource_i *r, *s, *t, *new;
- struct rman *rm;
+ struct resource_i *r, *s, *t, *new;
+ struct rman *rm;
/* Not supported for shared resources. */
r = rr->__r_i;
- if (r->r_flags & (RF_TIMESHARE | RF_SHAREABLE))
+ if (r->r_flags & RF_SHAREABLE)
return (EINVAL);
/*
@@ -430,14 +433,16 @@
return (0);
}
+#define SHARE_TYPE(f) (f & (RF_SHAREABLE | RF_PREFETCHABLE))
+
struct resource *
rman_reserve_resource_bound(struct rman *rm, u_long start, u_long end,
- u_long count, u_long bound, u_int flags,
- struct device *dev)
+ u_long count, u_long bound, u_int flags,
+ struct device *dev)
{
- u_int want_activate;
- struct resource_i *r, *s, *rv;
- u_long rstart, rend, amask, bmask;
+ u_int new_rflags;
+ struct resource_i *r, *s, *rv;
+ u_long rstart, rend, amask, bmask;
rv = NULL;
@@ -445,13 +450,14 @@
"length %#lx, flags %u, device %s\n", rm->rm_descr, start, end,
count, flags,
dev == NULL ? "<null>" : device_get_nameunit(dev)));
- want_activate = (flags & RF_ACTIVE);
- flags &= ~RF_ACTIVE;
+ KASSERT((flags & RF_FIRSTSHARE) == 0,
+ ("invalid flags %#x", flags));
+ new_rflags = (flags & ~RF_FIRSTSHARE) | RF_ALLOCATED;
mtx_lock(rm->rm_mtx);
for (r = TAILQ_FIRST(&rm->rm_list);
- r && r->r_end < start;
+ r && r->r_end < start + count - 1;
r = TAILQ_NEXT(r, r_link))
;
@@ -461,6 +467,9 @@
}
amask = (1ul << RF_ALIGNMENT(flags)) - 1;
+ KASSERT(start <= ULONG_MAX - amask,
+ ("start (%#lx) + amask (%#lx) would wrap around", start, amask));
+
/* If bound is 0, bmask will also be 0 */
bmask = ~(bound - 1);
/*
@@ -468,11 +477,20 @@
*/
for (s = r; s; s = TAILQ_NEXT(s, r_link)) {
DPRINTF(("considering [%#lx, %#lx]\n", s->r_start, s->r_end));
- if (s->r_start + count - 1 > end) {
+ /*
+ * The resource list is sorted, so there is no point in
+ * searching further once r_start is too large.
+ */
+ if (s->r_start > end - (count - 1)) {
DPRINTF(("s->r_start (%#lx) + count - 1> end (%#lx)\n",
s->r_start, end));
break;
}
+ if (s->r_start > ULONG_MAX - amask) {
+ DPRINTF(("s->r_start (%#lx) + amask (%#lx) too large\n",
+ s->r_start, amask));
+ break;
+ }
if (s->r_flags & RF_ALLOCATED) {
DPRINTF(("region is allocated\n"));
continue;
@@ -503,7 +521,7 @@
if ((s->r_end - s->r_start + 1) == count) {
DPRINTF(("candidate region is entire chunk\n"));
rv = s;
- rv->r_flags |= RF_ALLOCATED | flags;
+ rv->r_flags = new_rflags;
rv->r_dev = dev;
goto out;
}
@@ -523,7 +541,7 @@
goto out;
rv->r_start = rstart;
rv->r_end = rstart + count - 1;
- rv->r_flags = flags | RF_ALLOCATED;
+ rv->r_flags = new_rflags;
rv->r_dev = dev;
rv->r_rm = rm;
@@ -580,18 +598,13 @@
* additional work, but this does not seem warranted.)
*/
DPRINTF(("no unshared regions found\n"));
- if ((flags & (RF_SHAREABLE | RF_TIMESHARE)) == 0)
+ if ((flags & RF_SHAREABLE) == 0)
goto out;
- for (s = r; s; s = TAILQ_NEXT(s, r_link)) {
- if (s->r_start > end)
- break;
- if ((s->r_flags & flags) != flags)
- continue;
- rstart = ulmax(s->r_start, start);
- rend = ulmin(s->r_end, ulmax(start + count - 1, end));
- if (s->r_start >= start && s->r_end <= end
- && (s->r_end - s->r_start + 1) == count &&
+ for (s = r; s && s->r_end <= end; s = TAILQ_NEXT(s, r_link)) {
+ if (SHARE_TYPE(s->r_flags) == SHARE_TYPE(flags) &&
+ s->r_start >= start &&
+ (s->r_end - s->r_start + 1) == count &&
(s->r_start & amask) == 0 &&
((s->r_start ^ s->r_end) & bmask) == 0) {
rv = int_alloc_resource(M_NOWAIT);
@@ -599,8 +612,7 @@
goto out;
rv->r_start = s->r_start;
rv->r_end = s->r_end;
- rv->r_flags = s->r_flags &
- (RF_ALLOCATED | RF_SHAREABLE | RF_TIMESHARE);
+ rv->r_flags = new_rflags;
rv->r_dev = dev;
rv->r_rm = rm;
if (s->r_sharehead == NULL) {
@@ -621,26 +633,11 @@
goto out;
}
}
-
/*
* We couldn't find anything.
*/
+
out:
- /*
- * If the user specified RF_ACTIVE in the initial flags,
- * which is reflected in `want_activate', we attempt to atomically
- * activate the resource. If this fails, we release the resource
- * and indicate overall failure. (This behavior probably doesn't
- * make sense for RF_TIMESHARE-type resources.)
- */
- if (rv && want_activate) {
- struct resource_i *whohas;
- if (int_rman_activate_resource(rm, rv, &whohas)) {
- int_rman_release_resource(rm, rv);
- rv = NULL;
- }
- }
-
mtx_unlock(rm->rm_mtx);
return (rv == NULL ? NULL : &rv->r_r);
}
@@ -654,91 +651,17 @@
dev));
}
-static int
-int_rman_activate_resource(struct rman *rm, struct resource_i *r,
- struct resource_i **whohas)
-{
- struct resource_i *s;
- int ok;
-
- /*
- * If we are not timesharing, then there is nothing much to do.
- * If we already have the resource, then there is nothing at all to do.
- * If we are not on a sharing list with anybody else, then there is
- * little to do.
- */
- if ((r->r_flags & RF_TIMESHARE) == 0
- || (r->r_flags & RF_ACTIVE) != 0
- || r->r_sharehead == NULL) {
- r->r_flags |= RF_ACTIVE;
- return 0;
- }
-
- ok = 1;
- for (s = LIST_FIRST(r->r_sharehead); s && ok;
- s = LIST_NEXT(s, r_sharelink)) {
- if ((s->r_flags & RF_ACTIVE) != 0) {
- ok = 0;
- *whohas = s;
- }
- }
- if (ok) {
- r->r_flags |= RF_ACTIVE;
- return 0;
- }
- return EBUSY;
-}
-
int
rman_activate_resource(struct resource *re)
{
- int rv;
- struct resource_i *r, *whohas;
+ struct resource_i *r;
struct rman *rm;
r = re->__r_i;
rm = r->r_rm;
mtx_lock(rm->rm_mtx);
- rv = int_rman_activate_resource(rm, r, &whohas);
+ r->r_flags |= RF_ACTIVE;
mtx_unlock(rm->rm_mtx);
- return rv;
-}
-
-int
-rman_await_resource(struct resource *re, int pri, int timo)
-{
- int rv;
- struct resource_i *r, *whohas;
- struct rman *rm;
-
- r = re->__r_i;
- rm = r->r_rm;
- mtx_lock(rm->rm_mtx);
- for (;;) {
- rv = int_rman_activate_resource(rm, r, &whohas);
- if (rv != EBUSY)
- return (rv); /* returns with mutex held */
-
- if (r->r_sharehead == NULL)
- panic("rman_await_resource");
- whohas->r_flags |= RF_WANTED;
- rv = msleep(r->r_sharehead, rm->rm_mtx, pri, "rmwait", timo);
- if (rv) {
- mtx_unlock(rm->rm_mtx);
- return (rv);
- }
- }
-}
-
-static int
-int_rman_deactivate_resource(struct resource_i *r)
-{
-
- r->r_flags &= ~RF_ACTIVE;
- if (r->r_flags & RF_WANTED) {
- r->r_flags &= ~RF_WANTED;
- wakeup(r->r_sharehead);
- }
return 0;
}
@@ -745,11 +668,11 @@
int
rman_deactivate_resource(struct resource *r)
{
- struct rman *rm;
+ struct rman *rm;
rm = r->__r_i->r_rm;
mtx_lock(rm->rm_mtx);
- int_rman_deactivate_resource(r->__r_i);
+ r->__r_i->r_flags &= ~RF_ACTIVE;
mtx_unlock(rm->rm_mtx);
return 0;
}
@@ -757,10 +680,10 @@
static int
int_rman_release_resource(struct rman *rm, struct resource_i *r)
{
- struct resource_i *s, *t;
+ struct resource_i *s, *t;
if (r->r_flags & RF_ACTIVE)
- int_rman_deactivate_resource(r);
+ r->r_flags &= ~RF_ACTIVE;
/*
* Check for a sharing list first. If there is one, then we don't
@@ -851,9 +774,9 @@
int
rman_release_resource(struct resource *re)
{
- int rv;
- struct resource_i *r;
- struct rman *rm;
+ int rv;
+ struct resource_i *r;
+ struct rman *rm;
r = re->__r_i;
rm = r->r_rm;
@@ -866,7 +789,7 @@
uint32_t
rman_make_alignment_flags(uint32_t size)
{
- int i;
+ int i;
/*
* Find the hightest bit set, and add one if more than one bit
@@ -884,6 +807,7 @@
void
rman_set_start(struct resource *r, u_long start)
{
+
r->__r_i->r_start = start;
}
@@ -890,6 +814,7 @@
u_long
rman_get_start(struct resource *r)
{
+
return (r->__r_i->r_start);
}
@@ -896,6 +821,7 @@
void
rman_set_end(struct resource *r, u_long end)
{
+
r->__r_i->r_end = end;
}
@@ -902,6 +828,7 @@
u_long
rman_get_end(struct resource *r)
{
+
return (r->__r_i->r_end);
}
@@ -908,6 +835,7 @@
u_long
rman_get_size(struct resource *r)
{
+
return (r->__r_i->r_end - r->__r_i->r_start + 1);
}
@@ -914,6 +842,7 @@
u_int
rman_get_flags(struct resource *r)
{
+
return (r->__r_i->r_flags);
}
@@ -920,6 +849,7 @@
void
rman_set_virtual(struct resource *r, void *v)
{
+
r->__r_i->r_virtual = v;
}
@@ -926,6 +856,7 @@
void *
rman_get_virtual(struct resource *r)
{
+
return (r->__r_i->r_virtual);
}
@@ -932,6 +863,7 @@
void
rman_set_bustag(struct resource *r, bus_space_tag_t t)
{
+
r->r_bustag = t;
}
@@ -938,6 +870,7 @@
bus_space_tag_t
rman_get_bustag(struct resource *r)
{
+
return (r->r_bustag);
}
@@ -944,6 +877,7 @@
void
rman_set_bushandle(struct resource *r, bus_space_handle_t h)
{
+
r->r_bushandle = h;
}
@@ -950,6 +884,7 @@
bus_space_handle_t
rman_get_bushandle(struct resource *r)
{
+
return (r->r_bushandle);
}
@@ -956,6 +891,7 @@
void
rman_set_rid(struct resource *r, int rid)
{
+
r->__r_i->r_rid = rid;
}
@@ -962,6 +898,7 @@
int
rman_get_rid(struct resource *r)
{
+
return (r->__r_i->r_rid);
}
@@ -968,6 +905,7 @@
void
rman_set_device(struct resource *r, struct device *dev)
{
+
r->__r_i->r_dev = dev;
}
@@ -974,6 +912,7 @@
struct device *
rman_get_device(struct resource *r)
{
+
return (r->__r_i->r_dev);
}
@@ -1114,7 +1053,8 @@
devname = "nomatch";
} else
devname = NULL;
- db_printf(" 0x%lx-0x%lx ", r->r_start, r->r_end);
+ db_printf(" 0x%lx-0x%lx (RID=%d) ",
+ r->r_start, r->r_end, r->r_rid);
if (devname != NULL)
db_printf("(%s)\n", devname);
else
Modified: trunk/sys/kern/subr_rtc.c
===================================================================
--- trunk/sys/kern/subr_rtc.c 2018-05-26 14:26:33 UTC (rev 9955)
+++ trunk/sys/kern/subr_rtc.c 2018-05-26 14:27:13 UTC (rev 9956)
@@ -1,12 +1,18 @@
+/* $MidnightBSD$ */
/*-
* Copyright (c) 1988 University of Utah.
* Copyright (c) 1982, 1990, 1993
- * The Regents of the University of California. All rights reserved.
+ * The Regents of the University of California.
+ * Copyright (c) 2011 The FreeBSD Foundation
+ * All rights reserved.
*
* This code is derived from software contributed to Berkeley by
* the Systems Programming Group of the University of Utah Computer
* Science Department.
*
+ * Portions of this software were developed by Julien Ridoux at the University
+ * of Melbourne under sponsorship from the FreeBSD Foundation.
+ *
* Redistribution and use in source and binary forms, with or without
* modification, are permitted provided that the following conditions
* are met:
@@ -48,8 +54,10 @@
*/
#include <sys/cdefs.h>
-__FBSDID("$MidnightBSD$");
+__FBSDID("$FreeBSD: stable/10/sys/kern/subr_rtc.c 306501 2016-09-30 13:49:50Z royger $");
+#include "opt_ffclock.h"
+
#include <sys/param.h>
#include <sys/systm.h>
#include <sys/kernel.h>
@@ -56,6 +64,9 @@
#include <sys/bus.h>
#include <sys/clock.h>
#include <sys/sysctl.h>
+#ifdef FFCLOCK
+#include <sys/timeffc.h>
+#endif
#include <sys/timetc.h>
#include "clock_if.h"
@@ -74,7 +85,7 @@
{
if (clock_dev != NULL) {
- if (clock_res > res) {
+ if (clock_res <= res) {
if (bootverbose)
device_printf(dev, "not installed as "
"time-of-day clock: clock %s has higher "
@@ -133,6 +144,9 @@
ts.tv_sec += utc_offset();
timespecadd(&ts, &clock_adj);
tc_setclock(&ts);
+#ifdef FFCLOCK
+ ffclock_reset_clock(&ts);
+#endif
return;
wrong_time:
Modified: trunk/sys/kern/subr_sbuf.c
===================================================================
--- trunk/sys/kern/subr_sbuf.c 2018-05-26 14:26:33 UTC (rev 9955)
+++ trunk/sys/kern/subr_sbuf.c 2018-05-26 14:27:13 UTC (rev 9956)
@@ -1,3 +1,4 @@
+/* $MidnightBSD$ */
/*-
* Copyright (c) 2000-2008 Poul-Henning Kamp
* Copyright (c) 2000-2008 Dag-Erling Coïdan Smørgrav
@@ -27,7 +28,7 @@
*/
#include <sys/cdefs.h>
-__FBSDID("$MidnightBSD$");
+__FBSDID("$FreeBSD: stable/10/sys/kern/subr_sbuf.c 321112 2017-07-18 08:15:02Z ngie $");
#include <sys/param.h>
@@ -35,6 +36,7 @@
#include <sys/ctype.h>
#include <sys/errno.h>
#include <sys/kernel.h>
+#include <sys/limits.h>
#include <sys/malloc.h>
#include <sys/systm.h>
#include <sys/uio.h>
@@ -42,6 +44,7 @@
#else /* _KERNEL */
#include <ctype.h>
#include <errno.h>
+#include <limits.h>
#include <stdarg.h>
#include <stdio.h>
#include <stdlib.h>
@@ -52,11 +55,11 @@
#ifdef _KERNEL
static MALLOC_DEFINE(M_SBUF, "sbuf", "string buffers");
-#define SBMALLOC(size) malloc(size, M_SBUF, M_WAITOK)
+#define SBMALLOC(size) malloc(size, M_SBUF, M_WAITOK|M_ZERO)
#define SBFREE(buf) free(buf, M_SBUF)
#else /* _KERNEL */
#define KASSERT(e, m)
-#define SBMALLOC(size) malloc(size)
+#define SBMALLOC(size) calloc(1, size)
#define SBFREE(buf) free(buf)
#endif /* _KERNEL */
@@ -70,6 +73,7 @@
#define SBUF_FREESPACE(s) ((s)->s_size - ((s)->s_len + 1))
#define SBUF_CANEXTEND(s) ((s)->s_flags & SBUF_AUTOEXTEND)
#define SBUF_ISSECTION(s) ((s)->s_flags & SBUF_INSECTION)
+#define SBUF_NULINCLUDED(s) ((s)->s_flags & SBUF_INCLUDENUL)
/*
* Set / clear flags
@@ -77,6 +81,7 @@
#define SBUF_SETFLAG(s, f) do { (s)->s_flags |= (f); } while (0)
#define SBUF_CLEARFLAG(s, f) do { (s)->s_flags &= ~(f); } while (0)
+#define SBUF_MINSIZE 2 /* Min is 1 byte + nulterm. */
#define SBUF_MINEXTENDSIZE 16 /* Should be power of 2. */
#ifdef PAGE_SIZE
@@ -100,9 +105,15 @@
("%s called with a NULL sbuf pointer", fun));
KASSERT(s->s_buf != NULL,
("%s called with uninitialized or corrupt sbuf", fun));
- KASSERT(s->s_len < s->s_size,
- ("wrote past end of sbuf (%jd >= %jd)",
- (intmax_t)s->s_len, (intmax_t)s->s_size));
+ if (SBUF_ISFINISHED(s) && SBUF_NULINCLUDED(s)) {
+ KASSERT(s->s_len <= s->s_size,
+ ("wrote past end of sbuf (%jd >= %jd)",
+ (intmax_t)s->s_len, (intmax_t)s->s_size));
+ } else {
+ KASSERT(s->s_len < s->s_size,
+ ("wrote past end of sbuf (%jd >= %jd)",
+ (intmax_t)s->s_len, (intmax_t)s->s_size));
+ }
}
static void
@@ -185,8 +196,9 @@
s->s_buf = buf;
if ((s->s_flags & SBUF_AUTOEXTEND) == 0) {
- KASSERT(s->s_size >= 0,
- ("attempt to create a too small sbuf"));
+ KASSERT(s->s_size >= SBUF_MINSIZE,
+ ("attempt to create an sbuf smaller than %d bytes",
+ SBUF_MINSIZE));
}
if (s->s_buf != NULL)
@@ -262,6 +274,28 @@
}
#endif
+int
+sbuf_get_flags(struct sbuf *s)
+{
+
+ return (s->s_flags & SBUF_USRFLAGMSK);
+}
+
+void
+sbuf_clear_flags(struct sbuf *s, int flags)
+{
+
+ s->s_flags &= ~(flags & SBUF_USRFLAGMSK);
+}
+
+void
+sbuf_set_flags(struct sbuf *s, int flags)
+{
+
+
+ s->s_flags |= (flags & SBUF_USRFLAGMSK);
+}
+
/*
* Clear an sbuf and reset its position.
*/
@@ -352,13 +386,14 @@
}
/*
- * Append a byte to an sbuf. This is the core function for appending
+ * Append bytes to an sbuf. This is the core function for appending
* to an sbuf and is the main place that deals with extending the
* buffer and marking overflow.
*/
static void
-sbuf_put_byte(struct sbuf *s, int c)
+sbuf_put_bytes(struct sbuf *s, const char *buf, size_t len)
{
+ size_t n;
assert_sbuf_integrity(s);
assert_sbuf_state(s, 0);
@@ -365,23 +400,39 @@
if (s->s_error != 0)
return;
- if (SBUF_FREESPACE(s) <= 0) {
- /*
- * If there is a drain, use it, otherwise extend the
- * buffer.
- */
- if (s->s_drain_func != NULL)
- (void)sbuf_drain(s);
- else if (sbuf_extend(s, 1) < 0)
- s->s_error = ENOMEM;
- if (s->s_error != 0)
- return;
+ while (len > 0) {
+ if (SBUF_FREESPACE(s) <= 0) {
+ /*
+ * If there is a drain, use it, otherwise extend the
+ * buffer.
+ */
+ if (s->s_drain_func != NULL)
+ (void)sbuf_drain(s);
+ else if (sbuf_extend(s, len > INT_MAX ? INT_MAX : len)
+ < 0)
+ s->s_error = ENOMEM;
+ if (s->s_error != 0)
+ return;
+ }
+ n = SBUF_FREESPACE(s);
+ if (len < n)
+ n = len;
+ memcpy(&s->s_buf[s->s_len], buf, n);
+ s->s_len += n;
+ if (SBUF_ISSECTION(s))
+ s->s_sect_len += n;
+ len -= n;
+ buf += n;
}
- s->s_buf[s->s_len++] = c;
- if (SBUF_ISSECTION(s))
- s->s_sect_len++;
}
+static void
+sbuf_put_byte(struct sbuf *s, char c)
+{
+
+ sbuf_put_bytes(s, &c, 1);
+}
+
/*
* Append a byte string to an sbuf.
*/
@@ -388,19 +439,10 @@
int
sbuf_bcat(struct sbuf *s, const void *buf, size_t len)
{
- const char *str = buf;
- const char *end = str + len;
- assert_sbuf_integrity(s);
- assert_sbuf_state(s, 0);
-
+ sbuf_put_bytes(s, buf, len);
if (s->s_error != 0)
return (-1);
- for (; str < end; str++) {
- sbuf_put_byte(s, *str);
- if (s->s_error != 0)
- return (-1);
- }
return (0);
}
@@ -454,18 +496,12 @@
int
sbuf_cat(struct sbuf *s, const char *str)
{
+ size_t n;
- assert_sbuf_integrity(s);
- assert_sbuf_state(s, 0);
-
+ n = strlen(str);
+ sbuf_put_bytes(s, str, n);
if (s->s_error != 0)
return (-1);
-
- while (*str != '\0') {
- sbuf_put_byte(s, *str++);
- if (s->s_error != 0)
- return (-1);
- }
return (0);
}
@@ -588,6 +624,10 @@
va_copy(ap_copy, ap);
len = vsnprintf(&s->s_buf[s->s_len], SBUF_FREESPACE(s) + 1,
fmt, ap_copy);
+ if (len < 0) {
+ s->s_error = errno;
+ return (-1);
+ }
va_end(ap_copy);
if (SBUF_FREESPACE(s) >= len)
@@ -697,18 +737,21 @@
assert_sbuf_integrity(s);
assert_sbuf_state(s, 0);
+ s->s_buf[s->s_len] = '\0';
+ if (SBUF_NULINCLUDED(s))
+ s->s_len++;
if (s->s_drain_func != NULL) {
while (s->s_len > 0 && s->s_error == 0)
s->s_error = sbuf_drain(s);
}
- s->s_buf[s->s_len] = '\0';
SBUF_SETFLAG(s, SBUF_FINISHED);
#ifdef _KERNEL
return (s->s_error);
#else
- errno = s->s_error;
- if (s->s_error)
+ if (s->s_error != 0) {
+ errno = s->s_error;
return (-1);
+ }
return (0);
#endif
}
@@ -742,6 +785,10 @@
if (s->s_error != 0)
return (-1);
+
+ /* If finished, nulterm is already in len, else add one. */
+ if (SBUF_NULINCLUDED(s) && !SBUF_ISFINISHED(s))
+ return (s->s_len + 1);
return (s->s_len);
}
Modified: trunk/sys/kern/subr_scanf.c
===================================================================
--- trunk/sys/kern/subr_scanf.c 2018-05-26 14:26:33 UTC (rev 9955)
+++ trunk/sys/kern/subr_scanf.c 2018-05-26 14:27:13 UTC (rev 9956)
@@ -1,3 +1,4 @@
+/* $MidnightBSD$ */
/*-
* Copyright (c) 1990, 1993
* The Regents of the University of California. All rights reserved.
@@ -35,7 +36,7 @@
*/
#include <sys/cdefs.h>
-__FBSDID("$MidnightBSD$");
+__FBSDID("$FreeBSD: stable/10/sys/kern/subr_scanf.c 302234 2016-06-27 21:50:30Z bdrewery $");
#include <sys/param.h>
#include <sys/systm.h>
@@ -603,7 +604,7 @@
* z', but treats `a-a' as `the letter a, the
* character -, and the letter a'.
*
- * For compatibility, the `-' is not considerd
+ * For compatibility, the `-' is not considered
* to define a range if the character following
* it is either a close bracket (required by ANSI)
* or is not numerically greater than the character
Modified: trunk/sys/kern/subr_sglist.c
===================================================================
--- trunk/sys/kern/subr_sglist.c 2018-05-26 14:26:33 UTC (rev 9955)
+++ trunk/sys/kern/subr_sglist.c 2018-05-26 14:27:13 UTC (rev 9956)
@@ -1,3 +1,4 @@
+/* $MidnightBSD$ */
/*-
* Copyright (c) 2008 Yahoo!, Inc.
* All rights reserved.
@@ -29,10 +30,11 @@
*/
#include <sys/cdefs.h>
-__FBSDID("$MidnightBSD$");
+__FBSDID("$FreeBSD: stable/10/sys/kern/subr_sglist.c 297059 2016-03-20 05:01:40Z np $");
#include <sys/param.h>
#include <sys/kernel.h>
+#include <sys/bio.h>
#include <sys/malloc.h>
#include <sys/mbuf.h>
#include <sys/proc.h>
@@ -40,6 +42,7 @@
#include <sys/uio.h>
#include <vm/vm.h>
+#include <vm/vm_page.h>
#include <vm/pmap.h>
#include <vm/vm_map.h>
@@ -214,6 +217,9 @@
sglist_free(struct sglist *sg)
{
+ if (sg == NULL)
+ return;
+
if (refcount_release(&sg->sg_refs))
free(sg, M_SGLIST);
}
@@ -239,6 +245,44 @@
}
/*
+ * Append the segments to describe a bio's data to a scatter/gather list.
+ * If there are insufficient segments, then this fails with EFBIG.
+ *
+ * NOTE: This function expects bio_bcount to be initialized.
+ */
+int
+sglist_append_bio(struct sglist *sg, struct bio *bp)
+{
+ struct sgsave save;
+ vm_paddr_t paddr;
+ size_t len, tlen;
+ int error, i, ma_offs;
+
+ if ((bp->bio_flags & BIO_UNMAPPED) == 0) {
+ error = sglist_append(sg, bp->bio_data, bp->bio_bcount);
+ return (error);
+ }
+
+ if (sg->sg_maxseg == 0)
+ return (EINVAL);
+
+ SGLIST_SAVE(sg, save);
+ tlen = bp->bio_bcount;
+ ma_offs = bp->bio_ma_offset;
+ for (i = 0; tlen > 0; i++, tlen -= len) {
+ len = min(PAGE_SIZE - ma_offs, tlen);
+ paddr = VM_PAGE_TO_PHYS(bp->bio_ma[i]) + ma_offs;
+ error = sglist_append_phys(sg, paddr, len);
+ if (error) {
+ SGLIST_RESTORE(sg, save);
+ return (error);
+ }
+ ma_offs = 0;
+ }
+ return (0);
+}
+
+/*
* Append a single physical address range to a scatter/gather list.
* If there are insufficient segments, then this fails with EFBIG.
*/
Modified: trunk/sys/kern/subr_sleepqueue.c
===================================================================
--- trunk/sys/kern/subr_sleepqueue.c 2018-05-26 14:26:33 UTC (rev 9955)
+++ trunk/sys/kern/subr_sleepqueue.c 2018-05-26 14:27:13 UTC (rev 9956)
@@ -1,3 +1,4 @@
+/* $MidnightBSD$ */
/*-
* Copyright (c) 2004 John Baldwin <jhb at FreeBSD.org>
* All rights reserved.
@@ -10,9 +11,6 @@
* 2. Redistributions in binary form must reproduce the above copyright
* notice, this list of conditions and the following disclaimer in the
* documentation and/or other materials provided with the distribution.
- * 3. Neither the name of the author nor the names of any co-contributors
- * may be used to endorse or promote products derived from this software
- * without specific prior written permission.
*
* THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND
* ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
@@ -29,7 +27,7 @@
/*
* Implementation of sleep queues used to hold queue of threads blocked on
- * a wait channel. Sleep queues different from turnstiles in that wait
+ * a wait channel. Sleep queues are different from turnstiles in that wait
* channels are not owned by anyone, so there is no priority propagation.
* Sleep queues can also provide a timeout and can also be interrupted by
* signals. That said, there are several similarities between the turnstile
@@ -39,7 +37,7 @@
* a linked list of queues. An individual queue is located by using a hash
* to pick a chain, locking the chain, and then walking the chain searching
* for the queue. This means that a wait channel object does not need to
- * embed it's queue head just as locks do not embed their turnstile queue
+ * embed its queue head just as locks do not embed their turnstile queue
* head. Threads also carry around a sleep queue that they lend to the
* wait channel when blocking. Just as in turnstiles, the queue includes
* a free list of the sleep queues of other threads blocked on the same
@@ -60,7 +58,7 @@
*/
#include <sys/cdefs.h>
-__FBSDID("$MidnightBSD$");
+__FBSDID("$FreeBSD: stable/10/sys/kern/subr_sleepqueue.c 324800 2017-10-20 10:06:02Z hselasky $");
#include "opt_sleepqueue_profiling.h"
#include "opt_ddb.h"
@@ -88,20 +86,18 @@
#endif
/*
- * Constants for the hash table of sleep queue chains. These constants are
- * the same ones that 4BSD (and possibly earlier versions of BSD) used.
- * Basically, we ignore the lower 8 bits of the address since most wait
- * channel pointers are aligned and only look at the next 7 bits for the
- * hash. SC_TABLESIZE must be a power of two for SC_MASK to work properly.
+ * Constants for the hash table of sleep queue chains.
+ * SC_TABLESIZE must be a power of two for SC_MASK to work properly.
*/
-#define SC_TABLESIZE 128 /* Must be power of 2. */
+#define SC_TABLESIZE 256 /* Must be power of 2. */
#define SC_MASK (SC_TABLESIZE - 1)
#define SC_SHIFT 8
-#define SC_HASH(wc) (((uintptr_t)(wc) >> SC_SHIFT) & SC_MASK)
+#define SC_HASH(wc) ((((uintptr_t)(wc) >> SC_SHIFT) ^ (uintptr_t)(wc)) & \
+ SC_MASK)
#define SC_LOOKUP(wc) &sleepq_chains[SC_HASH(wc)]
#define NR_SLEEPQS 2
/*
- * There two different lists of sleep queues. Both lists are connected
+ * There are two different lists of sleep queues. Both lists are connected
* via the sq_hash entries. The first list is the sleep queue chain list
* that a sleep queue is on when it is attached to a wait channel. The
* second list is the free list hung off of a sleep queue that is attached
@@ -190,7 +186,7 @@
MTX_SPIN | MTX_RECURSE);
#ifdef SLEEPQUEUE_PROFILING
snprintf(chain_name, sizeof(chain_name), "%d", i);
- chain_oid = SYSCTL_ADD_NODE(NULL,
+ chain_oid = SYSCTL_ADD_NODE(NULL,
SYSCTL_STATIC_CHILDREN(_debug_sleepq_chains), OID_AUTO,
chain_name, CTLFLAG_RD, NULL, "sleepq chain stats");
SYSCTL_ADD_UINT(NULL, SYSCTL_CHILDREN(chain_oid), OID_AUTO,
@@ -206,7 +202,7 @@
#else
NULL, NULL, sleepq_init, NULL, UMA_ALIGN_CACHE, 0);
#endif
-
+
thread0.td_sleepqueue = sleepq_alloc();
}
@@ -296,8 +292,9 @@
MPASS((queue >= 0) && (queue < NR_SLEEPQS));
/* If this thread is not allowed to sleep, die a horrible death. */
- KASSERT(!(td->td_pflags & TDP_NOSLEEPING),
- ("Trying sleep, but thread marked as sleeping prohibited"));
+ KASSERT(td->td_no_sleeping == 0,
+ ("%s: td %p to sleep on wchan %p with sleeping prohibited",
+ __func__, td, wchan));
/* Look up the sleep queue associated with the wait channel 'wchan'. */
sq = sleepq_lookup(wchan);
@@ -360,10 +357,12 @@
* sleep queue after timo ticks if the thread has not already been awakened.
*/
void
-sleepq_set_timeout(void *wchan, int timo)
+sleepq_set_timeout_sbt(void *wchan, sbintime_t sbt, sbintime_t pr,
+ int flags)
{
struct sleepqueue_chain *sc;
struct thread *td;
+ sbintime_t pr1;
td = curthread;
sc = SC_LOOKUP(wchan);
@@ -371,7 +370,14 @@
MPASS(TD_ON_SLEEPQ(td));
MPASS(td->td_sleepqueue == NULL);
MPASS(wchan != NULL);
- callout_reset_curcpu(&td->td_slpcallout, timo, sleepq_timeout, td);
+ KASSERT(td->td_sleeptimo == 0, ("td %d %p td_sleeptimo %jx",
+ td->td_tid, td, (uintmax_t)td->td_sleeptimo));
+ thread_lock(td);
+ callout_when(sbt, pr, flags, &td->td_sleeptimo, &pr1);
+ thread_unlock(td);
+ callout_reset_sbt_on(&td->td_slpcallout, td->td_sleeptimo, pr1,
+ sleepq_timeout, td, PCPU_GET(cpuid), flags | C_PRECALC |
+ C_DIRECT_EXEC);
}
/*
@@ -404,8 +410,9 @@
struct thread *td;
struct proc *p;
struct sigacts *ps;
- int sig, ret, stop_allowed;
+ int sig, ret;
+ ret = 0;
td = curthread;
p = curproc;
sc = SC_LOOKUP(wchan);
@@ -419,46 +426,51 @@
}
/*
- * See if there are any pending signals for this thread. If not
- * we can switch immediately. Otherwise do the signal processing
- * directly.
+ * See if there are any pending signals or suspension requests for this
+ * thread. If not, we can switch immediately.
*/
thread_lock(td);
- if ((td->td_flags & (TDF_NEEDSIGCHK | TDF_NEEDSUSPCHK)) == 0) {
- sleepq_switch(wchan, pri);
- return (0);
+ if ((td->td_flags & (TDF_NEEDSIGCHK | TDF_NEEDSUSPCHK)) != 0) {
+ thread_unlock(td);
+ mtx_unlock_spin(&sc->sc_lock);
+ CTR3(KTR_PROC, "sleepq catching signals: thread %p (pid %ld, %s)",
+ (void *)td, (long)p->p_pid, td->td_name);
+ PROC_LOCK(p);
+ /*
+ * Check for suspension first. Checking for signals and then
+ * suspending could result in a missed signal, since a signal
+ * can be delivered while this thread is suspended.
+ */
+ if ((td->td_flags & TDF_NEEDSUSPCHK) != 0) {
+ ret = thread_suspend_check(1);
+ MPASS(ret == 0 || ret == EINTR || ret == ERESTART);
+ if (ret != 0) {
+ PROC_UNLOCK(p);
+ mtx_lock_spin(&sc->sc_lock);
+ thread_lock(td);
+ goto out;
+ }
+ }
+ if ((td->td_flags & TDF_NEEDSIGCHK) != 0) {
+ ps = p->p_sigacts;
+ mtx_lock(&ps->ps_mtx);
+ sig = cursig(td);
+ if (sig != 0)
+ ret = SIGISMEMBER(ps->ps_sigintr, sig) ?
+ EINTR : ERESTART;
+ mtx_unlock(&ps->ps_mtx);
+ }
+ /*
+ * Lock the per-process spinlock prior to dropping the PROC_LOCK
+ * to avoid a signal delivery race. PROC_LOCK, PROC_SLOCK, and
+ * thread_lock() are currently held in tdsendsignal().
+ */
+ PROC_SLOCK(p);
+ mtx_lock_spin(&sc->sc_lock);
+ PROC_UNLOCK(p);
+ thread_lock(td);
+ PROC_SUNLOCK(p);
}
- stop_allowed = (td->td_flags & TDF_SBDRY) ? SIG_STOP_NOT_ALLOWED :
- SIG_STOP_ALLOWED;
- thread_unlock(td);
- mtx_unlock_spin(&sc->sc_lock);
- CTR3(KTR_PROC, "sleepq catching signals: thread %p (pid %ld, %s)",
- (void *)td, (long)p->p_pid, td->td_name);
- PROC_LOCK(p);
- ps = p->p_sigacts;
- mtx_lock(&ps->ps_mtx);
- sig = cursig(td, stop_allowed);
- if (sig == 0) {
- mtx_unlock(&ps->ps_mtx);
- ret = thread_suspend_check(1);
- MPASS(ret == 0 || ret == EINTR || ret == ERESTART);
- } else {
- if (SIGISMEMBER(ps->ps_sigintr, sig))
- ret = EINTR;
- else
- ret = ERESTART;
- mtx_unlock(&ps->ps_mtx);
- }
- /*
- * Lock the per-process spinlock prior to dropping the PROC_LOCK
- * to avoid a signal delivery race. PROC_LOCK, PROC_SLOCK, and
- * thread_lock() are currently held in tdsendsignal().
- */
- PROC_SLOCK(p);
- mtx_lock_spin(&sc->sc_lock);
- PROC_UNLOCK(p);
- thread_lock(td);
- PROC_SUNLOCK(p);
if (ret == 0) {
sleepq_switch(wchan, pri);
return (0);
@@ -501,7 +513,7 @@
mtx_assert(&sc->sc_lock, MA_OWNED);
THREAD_LOCK_ASSERT(td, MA_OWNED);
- /*
+ /*
* If we have a sleep queue, then we've already been woken up, so
* just return.
*/
@@ -528,7 +540,7 @@
#endif
}
mtx_unlock_spin(&sc->sc_lock);
- return;
+ return;
}
#ifdef SLEEPQUEUE_PROFILING
if (prof_enabled)
@@ -552,36 +564,36 @@
sleepq_check_timeout(void)
{
struct thread *td;
+ int res;
td = curthread;
THREAD_LOCK_ASSERT(td, MA_OWNED);
/*
- * If TDF_TIMEOUT is set, we timed out.
+ * If TDF_TIMEOUT is set, we timed out. But recheck
+ * td_sleeptimo anyway.
*/
- if (td->td_flags & TDF_TIMEOUT) {
+ res = 0;
+ if (td->td_sleeptimo != 0) {
+ if (td->td_sleeptimo <= sbinuptime())
+ res = EWOULDBLOCK;
+ td->td_sleeptimo = 0;
+ }
+ if (td->td_flags & TDF_TIMEOUT)
td->td_flags &= ~TDF_TIMEOUT;
- return (EWOULDBLOCK);
- }
-
- /*
- * If TDF_TIMOFAIL is set, the timeout ran after we had
- * already been woken up.
- */
- if (td->td_flags & TDF_TIMOFAIL)
- td->td_flags &= ~TDF_TIMOFAIL;
-
- /*
- * If callout_stop() fails, then the timeout is running on
- * another CPU, so synchronize with it to avoid having it
- * accidentally wake up a subsequent sleep.
- */
- else if (callout_stop(&td->td_slpcallout) == 0) {
- td->td_flags |= TDF_TIMEOUT;
- TD_SET_SLEEPING(td);
- mi_switch(SW_INVOL | SWT_SLEEPQTIMO, NULL);
- }
- return (0);
+ else
+ /*
+ * We ignore the situation where timeout subsystem was
+ * unable to stop our callout. The struct thread is
+ * type-stable, the callout will use the correct
+ * memory when running. The checks of the
+ * td_sleeptimo value in this function and in
+ * sleepq_timeout() ensure that the thread does not
+ * get spurious wakeups, even if the callout was reset
+ * or thread reused.
+ */
+ callout_stop(&td->td_slpcallout);
+ return (res);
}
/*
@@ -890,12 +902,17 @@
CTR3(KTR_PROC, "sleepq_timeout: thread %p (pid %ld, %s)",
(void *)td, (long)td->td_proc->p_pid, (void *)td->td_name);
- /*
- * First, see if the thread is asleep and get the wait channel if
- * it is.
- */
thread_lock(td);
- if (TD_IS_SLEEPING(td) && TD_ON_SLEEPQ(td)) {
+
+ if (td->td_sleeptimo > sbinuptime() || td->td_sleeptimo == 0) {
+ /*
+ * The thread does not want a timeout (yet).
+ */
+ } else if (TD_IS_SLEEPING(td) && TD_ON_SLEEPQ(td)) {
+ /*
+ * See if the thread is asleep and get the wait
+ * channel if it is.
+ */
wchan = td->td_wchan;
sc = SC_LOOKUP(wchan);
THREAD_LOCKPTR_ASSERT(td, &sc->sc_lock);
@@ -903,40 +920,16 @@
MPASS(sq != NULL);
td->td_flags |= TDF_TIMEOUT;
wakeup_swapper = sleepq_resume_thread(sq, td, 0);
- thread_unlock(td);
- if (wakeup_swapper)
- kick_proc0();
- return;
- }
-
- /*
- * If the thread is on the SLEEPQ but isn't sleeping yet, it
- * can either be on another CPU in between sleepq_add() and
- * one of the sleepq_*wait*() routines or it can be in
- * sleepq_catch_signals().
- */
- if (TD_ON_SLEEPQ(td)) {
+ } else if (TD_ON_SLEEPQ(td)) {
+ /*
+ * If the thread is on the SLEEPQ but isn't sleeping
+ * yet, it can either be on another CPU in between
+ * sleepq_add() and one of the sleepq_*wait*()
+ * routines or it can be in sleepq_catch_signals().
+ */
td->td_flags |= TDF_TIMEOUT;
- thread_unlock(td);
- return;
}
- /*
- * Now check for the edge cases. First, if TDF_TIMEOUT is set,
- * then the other thread has already yielded to us, so clear
- * the flag and resume it. If TDF_TIMEOUT is not set, then the
- * we know that the other thread is not on a sleep queue, but it
- * hasn't resumed execution yet. In that case, set TDF_TIMOFAIL
- * to let it know that the timeout has already run and doesn't
- * need to be canceled.
- */
- if (td->td_flags & TDF_TIMEOUT) {
- MPASS(TD_IS_SLEEPING(td));
- td->td_flags &= ~TDF_TIMEOUT;
- TD_CLR_SLEEPING(td);
- wakeup_swapper = setrunnable(td);
- } else
- td->td_flags |= TDF_TIMOFAIL;
thread_unlock(td);
if (wakeup_swapper)
kick_proc0();
@@ -1222,7 +1215,7 @@
if (TAILQ_EMPTY(&sq->sq_blocked[i]))
db_printf("\tempty\n");
else
- TAILQ_FOREACH(td, &sq->sq_blocked[0],
+ TAILQ_FOREACH(td, &sq->sq_blocked[i],
td_slpq) {
db_printf("\t%p (tid %d, pid %d, \"%s\")\n", td,
td->td_tid, td->td_proc->p_pid,
Modified: trunk/sys/kern/subr_smp.c
===================================================================
--- trunk/sys/kern/subr_smp.c 2018-05-26 14:26:33 UTC (rev 9955)
+++ trunk/sys/kern/subr_smp.c 2018-05-26 14:27:13 UTC (rev 9956)
@@ -1,3 +1,4 @@
+/* $MidnightBSD$ */
/*-
* Copyright (c) 2001, John Baldwin <jhb at FreeBSD.org>.
* All rights reserved.
@@ -10,9 +11,6 @@
* 2. Redistributions in binary form must reproduce the above copyright
* notice, this list of conditions and the following disclaimer in the
* documentation and/or other materials provided with the distribution.
- * 3. Neither the name of the author nor the names of any co-contributors
- * may be used to endorse or promote products derived from this software
- * without specific prior written permission.
*
* THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND
* ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
@@ -33,7 +31,7 @@
*/
#include <sys/cdefs.h>
-__FBSDID("$MidnightBSD$");
+__FBSDID("$FreeBSD: stable/10/sys/kern/subr_smp.c 331910 2018-04-03 07:52:06Z avg $");
#include <sys/param.h>
#include <sys/systm.h>
@@ -44,6 +42,7 @@
#include <sys/lock.h>
#include <sys/mutex.h>
#include <sys/pcpu.h>
+#include <sys/sched.h>
#include <sys/smp.h>
#include <sys/sysctl.h>
@@ -55,11 +54,15 @@
#ifdef SMP
volatile cpuset_t stopped_cpus;
volatile cpuset_t started_cpus;
+volatile cpuset_t suspended_cpus;
cpuset_t hlt_cpus_mask;
cpuset_t logical_cpus_mask;
void (*cpustop_restartfunc)(void);
#endif
+
+static int sysctl_kern_smp_active(SYSCTL_HANDLER_ARGS);
+
/* This is used in modules that need to work in both SMP and UP. */
cpuset_t all_cpus;
@@ -79,9 +82,8 @@
SYSCTL_INT(_kern_smp, OID_AUTO, maxcpus, CTLFLAG_RD|CTLFLAG_CAPRD, &mp_maxcpus,
0, "Max number of CPUs that the system was compiled for.");
-int smp_active = 0; /* are the APs allowed to run? */
-SYSCTL_INT(_kern_smp, OID_AUTO, active, CTLFLAG_RW, &smp_active, 0,
- "Number of Auxillary Processors (APs) that were successfully started");
+SYSCTL_PROC(_kern_smp, OID_AUTO, active, CTLFLAG_RD | CTLTYPE_INT, NULL, 0,
+ sysctl_kern_smp_active, "I", "Indicates system is running in SMP mode");
int smp_disabled = 0; /* has smp been disabled? */
SYSCTL_INT(_kern_smp, OID_AUTO, disabled, CTLFLAG_RDTUN|CTLFLAG_CAPRD,
@@ -147,7 +149,7 @@
}
cpu_mp_start();
- printf("MidnightBSD/SMP: Multiprocessor System Detected: %d CPUs\n",
+ printf("FreeBSD/SMP: Multiprocessor System Detected: %d CPUs\n",
mp_ncpus);
cpu_mp_announce();
}
@@ -207,6 +209,7 @@
#endif
static volatile u_int stopping_cpu = NOCPU;
int i;
+ volatile cpuset_t *cpus;
KASSERT(
#if defined(__amd64__) || defined(__i386__)
@@ -222,6 +225,18 @@
CTR2(KTR_SMP, "stop_cpus(%s) with %u type",
cpusetobj_strprint(cpusetbuf, &map), type);
+#if defined(__amd64__) || defined(__i386__)
+ /*
+ * When suspending, ensure there are are no IPIs in progress.
+ * IPIs that have been issued, but not yet delivered (e.g.
+ * not pending on a vCPU when running under virtualization)
+ * will be lost, violating FreeBSD's assumption of reliable
+ * IPI delivery.
+ */
+ if (type == IPI_SUSPEND)
+ mtx_lock_spin(&smp_ipi_mtx);
+#endif
+
if (stopping_cpu != PCPU_GET(cpuid))
while (atomic_cmpset_int(&stopping_cpu, NOCPU,
PCPU_GET(cpuid)) == 0)
@@ -231,8 +246,15 @@
/* send the stop IPI to all CPUs in map */
ipi_selected(map, type);
+#if defined(__amd64__) || defined(__i386__)
+ if (type == IPI_SUSPEND)
+ cpus = &suspended_cpus;
+ else
+#endif
+ cpus = &stopped_cpus;
+
i = 0;
- while (!CPU_SUBSET(&stopped_cpus, &map)) {
+ while (!CPU_SUBSET(cpus, &map)) {
/* spin */
cpu_spinwait();
i++;
@@ -242,6 +264,11 @@
}
}
+#if defined(__amd64__) || defined(__i386__)
+ if (type == IPI_SUSPEND)
+ mtx_unlock_spin(&smp_ipi_mtx);
+#endif
+
stopping_cpu = NOCPU;
return (1);
}
@@ -282,28 +309,65 @@
* 0: NA
* 1: ok
*/
-int
-restart_cpus(cpuset_t map)
+static int
+generic_restart_cpus(cpuset_t map, u_int type)
{
#ifdef KTR
char cpusetbuf[CPUSETBUFSIZ];
#endif
+ volatile cpuset_t *cpus;
+ KASSERT(
+#if defined(__amd64__) || defined(__i386__)
+ type == IPI_STOP || type == IPI_STOP_HARD || type == IPI_SUSPEND,
+#else
+ type == IPI_STOP || type == IPI_STOP_HARD,
+#endif
+ ("%s: invalid stop type", __func__));
+
if (!smp_started)
return 0;
CTR1(KTR_SMP, "restart_cpus(%s)", cpusetobj_strprint(cpusetbuf, &map));
+#if defined(__amd64__) || defined(__i386__)
+ if (type == IPI_SUSPEND)
+ cpus = &resuming_cpus;
+ else
+#endif
+ cpus = &stopped_cpus;
+
/* signal other cpus to restart */
- CPU_COPY_STORE_REL(&map, &started_cpus);
+#if defined(__amd64__) || defined(__i386__)
+ if (type == IPI_SUSPEND)
+ CPU_COPY_STORE_REL(&map, &toresume_cpus);
+ else
+#endif
+ CPU_COPY_STORE_REL(&map, &started_cpus);
/* wait for each to clear its bit */
- while (CPU_OVERLAP(&stopped_cpus, &map))
+ while (CPU_OVERLAP(cpus, &map))
cpu_spinwait();
return 1;
}
+int
+restart_cpus(cpuset_t map)
+{
+
+ return (generic_restart_cpus(map, IPI_STOP));
+}
+
+#if defined(__amd64__) || defined(__i386__)
+int
+resume_cpus(cpuset_t map)
+{
+
+ return (generic_restart_cpus(map, IPI_SUSPEND));
+}
+#endif
+
/*
* All-CPU rendezvous. CPUs are signalled, all execute the setup function
* (if specified), rendezvous, execute the action function (if specified),
@@ -725,3 +789,65 @@
KASSERT((!smp_started),("smp_no_rendevous called and smp is started"));
#endif
}
+
+/*
+ * Wait specified idle threads to switch once. This ensures that even
+ * preempted threads have cycled through the switch function once,
+ * exiting their codepaths. This allows us to change global pointers
+ * with no other synchronization.
+ */
+int
+quiesce_cpus(cpuset_t map, const char *wmesg, int prio)
+{
+ struct pcpu *pcpu;
+ u_int gen[MAXCPU];
+ int error;
+ int cpu;
+
+ error = 0;
+ for (cpu = 0; cpu <= mp_maxid; cpu++) {
+ if (!CPU_ISSET(cpu, &map) || CPU_ABSENT(cpu))
+ continue;
+ pcpu = pcpu_find(cpu);
+ gen[cpu] = pcpu->pc_idlethread->td_generation;
+ }
+ for (cpu = 0; cpu <= mp_maxid; cpu++) {
+ if (!CPU_ISSET(cpu, &map) || CPU_ABSENT(cpu))
+ continue;
+ pcpu = pcpu_find(cpu);
+ thread_lock(curthread);
+ sched_bind(curthread, cpu);
+ thread_unlock(curthread);
+ while (gen[cpu] == pcpu->pc_idlethread->td_generation) {
+ error = tsleep(quiesce_cpus, prio, wmesg, 1);
+ if (error != EWOULDBLOCK)
+ goto out;
+ error = 0;
+ }
+ }
+out:
+ thread_lock(curthread);
+ sched_unbind(curthread);
+ thread_unlock(curthread);
+
+ return (error);
+}
+
+int
+quiesce_all_cpus(const char *wmesg, int prio)
+{
+
+ return quiesce_cpus(all_cpus, wmesg, prio);
+}
+
+/* Extra care is taken with this sysctl because the data type is volatile */
+static int
+sysctl_kern_smp_active(SYSCTL_HANDLER_ARGS)
+{
+ int error, active;
+
+ active = smp_started;
+ error = SYSCTL_OUT(req, &active, sizeof(active));
+ return (error);
+}
+
Modified: trunk/sys/kern/subr_stack.c
===================================================================
--- trunk/sys/kern/subr_stack.c 2018-05-26 14:26:33 UTC (rev 9955)
+++ trunk/sys/kern/subr_stack.c 2018-05-26 14:27:13 UTC (rev 9956)
@@ -1,3 +1,4 @@
+/* $MidnightBSD$ */
/*-
* Copyright (c) 2005 Antoine Brodin
* All rights reserved.
@@ -27,7 +28,7 @@
#include "opt_ddb.h"
#include <sys/cdefs.h>
-__FBSDID("$MidnightBSD$");
+__FBSDID("$FreeBSD: stable/10/sys/kern/subr_stack.c 227581 2011-11-16 19:06:55Z pjd $");
#include <sys/param.h>
#include <sys/kernel.h>
@@ -77,7 +78,7 @@
}
void
-stack_copy(struct stack *src, struct stack *dst)
+stack_copy(const struct stack *src, struct stack *dst)
{
*dst = *src;
@@ -91,7 +92,7 @@
}
void
-stack_print(struct stack *st)
+stack_print(const struct stack *st)
{
char namebuf[64];
long offset;
@@ -107,7 +108,7 @@
}
void
-stack_print_short(struct stack *st)
+stack_print_short(const struct stack *st)
{
char namebuf[64];
long offset;
@@ -127,7 +128,7 @@
}
void
-stack_print_ddb(struct stack *st)
+stack_print_ddb(const struct stack *st)
{
const char *name;
long offset;
@@ -143,7 +144,7 @@
#ifdef DDB
void
-stack_print_short_ddb(struct stack *st)
+stack_print_short_ddb(const struct stack *st)
{
const char *name;
long offset;
@@ -167,7 +168,7 @@
* other for use in the live kernel.
*/
void
-stack_sbuf_print(struct sbuf *sb, struct stack *st)
+stack_sbuf_print(struct sbuf *sb, const struct stack *st)
{
char namebuf[64];
long offset;
@@ -184,7 +185,7 @@
#ifdef DDB
void
-stack_sbuf_print_ddb(struct sbuf *sb, struct stack *st)
+stack_sbuf_print_ddb(struct sbuf *sb, const struct stack *st)
{
const char *name;
long offset;
@@ -201,8 +202,8 @@
#ifdef KTR
void
-stack_ktr(u_int mask, const char *file, int line, struct stack *st, u_int depth,
- int cheap)
+stack_ktr(u_int mask, const char *file, int line, const struct stack *st,
+ u_int depth, int cheap)
{
#ifdef DDB
const char *name;
Modified: trunk/sys/kern/subr_syscall.c
===================================================================
--- trunk/sys/kern/subr_syscall.c 2018-05-26 14:26:33 UTC (rev 9955)
+++ trunk/sys/kern/subr_syscall.c 2018-05-26 14:27:13 UTC (rev 9956)
@@ -1,3 +1,4 @@
+/* $MidnightBSD$ */
/*-
* Copyright (C) 1994, David Greenman
* Copyright (c) 1990, 1993
@@ -42,9 +43,9 @@
#include "opt_ktrace.h"
#include "opt_kdtrace.h"
-__FBSDID("$MidnightBSD$");
+__FBSDID("$FreeBSD: stable/10/sys/kern/subr_syscall.c 315949 2017-03-25 13:33:23Z badger $");
-#include <sys/capability.h>
+#include <sys/capsicum.h>
#include <sys/ktr.h>
#ifdef KTRACE
#include <sys/uio.h>
@@ -64,30 +65,32 @@
td->td_pticks = 0;
if (td->td_ucred != p->p_ucred)
cred_update_thread(td);
- if (p->p_flag & P_TRACED) {
- traced = 1;
+ traced = (p->p_flag & P_TRACED) != 0;
+ if (traced || td->td_dbgflags & TDB_USERWR) {
PROC_LOCK(p);
td->td_dbgflags &= ~TDB_USERWR;
- td->td_dbgflags |= TDB_SCE;
+ if (traced)
+ td->td_dbgflags |= TDB_SCE;
PROC_UNLOCK(p);
- } else
- traced = 0;
+ }
error = (p->p_sysent->sv_fetch_syscall_args)(td, sa);
#ifdef KTRACE
if (KTRPOINT(td, KTR_SYSCALL))
ktrsyscall(sa->code, sa->narg, sa->args);
#endif
+ KTR_START4(KTR_SYSC, "syscall", syscallname(p, sa->code),
+ (uintptr_t)td, "pid:%d", td->td_proc->p_pid, "arg0:%p", sa->args[0],
+ "arg1:%p", sa->args[1], "arg2:%p", sa->args[2]);
- CTR6(KTR_SYSC,
-"syscall: td=%p pid %d %s (%#lx, %#lx, %#lx)",
- td, td->td_proc->p_pid, syscallname(p, sa->code),
- sa->args[0], sa->args[1], sa->args[2]);
+ if (error == 0) {
- if (error == 0) {
STOPEVENT(p, S_SCE, sa->narg);
- if (p->p_flag & P_TRACED && p->p_stops & S_PT_SCE) {
+ if (p->p_flag & P_TRACED) {
PROC_LOCK(p);
- ptracestop((td), SIGTRAP);
+ td->td_dbg_sc_code = sa->code;
+ td->td_dbg_sc_narg = sa->narg;
+ if (p->p_ptevents & PTRACE_SCE)
+ ptracestop((td), SIGTRAP, NULL);
PROC_UNLOCK(p);
}
if (td->td_dbgflags & TDB_USERWR) {
@@ -96,6 +99,10 @@
* debugger modified registers or memory.
*/
error = (p->p_sysent->sv_fetch_syscall_args)(td, sa);
+ PROC_LOCK(p);
+ td->td_dbg_sc_code = sa->code;
+ td->td_dbg_sc_narg = sa->narg;
+ PROC_UNLOCK(p);
#ifdef KTRACE
if (KTRPOINT(td, KTR_SYSCALL))
ktrsyscall(sa->code, sa->narg, sa->args);
@@ -150,10 +157,12 @@
sa->callp, NULL, (error) ? -1 : td->td_retval[0]);
#endif
syscall_thread_exit(td, sa->callp);
- CTR4(KTR_SYSC, "syscall: p=%p error=%d return %#lx %#lx",
- p, error, td->td_retval[0], td->td_retval[1]);
}
retval:
+ KTR_STOP4(KTR_SYSC, "syscall", syscallname(p, sa->code),
+ (uintptr_t)td, "pid:%d", td->td_proc->p_pid, "error:%d", error,
+ "retval0:%#lx", td->td_retval[0], "retval1:%#lx",
+ td->td_retval[1]);
if (traced) {
PROC_LOCK(p);
td->td_dbgflags &= ~TDB_SCE;
@@ -172,31 +181,10 @@
p = td->td_proc;
/*
- * Check for misbehavior.
- */
- WITNESS_WARN(WARN_PANIC, NULL, "System call %s returning",
- syscallname(p, sa->code));
- KASSERT(td->td_critnest == 0,
- ("System call %s returning in a critical section",
- syscallname(p, sa->code)));
- KASSERT(td->td_locks == 0,
- ("System call %s returning with %d locks held",
- syscallname(p, sa->code), td->td_locks));
- KASSERT((td->td_pflags & TDP_NOFAULTING) == 0,
- ("System call %s returning with pagefaults disabled",
- syscallname(p, sa->code)));
- KASSERT((td->td_pflags & TDP_NOSLEEPING) == 0,
- ("System call %s returning with sleep disabled",
- syscallname(p, sa->code)));
-
- /*
* Handle reschedule and other end-of-syscall issues
*/
userret(td, td->td_frame);
- CTR4(KTR_SYSC, "syscall %s exit thread %p pid %d proc %s",
- syscallname(p, sa->code), td, td->td_proc->p_pid, td->td_name);
-
#ifdef KTRACE
if (KTRPOINT(td, KTR_SYSRET)) {
ktrsysret(sa->code, (td->td_pflags & TDP_NERRNO) == 0 ?
@@ -228,8 +216,8 @@
*/
if (traced &&
((td->td_dbgflags & (TDB_FORK | TDB_EXEC)) != 0 ||
- (p->p_stops & S_PT_SCX) != 0))
- ptracestop(td, SIGTRAP);
+ (p->p_ptevents & PTRACE_SCX) != 0))
+ ptracestop(td, SIGTRAP, NULL);
td->td_dbgflags &= ~(TDB_SCX | TDB_EXEC | TDB_FORK);
PROC_UNLOCK(p);
}
@@ -247,9 +235,28 @@
*/
td->td_pflags &= ~TDP_RFPPWAIT;
p2 = td->td_rfppwait_p;
+again:
PROC_LOCK(p2);
- while (p2->p_flag & P_PPWAIT)
- cv_wait(&p2->p_pwait, &p2->p_mtx);
+ while (p2->p_flag & P_PPWAIT) {
+ PROC_LOCK(p);
+ if (thread_suspend_check_needed()) {
+ PROC_UNLOCK(p2);
+ thread_suspend_check(0);
+ PROC_UNLOCK(p);
+ goto again;
+ } else {
+ PROC_UNLOCK(p);
+ }
+ cv_timedwait(&p2->p_pwait, &p2->p_mtx, hz);
+ }
PROC_UNLOCK(p2);
+
+ if (td->td_dbgflags & TDB_VFORK) {
+ PROC_LOCK(p);
+ if (p->p_ptevents & PTRACE_VFORK)
+ ptracestop(td, SIGTRAP, NULL);
+ td->td_dbgflags &= ~TDB_VFORK;
+ PROC_UNLOCK(p);
+ }
}
}
Modified: trunk/sys/kern/subr_taskqueue.c
===================================================================
--- trunk/sys/kern/subr_taskqueue.c 2018-05-26 14:26:33 UTC (rev 9955)
+++ trunk/sys/kern/subr_taskqueue.c 2018-05-26 14:27:13 UTC (rev 9956)
@@ -1,3 +1,4 @@
+/* $MidnightBSD$ */
/*-
* Copyright (c) 2000 Doug Rabson
* All rights reserved.
@@ -25,7 +26,7 @@
*/
#include <sys/cdefs.h>
-__FBSDID("$MidnightBSD$");
+__FBSDID("$FreeBSD: stable/10/sys/kern/subr_taskqueue.c 315268 2017-03-14 16:00:33Z hselasky $");
#include <sys/param.h>
#include <sys/systm.h>
@@ -46,6 +47,9 @@
static MALLOC_DEFINE(M_TASKQUEUE, "taskqueue", "Task Queues");
static void *taskqueue_giant_ih;
static void *taskqueue_ih;
+static void taskqueue_fast_enqueue(void *);
+static void taskqueue_swi_enqueue(void *);
+static void taskqueue_swi_giant_enqueue(void *);
struct taskqueue_busy {
struct task *tb_running;
@@ -63,13 +67,16 @@
int tq_spin;
int tq_flags;
int tq_callouts;
+ taskqueue_callback_fn tq_callbacks[TASKQUEUE_NUM_CALLBACKS];
+ void *tq_cb_contexts[TASKQUEUE_NUM_CALLBACKS];
};
#define TQ_FLAGS_ACTIVE (1 << 0)
#define TQ_FLAGS_BLOCKED (1 << 1)
-#define TQ_FLAGS_PENDING (1 << 2)
+#define TQ_FLAGS_UNLOCKED_ENQUEUE (1 << 2)
#define DT_CALLOUT_ARMED (1 << 0)
+#define DT_DRAIN_IN_PROGRESS (1 << 1)
#define TQ_LOCK(tq) \
do { \
@@ -78,6 +85,7 @@
else \
mtx_lock(&(tq)->tq_mutex); \
} while (0)
+#define TQ_ASSERT_LOCKED(tq) mtx_assert(&(tq)->tq_mutex, MA_OWNED)
#define TQ_UNLOCK(tq) \
do { \
@@ -86,6 +94,7 @@
else \
mtx_unlock(&(tq)->tq_mutex); \
} while (0)
+#define TQ_ASSERT_UNLOCKED(tq) mtx_assert(&(tq)->tq_mutex, MA_NOTOWNED)
void
_timeout_task_init(struct taskqueue *queue, struct timeout_task *timeout_task,
@@ -93,7 +102,8 @@
{
TASK_INIT(&timeout_task->t, priority, func, context);
- callout_init_mtx(&timeout_task->c, &queue->tq_mutex, 0);
+ callout_init_mtx(&timeout_task->c, &queue->tq_mutex,
+ CALLOUT_RETURNUNLOCKED);
timeout_task->q = queue;
timeout_task->f = 0;
}
@@ -124,6 +134,11 @@
queue->tq_context = context;
queue->tq_spin = (mtxflags & MTX_SPIN) != 0;
queue->tq_flags |= TQ_FLAGS_ACTIVE;
+ if (enqueue == taskqueue_fast_enqueue ||
+ enqueue == taskqueue_swi_enqueue ||
+ enqueue == taskqueue_swi_giant_enqueue ||
+ enqueue == taskqueue_thread_enqueue)
+ queue->tq_flags |= TQ_FLAGS_UNLOCKED_ENQUEUE;
mtx_init(&queue->tq_mutex, mtxname, NULL, mtxflags);
return queue;
@@ -137,6 +152,23 @@
MTX_DEF, "taskqueue");
}
+void
+taskqueue_set_callback(struct taskqueue *queue,
+ enum taskqueue_callback_type cb_type, taskqueue_callback_fn callback,
+ void *context)
+{
+
+ KASSERT(((cb_type >= TASKQUEUE_CALLBACK_TYPE_MIN) &&
+ (cb_type <= TASKQUEUE_CALLBACK_TYPE_MAX)),
+ ("Callback type %d not valid, must be %d-%d", cb_type,
+ TASKQUEUE_CALLBACK_TYPE_MIN, TASKQUEUE_CALLBACK_TYPE_MAX));
+ KASSERT((queue->tq_callbacks[cb_type] == NULL),
+ ("Re-initialization of taskqueue callback?"));
+
+ queue->tq_callbacks[cb_type] = callback;
+ queue->tq_cb_contexts[cb_type] = context;
+}
+
/*
* Signal a taskqueue thread to terminate.
*/
@@ -176,6 +208,7 @@
if (task->ta_pending) {
if (task->ta_pending < USHRT_MAX)
task->ta_pending++;
+ TQ_UNLOCK(queue);
return (0);
}
@@ -199,11 +232,14 @@
}
task->ta_pending = 1;
+ if ((queue->tq_flags & TQ_FLAGS_UNLOCKED_ENQUEUE) != 0)
+ TQ_UNLOCK(queue);
if ((queue->tq_flags & TQ_FLAGS_BLOCKED) == 0)
queue->tq_enqueue(queue->tq_context);
- else
- queue->tq_flags |= TQ_FLAGS_PENDING;
+ if ((queue->tq_flags & TQ_FLAGS_UNLOCKED_ENQUEUE) == 0)
+ TQ_UNLOCK(queue);
+ /* Return with lock released. */
return (0);
}
int
@@ -213,7 +249,7 @@
TQ_LOCK(queue);
res = taskqueue_enqueue_locked(queue, task);
- TQ_UNLOCK(queue);
+ /* The lock is released inside. */
return (res);
}
@@ -230,6 +266,7 @@
timeout_task->f &= ~DT_CALLOUT_ARMED;
queue->tq_callouts--;
taskqueue_enqueue_locked(timeout_task->q, &timeout_task->t);
+ /* The lock is released inside. */
}
int
@@ -244,8 +281,13 @@
KASSERT(!queue->tq_spin, ("Timeout for spin-queue"));
timeout_task->q = queue;
res = timeout_task->t.ta_pending;
- if (ticks == 0) {
+ if (timeout_task->f & DT_DRAIN_IN_PROGRESS) {
+ /* Do nothing */
+ TQ_UNLOCK(queue);
+ res = -1;
+ } else if (ticks == 0) {
taskqueue_enqueue_locked(queue, &timeout_task->t);
+ /* The lock is released inside. */
} else {
if ((timeout_task->f & DT_CALLOUT_ARMED) != 0) {
res++;
@@ -259,11 +301,20 @@
callout_reset(&timeout_task->c, ticks,
taskqueue_timeout_func, timeout_task);
}
+ TQ_UNLOCK(queue);
}
- TQ_UNLOCK(queue);
return (res);
}
+static void
+taskqueue_drain_running(struct taskqueue *queue)
+{
+
+ while (!TAILQ_EMPTY(&queue->tq_active))
+ TQ_SLEEP(queue, &queue->tq_active, &queue->tq_mutex,
+ PWAIT, "-", 0);
+}
+
void
taskqueue_block(struct taskqueue *queue)
{
@@ -279,10 +330,8 @@
TQ_LOCK(queue);
queue->tq_flags &= ~TQ_FLAGS_BLOCKED;
- if (queue->tq_flags & TQ_FLAGS_PENDING) {
- queue->tq_flags &= ~TQ_FLAGS_PENDING;
+ if (!STAILQ_EMPTY(&queue->tq_queue))
queue->tq_enqueue(queue->tq_context);
- }
TQ_UNLOCK(queue);
}
@@ -293,7 +342,7 @@
struct task *task;
int pending;
- mtx_assert(&queue->tq_mutex, MA_OWNED);
+ TQ_ASSERT_LOCKED(queue);
tb.tb_running = NULL;
TAILQ_INSERT_TAIL(&queue->tq_active, &tb, tb_link);
@@ -316,6 +365,8 @@
wakeup(task);
}
TAILQ_REMOVE(&queue->tq_active, &tb, tb_link);
+ if (TAILQ_EMPTY(&queue->tq_active))
+ wakeup(&queue->tq_active);
}
void
@@ -332,7 +383,7 @@
{
struct taskqueue_busy *tb;
- mtx_assert(&queue->tq_mutex, MA_OWNED);
+ TQ_ASSERT_LOCKED(queue);
TAILQ_FOREACH(tb, &queue->tq_active, tb_link) {
if (tb->tb_running == task)
return (1);
@@ -340,6 +391,23 @@
return (0);
}
+/*
+ * Only use this function in single threaded contexts. It returns
+ * non-zero if the given task is either pending or running. Else the
+ * task is idle and can be queued again or freed.
+ */
+int
+taskqueue_poll_is_busy(struct taskqueue *queue, struct task *task)
+{
+ int retval;
+
+ TQ_LOCK(queue);
+ retval = task->ta_pending > 0 || task_is_running(queue, task);
+ TQ_UNLOCK(queue);
+
+ return (retval);
+}
+
static int
taskqueue_cancel_locked(struct taskqueue *queue, struct task *task,
u_int *pendp)
@@ -356,11 +424,9 @@
int
taskqueue_cancel(struct taskqueue *queue, struct task *task, u_int *pendp)
{
- u_int pending;
int error;
TQ_LOCK(queue);
- pending = task->ta_pending;
error = taskqueue_cancel_locked(queue, task, pendp);
TQ_UNLOCK(queue);
@@ -402,12 +468,64 @@
}
void
+taskqueue_drain_all(struct taskqueue *queue)
+{
+ struct task *task;
+
+ if (!queue->tq_spin)
+ WITNESS_WARN(WARN_GIANTOK | WARN_SLEEPOK, NULL, __func__);
+
+ TQ_LOCK(queue);
+ task = STAILQ_LAST(&queue->tq_queue, task, ta_link);
+ while (task != NULL && task->ta_pending != 0) {
+ struct task *oldtask;
+ TQ_SLEEP(queue, task, &queue->tq_mutex, PWAIT, "-", 0);
+ /*
+ * While we were asleeep the last entry may have been freed.
+ * We need to check if it's still even in the queue.
+ * Not perfect, but it's better than referencing bad memory.
+ * first guess is the current 'end of queue' but if a new
+ * item has been added we need to take the expensive path
+ * Better fix in 11.
+ */
+ oldtask = task;
+ if (oldtask !=
+ (task = STAILQ_LAST(&queue->tq_queue, task, ta_link))) {
+ STAILQ_FOREACH(task, &queue->tq_queue, ta_link) {
+ if (task == oldtask)
+ break;
+ }
+ }
+ }
+ taskqueue_drain_running(queue);
+ KASSERT(STAILQ_EMPTY(&queue->tq_queue),
+ ("taskqueue queue is not empty after draining"));
+ TQ_UNLOCK(queue);
+}
+
+void
taskqueue_drain_timeout(struct taskqueue *queue,
struct timeout_task *timeout_task)
{
+ /*
+ * Set flag to prevent timer from re-starting during drain:
+ */
+ TQ_LOCK(queue);
+ KASSERT((timeout_task->f & DT_DRAIN_IN_PROGRESS) == 0,
+ ("Drain already in progress"));
+ timeout_task->f |= DT_DRAIN_IN_PROGRESS;
+ TQ_UNLOCK(queue);
+
callout_drain(&timeout_task->c);
taskqueue_drain(queue, &timeout_task->t);
+
+ /*
+ * Clear flag to allow timer to re-start:
+ */
+ TQ_LOCK(queue);
+ timeout_task->f &= ~DT_DRAIN_IN_PROGRESS;
+ TQ_UNLOCK(queue);
}
static void
@@ -489,6 +607,18 @@
return (0);
}
+static inline void
+taskqueue_run_callback(struct taskqueue *tq,
+ enum taskqueue_callback_type cb_type)
+{
+ taskqueue_callback_fn tq_callback;
+
+ TQ_ASSERT_UNLOCKED(tq);
+ tq_callback = tq->tq_callbacks[cb_type];
+ if (tq_callback != NULL)
+ tq_callback(tq->tq_cb_contexts[cb_type]);
+}
+
void
taskqueue_thread_loop(void *arg)
{
@@ -496,6 +626,7 @@
tqp = arg;
tq = *tqp;
+ taskqueue_run_callback(tq, TASKQUEUE_CALLBACK_TYPE_INIT);
TQ_LOCK(tq);
while ((tq->tq_flags & TQ_FLAGS_ACTIVE) != 0) {
taskqueue_run_locked(tq);
@@ -510,6 +641,15 @@
}
taskqueue_run_locked(tq);
+ /*
+ * This thread is on its way out, so just drop the lock temporarily
+ * in order to call the shutdown callback. This allows the callback
+ * to look at the taskqueue, even just before it dies.
+ */
+ TQ_UNLOCK(tq);
+ taskqueue_run_callback(tq, TASKQUEUE_CALLBACK_TYPE_SHUTDOWN);
+ TQ_LOCK(tq);
+
/* rendezvous with thread that asked us to terminate */
tq->tq_tcount--;
wakeup_one(tq->tq_threads);
@@ -525,7 +665,6 @@
tqp = context;
tq = *tqp;
- mtx_assert(&tq->tq_mutex, MA_OWNED);
wakeup_one(tq);
}
@@ -577,7 +716,6 @@
{
int i, j, ret = 0;
- TQ_LOCK(queue);
for (i = 0, j = 0; ; i++) {
if (queue->tq_threads[i] == NULL)
continue;
@@ -588,6 +726,5 @@
if (++j >= queue->tq_tcount)
break;
}
- TQ_UNLOCK(queue);
return (ret);
}
Added: trunk/sys/kern/subr_terminal.c
===================================================================
--- trunk/sys/kern/subr_terminal.c (rev 0)
+++ trunk/sys/kern/subr_terminal.c 2018-05-26 14:27:13 UTC (rev 9956)
@@ -0,0 +1,632 @@
+/* $MidnightBSD$ */
+/*-
+ * Copyright (c) 2009 The FreeBSD Foundation
+ * All rights reserved.
+ *
+ * This software was developed by Ed Schouten under sponsorship from the
+ * FreeBSD Foundation.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ * 1. Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ * 2. Redistributions in binary form must reproduce the above copyright
+ * notice, this list of conditions and the following disclaimer in the
+ * documentation and/or other materials provided with the distribution.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND
+ * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+ * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
+ * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE
+ * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
+ * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
+ * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
+ * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
+ * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
+ * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
+ * SUCH DAMAGE.
+ */
+
+#include <sys/cdefs.h>
+__FBSDID("$FreeBSD: stable/10/sys/kern/subr_terminal.c 274860 2014-11-22 16:55:55Z dumbbell $");
+
+#include <sys/param.h>
+#include <sys/cons.h>
+#include <sys/consio.h>
+#include <sys/kernel.h>
+#include <sys/lock.h>
+#include <sys/malloc.h>
+#include <sys/mutex.h>
+#include <sys/systm.h>
+#include <sys/terminal.h>
+#include <sys/tty.h>
+
+#include <machine/stdarg.h>
+
+static MALLOC_DEFINE(M_TERMINAL, "terminal", "terminal device");
+
+/*
+ * Locking.
+ *
+ * Normally we don't need to lock down the terminal emulator, because
+ * the TTY lock is already held when calling teken_input().
+ * Unfortunately this is not the case when the terminal acts as a
+ * console device, because cnputc() can be called at the same time.
+ * This means terminals may need to be locked down using a spin lock.
+ */
+#define TERMINAL_LOCK(tm) do { \
+ if ((tm)->tm_flags & TF_CONS) \
+ mtx_lock_spin(&(tm)->tm_mtx); \
+ else if ((tm)->tm_tty != NULL) \
+ tty_lock((tm)->tm_tty); \
+} while (0)
+#define TERMINAL_UNLOCK(tm) do { \
+ if ((tm)->tm_flags & TF_CONS) \
+ mtx_unlock_spin(&(tm)->tm_mtx); \
+ else if ((tm)->tm_tty != NULL) \
+ tty_unlock((tm)->tm_tty); \
+} while (0)
+#define TERMINAL_LOCK_TTY(tm) do { \
+ if ((tm)->tm_flags & TF_CONS) \
+ mtx_lock_spin(&(tm)->tm_mtx); \
+} while (0)
+#define TERMINAL_UNLOCK_TTY(tm) do { \
+ if ((tm)->tm_flags & TF_CONS) \
+ mtx_unlock_spin(&(tm)->tm_mtx); \
+} while (0)
+#define TERMINAL_LOCK_CONS(tm) mtx_lock_spin(&(tm)->tm_mtx)
+#define TERMINAL_UNLOCK_CONS(tm) mtx_unlock_spin(&(tm)->tm_mtx)
+
+/*
+ * TTY routines.
+ */
+
+static tsw_open_t termtty_open;
+static tsw_close_t termtty_close;
+static tsw_outwakeup_t termtty_outwakeup;
+static tsw_ioctl_t termtty_ioctl;
+static tsw_mmap_t termtty_mmap;
+
+static struct ttydevsw terminal_tty_class = {
+ .tsw_open = termtty_open,
+ .tsw_close = termtty_close,
+ .tsw_outwakeup = termtty_outwakeup,
+ .tsw_ioctl = termtty_ioctl,
+ .tsw_mmap = termtty_mmap,
+};
+
+/*
+ * Terminal emulator routines.
+ */
+
+static tf_bell_t termteken_bell;
+static tf_cursor_t termteken_cursor;
+static tf_putchar_t termteken_putchar;
+static tf_fill_t termteken_fill;
+static tf_copy_t termteken_copy;
+static tf_param_t termteken_param;
+static tf_respond_t termteken_respond;
+
+static teken_funcs_t terminal_drawmethods = {
+ .tf_bell = termteken_bell,
+ .tf_cursor = termteken_cursor,
+ .tf_putchar = termteken_putchar,
+ .tf_fill = termteken_fill,
+ .tf_copy = termteken_copy,
+ .tf_param = termteken_param,
+ .tf_respond = termteken_respond,
+};
+
+/* Kernel message formatting. */
+static const teken_attr_t kernel_message = {
+ .ta_fgcolor = TCHAR_FGCOLOR(TERMINAL_KERN_ATTR),
+ .ta_bgcolor = TCHAR_BGCOLOR(TERMINAL_KERN_ATTR),
+ .ta_format = TCHAR_FORMAT(TERMINAL_KERN_ATTR)
+};
+
+static const teken_attr_t default_message = {
+ .ta_fgcolor = TCHAR_FGCOLOR(TERMINAL_NORM_ATTR),
+ .ta_bgcolor = TCHAR_BGCOLOR(TERMINAL_NORM_ATTR),
+ .ta_format = TCHAR_FORMAT(TERMINAL_NORM_ATTR)
+};
+
+#define TCHAR_CREATE(c, a) ((c) | TFORMAT((a)->ta_format) | \
+ TCOLOR_FG(teken_256to8((a)->ta_fgcolor)) | \
+ TCOLOR_BG(teken_256to8((a)->ta_bgcolor)))
+
+static void
+terminal_init(struct terminal *tm)
+{
+
+ if (tm->tm_flags & TF_CONS)
+ mtx_init(&tm->tm_mtx, "trmlck", NULL, MTX_SPIN);
+ teken_init(&tm->tm_emulator, &terminal_drawmethods, tm);
+ teken_set_defattr(&tm->tm_emulator, &default_message);
+}
+
+struct terminal *
+terminal_alloc(const struct terminal_class *tc, void *softc)
+{
+ struct terminal *tm;
+
+ tm = malloc(sizeof(struct terminal), M_TERMINAL, M_WAITOK|M_ZERO);
+ terminal_init(tm);
+
+ tm->tm_class = tc;
+ tm->tm_softc = softc;
+
+ return (tm);
+}
+
+static void
+terminal_sync_ttysize(struct terminal *tm)
+{
+ struct tty *tp;
+
+ tp = tm->tm_tty;
+ if (tp == NULL)
+ return;
+
+ tty_lock(tp);
+ tty_set_winsize(tp, &tm->tm_winsize);
+ tty_unlock(tp);
+}
+
+void
+terminal_maketty(struct terminal *tm, const char *fmt, ...)
+{
+ struct tty *tp;
+ char name[8];
+ va_list ap;
+
+ va_start(ap, fmt);
+ vsnrprintf(name, sizeof name, 32, fmt, ap);
+ va_end(ap);
+
+ tp = tty_alloc(&terminal_tty_class, tm);
+ tty_makedev(tp, NULL, "%s", name);
+ tm->tm_tty = tp;
+ terminal_sync_ttysize(tm);
+}
+
+void
+terminal_set_cursor(struct terminal *tm, const term_pos_t *pos)
+{
+
+ teken_set_cursor(&tm->tm_emulator, pos);
+}
+
+void
+terminal_set_winsize_blank(struct terminal *tm, const struct winsize *size,
+ int blank, const term_attr_t *attr)
+{
+ term_rect_t r;
+
+ tm->tm_winsize = *size;
+
+ r.tr_begin.tp_row = r.tr_begin.tp_col = 0;
+ r.tr_end.tp_row = size->ws_row;
+ r.tr_end.tp_col = size->ws_col;
+
+ TERMINAL_LOCK(tm);
+ if (blank == 0)
+ teken_set_winsize_noreset(&tm->tm_emulator, &r.tr_end);
+ else
+ teken_set_winsize(&tm->tm_emulator, &r.tr_end);
+ TERMINAL_UNLOCK(tm);
+
+ if ((blank != 0) && !(tm->tm_flags & TF_MUTE))
+ tm->tm_class->tc_fill(tm, &r,
+ TCHAR_CREATE((teken_char_t)' ', attr));
+
+ terminal_sync_ttysize(tm);
+}
+
+void
+terminal_set_winsize(struct terminal *tm, const struct winsize *size)
+{
+
+ terminal_set_winsize_blank(tm, size, 1,
+ (const term_attr_t *)&default_message);
+}
+
+/*
+ * XXX: This function is a kludge. Drivers like vt(4) need to
+ * temporarily stop input when resizing, etc. This should ideally be
+ * handled within the driver.
+ */
+
+void
+terminal_mute(struct terminal *tm, int yes)
+{
+
+ TERMINAL_LOCK(tm);
+ if (yes)
+ tm->tm_flags |= TF_MUTE;
+ else
+ tm->tm_flags &= ~TF_MUTE;
+ TERMINAL_UNLOCK(tm);
+}
+
+void
+terminal_input_char(struct terminal *tm, term_char_t c)
+{
+ struct tty *tp;
+
+ tp = tm->tm_tty;
+ if (tp == NULL)
+ return;
+
+ /*
+ * Strip off any attributes. Also ignore input of second part of
+ * CJK fullwidth characters, as we don't want to return these
+ * characters twice.
+ */
+ if (TCHAR_FORMAT(c) & TF_CJK_RIGHT)
+ return;
+ c = TCHAR_CHARACTER(c);
+
+ tty_lock(tp);
+ /*
+ * Conversion to UTF-8.
+ */
+ if (c < 0x80) {
+ ttydisc_rint(tp, c, 0);
+ } else if (c < 0x800) {
+ char str[2] = {
+ 0xc0 | (c >> 6),
+ 0x80 | (c & 0x3f)
+ };
+
+ ttydisc_rint_simple(tp, str, sizeof str);
+ } else if (c < 0x10000) {
+ char str[3] = {
+ 0xe0 | (c >> 12),
+ 0x80 | ((c >> 6) & 0x3f),
+ 0x80 | (c & 0x3f)
+ };
+
+ ttydisc_rint_simple(tp, str, sizeof str);
+ } else {
+ char str[4] = {
+ 0xf0 | (c >> 18),
+ 0x80 | ((c >> 12) & 0x3f),
+ 0x80 | ((c >> 6) & 0x3f),
+ 0x80 | (c & 0x3f)
+ };
+
+ ttydisc_rint_simple(tp, str, sizeof str);
+ }
+ ttydisc_rint_done(tp);
+ tty_unlock(tp);
+}
+
+void
+terminal_input_raw(struct terminal *tm, char c)
+{
+ struct tty *tp;
+
+ tp = tm->tm_tty;
+ if (tp == NULL)
+ return;
+
+ tty_lock(tp);
+ ttydisc_rint(tp, c, 0);
+ ttydisc_rint_done(tp);
+ tty_unlock(tp);
+}
+
+void
+terminal_input_special(struct terminal *tm, unsigned int k)
+{
+ struct tty *tp;
+ const char *str;
+
+ tp = tm->tm_tty;
+ if (tp == NULL)
+ return;
+
+ str = teken_get_sequence(&tm->tm_emulator, k);
+ if (str == NULL)
+ return;
+
+ tty_lock(tp);
+ ttydisc_rint_simple(tp, str, strlen(str));
+ ttydisc_rint_done(tp);
+ tty_unlock(tp);
+}
+
+/*
+ * Binding with the TTY layer.
+ */
+
+static int
+termtty_open(struct tty *tp)
+{
+ struct terminal *tm = tty_softc(tp);
+
+ tm->tm_class->tc_opened(tm, 1);
+ return (0);
+}
+
+static void
+termtty_close(struct tty *tp)
+{
+ struct terminal *tm = tty_softc(tp);
+
+ tm->tm_class->tc_opened(tm, 0);
+}
+
+static void
+termtty_outwakeup(struct tty *tp)
+{
+ struct terminal *tm = tty_softc(tp);
+ char obuf[128];
+ size_t olen;
+ unsigned int flags = 0;
+
+ while ((olen = ttydisc_getc(tp, obuf, sizeof obuf)) > 0) {
+ TERMINAL_LOCK_TTY(tm);
+ if (!(tm->tm_flags & TF_MUTE)) {
+ tm->tm_flags &= ~TF_BELL;
+ teken_input(&tm->tm_emulator, obuf, olen);
+ flags |= tm->tm_flags;
+ }
+ TERMINAL_UNLOCK_TTY(tm);
+ }
+
+ tm->tm_class->tc_done(tm);
+ if (flags & TF_BELL)
+ tm->tm_class->tc_bell(tm);
+}
+
+static int
+termtty_ioctl(struct tty *tp, u_long cmd, caddr_t data, struct thread *td)
+{
+ struct terminal *tm = tty_softc(tp);
+ int error;
+
+ switch (cmd) {
+ case CONS_GETINFO: {
+ vid_info_t *vi = (vid_info_t *)data;
+ const teken_pos_t *p;
+ int fg, bg;
+
+ if (vi->size != sizeof(vid_info_t))
+ return (EINVAL);
+
+ /* Already help the console driver by filling in some data. */
+ p = teken_get_cursor(&tm->tm_emulator);
+ vi->mv_row = p->tp_row;
+ vi->mv_col = p->tp_col;
+
+ p = teken_get_winsize(&tm->tm_emulator);
+ vi->mv_rsz = p->tp_row;
+ vi->mv_csz = p->tp_col;
+
+ teken_get_defattr_cons25(&tm->tm_emulator, &fg, &bg);
+ vi->mv_norm.fore = fg;
+ vi->mv_norm.back = bg;
+ /* XXX: keep vidcontrol happy; bold backgrounds. */
+ vi->mv_rev.fore = bg;
+ vi->mv_rev.back = fg & 0x7;
+ break;
+ }
+ }
+
+ /*
+ * Unlike various other drivers, this driver will never
+ * deallocate TTYs. This means it's safe to temporarily unlock
+ * the TTY when handling ioctls.
+ */
+ tty_unlock(tp);
+ error = tm->tm_class->tc_ioctl(tm, cmd, data, td);
+ tty_lock(tp);
+ return (error);
+}
+
+static int
+termtty_mmap(struct tty *tp, vm_ooffset_t offset, vm_paddr_t * paddr,
+ int nprot, vm_memattr_t *memattr)
+{
+ struct terminal *tm = tty_softc(tp);
+
+ return (tm->tm_class->tc_mmap(tm, offset, paddr, nprot, memattr));
+}
+
+/*
+ * Binding with the kernel and debug console.
+ */
+
+static cn_probe_t termcn_cnprobe;
+static cn_init_t termcn_cninit;
+static cn_term_t termcn_cnterm;
+static cn_getc_t termcn_cngetc;
+static cn_putc_t termcn_cnputc;
+static cn_grab_t termcn_cngrab;
+static cn_ungrab_t termcn_cnungrab;
+
+const struct consdev_ops termcn_cnops = {
+ .cn_probe = termcn_cnprobe,
+ .cn_init = termcn_cninit,
+ .cn_term = termcn_cnterm,
+ .cn_getc = termcn_cngetc,
+ .cn_putc = termcn_cnputc,
+ .cn_grab = termcn_cngrab,
+ .cn_ungrab = termcn_cnungrab,
+};
+
+void
+termcn_cnregister(struct terminal *tm)
+{
+ struct consdev *cp;
+
+ cp = tm->consdev;
+ if (cp == NULL) {
+ cp = malloc(sizeof(struct consdev), M_TERMINAL,
+ M_WAITOK|M_ZERO);
+ cp->cn_ops = &termcn_cnops;
+ cp->cn_arg = tm;
+ cp->cn_pri = CN_INTERNAL;
+ sprintf(cp->cn_name, "ttyv0");
+
+ tm->tm_flags = TF_CONS;
+ tm->consdev = cp;
+
+ terminal_init(tm);
+ }
+
+ /* Attach terminal as console. */
+ cnadd(cp);
+}
+
+static void
+termcn_cngrab(struct consdev *cp)
+{
+ struct terminal *tm = cp->cn_arg;
+
+ tm->tm_class->tc_cngrab(tm);
+}
+
+static void
+termcn_cnungrab(struct consdev *cp)
+{
+ struct terminal *tm = cp->cn_arg;
+
+ tm->tm_class->tc_cnungrab(tm);
+}
+
+static void
+termcn_cnprobe(struct consdev *cp)
+{
+ struct terminal *tm = cp->cn_arg;
+
+ if (tm == NULL) {
+ cp->cn_pri = CN_DEAD;
+ return;
+ }
+
+ tm->consdev = cp;
+ terminal_init(tm);
+
+ tm->tm_class->tc_cnprobe(tm, cp);
+}
+
+static void
+termcn_cninit(struct consdev *cp)
+{
+
+}
+
+static void
+termcn_cnterm(struct consdev *cp)
+{
+
+}
+
+static int
+termcn_cngetc(struct consdev *cp)
+{
+ struct terminal *tm = cp->cn_arg;
+
+ return (tm->tm_class->tc_cngetc(tm));
+}
+
+static void
+termcn_cnputc(struct consdev *cp, int c)
+{
+ struct terminal *tm = cp->cn_arg;
+ teken_attr_t backup;
+ char cv = c;
+
+ TERMINAL_LOCK_CONS(tm);
+ if (!(tm->tm_flags & TF_MUTE)) {
+ backup = *teken_get_curattr(&tm->tm_emulator);
+ teken_set_curattr(&tm->tm_emulator, &kernel_message);
+ teken_input(&tm->tm_emulator, &cv, 1);
+ teken_set_curattr(&tm->tm_emulator, &backup);
+ }
+ TERMINAL_UNLOCK_CONS(tm);
+
+ tm->tm_class->tc_done(tm);
+}
+
+/*
+ * Binding with the terminal emulator.
+ */
+
+static void
+termteken_bell(void *softc)
+{
+ struct terminal *tm = softc;
+
+ tm->tm_flags |= TF_BELL;
+}
+
+static void
+termteken_cursor(void *softc, const teken_pos_t *p)
+{
+ struct terminal *tm = softc;
+
+ tm->tm_class->tc_cursor(tm, p);
+}
+
+static void
+termteken_putchar(void *softc, const teken_pos_t *p, teken_char_t c,
+ const teken_attr_t *a)
+{
+ struct terminal *tm = softc;
+
+ tm->tm_class->tc_putchar(tm, p, TCHAR_CREATE(c, a));
+}
+
+static void
+termteken_fill(void *softc, const teken_rect_t *r, teken_char_t c,
+ const teken_attr_t *a)
+{
+ struct terminal *tm = softc;
+
+ tm->tm_class->tc_fill(tm, r, TCHAR_CREATE(c, a));
+}
+
+static void
+termteken_copy(void *softc, const teken_rect_t *r, const teken_pos_t *p)
+{
+ struct terminal *tm = softc;
+
+ tm->tm_class->tc_copy(tm, r, p);
+}
+
+static void
+termteken_param(void *softc, int cmd, unsigned int arg)
+{
+ struct terminal *tm = softc;
+
+ tm->tm_class->tc_param(tm, cmd, arg);
+}
+
+static void
+termteken_respond(void *softc, const void *buf, size_t len)
+{
+#if 0
+ struct terminal *tm = softc;
+ struct tty *tp;
+
+ /*
+ * Only inject a response into the TTY if the data actually
+ * originated from the TTY.
+ *
+ * XXX: This cannot be done right now. The TTY could pick up
+ * other locks. It could also in theory cause loops, when the
+ * TTY performs echoing of a command that generates even more
+ * input.
+ */
+ tp = tm->tm_tty;
+ if (tp == NULL)
+ return;
+
+ ttydisc_rint_simple(tp, buf, len);
+ ttydisc_rint_done(tp);
+#endif
+}
Property changes on: trunk/sys/kern/subr_terminal.c
___________________________________________________________________
Added: svn:eol-style
## -0,0 +1 ##
+native
\ No newline at end of property
Added: svn:keywords
## -0,0 +1 ##
+MidnightBSD=%H
\ No newline at end of property
Added: svn:mime-type
## -0,0 +1 ##
+text/plain
\ No newline at end of property
Modified: trunk/sys/kern/subr_trap.c
===================================================================
--- trunk/sys/kern/subr_trap.c 2018-05-26 14:26:33 UTC (rev 9955)
+++ trunk/sys/kern/subr_trap.c 2018-05-26 14:27:13 UTC (rev 9956)
@@ -1,3 +1,4 @@
+/* $MidnightBSD$ */
/*-
* Copyright (C) 1994, David Greenman
* Copyright (c) 1990, 1993
@@ -42,9 +43,8 @@
*/
#include <sys/cdefs.h>
-__FBSDID("$MidnightBSD$");
+__FBSDID("$FreeBSD: stable/10/sys/kern/subr_trap.c 303607 2016-08-01 06:35:35Z kib $");
-#include "opt_capsicum.h"
#include "opt_hwpmc_hooks.h"
#include "opt_ktrace.h"
#include "opt_kdtrace.h"
@@ -52,7 +52,7 @@
#include <sys/param.h>
#include <sys/bus.h>
-#include <sys/capability.h>
+#include <sys/capsicum.h>
#include <sys/kernel.h>
#include <sys/lock.h>
#include <sys/mutex.h>
@@ -61,6 +61,7 @@
#include <sys/ktr.h>
#include <sys/pioctl.h>
#include <sys/ptrace.h>
+#include <sys/racct.h>
#include <sys/resourcevar.h>
#include <sys/sched.h>
#include <sys/signalvar.h>
@@ -93,6 +94,8 @@
#include <security/mac/mac_framework.h>
+void (*softdep_ast_cleanup)(void);
+
/*
* Define the code needed before returning to user mode, for trap and
* syscall.
@@ -106,21 +109,36 @@
td->td_name);
KASSERT((p->p_flag & P_WEXIT) == 0,
("Exiting process returns to usermode"));
-#if 0
#ifdef DIAGNOSTIC
- /* Check that we called signotify() enough. */
- PROC_LOCK(p);
- thread_lock(td);
- if (SIGPENDING(td) && ((td->td_flags & TDF_NEEDSIGCHK) == 0 ||
- (td->td_flags & TDF_ASTPENDING) == 0))
- printf("failed to set signal flags properly for ast()\n");
- thread_unlock(td);
- PROC_UNLOCK(p);
+ /*
+ * Check that we called signotify() enough. For
+ * multi-threaded processes, where signal distribution might
+ * change due to other threads changing sigmask, the check is
+ * racy and cannot be performed reliably.
+ * If current process is vfork child, indicated by P_PPWAIT, then
+ * issignal() ignores stops, so we block the check to avoid
+ * classifying pending signals.
+ */
+ if (p->p_numthreads == 1) {
+ PROC_LOCK(p);
+ thread_lock(td);
+ if ((p->p_flag & P_PPWAIT) == 0) {
+ KASSERT(!SIGPENDING(td) || (td->td_flags &
+ (TDF_NEEDSIGCHK | TDF_ASTPENDING)) ==
+ (TDF_NEEDSIGCHK | TDF_ASTPENDING),
+ ("failed to set signal flags for ast p %p "
+ "td %p fl %x", p, td, td->td_flags));
+ }
+ thread_unlock(td);
+ PROC_UNLOCK(p);
+ }
#endif
-#endif
#ifdef KTRACE
KTRUSERRET(td);
#endif
+ if (softdep_ast_cleanup != NULL)
+ softdep_ast_cleanup();
+
/*
* If this thread tickled GEOM, we need to wait for the giggling to
* stop before we return to userland
@@ -137,12 +155,35 @@
* Let the scheduler adjust our priority etc.
*/
sched_userret(td);
+#ifdef XEN
+ PT_UPDATES_FLUSH();
+#endif
+
+ /*
+ * Check for misbehavior.
+ *
+ * In case there is a callchain tracing ongoing because of
+ * hwpmc(4), skip the scheduler pinning check.
+ * hwpmc(4) subsystem, infact, will collect callchain informations
+ * at ast() checkpoint, which is past userret().
+ */
+ WITNESS_WARN(WARN_PANIC, NULL, "userret: returning");
+ KASSERT(td->td_critnest == 0,
+ ("userret: Returning in a critical section"));
KASSERT(td->td_locks == 0,
- ("userret: Returning with %d locks held.", td->td_locks));
+ ("userret: Returning with %d locks held", td->td_locks));
+ KASSERT((td->td_pflags & TDP_NOFAULTING) == 0,
+ ("userret: Returning with pagefaults disabled"));
+ KASSERT(td->td_no_sleeping == 0,
+ ("userret: Returning with sleep disabled"));
+ KASSERT(td->td_pinned == 0 || (td->td_pflags & TDP_CALLCHAIN) != 0,
+ ("userret: Returning with with pinned thread"));
KASSERT(td->td_vp_reserv == 0,
("userret: Returning while holding vnode reservation"));
KASSERT((td->td_flags & TDF_SBDRY) == 0,
("userret: Returning with stop signals deferred"));
+ KASSERT(td->td_su == NULL,
+ ("userret: Returning with SU cleanup request not handled"));
#ifdef VIMAGE
/* Unfortunately td_vnet_lpush needs VNET_DEBUG. */
VNET_ASSERT(curvnet == NULL,
@@ -150,15 +191,14 @@
__func__, td, p->p_pid, td->td_name, curvnet,
(td->td_vnet_lpush != NULL) ? td->td_vnet_lpush : "N/A"));
#endif
-#ifdef XEN
- PT_UPDATES_FLUSH();
+#ifdef RACCT
+ if (racct_enable) {
+ PROC_LOCK(p);
+ while (p->p_throttled == 1)
+ msleep(p->p_racct, &p->p_mtx, 0, "racct", 0);
+ PROC_UNLOCK(p);
+ }
#endif
-#ifdef RACCT
- PROC_LOCK(p);
- while (p->p_throttled == 1)
- msleep(p->p_racct, &p->p_mtx, 0, "racct", 0);
- PROC_UNLOCK(p);
-#endif
}
/*
@@ -241,6 +281,29 @@
#endif
}
+#ifdef DIAGNOSTIC
+ if (p->p_numthreads == 1 && (flags & TDF_NEEDSIGCHK) == 0) {
+ PROC_LOCK(p);
+ thread_lock(td);
+ /*
+ * Note that TDF_NEEDSIGCHK should be re-read from
+ * td_flags, since signal might have been delivered
+ * after we cleared td_flags above. This is one of
+ * the reason for looping check for AST condition.
+ * See comment in userret() about P_PPWAIT.
+ */
+ if ((p->p_flag & P_PPWAIT) == 0) {
+ KASSERT(!SIGPENDING(td) || (td->td_flags &
+ (TDF_NEEDSIGCHK | TDF_ASTPENDING)) ==
+ (TDF_NEEDSIGCHK | TDF_ASTPENDING),
+ ("failed2 to set signal flags for ast p %p td %p "
+ "fl %x %x", p, td, flags, td->td_flags));
+ }
+ thread_unlock(td);
+ PROC_UNLOCK(p);
+ }
+#endif
+
/*
* Check for signals. Unlocked reads of p_pendingcnt or
* p_siglist might cause process-directed signal to be handled
@@ -250,7 +313,7 @@
!SIGISEMPTY(p->p_siglist)) {
PROC_LOCK(p);
mtx_lock(&p->p_sigacts->ps_mtx);
- while ((sig = cursig(td, SIG_STOP_ALLOWED)) != 0)
+ while ((sig = cursig(td)) != 0)
postsig(sig);
mtx_unlock(&p->p_sigacts->ps_mtx);
PROC_UNLOCK(p);
@@ -271,7 +334,6 @@
}
userret(td, framep);
- mtx_assert(&Giant, MA_NOTOWNED);
}
const char *
Modified: trunk/sys/kern/subr_turnstile.c
===================================================================
--- trunk/sys/kern/subr_turnstile.c 2018-05-26 14:26:33 UTC (rev 9955)
+++ trunk/sys/kern/subr_turnstile.c 2018-05-26 14:27:13 UTC (rev 9956)
@@ -1,3 +1,4 @@
+/* $MidnightBSD$ */
/*-
* Copyright (c) 1998 Berkeley Software Design, Inc. All rights reserved.
*
@@ -25,8 +26,8 @@
* OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
* SUCH DAMAGE.
*
- * from BSDI $Id: subr_turnstile.c,v 1.4 2012-10-09 04:08:16 laffer1 Exp $
- * and BSDI $Id: subr_turnstile.c,v 1.4 2012-10-09 04:08:16 laffer1 Exp $
+ * from BSDI $Id: mutex_witness.c,v 1.1.2.20 2000/04/27 03:10:27 cp Exp $
+ * and BSDI $Id: synch_machdep.c,v 2.3.2.39 2000/04/27 03:10:25 cp Exp $
*/
/*
@@ -57,7 +58,7 @@
*/
#include <sys/cdefs.h>
-__FBSDID("$MidnightBSD$");
+__FBSDID("$FreeBSD: stable/10/sys/kern/subr_turnstile.c 296728 2016-03-12 17:17:34Z kib $");
#include "opt_ddb.h"
#include "opt_kdtrace.h"
@@ -170,8 +171,8 @@
static void turnstile_fini(void *mem, int size);
SDT_PROVIDER_DECLARE(sched);
-SDT_PROBE_DEFINE(sched, , , sleep, sleep);
-SDT_PROBE_DEFINE2(sched, , , wakeup, wakeup, "struct thread *",
+SDT_PROBE_DEFINE(sched, , , sleep);
+SDT_PROBE_DEFINE2(sched, , , wakeup, "struct thread *",
"struct proc *");
/*
@@ -215,10 +216,9 @@
/*
* If the thread is asleep, then we are probably about
- * to deadlock. To make debugging this easier, just
- * panic and tell the user which thread misbehaved so
- * they can hopefully get a stack trace from the truly
- * misbehaving thread.
+ * to deadlock. To make debugging this easier, show
+ * backtrace of misbehaving thread and panic to not
+ * leave the kernel deadlocked.
*/
if (TD_IS_SLEEPING(td)) {
printf(
@@ -1028,8 +1028,7 @@
{
db_printf("%s%p (tid %d, pid %d, \"%s\")\n", prefix, td, td->td_tid,
- td->td_proc->p_pid, td->td_name[0] != '\0' ? td->td_name :
- td->td_name);
+ td->td_proc->p_pid, td->td_name);
}
static void
@@ -1111,8 +1110,7 @@
*/
while (!db_pager_quit) {
db_printf("%sthread %d (pid %d, %s) ", prefix, td->td_tid,
- td->td_proc->p_pid, td->td_name[0] != '\0' ? td->td_name :
- td->td_name);
+ td->td_proc->p_pid, td->td_name);
switch (td->td_state) {
case TDS_INACTIVE:
db_printf("is inactive\n");
@@ -1195,8 +1193,7 @@
*/
while (!db_pager_quit) {
db_printf("%sthread %d (pid %d, %s) ", prefix, td->td_tid,
- td->td_proc->p_pid, td->td_name[0] != '\0' ? td->td_name :
- td->td_name);
+ td->td_proc->p_pid, td->td_name);
switch (td->td_state) {
case TDS_INACTIVE:
db_printf("is inactive\n");
Modified: trunk/sys/kern/subr_uio.c
===================================================================
--- trunk/sys/kern/subr_uio.c 2018-05-26 14:26:33 UTC (rev 9955)
+++ trunk/sys/kern/subr_uio.c 2018-05-26 14:27:13 UTC (rev 9956)
@@ -1,3 +1,4 @@
+/* $MidnightBSD$ */
/*-
* Copyright (c) 1982, 1986, 1991, 1993
* The Regents of the University of California. All rights reserved.
@@ -7,6 +8,11 @@
* Co. or Unix System Laboratories, Inc. and are reproduced herein with
* the permission of UNIX System Laboratories, Inc.
*
+ * Copyright (c) 2014 The FreeBSD Foundation
+ *
+ * Portions of this software were developed by Konstantin Belousov
+ * under sponsorship from the FreeBSD Foundation.
+ *
* Redistribution and use in source and binary forms, with or without
* modification, are permitted provided that the following conditions
* are met:
@@ -35,10 +41,8 @@
*/
#include <sys/cdefs.h>
-__FBSDID("$MidnightBSD$");
+__FBSDID("$FreeBSD: stable/10/sys/kern/subr_uio.c 308103 2016-10-30 11:45:01Z kib $");
-#include "opt_zero.h"
-
#include <sys/param.h>
#include <sys/systm.h>
#include <sys/kernel.h>
@@ -45,9 +49,9 @@
#include <sys/limits.h>
#include <sys/lock.h>
#include <sys/mman.h>
-#include <sys/mutex.h>
#include <sys/proc.h>
#include <sys/resourcevar.h>
+#include <sys/rwlock.h>
#include <sys/sched.h>
#include <sys/sysctl.h>
#include <sys/vnode.h>
@@ -56,80 +60,16 @@
#include <vm/vm_param.h>
#include <vm/vm_extern.h>
#include <vm/vm_page.h>
+#include <vm/vm_pageout.h>
#include <vm/vm_map.h>
-#ifdef ZERO_COPY_SOCKETS
-#include <vm/vm_object.h>
-#endif
-SYSCTL_INT(_kern, KERN_IOV_MAX, iov_max, CTLFLAG_RD, NULL, UIO_MAXIOV,
+#include <machine/bus.h>
+
+SYSCTL_INT(_kern, KERN_IOV_MAX, iov_max, CTLFLAG_RD, SYSCTL_NULL_INT_PTR, UIO_MAXIOV,
"Maximum number of elements in an I/O vector; sysconf(_SC_IOV_MAX)");
static int uiomove_faultflag(void *cp, int n, struct uio *uio, int nofault);
-#ifdef ZERO_COPY_SOCKETS
-/* Declared in uipc_socket.c */
-extern int so_zero_copy_receive;
-
-/*
- * Identify the physical page mapped at the given kernel virtual
- * address. Insert this physical page into the given address space at
- * the given virtual address, replacing the physical page, if any,
- * that already exists there.
- */
-static int
-vm_pgmoveco(vm_map_t mapa, vm_offset_t kaddr, vm_offset_t uaddr)
-{
- vm_map_t map = mapa;
- vm_page_t kern_pg, user_pg;
- vm_object_t uobject;
- vm_map_entry_t entry;
- vm_pindex_t upindex;
- vm_prot_t prot;
- boolean_t wired;
-
- KASSERT((uaddr & PAGE_MASK) == 0,
- ("vm_pgmoveco: uaddr is not page aligned"));
-
- /*
- * Herein the physical page is validated and dirtied. It is
- * unwired in sf_buf_mext().
- */
- kern_pg = PHYS_TO_VM_PAGE(vtophys(kaddr));
- kern_pg->valid = VM_PAGE_BITS_ALL;
- KASSERT(kern_pg->queue == PQ_NONE && kern_pg->wire_count == 1,
- ("vm_pgmoveco: kern_pg is not correctly wired"));
-
- if ((vm_map_lookup(&map, uaddr,
- VM_PROT_WRITE, &entry, &uobject,
- &upindex, &prot, &wired)) != KERN_SUCCESS) {
- return(EFAULT);
- }
- VM_OBJECT_LOCK(uobject);
-retry:
- if ((user_pg = vm_page_lookup(uobject, upindex)) != NULL) {
- if (vm_page_sleep_if_busy(user_pg, TRUE, "vm_pgmoveco"))
- goto retry;
- vm_page_lock(user_pg);
- pmap_remove_all(user_pg);
- vm_page_free(user_pg);
- vm_page_unlock(user_pg);
- } else {
- /*
- * Even if a physical page does not exist in the
- * object chain's first object, a physical page from a
- * backing object may be mapped read only.
- */
- if (uobject->backing_object != NULL)
- pmap_remove(map->pmap, uaddr, uaddr + PAGE_SIZE);
- }
- vm_page_insert(kern_pg, uobject, upindex);
- vm_page_dirty(kern_pg);
- VM_OBJECT_UNLOCK(uobject);
- vm_map_lookup_done(map, entry);
- return(KERN_SUCCESS);
-}
-#endif /* ZERO_COPY_SOCKETS */
-
int
copyin_nofault(const void *udaddr, void *kaddr, size_t len)
{
@@ -152,7 +92,105 @@
return (error);
}
+#define PHYS_PAGE_COUNT(len) (howmany(len, PAGE_SIZE) + 1)
+
int
+physcopyin(void *src, vm_paddr_t dst, size_t len)
+{
+ vm_page_t m[PHYS_PAGE_COUNT(len)];
+ struct iovec iov[1];
+ struct uio uio;
+ int i;
+
+ iov[0].iov_base = src;
+ iov[0].iov_len = len;
+ uio.uio_iov = iov;
+ uio.uio_iovcnt = 1;
+ uio.uio_offset = 0;
+ uio.uio_resid = len;
+ uio.uio_segflg = UIO_SYSSPACE;
+ uio.uio_rw = UIO_WRITE;
+ for (i = 0; i < PHYS_PAGE_COUNT(len); i++, dst += PAGE_SIZE)
+ m[i] = PHYS_TO_VM_PAGE(dst);
+ return (uiomove_fromphys(m, dst & PAGE_MASK, len, &uio));
+}
+
+int
+physcopyout(vm_paddr_t src, void *dst, size_t len)
+{
+ vm_page_t m[PHYS_PAGE_COUNT(len)];
+ struct iovec iov[1];
+ struct uio uio;
+ int i;
+
+ iov[0].iov_base = dst;
+ iov[0].iov_len = len;
+ uio.uio_iov = iov;
+ uio.uio_iovcnt = 1;
+ uio.uio_offset = 0;
+ uio.uio_resid = len;
+ uio.uio_segflg = UIO_SYSSPACE;
+ uio.uio_rw = UIO_READ;
+ for (i = 0; i < PHYS_PAGE_COUNT(len); i++, src += PAGE_SIZE)
+ m[i] = PHYS_TO_VM_PAGE(src);
+ return (uiomove_fromphys(m, src & PAGE_MASK, len, &uio));
+}
+
+#undef PHYS_PAGE_COUNT
+
+int
+physcopyin_vlist(bus_dma_segment_t *src, off_t offset, vm_paddr_t dst,
+ size_t len)
+{
+ size_t seg_len;
+ int error;
+
+ error = 0;
+ while (offset >= src->ds_len) {
+ offset -= src->ds_len;
+ src++;
+ }
+
+ while (len > 0 && error == 0) {
+ seg_len = MIN(src->ds_len - offset, len);
+ error = physcopyin((void *)(uintptr_t)(src->ds_addr + offset),
+ dst, seg_len);
+ offset = 0;
+ src++;
+ len -= seg_len;
+ dst += seg_len;
+ }
+
+ return (error);
+}
+
+int
+physcopyout_vlist(vm_paddr_t src, bus_dma_segment_t *dst, off_t offset,
+ size_t len)
+{
+ size_t seg_len;
+ int error;
+
+ error = 0;
+ while (offset >= dst->ds_len) {
+ offset -= dst->ds_len;
+ dst++;
+ }
+
+ while (len > 0 && error == 0) {
+ seg_len = MIN(dst->ds_len - offset, len);
+ error = physcopyout(src, (void *)(uintptr_t)(dst->ds_addr +
+ offset), seg_len);
+ offset = 0;
+ dst++;
+ len -= seg_len;
+ src += seg_len;
+ }
+
+ return (error);
+}
+
+int
uiomove(void *cp, int n, struct uio *uio)
{
@@ -261,104 +299,7 @@
return (uiomove((char *)buf + offset, n, uio));
}
-#ifdef ZERO_COPY_SOCKETS
/*
- * Experimental support for zero-copy I/O
- */
-static int
-userspaceco(void *cp, u_int cnt, struct uio *uio, int disposable)
-{
- struct iovec *iov;
- int error;
-
- iov = uio->uio_iov;
- if (uio->uio_rw == UIO_READ) {
- if ((so_zero_copy_receive != 0)
- && ((cnt & PAGE_MASK) == 0)
- && ((((intptr_t) iov->iov_base) & PAGE_MASK) == 0)
- && ((uio->uio_offset & PAGE_MASK) == 0)
- && ((((intptr_t) cp) & PAGE_MASK) == 0)
- && (disposable != 0)) {
- /* SOCKET: use page-trading */
- /*
- * We only want to call vm_pgmoveco() on
- * disposeable pages, since it gives the
- * kernel page to the userland process.
- */
- error = vm_pgmoveco(&curproc->p_vmspace->vm_map,
- (vm_offset_t)cp, (vm_offset_t)iov->iov_base);
-
- /*
- * If we get an error back, attempt
- * to use copyout() instead. The
- * disposable page should be freed
- * automatically if we weren't able to move
- * it into userland.
- */
- if (error != 0)
- error = copyout(cp, iov->iov_base, cnt);
- } else {
- error = copyout(cp, iov->iov_base, cnt);
- }
- } else {
- error = copyin(iov->iov_base, cp, cnt);
- }
- return (error);
-}
-
-int
-uiomoveco(void *cp, int n, struct uio *uio, int disposable)
-{
- struct iovec *iov;
- u_int cnt;
- int error;
-
- KASSERT(uio->uio_rw == UIO_READ || uio->uio_rw == UIO_WRITE,
- ("uiomoveco: mode"));
- KASSERT(uio->uio_segflg != UIO_USERSPACE || uio->uio_td == curthread,
- ("uiomoveco proc"));
-
- while (n > 0 && uio->uio_resid) {
- iov = uio->uio_iov;
- cnt = iov->iov_len;
- if (cnt == 0) {
- uio->uio_iov++;
- uio->uio_iovcnt--;
- continue;
- }
- if (cnt > n)
- cnt = n;
-
- switch (uio->uio_segflg) {
-
- case UIO_USERSPACE:
- maybe_yield();
- error = userspaceco(cp, cnt, uio, disposable);
- if (error)
- return (error);
- break;
-
- case UIO_SYSSPACE:
- if (uio->uio_rw == UIO_READ)
- bcopy(cp, iov->iov_base, cnt);
- else
- bcopy(iov->iov_base, cp, cnt);
- break;
- case UIO_NOCOPY:
- break;
- }
- iov->iov_base = (char *)iov->iov_base + cnt;
- iov->iov_len -= cnt;
- uio->uio_resid -= cnt;
- uio->uio_offset += cnt;
- cp = (char *)cp + cnt;
- n -= cnt;
- }
- return (0);
-}
-#endif /* ZERO_COPY_SOCKETS */
-
-/*
* Give next character to user as result of read.
*/
int
@@ -389,7 +330,6 @@
case UIO_SYSSPACE:
iov_base = iov->iov_base;
*iov_base = c;
- iov->iov_base = iov_base;
break;
case UIO_NOCOPY:
@@ -441,7 +381,7 @@
}
int
-copyiniov(struct iovec *iovp, u_int iovcnt, struct iovec **iov, int error)
+copyiniov(const struct iovec *iovp, u_int iovcnt, struct iovec **iov, int error)
{
u_int iovlen;
@@ -459,7 +399,7 @@
}
int
-copyinuio(struct iovec *iovp, u_int iovcnt, struct uio **uiop)
+copyinuio(const struct iovec *iovp, u_int iovcnt, struct uio **uiop)
{
struct iovec *iov;
struct uio *uio;
@@ -529,7 +469,7 @@
lim_max(td->td_proc, RLIMIT_DATA));
PROC_UNLOCK(td->td_proc);
- /* round size up to page boundry */
+ /* round size up to page boundary */
size = (vm_size_t)round_page(sz);
error = vm_mmap(&vms->vm_map, addr, size, PROT_READ | PROT_WRITE,
@@ -558,3 +498,128 @@
return (0);
}
+
+#ifdef NO_FUEWORD
+/*
+ * XXXKIB The temporal implementation of fue*() functions which do not
+ * handle usermode -1 properly, mixing it with the fault code. Keep
+ * this until MD code is written. Currently sparc64, mips and arm do
+ * not have proper implementation.
+ */
+
+int
+fueword(volatile const void *base, long *val)
+{
+ long res;
+
+ res = fuword(base);
+ if (res == -1)
+ return (-1);
+ *val = res;
+ return (0);
+}
+
+int
+fueword32(volatile const void *base, int32_t *val)
+{
+ int32_t res;
+
+ res = fuword32(base);
+ if (res == -1)
+ return (-1);
+ *val = res;
+ return (0);
+}
+
+#ifdef _LP64
+int
+fueword64(volatile const void *base, int64_t *val)
+{
+ int64_t res;
+
+ res = fuword64(base);
+ if (res == -1)
+ return (-1);
+ *val = res;
+ return (0);
+}
+#endif
+
+int
+casueword32(volatile uint32_t *base, uint32_t oldval, uint32_t *oldvalp,
+ uint32_t newval)
+{
+ int32_t ov;
+
+ ov = casuword32(base, oldval, newval);
+ if (ov == -1)
+ return (-1);
+ *oldvalp = ov;
+ return (0);
+}
+
+int
+casueword(volatile u_long *p, u_long oldval, u_long *oldvalp, u_long newval)
+{
+ u_long ov;
+
+ ov = casuword(p, oldval, newval);
+ if (ov == -1)
+ return (-1);
+ *oldvalp = ov;
+ return (0);
+}
+#else /* NO_FUEWORD */
+int32_t
+fuword32(volatile const void *addr)
+{
+ int rv;
+ int32_t val;
+
+ rv = fueword32(addr, &val);
+ return (rv == -1 ? -1 : val);
+}
+
+#ifdef _LP64
+int64_t
+fuword64(volatile const void *addr)
+{
+ int rv;
+ int64_t val;
+
+ rv = fueword64(addr, &val);
+ return (rv == -1 ? -1 : val);
+}
+#endif /* _LP64 */
+
+long
+fuword(volatile const void *addr)
+{
+ long val;
+ int rv;
+
+ rv = fueword(addr, &val);
+ return (rv == -1 ? -1 : val);
+}
+
+uint32_t
+casuword32(volatile uint32_t *addr, uint32_t old, uint32_t new)
+{
+ int rv;
+ uint32_t val;
+
+ rv = casueword32(addr, old, &val, new);
+ return (rv == -1 ? -1 : val);
+}
+
+u_long
+casuword(volatile u_long *addr, u_long old, u_long new)
+{
+ int rv;
+ u_long val;
+
+ rv = casueword(addr, old, &val, new);
+ return (rv == -1 ? -1 : val);
+}
+
+#endif /* NO_FUEWORD */
Modified: trunk/sys/kern/subr_unit.c
===================================================================
--- trunk/sys/kern/subr_unit.c 2018-05-26 14:26:33 UTC (rev 9955)
+++ trunk/sys/kern/subr_unit.c 2018-05-26 14:27:13 UTC (rev 9956)
@@ -1,3 +1,4 @@
+/* $MidnightBSD$ */
/*-
* Copyright (c) 2004 Poul-Henning Kamp
* All rights reserved.
@@ -23,7 +24,7 @@
* OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
* SUCH DAMAGE.
*
- * $MidnightBSD$
+ * $FreeBSD: stable/10/sys/kern/subr_unit.c 312325 2017-01-17 01:58:50Z ngie $
*
*
* Unit number allocation functions.
@@ -68,8 +69,8 @@
*/
#include <sys/types.h>
-#include <sys/queue.h>
#include <sys/bitstring.h>
+#include <sys/_unrhdr.h>
#ifdef _KERNEL
@@ -187,28 +188,12 @@
/* Number of bits in the bitmap */
#define NBITS ((int)sizeof(((struct unrb *)NULL)->map) * 8)
-/* Header element for a unr number space. */
-
-struct unrhdr {
- TAILQ_HEAD(unrhd,unr) head;
- u_int low; /* Lowest item */
- u_int high; /* Highest item */
- u_int busy; /* Count of allocated items */
- u_int alloc; /* Count of memory allocations */
- u_int first; /* items in allocated from start */
- u_int last; /* items free at end */
- struct mtx *mtx;
- TAILQ_HEAD(unrfr,unr) ppfree; /* Items to be freed after mtx
- lock dropped */
-};
-
-
#if defined(DIAGNOSTIC) || !defined(_KERNEL)
/*
* Consistency check function.
*
* Checks the internal consistency as well as we can.
- *
+ *
* Called at all boundaries of this API.
*/
static void
@@ -236,7 +221,7 @@
("UNR inconsistency: busy %u found %u (line %d)\n",
ub->busy, w, line));
y += w;
- } else if (up->ptr != NULL)
+ } else if (up->ptr != NULL)
y += up->len;
}
KASSERT (y == uh->busy,
@@ -315,20 +300,12 @@
mtx_unlock(uh->mtx);
}
-/*
- * Allocate a new unrheader set.
- *
- * Highest and lowest valid values given as parameters.
- */
-
-struct unrhdr *
-new_unrhdr(int low, int high, struct mtx *mutex)
+void
+init_unrhdr(struct unrhdr *uh, int low, int high, struct mtx *mutex)
{
- struct unrhdr *uh;
KASSERT(low >= 0 && low <= high,
("UNR: use error: new_unrhdr(%d, %d)", low, high));
- uh = Malloc(sizeof *uh);
if (mutex != NULL)
uh->mtx = mutex;
else
@@ -340,6 +317,21 @@
uh->first = 0;
uh->last = 1 + (high - low);
check_unrhdr(uh, __LINE__);
+}
+
+/*
+ * Allocate a new unrheader set.
+ *
+ * Highest and lowest valid values given as parameters.
+ */
+
+struct unrhdr *
+new_unrhdr(int low, int high, struct mtx *mutex)
+{
+ struct unrhdr *uh;
+
+ uh = Malloc(sizeof *uh);
+ init_unrhdr(uh, low, high, mutex);
return (uh);
}
@@ -364,7 +356,7 @@
/*
* Look for sequence of items which can be combined into a bitmap, if
* multiple are present, take the one which saves most memory.
- *
+ *
* Return (1) if a sequence was found to indicate that another call
* might be able to do more. Return (0) if we found no suitable sequence.
*
@@ -591,7 +583,7 @@
}
/*
- * We can always allocate from the first list element, so if we have
+ * We can always allocate from the first list element, so if we have
* nothing on the list, we must have run out of unit numbers.
*/
if (up == NULL)
@@ -806,7 +798,7 @@
/* Handle bitmap items */
if (is_bitmap(uh, up)) {
ub = up->ptr;
-
+
KASSERT(bit_test(ub->map, item) != 0,
("UNR: Freeing free item %d (bitmap)\n", item));
bit_clear(ub->map, item);
@@ -909,7 +901,7 @@
for (x = 0; x < up->len; x++) {
if (bit_test(ub->map, x))
printf("#");
- else
+ else
printf(" ");
}
printf("]\n");
Modified: trunk/sys/kern/subr_witness.c
===================================================================
--- trunk/sys/kern/subr_witness.c 2018-05-26 14:26:33 UTC (rev 9955)
+++ trunk/sys/kern/subr_witness.c 2018-05-26 14:27:13 UTC (rev 9956)
@@ -1,3 +1,4 @@
+/* $MidnightBSD$ */
/*-
* Copyright (c) 2008 Isilon Systems, Inc.
* Copyright (c) 2008 Ilya Maykov <ivmaykov at gmail.com>
@@ -28,8 +29,8 @@
* OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
* SUCH DAMAGE.
*
- * from BSDI $Id: subr_witness.c,v 1.9 2012-10-09 04:08:16 laffer1 Exp $
- * and BSDI $Id: subr_witness.c,v 1.9 2012-10-09 04:08:16 laffer1 Exp $
+ * from BSDI $Id: mutex_witness.c,v 1.1.2.20 2000/04/27 03:10:27 cp Exp $
+ * and BSDI $Id: synch_machdep.c,v 2.3.2.39 2000/04/27 03:10:25 cp Exp $
*/
/*
@@ -85,7 +86,7 @@
*/
#include <sys/cdefs.h>
-__FBSDID("$MidnightBSD$");
+__FBSDID("$FreeBSD: stable/10/sys/kern/subr_witness.c 309871 2016-12-12 02:24:46Z markj $");
#include "opt_ddb.h"
#include "opt_hwpmc_hooks.h"
@@ -135,7 +136,7 @@
#define WITNESS_COUNT 1024
#define WITNESS_CHILDCOUNT (WITNESS_COUNT * 4)
#define WITNESS_HASH_SIZE 251 /* Prime, gives load factor < 2 */
-#define WITNESS_PENDLIST 768
+#define WITNESS_PENDLIST (1024 + MAXCPU)
/* Allocate 256 KB of stack data space */
#define WITNESS_LO_DATA_COUNT 2048
@@ -305,13 +306,6 @@
}
static __inline int
-witness_lock_order_key_empty(const struct witness_lock_order_key *key)
-{
-
- return (key->from == 0 && key->to == 0);
-}
-
-static __inline int
witness_lock_order_key_equal(const struct witness_lock_order_key *a,
const struct witness_lock_order_key *b)
{
@@ -332,7 +326,7 @@
static struct witness *enroll(const char *description,
struct lock_class *lock_class);
static struct lock_instance *find_instance(struct lock_list_entry *list,
- struct lock_object *lock);
+ const struct lock_object *lock);
static int isitmychild(struct witness *parent, struct witness *child);
static int isitmydescendant(struct witness *parent, struct witness *child);
static void itismychild(struct witness *parent, struct witness *child);
@@ -498,6 +492,11 @@
{ "time lock", &lock_class_mtx_sleep },
{ NULL, NULL },
/*
+ * umtx
+ */
+ { "umtx lock", &lock_class_mtx_sleep },
+ { NULL, NULL },
+ /*
* Sockets
*/
{ "accept", &lock_class_mtx_sleep },
@@ -520,7 +519,7 @@
{ "udpinp", &lock_class_rw },
{ "in_multi_mtx", &lock_class_mtx_sleep },
{ "igmp_mtx", &lock_class_mtx_sleep },
- { "if_addr_mtx", &lock_class_mtx_sleep },
+ { "if_addr_lock", &lock_class_rw },
{ NULL, NULL },
/*
* IPv6 multicast:
@@ -529,12 +528,12 @@
{ "udpinp", &lock_class_rw },
{ "in6_multi_mtx", &lock_class_mtx_sleep },
{ "mld_mtx", &lock_class_mtx_sleep },
- { "if_addr_mtx", &lock_class_mtx_sleep },
+ { "if_addr_lock", &lock_class_rw },
{ NULL, NULL },
/*
* UNIX Domain Sockets
*/
- { "unp_global_rwlock", &lock_class_rw },
+ { "unp_link_rwlock", &lock_class_rw },
{ "unp_list_lock", &lock_class_mtx_sleep },
{ "unp", &lock_class_mtx_sleep },
{ "so_snd", &lock_class_mtx_sleep },
@@ -594,7 +593,7 @@
* CDEV
*/
{ "vm map (system)", &lock_class_mtx_sleep },
- { "vm page queue", &lock_class_mtx_sleep },
+ { "vm pagequeue", &lock_class_mtx_sleep },
{ "vnode interlock", &lock_class_mtx_sleep },
{ "cdev", &lock_class_mtx_sleep },
{ NULL, NULL },
@@ -602,9 +601,9 @@
* VM
*/
{ "vm map (user)", &lock_class_sx },
- { "vm object", &lock_class_mtx_sleep },
+ { "vm object", &lock_class_rw },
{ "vm page", &lock_class_mtx_sleep },
- { "vm page queue", &lock_class_mtx_sleep },
+ { "vm pagequeue", &lock_class_mtx_sleep },
{ "pmap pv global", &lock_class_rw },
{ "pmap", &lock_class_mtx_sleep },
{ "pmap pv list", &lock_class_rw },
@@ -649,7 +648,6 @@
#endif
{ "process slock", &lock_class_mtx_spin },
{ "sleepq chain", &lock_class_mtx_spin },
- { "umtx lock", &lock_class_mtx_spin },
{ "rm_spinlock", &lock_class_mtx_spin },
{ "turnstile chain", &lock_class_mtx_spin },
{ "turnstile lock", &lock_class_mtx_spin },
@@ -669,6 +667,9 @@
*/
{ "intrcnt", &lock_class_mtx_spin },
{ "icu", &lock_class_mtx_spin },
+#if defined(SMP) && defined(__sparc64__)
+ { "ipi", &lock_class_mtx_spin },
+#endif
#ifdef __i386__
{ "allpmaps", &lock_class_mtx_spin },
{ "descriptor tables", &lock_class_mtx_spin },
@@ -822,16 +823,16 @@
class = LOCK_CLASS(lock);
if ((lock->lo_flags & LO_RECURSABLE) != 0 &&
(class->lc_flags & LC_RECURSABLE) == 0)
- panic("%s: lock (%s) %s can not be recursable", __func__,
- class->lc_name, lock->lo_name);
+ kassert_panic("%s: lock (%s) %s can not be recursable",
+ __func__, class->lc_name, lock->lo_name);
if ((lock->lo_flags & LO_SLEEPABLE) != 0 &&
(class->lc_flags & LC_SLEEPABLE) == 0)
- panic("%s: lock (%s) %s can not be sleepable", __func__,
- class->lc_name, lock->lo_name);
+ kassert_panic("%s: lock (%s) %s can not be sleepable",
+ __func__, class->lc_name, lock->lo_name);
if ((lock->lo_flags & LO_UPGRADABLE) != 0 &&
(class->lc_flags & LC_UPGRADABLE) == 0)
- panic("%s: lock (%s) %s can not be upgradable", __func__,
- class->lc_name, lock->lo_name);
+ kassert_panic("%s: lock (%s) %s can not be upgradable",
+ __func__, class->lc_name, lock->lo_name);
/*
* If we shouldn't watch this lock, then just clear lo_witness.
@@ -847,7 +848,8 @@
pending_locks[pending_cnt].wh_lock = lock;
pending_locks[pending_cnt++].wh_type = type;
if (pending_cnt > WITNESS_PENDLIST)
- panic("%s: pending locks list is too small, bump it\n",
+ panic("%s: pending locks list is too small, "
+ "increase WITNESS_PENDLIST\n",
__func__);
} else
lock->lo_witness = enroll(type, class);
@@ -1052,7 +1054,7 @@
{
struct lock_list_entry *lock_list, *lle;
struct lock_instance *lock1, *lock2, *plock;
- struct lock_class *class;
+ struct lock_class *class, *iclass;
struct witness *w, *w1;
struct thread *td;
int i, j;
@@ -1073,7 +1075,8 @@
* all spin locks.
*/
if (td->td_critnest != 0 && !kdb_active)
- panic("blockable sleep lock (%s) %s @ %s:%d",
+ kassert_panic("acquiring blockable sleep lock with "
+ "spinlock or critical section held (%s) %s @ %s:%d",
class->lc_name, lock->lo_name,
fixup_filename(file), line);
@@ -1117,7 +1120,7 @@
fixup_filename(file), line);
printf("while exclusively locked from %s:%d\n",
fixup_filename(lock1->li_file), lock1->li_line);
- panic("share->excl");
+ kassert_panic("excl->share");
}
if ((lock1->li_flags & LI_EXCLUSIVE) == 0 &&
(flags & LOP_EXCLUSIVE) != 0) {
@@ -1126,11 +1129,25 @@
fixup_filename(file), line);
printf("while share locked from %s:%d\n",
fixup_filename(lock1->li_file), lock1->li_line);
- panic("excl->share");
+ kassert_panic("share->excl");
}
return;
}
+ /* Warn if the interlock is not locked exactly once. */
+ if (interlock != NULL) {
+ iclass = LOCK_CLASS(interlock);
+ lock1 = find_instance(lock_list, interlock);
+ if (lock1 == NULL)
+ kassert_panic("interlock (%s) %s not locked @ %s:%d",
+ iclass->lc_name, interlock->lo_name,
+ fixup_filename(file), line);
+ else if ((lock1->li_flags & LI_RECURSEMASK) != 0)
+ kassert_panic("interlock (%s) %s recursed @ %s:%d",
+ iclass->lc_name, interlock->lo_name,
+ fixup_filename(file), line);
+ }
+
/*
* Find the previously acquired lock, but ignore interlocks.
*/
@@ -1154,19 +1171,25 @@
/*
* Try to perform most checks without a lock. If this succeeds we
- * can skip acquiring the lock and return success.
+ * can skip acquiring the lock and return success. Otherwise we redo
+ * the check with the lock held to handle races with concurrent updates.
*/
w1 = plock->li_lock->lo_witness;
if (witness_lock_order_check(w1, w))
return;
+ mtx_lock_spin(&w_mtx);
+ if (witness_lock_order_check(w1, w)) {
+ mtx_unlock_spin(&w_mtx);
+ return;
+ }
+ witness_lock_order_add(w1, w);
+
/*
* Check for duplicate locks of the same type. Note that we only
* have to check for this on the last lock we just acquired. Any
* other cases will be caught as lock order violations.
*/
- mtx_lock_spin(&w_mtx);
- witness_lock_order_add(w1, w);
if (w1 == w) {
i = w->w_index;
if (!(lock->lo_flags & LO_DUPOK) && !(flags & LOP_DUPOK) &&
@@ -1199,16 +1222,14 @@
for (j = 0, lle = lock_list; lle != NULL; lle = lle->ll_next) {
for (i = lle->ll_count - 1; i >= 0; i--, j++) {
- MPASS(j < WITNESS_COUNT);
+ MPASS(j < LOCK_CHILDCOUNT * LOCK_NCHILDREN);
lock1 = &lle->ll_children[i];
/*
- * Ignore the interlock the first time we see it.
+ * Ignore the interlock.
*/
- if (interlock != NULL && interlock == lock1->li_lock) {
- interlock = NULL;
+ if (interlock == lock1->li_lock)
continue;
- }
/*
* If this lock doesn't undergo witness checking,
@@ -1287,8 +1308,20 @@
w->w_reversed = w1->w_reversed = 1;
witness_increment_graph_generation();
mtx_unlock_spin(&w_mtx);
-
+
+#ifdef WITNESS_NO_VNODE
/*
+ * There are known LORs between VNODE locks. They are
+ * not an indication of a bug. VNODE locks are flagged
+ * as such (LO_IS_VNODE) and we don't yell if the LOR
+ * is between 2 VNODE locks.
+ */
+ if ((lock->lo_flags & LO_IS_VNODE) != 0 &&
+ (lock1->li_lock->lo_flags & LO_IS_VNODE) != 0)
+ return;
+#endif
+
+ /*
* Ok, yell about it.
*/
if (((lock->lo_flags & LO_SLEEPABLE) != 0 &&
@@ -1433,26 +1466,32 @@
class = LOCK_CLASS(lock);
if (witness_watch) {
if ((lock->lo_flags & LO_UPGRADABLE) == 0)
- panic("upgrade of non-upgradable lock (%s) %s @ %s:%d",
+ kassert_panic(
+ "upgrade of non-upgradable lock (%s) %s @ %s:%d",
class->lc_name, lock->lo_name,
fixup_filename(file), line);
if ((class->lc_flags & LC_SLEEPLOCK) == 0)
- panic("upgrade of non-sleep lock (%s) %s @ %s:%d",
+ kassert_panic(
+ "upgrade of non-sleep lock (%s) %s @ %s:%d",
class->lc_name, lock->lo_name,
fixup_filename(file), line);
}
instance = find_instance(curthread->td_sleeplocks, lock);
- if (instance == NULL)
- panic("upgrade of unlocked lock (%s) %s @ %s:%d",
+ if (instance == NULL) {
+ kassert_panic("upgrade of unlocked lock (%s) %s @ %s:%d",
class->lc_name, lock->lo_name,
fixup_filename(file), line);
+ return;
+ }
if (witness_watch) {
if ((instance->li_flags & LI_EXCLUSIVE) != 0)
- panic("upgrade of exclusive lock (%s) %s @ %s:%d",
+ kassert_panic(
+ "upgrade of exclusive lock (%s) %s @ %s:%d",
class->lc_name, lock->lo_name,
fixup_filename(file), line);
if ((instance->li_flags & LI_RECURSEMASK) != 0)
- panic("upgrade of recursed lock (%s) %s r=%d @ %s:%d",
+ kassert_panic(
+ "upgrade of recursed lock (%s) %s r=%d @ %s:%d",
class->lc_name, lock->lo_name,
instance->li_flags & LI_RECURSEMASK,
fixup_filename(file), line);
@@ -1473,26 +1512,32 @@
class = LOCK_CLASS(lock);
if (witness_watch) {
if ((lock->lo_flags & LO_UPGRADABLE) == 0)
- panic("downgrade of non-upgradable lock (%s) %s @ %s:%d",
+ kassert_panic(
+ "downgrade of non-upgradable lock (%s) %s @ %s:%d",
class->lc_name, lock->lo_name,
fixup_filename(file), line);
if ((class->lc_flags & LC_SLEEPLOCK) == 0)
- panic("downgrade of non-sleep lock (%s) %s @ %s:%d",
+ kassert_panic(
+ "downgrade of non-sleep lock (%s) %s @ %s:%d",
class->lc_name, lock->lo_name,
fixup_filename(file), line);
}
instance = find_instance(curthread->td_sleeplocks, lock);
- if (instance == NULL)
- panic("downgrade of unlocked lock (%s) %s @ %s:%d",
+ if (instance == NULL) {
+ kassert_panic("downgrade of unlocked lock (%s) %s @ %s:%d",
class->lc_name, lock->lo_name,
fixup_filename(file), line);
+ return;
+ }
if (witness_watch) {
if ((instance->li_flags & LI_EXCLUSIVE) == 0)
- panic("downgrade of shared lock (%s) %s @ %s:%d",
+ kassert_panic(
+ "downgrade of shared lock (%s) %s @ %s:%d",
class->lc_name, lock->lo_name,
fixup_filename(file), line);
if ((instance->li_flags & LI_RECURSEMASK) != 0)
- panic("downgrade of recursed lock (%s) %s r=%d @ %s:%d",
+ kassert_panic(
+ "downgrade of recursed lock (%s) %s r=%d @ %s:%d",
class->lc_name, lock->lo_name,
instance->li_flags & LI_RECURSEMASK,
fixup_filename(file), line);
@@ -1534,11 +1579,13 @@
* We have to make sure we flush these queues, so just search for
* eventual register locks and remove them.
*/
- if (witness_watch > 0)
- panic("lock (%s) %s not locked @ %s:%d", class->lc_name,
+ if (witness_watch > 0) {
+ kassert_panic("lock (%s) %s not locked @ %s:%d", class->lc_name,
lock->lo_name, fixup_filename(file), line);
- else
return;
+ } else {
+ return;
+ }
found:
/* First, check for shared/exclusive mismatches. */
@@ -1548,7 +1595,7 @@
lock->lo_name, fixup_filename(file), line);
printf("while exclusively locked from %s:%d\n",
fixup_filename(instance->li_file), instance->li_line);
- panic("excl->ushare");
+ kassert_panic("excl->ushare");
}
if ((instance->li_flags & LI_EXCLUSIVE) == 0 && witness_watch > 0 &&
(flags & LOP_EXCLUSIVE) != 0) {
@@ -1557,7 +1604,7 @@
printf("while share locked from %s:%d\n",
fixup_filename(instance->li_file),
instance->li_line);
- panic("share->uexcl");
+ kassert_panic("share->uexcl");
}
/* If we are recursed, unrecurse. */
if ((instance->li_flags & LI_RECURSEMASK) > 0) {
@@ -1571,7 +1618,7 @@
if ((instance->li_flags & LI_NORELEASE) != 0 && witness_watch > 0) {
printf("forbidden unlock of (%s) %s @ %s:%d\n", class->lc_name,
lock->lo_name, fixup_filename(file), line);
- panic("lock marked norelease");
+ kassert_panic("lock marked norelease");
}
/* Otherwise, remove this item from the list. */
@@ -1626,7 +1673,8 @@
witness_list_lock(&lle->ll_children[i], printf);
}
- panic("Thread %p cannot exit while holding sleeplocks\n", td);
+ kassert_panic(
+ "Thread %p cannot exit while holding sleeplocks\n", td);
}
witness_lock_list_free(lle);
}
@@ -1707,7 +1755,7 @@
} else
sched_unpin();
if (flags & WARN_PANIC && n)
- panic("%s", __func__);
+ kassert_panic("%s", __func__);
else
witness_debugger(n);
return (n);
@@ -1750,11 +1798,13 @@
return (NULL);
else
typelist = &w_spin;
- } else if ((lock_class->lc_flags & LC_SLEEPLOCK))
+ } else if ((lock_class->lc_flags & LC_SLEEPLOCK)) {
typelist = &w_sleep;
- else
- panic("lock class %s is not sleep or spin",
+ } else {
+ kassert_panic("lock class %s is not sleep or spin",
lock_class->lc_name);
+ return (NULL);
+ }
mtx_lock_spin(&w_mtx);
w = witness_hash_get(description);
@@ -1784,7 +1834,7 @@
w->w_refcount++;
mtx_unlock_spin(&w_mtx);
if (lock_class != w->w_class)
- panic(
+ kassert_panic(
"lock (%s) %s does not match earlier (%s) lock",
description, lock_class->lc_name,
w->w_class->lc_name);
@@ -1910,6 +1960,7 @@
static void
itismychild(struct witness *parent, struct witness *child)
{
+ int unlocked;
MPASS(child != NULL && parent != NULL);
if (witness_cold == 0)
@@ -1916,12 +1967,19 @@
mtx_assert(&w_mtx, MA_OWNED);
if (!witness_lock_type_equal(parent, child)) {
- if (witness_cold == 0)
+ if (witness_cold == 0) {
+ unlocked = 1;
mtx_unlock_spin(&w_mtx);
- panic("%s: parent \"%s\" (%s) and child \"%s\" (%s) are not "
+ } else {
+ unlocked = 0;
+ }
+ kassert_panic(
+ "%s: parent \"%s\" (%s) and child \"%s\" (%s) are not "
"the same lock type", __func__, parent->w_name,
parent->w_class->lc_name, child->w_name,
child->w_class->lc_name);
+ if (unlocked)
+ mtx_lock_spin(&w_mtx);
}
adopt(parent, child);
}
@@ -1945,7 +2003,10 @@
/* The flags on one better be the inverse of the flags on the other */
if (!((WITNESS_ATOD(r1) == r2 && WITNESS_DTOA(r2) == r1) ||
- (WITNESS_DTOA(r1) == r2 && WITNESS_ATOD(r2) == r1))) {
+ (WITNESS_DTOA(r1) == r2 && WITNESS_ATOD(r2) == r1))) {
+ /* Don't squawk if we're potentially racing with an update. */
+ if (!mtx_owned(&w_mtx))
+ return (0);
printf("%s: rmatrix mismatch between %s (index %d) and %s "
"(index %d): w_rmatrix[%d][%d] == %hhx but "
"w_rmatrix[%d][%d] == %hhx\n",
@@ -2073,7 +2134,7 @@
}
static struct lock_instance *
-find_instance(struct lock_list_entry *list, struct lock_object *lock)
+find_instance(struct lock_list_entry *list, const struct lock_object *lock)
{
struct lock_list_entry *lle;
struct lock_instance *instance;
@@ -2191,9 +2252,11 @@
lock_list = PCPU_GET(spinlocks);
}
instance = find_instance(lock_list, lock);
- if (instance == NULL)
- panic("%s: lock (%s) %s not locked", __func__,
+ if (instance == NULL) {
+ kassert_panic("%s: lock (%s) %s not locked", __func__,
class->lc_name, lock->lo_name);
+ return;
+ }
*filep = instance->li_file;
*linep = instance->li_line;
}
@@ -2225,16 +2288,19 @@
}
instance = find_instance(lock_list, lock);
if (instance == NULL)
- panic("%s: lock (%s) %s not locked", __func__,
+ kassert_panic("%s: lock (%s) %s not locked", __func__,
class->lc_name, lock->lo_name);
lock->lo_witness->w_file = file;
lock->lo_witness->w_line = line;
+ if (instance == NULL)
+ return;
instance->li_file = file;
instance->li_line = line;
}
void
-witness_assert(struct lock_object *lock, int flags, const char *file, int line)
+witness_assert(const struct lock_object *lock, int flags, const char *file,
+ int line)
{
#ifdef INVARIANT_SUPPORT
struct lock_instance *instance;
@@ -2248,13 +2314,14 @@
else if ((class->lc_flags & LC_SPINLOCK) != 0)
instance = find_instance(PCPU_GET(spinlocks), lock);
else {
- panic("Lock (%s) %s is not sleep or spin!",
+ kassert_panic("Lock (%s) %s is not sleep or spin!",
class->lc_name, lock->lo_name);
+ return;
}
switch (flags) {
case LA_UNLOCKED:
if (instance != NULL)
- panic("Lock (%s) %s locked @ %s:%d.",
+ kassert_panic("Lock (%s) %s locked @ %s:%d.",
class->lc_name, lock->lo_name,
fixup_filename(file), line);
break;
@@ -2268,7 +2335,7 @@
case LA_XLOCKED | LA_RECURSED:
case LA_XLOCKED | LA_NOTRECURSED:
if (instance == NULL) {
- panic("Lock (%s) %s not locked @ %s:%d.",
+ kassert_panic("Lock (%s) %s not locked @ %s:%d.",
class->lc_name, lock->lo_name,
fixup_filename(file), line);
break;
@@ -2275,27 +2342,29 @@
}
if ((flags & LA_XLOCKED) != 0 &&
(instance->li_flags & LI_EXCLUSIVE) == 0)
- panic("Lock (%s) %s not exclusively locked @ %s:%d.",
+ kassert_panic(
+ "Lock (%s) %s not exclusively locked @ %s:%d.",
class->lc_name, lock->lo_name,
fixup_filename(file), line);
if ((flags & LA_SLOCKED) != 0 &&
(instance->li_flags & LI_EXCLUSIVE) != 0)
- panic("Lock (%s) %s exclusively locked @ %s:%d.",
+ kassert_panic(
+ "Lock (%s) %s exclusively locked @ %s:%d.",
class->lc_name, lock->lo_name,
fixup_filename(file), line);
if ((flags & LA_RECURSED) != 0 &&
(instance->li_flags & LI_RECURSEMASK) == 0)
- panic("Lock (%s) %s not recursed @ %s:%d.",
+ kassert_panic("Lock (%s) %s not recursed @ %s:%d.",
class->lc_name, lock->lo_name,
fixup_filename(file), line);
if ((flags & LA_NOTRECURSED) != 0 &&
(instance->li_flags & LI_RECURSEMASK) != 0)
- panic("Lock (%s) %s recursed @ %s:%d.",
+ kassert_panic("Lock (%s) %s recursed @ %s:%d.",
class->lc_name, lock->lo_name,
fixup_filename(file), line);
break;
default:
- panic("Invalid lock assertion at %s:%d.",
+ kassert_panic("Invalid lock assertion at %s:%d.",
fixup_filename(file), line);
}
@@ -2320,9 +2389,11 @@
lock_list = PCPU_GET(spinlocks);
}
instance = find_instance(lock_list, lock);
- if (instance == NULL)
- panic("%s: lock (%s) %s not locked", __func__,
+ if (instance == NULL) {
+ kassert_panic("%s: lock (%s) %s not locked", __func__,
class->lc_name, lock->lo_name);
+ return;
+ }
if (set)
instance->li_flags |= flag;
@@ -2828,7 +2899,7 @@
return (1);
}
-/* Call this whenver the structure of the witness graph changes. */
+/* Call this whenever the structure of the witness graph changes. */
static void
witness_increment_graph_generation(void)
{
More information about the Midnightbsd-cvs
mailing list