Merge ^/head r293430 through r293685.

This commit is contained in:
Dimitry Andric 2016-01-11 19:36:44 +00:00
commit 89d3f0ea4e
Notes: svn2git 2020-12-20 02:59:44 +00:00
svn path=/projects/clang380-import/; revision=293687
193 changed files with 2461 additions and 2054 deletions

View File

@ -570,9 +570,8 @@ _worldtmp: .PHONY
.else .else
rm -rf ${WORLDTMP}/legacy/usr/include rm -rf ${WORLDTMP}/legacy/usr/include
# XXX - These three can depend on any header file. # XXX - These three can depend on any header file.
rm -f ${OBJTREE}${.CURDIR}/usr.bin/kdump/ioctl.c rm -f ${OBJTREE}${.CURDIR}/lib/libsysdecode/ioctl.c
rm -f ${OBJTREE}${.CURDIR}/usr.bin/kdump/kdump_subr.c rm -f ${OBJTREE}${.CURDIR}/usr.bin/kdump/kdump_subr.c
rm -f ${OBJTREE}${.CURDIR}/usr.bin/truss/ioctl.c
.endif .endif
.for _dir in \ .for _dir in \
lib usr legacy/bin legacy/usr lib usr legacy/bin legacy/usr
@ -1425,11 +1424,13 @@ _vtfontcvt= usr.bin/vtfontcvt
_sed= usr.bin/sed _sed= usr.bin/sed
.endif .endif
.if ${BOOTSTRAPPING} < 1000002 .if ${BOOTSTRAPPING} < 1000033
_libopenbsd= lib/libopenbsd _libopenbsd= lib/libopenbsd
_m4= usr.bin/m4 _m4= usr.bin/m4
_lex= usr.bin/lex
${_bt}-usr.bin/m4: ${_bt}-lib/libopenbsd ${_bt}-usr.bin/m4: ${_bt}-lib/libopenbsd
${_bt}-usr.bin/lex: ${_bt}-usr.bin/m4
.endif .endif
.if ${BOOTSTRAPPING} < 1000026 .if ${BOOTSTRAPPING} < 1000026
@ -1443,12 +1444,6 @@ ${_bt}-usr.sbin/nmtree: ${_bt}-lib/libnetbsd
_cat= bin/cat _cat= bin/cat
.endif .endif
.if ${BOOTSTRAPPING} < 1000033
_lex= usr.bin/lex
${_bt}-usr.bin/lex: ${_bt}-usr.bin/m4
.endif
# r277259 crunchide: Correct 64-bit section header offset # r277259 crunchide: Correct 64-bit section header offset
# r281674 crunchide: always include both 32- and 64-bit ELF support # r281674 crunchide: always include both 32- and 64-bit ELF support
# r285986 crunchen: use STRIPBIN rather than STRIP # r285986 crunchen: use STRIPBIN rather than STRIP

View File

@ -1039,12 +1039,12 @@ evalcommand(union node *cmd, int flags, struct backcmd *backcmd)
reffunc(cmdentry.u.func); reffunc(cmdentry.u.func);
savehandler = handler; savehandler = handler;
if (setjmp(jmploc.loc)) { if (setjmp(jmploc.loc)) {
freeparam(&shellparam);
shellparam = saveparam;
popredir(); popredir();
unreffunc(cmdentry.u.func); unreffunc(cmdentry.u.func);
poplocalvars(); poplocalvars();
localvars = savelocalvars; localvars = savelocalvars;
freeparam(&shellparam);
shellparam = saveparam;
funcnest--; funcnest--;
handler = savehandler; handler = savehandler;
longjmp(handler->loc, 1); longjmp(handler->loc, 1);

View File

@ -111,6 +111,7 @@ FILES+= local1.0
FILES+= local2.0 FILES+= local2.0
FILES+= local3.0 FILES+= local3.0
FILES+= local4.0 FILES+= local4.0
FILES+= local5.0
.if ${MK_NLS} != "no" .if ${MK_NLS} != "no"
FILES+= locale1.0 FILES+= locale1.0
.endif .endif

View File

@ -0,0 +1,15 @@
# $FreeBSD$
f() {
local PATH IFS elem
IFS=:
for elem in ''$PATH''; do
PATH=/var/empty/$elem:$PATH
done
ls -d / >/dev/null
}
p1=$(command -v ls)
f
p2=$(command -v ls)
[ "$p1" = "$p2" ]

View File

@ -791,6 +791,7 @@ poplocalvars(void)
{ {
struct localvar *lvp; struct localvar *lvp;
struct var *vp; struct var *vp;
int islocalevar;
INTOFF; INTOFF;
while ((lvp = localvars) != NULL) { while ((lvp = localvars) != NULL) {
@ -803,10 +804,20 @@ poplocalvars(void)
} else if ((lvp->flags & (VUNSET|VSTRFIXED)) == VUNSET) { } else if ((lvp->flags & (VUNSET|VSTRFIXED)) == VUNSET) {
(void)unsetvar(vp->text); (void)unsetvar(vp->text);
} else { } else {
islocalevar = (vp->flags | lvp->flags) & VEXPORT &&
localevar(lvp->text);
if ((vp->flags & VTEXTFIXED) == 0) if ((vp->flags & VTEXTFIXED) == 0)
ckfree(vp->text); ckfree(vp->text);
vp->flags = lvp->flags; vp->flags = lvp->flags;
vp->text = lvp->text; vp->text = lvp->text;
if (vp->func)
(*vp->func)(vp->text + vp->name_len + 1);
if (islocalevar) {
change_env(vp->text, vp->flags & VEXPORT &&
(vp->flags & VUNSET) == 0);
setlocale(LC_ALL, "");
updatecharset();
}
} }
ckfree(lvp); ckfree(lvp);
} }

View File

@ -1437,7 +1437,7 @@ main(int argc, char *argv[])
for (;;) { for (;;) {
r = poll (hv_kvp_poll_fd, 1, 100); r = poll (hv_kvp_poll_fd, 1, INFTIM);
KVP_LOG(LOG_DEBUG, "poll returned r = %d, revent = 0x%x\n", KVP_LOG(LOG_DEBUG, "poll returned r = %d, revent = 0x%x\n",
r, hv_kvp_poll_fd[0].revents); r, hv_kvp_poll_fd[0].revents);

View File

@ -2,6 +2,9 @@
GCCDIR= ${.CURDIR}/../../../contrib/gcc GCCDIR= ${.CURDIR}/../../../contrib/gcc
GCCLIB= ${.CURDIR}/../../../contrib/gcclibs GCCLIB= ${.CURDIR}/../../../contrib/gcclibs
COMPILERRTDIR= ${.CURDIR}/../../../contrib/compiler-rt
UNWINDINCDIR= ${.CURDIR}/../../../contrib/llvm/projects/libunwind/include
UNWINDSRCDIR= ${.CURDIR}/../../../contrib/llvm/projects/libunwind/src
SHLIB_NAME= libgcc_s.so.1 SHLIB_NAME= libgcc_s.so.1
SHLIBDIR?= /lib SHLIBDIR?= /lib
@ -67,8 +70,37 @@ LIB2ADD = $(LIB2FUNCS_EXTRA)
LIB2ADD_ST = $(LIB2FUNCS_STATIC_EXTRA) LIB2ADD_ST = $(LIB2FUNCS_STATIC_EXTRA)
# Additional sources to handle exceptions; overridden by targets as needed. # Additional sources to handle exceptions; overridden by targets as needed.
.if ${MK_LLVM_LIBUNWIND} != "no"
.PATH: ${COMPILERRTDIR}/lib/builtins
.PATH: ${UNWINDSRCDIR}
LIB2ADDEH = gcc_personality_v0.c \
int_util.c \
Unwind-EHABI.cpp \
Unwind-sjlj.c \
UnwindLevel1-gcc-ext.c \
UnwindLevel1.c \
UnwindRegistersRestore.S \
UnwindRegistersSave.S \
libunwind.cpp
CFLAGS+= -I${UNWINDINCDIR} -I${.CURDIR}
.if empty(CXXFLAGS:M-std=*)
CXXFLAGS+= -std=c++11
.endif
CXXFLAGS+= -fno-rtti
.else # MK_LLVM_LIBUNWIND
.if ${TARGET_CPUARCH} == "arm"
LIB2ADDEH = unwind-arm.c libunwind.S pr-support.c unwind-c.c
.else
LIB2ADDEH = unwind-dw2.c unwind-dw2-fde-glibc.c unwind-sjlj.c gthr-gnat.c \ LIB2ADDEH = unwind-dw2.c unwind-dw2-fde-glibc.c unwind-sjlj.c gthr-gnat.c \
unwind-c.c unwind-c.c
.endif
.endif # MK_LLVM_LIBUNWIND
LIB2ADDEHSTATIC = $(LIB2ADDEH) LIB2ADDEHSTATIC = $(LIB2ADDEH)
LIB2ADDEHSHARED = $(LIB2ADDEH) LIB2ADDEHSHARED = $(LIB2ADDEH)
@ -116,7 +148,6 @@ CFLAGS.clang+= -fheinous-gnu-extensions
LIB1ASMSRC = lib1funcs.asm LIB1ASMSRC = lib1funcs.asm
LIB1ASMFUNCS = _dvmd_tls _bb_init_func LIB1ASMFUNCS = _dvmd_tls _bb_init_func
LIB2ADDEH = unwind-arm.c libunwind.S pr-support.c unwind-c.c
# Some compilers generate __aeabi_ functions libgcc_s is missing # Some compilers generate __aeabi_ functions libgcc_s is missing
LIBADD+= compiler_rt LIBADD+= compiler_rt
.endif .endif
@ -160,7 +191,10 @@ LIB2_DIVMOD_FUNCS:= ${LIB2_DIVMOD_FUNCS:S/${sym}//g}
.endfor .endfor
.endif .endif
COMMONHDRS= tm.h tconfig.h options.h unwind.h gthr-default.h COMMONHDRS= tm.h tconfig.h options.h gthr-default.h
.if ${MK_LLVM_LIBUNWIND} == no
COMMONHDRS+= unwind.h
.endif
#----------------------------------------------------------------------- #-----------------------------------------------------------------------
# #
@ -170,6 +204,9 @@ HIDE = -fvisibility=hidden -DHIDE_EXPORTS
CC_T = ${CC} -c ${CFLAGS} ${HIDE} -fPIC CC_T = ${CC} -c ${CFLAGS} ${HIDE} -fPIC
CC_P = ${CC} -c ${CFLAGS} ${HIDE} -p -fPIC CC_P = ${CC} -c ${CFLAGS} ${HIDE} -p -fPIC
CC_S = ${CC} -c ${CFLAGS} ${PICFLAG} -DSHARED CC_S = ${CC} -c ${CFLAGS} ${PICFLAG} -DSHARED
CXX_T = ${CXX} -c ${CXXFLAGS} ${HIDE} -fPIC
CXX_P = ${CXX} -c ${CXXFLAGS} ${HIDE} -p -fPIC
CXX_S = ${CXX} -c ${CXXFLAGS} ${PICFLAG} -DSHARED
#----------------------------------------------------------------------- #-----------------------------------------------------------------------
# #
@ -284,16 +321,26 @@ EH_OBJS_S = ${LIB2ADDEHSHARED:R:S/$/.So/}
EH_CFLAGS = -fexceptions -D__GLIBC__=3 -DElfW=__ElfN EH_CFLAGS = -fexceptions -D__GLIBC__=3 -DElfW=__ElfN
SOBJS += ${EH_OBJS_S} SOBJS += ${EH_OBJS_S}
.for _src in ${LIB2ADDEHSTATIC} .for _src in ${LIB2ADDEHSTATIC:M*.c}
${_src:R:S/$/.o/}: ${_src} ${COMMONHDRS} ${_src:R:S/$/.o/}: ${_src} ${COMMONHDRS}
${CC_T} ${EH_CFLAGS} -o ${.TARGET} ${.IMPSRC} ${CC_T} ${EH_CFLAGS} -o ${.TARGET} ${.IMPSRC}
${_src:R:S/$/.po/}: ${_src} ${COMMONHDRS} ${_src:R:S/$/.po/}: ${_src} ${COMMONHDRS}
${CC_P} ${EH_CFLAGS} -o ${.TARGET} ${.IMPSRC} ${CC_P} ${EH_CFLAGS} -o ${.TARGET} ${.IMPSRC}
.endfor .endfor
.for _src in ${LIB2ADDEHSHARED} .for _src in ${LIB2ADDEHSTATIC:M*.cpp}
${_src:R:S/$/.o/}: ${_src} ${COMMONHDRS}
${CXX_T} ${EH_CFLAGS} -o ${.TARGET} ${.IMPSRC}
${_src:R:S/$/.po/}: ${_src} ${COMMONHDRS}
${CXX_P} ${EH_CFLAGS} -o ${.TARGET} ${.IMPSRC}
.endfor
.for _src in ${LIB2ADDEHSHARED:M*.c}
${_src:R:S/$/.So/}: ${_src} ${COMMONHDRS} ${_src:R:S/$/.So/}: ${_src} ${COMMONHDRS}
${CC_S} ${EH_CFLAGS} -o ${.TARGET} ${.IMPSRC} ${CC_S} ${EH_CFLAGS} -o ${.TARGET} ${.IMPSRC}
.endfor .endfor
.for _src in ${LIB2ADDEHSHARED:M*.cpp}
${_src:R:S/$/.So/}: ${_src} ${COMMONHDRS}
${CXX_S} ${EH_CFLAGS} -o ${.TARGET} ${.IMPSRC}
.endfor
#----------------------------------------------------------------------- #-----------------------------------------------------------------------

View File

@ -59,10 +59,12 @@
#define _POSIX_TZNAME_MAX 3 #define _POSIX_TZNAME_MAX 3
#endif #endif
#if __POSIX_VISIBLE >= 200112
#define BC_BASE_MAX 99 /* max ibase/obase values in bc(1) */ #define BC_BASE_MAX 99 /* max ibase/obase values in bc(1) */
#define BC_DIM_MAX 2048 /* max array elements in bc(1) */ #define BC_DIM_MAX 2048 /* max array elements in bc(1) */
#define BC_SCALE_MAX 99 /* max scale value in bc(1) */ #define BC_SCALE_MAX 99 /* max scale value in bc(1) */
#define BC_STRING_MAX 1000 /* max const string length in bc(1) */ #define BC_STRING_MAX 1000 /* max const string length in bc(1) */
#define CHARCLASS_NAME_MAX 14 /* max character class name size */
#define COLL_WEIGHTS_MAX 10 /* max weights for order keyword */ #define COLL_WEIGHTS_MAX 10 /* max weights for order keyword */
#define EXPR_NEST_MAX 32 /* max expressions nested in expr(1) */ #define EXPR_NEST_MAX 32 /* max expressions nested in expr(1) */
#define LINE_MAX 2048 /* max bytes in an input line */ #define LINE_MAX 2048 /* max bytes in an input line */
@ -72,11 +74,14 @@
#define _POSIX2_BC_DIM_MAX 2048 #define _POSIX2_BC_DIM_MAX 2048
#define _POSIX2_BC_SCALE_MAX 99 #define _POSIX2_BC_SCALE_MAX 99
#define _POSIX2_BC_STRING_MAX 1000 #define _POSIX2_BC_STRING_MAX 1000
#define _POSIX2_CHARCLASS_NAME_MAX 14
#define _POSIX2_COLL_WEIGHTS_MAX 2
#define _POSIX2_EQUIV_CLASS_MAX 2 #define _POSIX2_EQUIV_CLASS_MAX 2
#define _POSIX2_EXPR_NEST_MAX 32 #define _POSIX2_EXPR_NEST_MAX 32
#define _POSIX2_LINE_MAX 2048 #define _POSIX2_LINE_MAX 2048
#define _POSIX2_RE_DUP_MAX 255 #define _POSIX2_RE_DUP_MAX 255
#endif #endif
#endif
#if __POSIX_VISIBLE >= 199309 #if __POSIX_VISIBLE >= 199309
#define _POSIX_AIO_LISTIO_MAX 2 #define _POSIX_AIO_LISTIO_MAX 2
@ -110,8 +115,6 @@
#define _POSIX_TRACE_SYS_MAX 8 #define _POSIX_TRACE_SYS_MAX 8
#define _POSIX_TRACE_USER_EVENT_MAX 32 #define _POSIX_TRACE_USER_EVENT_MAX 32
#define _POSIX_TTY_NAME_MAX 9 #define _POSIX_TTY_NAME_MAX 9
#define _POSIX2_CHARCLASS_NAME_MAX 14
#define _POSIX2_COLL_WEIGHTS_MAX 2
#define _POSIX_RE_DUP_MAX _POSIX2_RE_DUP_MAX #define _POSIX_RE_DUP_MAX _POSIX2_RE_DUP_MAX
#endif #endif

View File

@ -7,6 +7,7 @@ OBJS= ${SRCS:N*.h:R:S/$/.o/g}
OBJS+= Scrt1.o gcrt1.o OBJS+= Scrt1.o gcrt1.o
CFLAGS+= -I${.CURDIR}/../common \ CFLAGS+= -I${.CURDIR}/../common \
-I${.CURDIR}/../../libc/include -I${.CURDIR}/../../libc/include
STATIC_CFLAGS+= -mlong-calls
FILES= ${OBJS} FILES= ${OBJS}
FILESMODE= ${LIBMODE} FILESMODE= ${LIBMODE}
@ -23,14 +24,14 @@ CLEANFILES+= crt1.s gcrt1.s Scrt1.s
# directly compiled to .o files. # directly compiled to .o files.
crt1.s: crt1.c crt1.s: crt1.c
${CC} ${CFLAGS} -S -o ${.TARGET} ${.CURDIR}/crt1.c ${CC} ${CFLAGS} ${STATIC_CFLAGS} -S -o ${.TARGET} ${.CURDIR}/crt1.c
sed ${SED_FIX_NOTE} ${.TARGET} sed ${SED_FIX_NOTE} ${.TARGET}
crt1.o: crt1.s crt1.o: crt1.s
${CC} ${ACFLAGS} -c -o ${.TARGET} crt1.s ${CC} ${ACFLAGS} -c -o ${.TARGET} crt1.s
gcrt1.s: crt1.c gcrt1.s: crt1.c
${CC} ${CFLAGS} -DGCRT -S -o ${.TARGET} ${.CURDIR}/crt1.c ${CC} ${CFLAGS} ${STATIC_CFLAGS} -DGCRT -S -o ${.TARGET} ${.CURDIR}/crt1.c
sed ${SED_FIX_NOTE} ${.TARGET} sed ${SED_FIX_NOTE} ${.TARGET}
gcrt1.o: gcrt1.s gcrt1.o: gcrt1.s

View File

@ -25,7 +25,7 @@
.\" .\"
.\" $FreeBSD$ .\" $FreeBSD$
.\" .\"
.Dd January 7, 2010 .Dd January 7, 2016
.Dt SENDFILE 2 .Dt SENDFILE 2
.Os .Os
.Sh NAME .Sh NAME
@ -46,7 +46,7 @@
The The
.Fn sendfile .Fn sendfile
system call system call
sends a regular file specified by descriptor sends a regular file or shared memory object specified by descriptor
.Fa fd .Fa fd
out a stream socket specified by descriptor out a stream socket specified by descriptor
.Fa s . .Fa s .
@ -101,32 +101,55 @@ the system will write the total number of bytes sent on the socket to the
variable pointed to by variable pointed to by
.Fa sbytes . .Fa sbytes .
.Pp .Pp
The The least significant 16 bits of
.Fa flags .Fa flags
argument is a bitmap of these values: argument is a bitmap of these values:
.Bl -item -offset indent .Bl -tag -offset indent
.It .It Dv SF_NODISKIO
.Dv SF_NODISKIO . This flag causes
This flag causes any .Nm
.Fn sendfile to return
call which would block on disk I/O to instead .Er EBUSY
return instead of blocking when a busy page is encountered.
.Er EBUSY . This rare situation can happen if some other process is now working
Busy servers may benefit by transferring requests that would with the same region of the file.
block to a separate I/O worker thread. It is advised to retry the operation after a short period.
.It .Pp
.Dv SF_MNOWAIT . Note that in older
Do not wait for some kernel resource to become available, .Fx
in particular, versions the
.Vt mbuf .Dv SF_NODISKIO
and had slightly different notion.
.Vt sf_buf . The flag prevented
The flag does not make the .Nm
.Fn sendfile to run I/O operations in case if an invalid (not cached) page is encountered,
syscall truly non-blocking, since other resources are still allocated thus avoiding blocking on I/O.
in a blocking fashion. Starting with
.It .Fx 11
.Dv SF_SYNC . .Nm
sending files off the
.Xr ffs 7
filesystem doesn't block on I/O
(see
.Sx IMPLEMENTATION NOTES
), so the condition no longer applies.
However, it is safe if an application utilizes
.Dv SF_NODISKIO
and on
.Er EBUSY
performs the same action as it did in
older
.Fx
versions, e.g.
.Xr aio_read 2,
.Xr read 2
or
.Nm
in a different context.
.It Dv SF_NOCACHE
The data sent to socket will not be cached by the virtual memory system,
and will be freed directly to the pool of free pages.
.It Dv SF_SYNC
.Nm .Nm
sleeps until the network stack no longer references the VM pages sleeps until the network stack no longer references the VM pages
of the file, making subsequent modifications to it safe. of the file, making subsequent modifications to it safe.
@ -134,6 +157,22 @@ Please note that this is not a guarantee that the data has actually
been sent. been sent.
.El .El
.Pp .Pp
The most significant 16 bits of
.Fa flags
specify amount of pages that
.Nm
may read ahead when reading the file.
A macro
.Fn SF_FLAGS
is provided to combine readahead amount and flags.
Example shows specifing readahead of 16 pages and
.Dv SF_NOCACHE
flag:
.Pp
.Bd -literal -offset indent -compact
SF_FLAGS(16, SF_NOCACHE)
.Ed
.Pp
When using a socket marked for non-blocking I/O, When using a socket marked for non-blocking I/O,
.Fn sendfile .Fn sendfile
may send fewer bytes than requested. may send fewer bytes than requested.
@ -149,6 +188,18 @@ The
.Fx .Fx
implementation of implementation of
.Fn sendfile .Fn sendfile
doesn't block on disk I/O when it sends a file off the
.Xr ffs 7
filesystem.
The syscall returns success before the actual I/O completes, and data
is put into the socket later unattended.
However, the order of data in the socket is preserved, so it is safe
to do further writes to the socket.
.Pp
The
.Fx
implementation of
.Fn sendfile
is "zero-copy", meaning that it has been optimized so that copying of the file data is avoided. is "zero-copy", meaning that it has been optimized so that copying of the file data is avoided.
.Sh TUNING .Sh TUNING
On some architectures, this system call internally uses a special On some architectures, this system call internally uses a special
@ -232,12 +283,10 @@ The
argument argument
is not a valid socket descriptor. is not a valid socket descriptor.
.It Bq Er EBUSY .It Bq Er EBUSY
Completing the entire transfer would have required disk I/O, so A busy page was encountered and
it was aborted.
Partial data may have been sent.
(This error can only occur when
.Dv SF_NODISKIO .Dv SF_NODISKIO
is specified.) had been specified.
Partial data may have been sent.
.It Bq Er EFAULT .It Bq Er EFAULT
An invalid address was specified for an argument. An invalid address was specified for an argument.
.It Bq Er EINTR .It Bq Er EINTR
@ -310,9 +359,19 @@ first appeared in
.Fx 3.0 . .Fx 3.0 .
This manual page first appeared in This manual page first appeared in
.Fx 3.1 . .Fx 3.1 .
In
.Fx 10
support for sending shared memory descriptors had been introduced.
In
.Fx 11
a non-blocking implementation had been introduced.
.Sh AUTHORS .Sh AUTHORS
The The initial implementation of
.Fn sendfile .Fn sendfile
system call system call
and this manual page were written by and this manual page were written by
.An David G. Lawrence Aq Mt dg@dglawrence.com . .An David G. Lawrence Aq Mt dg@dglawrence.com .
The
.Fx 11
implementation was written by
.An Gleb Smirnoff Aq Mt glebius@FreeBSD.org .

View File

@ -46,7 +46,7 @@ tohex(char **buf, int len, uint32_t val)
char *walker = *buf; char *walker = *buf;
int i; int i;
for (i = len - 1; i >= 0; i++) { for (i = len - 1; i >= 0; i--) {
walker[i] = hexstr[val & 0xf]; walker[i] = hexstr[val & 0xf];
val >>= 4; val >>= 4;
} }
@ -107,5 +107,5 @@ uuid_to_string(const uuid_t *u, char **s, uint32_t *status)
tohex(&w, 2, u->node[3]); tohex(&w, 2, u->node[3]);
tohex(&w, 2, u->node[4]); tohex(&w, 2, u->node[4]);
tohex(&w, 2, u->node[5]); tohex(&w, 2, u->node[5]);
*w++ - '\0'; *w++ = '\0';
} }

View File

@ -275,6 +275,7 @@ extra_chroot_setup() {
PBUILD_FLAGS="${PBUILD_FLAGS} OSREL=${REVISION}" PBUILD_FLAGS="${PBUILD_FLAGS} OSREL=${REVISION}"
chroot ${CHROOTDIR} make -C /usr/ports/textproc/docproj \ chroot ${CHROOTDIR} make -C /usr/ports/textproc/docproj \
${PBUILD_FLAGS} OPTIONS_UNSET="FOP IGOR" \ ${PBUILD_FLAGS} OPTIONS_UNSET="FOP IGOR" \
FORCE_PKG_REGISTER=1 \
install clean distclean install clean distclean
fi fi
fi fi

View File

@ -33,7 +33,7 @@
.\" .\"
.\" $FreeBSD$ .\" $FreeBSD$
.\" .\"
.Dd May 9, 2014 .Dd January 11, 2016
.Dt ISMT 4 .Dt ISMT 4
.Os .Os
.Sh NAME .Sh NAME
@ -54,6 +54,6 @@ in the Intel Atom S1200 and C2000 CPUs.
The The
.Nm .Nm
driver first appeared in driver first appeared in
.Fx 11.0 . .Fx 10.3 .
.Sh AUTHORS .Sh AUTHORS
.An Jim Harris Aq Mt jimharris@FreeBSD.org .An Jim Harris Aq Mt jimharris@FreeBSD.org

View File

@ -1,7 +1,7 @@
.\" DO NOT EDIT-- this file is automatically generated. .\" DO NOT EDIT-- this file is automatically generated.
.\" from FreeBSD: head/tools/build/options/makeman 292283 2015-12-15 18:42:30Z bdrewery .\" from FreeBSD: head/tools/build/options/makeman 292283 2015-12-15 18:42:30Z bdrewery
.\" $FreeBSD$ .\" $FreeBSD$
.Dd December 15, 2015 .Dd January 9, 2016
.Dt SRC.CONF 5 .Dt SRC.CONF 5
.Os .Os
.Sh NAME .Sh NAME
@ -948,9 +948,30 @@ Set to not build the
.Nm libthr .Nm libthr
(1:1 threading) (1:1 threading)
library. library.
.It Va WITHOUT_LLDB
.\" from FreeBSD: head/tools/build/options/WITHOUT_LLDB 289275 2015-10-14 00:23:31Z emaste
Set to not build the LLDB debugger.
.Pp
It is a default setting on
arm/arm, arm/armeb, arm/armv6, arm/armv6hf, i386/i386, mips/mipsel, mips/mips, mips/mips64el, mips/mips64, mips/mipsn32, pc98/i386, powerpc/powerpc, powerpc/powerpc64 and sparc64/sparc64.
.It Va WITH_LLDB .It Va WITH_LLDB
.\" from FreeBSD: head/tools/build/options/WITH_LLDB 255722 2013-09-20 01:52:02Z emaste .\" from FreeBSD: head/tools/build/options/WITH_LLDB 255722 2013-09-20 01:52:02Z emaste
Set to build the LLDB debugger. Set to build the LLDB debugger.
.Pp
It is a default setting on
amd64/amd64 and arm64/aarch64.
.It Va WITHOUT_LLVM_LIBUNWIND
.\" from FreeBSD: head/tools/build/options/WITHOUT_LLVM_LIBUNWIND 293450 2016-01-09 00:42:07Z emaste
Set to use GCC's stack unwinder (instead of LLVM's libunwind).
.Pp
It is a default setting on
amd64/amd64, arm/arm, arm/armeb, arm/armv6, arm/armv6hf, i386/i386, mips/mipsel, mips/mips, mips/mips64el, mips/mips64, mips/mipsn32, pc98/i386, powerpc/powerpc, powerpc/powerpc64 and sparc64/sparc64.
.It Va WITH_LLVM_LIBUNWIND
.\" from FreeBSD: head/tools/build/options/WITH_LLVM_LIBUNWIND 293450 2016-01-09 00:42:07Z emaste
Set to use LLVM's libunwind stack unwinder (instead of GCC's unwinder).
.Pp
It is a default setting on
arm64/aarch64.
.It Va WITHOUT_LOCALES .It Va WITHOUT_LOCALES
.\" from FreeBSD: head/tools/build/options/WITHOUT_LOCALES 156932 2006-03-21 07:50:50Z ru .\" from FreeBSD: head/tools/build/options/WITHOUT_LOCALES 156932 2006-03-21 07:50:50Z ru
Set to not build localization files; see Set to not build localization files; see

View File

@ -344,6 +344,7 @@ adrian -> loos
adrian -> monthadar adrian -> monthadar
adrian -> ray adrian -> ray
adrian -> rmh adrian -> rmh
adrian -> sephe
ae -> melifaro ae -> melifaro
@ -404,6 +405,7 @@ das -> rodrigc
delphij -> gabor delphij -> gabor
delphij -> rafan delphij -> rafan
delphij -> sephe
des -> anholt des -> anholt
des -> hmp des -> hmp

View File

@ -231,9 +231,9 @@ __DEFAULT_NO_OPTIONS+=CLANG CLANG_BOOTSTRAP CLANG_FULL CLANG_IS_CC
# In-tree binutils/gcc are older versions without modern architecture support. # In-tree binutils/gcc are older versions without modern architecture support.
.if ${__T} == "aarch64" || ${__T} == "riscv64" .if ${__T} == "aarch64" || ${__T} == "riscv64"
BROKEN_OPTIONS+=BINUTILS BINUTILS_BOOTSTRAP GCC GCC_BOOTSTRAP GDB BROKEN_OPTIONS+=BINUTILS BINUTILS_BOOTSTRAP GCC GCC_BOOTSTRAP GDB
__DEFAULT_YES_OPTIONS+=ELFCOPY_AS_OBJCOPY __DEFAULT_YES_OPTIONS+=ELFCOPY_AS_OBJCOPY LLVM_LIBUNWIND
.else .else
__DEFAULT_NO_OPTIONS+=ELFCOPY_AS_OBJCOPY __DEFAULT_NO_OPTIONS+=ELFCOPY_AS_OBJCOPY LLVM_LIBUNWIND
.endif .endif
.if ${__T} == "riscv64" .if ${__T} == "riscv64"
BROKEN_OPTIONS+=PROFILE # "sorry, unimplemented: profiler support for RISC-V" BROKEN_OPTIONS+=PROFILE # "sorry, unimplemented: profiler support for RISC-V"

View File

@ -80,6 +80,7 @@ struct sysentvec elf64_freebsd_sysvec = {
.sv_shared_page_len = PAGE_SIZE, .sv_shared_page_len = PAGE_SIZE,
.sv_schedtail = NULL, .sv_schedtail = NULL,
.sv_thread_detach = NULL, .sv_thread_detach = NULL,
.sv_trap = NULL,
}; };
INIT_SYSENTVEC(elf64_sysvec, &elf64_freebsd_sysvec); INIT_SYSENTVEC(elf64_sysvec, &elf64_freebsd_sysvec);

View File

@ -322,6 +322,13 @@ trap(struct trapframe *frame)
break; break;
case T_PAGEFLT: /* page fault */ case T_PAGEFLT: /* page fault */
/*
* Emulator can take care about this trap?
*/
if (*p->p_sysent->sv_trap != NULL &&
(*p->p_sysent->sv_trap)(td) == 0)
goto userout;
addr = frame->tf_addr; addr = frame->tf_addr;
i = trap_pfault(frame, TRUE); i = trap_pfault(frame, TRUE);
if (i == -1) if (i == -1)

View File

@ -129,6 +129,7 @@ static void linux_set_syscall_retval(struct thread *td, int error);
static int linux_fetch_syscall_args(struct thread *td, struct syscall_args *sa); static int linux_fetch_syscall_args(struct thread *td, struct syscall_args *sa);
static void linux_exec_setregs(struct thread *td, struct image_params *imgp, static void linux_exec_setregs(struct thread *td, struct image_params *imgp,
u_long stack); u_long stack);
static int linux_vsyscall(struct thread *td);
/* /*
* Linux syscalls return negative errno's, we do positive and map them * Linux syscalls return negative errno's, we do positive and map them
@ -746,6 +747,53 @@ exec_linux_imgact_try(struct image_params *imgp)
return(error); return(error);
} }
#define LINUX_VSYSCALL_START (-10UL << 20)
#define LINUX_VSYSCALL_SZ 1024
const unsigned long linux_vsyscall_vector[] = {
LINUX_SYS_gettimeofday,
LINUX_SYS_linux_time,
/* getcpu not implemented */
};
static int
linux_vsyscall(struct thread *td)
{
struct trapframe *frame;
uint64_t retqaddr;
int code, traced;
int error;
frame = td->td_frame;
/* Check %rip for vsyscall area */
if (__predict_true(frame->tf_rip < LINUX_VSYSCALL_START))
return (EINVAL);
if ((frame->tf_rip & (LINUX_VSYSCALL_SZ - 1)) != 0)
return (EINVAL);
code = (frame->tf_rip - LINUX_VSYSCALL_START) / LINUX_VSYSCALL_SZ;
if (code >= nitems(linux_vsyscall_vector))
return (EINVAL);
/*
* vsyscall called as callq *(%rax), so we must
* use return address from %rsp and also fixup %rsp
*/
error = copyin((void *)frame->tf_rsp, &retqaddr, sizeof(retqaddr));
if (error)
return (error);
frame->tf_rip = retqaddr;
frame->tf_rax = linux_vsyscall_vector[code];
frame->tf_rsp += 8;
traced = (frame->tf_flags & PSL_T);
amd64_syscall(td, traced);
return (0);
}
struct sysentvec elf_linux_sysvec = { struct sysentvec elf_linux_sysvec = {
.sv_size = LINUX_SYS_MAXSYSCALL, .sv_size = LINUX_SYS_MAXSYSCALL,
.sv_table = linux_sysent, .sv_table = linux_sysent,
@ -778,7 +826,8 @@ struct sysentvec elf_linux_sysvec = {
.sv_shared_page_base = SHAREDPAGE, .sv_shared_page_base = SHAREDPAGE,
.sv_shared_page_len = PAGE_SIZE, .sv_shared_page_len = PAGE_SIZE,
.sv_schedtail = linux_schedtail, .sv_schedtail = linux_schedtail,
.sv_thread_detach = linux_thread_detach .sv_thread_detach = linux_thread_detach,
.sv_trap = linux_vsyscall,
}; };
static void static void

View File

@ -1040,6 +1040,7 @@ struct sysentvec elf_linux_sysvec = {
.sv_shared_page_len = PAGE_SIZE, .sv_shared_page_len = PAGE_SIZE,
.sv_schedtail = linux_schedtail, .sv_schedtail = linux_schedtail,
.sv_thread_detach = linux_thread_detach, .sv_thread_detach = linux_thread_detach,
.sv_trap = NULL,
}; };
static void static void

View File

@ -86,6 +86,7 @@ struct sysentvec elf32_freebsd_sysvec = {
.sv_shared_page_len = PAGE_SIZE, .sv_shared_page_len = PAGE_SIZE,
.sv_schedtail = NULL, .sv_schedtail = NULL,
.sv_thread_detach = NULL, .sv_thread_detach = NULL,
.sv_trap = NULL,
}; };
INIT_SYSENTVEC(elf32_sysvec, &elf32_freebsd_sysvec); INIT_SYSENTVEC(elf32_sysvec, &elf32_freebsd_sysvec);

View File

@ -87,6 +87,8 @@ static struct sysentvec elf64_freebsd_sysvec = {
.sv_shared_page_base = SHAREDPAGE, .sv_shared_page_base = SHAREDPAGE,
.sv_shared_page_len = PAGE_SIZE, .sv_shared_page_len = PAGE_SIZE,
.sv_schedtail = NULL, .sv_schedtail = NULL,
.sv_thread_detach = NULL,
.sv_trap = NULL,
}; };
INIT_SYSENTVEC(elf64_sysvec, &elf64_freebsd_sysvec); INIT_SYSENTVEC(elf64_sysvec, &elf64_freebsd_sysvec);

View File

@ -211,7 +211,6 @@ fsread(ufs_ino_t inode, void *buf, size_t nbyte)
break; break;
} }
if (sblock_try[n] == -1) { if (sblock_try[n] == -1) {
printf("Not ufs\n");
return -1; return -1;
} }
dsk_meta++; dsk_meta++;

View File

@ -41,14 +41,13 @@ CFLAGS+= -fPIC
LDFLAGS+= -Wl,-znocombreloc LDFLAGS+= -Wl,-znocombreloc
.endif .endif
.if ${MACHINE_CPUARCH} == "arm" || ${MACHINE_CPUARCH} == "i386"
# #
# Add libstand for the runtime functions used by the compiler - for example # Add libstand for the runtime functions used by the compiler - for example
# __aeabi_* (arm) or __divdi3 (i386). # __aeabi_* (arm) or __divdi3 (i386).
# as well as required string and memory functions for all platforms.
# #
DPADD+= ${LIBSTAND} DPADD+= ${LIBSTAND}
LDADD+= -lstand LDADD+= -lstand
.endif
DPADD+= ${LDSCRIPT} DPADD+= ${LDSCRIPT}

View File

@ -24,6 +24,7 @@ __FBSDID("$FreeBSD$");
#include <sys/dirent.h> #include <sys/dirent.h>
#include <machine/elf.h> #include <machine/elf.h>
#include <machine/stdarg.h> #include <machine/stdarg.h>
#include <stand.h>
#include <efi.h> #include <efi.h>
#include <eficonsctl.h> #include <eficonsctl.h>
@ -33,28 +34,8 @@ __FBSDID("$FreeBSD$");
#define BSIZEMAX 16384 #define BSIZEMAX 16384
typedef int putc_func_t(char c, void *arg); void panic(const char *fmt, ...) __dead2;
void putchar(int c);
struct sp_data {
char *sp_buf;
u_int sp_len;
u_int sp_size;
};
static const char digits[] = "0123456789abcdef";
static void panic(const char *fmt, ...) __dead2;
static int printf(const char *fmt, ...);
static int putchar(char c, void *arg);
static int vprintf(const char *fmt, va_list ap);
static int vsnprintf(char *str, size_t sz, const char *fmt, va_list ap);
static int __printf(const char *fmt, putc_func_t *putc, void *arg, va_list ap);
static int __putc(char c, void *arg);
static int __puts(const char *s, putc_func_t *putc, void *arg);
static int __sputc(char c, void *arg);
static char *__uitoa(char *buf, u_int val, int base);
static char *__ultoa(char *buf, u_long val, int base);
static int domount(EFI_DEVICE_PATH *device, EFI_BLOCK_IO *blkio, int quiet); static int domount(EFI_DEVICE_PATH *device, EFI_BLOCK_IO *blkio, int quiet);
static void load(const char *fname); static void load(const char *fname);
@ -62,39 +43,6 @@ static void load(const char *fname);
static EFI_SYSTEM_TABLE *systab; static EFI_SYSTEM_TABLE *systab;
static EFI_HANDLE *image; static EFI_HANDLE *image;
static void
bcopy(const void *src, void *dst, size_t len)
{
const char *s = src;
char *d = dst;
while (len-- != 0)
*d++ = *s++;
}
static void
memcpy(void *dst, const void *src, size_t len)
{
bcopy(src, dst, len);
}
static void
bzero(void *b, size_t len)
{
char *p = b;
while (len-- != 0)
*p++ = 0;
}
static int
strcmp(const char *s1, const char *s2)
{
for (; *s1 == *s2 && *s1; s1++, s2++)
;
return ((u_char)*s1 - (u_char)*s2);
}
static EFI_GUID BlockIoProtocolGUID = BLOCK_IO_PROTOCOL; static EFI_GUID BlockIoProtocolGUID = BLOCK_IO_PROTOCOL;
static EFI_GUID DevicePathGUID = DEVICE_PATH_PROTOCOL; static EFI_GUID DevicePathGUID = DEVICE_PATH_PROTOCOL;
static EFI_GUID LoadedImageGUID = LOADED_IMAGE_PROTOCOL; static EFI_GUID LoadedImageGUID = LOADED_IMAGE_PROTOCOL;
@ -250,7 +198,6 @@ fsstat(ufs_ino_t inode)
break; break;
} }
if (sblock_try[n] == -1) { if (sblock_try[n] == -1) {
printf("Not ufs\n");
return -1; return -1;
} }
dsk_meta++; dsk_meta++;
@ -346,38 +293,22 @@ load(const char *fname)
EFI_ERROR_CODE(status)); EFI_ERROR_CODE(status));
} }
static void void
panic(const char *fmt, ...) panic(const char *fmt, ...)
{ {
char buf[128];
va_list ap; va_list ap;
printf("panic: ");
va_start(ap, fmt); va_start(ap, fmt);
vsnprintf(buf, sizeof buf, fmt, ap); vprintf(fmt, ap);
printf("panic: %s\n", buf);
va_end(ap); va_end(ap);
printf("\n");
while (1) {} while (1) {}
} }
static int void
printf(const char *fmt, ...) putchar(int c)
{
va_list ap;
int ret;
/* Don't annoy the user as we probe for partitions */
if (strcmp(fmt,"Not ufs\n") == 0)
return 0;
va_start(ap, fmt);
ret = vprintf(fmt, ap);
va_end(ap);
return (ret);
}
static int
putchar(char c, void *arg)
{ {
CHAR16 buf[2]; CHAR16 buf[2];
@ -389,187 +320,4 @@ putchar(char c, void *arg)
buf[0] = c; buf[0] = c;
buf[1] = 0; buf[1] = 0;
systab->ConOut->OutputString(systab->ConOut, buf); systab->ConOut->OutputString(systab->ConOut, buf);
return (1);
}
static int
vprintf(const char *fmt, va_list ap)
{
int ret;
ret = __printf(fmt, putchar, 0, ap);
return (ret);
}
static int
vsnprintf(char *str, size_t sz, const char *fmt, va_list ap)
{
struct sp_data sp;
int ret;
sp.sp_buf = str;
sp.sp_len = 0;
sp.sp_size = sz;
ret = __printf(fmt, __sputc, &sp, ap);
return (ret);
}
static int
__printf(const char *fmt, putc_func_t *putc, void *arg, va_list ap)
{
char buf[(sizeof(long) * 8) + 1];
char *nbuf;
u_long ul;
u_int ui;
int lflag;
int sflag;
char *s;
int pad;
int ret;
int c;
nbuf = &buf[sizeof buf - 1];
ret = 0;
while ((c = *fmt++) != 0) {
if (c != '%') {
ret += putc(c, arg);
continue;
}
lflag = 0;
sflag = 0;
pad = 0;
reswitch: c = *fmt++;
switch (c) {
case '#':
sflag = 1;
goto reswitch;
case '%':
ret += putc('%', arg);
break;
case 'c':
c = va_arg(ap, int);
ret += putc(c, arg);
break;
case 'd':
if (lflag == 0) {
ui = (u_int)va_arg(ap, int);
if (ui < (int)ui) {
ui = -ui;
ret += putc('-', arg);
}
s = __uitoa(nbuf, ui, 10);
} else {
ul = (u_long)va_arg(ap, long);
if (ul < (long)ul) {
ul = -ul;
ret += putc('-', arg);
}
s = __ultoa(nbuf, ul, 10);
}
ret += __puts(s, putc, arg);
break;
case 'l':
lflag = 1;
goto reswitch;
case 'o':
if (lflag == 0) {
ui = (u_int)va_arg(ap, u_int);
s = __uitoa(nbuf, ui, 8);
} else {
ul = (u_long)va_arg(ap, u_long);
s = __ultoa(nbuf, ul, 8);
}
ret += __puts(s, putc, arg);
break;
case 'p':
ul = (u_long)va_arg(ap, void *);
s = __ultoa(nbuf, ul, 16);
ret += __puts("0x", putc, arg);
ret += __puts(s, putc, arg);
break;
case 's':
s = va_arg(ap, char *);
ret += __puts(s, putc, arg);
break;
case 'u':
if (lflag == 0) {
ui = va_arg(ap, u_int);
s = __uitoa(nbuf, ui, 10);
} else {
ul = va_arg(ap, u_long);
s = __ultoa(nbuf, ul, 10);
}
ret += __puts(s, putc, arg);
break;
case 'x':
if (lflag == 0) {
ui = va_arg(ap, u_int);
s = __uitoa(nbuf, ui, 16);
} else {
ul = va_arg(ap, u_long);
s = __ultoa(nbuf, ul, 16);
}
if (sflag)
ret += __puts("0x", putc, arg);
ret += __puts(s, putc, arg);
break;
case '0': case '1': case '2': case '3': case '4':
case '5': case '6': case '7': case '8': case '9':
pad = pad * 10 + c - '0';
goto reswitch;
default:
break;
}
}
return (ret);
}
static int
__sputc(char c, void *arg)
{
struct sp_data *sp;
sp = arg;
if (sp->sp_len < sp->sp_size)
sp->sp_buf[sp->sp_len++] = c;
sp->sp_buf[sp->sp_len] = '\0';
return (1);
}
static int
__puts(const char *s, putc_func_t *putc, void *arg)
{
const char *p;
int ret;
ret = 0;
for (p = s; *p != '\0'; p++)
ret += putc(*p, arg);
return (ret);
}
static char *
__uitoa(char *buf, u_int ui, int base)
{
char *p;
p = buf;
*p = '\0';
do
*--p = digits[ui % base];
while ((ui /= base) != 0);
return (p);
}
static char *
__ultoa(char *buf, u_long ul, int base)
{
char *p;
p = buf;
*p = '\0';
do
*--p = digits[ul % base];
while ((ul /= base) != 0);
return (p);
} }

View File

@ -296,7 +296,8 @@ extract_currdev(void)
} }
#ifdef LOADER_ZFS_SUPPORT #ifdef LOADER_ZFS_SUPPORT
init_zfs_bootenv(zfs_fmtdev(&new_currdev)); if (new_currdev.d_type == DEVT_ZFS)
init_zfs_bootenv(zfs_fmtdev(&new_currdev));
#endif #endif
env_setenv("currdev", EV_VOLATILE, i386_fmtdev(&new_currdev), env_setenv("currdev", EV_VOLATILE, i386_fmtdev(&new_currdev),
@ -311,9 +312,14 @@ init_zfs_bootenv(char *currdev)
{ {
char *beroot; char *beroot;
if (strlen(currdev) == 0)
return;
if(strncmp(currdev, "zfs:", 4) != 0)
return;
/* Remove the trailing : */ /* Remove the trailing : */
currdev[strlen(currdev) - 1] = '\0'; currdev[strlen(currdev) - 1] = '\0';
setenv("zfs_be_active", currdev, 1); setenv("zfs_be_active", currdev, 1);
setenv("zfs_be_currpage", "1", 1);
/* Do not overwrite if already set */ /* Do not overwrite if already set */
setenv("vfs.root.mountfrom", currdev, 0); setenv("vfs.root.mountfrom", currdev, 0);
/* Forward past zfs: */ /* Forward past zfs: */
@ -323,9 +329,7 @@ init_zfs_bootenv(char *currdev)
beroot = strrchr(currdev, '/'); beroot = strrchr(currdev, '/');
if (beroot != NULL) if (beroot != NULL)
beroot[0] = '\0'; beroot[0] = '\0';
beroot = currdev; beroot = currdev;
setenv("zfs_be_root", beroot, 1); setenv("zfs_be_root", beroot, 1);
} }
#endif #endif
@ -394,6 +398,7 @@ static int
command_reloadbe(int argc, char *argv[]) command_reloadbe(int argc, char *argv[])
{ {
int err; int err;
char *root;
if (argc > 2) { if (argc > 2) {
command_errmsg = "wrong number of arguments"; command_errmsg = "wrong number of arguments";
@ -403,6 +408,11 @@ command_reloadbe(int argc, char *argv[])
if (argc == 2) { if (argc == 2) {
err = zfs_bootenv(argv[1]); err = zfs_bootenv(argv[1]);
} else { } else {
root = getenv("zfs_be_root");
if (root == NULL) {
/* There does not appear to be a ZFS pool here, exit without error */
return (CMD_OK);
}
err = zfs_bootenv(getenv("zfs_be_root")); err = zfs_bootenv(getenv("zfs_be_root"));
} }

View File

@ -564,10 +564,6 @@ printf(const char *fmt, ...)
va_list ap; va_list ap;
int ret; int ret;
/* Don't annoy the user as we probe for partitions */
if (strcmp(fmt,"Not ufs\n") == 0)
return 0;
va_start(ap, fmt); va_start(ap, fmt);
ret = vprintf(fmt, ap); ret = vprintf(fmt, ap);
va_end(ap); va_end(ap);

View File

@ -1,136 +1,12 @@
# $FreeBSD$ # $FreeBSD$
# Originally from $NetBSD: Makefile,v 1.21 1997/10/26 22:08:38 lukem Exp $
#
# Notes:
# - We don't use the libc strerror/sys_errlist because the string table is
# quite large.
#
MAN= .include <src.opts.mk>
.include <bsd.own.mk>
MK_SSP= no
LIBSTAND_SRC= ${.CURDIR}/../../../../lib/libstand LIBSTAND_SRC= ${.CURDIR}/../../../../lib/libstand
LIBC_SRC= ${LIBSTAND_SRC}/../libc
.PATH: ${LIBSTAND_SRC}
LIB= stand
INTERNALLIB= INTERNALLIB=
MK_PROFILE= no INCS=
NO_PIC= MAN=
.PATH: ${LIBSTAND_SRC}
WARNS?= 0 .include "${LIBSTAND_SRC}/Makefile"
# standalone components and stuff we have modified locally
SRCS+= gzguts.h zutil.h __main.c assert.c bcd.c bswap.c environment.c getopt.c gets.c \
globals.c pager.c printf.c strdup.c strerror.c strtol.c strtoul.c random.c \
sbrk.c twiddle.c zalloc.c zalloc_malloc.c
# private (pruned) versions of libc string functions
SRCS+= strcasecmp.c
.PATH: ${LIBC_SRC}/net
SRCS+= ntoh.c
# string functions from libc
.PATH: ${LIBC_SRC}/string
.if ${MACHINE_CPUARCH} == "i386" || ${MACHINE_CPUARCH} == "powerpc" || \
${MACHINE_CPUARCH} == "sparc64" || ${MACHINE_CPUARCH} == "amd64" || \
${MACHINE_CPUARCH} == "arm"
SRCS+= bcmp.c bcopy.c bzero.c ffs.c memccpy.c memchr.c memcmp.c memcpy.c \
memmove.c memset.c qdivrem.c strcat.c strchr.c strcmp.c strcpy.c \
strcspn.c strlen.c strncat.c strncmp.c strncpy.c strpbrk.c \
strrchr.c strsep.c strspn.c strstr.c strtok.c swab.c
.endif
.if ${MACHINE_CPUARCH} == "arm"
.PATH: ${LIBC_SRC}/arm/gen
SRCS+= divsi3.S
.endif
.if ${MACHINE_CPUARCH} == "powerpc"
.PATH: ${LIBC_SRC}/quad
SRCS+= ashldi3.c ashrdi3.c
.PATH: ${LIBC_SRC}/powerpc/gen
SRCS+= syncicache.c
.endif
# uuid functions from libc
.PATH: ${LIBC_SRC}/uuid
SRCS+= uuid_equal.c uuid_is_nil.c
# _setjmp/_longjmp
.if ${MACHINE_CPUARCH} == "amd64"
.PATH: ${LIBSTAND_SRC}/amd64
.elif ${MACHINE_ARCH} == "powerpc64"
.PATH: ${LIBSTAND_SRC}/powerpc
.else
.PATH: ${LIBSTAND_SRC}/${MACHINE_CPUARCH}
.endif
SRCS+= _setjmp.S
# decompression functionality from libbz2
# NOTE: to actually test this functionality after libbz2 upgrade compile
# loader(8) with LOADER_BZIP2_SUPPORT defined
.PATH: ${LIBSTAND_SRC}/../../contrib/bzip2
CFLAGS+= -DBZ_NO_STDIO -DBZ_NO_COMPRESS
SRCS+= libstand_bzlib_private.h
.for file in bzlib.c crctable.c decompress.c huffman.c randtable.c
SRCS+= _${file}
CLEANFILES+= _${file}
_${file}: ${file}
sed "s|bzlib_private\.h|libstand_bzlib_private.h|" \
${.ALLSRC} > ${.TARGET}
.endfor
CLEANFILES+= libstand_bzlib_private.h
libstand_bzlib_private.h: bzlib_private.h
sed -e 's|<stdlib.h>|"stand.h"|' \
${.ALLSRC} > ${.TARGET}
# decompression functionality from libz
.PATH: ${LIBSTAND_SRC}/../libz
CFLAGS+=-DHAVE_MEMCPY -I${LIBSTAND_SRC}/../libz
SRCS+= adler32.c crc32.c libstand_zutil.h libstand_gzguts.h
.for file in infback.c inffast.c inflate.c inftrees.c zutil.c
SRCS+= _${file}
CLEANFILES+= _${file}
_${file}: ${file}
sed -e "s|zutil\.h|libstand_zutil.h|" \
-e "s|gzguts\.h|libstand_gzguts.h|" \
${.ALLSRC} > ${.TARGET}
.endfor
# depend on stand.h being able to be included multiple times
.for file in zutil.h gzguts.h
CLEANFILES+= libstand_${file}
libstand_${file}: ${file}
sed -e 's|<fcntl.h>|"stand.h"|' \
-e 's|<stddef.h>|"stand.h"|' \
-e 's|<string.h>|"stand.h"|' \
-e 's|<stdio.h>|"stand.h"|' \
-e 's|<stdlib.h>|"stand.h"|' \
${.ALLSRC} > ${.TARGET}
.endfor
# io routines
SRCS+= closeall.c dev.c ioctl.c nullfs.c stat.c \
fstat.c close.c lseek.c open.c read.c write.c readdir.c
# network routines
SRCS+= arp.c ether.c inet_ntoa.c in_cksum.c net.c udp.c netif.c rpc.c
# network info services:
SRCS+= bootp.c rarp.c bootparam.c
# boot filesystems
SRCS+= ufs.c nfs.c cd9660.c tftp.c gzipfs.c bzipfs.c
SRCS+= dosfs.c ext2fs.c
SRCS+= splitfs.c
.include <bsd.stand.mk>
.include <bsd.lib.mk>

View File

@ -6,7 +6,6 @@ DIRDEPS = \
include/arpa \ include/arpa \
include/xlocale \ include/xlocale \
lib/libbz2 \ lib/libbz2 \
lib/libstand \
.include <dirdeps.mk> .include <dirdeps.mk>

View File

@ -168,6 +168,7 @@ extract_currdev(void)
zdev.d_type = zdev.d_dev->dv_type; zdev.d_type = zdev.d_dev->dv_type;
dev = *(struct disk_devdesc *)&zdev; dev = *(struct disk_devdesc *)&zdev;
init_zfs_bootenv(zfs_fmtdev(&dev));
} else } else
#endif #endif
@ -191,10 +192,6 @@ extract_currdev(void)
dev.d_unit = 0; dev.d_unit = 0;
} }
#if defined(USERBOOT_ZFS_SUPPORT)
init_zfs_bootenv(zfs_fmtdev(&dev));
#endif
env_setenv("currdev", EV_VOLATILE, userboot_fmtdev(&dev), env_setenv("currdev", EV_VOLATILE, userboot_fmtdev(&dev),
userboot_setcurrdev, env_nounset); userboot_setcurrdev, env_nounset);
env_setenv("loaddev", EV_VOLATILE, userboot_fmtdev(&dev), env_setenv("loaddev", EV_VOLATILE, userboot_fmtdev(&dev),
@ -207,9 +204,14 @@ init_zfs_bootenv(char *currdev)
{ {
char *beroot; char *beroot;
if (strlen(currdev) == 0)
return;
if(strncmp(currdev, "zfs:", 4) != 0)
return;
/* Remove the trailing : */ /* Remove the trailing : */
currdev[strlen(currdev) - 1] = '\0'; currdev[strlen(currdev) - 1] = '\0';
setenv("zfs_be_active", currdev, 1); setenv("zfs_be_active", currdev, 1);
setenv("zfs_be_currpage", "1", 1);
/* Do not overwrite if already set */ /* Do not overwrite if already set */
setenv("vfs.root.mountfrom", currdev, 0); setenv("vfs.root.mountfrom", currdev, 0);
/* Forward past zfs: */ /* Forward past zfs: */
@ -219,9 +221,7 @@ init_zfs_bootenv(char *currdev)
beroot = strrchr(currdev, '/'); beroot = strrchr(currdev, '/');
if (beroot != NULL) if (beroot != NULL)
beroot[0] = '\0'; beroot[0] = '\0';
beroot = currdev; beroot = currdev;
setenv("zfs_be_root", beroot, 1); setenv("zfs_be_root", beroot, 1);
} }
@ -273,6 +273,7 @@ static int
command_reloadbe(int argc, char *argv[]) command_reloadbe(int argc, char *argv[])
{ {
int err; int err;
char *root;
if (argc > 2) { if (argc > 2) {
command_errmsg = "wrong number of arguments"; command_errmsg = "wrong number of arguments";
@ -282,7 +283,11 @@ command_reloadbe(int argc, char *argv[])
if (argc == 2) { if (argc == 2) {
err = zfs_bootenv(argv[1]); err = zfs_bootenv(argv[1]);
} else { } else {
err = zfs_bootenv(getenv("zfs_be_root")); root = getenv("zfs_be_root");
if (root == NULL) {
return (CMD_OK);
}
err = zfs_bootenv(root);
} }
if (err != 0) { if (err != 0) {

View File

@ -413,7 +413,7 @@ struct zfs_probe_args {
int fd; int fd;
const char *devname; const char *devname;
uint64_t *pool_guid; uint64_t *pool_guid;
uint16_t secsz; u_int secsz;
}; };
static int static int
@ -712,13 +712,18 @@ zfs_list(const char *name)
int int
zfs_bootenv(const char *name) zfs_bootenv(const char *name)
{ {
static char poolname[ZFS_MAXNAMELEN], *dsname; static char poolname[ZFS_MAXNAMELEN], *dsname, *root;
char becount[4]; char becount[4];
uint64_t objid; uint64_t objid;
spa_t *spa; spa_t *spa;
int len, rv, pages, perpage, currpage; int len, rv, pages, perpage, currpage;
if (strcmp(name, getenv("zfs_be_root")) != 0) { if (name == NULL)
return (EINVAL);
if ((root = getenv("zfs_be_root")) == NULL)
return (EINVAL);
if (strcmp(name, root) != 0) {
if (setenv("zfs_be_root", name, 1) != 0) if (setenv("zfs_be_root", name, 1) != 0)
return (ENOMEM); return (ENOMEM);
} }

View File

@ -78,6 +78,9 @@ static void
vdev_geom_attrchanged(struct g_consumer *cp, const char *attr) vdev_geom_attrchanged(struct g_consumer *cp, const char *attr)
{ {
vdev_t *vd; vdev_t *vd;
spa_t *spa;
char *physpath;
int error, physpath_len;
vd = cp->private; vd = cp->private;
if (vd == NULL) if (vd == NULL)
@ -87,6 +90,47 @@ vdev_geom_attrchanged(struct g_consumer *cp, const char *attr)
vdev_geom_set_rotation_rate(vd, cp); vdev_geom_set_rotation_rate(vd, cp);
return; return;
} }
if (strcmp(attr, "GEOM::physpath") != 0)
return;
if (g_access(cp, 1, 0, 0) != 0)
return;
/*
* Record/Update physical path information for this device.
*/
spa = vd->vdev_spa;
physpath_len = MAXPATHLEN;
physpath = g_malloc(physpath_len, M_WAITOK|M_ZERO);
error = g_io_getattr("GEOM::physpath", cp, &physpath_len, physpath);
g_access(cp, -1, 0, 0);
if (error == 0) {
char *old_physpath;
old_physpath = vd->vdev_physpath;
vd->vdev_physpath = spa_strdup(physpath);
spa_async_request(spa, SPA_ASYNC_CONFIG_UPDATE);
if (old_physpath != NULL) {
int held_lock;
held_lock = spa_config_held(spa, SCL_STATE, RW_WRITER);
if (held_lock == 0) {
g_topology_unlock();
spa_config_enter(spa, SCL_STATE, FTAG,
RW_WRITER);
}
spa_strfree(old_physpath);
if (held_lock == 0) {
spa_config_exit(spa, SCL_STATE, FTAG);
g_topology_lock();
}
}
}
g_free(physpath);
} }
static void static void
@ -97,8 +141,10 @@ vdev_geom_orphan(struct g_consumer *cp)
g_topology_assert(); g_topology_assert();
vd = cp->private; vd = cp->private;
if (vd == NULL) if (vd == NULL) {
/* Vdev close in progress. Ignore the event. */
return; return;
}
/* /*
* Orphan callbacks occur from the GEOM event thread. * Orphan callbacks occur from the GEOM event thread.
@ -120,7 +166,7 @@ vdev_geom_orphan(struct g_consumer *cp)
} }
static struct g_consumer * static struct g_consumer *
vdev_geom_attach(struct g_provider *pp) vdev_geom_attach(struct g_provider *pp, vdev_t *vd)
{ {
struct g_geom *gp; struct g_geom *gp;
struct g_consumer *cp; struct g_consumer *cp;
@ -139,6 +185,7 @@ vdev_geom_attach(struct g_provider *pp)
if (gp == NULL) { if (gp == NULL) {
gp = g_new_geomf(&zfs_vdev_class, "zfs::vdev"); gp = g_new_geomf(&zfs_vdev_class, "zfs::vdev");
gp->orphan = vdev_geom_orphan; gp->orphan = vdev_geom_orphan;
gp->attrchanged = vdev_geom_attrchanged;
cp = g_new_consumer(gp); cp = g_new_consumer(gp);
if (g_attach(cp, pp) != 0) { if (g_attach(cp, pp) != 0) {
g_wither_geom(gp, ENXIO); g_wither_geom(gp, ENXIO);
@ -175,28 +222,56 @@ vdev_geom_attach(struct g_provider *pp)
ZFS_LOG(1, "Used existing consumer for %s.", pp->name); ZFS_LOG(1, "Used existing consumer for %s.", pp->name);
} }
} }
/*
* BUG: cp may already belong to a vdev. This could happen if:
* 1) That vdev is a shared spare, or
* 2) We are trying to reopen a missing vdev and we are scanning by
* guid. In that case, we'll ultimately fail to open this consumer,
* but not until after setting the private field.
* The solution is to:
* 1) Don't set the private field until after the open succeeds, and
* 2) Set it to a linked list of vdevs, not just a single vdev
*/
cp->private = vd;
vd->vdev_tsd = cp;
/* Fetch initial physical path information for this device. */
vdev_geom_attrchanged(cp, "GEOM::physpath");
cp->flags |= G_CF_DIRECT_SEND | G_CF_DIRECT_RECEIVE; cp->flags |= G_CF_DIRECT_SEND | G_CF_DIRECT_RECEIVE;
return (cp); return (cp);
} }
static void static void
vdev_geom_detach(void *arg, int flag __unused) vdev_geom_close_locked(vdev_t *vd)
{ {
struct g_geom *gp; struct g_geom *gp;
struct g_consumer *cp; struct g_consumer *cp;
g_topology_assert(); g_topology_assert();
cp = arg;
gp = cp->geom; cp = vd->vdev_tsd;
if (cp == NULL)
return;
ZFS_LOG(1, "Closing access to %s.", cp->provider->name); ZFS_LOG(1, "Closing access to %s.", cp->provider->name);
KASSERT(vd->vdev_tsd == cp, ("%s: vdev_tsd is not cp", __func__));
vd->vdev_tsd = NULL;
vd->vdev_delayed_close = B_FALSE;
cp->private = NULL;
gp = cp->geom;
g_access(cp, -1, 0, -1); g_access(cp, -1, 0, -1);
/* Destroy consumer on last close. */ /* Destroy consumer on last close. */
if (cp->acr == 0 && cp->ace == 0) { if (cp->acr == 0 && cp->ace == 0) {
ZFS_LOG(1, "Destroyed consumer to %s.", cp->provider->name);
if (cp->acw > 0) if (cp->acw > 0)
g_access(cp, 0, -cp->acw, 0); g_access(cp, 0, -cp->acw, 0);
g_detach(cp); if (cp->provider != NULL) {
ZFS_LOG(1, "Destroyed consumer to %s.",
cp->provider->name);
g_detach(cp);
}
g_destroy_consumer(cp); g_destroy_consumer(cp);
} }
/* Destroy geom if there are no consumers left. */ /* Destroy geom if there are no consumers left. */
@ -490,7 +565,7 @@ vdev_geom_read_guids(struct g_consumer *cp, uint64_t *pguid, uint64_t *vguid)
} }
static struct g_consumer * static struct g_consumer *
vdev_geom_attach_by_guids(uint64_t pool_guid, uint64_t vdev_guid) vdev_geom_attach_by_guids(vdev_t *vd)
{ {
struct g_class *mp; struct g_class *mp;
struct g_geom *gp, *zgp; struct g_geom *gp, *zgp;
@ -519,9 +594,10 @@ vdev_geom_attach_by_guids(uint64_t pool_guid, uint64_t vdev_guid)
vdev_geom_read_guids(zcp, &pguid, &vguid); vdev_geom_read_guids(zcp, &pguid, &vguid);
g_topology_lock(); g_topology_lock();
vdev_geom_detach_taster(zcp); vdev_geom_detach_taster(zcp);
if (pguid != pool_guid || vguid != vdev_guid) if (pguid != spa_guid(vd->vdev_spa) ||
vguid != vd->vdev_guid)
continue; continue;
cp = vdev_geom_attach(pp); cp = vdev_geom_attach(pp, vd);
if (cp == NULL) { if (cp == NULL) {
printf("ZFS WARNING: Unable to " printf("ZFS WARNING: Unable to "
"attach to %s.\n", pp->name); "attach to %s.\n", pp->name);
@ -551,7 +627,7 @@ vdev_geom_open_by_guids(vdev_t *vd)
g_topology_assert(); g_topology_assert();
ZFS_LOG(1, "Searching by guid [%ju].", (uintmax_t)vd->vdev_guid); ZFS_LOG(1, "Searching by guid [%ju].", (uintmax_t)vd->vdev_guid);
cp = vdev_geom_attach_by_guids(spa_guid(vd->vdev_spa), vd->vdev_guid); cp = vdev_geom_attach_by_guids(vd);
if (cp != NULL) { if (cp != NULL) {
len = strlen(cp->provider->name) + strlen("/dev/") + 1; len = strlen(cp->provider->name) + strlen("/dev/") + 1;
buf = kmem_alloc(len, KM_SLEEP); buf = kmem_alloc(len, KM_SLEEP);
@ -585,7 +661,7 @@ vdev_geom_open_by_path(vdev_t *vd, int check_guid)
pp = g_provider_by_name(vd->vdev_path + sizeof("/dev/") - 1); pp = g_provider_by_name(vd->vdev_path + sizeof("/dev/") - 1);
if (pp != NULL) { if (pp != NULL) {
ZFS_LOG(1, "Found provider by name %s.", vd->vdev_path); ZFS_LOG(1, "Found provider by name %s.", vd->vdev_path);
cp = vdev_geom_attach(pp); cp = vdev_geom_attach(pp, vd);
if (cp != NULL && check_guid && ISP2(pp->sectorsize) && if (cp != NULL && check_guid && ISP2(pp->sectorsize) &&
pp->sectorsize <= VDEV_PAD_SIZE) { pp->sectorsize <= VDEV_PAD_SIZE) {
g_topology_unlock(); g_topology_unlock();
@ -593,7 +669,7 @@ vdev_geom_open_by_path(vdev_t *vd, int check_guid)
g_topology_lock(); g_topology_lock();
if (pguid != spa_guid(vd->vdev_spa) || if (pguid != spa_guid(vd->vdev_spa) ||
vguid != vd->vdev_guid) { vguid != vd->vdev_guid) {
vdev_geom_detach(cp, 0); vdev_geom_close_locked(vd);
cp = NULL; cp = NULL;
ZFS_LOG(1, "guid mismatch for provider %s: " ZFS_LOG(1, "guid mismatch for provider %s: "
"%ju:%ju != %ju:%ju.", vd->vdev_path, "%ju:%ju != %ju:%ju.", vd->vdev_path,
@ -675,7 +751,8 @@ vdev_geom_open(vdev_t *vd, uint64_t *psize, uint64_t *max_psize,
!ISP2(cp->provider->sectorsize)) { !ISP2(cp->provider->sectorsize)) {
ZFS_LOG(1, "Provider %s has unsupported sectorsize.", ZFS_LOG(1, "Provider %s has unsupported sectorsize.",
vd->vdev_path); vd->vdev_path);
vdev_geom_detach(cp, 0);
vdev_geom_close_locked(vd);
error = EINVAL; error = EINVAL;
cp = NULL; cp = NULL;
} else if (cp->acw == 0 && (spa_mode(vd->vdev_spa) & FWRITE) != 0) { } else if (cp->acw == 0 && (spa_mode(vd->vdev_spa) & FWRITE) != 0) {
@ -692,19 +769,17 @@ vdev_geom_open(vdev_t *vd, uint64_t *psize, uint64_t *max_psize,
if (error != 0) { if (error != 0) {
printf("ZFS WARNING: Unable to open %s for writing (error=%d).\n", printf("ZFS WARNING: Unable to open %s for writing (error=%d).\n",
vd->vdev_path, error); vd->vdev_path, error);
vdev_geom_detach(cp, 0); vdev_geom_close_locked(vd);
cp = NULL; cp = NULL;
} }
} }
g_topology_unlock(); g_topology_unlock();
PICKUP_GIANT(); PICKUP_GIANT();
if (cp == NULL) { if (cp == NULL) {
vd->vdev_stat.vs_aux = VDEV_AUX_OPEN_FAILED; vd->vdev_stat.vs_aux = VDEV_AUX_OPEN_FAILED;
return (error); return (error);
} }
cp->private = vd;
vd->vdev_tsd = cp;
pp = cp->provider; pp = cp->provider;
/* /*
@ -727,12 +802,6 @@ vdev_geom_open(vdev_t *vd, uint64_t *psize, uint64_t *max_psize,
*/ */
vd->vdev_nowritecache = B_FALSE; vd->vdev_nowritecache = B_FALSE;
if (vd->vdev_physpath != NULL)
spa_strfree(vd->vdev_physpath);
bufsize = sizeof("/dev/") + strlen(pp->name);
vd->vdev_physpath = kmem_alloc(bufsize, KM_SLEEP);
snprintf(vd->vdev_physpath, bufsize, "/dev/%s", pp->name);
/* /*
* Determine the device's rotation rate. * Determine the device's rotation rate.
*/ */
@ -744,15 +813,12 @@ vdev_geom_open(vdev_t *vd, uint64_t *psize, uint64_t *max_psize,
static void static void
vdev_geom_close(vdev_t *vd) vdev_geom_close(vdev_t *vd)
{ {
struct g_consumer *cp;
cp = vd->vdev_tsd; DROP_GIANT();
if (cp == NULL) g_topology_lock();
return; vdev_geom_close_locked(vd);
vd->vdev_tsd = NULL; g_topology_unlock();
vd->vdev_delayed_close = B_FALSE; PICKUP_GIANT();
cp->private = NULL; /* XXX locking */
g_post_event(vdev_geom_detach, cp, M_WAITOK, NULL);
} }
static void static void

View File

@ -134,6 +134,7 @@ struct sysentvec ia32_freebsd_sysvec = {
.sv_shared_page_len = PAGE_SIZE, .sv_shared_page_len = PAGE_SIZE,
.sv_schedtail = NULL, .sv_schedtail = NULL,
.sv_thread_detach = NULL, .sv_thread_detach = NULL,
.sv_trap = NULL,
}; };
INIT_SYSENTVEC(elf_ia32_sysvec, &ia32_freebsd_sysvec); INIT_SYSENTVEC(elf_ia32_sysvec, &ia32_freebsd_sysvec);

View File

@ -1099,8 +1099,12 @@ linux_get_robust_list(struct thread *td, struct linux_get_robust_list_args *args
ESRCH); ESRCH);
return (ESRCH); return (ESRCH);
} }
if (SV_PROC_ABI(td2->td_proc) != SV_ABI_LINUX) if (SV_PROC_ABI(td2->td_proc) != SV_ABI_LINUX) {
LIN_SDT_PROBE1(futex, linux_get_robust_list, return,
EPERM);
PROC_UNLOCK(td2->td_proc);
return (EPERM); return (EPERM);
}
em = em_find(td2); em = em_find(td2);
KASSERT(em != NULL, ("get_robust_list: emuldata notfound.\n")); KASSERT(em != NULL, ("get_robust_list: emuldata notfound.\n"));

View File

@ -194,6 +194,7 @@ struct sysentvec svr4_sysvec = {
.sv_syscallnames = NULL, .sv_syscallnames = NULL,
.sv_schedtail = NULL, .sv_schedtail = NULL,
.sv_thread_detach = NULL, .sv_thread_detach = NULL,
.sv_trap = NULL,
}; };
const char svr4_emul_path[] = "/compat/svr4"; const char svr4_emul_path[] = "/compat/svr4";

View File

@ -50,6 +50,7 @@ static const char rcsid[] = "@(#)$Id$";
# include <net/netisr.h> # include <net/netisr.h>
#include <net/route.h> #include <net/route.h>
#include <netinet/in.h> #include <netinet/in.h>
#include <netinet/in_fib.h>
#include <netinet/in_var.h> #include <netinet/in_var.h>
#include <netinet/in_systm.h> #include <netinet/in_systm.h>
#include <netinet/ip.h> #include <netinet/ip.h>
@ -712,17 +713,16 @@ ipf_fastroute(m0, mpp, fin, fdp)
{ {
register struct ip *ip, *mhip; register struct ip *ip, *mhip;
register struct mbuf *m = *mpp; register struct mbuf *m = *mpp;
register struct route *ro;
int len, off, error = 0, hlen, code; int len, off, error = 0, hlen, code;
struct ifnet *ifp, *sifp; struct ifnet *ifp, *sifp;
struct sockaddr_in *dst; struct sockaddr_in dst;
struct route iproute; struct nhop4_extended nh4;
int has_nhop = 0;
u_long fibnum = 0;
u_short ip_off; u_short ip_off;
frdest_t node; frdest_t node;
frentry_t *fr; frentry_t *fr;
ro = NULL;
#ifdef M_WRITABLE #ifdef M_WRITABLE
/* /*
* HOT FIX/KLUDGE: * HOT FIX/KLUDGE:
@ -766,11 +766,10 @@ ipf_fastroute(m0, mpp, fin, fdp)
/* /*
* Route packet. * Route packet.
*/ */
ro = &iproute; bzero(&dst, sizeof (dst));
bzero(ro, sizeof (*ro)); dst.sin_family = AF_INET;
dst = (struct sockaddr_in *)&ro->ro_dst; dst.sin_addr = ip->ip_dst;
dst->sin_family = AF_INET; dst.sin_len = sizeof(dst);
dst->sin_addr = ip->ip_dst;
fr = fin->fin_fr; fr = fin->fin_fr;
if ((fr != NULL) && !(fr->fr_flags & FR_KEEPSTATE) && (fdp != NULL) && if ((fr != NULL) && !(fr->fr_flags & FR_KEEPSTATE) && (fdp != NULL) &&
@ -790,25 +789,22 @@ ipf_fastroute(m0, mpp, fin, fdp)
} }
if ((fdp != NULL) && (fdp->fd_ip.s_addr != 0)) if ((fdp != NULL) && (fdp->fd_ip.s_addr != 0))
dst->sin_addr = fdp->fd_ip; dst.sin_addr = fdp->fd_ip;
dst->sin_len = sizeof(*dst); fibnum = M_GETFIB(m0);
in_rtalloc(ro, M_GETFIB(m0)); if (fib4_lookup_nh_ext(fibnum, dst.sin_addr, NHR_REF, 0, &nh4) != 0) {
if ((ifp == NULL) && (ro->ro_rt != NULL))
ifp = ro->ro_rt->rt_ifp;
if ((ro->ro_rt == NULL) || (ifp == NULL)) {
if (in_localaddr(ip->ip_dst)) if (in_localaddr(ip->ip_dst))
error = EHOSTUNREACH; error = EHOSTUNREACH;
else else
error = ENETUNREACH; error = ENETUNREACH;
goto bad; goto bad;
} }
if (ro->ro_rt->rt_flags & RTF_GATEWAY)
dst = (struct sockaddr_in *)ro->ro_rt->rt_gateway; has_nhop = 1;
if (ro->ro_rt) if (ifp == NULL)
counter_u64_add(ro->ro_rt->rt_pksent, 1); ifp = nh4.nh_ifp;
if (nh4.nh_flags & NHF_GATEWAY)
dst.sin_addr = nh4.nh_addr;
/* /*
* For input packets which are being "fastrouted", they won't * For input packets which are being "fastrouted", they won't
@ -852,8 +848,8 @@ ipf_fastroute(m0, mpp, fin, fdp)
if (ntohs(ip->ip_len) <= ifp->if_mtu) { if (ntohs(ip->ip_len) <= ifp->if_mtu) {
if (!ip->ip_sum) if (!ip->ip_sum)
ip->ip_sum = in_cksum(m, hlen); ip->ip_sum = in_cksum(m, hlen);
error = (*ifp->if_output)(ifp, m, (struct sockaddr *)dst, error = (*ifp->if_output)(ifp, m, (struct sockaddr *)&dst,
ro NULL
); );
goto done; goto done;
} }
@ -935,8 +931,8 @@ ipf_fastroute(m0, mpp, fin, fdp)
m->m_act = 0; m->m_act = 0;
if (error == 0) if (error == 0)
error = (*ifp->if_output)(ifp, m, error = (*ifp->if_output)(ifp, m,
(struct sockaddr *)dst, (struct sockaddr *)&dst,
ro NULL
); );
else else
FREE_MB_T(m); FREE_MB_T(m);
@ -948,9 +944,9 @@ ipf_fastroute(m0, mpp, fin, fdp)
else else
ipfmain.ipf_frouteok[1]++; ipfmain.ipf_frouteok[1]++;
if ((ro != NULL) && (ro->ro_rt != NULL)) { if (has_nhop)
RTFREE(ro->ro_rt); fib4_free_nh_ext(fibnum, &nh4);
}
return 0; return 0;
bad: bad:
if (error == EMSGSIZE) { if (error == EMSGSIZE) {
@ -971,18 +967,11 @@ int
ipf_verifysrc(fin) ipf_verifysrc(fin)
fr_info_t *fin; fr_info_t *fin;
{ {
struct sockaddr_in *dst; struct nhop4_basic nh4;
struct route iproute;
bzero((char *)&iproute, sizeof(iproute)); if (fib4_lookup_nh_basic(0, fin->fin_src, 0, 0, &nh4) != 0)
dst = (struct sockaddr_in *)&iproute.ro_dst; return (0);
dst->sin_len = sizeof(*dst); return (fin->fin_ifp == nh4.nh_ifp);
dst->sin_family = AF_INET;
dst->sin_addr = fin->fin_src;
in_rtalloc(&iproute, 0);
if (iproute.ro_rt == NULL)
return 0;
return (fin->fin_ifp == iproute.ro_rt->rt_ifp);
} }

View File

@ -3642,6 +3642,9 @@ setup_intr_handlers(struct adapter *sc)
#ifdef DEV_NETMAP #ifdef DEV_NETMAP
struct sge_nm_rxq *nm_rxq; struct sge_nm_rxq *nm_rxq;
#endif #endif
#ifdef RSS
int nbuckets = rss_getnumbuckets();
#endif
/* /*
* Setup interrupts. * Setup interrupts.
@ -3700,6 +3703,10 @@ setup_intr_handlers(struct adapter *sc)
t4_intr, rxq, s); t4_intr, rxq, s);
if (rc != 0) if (rc != 0)
return (rc); return (rc);
#ifdef RSS
bus_bind_intr(sc->dev, irq->res,
rss_getcpu(q % nbuckets));
#endif
irq++; irq++;
rid++; rid++;
vi->nintr++; vi->nintr++;

View File

@ -205,6 +205,7 @@
* requires ACR[6]. * requires ACR[6].
*/ */
#define com_icr 5 /* index control register (R/W) */ #define com_icr 5 /* index control register (R/W) */
#define REG_ICR com_icr
/* /*
* 16950 register #7. It is the same as com_scr except it has a different * 16950 register #7. It is the same as com_scr except it has a different
@ -220,6 +221,7 @@
*/ */
#define com_acr 0 /* additional control register (R/W) */ #define com_acr 0 /* additional control register (R/W) */
#define REG_ACR com_acr
#define ACR_ASE 0x80 /* ASR/RFL/TFL enable */ #define ACR_ASE 0x80 /* ASR/RFL/TFL enable */
#define ACR_ICRE 0x40 /* ICR enable */ #define ACR_ICRE 0x40 /* ICR enable */
#define ACR_TLE 0x20 /* TTL/RTL enable */ #define ACR_TLE 0x20 /* TTL/RTL enable */

View File

@ -98,6 +98,9 @@ SYSCTL_INT(_kern_iscsi, OID_AUTO, maxtags, CTLFLAG_RWTUN, &maxtags,
static int fail_on_disconnection = 0; static int fail_on_disconnection = 0;
SYSCTL_INT(_kern_iscsi, OID_AUTO, fail_on_disconnection, CTLFLAG_RWTUN, SYSCTL_INT(_kern_iscsi, OID_AUTO, fail_on_disconnection, CTLFLAG_RWTUN,
&fail_on_disconnection, 0, "Destroy CAM SIM on connection failure"); &fail_on_disconnection, 0, "Destroy CAM SIM on connection failure");
static int fail_on_shutdown = 1;
SYSCTL_INT(_kern_iscsi, OID_AUTO, fail_on_shutdown, CTLFLAG_RWTUN,
&fail_on_shutdown, 0, "Fail disconnected sessions on shutdown");
static MALLOC_DEFINE(M_ISCSI, "iSCSI", "iSCSI initiator"); static MALLOC_DEFINE(M_ISCSI, "iSCSI", "iSCSI initiator");
static uma_zone_t iscsi_outstanding_zone; static uma_zone_t iscsi_outstanding_zone;
@ -417,8 +420,6 @@ iscsi_maintenance_thread_terminate(struct iscsi_session *is)
sc = is->is_softc; sc = is->is_softc;
sx_xlock(&sc->sc_lock); sx_xlock(&sc->sc_lock);
TAILQ_REMOVE(&sc->sc_sessions, is, is_next);
sx_xunlock(&sc->sc_lock);
icl_conn_close(is->is_conn); icl_conn_close(is->is_conn);
callout_drain(&is->is_callout); callout_drain(&is->is_callout);
@ -450,6 +451,9 @@ iscsi_maintenance_thread_terminate(struct iscsi_session *is)
#ifdef ICL_KERNEL_PROXY #ifdef ICL_KERNEL_PROXY
cv_destroy(&is->is_login_cv); cv_destroy(&is->is_login_cv);
#endif #endif
TAILQ_REMOVE(&sc->sc_sessions, is, is_next);
sx_xunlock(&sc->sc_lock);
ISCSI_SESSION_DEBUG(is, "terminated"); ISCSI_SESSION_DEBUG(is, "terminated");
free(is, M_ISCSI); free(is, M_ISCSI);
@ -473,12 +477,7 @@ iscsi_maintenance_thread(void *arg)
STAILQ_EMPTY(&is->is_postponed)) STAILQ_EMPTY(&is->is_postponed))
cv_wait(&is->is_maintenance_cv, &is->is_lock); cv_wait(&is->is_maintenance_cv, &is->is_lock);
if (is->is_reconnecting) { /* Terminate supersedes reconnect. */
ISCSI_SESSION_UNLOCK(is);
iscsi_maintenance_thread_reconnect(is);
continue;
}
if (is->is_terminating) { if (is->is_terminating) {
ISCSI_SESSION_UNLOCK(is); ISCSI_SESSION_UNLOCK(is);
iscsi_maintenance_thread_terminate(is); iscsi_maintenance_thread_terminate(is);
@ -486,6 +485,12 @@ iscsi_maintenance_thread(void *arg)
return; return;
} }
if (is->is_reconnecting) {
ISCSI_SESSION_UNLOCK(is);
iscsi_maintenance_thread_reconnect(is);
continue;
}
iscsi_session_send_postponed(is); iscsi_session_send_postponed(is);
ISCSI_SESSION_UNLOCK(is); ISCSI_SESSION_UNLOCK(is);
} }
@ -605,6 +610,11 @@ iscsi_callout(void *context)
return; return;
out: out:
if (is->is_terminating) {
ISCSI_SESSION_UNLOCK(is);
return;
}
ISCSI_SESSION_UNLOCK(is); ISCSI_SESSION_UNLOCK(is);
if (reconnect_needed) if (reconnect_needed)
@ -2326,30 +2336,62 @@ iscsi_poll(struct cam_sim *sim)
} }
static void static void
iscsi_shutdown(struct iscsi_softc *sc) iscsi_terminate_sessions(struct iscsi_softc *sc)
{ {
struct iscsi_session *is; struct iscsi_session *is;
/* sx_slock(&sc->sc_lock);
* Trying to reconnect during system shutdown would lead to hang. TAILQ_FOREACH(is, &sc->sc_sessions, is_next)
*/ iscsi_session_terminate(is);
fail_on_disconnection = 1; while(!TAILQ_EMPTY(&sc->sc_sessions)) {
ISCSI_DEBUG("waiting for sessions to terminate");
cv_wait(&sc->sc_cv, &sc->sc_lock);
}
ISCSI_DEBUG("all sessions terminated");
sx_sunlock(&sc->sc_lock);
}
static void
iscsi_shutdown_pre(struct iscsi_softc *sc)
{
struct iscsi_session *is;
if (!fail_on_shutdown)
return;
/* /*
* If we have any sessions waiting for reconnection, request * If we have any sessions waiting for reconnection, request
* maintenance thread to fail them immediately instead of waiting * maintenance thread to fail them immediately instead of waiting
* for reconnect timeout. * for reconnect timeout.
*
* This prevents LUNs with mounted filesystems that are supported
* by disconnected iSCSI sessions from hanging, however it will
* fail all queued BIOs.
*/ */
ISCSI_DEBUG("forcing failing all disconnected sessions due to shutdown");
fail_on_disconnection = 1;
sx_slock(&sc->sc_lock); sx_slock(&sc->sc_lock);
TAILQ_FOREACH(is, &sc->sc_sessions, is_next) { TAILQ_FOREACH(is, &sc->sc_sessions, is_next) {
ISCSI_SESSION_LOCK(is); ISCSI_SESSION_LOCK(is);
if (is->is_waiting_for_iscsid) if (!is->is_connected) {
ISCSI_SESSION_DEBUG(is, "force failing disconnected session early");
iscsi_session_reconnect(is); iscsi_session_reconnect(is);
}
ISCSI_SESSION_UNLOCK(is); ISCSI_SESSION_UNLOCK(is);
} }
sx_sunlock(&sc->sc_lock); sx_sunlock(&sc->sc_lock);
} }
static void
iscsi_shutdown_post(struct iscsi_softc *sc)
{
ISCSI_DEBUG("removing all sessions due to shutdown");
iscsi_terminate_sessions(sc);
}
static int static int
iscsi_load(void) iscsi_load(void)
{ {
@ -2372,8 +2414,16 @@ iscsi_load(void)
} }
sc->sc_cdev->si_drv1 = sc; sc->sc_cdev->si_drv1 = sc;
sc->sc_shutdown_eh = EVENTHANDLER_REGISTER(shutdown_pre_sync, sc->sc_shutdown_pre_eh = EVENTHANDLER_REGISTER(shutdown_pre_sync,
iscsi_shutdown, sc, SHUTDOWN_PRI_DEFAULT-1); iscsi_shutdown_pre, sc, SHUTDOWN_PRI_FIRST);
/*
* shutdown_post_sync needs to run after filesystem shutdown and before
* CAM shutdown - otherwise when rebooting with an iSCSI session that is
* disconnected but has outstanding requests, dashutdown() will hang on
* cam_periph_runccb().
*/
sc->sc_shutdown_post_eh = EVENTHANDLER_REGISTER(shutdown_post_sync,
iscsi_shutdown_post, sc, SHUTDOWN_PRI_DEFAULT - 1);
return (0); return (0);
} }
@ -2381,7 +2431,6 @@ iscsi_load(void)
static int static int
iscsi_unload(void) iscsi_unload(void)
{ {
struct iscsi_session *is, *tmp;
if (sc->sc_cdev != NULL) { if (sc->sc_cdev != NULL) {
ISCSI_DEBUG("removing device node"); ISCSI_DEBUG("removing device node");
@ -2389,18 +2438,12 @@ iscsi_unload(void)
ISCSI_DEBUG("device node removed"); ISCSI_DEBUG("device node removed");
} }
if (sc->sc_shutdown_eh != NULL) if (sc->sc_shutdown_pre_eh != NULL)
EVENTHANDLER_DEREGISTER(shutdown_pre_sync, sc->sc_shutdown_eh); EVENTHANDLER_DEREGISTER(shutdown_pre_sync, sc->sc_shutdown_pre_eh);
if (sc->sc_shutdown_post_eh != NULL)
EVENTHANDLER_DEREGISTER(shutdown_post_sync, sc->sc_shutdown_post_eh);
sx_slock(&sc->sc_lock); iscsi_terminate_sessions(sc);
TAILQ_FOREACH_SAFE(is, &sc->sc_sessions, is_next, tmp)
iscsi_session_terminate(is);
while(!TAILQ_EMPTY(&sc->sc_sessions)) {
ISCSI_DEBUG("waiting for sessions to terminate");
cv_wait(&sc->sc_cv, &sc->sc_lock);
}
ISCSI_DEBUG("all sessions terminated");
sx_sunlock(&sc->sc_lock);
uma_zdestroy(iscsi_outstanding_zone); uma_zdestroy(iscsi_outstanding_zone);
sx_destroy(&sc->sc_lock); sx_destroy(&sc->sc_lock);

View File

@ -131,7 +131,8 @@ struct iscsi_softc {
TAILQ_HEAD(, iscsi_session) sc_sessions; TAILQ_HEAD(, iscsi_session) sc_sessions;
struct cv sc_cv; struct cv sc_cv;
unsigned int sc_last_session_id; unsigned int sc_last_session_id;
eventhandler_tag sc_shutdown_eh; eventhandler_tag sc_shutdown_pre_eh;
eventhandler_tag sc_shutdown_post_eh;
}; };
#endif /* !ISCSI_H */ #endif /* !ISCSI_H */

View File

@ -42,12 +42,16 @@ __FBSDID("$FreeBSD$");
#include <machine/bus.h> #include <machine/bus.h>
#include <sys/rman.h> #include <sys/rman.h>
#include <dev/ic/ns16550.h>
#include <dev/pci/pcireg.h>
#include <dev/pci/pcivar.h> #include <dev/pci/pcivar.h>
#include <dev/puc/puc_bus.h> #include <dev/puc/puc_bus.h>
#include <dev/puc/puc_cfg.h> #include <dev/puc/puc_cfg.h>
#include <dev/puc/puc_bfe.h> #include <dev/puc/puc_bfe.h>
static puc_config_f puc_config_advantech;
static puc_config_f puc_config_amc; static puc_config_f puc_config_amc;
static puc_config_f puc_config_diva; static puc_config_f puc_config_diva;
static puc_config_f puc_config_exar; static puc_config_f puc_config_exar;
@ -691,10 +695,25 @@ const struct puc_cfg puc_pci_devices[] = {
.config_function = puc_config_exar_pcie .config_function = puc_config_exar_pcie
}, },
/*
* The Advantech PCI-1602 Rev. A use the first two ports of an Oxford
* Semiconductor OXuPCI954. Note these boards have a hardware bug in
* that they drive the RS-422/485 transmitters after power-on until a
* driver initalizes the UARTs.
*/
{ 0x13fe, 0x1600, 0x1602, 0x0002, { 0x13fe, 0x1600, 0x1602, 0x0002,
"Advantech PCI-1602", "Advantech PCI-1602 Rev. A",
DEFAULT_RCLK * 8, DEFAULT_RCLK * 8,
PUC_PORT_2S, 0x10, 0, 8, PUC_PORT_2S, 0x10, 0, 8,
.config_function = puc_config_advantech
},
/* Advantech PCI-1602 Rev. B1/PCI-1603 are also based on OXuPCI952. */
{ 0x13fe, 0xa102, 0x13fe, 0xa102,
"Advantech 2-port PCI (PCI-1602 Rev. B1/PCI-1603)",
DEFAULT_RCLK * 8,
PUC_PORT_2S, 0x10, 4, 0,
.config_function = puc_config_advantech
}, },
{ 0x1407, 0x0100, 0xffff, 0, { 0x1407, 0x0100, 0xffff, 0,
@ -1255,6 +1274,92 @@ const struct puc_cfg puc_pci_devices[] = {
{ 0xffff, 0, 0xffff, 0, NULL, 0 } { 0xffff, 0, 0xffff, 0, NULL, 0 }
}; };
static int
puc_config_advantech(struct puc_softc *sc, enum puc_cfg_cmd cmd, int port,
intptr_t *res __unused)
{
const struct puc_cfg *cfg;
struct resource *cres;
struct puc_bar *bar;
device_t cdev, dev;
bus_size_t off;
int base, crtype, fixed, high, i, oxpcie;
uint8_t acr, func, mask;
if (cmd != PUC_CFG_SETUP)
return (ENXIO);
base = fixed = oxpcie = 0;
crtype = SYS_RES_IOPORT;
acr = mask = 0x0;
func = high = 1;
off = 0x60;
cfg = sc->sc_cfg;
switch (cfg->subvendor) {
case 0x13fe:
switch (cfg->device) {
case 0xa102:
high = 0;
break;
default:
break;
}
default:
break;
}
if (fixed == 1)
goto setup;
dev = sc->sc_dev;
cdev = pci_find_dbsf(pci_get_domain(dev), pci_get_bus(dev),
pci_get_slot(dev), func);
if (cdev == NULL) {
device_printf(dev, "could not find config function\n");
return (ENXIO);
}
i = PCIR_BAR(0);
cres = bus_alloc_resource_any(cdev, crtype, &i, RF_ACTIVE);
if (cres == NULL) {
device_printf(dev, "could not allocate config resource\n");
return (ENXIO);
}
if (oxpcie == 0) {
mask = bus_read_1(cres, off);
if (pci_get_function(dev) == 1)
base = 4;
}
setup:
for (i = 0; i < sc->sc_nports; ++i) {
device_printf(dev, "port %d: ", i);
bar = puc_get_bar(sc, cfg->rid + i * cfg->d_rid);
if (bar == NULL) {
printf("could not get BAR\n");
continue;
}
if (fixed == 0) {
if ((mask & (1 << (base + i))) == 0) {
acr = 0;
printf("RS-232\n");
} else {
acr = (high == 1 ? 0x18 : 0x10);
printf("RS-422/RS-485, active-%s auto-DTR\n",
high == 1 ? "high" : "low");
}
}
bus_write_1(bar->b_res, REG_SPR, REG_ACR);
bus_write_1(bar->b_res, REG_ICR, acr);
}
bus_release_resource(cdev, crtype, rman_get_rid(cres), cres);
return (0);
}
static int static int
puc_config_amc(struct puc_softc *sc __unused, enum puc_cfg_cmd cmd, int port, puc_config_amc(struct puc_softc *sc __unused, enum puc_cfg_cmd cmd, int port,
intptr_t *res) intptr_t *res)
@ -1360,24 +1465,17 @@ puc_config_quatech(struct puc_softc *sc, enum puc_cfg_cmd cmd,
bar = puc_get_bar(sc, cfg->rid); bar = puc_get_bar(sc, cfg->rid);
if (bar == NULL) if (bar == NULL)
return (ENXIO); return (ENXIO);
/* Set DLAB in the LCR register of UART 0. */ bus_write_1(bar->b_res, REG_LCR, LCR_DLAB);
bus_write_1(bar->b_res, 3, 0x80); bus_write_1(bar->b_res, REG_SPR, 0);
/* Write 0 to the SPR register of UART 0. */ v0 = bus_read_1(bar->b_res, REG_SPR);
bus_write_1(bar->b_res, 7, 0); bus_write_1(bar->b_res, REG_SPR, 0x80 + -cfg->clock);
/* Read back the contents of the SPR register of UART 0. */ v1 = bus_read_1(bar->b_res, REG_SPR);
v0 = bus_read_1(bar->b_res, 7); bus_write_1(bar->b_res, REG_LCR, 0);
/* Write a specific value to the SPR register of UART 0. */
bus_write_1(bar->b_res, 7, 0x80 + -cfg->clock);
/* Read back the contents of the SPR register of UART 0. */
v1 = bus_read_1(bar->b_res, 7);
/* Clear DLAB in the LCR register of UART 0. */
bus_write_1(bar->b_res, 3, 0);
/* Save the two values read-back from the SPR register. */
sc->sc_cfg_data = (v0 << 8) | v1; sc->sc_cfg_data = (v0 << 8) | v1;
if (v0 == 0 && v1 == 0x80 + -cfg->clock) { if (v0 == 0 && v1 == 0x80 + -cfg->clock) {
/* /*
* The SPR register echoed the two values written * The SPR register echoed the two values written
* by us. This means that the SPAD jumper is set. * by us. This means that the SPAD jumper is set.
*/ */
device_printf(sc->sc_dev, "warning: extra features " device_printf(sc->sc_dev, "warning: extra features "
"not usable -- SPAD compatibility enabled\n"); "not usable -- SPAD compatibility enabled\n");
@ -1385,7 +1483,7 @@ puc_config_quatech(struct puc_softc *sc, enum puc_cfg_cmd cmd,
} }
if (v0 != 0) { if (v0 != 0) {
/* /*
* The first value doesn't match. This can only mean * The first value doesn't match. This can only mean
* that the SPAD jumper is not set and that a non- * that the SPAD jumper is not set and that a non-
* standard fixed clock multiplier jumper is set. * standard fixed clock multiplier jumper is set.
*/ */
@ -1399,8 +1497,8 @@ puc_config_quatech(struct puc_softc *sc, enum puc_cfg_cmd cmd,
return (0); return (0);
} }
/* /*
* The first value matched, but the second didn't. We know * The first value matched, but the second didn't. We know
* that the SPAD jumper is not set. We also know that the * that the SPAD jumper is not set. We also know that the
* clock rate multiplier is software controlled *and* that * clock rate multiplier is software controlled *and* that
* we just programmed it to the maximum allowed. * we just programmed it to the maximum allowed.
*/ */
@ -1415,8 +1513,8 @@ puc_config_quatech(struct puc_softc *sc, enum puc_cfg_cmd cmd,
/* /*
* XXX With the SPAD jumper applied, there's no * XXX With the SPAD jumper applied, there's no
* easy way of knowing if there's also a clock * easy way of knowing if there's also a clock
* rate multiplier jumper installed. Let's hope * rate multiplier jumper installed. Let's hope
* not... * not ...
*/ */
*res = DEFAULT_RCLK; *res = DEFAULT_RCLK;
} else if (v0 == 0) { } else if (v0 == 0) {
@ -1678,15 +1776,15 @@ puc_config_oxford_pcie(struct puc_softc *sc, enum puc_cfg_cmd cmd, int port,
case PUC_CFG_GET_NPORTS: case PUC_CFG_GET_NPORTS:
/* /*
* Check if we are being called from puc_bfe_attach() * Check if we are being called from puc_bfe_attach()
* or puc_bfe_probe(). If puc_bfe_probe(), we cannot * or puc_bfe_probe(). If puc_bfe_probe(), we cannot
* puc_get_bar(), so we return a value of 16. This has cosmetic * puc_get_bar(), so we return a value of 16. This has
* side-effects at worst; in PUC_CFG_GET_DESC, * cosmetic side-effects at worst; in PUC_CFG_GET_DESC,
* (int)sc->sc_cfg_data will not contain the true number of * sc->sc_cfg_data will not contain the true number of
* ports in PUC_CFG_GET_DESC, but we are not implementing that * ports in PUC_CFG_GET_DESC, but we are not implementing
* call for this device family anyway. * that call for this device family anyway.
* *
* The check is for initialisation of sc->sc_bar[idx], which is * The check is for initialization of sc->sc_bar[idx],
* only done in puc_bfe_attach(). * which is only done in puc_bfe_attach().
*/ */
idx = 0; idx = 0;
do { do {

View File

@ -1683,7 +1683,7 @@ rtwn_tx(struct rtwn_softc *sc, struct mbuf *m, struct ieee80211_node *ni)
txd->txdw5 |= htole32(SM(R92C_TXDW5_DATARATE, 0)); txd->txdw5 |= htole32(SM(R92C_TXDW5_DATARATE, 0));
} }
/* Set sequence number (already little endian). */ /* Set sequence number (already little endian). */
txd->txdseq = *(uint16_t *)wh->i_seq; txd->txdseq = htole16(M_SEQNO_GET(m) % IEEE80211_SEQ_RANGE);
if (!qos) { if (!qos) {
/* Use HW sequence numbering for non-QoS frames. */ /* Use HW sequence numbering for non-QoS frames. */

View File

@ -238,6 +238,7 @@ sfxge_map_mbuf_fast(bus_dma_tag_t tag, bus_dmamap_t map,
#define EFSYS_OPT_FALCON_NIC_CFG_OVERRIDE 0 #define EFSYS_OPT_FALCON_NIC_CFG_OVERRIDE 0
#define EFSYS_OPT_SIENA 1 #define EFSYS_OPT_SIENA 1
#define EFSYS_OPT_HUNTINGTON 1 #define EFSYS_OPT_HUNTINGTON 1
#define EFSYS_OPT_MEDFORD 0
#ifdef DEBUG #ifdef DEBUG
#define EFSYS_OPT_CHECK_REG 1 #define EFSYS_OPT_CHECK_REG 1
#else #else

View File

@ -1634,7 +1634,7 @@ ti_newbuf_jumbo(struct ti_softc *sc, int idx, struct mbuf *m_old)
m[i]->m_data = (void *)sf_buf_kva(sf[i]); m[i]->m_data = (void *)sf_buf_kva(sf[i]);
m[i]->m_len = PAGE_SIZE; m[i]->m_len = PAGE_SIZE;
MEXTADD(m[i], sf_buf_kva(sf[i]), PAGE_SIZE, MEXTADD(m[i], sf_buf_kva(sf[i]), PAGE_SIZE,
sf_buf_mext, (void*)sf_buf_kva(sf[i]), sf[i], sf_mext_free, (void*)sf_buf_kva(sf[i]), sf[i],
0, EXT_DISPOSABLE); 0, EXT_DISPOSABLE);
m[i]->m_next = m[i+1]; m[i]->m_next = m[i+1];
} }
@ -1699,7 +1699,7 @@ ti_newbuf_jumbo(struct ti_softc *sc, int idx, struct mbuf *m_old)
if (m[i]) if (m[i])
m_freem(m[i]); m_freem(m[i]);
if (sf[i]) if (sf[i])
sf_buf_mext((void *)sf_buf_kva(sf[i]), sf[i]); sf_mext_free((void *)sf_buf_kva(sf[i]), sf[i]);
} }
return (ENOBUFS); return (ENOBUFS);
} }

View File

@ -57,6 +57,7 @@ struct ofwfb_softc {
int iso_palette; int iso_palette;
}; };
static void ofwfb_initialize(struct vt_device *vd);
static vd_probe_t ofwfb_probe; static vd_probe_t ofwfb_probe;
static vd_init_t ofwfb_init; static vd_init_t ofwfb_init;
static vd_bitblt_text_t ofwfb_bitblt_text; static vd_bitblt_text_t ofwfb_bitblt_text;
@ -124,6 +125,18 @@ ofwfb_bitblt_bitmap(struct vt_device *vd, const struct vt_window *vw,
uint8_t c[4]; uint8_t c[4];
} ch1, ch2; } ch1, ch2;
#ifdef __powerpc__
/* Deal with unmapped framebuffers */
if (sc->fb_flags & FB_FLAG_NOWRITE) {
if (pmap_bootstrapped) {
sc->fb_flags &= ~FB_FLAG_NOWRITE;
ofwfb_initialize(vd);
} else {
return;
}
}
#endif
fgc = sc->fb_cmap[fg]; fgc = sc->fb_cmap[fg];
bgc = sc->fb_cmap[bg]; bgc = sc->fb_cmap[bg];
b = m = 0; b = m = 0;
@ -271,6 +284,11 @@ ofwfb_initialize(struct vt_device *vd)
cell_t retval; cell_t retval;
uint32_t oldpix; uint32_t oldpix;
sc->fb.fb_cmsize = 16;
if (sc->fb.fb_flags & FB_FLAG_NOWRITE)
return;
/* /*
* Set up the color map * Set up the color map
*/ */
@ -318,8 +336,6 @@ ofwfb_initialize(struct vt_device *vd)
panic("Unknown color space depth %d", sc->fb.fb_bpp); panic("Unknown color space depth %d", sc->fb.fb_bpp);
break; break;
} }
sc->fb.fb_cmsize = 16;
} }
static int static int
@ -466,6 +482,11 @@ ofwfb_init(struct vt_device *vd)
#if defined(__powerpc__) #if defined(__powerpc__)
OF_decode_addr(node, fb_phys, &sc->sc_memt, &sc->fb.fb_vbase); OF_decode_addr(node, fb_phys, &sc->sc_memt, &sc->fb.fb_vbase);
sc->fb.fb_pbase = sc->fb.fb_vbase; /* 1:1 mapped */ sc->fb.fb_pbase = sc->fb.fb_vbase; /* 1:1 mapped */
#ifdef __powerpc64__
/* Real mode under a hypervisor probably doesn't cover FB */
if (!(mfmsr() & (PSL_HV | PSL_DR)))
sc->fb.fb_flags |= FB_FLAG_NOWRITE;
#endif
#else #else
/* No ability to interpret assigned-addresses otherwise */ /* No ability to interpret assigned-addresses otherwise */
return (CN_DEAD); return (CN_DEAD);

View File

@ -102,9 +102,6 @@ ext4_bmapext(struct vnode *vp, int32_t bn, int64_t *bnp, int *runp, int *runb)
fs = ip->i_e2fs; fs = ip->i_e2fs;
lbn = bn; lbn = bn;
/*
* TODO: need to implement read ahead to improve the performance.
*/
if (runp != NULL) if (runp != NULL)
*runp = 0; *runp = 0;
@ -112,15 +109,25 @@ ext4_bmapext(struct vnode *vp, int32_t bn, int64_t *bnp, int *runp, int *runb)
*runb = 0; *runb = 0;
ext4_ext_find_extent(fs, ip, lbn, &path); ext4_ext_find_extent(fs, ip, lbn, &path);
ep = path.ep_ext; if (path.ep_is_sparse) {
if (ep == NULL) *bnp = -1;
ret = EIO; if (runp != NULL)
else { *runp = path.ep_sparse_ext.e_len -
*bnp = fsbtodb(fs, lbn - ep->e_blk + (lbn - path.ep_sparse_ext.e_blk) - 1;
(ep->e_start_lo | (daddr_t)ep->e_start_hi << 32)); } else {
ep = path.ep_ext;
if (ep == NULL)
ret = EIO;
else {
*bnp = fsbtodb(fs, lbn - ep->e_blk +
(ep->e_start_lo | (daddr_t)ep->e_start_hi << 32));
if (*bnp == 0) if (*bnp == 0)
*bnp = -1; *bnp = -1;
if (runp != NULL)
*runp = ep->e_len - (lbn - ep->e_blk) - 1;
}
} }
if (path.ep_bp != NULL) { if (path.ep_bp != NULL) {

View File

@ -66,13 +66,14 @@ static void
ext4_ext_binsearch(struct inode *ip, struct ext4_extent_path *path, daddr_t lbn) ext4_ext_binsearch(struct inode *ip, struct ext4_extent_path *path, daddr_t lbn)
{ {
struct ext4_extent_header *ehp = path->ep_header; struct ext4_extent_header *ehp = path->ep_header;
struct ext4_extent *l, *r, *m; struct ext4_extent *first, *l, *r, *m;
if (ehp->eh_ecount == 0) if (ehp->eh_ecount == 0)
return; return;
l = (struct ext4_extent *)(char *)(ehp + 1); first = (struct ext4_extent *)(char *)(ehp + 1);
r = (struct ext4_extent *)(char *)(ehp + 1) + ehp->eh_ecount - 1; l = first;
r = first + ehp->eh_ecount - 1;
while (l <= r) { while (l <= r) {
m = l + (r - l) / 2; m = l + (r - l) / 2;
if (lbn < m->e_blk) if (lbn < m->e_blk)
@ -81,7 +82,25 @@ ext4_ext_binsearch(struct inode *ip, struct ext4_extent_path *path, daddr_t lbn)
l = m + 1; l = m + 1;
} }
if (l == first) {
path->ep_sparse_ext.e_blk = lbn;
path->ep_sparse_ext.e_len = first->e_blk - lbn;
path->ep_sparse_ext.e_start_hi = 0;
path->ep_sparse_ext.e_start_lo = 0;
path->ep_is_sparse = 1;
return;
}
path->ep_ext = l - 1; path->ep_ext = l - 1;
if (path->ep_ext->e_blk + path->ep_ext->e_len <= lbn) {
path->ep_sparse_ext.e_blk = lbn;
if (l <= (first + ehp->eh_ecount - 1))
path->ep_sparse_ext.e_len = l->e_blk - lbn;
else // XXX: where does it end?
path->ep_sparse_ext.e_len = 1;
path->ep_sparse_ext.e_start_hi = 0;
path->ep_sparse_ext.e_start_lo = 0;
path->ep_is_sparse = 1;
}
} }
/* /*
@ -169,6 +188,7 @@ ext4_ext_find_extent(struct m_ext2fs *fs, struct inode *ip,
path->ep_depth = i; path->ep_depth = i;
path->ep_ext = NULL; path->ep_ext = NULL;
path->ep_index = NULL; path->ep_index = NULL;
path->ep_is_sparse = 0;
ext4_ext_binsearch(ip, path, lbn); ext4_ext_binsearch(ip, path, lbn);
return (path); return (path);

View File

@ -84,7 +84,11 @@ struct ext4_extent_cache {
struct ext4_extent_path { struct ext4_extent_path {
uint16_t ep_depth; uint16_t ep_depth;
struct buf *ep_bp; struct buf *ep_bp;
struct ext4_extent *ep_ext; int ep_is_sparse;
union {
struct ext4_extent ep_sparse_ext;
struct ext4_extent *ep_ext;
};
struct ext4_extent_index *ep_index; struct ext4_extent_index *ep_index;
struct ext4_extent_header *ep_header; struct ext4_extent_header *ep_header;
}; };

View File

@ -590,7 +590,7 @@ ext2_mountfs(struct vnode *devvp, struct mount *mp)
* while Linux keeps the super block in a locked buffer. * while Linux keeps the super block in a locked buffer.
*/ */
ump->um_e2fs = malloc(sizeof(struct m_ext2fs), ump->um_e2fs = malloc(sizeof(struct m_ext2fs),
M_EXT2MNT, M_WAITOK); M_EXT2MNT, M_WAITOK | M_ZERO);
ump->um_e2fs->e2fs = malloc(sizeof(struct ext2fs), ump->um_e2fs->e2fs = malloc(sizeof(struct ext2fs),
M_EXT2MNT, M_WAITOK); M_EXT2MNT, M_WAITOK);
mtx_init(EXT2_MTX(ump), "EXT2FS", "EXT2FS Lock", MTX_DEF); mtx_init(EXT2_MTX(ump), "EXT2FS", "EXT2FS Lock", MTX_DEF);

View File

@ -1787,6 +1787,7 @@ ext2_ioctl(struct vop_ioctl_args *ap)
static int static int
ext4_ext_read(struct vop_read_args *ap) ext4_ext_read(struct vop_read_args *ap)
{ {
static unsigned char zeroes[EXT2_MAX_BLOCK_SIZE];
struct vnode *vp; struct vnode *vp;
struct inode *ip; struct inode *ip;
struct uio *uio; struct uio *uio;
@ -1831,11 +1832,15 @@ ext4_ext_read(struct vop_read_args *ap)
switch (cache_type) { switch (cache_type) {
case EXT4_EXT_CACHE_NO: case EXT4_EXT_CACHE_NO:
ext4_ext_find_extent(fs, ip, lbn, &path); ext4_ext_find_extent(fs, ip, lbn, &path);
ep = path.ep_ext; if (path.ep_is_sparse)
ep = &path.ep_sparse_ext;
else
ep = path.ep_ext;
if (ep == NULL) if (ep == NULL)
return (EIO); return (EIO);
ext4_ext_put_cache(ip, ep, EXT4_EXT_CACHE_IN); ext4_ext_put_cache(ip, ep,
path.ep_is_sparse ? EXT4_EXT_CACHE_GAP : EXT4_EXT_CACHE_IN);
newblk = lbn - ep->e_blk + (ep->e_start_lo | newblk = lbn - ep->e_blk + (ep->e_start_lo |
(daddr_t)ep->e_start_hi << 32); (daddr_t)ep->e_start_hi << 32);
@ -1848,7 +1853,7 @@ ext4_ext_read(struct vop_read_args *ap)
case EXT4_EXT_CACHE_GAP: case EXT4_EXT_CACHE_GAP:
/* block has not been allocated yet */ /* block has not been allocated yet */
return (0); break;
case EXT4_EXT_CACHE_IN: case EXT4_EXT_CACHE_IN:
newblk = lbn - nex.e_blk + (nex.e_start_lo | newblk = lbn - nex.e_blk + (nex.e_start_lo |
@ -1859,24 +1864,34 @@ ext4_ext_read(struct vop_read_args *ap)
panic("%s: invalid cache type", __func__); panic("%s: invalid cache type", __func__);
} }
error = bread(ip->i_devvp, fsbtodb(fs, newblk), size, NOCRED, &bp); if (cache_type == EXT4_EXT_CACHE_GAP ||
if (error) { (cache_type == EXT4_EXT_CACHE_NO && path.ep_is_sparse)) {
brelse(bp); if (xfersize > sizeof(zeroes))
return (error); xfersize = sizeof(zeroes);
} error = uiomove(zeroes, xfersize, uio);
if (error)
size -= bp->b_resid; return (error);
if (size < xfersize) { } else {
if (size == 0) { error = bread(ip->i_devvp, fsbtodb(fs, newblk), size,
bqrelse(bp); NOCRED, &bp);
break; if (error) {
brelse(bp);
return (error);
} }
xfersize = size;
size -= bp->b_resid;
if (size < xfersize) {
if (size == 0) {
bqrelse(bp);
break;
}
xfersize = size;
}
error = uiomove(bp->b_data + blkoffset, xfersize, uio);
bqrelse(bp);
if (error)
return (error);
} }
error = uiomove(bp->b_data + blkoffset, (int)xfersize, uio);
bqrelse(bp);
if (error)
return (error);
} }
return (0); return (0);

View File

@ -333,18 +333,18 @@ smbfs_smb_flush(struct smbnode *np, struct smb_cred *scred)
} }
int int
smbfs_smb_setfsize(struct smbnode *np, int newsize, struct smb_cred *scred) smbfs_smb_setfsize(struct smbnode *np, int64_t newsize, struct smb_cred *scred)
{ {
struct smb_share *ssp = np->n_mount->sm_share; struct smb_share *ssp = np->n_mount->sm_share;
struct smb_rq *rqp; struct smb_rq *rqp;
struct mbchain *mbp; struct mbchain *mbp;
int error; int error;
if (!smbfs_smb_seteof(np, (int64_t) newsize, scred)) { if (!smbfs_smb_seteof(np, newsize, scred)) {
np->n_flag |= NFLUSHWIRE; np->n_flag |= NFLUSHWIRE;
return (0); return (0);
} }
/* XXX: We should use SMB_COM_WRITE_ANDX to support large offsets */
error = smb_rq_alloc(SSTOCP(ssp), SMB_COM_WRITE, scred, &rqp); error = smb_rq_alloc(SSTOCP(ssp), SMB_COM_WRITE, scred, &rqp);
if (error) if (error)
return (error); return (error);
@ -352,7 +352,7 @@ smbfs_smb_setfsize(struct smbnode *np, int newsize, struct smb_cred *scred)
smb_rq_wstart(rqp); smb_rq_wstart(rqp);
mb_put_mem(mbp, (caddr_t)&np->n_fid, 2, MB_MSYSTEM); mb_put_mem(mbp, (caddr_t)&np->n_fid, 2, MB_MSYSTEM);
mb_put_uint16le(mbp, 0); mb_put_uint16le(mbp, 0);
mb_put_uint32le(mbp, newsize); mb_put_uint32le(mbp, (uint32_t)newsize);
mb_put_uint16le(mbp, 0); mb_put_uint16le(mbp, 0);
smb_rq_wend(rqp); smb_rq_wend(rqp);
smb_rq_bstart(rqp); smb_rq_bstart(rqp);

View File

@ -128,7 +128,8 @@ int smbfs_smb_lock(struct smbnode *np, int op, caddr_t id,
off_t start, off_t end, struct smb_cred *scred); off_t start, off_t end, struct smb_cred *scred);
int smbfs_smb_statfs(struct smb_share *ssp, struct statfs *sbp, int smbfs_smb_statfs(struct smb_share *ssp, struct statfs *sbp,
struct smb_cred *scred); struct smb_cred *scred);
int smbfs_smb_setfsize(struct smbnode *np, int newsize, struct smb_cred *scred); int smbfs_smb_setfsize(struct smbnode *np, int64_t newsize,
struct smb_cred *scred);
int smbfs_smb_query_info(struct smbnode *np, const char *name, int len, int smbfs_smb_query_info(struct smbnode *np, const char *name, int len,
struct smbfattr *fap, struct smb_cred *scred); struct smbfattr *fap, struct smb_cred *scred);

View File

@ -358,7 +358,8 @@ smbfs_setattr(ap)
doclose = 1; doclose = 1;
} }
if (error == 0) if (error == 0)
error = smbfs_smb_setfsize(np, vap->va_size, scred); error = smbfs_smb_setfsize(np,
(int64_t)vap->va_size, scred);
if (doclose) if (doclose)
smbfs_smb_close(ssp, np->n_fid, NULL, scred); smbfs_smb_close(ssp, np->n_fid, NULL, scred);
if (error) { if (error) {

View File

@ -87,6 +87,7 @@ struct sysentvec elf32_freebsd_sysvec = {
.sv_shared_page_len = PAGE_SIZE, .sv_shared_page_len = PAGE_SIZE,
.sv_schedtail = NULL, .sv_schedtail = NULL,
.sv_thread_detach = NULL, .sv_thread_detach = NULL,
.sv_trap = NULL,
}; };
INIT_SYSENTVEC(elf32_sysvec, &elf32_freebsd_sysvec); INIT_SYSENTVEC(elf32_sysvec, &elf32_freebsd_sysvec);

View File

@ -90,6 +90,7 @@ struct sysentvec ibcs2_svr3_sysvec = {
.sv_syscallnames = NULL, .sv_syscallnames = NULL,
.sv_schedtail = NULL, .sv_schedtail = NULL,
.sv_thread_detach = NULL, .sv_thread_detach = NULL,
.sv_trap = NULL,
}; };
static int static int

View File

@ -985,6 +985,7 @@ struct sysentvec linux_sysvec = {
.sv_shared_page_len = PAGE_SIZE, .sv_shared_page_len = PAGE_SIZE,
.sv_schedtail = linux_schedtail, .sv_schedtail = linux_schedtail,
.sv_thread_detach = linux_thread_detach, .sv_thread_detach = linux_thread_detach,
.sv_trap = NULL,
}; };
INIT_SYSENTVEC(aout_sysvec, &linux_sysvec); INIT_SYSENTVEC(aout_sysvec, &linux_sysvec);
@ -1021,6 +1022,7 @@ struct sysentvec elf_linux_sysvec = {
.sv_shared_page_len = PAGE_SIZE, .sv_shared_page_len = PAGE_SIZE,
.sv_schedtail = linux_schedtail, .sv_schedtail = linux_schedtail,
.sv_thread_detach = linux_thread_detach, .sv_thread_detach = linux_thread_detach,
.sv_trap = NULL,
}; };
static void static void

View File

@ -97,6 +97,7 @@ struct sysentvec aout_sysvec = {
.sv_syscallnames = syscallnames, .sv_syscallnames = syscallnames,
.sv_schedtail = NULL, .sv_schedtail = NULL,
.sv_thread_detach = NULL, .sv_thread_detach = NULL,
.sv_trap = NULL,
}; };
#elif defined(__amd64__) #elif defined(__amd64__)

View File

@ -414,6 +414,7 @@ struct sysentvec null_sysvec = {
.sv_syscallnames = NULL, .sv_syscallnames = NULL,
.sv_schedtail = NULL, .sv_schedtail = NULL,
.sv_thread_detach = NULL, .sv_thread_detach = NULL,
.sv_trap = NULL,
}; };
/* /*

View File

@ -31,6 +31,7 @@ __FBSDID("$FreeBSD$");
#include <sys/param.h> #include <sys/param.h>
#include <sys/systm.h> #include <sys/systm.h>
#include <sys/limits.h>
#include <sys/lock.h> #include <sys/lock.h>
#include <sys/mutex.h> #include <sys/mutex.h>
#include <sys/proc.h> #include <sys/proc.h>
@ -46,6 +47,17 @@ __FBSDID("$FreeBSD$");
#include <sys/ktrace.h> #include <sys/ktrace.h>
#endif #endif
/*
* A bound below which cv_waiters is valid. Once cv_waiters reaches this bound,
* cv_signal must manually check the wait queue for threads.
*/
#define CV_WAITERS_BOUND INT_MAX
#define CV_WAITERS_INC(cvp) do { \
if ((cvp)->cv_waiters < CV_WAITERS_BOUND) \
(cvp)->cv_waiters++; \
} while (0)
/* /*
* Common sanity checks for cv_wait* functions. * Common sanity checks for cv_wait* functions.
*/ */
@ -122,7 +134,7 @@ _cv_wait(struct cv *cvp, struct lock_object *lock)
sleepq_lock(cvp); sleepq_lock(cvp);
cvp->cv_waiters++; CV_WAITERS_INC(cvp);
if (lock == &Giant.lock_object) if (lock == &Giant.lock_object)
mtx_assert(&Giant, MA_OWNED); mtx_assert(&Giant, MA_OWNED);
DROP_GIANT(); DROP_GIANT();
@ -184,7 +196,7 @@ _cv_wait_unlock(struct cv *cvp, struct lock_object *lock)
sleepq_lock(cvp); sleepq_lock(cvp);
cvp->cv_waiters++; CV_WAITERS_INC(cvp);
DROP_GIANT(); DROP_GIANT();
sleepq_add(cvp, lock, cvp->cv_description, SLEEPQ_CONDVAR, 0); sleepq_add(cvp, lock, cvp->cv_description, SLEEPQ_CONDVAR, 0);
@ -240,7 +252,7 @@ _cv_wait_sig(struct cv *cvp, struct lock_object *lock)
sleepq_lock(cvp); sleepq_lock(cvp);
cvp->cv_waiters++; CV_WAITERS_INC(cvp);
if (lock == &Giant.lock_object) if (lock == &Giant.lock_object)
mtx_assert(&Giant, MA_OWNED); mtx_assert(&Giant, MA_OWNED);
DROP_GIANT(); DROP_GIANT();
@ -307,7 +319,7 @@ _cv_timedwait_sbt(struct cv *cvp, struct lock_object *lock, sbintime_t sbt,
sleepq_lock(cvp); sleepq_lock(cvp);
cvp->cv_waiters++; CV_WAITERS_INC(cvp);
if (lock == &Giant.lock_object) if (lock == &Giant.lock_object)
mtx_assert(&Giant, MA_OWNED); mtx_assert(&Giant, MA_OWNED);
DROP_GIANT(); DROP_GIANT();
@ -376,7 +388,7 @@ _cv_timedwait_sig_sbt(struct cv *cvp, struct lock_object *lock,
sleepq_lock(cvp); sleepq_lock(cvp);
cvp->cv_waiters++; CV_WAITERS_INC(cvp);
if (lock == &Giant.lock_object) if (lock == &Giant.lock_object)
mtx_assert(&Giant, MA_OWNED); mtx_assert(&Giant, MA_OWNED);
DROP_GIANT(); DROP_GIANT();
@ -422,8 +434,15 @@ cv_signal(struct cv *cvp)
wakeup_swapper = 0; wakeup_swapper = 0;
sleepq_lock(cvp); sleepq_lock(cvp);
if (cvp->cv_waiters > 0) { if (cvp->cv_waiters > 0) {
cvp->cv_waiters--; if (cvp->cv_waiters == CV_WAITERS_BOUND &&
wakeup_swapper = sleepq_signal(cvp, SLEEPQ_CONDVAR, 0, 0); sleepq_lookup(cvp) == NULL) {
cvp->cv_waiters = 0;
} else {
if (cvp->cv_waiters < CV_WAITERS_BOUND)
cvp->cv_waiters--;
wakeup_swapper = sleepq_signal(cvp, SLEEPQ_CONDVAR, 0,
0);
}
} }
sleepq_release(cvp); sleepq_release(cvp);
if (wakeup_swapper) if (wakeup_swapper)

View File

@ -338,6 +338,9 @@ mb_free_ext(struct mbuf *m)
case EXT_SFBUF: case EXT_SFBUF:
sf_ext_free(m->m_ext.ext_arg1, m->m_ext.ext_arg2); sf_ext_free(m->m_ext.ext_arg1, m->m_ext.ext_arg2);
break; break;
case EXT_SFBUF_NOCACHE:
sf_ext_free_nocache(m->m_ext.ext_arg1, m->m_ext.ext_arg2);
break;
default: default:
KASSERT(m->m_ext.ext_cnt != NULL, KASSERT(m->m_ext.ext_cnt != NULL,
("%s: no refcounting pointer on %p", __func__, m)); ("%s: no refcounting pointer on %p", __func__, m));
@ -404,6 +407,7 @@ mb_dupcl(struct mbuf *n, const struct mbuf *m)
switch (m->m_ext.ext_type) { switch (m->m_ext.ext_type) {
case EXT_SFBUF: case EXT_SFBUF:
case EXT_SFBUF_NOCACHE:
sf_ext_ref(m->m_ext.ext_arg1, m->m_ext.ext_arg2); sf_ext_ref(m->m_ext.ext_arg1, m->m_ext.ext_arg2);
break; break;
default: default:

View File

@ -68,6 +68,23 @@ static u_long sb_efficiency = 8; /* parameter for sbreserve() */
static struct mbuf *sbcut_internal(struct sockbuf *sb, int len); static struct mbuf *sbcut_internal(struct sockbuf *sb, int len);
static void sbflush_internal(struct sockbuf *sb); static void sbflush_internal(struct sockbuf *sb);
/*
* Our own version of m_clrprotoflags(), that can preserve M_NOTREADY.
*/
static void
sbm_clrprotoflags(struct mbuf *m, int flags)
{
int mask;
mask = ~M_PROTOFLAGS;
if (flags & PRUS_NOTREADY)
mask |= M_NOTREADY;
while (m) {
m->m_flags &= mask;
m = m->m_next;
}
}
/* /*
* Mark ready "count" mbufs starting with "m". * Mark ready "count" mbufs starting with "m".
*/ */
@ -569,7 +586,7 @@ sblastmbufchk(struct sockbuf *sb, const char *file, int line)
* are discarded and mbufs are compacted where possible. * are discarded and mbufs are compacted where possible.
*/ */
void void
sbappend_locked(struct sockbuf *sb, struct mbuf *m) sbappend_locked(struct sockbuf *sb, struct mbuf *m, int flags)
{ {
struct mbuf *n; struct mbuf *n;
@ -577,7 +594,7 @@ sbappend_locked(struct sockbuf *sb, struct mbuf *m)
if (m == 0) if (m == 0)
return; return;
m_clrprotoflags(m); sbm_clrprotoflags(m, flags);
SBLASTRECORDCHK(sb); SBLASTRECORDCHK(sb);
n = sb->sb_mb; n = sb->sb_mb;
if (n) { if (n) {
@ -620,11 +637,11 @@ sbappend_locked(struct sockbuf *sb, struct mbuf *m)
* are discarded and mbufs are compacted where possible. * are discarded and mbufs are compacted where possible.
*/ */
void void
sbappend(struct sockbuf *sb, struct mbuf *m) sbappend(struct sockbuf *sb, struct mbuf *m, int flags)
{ {
SOCKBUF_LOCK(sb); SOCKBUF_LOCK(sb);
sbappend_locked(sb, m); sbappend_locked(sb, m, flags);
SOCKBUF_UNLOCK(sb); SOCKBUF_UNLOCK(sb);
} }

View File

@ -113,15 +113,6 @@ static int getpeername1(struct thread *td, struct getpeername_args *uap,
counter_u64_t sfstat[sizeof(struct sfstat) / sizeof(uint64_t)]; counter_u64_t sfstat[sizeof(struct sfstat) / sizeof(uint64_t)];
/*
* sendfile(2)-related variables and associated sysctls
*/
static SYSCTL_NODE(_kern_ipc, OID_AUTO, sendfile, CTLFLAG_RW, 0,
"sendfile(2) tunables");
static int sfreadahead = 1;
SYSCTL_INT(_kern_ipc_sendfile, OID_AUTO, readahead, CTLFLAG_RW,
&sfreadahead, 0, "Number of sendfile(2) read-ahead MAXBSIZE blocks");
static void static void
sfstat_init(const void *unused) sfstat_init(const void *unused)
{ {
@ -1858,13 +1849,12 @@ sf_ext_free(void *arg1, void *arg2)
sf_buf_free(sf); sf_buf_free(sf);
vm_page_lock(pg); vm_page_lock(pg);
vm_page_unwire(pg, PQ_INACTIVE);
/* /*
* Check for the object going away on us. This can * Check for the object going away on us. This can
* happen since we don't hold a reference to it. * happen since we don't hold a reference to it.
* If so, we're responsible for freeing the page. * If so, we're responsible for freeing the page.
*/ */
if (pg->wire_count == 0 && pg->object == NULL) if (vm_page_unwire(pg, PQ_INACTIVE) && pg->object == NULL)
vm_page_free(pg); vm_page_free(pg);
vm_page_unlock(pg); vm_page_unlock(pg);
@ -1877,6 +1867,43 @@ sf_ext_free(void *arg1, void *arg2)
} }
} }
/*
* Same as above, but forces the page to be detached from the object
* and go into free pool.
*/
void
sf_ext_free_nocache(void *arg1, void *arg2)
{
struct sf_buf *sf = arg1;
struct sendfile_sync *sfs = arg2;
vm_page_t pg = sf_buf_page(sf);
sf_buf_free(sf);
vm_page_lock(pg);
if (vm_page_unwire(pg, PQ_NONE)) {
vm_object_t obj;
/* Try to free the page, but only if it is cheap to. */
if ((obj = pg->object) == NULL)
vm_page_free(pg);
else if (!vm_page_xbusied(pg) && VM_OBJECT_TRYWLOCK(obj)) {
vm_page_free(pg);
VM_OBJECT_WUNLOCK(obj);
} else
vm_page_deactivate(pg);
}
vm_page_unlock(pg);
if (sfs != NULL) {
mtx_lock(&sfs->mtx);
KASSERT(sfs->count > 0, ("Sendfile sync botchup count == 0"));
if (--sfs->count == 0)
cv_signal(&sfs->cv);
mtx_unlock(&sfs->mtx);
}
}
/* /*
* sendfile(2) * sendfile(2)
* *
@ -1974,103 +2001,252 @@ freebsd4_sendfile(struct thread *td, struct freebsd4_sendfile_args *uap)
} }
#endif /* COMPAT_FREEBSD4 */ #endif /* COMPAT_FREEBSD4 */
static int /*
sendfile_readpage(vm_object_t obj, struct vnode *vp, int nd, * How much data to put into page i of n.
off_t off, int xfsize, int bsize, struct thread *td, vm_page_t *res) * Only first and last pages are special.
*/
static inline off_t
xfsize(int i, int n, off_t off, off_t len)
{ {
vm_page_t m;
vm_pindex_t pindex;
ssize_t resid;
int error, readahead, rv;
pindex = OFF_TO_IDX(off); if (i == 0)
VM_OBJECT_WLOCK(obj); return (omin(PAGE_SIZE - (off & PAGE_MASK), len));
m = vm_page_grab(obj, pindex, (vp != NULL ? VM_ALLOC_NOBUSY |
VM_ALLOC_IGN_SBUSY : 0) | VM_ALLOC_WIRED | VM_ALLOC_NORMAL);
/* if (i == n - 1 && ((off + len) & PAGE_MASK) > 0)
* Check if page is valid for what we need, otherwise initiate I/O. return ((off + len) & PAGE_MASK);
*
* The non-zero nd argument prevents disk I/O, instead we return (PAGE_SIZE);
* return the caller what he specified in nd. In particular, }
* if we already turned some pages into mbufs, nd == EAGAIN
* and the main function send them the pages before we come /*
* here again and block. * Offset within object for i page.
*/ */
if (m->valid != 0 && vm_page_is_valid(m, off & PAGE_MASK, xfsize)) { static inline vm_offset_t
if (vp == NULL) vmoff(int i, off_t off)
vm_page_xunbusy(m); {
VM_OBJECT_WUNLOCK(obj);
*res = m; if (i == 0)
return (0); return ((vm_offset_t)off);
} else if (nd != 0) {
if (vp == NULL) return (trunc_page(off + i * PAGE_SIZE));
vm_page_xunbusy(m); }
error = nd;
goto free_page; /*
* Pretend as if we don't have enough space, subtract xfsize() of
* all pages that failed.
*/
static inline void
fixspace(int old, int new, off_t off, int *space)
{
KASSERT(old > new, ("%s: old %d new %d", __func__, old, new));
/* Subtract last one. */
*space -= xfsize(old - 1, old, off, *space);
old--;
if (new == old)
/* There was only one page. */
return;
/* Subtract first one. */
if (new == 0) {
*space -= xfsize(0, old, off, *space);
new++;
} }
/* /* Rest of pages are full sized. */
* Get the page from backing store. *space -= (old - new) * PAGE_SIZE;
*/
error = 0; KASSERT(*space >= 0, ("%s: space went backwards", __func__));
if (vp != NULL) { }
VM_OBJECT_WUNLOCK(obj);
readahead = sfreadahead * MAXBSIZE; /*
* Structure describing a single sendfile(2) I/O, which may consist of
* several underlying pager I/Os.
*
* The syscall context allocates the structure and initializes 'nios'
* to 1. As sendfile_swapin() runs through pages and starts asynchronous
* paging operations, it increments 'nios'.
*
* Every I/O completion calls sf_iodone(), which decrements the 'nios', and
* the syscall also calls sf_iodone() after allocating all mbufs, linking them
* and sending to socket. Whoever reaches zero 'nios' is responsible to
* call pru_ready on the socket, to notify it of readyness of the data.
*/
struct sf_io {
volatile u_int nios;
u_int error;
int npages;
struct file *sock_fp;
struct mbuf *m;
vm_page_t pa[];
};
static void
sf_iodone(void *arg, vm_page_t *pg, int count, int error)
{
struct sf_io *sfio = arg;
struct socket *so;
for (int i = 0; i < count; i++)
vm_page_xunbusy(pg[i]);
if (error)
sfio->error = error;
if (!refcount_release(&sfio->nios))
return;
so = sfio->sock_fp->f_data;
if (sfio->error) {
struct mbuf *m;
/* /*
* Use vn_rdwr() instead of the pager interface for * I/O operation failed. The state of data in the socket
* the vnode, to allow the read-ahead. * is now inconsistent, and all what we can do is to tear
* it down. Protocol abort method would tear down protocol
* state, free all ready mbufs and detach not ready ones.
* We will free the mbufs corresponding to this I/O manually.
* *
* XXXMAC: Because we don't have fp->f_cred here, we * The socket would be marked with EIO and made available
* pass in NOCRED. This is probably wrong, but is * for read, so that application receives EIO on next
* consistent with our original implementation. * syscall and eventually closes the socket.
*/ */
error = vn_rdwr(UIO_READ, vp, NULL, readahead, trunc_page(off), so->so_proto->pr_usrreqs->pru_abort(so);
UIO_NOCOPY, IO_NODELOCKED | IO_VMIO | ((readahead / so->so_error = EIO;
bsize) << IO_SEQSHIFT), td->td_ucred, NOCRED, &resid, td);
SFSTAT_INC(sf_iocnt); m = sfio->m;
VM_OBJECT_WLOCK(obj); for (int i = 0; i < sfio->npages; i++)
m = m_free(m);
} else { } else {
if (vm_pager_has_page(obj, pindex, NULL, NULL)) { CURVNET_SET(so->so_vnet);
rv = vm_pager_get_pages(obj, &m, 1, NULL, NULL); (void )(so->so_proto->pr_usrreqs->pru_ready)(so, sfio->m,
SFSTAT_INC(sf_iocnt); sfio->npages);
if (rv != VM_PAGER_OK) { CURVNET_RESTORE();
vm_page_lock(m);
vm_page_free(m);
vm_page_unlock(m);
m = NULL;
error = EIO;
}
} else {
pmap_zero_page(m);
m->valid = VM_PAGE_BITS_ALL;
m->dirty = 0;
}
if (m != NULL)
vm_page_xunbusy(m);
} }
if (error == 0) {
*res = m; /* XXXGL: curthread */
} else if (m != NULL) { fdrop(sfio->sock_fp, curthread);
free_page: free(sfio, M_TEMP);
vm_page_lock(m); }
vm_page_unwire(m, PQ_INACTIVE);
/*
* Iterate through pages vector and request paging for non-valid pages.
*/
static int
sendfile_swapin(vm_object_t obj, struct sf_io *sfio, off_t off, off_t len,
int npages, int rhpages, int flags)
{
vm_page_t *pa = sfio->pa;
int nios;
nios = 0;
flags = (flags & SF_NODISKIO) ? VM_ALLOC_NOWAIT : 0;
/*
* First grab all the pages and wire them. Note that we grab
* only required pages. Readahead pages are dealt with later.
*/
VM_OBJECT_WLOCK(obj);
for (int i = 0; i < npages; i++) {
pa[i] = vm_page_grab(obj, OFF_TO_IDX(vmoff(i, off)),
VM_ALLOC_WIRED | VM_ALLOC_NORMAL | flags);
if (pa[i] == NULL) {
npages = i;
rhpages = 0;
break;
}
}
for (int i = 0; i < npages;) {
int j, a, count, rv;
/* Skip valid pages. */
if (vm_page_is_valid(pa[i], vmoff(i, off) & PAGE_MASK,
xfsize(i, npages, off, len))) {
vm_page_xunbusy(pa[i]);
SFSTAT_INC(sf_pages_valid);
i++;
continue;
}
/* /*
* See if anyone else might know about this page. If * Now 'i' points to first invalid page, iterate further
* not and it is not valid, then free it. * to make 'j' point at first valid after a bunch of
* invalid ones.
*/ */
if (m->wire_count == 0 && m->valid == 0 && !vm_page_busied(m)) for (j = i + 1; j < npages; j++)
vm_page_free(m); if (vm_page_is_valid(pa[j], vmoff(j, off) & PAGE_MASK,
vm_page_unlock(m); xfsize(j, npages, off, len))) {
SFSTAT_INC(sf_pages_valid);
break;
}
/*
* Now we got region of invalid pages between 'i' and 'j'.
* Check that they belong to pager. They may not be there,
* which is a regular situation for shmem pager. For vnode
* pager this happens only in case of sparse file.
*
* Important feature of vm_pager_has_page() is the hint
* stored in 'a', about how many pages we can pagein after
* this page in a single I/O.
*/
while (!vm_pager_has_page(obj, OFF_TO_IDX(vmoff(i, off)),
NULL, &a) && i < j) {
pmap_zero_page(pa[i]);
pa[i]->valid = VM_PAGE_BITS_ALL;
pa[i]->dirty = 0;
vm_page_xunbusy(pa[i]);
i++;
}
if (i == j)
continue;
/*
* We want to pagein as many pages as possible, limited only
* by the 'a' hint and actual request.
*
* We should not pagein into already valid page, thus if
* 'j' didn't reach last page, trim by that page.
*
* When the pagein fulfils the request, also specify readahead.
*/
if (j < npages)
a = min(a, j - i - 1);
count = min(a + 1, npages - i);
refcount_acquire(&sfio->nios);
rv = vm_pager_get_pages_async(obj, pa + i, count, NULL,
i + count == npages ? &rhpages : NULL,
&sf_iodone, sfio);
KASSERT(rv == VM_PAGER_OK, ("%s: pager fail obj %p page %p",
__func__, obj, pa[i]));
SFSTAT_INC(sf_iocnt);
SFSTAT_ADD(sf_pages_read, count);
if (i + count == npages)
SFSTAT_ADD(sf_rhpages_read, rhpages);
#ifdef INVARIANTS
for (j = i; j < i + count && j < npages; j++)
KASSERT(pa[j] == vm_page_lookup(obj,
OFF_TO_IDX(vmoff(j, off))),
("pa[j] %p lookup %p\n", pa[j],
vm_page_lookup(obj, OFF_TO_IDX(vmoff(j, off)))));
#endif
i += count;
nios++;
} }
KASSERT(error != 0 || (m->wire_count > 0 &&
vm_page_is_valid(m, off & PAGE_MASK, xfsize)),
("wrong page state m %p off %#jx xfsize %d", m, (uintmax_t)off,
xfsize));
VM_OBJECT_WUNLOCK(obj); VM_OBJECT_WUNLOCK(obj);
return (error);
if (nios == 0 && npages != 0)
SFSTAT_INC(sf_noiocnt);
return (nios);
} }
static int static int
@ -2178,80 +2354,65 @@ vn_sendfile(struct file *fp, int sockfd, struct uio *hdr_uio,
struct vnode *vp; struct vnode *vp;
struct vm_object *obj; struct vm_object *obj;
struct socket *so; struct socket *so;
struct mbuf *m; struct mbuf *m, *mh, *mhtail;
struct sf_buf *sf; struct sf_buf *sf;
struct vm_page *pg;
struct shmfd *shmfd; struct shmfd *shmfd;
struct sendfile_sync *sfs; struct sendfile_sync *sfs;
struct vattr va; struct vattr va;
off_t off, xfsize, fsbytes, sbytes, rem, obj_size; off_t off, sbytes, rem, obj_size;
int error, bsize, nd, hdrlen, mnw; int error, softerr, bsize, hdrlen;
pg = NULL;
obj = NULL; obj = NULL;
so = NULL; so = NULL;
m = NULL; m = mh = NULL;
sfs = NULL; sfs = NULL;
fsbytes = sbytes = 0; sbytes = 0;
hdrlen = mnw = 0; softerr = 0;
rem = nbytes;
obj_size = 0;
error = sendfile_getobj(td, fp, &obj, &vp, &shmfd, &obj_size, &bsize); error = sendfile_getobj(td, fp, &obj, &vp, &shmfd, &obj_size, &bsize);
if (error != 0) if (error != 0)
return (error); return (error);
if (rem == 0)
rem = obj_size;
error = kern_sendfile_getsock(td, sockfd, &sock_fp, &so); error = kern_sendfile_getsock(td, sockfd, &sock_fp, &so);
if (error != 0) if (error != 0)
goto out; goto out;
/*
* Do not wait on memory allocations but return ENOMEM for
* caller to retry later.
* XXX: Experimental.
*/
if (flags & SF_MNOWAIT)
mnw = 1;
if (flags & SF_SYNC) {
sfs = malloc(sizeof *sfs, M_TEMP, M_WAITOK | M_ZERO);
mtx_init(&sfs->mtx, "sendfile", NULL, MTX_DEF);
cv_init(&sfs->cv, "sendfile");
}
#ifdef MAC #ifdef MAC
error = mac_socket_check_send(td->td_ucred, so); error = mac_socket_check_send(td->td_ucred, so);
if (error != 0) if (error != 0)
goto out; goto out;
#endif #endif
SFSTAT_INC(sf_syscalls);
SFSTAT_ADD(sf_rhpages_requested, SF_READAHEAD(flags));
if (flags & SF_SYNC) {
sfs = malloc(sizeof *sfs, M_TEMP, M_WAITOK | M_ZERO);
mtx_init(&sfs->mtx, "sendfile", NULL, MTX_DEF);
cv_init(&sfs->cv, "sendfile");
}
/* If headers are specified copy them into mbufs. */ /* If headers are specified copy them into mbufs. */
if (hdr_uio != NULL) { if (hdr_uio != NULL && hdr_uio->uio_resid > 0) {
hdr_uio->uio_td = td; hdr_uio->uio_td = td;
hdr_uio->uio_rw = UIO_WRITE; hdr_uio->uio_rw = UIO_WRITE;
if (hdr_uio->uio_resid > 0) { /*
/* * In FBSD < 5.0 the nbytes to send also included
* In FBSD < 5.0 the nbytes to send also included * the header. If compat is specified subtract the
* the header. If compat is specified subtract the * header size from nbytes.
* header size from nbytes. */
*/ if (kflags & SFK_COMPAT) {
if (kflags & SFK_COMPAT) { if (nbytes > hdr_uio->uio_resid)
if (nbytes > hdr_uio->uio_resid) nbytes -= hdr_uio->uio_resid;
nbytes -= hdr_uio->uio_resid; else
else nbytes = 0;
nbytes = 0;
}
m = m_uiotombuf(hdr_uio, (mnw ? M_NOWAIT : M_WAITOK),
0, 0, 0);
if (m == NULL) {
error = mnw ? EAGAIN : ENOBUFS;
goto out;
}
hdrlen = m_length(m, NULL);
} }
} mh = m_uiotombuf(hdr_uio, M_WAITOK, 0, 0, 0);
hdrlen = m_length(mh, &mhtail);
} else
hdrlen = 0;
rem = nbytes ? omin(nbytes, obj_size - offset) : obj_size - offset;
/* /*
* Protect against multiple writers to the socket. * Protect against multiple writers to the socket.
@ -2272,21 +2433,13 @@ vn_sendfile(struct file *fp, int sockfd, struct uio *hdr_uio,
* The outer loop checks the state and available space of the socket * The outer loop checks the state and available space of the socket
* and takes care of the overall progress. * and takes care of the overall progress.
*/ */
for (off = offset; ; ) { for (off = offset; rem > 0; ) {
struct sf_io *sfio;
vm_page_t *pa;
struct mbuf *mtail; struct mbuf *mtail;
int loopbytes; int nios, space, npages, rhpages;
int space;
int done;
if ((nbytes != 0 && nbytes == fsbytes) ||
(nbytes == 0 && obj_size == fsbytes))
break;
mtail = NULL; mtail = NULL;
loopbytes = 0;
space = 0;
done = 0;
/* /*
* Check the socket state for ongoing connection, * Check the socket state for ongoing connection,
* no errors and space in socket buffer. * no errors and space in socket buffer.
@ -2362,49 +2515,58 @@ vn_sendfile(struct file *fp, int sockfd, struct uio *hdr_uio,
VOP_UNLOCK(vp, 0); VOP_UNLOCK(vp, 0);
goto done; goto done;
} }
obj_size = va.va_size; if (va.va_size != obj_size) {
if (nbytes == 0)
rem += va.va_size - obj_size;
else if (offset + nbytes > va.va_size)
rem -= (offset + nbytes - va.va_size);
obj_size = va.va_size;
}
} }
if (space > rem)
space = rem;
npages = howmany(space + (off & PAGE_MASK), PAGE_SIZE);
/*
* Calculate maximum allowed number of pages for readahead
* at this iteration. First, we allow readahead up to "rem".
* If application wants more, let it be, but there is no
* reason to go above MAXPHYS. Also check against "obj_size",
* since vm_pager_has_page() can hint beyond EOF.
*/
rhpages = howmany(rem + (off & PAGE_MASK), PAGE_SIZE) - npages;
rhpages += SF_READAHEAD(flags);
rhpages = min(howmany(MAXPHYS, PAGE_SIZE), rhpages);
rhpages = min(howmany(obj_size - trunc_page(off), PAGE_SIZE) -
npages, rhpages);
sfio = malloc(sizeof(struct sf_io) +
npages * sizeof(vm_page_t), M_TEMP, M_WAITOK);
refcount_init(&sfio->nios, 1);
sfio->error = 0;
nios = sendfile_swapin(obj, sfio, off, space, npages, rhpages,
flags);
/* /*
* Loop and construct maximum sized mbuf chain to be bulk * Loop and construct maximum sized mbuf chain to be bulk
* dumped into socket buffer. * dumped into socket buffer.
*/ */
while (space > loopbytes) { pa = sfio->pa;
vm_offset_t pgoff; for (int i = 0; i < npages; i++) {
struct mbuf *m0; struct mbuf *m0;
/* /*
* Calculate the amount to transfer. * If a page wasn't grabbed successfully, then
* Not to exceed a page, the EOF, * trim the array. Can happen only with SF_NODISKIO.
* or the passed in nbytes.
*/ */
pgoff = (vm_offset_t)(off & PAGE_MASK); if (pa[i] == NULL) {
rem = obj_size - offset; SFSTAT_INC(sf_busy);
if (nbytes != 0) fixspace(npages, i, off, &space);
rem = omin(rem, nbytes); npages = i;
rem -= fsbytes + loopbytes; softerr = EBUSY;
xfsize = omin(PAGE_SIZE - pgoff, rem);
xfsize = omin(space - loopbytes, xfsize);
if (xfsize <= 0) {
done = 1; /* all data sent */
break;
}
/*
* Attempt to look up the page. Allocate
* if not found or wait and loop if busy.
*/
if (m != NULL)
nd = EAGAIN; /* send what we already got */
else if ((flags & SF_NODISKIO) != 0)
nd = EBUSY;
else
nd = 0;
error = sendfile_readpage(obj, vp, nd, off,
xfsize, bsize, td, &pg);
if (error != 0) {
if (error == EAGAIN)
error = 0; /* not a real error */
break; break;
} }
@ -2417,56 +2579,59 @@ vn_sendfile(struct file *fp, int sockfd, struct uio *hdr_uio,
* threads might exhaust the buffers and then * threads might exhaust the buffers and then
* deadlock. * deadlock.
*/ */
sf = sf_buf_alloc(pg, (mnw || m != NULL) ? SFB_NOWAIT : sf = sf_buf_alloc(pa[i],
SFB_CATCH); m != NULL ? SFB_NOWAIT : SFB_CATCH);
if (sf == NULL) { if (sf == NULL) {
SFSTAT_INC(sf_allocfail); SFSTAT_INC(sf_allocfail);
vm_page_lock(pg); for (int j = i; j < npages; j++) {
vm_page_unwire(pg, PQ_INACTIVE); vm_page_lock(pa[j]);
KASSERT(pg->object != NULL, vm_page_unwire(pa[j], PQ_INACTIVE);
("%s: object disappeared", __func__)); vm_page_unlock(pa[j]);
vm_page_unlock(pg); }
if (m == NULL) if (m == NULL)
error = (mnw ? EAGAIN : EINTR); softerr = ENOBUFS;
fixspace(npages, i, off, &space);
npages = i;
break; break;
} }
/* m0 = m_get(M_WAITOK, MT_DATA);
* Get an mbuf and set it up as having m0->m_ext.ext_buf = (char *)sf_buf_kva(sf);
* external storage.
*/
m0 = m_get((mnw ? M_NOWAIT : M_WAITOK), MT_DATA);
if (m0 == NULL) {
error = (mnw ? EAGAIN : ENOBUFS);
sf_ext_free(sf, NULL);
break;
}
/*
* Attach EXT_SFBUF external storage.
*/
m0->m_ext.ext_buf = (caddr_t )sf_buf_kva(sf);
m0->m_ext.ext_size = PAGE_SIZE; m0->m_ext.ext_size = PAGE_SIZE;
m0->m_ext.ext_arg1 = sf; m0->m_ext.ext_arg1 = sf;
m0->m_ext.ext_arg2 = sfs; m0->m_ext.ext_arg2 = sfs;
m0->m_ext.ext_type = EXT_SFBUF; /*
* SF_NOCACHE sets the page as being freed upon send.
* However, we ignore it for the last page in 'space',
* if the page is truncated, and we got more data to
* send (rem > space), or if we have readahead
* configured (rhpages > 0).
*/
if ((flags & SF_NOCACHE) == 0 ||
(i == npages - 1 &&
((off + space) & PAGE_MASK) &&
(rem > space || rhpages > 0)))
m0->m_ext.ext_type = EXT_SFBUF;
else
m0->m_ext.ext_type = EXT_SFBUF_NOCACHE;
m0->m_ext.ext_flags = 0; m0->m_ext.ext_flags = 0;
m0->m_flags |= (M_EXT|M_RDONLY); m0->m_flags |= (M_EXT | M_RDONLY);
m0->m_data = (char *)sf_buf_kva(sf) + pgoff; if (nios)
m0->m_len = xfsize; m0->m_flags |= M_NOTREADY;
m0->m_data = (char *)sf_buf_kva(sf) +
(vmoff(i, off) & PAGE_MASK);
m0->m_len = xfsize(i, npages, off, space);
if (i == 0)
sfio->m = m0;
/* Append to mbuf chain. */ /* Append to mbuf chain. */
if (mtail != NULL) if (mtail != NULL)
mtail->m_next = m0; mtail->m_next = m0;
else if (m != NULL)
m_last(m)->m_next = m0;
else else
m = m0; m = m0;
mtail = m0; mtail = m0;
/* Keep track of bits processed. */
loopbytes += xfsize;
off += xfsize;
if (sfs != NULL) { if (sfs != NULL) {
mtx_lock(&sfs->mtx); mtx_lock(&sfs->mtx);
sfs->count++; sfs->count++;
@ -2477,49 +2642,60 @@ vn_sendfile(struct file *fp, int sockfd, struct uio *hdr_uio,
if (vp != NULL) if (vp != NULL)
VOP_UNLOCK(vp, 0); VOP_UNLOCK(vp, 0);
/* Add the buffer chain to the socket buffer. */ /* Keep track of bytes processed. */
if (m != NULL) { off += space;
int mlen, err; rem -= space;
mlen = m_length(m, NULL); /* Prepend header, if any. */
SOCKBUF_LOCK(&so->so_snd); if (hdrlen) {
if (so->so_snd.sb_state & SBS_CANTSENDMORE) { mhtail->m_next = m;
error = EPIPE; m = mh;
SOCKBUF_UNLOCK(&so->so_snd); mh = NULL;
goto done;
}
SOCKBUF_UNLOCK(&so->so_snd);
CURVNET_SET(so->so_vnet);
/* Avoid error aliasing. */
err = (*so->so_proto->pr_usrreqs->pru_send)
(so, 0, m, NULL, NULL, td);
CURVNET_RESTORE();
if (err == 0) {
/*
* We need two counters to get the
* file offset and nbytes to send
* right:
* - sbytes contains the total amount
* of bytes sent, including headers.
* - fsbytes contains the total amount
* of bytes sent from the file.
*/
sbytes += mlen;
fsbytes += mlen;
if (hdrlen) {
fsbytes -= hdrlen;
hdrlen = 0;
}
} else if (error == 0)
error = err;
m = NULL; /* pru_send always consumes */
} }
/* Quit outer loop on error or when we're done. */ if (m == NULL) {
if (done) KASSERT(softerr, ("%s: m NULL, no error", __func__));
break; error = softerr;
if (error != 0) free(sfio, M_TEMP);
goto done; goto done;
}
/* Add the buffer chain to the socket buffer. */
KASSERT(m_length(m, NULL) == space + hdrlen,
("%s: mlen %u space %d hdrlen %d",
__func__, m_length(m, NULL), space, hdrlen));
CURVNET_SET(so->so_vnet);
if (nios == 0) {
/*
* If sendfile_swapin() didn't initiate any I/Os,
* which happens if all data is cached in VM, then
* we can send data right now without the
* PRUS_NOTREADY flag.
*/
free(sfio, M_TEMP);
error = (*so->so_proto->pr_usrreqs->pru_send)
(so, 0, m, NULL, NULL, td);
} else {
sfio->sock_fp = sock_fp;
sfio->npages = npages;
fhold(sock_fp);
error = (*so->so_proto->pr_usrreqs->pru_send)
(so, PRUS_NOTREADY, m, NULL, NULL, td);
sf_iodone(sfio, NULL, 0, 0);
}
CURVNET_RESTORE();
m = NULL; /* pru_send always consumes */
if (error)
goto done;
sbytes += space + hdrlen;
if (hdrlen)
hdrlen = 0;
if (softerr) {
error = softerr;
goto done;
}
} }
/* /*
@ -2552,6 +2728,8 @@ vn_sendfile(struct file *fp, int sockfd, struct uio *hdr_uio,
fdrop(sock_fp, td); fdrop(sock_fp, td);
if (m) if (m)
m_freem(m); m_freem(m);
if (mh)
m_freem(mh);
if (sfs != NULL) { if (sfs != NULL) {
mtx_lock(&sfs->mtx); mtx_lock(&sfs->mtx);

View File

@ -981,7 +981,7 @@ uipc_send(struct socket *so, int flags, struct mbuf *m, struct sockaddr *nam,
control)) control))
control = NULL; control = NULL;
} else } else
sbappend_locked(&so2->so_rcv, m); sbappend_locked(&so2->so_rcv, m, flags);
break; break;
case SOCK_SEQPACKET: { case SOCK_SEQPACKET: {

View File

@ -81,6 +81,7 @@ struct sysentvec elf64_freebsd_sysvec = {
.sv_syscallnames = syscallnames, .sv_syscallnames = syscallnames,
.sv_schedtail = NULL, .sv_schedtail = NULL,
.sv_thread_detach = NULL, .sv_thread_detach = NULL,
.sv_trap = NULL,
}; };
static Elf64_Brandinfo freebsd_brand_info = { static Elf64_Brandinfo freebsd_brand_info = {
@ -135,6 +136,7 @@ struct sysentvec elf32_freebsd_sysvec = {
.sv_syscallnames = syscallnames, .sv_syscallnames = syscallnames,
.sv_schedtail = NULL, .sv_schedtail = NULL,
.sv_thread_detach = NULL, .sv_thread_detach = NULL,
.sv_trap = NULL,
}; };
static Elf32_Brandinfo freebsd_brand_info = { static Elf32_Brandinfo freebsd_brand_info = {

View File

@ -104,6 +104,7 @@ struct sysentvec elf32_freebsd_sysvec = {
.sv_syscallnames = freebsd32_syscallnames, .sv_syscallnames = freebsd32_syscallnames,
.sv_schedtail = NULL, .sv_schedtail = NULL,
.sv_thread_detach = NULL, .sv_thread_detach = NULL,
.sv_trap = NULL,
}; };
INIT_SYSENTVEC(elf32_sysvec, &elf32_freebsd_sysvec); INIT_SYSENTVEC(elf32_sysvec, &elf32_freebsd_sysvec);

View File

@ -113,9 +113,8 @@ arc_output(struct ifnet *ifp, struct mbuf *m, const struct sockaddr *dst,
error = 0; error = 0;
#if defined(INET) || defined(INET6) #if defined(INET) || defined(INET6)
if (ro != NULL && ro->ro_rt != NULL && if (ro != NULL)
(ro->ro_rt->rt_flags & RTF_GATEWAY) != 0) is_gw = (ro->ro_flags & RT_HAS_GW) != 0;
is_gw = 1;
#endif #endif
switch (dst->sa_family) { switch (dst->sa_family) {

View File

@ -202,7 +202,6 @@ ether_resolve_addr(struct ifnet *ifp, struct mbuf *m,
uint32_t *pflags) uint32_t *pflags)
{ {
struct ether_header *eh; struct ether_header *eh;
struct rtentry *rt;
uint32_t lleflags = 0; uint32_t lleflags = 0;
int error = 0; int error = 0;
#if defined(INET) || defined(INET6) #if defined(INET) || defined(INET6)
@ -253,8 +252,7 @@ ether_resolve_addr(struct ifnet *ifp, struct mbuf *m,
} }
if (error == EHOSTDOWN) { if (error == EHOSTDOWN) {
rt = (ro != NULL) ? ro->ro_rt : NULL; if (ro != NULL && (ro->ro_flags & RT_HAS_GW) != 0)
if (rt != NULL && (rt->rt_flags & RTF_GATEWAY) != 0)
error = EHOSTUNREACH; error = EHOSTUNREACH;
} }

View File

@ -119,9 +119,8 @@ fddi_output(struct ifnet *ifp, struct mbuf *m, const struct sockaddr *dst,
getmicrotime(&ifp->if_lastchange); getmicrotime(&ifp->if_lastchange);
#if defined(INET) || defined(INET6) #if defined(INET) || defined(INET6)
if (ro != NULL && ro->ro_rt != NULL && if (ro != NULL)
(ro->ro_rt->rt_flags & RTF_GATEWAY) != 0) is_gw = (ro->ro_flags & RT_HAS_GW) != 0;
is_gw = 1;
#endif #endif
switch (dst->sa_family) { switch (dst->sa_family) {

View File

@ -106,9 +106,8 @@ firewire_output(struct ifnet *ifp, struct mbuf *m, const struct sockaddr *dst,
} }
#if defined(INET) || defined(INET6) #if defined(INET) || defined(INET6)
if (ro != NULL && ro->ro_rt != NULL && if (ro != NULL)
(ro->ro_rt->rt_flags & RTF_GATEWAY) != 0) is_gw = (ro->ro_flags & RT_HAS_GW) != 0;
is_gw = 1;
#endif #endif
/* /*
* For unicast, we make a tag to store the lladdr of the * For unicast, we make a tag to store the lladdr of the
@ -145,10 +144,6 @@ firewire_output(struct ifnet *ifp, struct mbuf *m, const struct sockaddr *dst,
* doesn't fit into the arp model. * doesn't fit into the arp model.
*/ */
if (unicast) { if (unicast) {
is_gw = 0;
if (ro != NULL && ro->ro_rt != NULL &&
(ro->ro_rt->rt_flags & RTF_GATEWAY) != 0)
is_gw = 1;
error = arpresolve(ifp, is_gw, m, dst, (u_char *) destfw, NULL); error = arpresolve(ifp, is_gw, m, dst, (u_char *) destfw, NULL);
if (error) if (error)
return (error == EWOULDBLOCK ? 0 : error); return (error == EWOULDBLOCK ? 0 : error);

View File

@ -214,12 +214,8 @@ iso88025_output(struct ifnet *ifp, struct mbuf *m, const struct sockaddr *dst,
struct rtentry *rt0 = NULL; struct rtentry *rt0 = NULL;
int is_gw = 0; int is_gw = 0;
if (ro != NULL) { if (ro != NULL)
rt0 = ro->ro_rt; is_gw = (ro->ro_flags & RT_HAS_GW) != 0;
if (rt0 != NULL && (rt0->rt_flags & RTF_GATEWAY) != 0)
is_gw = 1;
}
#ifdef MAC #ifdef MAC
error = mac_ifnet_check_transmit(ifp, m); error = mac_ifnet_check_transmit(ifp, m);
if (error) if (error)

View File

@ -202,15 +202,12 @@ looutput(struct ifnet *ifp, struct mbuf *m, const struct sockaddr *dst,
struct route *ro) struct route *ro)
{ {
u_int32_t af; u_int32_t af;
struct rtentry *rt = NULL;
#ifdef MAC #ifdef MAC
int error; int error;
#endif #endif
M_ASSERTPKTHDR(m); /* check if we have the packet header */ M_ASSERTPKTHDR(m); /* check if we have the packet header */
if (ro != NULL)
rt = ro->ro_rt;
#ifdef MAC #ifdef MAC
error = mac_ifnet_check_transmit(ifp, m); error = mac_ifnet_check_transmit(ifp, m);
if (error) { if (error) {
@ -219,10 +216,9 @@ looutput(struct ifnet *ifp, struct mbuf *m, const struct sockaddr *dst,
} }
#endif #endif
if (rt && rt->rt_flags & (RTF_REJECT|RTF_BLACKHOLE)) { if (ro != NULL && ro->ro_flags & (RT_REJECT|RT_BLACKHOLE)) {
m_freem(m); m_freem(m);
return (rt->rt_flags & RTF_BLACKHOLE ? 0 : return (ro->ro_flags & RT_BLACKHOLE ? 0 : EHOSTUNREACH);
rt->rt_flags & RTF_HOST ? EHOSTUNREACH : ENETUNREACH);
} }
if_inc_counter(ifp, IFCOUNTER_OPACKETS, 1); if_inc_counter(ifp, IFCOUNTER_OPACKETS, 1);

View File

@ -197,14 +197,49 @@ rt_mpath_conflict(struct radix_node_head *rnh, struct rtentry *rt,
return (0); return (0);
} }
void static struct rtentry *
rtalloc_mpath_fib(struct route *ro, uint32_t hash, u_int fibnum) rt_mpath_selectrte(struct rtentry *rte, uint32_t hash)
{ {
struct radix_node *rn0, *rn; struct radix_node *rn0, *rn;
u_int32_t n; u_int32_t n;
struct rtentry *rt; struct rtentry *rt;
int64_t weight; int64_t weight;
/* beyond here, we use rn as the master copy */
rn0 = rn = (struct radix_node *)rte;
n = rn_mpath_count(rn0);
/* gw selection by Modulo-N Hash (RFC2991) XXX need improvement? */
hash += hashjitter;
hash %= n;
for (weight = abs((int32_t)hash), rt = rte;
weight >= rt->rt_weight && rn;
weight -= rt->rt_weight) {
/* stay within the multipath routes */
if (rn->rn_dupedkey && rn->rn_mask != rn->rn_dupedkey->rn_mask)
break;
rn = rn->rn_dupedkey;
rt = (struct rtentry *)rn;
}
return (rt);
}
struct rtentry *
rt_mpath_select(struct rtentry *rte, uint32_t hash)
{
if (rn_mpath_next((struct radix_node *)rte) == NULL)
return (rte);
return (rt_mpath_selectrte(rte, hash));
}
void
rtalloc_mpath_fib(struct route *ro, uint32_t hash, u_int fibnum)
{
struct rtentry *rt;
/* /*
* XXX we don't attempt to lookup cached route again; what should * XXX we don't attempt to lookup cached route again; what should
* be done for sendto(3) case? * be done for sendto(3) case?
@ -222,34 +257,18 @@ rtalloc_mpath_fib(struct route *ro, uint32_t hash, u_int fibnum)
return; return;
} }
/* beyond here, we use rn as the master copy */ rt = rt_mpath_selectrte(ro->ro_rt, hash);
rn0 = rn = (struct radix_node *)ro->ro_rt;
n = rn_mpath_count(rn0);
/* gw selection by Modulo-N Hash (RFC2991) XXX need improvement? */
hash += hashjitter;
hash %= n;
for (weight = abs((int32_t)hash), rt = ro->ro_rt;
weight >= rt->rt_weight && rn;
weight -= rt->rt_weight) {
/* stay within the multipath routes */
if (rn->rn_dupedkey && rn->rn_mask != rn->rn_dupedkey->rn_mask)
break;
rn = rn->rn_dupedkey;
rt = (struct rtentry *)rn;
}
/* XXX try filling rt_gwroute and avoid unreachable gw */ /* XXX try filling rt_gwroute and avoid unreachable gw */
/* gw selection has failed - there must be only zero weight routes */ /* gw selection has failed - there must be only zero weight routes */
if (!rn) { if (!rt) {
RT_UNLOCK(ro->ro_rt); RT_UNLOCK(ro->ro_rt);
ro->ro_rt = NULL; ro->ro_rt = NULL;
return; return;
} }
if (ro->ro_rt != rt) { if (ro->ro_rt != rt) {
RTFREE_LOCKED(ro->ro_rt); RTFREE_LOCKED(ro->ro_rt);
ro->ro_rt = (struct rtentry *)rn; ro->ro_rt = rt;
RT_LOCK(ro->ro_rt); RT_LOCK(ro->ro_rt);
RT_ADDREF(ro->ro_rt); RT_ADDREF(ro->ro_rt);

View File

@ -52,6 +52,7 @@ int rt_mpath_conflict(struct radix_node_head *, struct rtentry *,
struct sockaddr *); struct sockaddr *);
void rtalloc_mpath_fib(struct route *, u_int32_t, u_int); void rtalloc_mpath_fib(struct route *, u_int32_t, u_int);
#define rtalloc_mpath(_route, _hash) rtalloc_mpath_fib((_route), (_hash), 0) #define rtalloc_mpath(_route, _hash) rtalloc_mpath_fib((_route), (_hash), 0)
struct rtentry *rt_mpath_select(struct rtentry *, uint32_t);
struct radix_node *rn_mpath_lookup(void *, void *, struct radix_node *rn_mpath_lookup(void *, void *,
struct radix_node_head *); struct radix_node_head *);
int rt_mpath_deldup(struct rtentry *, struct rtentry *); int rt_mpath_deldup(struct rtentry *, struct rtentry *);

View File

@ -568,7 +568,7 @@ rtredirect_fib(struct sockaddr *dst,
struct sockaddr *src, struct sockaddr *src,
u_int fibnum) u_int fibnum)
{ {
struct rtentry *rt, *rt0 = NULL; struct rtentry *rt;
int error = 0; int error = 0;
short *stat = NULL; short *stat = NULL;
struct rt_addrinfo info; struct rt_addrinfo info;
@ -627,7 +627,7 @@ rtredirect_fib(struct sockaddr *dst,
* Create new route, rather than smashing route to net. * Create new route, rather than smashing route to net.
*/ */
create: create:
rt0 = rt; RTFREE(rt);
rt = NULL; rt = NULL;
flags |= RTF_DYNAMIC; flags |= RTF_DYNAMIC;
@ -637,21 +637,14 @@ rtredirect_fib(struct sockaddr *dst,
info.rti_info[RTAX_NETMASK] = netmask; info.rti_info[RTAX_NETMASK] = netmask;
info.rti_ifa = ifa; info.rti_ifa = ifa;
info.rti_flags = flags; info.rti_flags = flags;
if (rt0 != NULL)
RT_UNLOCK(rt0); /* drop lock to avoid LOR with RNH */
error = rtrequest1_fib(RTM_ADD, &info, &rt, fibnum); error = rtrequest1_fib(RTM_ADD, &info, &rt, fibnum);
if (rt != NULL) { if (rt != NULL) {
RT_LOCK(rt); RT_LOCK(rt);
if (rt0 != NULL)
EVENTHANDLER_INVOKE(route_redirect_event, rt0, rt, dst);
flags = rt->rt_flags; flags = rt->rt_flags;
} }
if (rt0 != NULL)
RTFREE(rt0);
stat = &V_rtstat.rts_dynamic; stat = &V_rtstat.rts_dynamic;
} else { } else {
struct rtentry *gwrt;
/* /*
* Smash the current notion of the gateway to * Smash the current notion of the gateway to
@ -669,11 +662,7 @@ rtredirect_fib(struct sockaddr *dst,
RADIX_NODE_HEAD_LOCK(rnh); RADIX_NODE_HEAD_LOCK(rnh);
RT_LOCK(rt); RT_LOCK(rt);
rt_setgate(rt, rt_key(rt), gateway); rt_setgate(rt, rt_key(rt), gateway);
gwrt = rtalloc1(gateway, 1, RTF_RNH_LOCKED);
RADIX_NODE_HEAD_UNLOCK(rnh); RADIX_NODE_HEAD_UNLOCK(rnh);
EVENTHANDLER_INVOKE(route_redirect_event, rt, gwrt, dst);
if (gwrt)
RTFREE_LOCKED(gwrt);
} }
} else } else
error = EHOSTUNREACH; error = EHOSTUNREACH;
@ -858,7 +847,7 @@ rt_exportinfo(struct rtentry *rt, struct rt_addrinfo *info, int flags)
src = rt_key(rt); src = rt_key(rt);
dst = info->rti_info[RTAX_DST]; dst = info->rti_info[RTAX_DST];
sa_len = src->sa_len; sa_len = src->sa_len;
if (src != NULL && dst != NULL) { if (dst != NULL) {
if (src->sa_len > dst->sa_len) if (src->sa_len > dst->sa_len)
return (ENOMEM); return (ENOMEM);
memcpy(dst, src, src->sa_len); memcpy(dst, src, src->sa_len);

View File

@ -64,9 +64,13 @@ struct route {
#define RT_CACHING_CONTEXT 0x1 /* XXX: not used anywhere */ #define RT_CACHING_CONTEXT 0x1 /* XXX: not used anywhere */
#define RT_NORTREF 0x2 /* doesn't hold reference on ro_rt */ #define RT_NORTREF 0x2 /* doesn't hold reference on ro_rt */
#define RT_L2_ME (1 << RT_L2_ME_BIT) #define RT_L2_ME (1 << RT_L2_ME_BIT) /* 0x0004 */
#define RT_MAY_LOOP (1 << RT_MAY_LOOP_BIT) #define RT_MAY_LOOP (1 << RT_MAY_LOOP_BIT) /* 0x0008 */
#define RT_HAS_HEADER (1 << RT_HAS_HEADER_BIT) #define RT_HAS_HEADER (1 << RT_HAS_HEADER_BIT) /* 0x0010 */
#define RT_REJECT 0x0020 /* Destination is reject */
#define RT_BLACKHOLE 0x0040 /* Destination is blackhole */
#define RT_HAS_GW 0x0080 /* Destination has GW */
struct rt_metrics { struct rt_metrics {
u_long rmx_locks; /* Kernel must leave these values alone */ u_long rmx_locks; /* Kernel must leave these values alone */
@ -215,6 +219,21 @@ fib_rte_to_nh_flags(int rt_flags)
return (res); return (res);
} }
#ifdef _KERNEL
/* rte<>ro_flags translation */
static inline void
rt_update_ro_flags(struct route *ro)
{
int rt_flags = ro->ro_rt->rt_flags;
ro->ro_flags &= ~ (RT_REJECT|RT_BLACKHOLE|RT_HAS_GW);
ro->ro_flags |= (rt_flags & RTF_REJECT) ? RT_REJECT : 0;
ro->ro_flags |= (rt_flags & RTF_BLACKHOLE) ? RT_BLACKHOLE : 0;
ro->ro_flags |= (rt_flags & RTF_GATEWAY) ? RT_HAS_GW : 0;
}
#endif
/* /*
* Routing statistics. * Routing statistics.
*/ */
@ -467,9 +486,6 @@ int rib_lookup_info(uint32_t, const struct sockaddr *, uint32_t, uint32_t,
struct rt_addrinfo *); struct rt_addrinfo *);
void rib_free_info(struct rt_addrinfo *info); void rib_free_info(struct rt_addrinfo *info);
#include <sys/eventhandler.h>
typedef void (*rtevent_redirect_fn)(void *, struct rtentry *, struct rtentry *, struct sockaddr *);
EVENTHANDLER_DECLARE(route_redirect_event, rtevent_redirect_fn);
#endif #endif
#endif #endif

View File

@ -34,6 +34,7 @@ __FBSDID("$FreeBSD$");
#include <sys/param.h> #include <sys/param.h>
#include <sys/kernel.h> #include <sys/kernel.h>
#include <sys/systm.h> #include <sys/systm.h>
#include <sys/eventhandler.h>
#include <sys/linker.h> #include <sys/linker.h>
#include <sys/mbuf.h> #include <sys/mbuf.h>
#include <sys/module.h> #include <sys/module.h>

View File

@ -972,7 +972,7 @@ ng_btsocket_rfcomm_send(struct socket *so, int flags, struct mbuf *m,
} }
/* Put the packet on the socket's send queue and wakeup RFCOMM task */ /* Put the packet on the socket's send queue and wakeup RFCOMM task */
sbappend(&pcb->so->so_snd, m); sbappend(&pcb->so->so_snd, m, flags);
m = NULL; m = NULL;
if (!(pcb->flags & NG_BTSOCKET_RFCOMM_DLC_SENDING)) { if (!(pcb->flags & NG_BTSOCKET_RFCOMM_DLC_SENDING)) {
@ -2396,7 +2396,7 @@ ng_btsocket_rfcomm_receive_uih(ng_btsocket_rfcomm_session_p s, int dlci,
error = ENOBUFS; error = ENOBUFS;
} else { } else {
/* Append packet to the socket receive queue */ /* Append packet to the socket receive queue */
sbappend(&pcb->so->so_rcv, m0); sbappend(&pcb->so->so_rcv, m0, 0);
m0 = NULL; m0 = NULL;
sorwakeup(pcb->so); sorwakeup(pcb->so);

View File

@ -37,6 +37,7 @@ __FBSDID("$FreeBSD$");
#include <sys/systm.h> #include <sys/systm.h>
#include <sys/counter.h> #include <sys/counter.h>
#include <sys/kernel.h> #include <sys/kernel.h>
#include <sys/ktr.h>
#include <sys/limits.h> #include <sys/limits.h>
#include <sys/mbuf.h> #include <sys/mbuf.h>
#include <sys/syslog.h> #include <sys/syslog.h>

View File

@ -35,6 +35,7 @@ __FBSDID("$FreeBSD$");
#include <sys/systm.h> #include <sys/systm.h>
#include <sys/counter.h> #include <sys/counter.h>
#include <sys/kernel.h> #include <sys/kernel.h>
#include <sys/ktr.h>
#include <sys/limits.h> #include <sys/limits.h>
#include <sys/mbuf.h> #include <sys/mbuf.h>
#include <sys/syslog.h> #include <sys/syslog.h>

View File

@ -38,6 +38,7 @@ __FBSDID("$FreeBSD$");
#include <sys/systm.h> #include <sys/systm.h>
#include <sys/counter.h> #include <sys/counter.h>
#include <sys/kernel.h> #include <sys/kernel.h>
#include <sys/ktr.h>
#include <sys/limits.h> #include <sys/limits.h>
#include <sys/mbuf.h> #include <sys/mbuf.h>
#include <sys/socket.h> #include <sys/socket.h>

View File

@ -200,6 +200,13 @@ fib4_lookup_nh_ext(uint32_t fibnum, struct in_addr dst, uint32_t flags,
rn = rh->rnh_matchaddr((void *)&sin, rh); rn = rh->rnh_matchaddr((void *)&sin, rh);
if (rn != NULL && ((rn->rn_flags & RNF_ROOT) == 0)) { if (rn != NULL && ((rn->rn_flags & RNF_ROOT) == 0)) {
rte = RNTORT(rn); rte = RNTORT(rn);
#ifdef RADIX_MPATH
rte = rt_mpath_select(rte, flowid);
if (rte == NULL) {
RADIX_NODE_HEAD_RUNLOCK(rh);
return (ENOENT);
}
#endif
/* Ensure route & ifp is UP */ /* Ensure route & ifp is UP */
if (RT_LINK_IS_UP(rte->rt_ifp)) { if (RT_LINK_IS_UP(rte->rt_ifp)) {
fib4_rte_to_nh_extended(rte, dst, flags, pnh4); fib4_rte_to_nh_extended(rte, dst, flags, pnh4);

View File

@ -51,6 +51,7 @@ __FBSDID("$FreeBSD$");
#include <sys/malloc.h> #include <sys/malloc.h>
#include <sys/mbuf.h> #include <sys/mbuf.h>
#include <sys/callout.h> #include <sys/callout.h>
#include <sys/eventhandler.h>
#include <sys/domain.h> #include <sys/domain.h>
#include <sys/protosw.h> #include <sys/protosw.h>
#include <sys/rmlock.h> #include <sys/rmlock.h>

View File

@ -65,6 +65,8 @@ __FBSDID("$FreeBSD$");
#include <sys/param.h> #include <sys/param.h>
#include <sys/systm.h> #include <sys/systm.h>
#include <sys/lock.h>
#include <sys/mutex.h>
#include <sys/socket.h> #include <sys/socket.h>
#include <sys/sockio.h> #include <sys/sockio.h>
#include <sys/mbuf.h> #include <sys/mbuf.h>

View File

@ -77,6 +77,7 @@ __FBSDID("$FreeBSD$");
#include <sys/param.h> #include <sys/param.h>
#include <sys/kernel.h> #include <sys/kernel.h>
#include <sys/stddef.h> #include <sys/stddef.h>
#include <sys/eventhandler.h>
#include <sys/lock.h> #include <sys/lock.h>
#include <sys/ktr.h> #include <sys/ktr.h>
#include <sys/malloc.h> #include <sys/malloc.h>

View File

@ -376,6 +376,7 @@ ip_output(struct mbuf *m, struct mbuf *opt, struct route *ro, int flags,
ia = ifatoia(rte->rt_ifa); ia = ifatoia(rte->rt_ifa);
ifp = rte->rt_ifp; ifp = rte->rt_ifp;
counter_u64_add(rte->rt_pksent, 1); counter_u64_add(rte->rt_pksent, 1);
rt_update_ro_flags(ro);
if (rte->rt_flags & RTF_GATEWAY) if (rte->rt_flags & RTF_GATEWAY)
gw = (struct sockaddr_in *)rte->rt_gateway; gw = (struct sockaddr_in *)rte->rt_gateway;
if (rte->rt_flags & RTF_HOST) if (rte->rt_flags & RTF_HOST)

View File

@ -40,6 +40,7 @@ __FBSDID("$FreeBSD$");
#include <sys/param.h> #include <sys/param.h>
#include <sys/jail.h> #include <sys/jail.h>
#include <sys/kernel.h> #include <sys/kernel.h>
#include <sys/eventhandler.h>
#include <sys/lock.h> #include <sys/lock.h>
#include <sys/malloc.h> #include <sys/malloc.h>
#include <sys/mbuf.h> #include <sys/mbuf.h>

View File

@ -38,6 +38,7 @@ __FBSDID("$FreeBSD$");
#include <sys/param.h> #include <sys/param.h>
#include <sys/kernel.h> #include <sys/kernel.h>
#include <sys/eventhandler.h>
#include <sys/malloc.h> #include <sys/malloc.h>
#include <sys/mbuf.h> #include <sys/mbuf.h>
#include <sys/socket.h> #include <sys/socket.h>

View File

@ -41,6 +41,7 @@ __FBSDID("$FreeBSD$");
#include <sys/param.h> #include <sys/param.h>
#include <sys/systm.h> #include <sys/systm.h>
#include <sys/callout.h> #include <sys/callout.h>
#include <sys/eventhandler.h>
#include <sys/hhook.h> #include <sys/hhook.h>
#include <sys/kernel.h> #include <sys/kernel.h>
#include <sys/khelp.h> #include <sys/khelp.h>

View File

@ -70,7 +70,6 @@ static TAILQ_HEAD(, toedev) toedev_list;
static eventhandler_tag listen_start_eh; static eventhandler_tag listen_start_eh;
static eventhandler_tag listen_stop_eh; static eventhandler_tag listen_stop_eh;
static eventhandler_tag lle_event_eh; static eventhandler_tag lle_event_eh;
static eventhandler_tag route_redirect_eh;
static int static int
toedev_connect(struct toedev *tod __unused, struct socket *so __unused, toedev_connect(struct toedev *tod __unused, struct socket *so __unused,
@ -437,17 +436,6 @@ toe_lle_event(void *arg __unused, struct llentry *lle, int evt)
tod->tod_l2_update(tod, ifp, sa, lladdr, vtag); tod->tod_l2_update(tod, ifp, sa, lladdr, vtag);
} }
/*
* XXX: implement.
*/
static void
toe_route_redirect_event(void *arg __unused, struct rtentry *rt0,
struct rtentry *rt1, struct sockaddr *sa)
{
return;
}
/* /*
* Returns 0 or EWOULDBLOCK on success (any other value is an error). 0 means * Returns 0 or EWOULDBLOCK on success (any other value is an error). 0 means
* lladdr and vtag are valid on return, EWOULDBLOCK means the TOE driver's * lladdr and vtag are valid on return, EWOULDBLOCK means the TOE driver's
@ -534,8 +522,6 @@ toecore_load(void)
toe_listen_stop_event, NULL, EVENTHANDLER_PRI_ANY); toe_listen_stop_event, NULL, EVENTHANDLER_PRI_ANY);
lle_event_eh = EVENTHANDLER_REGISTER(lle_event, toe_lle_event, NULL, lle_event_eh = EVENTHANDLER_REGISTER(lle_event, toe_lle_event, NULL,
EVENTHANDLER_PRI_ANY); EVENTHANDLER_PRI_ANY);
route_redirect_eh = EVENTHANDLER_REGISTER(route_redirect_event,
toe_route_redirect_event, NULL, EVENTHANDLER_PRI_ANY);
return (0); return (0);
} }
@ -553,7 +539,6 @@ toecore_unload(void)
EVENTHANDLER_DEREGISTER(tcp_offload_listen_start, listen_start_eh); EVENTHANDLER_DEREGISTER(tcp_offload_listen_start, listen_start_eh);
EVENTHANDLER_DEREGISTER(tcp_offload_listen_stop, listen_stop_eh); EVENTHANDLER_DEREGISTER(tcp_offload_listen_stop, listen_stop_eh);
EVENTHANDLER_DEREGISTER(lle_event, lle_event_eh); EVENTHANDLER_DEREGISTER(lle_event, lle_event_eh);
EVENTHANDLER_DEREGISTER(route_redirect_event, route_redirect_eh);
mtx_unlock(&toedev_lock); mtx_unlock(&toedev_lock);
mtx_destroy(&toedev_lock); mtx_destroy(&toedev_lock);

View File

@ -39,6 +39,7 @@ __FBSDID("$FreeBSD$");
#include <sys/malloc.h> #include <sys/malloc.h>
#include <sys/mbuf.h> #include <sys/mbuf.h>
#include <sys/domain.h> #include <sys/domain.h>
#include <sys/eventhandler.h>
#include <sys/protosw.h> #include <sys/protosw.h>
#include <sys/socket.h> #include <sys/socket.h>
#include <sys/errno.h> #include <sys/errno.h>

View File

@ -2114,13 +2114,13 @@ icmp6_rip6_input(struct mbuf **mp, int off)
void void
icmp6_reflect(struct mbuf *m, size_t off) icmp6_reflect(struct mbuf *m, size_t off)
{ {
struct in6_addr src, *srcp = NULL; struct in6_addr src6, *srcp;
struct ip6_hdr *ip6; struct ip6_hdr *ip6;
struct icmp6_hdr *icmp6; struct icmp6_hdr *icmp6;
struct in6_ifaddr *ia = NULL; struct in6_ifaddr *ia = NULL;
struct ifnet *outif = NULL; struct ifnet *outif = NULL;
int plen; int plen;
int type, code; int type, code, hlim;
/* too short to reflect */ /* too short to reflect */
if (off < sizeof(struct ip6_hdr)) { if (off < sizeof(struct ip6_hdr)) {
@ -2166,6 +2166,8 @@ icmp6_reflect(struct mbuf *m, size_t off)
icmp6 = (struct icmp6_hdr *)(ip6 + 1); icmp6 = (struct icmp6_hdr *)(ip6 + 1);
type = icmp6->icmp6_type; /* keep type for statistics */ type = icmp6->icmp6_type; /* keep type for statistics */
code = icmp6->icmp6_code; /* ditto. */ code = icmp6->icmp6_code; /* ditto. */
hlim = 0;
srcp = NULL;
/* /*
* If the incoming packet was addressed directly to us (i.e. unicast), * If the incoming packet was addressed directly to us (i.e. unicast),
@ -2177,34 +2179,43 @@ icmp6_reflect(struct mbuf *m, size_t off)
if (!IN6_IS_ADDR_MULTICAST(&ip6->ip6_dst)) { if (!IN6_IS_ADDR_MULTICAST(&ip6->ip6_dst)) {
ia = in6ifa_ifwithaddr(&ip6->ip6_dst, 0 /* XXX */); ia = in6ifa_ifwithaddr(&ip6->ip6_dst, 0 /* XXX */);
if (ia != NULL && !(ia->ia6_flags & if (ia != NULL && !(ia->ia6_flags &
(IN6_IFF_ANYCAST|IN6_IFF_NOTREADY))) (IN6_IFF_ANYCAST|IN6_IFF_NOTREADY))) {
srcp = &ia->ia_addr.sin6_addr; src6 = ia->ia_addr.sin6_addr;
srcp = &src6;
if (m->m_pkthdr.rcvif != NULL) {
/* XXX: This may not be the outgoing interface */
hlim = ND_IFINFO(m->m_pkthdr.rcvif)->chlim;
} else
hlim = V_ip6_defhlim;
}
if (ia != NULL)
ifa_free(&ia->ia_ifa);
} }
if (srcp == NULL) { if (srcp == NULL) {
int e; int error;
struct sockaddr_in6 sin6; struct in6_addr dst6;
uint32_t scopeid;
/* /*
* This case matches to multicasts, our anycast, or unicasts * This case matches to multicasts, our anycast, or unicasts
* that we do not own. Select a source address based on the * that we do not own. Select a source address based on the
* source address of the erroneous packet. * source address of the erroneous packet.
*/ */
bzero(&sin6, sizeof(sin6)); in6_splitscope(&ip6->ip6_dst, &dst6, &scopeid);
sin6.sin6_family = AF_INET6; error = in6_selectsrc_addr(RT_DEFAULT_FIB, &dst6,
sin6.sin6_len = sizeof(sin6); scopeid, NULL, &src6, &hlim);
sin6.sin6_addr = ip6->ip6_dst; /* zone ID should be embedded */
e = in6_selectsrc(&sin6, NULL, NULL, NULL, &outif, &src); if (error) {
if (e) {
char ip6buf[INET6_ADDRSTRLEN]; char ip6buf[INET6_ADDRSTRLEN];
nd6log((LOG_DEBUG, nd6log((LOG_DEBUG,
"icmp6_reflect: source can't be determined: " "icmp6_reflect: source can't be determined: "
"dst=%s, error=%d\n", "dst=%s, error=%d\n",
ip6_sprintf(ip6buf, &sin6.sin6_addr), e)); ip6_sprintf(ip6buf, &ip6->ip6_dst), error));
goto bad; goto bad;
} }
srcp = &src; srcp = &src6;
} }
/* /*
* ip6_input() drops a packet if its src is multicast. * ip6_input() drops a packet if its src is multicast.
@ -2216,13 +2227,7 @@ icmp6_reflect(struct mbuf *m, size_t off)
ip6->ip6_vfc &= ~IPV6_VERSION_MASK; ip6->ip6_vfc &= ~IPV6_VERSION_MASK;
ip6->ip6_vfc |= IPV6_VERSION; ip6->ip6_vfc |= IPV6_VERSION;
ip6->ip6_nxt = IPPROTO_ICMPV6; ip6->ip6_nxt = IPPROTO_ICMPV6;
if (outif) ip6->ip6_hlim = hlim;
ip6->ip6_hlim = ND_IFINFO(outif)->chlim;
else if (m->m_pkthdr.rcvif) {
/* XXX: This may not be the outgoing interface */
ip6->ip6_hlim = ND_IFINFO(m->m_pkthdr.rcvif)->chlim;
} else
ip6->ip6_hlim = V_ip6_defhlim;
icmp6->icmp6_cksum = 0; icmp6->icmp6_cksum = 0;
icmp6->icmp6_cksum = in6_cksum(m, IPPROTO_ICMPV6, icmp6->icmp6_cksum = in6_cksum(m, IPPROTO_ICMPV6,
@ -2238,13 +2243,9 @@ icmp6_reflect(struct mbuf *m, size_t off)
if (outif) if (outif)
icmp6_ifoutstat_inc(outif, type, code); icmp6_ifoutstat_inc(outif, type, code);
if (ia != NULL)
ifa_free(&ia->ia_ifa);
return; return;
bad: bad:
if (ia != NULL)
ifa_free(&ia->ia_ifa);
m_freem(m); m_freem(m);
return; return;
} }

View File

@ -241,6 +241,13 @@ fib6_lookup_nh_ext(uint32_t fibnum, const struct in6_addr *dst,uint32_t scopeid,
rn = rh->rnh_matchaddr((void *)&sin6, rh); rn = rh->rnh_matchaddr((void *)&sin6, rh);
if (rn != NULL && ((rn->rn_flags & RNF_ROOT) == 0)) { if (rn != NULL && ((rn->rn_flags & RNF_ROOT) == 0)) {
rte = RNTORT(rn); rte = RNTORT(rn);
#ifdef RADIX_MPATH
rte = rt_mpath_select(rte, flowid);
if (rte == NULL) {
RADIX_NODE_HEAD_RUNLOCK(rh);
return (ENOENT);
}
#endif
/* Ensure route & ifp is UP */ /* Ensure route & ifp is UP */
if (RT_LINK_IS_UP(rte->rt_ifp)) { if (RT_LINK_IS_UP(rte->rt_ifp)) {
fib6_rte_to_nh_extended(rte, &sin6.sin6_addr, flags, fib6_rte_to_nh_extended(rte, &sin6.sin6_addr, flags,

View File

@ -328,7 +328,6 @@ in6_pcbladdr(register struct inpcb *inp, struct sockaddr *nam,
{ {
register struct sockaddr_in6 *sin6 = (struct sockaddr_in6 *)nam; register struct sockaddr_in6 *sin6 = (struct sockaddr_in6 *)nam;
int error = 0; int error = 0;
struct ifnet *ifp = NULL;
int scope_ambiguous = 0; int scope_ambiguous = 0;
struct in6_addr in6a; struct in6_addr in6a;
@ -358,20 +357,15 @@ in6_pcbladdr(register struct inpcb *inp, struct sockaddr *nam,
if ((error = prison_remote_ip6(inp->inp_cred, &sin6->sin6_addr)) != 0) if ((error = prison_remote_ip6(inp->inp_cred, &sin6->sin6_addr)) != 0)
return (error); return (error);
error = in6_selectsrc(sin6, inp->in6p_outputopts, error = in6_selectsrc_socket(sin6, inp->in6p_outputopts,
inp, inp->inp_cred, &ifp, &in6a); inp, inp->inp_cred, scope_ambiguous, &in6a, NULL);
if (error) if (error)
return (error); return (error);
if (ifp && scope_ambiguous &&
(error = in6_setscope(&sin6->sin6_addr, ifp, NULL)) != 0) {
return(error);
}
/* /*
* Do not update this earlier, in case we return with an error. * Do not update this earlier, in case we return with an error.
* *
* XXX: this in6_selectsrc result might replace the bound local * XXX: this in6_selectsrc_socket result might replace the bound local
* address with the address specified by setsockopt(IPV6_PKTINFO). * address with the address specified by setsockopt(IPV6_PKTINFO).
* Is it the intended behavior? * Is it the intended behavior?
*/ */

View File

@ -107,7 +107,6 @@ in6_addroute(void *v_arg, void *n_arg, struct radix_node_head *head,
{ {
struct rtentry *rt = (struct rtentry *)treenodes; struct rtentry *rt = (struct rtentry *)treenodes;
struct sockaddr_in6 *sin6 = (struct sockaddr_in6 *)rt_key(rt); struct sockaddr_in6 *sin6 = (struct sockaddr_in6 *)rt_key(rt);
struct radix_node *ret;
RADIX_NODE_HEAD_WLOCK_ASSERT(head); RADIX_NODE_HEAD_WLOCK_ASSERT(head);
if (IN6_IS_ADDR_MULTICAST(&sin6->sin6_addr)) if (IN6_IS_ADDR_MULTICAST(&sin6->sin6_addr))
@ -148,34 +147,7 @@ in6_addroute(void *v_arg, void *n_arg, struct radix_node_head *head,
rt->rt_mtu = IN6_LINKMTU(rt->rt_ifp); rt->rt_mtu = IN6_LINKMTU(rt->rt_ifp);
} }
ret = rn_addroute(v_arg, n_arg, head, treenodes); return (rn_addroute(v_arg, n_arg, head, treenodes));
if (ret == NULL) {
struct rtentry *rt2;
/*
* We are trying to add a net route, but can't.
* The following case should be allowed, so we'll make a
* special check for this:
* Two IPv6 addresses with the same prefix is assigned
* to a single interrface.
* # ifconfig if0 inet6 3ffe:0501::1 prefix 64 alias (*1)
* # ifconfig if0 inet6 3ffe:0501::2 prefix 64 alias (*2)
* In this case, (*1) and (*2) want to add the same
* net route entry, 3ffe:0501:: -> if0.
* This case should not raise an error.
*/
rt2 = in6_rtalloc1((struct sockaddr *)sin6, 0, RTF_RNH_LOCKED,
rt->rt_fibnum);
if (rt2) {
if (((rt2->rt_flags & (RTF_HOST|RTF_GATEWAY)) == 0)
&& rt2->rt_gateway
&& rt2->rt_gateway->sa_family == AF_LINK
&& rt2->rt_ifp == rt->rt_ifp) {
ret = rt2->rt_nodes;
}
RTFREE_LOCKED(rt2);
}
}
return (ret);
} }
/* /*

View File

@ -136,6 +136,9 @@ static int selectroute(struct sockaddr_in6 *, struct ip6_pktopts *,
static int in6_selectif(struct sockaddr_in6 *, struct ip6_pktopts *, static int in6_selectif(struct sockaddr_in6 *, struct ip6_pktopts *,
struct ip6_moptions *, struct ifnet **, struct ip6_moptions *, struct ifnet **,
struct ifnet *, u_int); struct ifnet *, u_int);
static int in6_selectsrc(uint32_t, struct sockaddr_in6 *,
struct ip6_pktopts *, struct inpcb *, struct ucred *,
struct ifnet **, struct in6_addr *);
static struct in6_addrpolicy *lookup_addrsel_policy(struct sockaddr_in6 *); static struct in6_addrpolicy *lookup_addrsel_policy(struct sockaddr_in6 *);
@ -175,9 +178,9 @@ static struct in6_addrpolicy *match_addrsel_policy(struct sockaddr_in6 *);
goto out; /* XXX: we can't use 'break' here */ \ goto out; /* XXX: we can't use 'break' here */ \
} while(0) } while(0)
int static int
in6_selectsrc(struct sockaddr_in6 *dstsock, struct ip6_pktopts *opts, in6_selectsrc(uint32_t fibnum, struct sockaddr_in6 *dstsock,
struct inpcb *inp, struct ucred *cred, struct ip6_pktopts *opts, struct inpcb *inp, struct ucred *cred,
struct ifnet **ifpp, struct in6_addr *srcp) struct ifnet **ifpp, struct in6_addr *srcp)
{ {
struct rm_priotracker in6_ifa_tracker; struct rm_priotracker in6_ifa_tracker;
@ -228,7 +231,7 @@ in6_selectsrc(struct sockaddr_in6 *dstsock, struct ip6_pktopts *opts,
/* get the outgoing interface */ /* get the outgoing interface */
if ((error = in6_selectif(dstsock, opts, mopts, &ifp, oifp, if ((error = in6_selectif(dstsock, opts, mopts, &ifp, oifp,
(inp != NULL) ? inp->inp_inc.inc_fibnum : RT_DEFAULT_FIB)) fibnum))
!= 0) != 0)
return (error); return (error);
@ -544,6 +547,79 @@ in6_selectsrc(struct sockaddr_in6 *dstsock, struct ip6_pktopts *opts,
return (0); return (0);
} }
/*
* Select source address based on @inp, @dstsock and @opts.
* Stores selected address to @srcp. If @scope_ambiguous is set,
* embed scope from selected outgoing interface. If @hlim pointer
* is provided, stores calculated hop limit there.
* Returns 0 on success.
*/
int
in6_selectsrc_socket(struct sockaddr_in6 *dstsock, struct ip6_pktopts *opts,
struct inpcb *inp, struct ucred *cred, int scope_ambiguous,
struct in6_addr *srcp, int *hlim)
{
struct ifnet *retifp;
uint32_t fibnum;
int error;
fibnum = (inp != NULL) ? inp->inp_inc.inc_fibnum : RT_DEFAULT_FIB;
retifp = NULL;
error = in6_selectsrc(fibnum, dstsock, opts, inp, cred, &retifp, srcp);
if (error != 0)
return (error);
if (hlim != NULL)
*hlim = in6_selecthlim(inp, retifp);
if (retifp == NULL || scope_ambiguous == 0)
return (0);
/*
* Application should provide a proper zone ID or the use of
* default zone IDs should be enabled. Unfortunately, some
* applications do not behave as it should, so we need a
* workaround. Even if an appropriate ID is not determined
* (when it's required), if we can determine the outgoing
* interface. determine the zone ID based on the interface.
*/
error = in6_setscope(&dstsock->sin6_addr, retifp, NULL);
return (error);
}
/*
* Select source address based on @fibnum, @dst and @scopeid.
* Stores selected address to @srcp.
* Returns 0 on success.
*
* Used by non-socket based consumers (ND code mostly)
*/
int
in6_selectsrc_addr(uint32_t fibnum, const struct in6_addr *dst,
uint32_t scopeid, struct ifnet *ifp, struct in6_addr *srcp,
int *hlim)
{
struct ifnet *retifp;
struct sockaddr_in6 dst_sa;
int error;
retifp = ifp;
bzero(&dst_sa, sizeof(dst_sa));
dst_sa.sin6_family = AF_INET6;
dst_sa.sin6_len = sizeof(dst_sa);
dst_sa.sin6_addr = *dst;
dst_sa.sin6_scope_id = scopeid;
sa6_embedscope(&dst_sa, 0);
error = in6_selectsrc(fibnum, &dst_sa, NULL, NULL, NULL, &retifp, srcp);
if (hlim != NULL)
*hlim = in6_selecthlim(NULL, retifp);
return (error);
}
/* /*
* clone - meaningful only for bsdi and freebsd * clone - meaningful only for bsdi and freebsd
*/ */

View File

@ -418,9 +418,10 @@ int rip6_usrreq(struct socket *,
int dest6_input(struct mbuf **, int *, int); int dest6_input(struct mbuf **, int *, int);
int none_input(struct mbuf **, int *, int); int none_input(struct mbuf **, int *, int);
int in6_selectsrc(struct sockaddr_in6 *, struct ip6_pktopts *, int in6_selectsrc_socket(struct sockaddr_in6 *, struct ip6_pktopts *,
struct inpcb *inp, struct ucred *cred, struct inpcb *, struct ucred *, int, struct in6_addr *, int *);
struct ifnet **, struct in6_addr *); int in6_selectsrc_addr(uint32_t, const struct in6_addr *,
uint32_t, struct ifnet *, struct in6_addr *, int *);
int in6_selectroute(struct sockaddr_in6 *, struct ip6_pktopts *, int in6_selectroute(struct sockaddr_in6 *, struct ip6_pktopts *,
struct ip6_moptions *, struct route_in6 *, struct ifnet **, struct ip6_moptions *, struct route_in6 *, struct ifnet **,
struct rtentry **); struct rtentry **);

View File

@ -481,27 +481,21 @@ nd6_ns_output_fib(struct ifnet *ifp, const struct in6_addr *saddr6,
ifa_free(ifa); ifa_free(ifa);
} else { } else {
int error; int error;
struct sockaddr_in6 dst_sa; struct in6_addr dst6, src6;
struct in6_addr src_in; uint32_t scopeid;
struct ifnet *oifp;
bzero(&dst_sa, sizeof(dst_sa)); in6_splitscope(&ip6->ip6_dst, &dst6, &scopeid);
dst_sa.sin6_family = AF_INET6; error = in6_selectsrc_addr(RT_DEFAULT_FIB, &dst6,
dst_sa.sin6_len = sizeof(dst_sa); scopeid, ifp, &src6, NULL);
dst_sa.sin6_addr = ip6->ip6_dst;
oifp = ifp;
error = in6_selectsrc(&dst_sa, NULL,
NULL, NULL, &oifp, &src_in);
if (error) { if (error) {
char ip6buf[INET6_ADDRSTRLEN]; char ip6buf[INET6_ADDRSTRLEN];
nd6log((LOG_DEBUG, "%s: source can't be " nd6log((LOG_DEBUG, "%s: source can't be "
"determined: dst=%s, error=%d\n", __func__, "determined: dst=%s, error=%d\n", __func__,
ip6_sprintf(ip6buf, &dst_sa.sin6_addr), ip6_sprintf(ip6buf, &dst6),
error)); error));
goto bad; goto bad;
} }
ip6->ip6_src = src_in; ip6->ip6_src = src6;
} }
} else { } else {
/* /*
@ -941,12 +935,12 @@ nd6_na_output_fib(struct ifnet *ifp, const struct in6_addr *daddr6_0,
{ {
struct mbuf *m; struct mbuf *m;
struct m_tag *mtag; struct m_tag *mtag;
struct ifnet *oifp;
struct ip6_hdr *ip6; struct ip6_hdr *ip6;
struct nd_neighbor_advert *nd_na; struct nd_neighbor_advert *nd_na;
struct ip6_moptions im6o; struct ip6_moptions im6o;
struct in6_addr src, daddr6; struct in6_addr daddr6, dst6, src6;
struct sockaddr_in6 dst_sa; uint32_t scopeid;
int icmp6len, maxlen, error; int icmp6len, maxlen, error;
caddr_t mac = NULL; caddr_t mac = NULL;
@ -998,24 +992,21 @@ nd6_na_output_fib(struct ifnet *ifp, const struct in6_addr *daddr6_0,
flags &= ~ND_NA_FLAG_SOLICITED; flags &= ~ND_NA_FLAG_SOLICITED;
} }
ip6->ip6_dst = daddr6; ip6->ip6_dst = daddr6;
bzero(&dst_sa, sizeof(struct sockaddr_in6));
dst_sa.sin6_family = AF_INET6;
dst_sa.sin6_len = sizeof(struct sockaddr_in6);
dst_sa.sin6_addr = daddr6;
/* /*
* Select a source whose scope is the same as that of the dest. * Select a source whose scope is the same as that of the dest.
*/ */
oifp = ifp; in6_splitscope(&daddr6, &dst6, &scopeid);
error = in6_selectsrc(&dst_sa, NULL, NULL, NULL, &oifp, &src); error = in6_selectsrc_addr(RT_DEFAULT_FIB, &dst6,
scopeid, ifp, &src6, NULL);
if (error) { if (error) {
char ip6buf[INET6_ADDRSTRLEN]; char ip6buf[INET6_ADDRSTRLEN];
nd6log((LOG_DEBUG, "nd6_na_output: source can't be " nd6log((LOG_DEBUG, "nd6_na_output: source can't be "
"determined: dst=%s, error=%d\n", "determined: dst=%s, error=%d\n",
ip6_sprintf(ip6buf, &dst_sa.sin6_addr), error)); ip6_sprintf(ip6buf, &daddr6), error));
goto bad; goto bad;
} }
ip6->ip6_src = src; ip6->ip6_src = src6;
nd_na = (struct nd_neighbor_advert *)(ip6 + 1); nd_na = (struct nd_neighbor_advert *)(ip6 + 1);
nd_na->nd_na_type = ND_NEIGHBOR_ADVERT; nd_na->nd_na_type = ND_NEIGHBOR_ADVERT;
nd_na->nd_na_code = 0; nd_na->nd_na_code = 0;

View File

@ -397,6 +397,7 @@ rip6_output(struct mbuf *m, struct socket *so, ...)
int type = 0, code = 0; /* for ICMPv6 output statistics only */ int type = 0, code = 0; /* for ICMPv6 output statistics only */
int scope_ambiguous = 0; int scope_ambiguous = 0;
int use_defzone = 0; int use_defzone = 0;
int hlim = 0;
struct in6_addr in6a; struct in6_addr in6a;
va_list ap; va_list ap;
@ -460,8 +461,9 @@ rip6_output(struct mbuf *m, struct socket *so, ...)
/* /*
* Source address selection. * Source address selection.
*/ */
error = in6_selectsrc(dstsock, optp, in6p, so->so_cred, error = in6_selectsrc_socket(dstsock, optp, in6p, so->so_cred,
&oifp, &in6a); scope_ambiguous, &in6a, &hlim);
if (error) if (error)
goto bad; goto bad;
error = prison_check_ip6(in6p->inp_cred, &in6a); error = prison_check_ip6(in6p->inp_cred, &in6a);
@ -469,19 +471,6 @@ rip6_output(struct mbuf *m, struct socket *so, ...)
goto bad; goto bad;
ip6->ip6_src = in6a; ip6->ip6_src = in6a;
if (oifp && scope_ambiguous) {
/*
* Application should provide a proper zone ID or the use of
* default zone IDs should be enabled. Unfortunately, some
* applications do not behave as it should, so we need a
* workaround. Even if an appropriate ID is not determined
* (when it's required), if we can determine the outgoing
* interface. determine the zone ID based on the interface.
*/
error = in6_setscope(&dstsock->sin6_addr, oifp, NULL);
if (error != 0)
goto bad;
}
ip6->ip6_dst = dstsock->sin6_addr; ip6->ip6_dst = dstsock->sin6_addr;
/* /*
@ -496,7 +485,7 @@ rip6_output(struct mbuf *m, struct socket *so, ...)
* ip6_plen will be filled in ip6_output, so not fill it here. * ip6_plen will be filled in ip6_output, so not fill it here.
*/ */
ip6->ip6_nxt = in6p->inp_ip_p; ip6->ip6_nxt = in6p->inp_ip_p;
ip6->ip6_hlim = in6_selecthlim(in6p, oifp); ip6->ip6_hlim = hlim;
if (so->so_proto->pr_protocol == IPPROTO_ICMPV6 || if (so->so_proto->pr_protocol == IPPROTO_ICMPV6 ||
in6p->in6p_cksum != -1) { in6p->in6p_cksum != -1) {
@ -784,7 +773,6 @@ rip6_connect(struct socket *so, struct sockaddr *nam, struct thread *td)
struct inpcb *inp; struct inpcb *inp;
struct sockaddr_in6 *addr = (struct sockaddr_in6 *)nam; struct sockaddr_in6 *addr = (struct sockaddr_in6 *)nam;
struct in6_addr in6a; struct in6_addr in6a;
struct ifnet *ifp = NULL;
int error = 0, scope_ambiguous = 0; int error = 0, scope_ambiguous = 0;
inp = sotoinpcb(so); inp = sotoinpcb(so);
@ -813,21 +801,14 @@ rip6_connect(struct socket *so, struct sockaddr *nam, struct thread *td)
INP_INFO_WLOCK(&V_ripcbinfo); INP_INFO_WLOCK(&V_ripcbinfo);
INP_WLOCK(inp); INP_WLOCK(inp);
/* Source address selection. XXX: need pcblookup? */ /* Source address selection. XXX: need pcblookup? */
error = in6_selectsrc(addr, inp->in6p_outputopts, error = in6_selectsrc_socket(addr, inp->in6p_outputopts,
inp, so->so_cred, &ifp, &in6a); inp, so->so_cred, scope_ambiguous, &in6a, NULL);
if (error) { if (error) {
INP_WUNLOCK(inp); INP_WUNLOCK(inp);
INP_INFO_WUNLOCK(&V_ripcbinfo); INP_INFO_WUNLOCK(&V_ripcbinfo);
return (error); return (error);
} }
/* XXX: see above */
if (ifp && scope_ambiguous &&
(error = in6_setscope(&addr->sin6_addr, ifp, NULL)) != 0) {
INP_WUNLOCK(inp);
INP_INFO_WUNLOCK(&V_ripcbinfo);
return (error);
}
inp->in6p_faddr = addr->sin6_addr; inp->in6p_faddr = addr->sin6_addr;
inp->in6p_laddr = in6a; inp->in6p_laddr = in6a;
soisconnected(so); soisconnected(so);

View File

@ -631,7 +631,6 @@ udp6_output(struct inpcb *inp, struct mbuf *m, struct sockaddr *addr6,
struct udphdr *udp6; struct udphdr *udp6;
struct in6_addr *laddr, *faddr, in6a; struct in6_addr *laddr, *faddr, in6a;
struct sockaddr_in6 *sin6 = NULL; struct sockaddr_in6 *sin6 = NULL;
struct ifnet *oifp = NULL;
int cscov_partial = 0; int cscov_partial = 0;
int scope_ambiguous = 0; int scope_ambiguous = 0;
u_short fport; u_short fport;
@ -731,15 +730,10 @@ udp6_output(struct inpcb *inp, struct mbuf *m, struct sockaddr *addr6,
} }
if (!IN6_IS_ADDR_V4MAPPED(faddr)) { if (!IN6_IS_ADDR_V4MAPPED(faddr)) {
error = in6_selectsrc(sin6, optp, inp, error = in6_selectsrc_socket(sin6, optp, inp,
td->td_ucred, &oifp, &in6a); td->td_ucred, scope_ambiguous, &in6a, NULL);
if (error) if (error)
goto release; goto release;
if (oifp && scope_ambiguous &&
(error = in6_setscope(&sin6->sin6_addr,
oifp, NULL))) {
goto release;
}
laddr = &in6a; laddr = &in6a;
} else } else
laddr = &inp->in6p_laddr; /* XXX */ laddr = &inp->in6p_laddr; /* XXX */

View File

@ -2097,7 +2097,7 @@ export_table_info(struct ip_fw_chain *ch, struct table_config *tc,
i->count = table_get_count(ch, tc); i->count = table_get_count(ch, tc);
i->limit = tc->limit; i->limit = tc->limit;
i->flags |= (tc->locked != 0) ? IPFW_TGFLAGS_LOCKED : 0; i->flags |= (tc->locked != 0) ? IPFW_TGFLAGS_LOCKED : 0;
i->size = tc->count * sizeof(ipfw_obj_tentry); i->size = i->count * sizeof(ipfw_obj_tentry);
i->size += sizeof(ipfw_obj_header) + sizeof(ipfw_xtable_info); i->size += sizeof(ipfw_obj_header) + sizeof(ipfw_xtable_info);
strlcpy(i->tablename, tc->tablename, sizeof(i->tablename)); strlcpy(i->tablename, tc->tablename, sizeof(i->tablename));
ti = KIDX_TO_TI(ch, tc->no.kidx); ti = KIDX_TO_TI(ch, tc->no.kidx);

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