Merge ^/head r293430 through r293685.
This commit is contained in:
commit
79c349e677
@ -570,9 +570,8 @@ _worldtmp: .PHONY
|
||||
.else
|
||||
rm -rf ${WORLDTMP}/legacy/usr/include
|
||||
# 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/truss/ioctl.c
|
||||
.endif
|
||||
.for _dir in \
|
||||
lib usr legacy/bin legacy/usr
|
||||
@ -1425,11 +1424,13 @@ _vtfontcvt= usr.bin/vtfontcvt
|
||||
_sed= usr.bin/sed
|
||||
.endif
|
||||
|
||||
.if ${BOOTSTRAPPING} < 1000002
|
||||
.if ${BOOTSTRAPPING} < 1000033
|
||||
_libopenbsd= lib/libopenbsd
|
||||
_m4= usr.bin/m4
|
||||
_lex= usr.bin/lex
|
||||
|
||||
${_bt}-usr.bin/m4: ${_bt}-lib/libopenbsd
|
||||
${_bt}-usr.bin/lex: ${_bt}-usr.bin/m4
|
||||
.endif
|
||||
|
||||
.if ${BOOTSTRAPPING} < 1000026
|
||||
@ -1443,12 +1444,6 @@ ${_bt}-usr.sbin/nmtree: ${_bt}-lib/libnetbsd
|
||||
_cat= bin/cat
|
||||
.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
|
||||
# r281674 crunchide: always include both 32- and 64-bit ELF support
|
||||
# r285986 crunchen: use STRIPBIN rather than STRIP
|
||||
|
@ -1039,12 +1039,12 @@ evalcommand(union node *cmd, int flags, struct backcmd *backcmd)
|
||||
reffunc(cmdentry.u.func);
|
||||
savehandler = handler;
|
||||
if (setjmp(jmploc.loc)) {
|
||||
freeparam(&shellparam);
|
||||
shellparam = saveparam;
|
||||
popredir();
|
||||
unreffunc(cmdentry.u.func);
|
||||
poplocalvars();
|
||||
localvars = savelocalvars;
|
||||
freeparam(&shellparam);
|
||||
shellparam = saveparam;
|
||||
funcnest--;
|
||||
handler = savehandler;
|
||||
longjmp(handler->loc, 1);
|
||||
|
@ -111,6 +111,7 @@ FILES+= local1.0
|
||||
FILES+= local2.0
|
||||
FILES+= local3.0
|
||||
FILES+= local4.0
|
||||
FILES+= local5.0
|
||||
.if ${MK_NLS} != "no"
|
||||
FILES+= locale1.0
|
||||
.endif
|
||||
|
15
bin/sh/tests/builtins/local5.0
Normal file
15
bin/sh/tests/builtins/local5.0
Normal 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" ]
|
11
bin/sh/var.c
11
bin/sh/var.c
@ -791,6 +791,7 @@ poplocalvars(void)
|
||||
{
|
||||
struct localvar *lvp;
|
||||
struct var *vp;
|
||||
int islocalevar;
|
||||
|
||||
INTOFF;
|
||||
while ((lvp = localvars) != NULL) {
|
||||
@ -803,10 +804,20 @@ poplocalvars(void)
|
||||
} else if ((lvp->flags & (VUNSET|VSTRFIXED)) == VUNSET) {
|
||||
(void)unsetvar(vp->text);
|
||||
} else {
|
||||
islocalevar = (vp->flags | lvp->flags) & VEXPORT &&
|
||||
localevar(lvp->text);
|
||||
if ((vp->flags & VTEXTFIXED) == 0)
|
||||
ckfree(vp->text);
|
||||
vp->flags = lvp->flags;
|
||||
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);
|
||||
}
|
||||
|
@ -1437,7 +1437,7 @@ main(int argc, char *argv[])
|
||||
|
||||
|
||||
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",
|
||||
r, hv_kvp_poll_fd[0].revents);
|
||||
|
@ -2,6 +2,9 @@
|
||||
|
||||
GCCDIR= ${.CURDIR}/../../../contrib/gcc
|
||||
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
|
||||
SHLIBDIR?= /lib
|
||||
@ -67,8 +70,37 @@ LIB2ADD = $(LIB2FUNCS_EXTRA)
|
||||
LIB2ADD_ST = $(LIB2FUNCS_STATIC_EXTRA)
|
||||
|
||||
# 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 \
|
||||
unwind-c.c
|
||||
.endif
|
||||
|
||||
.endif # MK_LLVM_LIBUNWIND
|
||||
|
||||
LIB2ADDEHSTATIC = $(LIB2ADDEH)
|
||||
LIB2ADDEHSHARED = $(LIB2ADDEH)
|
||||
|
||||
@ -116,7 +148,6 @@ CFLAGS.clang+= -fheinous-gnu-extensions
|
||||
|
||||
LIB1ASMSRC = lib1funcs.asm
|
||||
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
|
||||
LIBADD+= compiler_rt
|
||||
.endif
|
||||
@ -160,7 +191,10 @@ LIB2_DIVMOD_FUNCS:= ${LIB2_DIVMOD_FUNCS:S/${sym}//g}
|
||||
.endfor
|
||||
.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_P = ${CC} -c ${CFLAGS} ${HIDE} -p -fPIC
|
||||
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
|
||||
SOBJS += ${EH_OBJS_S}
|
||||
|
||||
.for _src in ${LIB2ADDEHSTATIC}
|
||||
.for _src in ${LIB2ADDEHSTATIC:M*.c}
|
||||
${_src:R:S/$/.o/}: ${_src} ${COMMONHDRS}
|
||||
${CC_T} ${EH_CFLAGS} -o ${.TARGET} ${.IMPSRC}
|
||||
${_src:R:S/$/.po/}: ${_src} ${COMMONHDRS}
|
||||
${CC_P} ${EH_CFLAGS} -o ${.TARGET} ${.IMPSRC}
|
||||
.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}
|
||||
${CC_S} ${EH_CFLAGS} -o ${.TARGET} ${.IMPSRC}
|
||||
.endfor
|
||||
.for _src in ${LIB2ADDEHSHARED:M*.cpp}
|
||||
${_src:R:S/$/.So/}: ${_src} ${COMMONHDRS}
|
||||
${CXX_S} ${EH_CFLAGS} -o ${.TARGET} ${.IMPSRC}
|
||||
.endfor
|
||||
|
||||
|
||||
#-----------------------------------------------------------------------
|
||||
|
@ -59,10 +59,12 @@
|
||||
#define _POSIX_TZNAME_MAX 3
|
||||
#endif
|
||||
|
||||
#if __POSIX_VISIBLE >= 200112
|
||||
#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_SCALE_MAX 99 /* max scale value 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 EXPR_NEST_MAX 32 /* max expressions nested in expr(1) */
|
||||
#define LINE_MAX 2048 /* max bytes in an input line */
|
||||
@ -72,11 +74,14 @@
|
||||
#define _POSIX2_BC_DIM_MAX 2048
|
||||
#define _POSIX2_BC_SCALE_MAX 99
|
||||
#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_EXPR_NEST_MAX 32
|
||||
#define _POSIX2_LINE_MAX 2048
|
||||
#define _POSIX2_RE_DUP_MAX 255
|
||||
#endif
|
||||
#endif
|
||||
|
||||
#if __POSIX_VISIBLE >= 199309
|
||||
#define _POSIX_AIO_LISTIO_MAX 2
|
||||
@ -110,8 +115,6 @@
|
||||
#define _POSIX_TRACE_SYS_MAX 8
|
||||
#define _POSIX_TRACE_USER_EVENT_MAX 32
|
||||
#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
|
||||
#endif
|
||||
|
@ -7,6 +7,7 @@ OBJS= ${SRCS:N*.h:R:S/$/.o/g}
|
||||
OBJS+= Scrt1.o gcrt1.o
|
||||
CFLAGS+= -I${.CURDIR}/../common \
|
||||
-I${.CURDIR}/../../libc/include
|
||||
STATIC_CFLAGS+= -mlong-calls
|
||||
|
||||
FILES= ${OBJS}
|
||||
FILESMODE= ${LIBMODE}
|
||||
@ -23,14 +24,14 @@ CLEANFILES+= crt1.s gcrt1.s Scrt1.s
|
||||
# directly compiled to .o files.
|
||||
|
||||
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}
|
||||
|
||||
crt1.o: crt1.s
|
||||
${CC} ${ACFLAGS} -c -o ${.TARGET} crt1.s
|
||||
|
||||
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}
|
||||
|
||||
gcrt1.o: gcrt1.s
|
||||
|
@ -25,7 +25,7 @@
|
||||
.\"
|
||||
.\" $FreeBSD$
|
||||
.\"
|
||||
.Dd January 7, 2010
|
||||
.Dd January 7, 2016
|
||||
.Dt SENDFILE 2
|
||||
.Os
|
||||
.Sh NAME
|
||||
@ -46,7 +46,7 @@
|
||||
The
|
||||
.Fn sendfile
|
||||
system call
|
||||
sends a regular file specified by descriptor
|
||||
sends a regular file or shared memory object specified by descriptor
|
||||
.Fa fd
|
||||
out a stream socket specified by descriptor
|
||||
.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
|
||||
.Fa sbytes .
|
||||
.Pp
|
||||
The
|
||||
The least significant 16 bits of
|
||||
.Fa flags
|
||||
argument is a bitmap of these values:
|
||||
.Bl -item -offset indent
|
||||
.It
|
||||
.Dv SF_NODISKIO .
|
||||
This flag causes any
|
||||
.Fn sendfile
|
||||
call which would block on disk I/O to instead
|
||||
return
|
||||
.Er EBUSY .
|
||||
Busy servers may benefit by transferring requests that would
|
||||
block to a separate I/O worker thread.
|
||||
.It
|
||||
.Dv SF_MNOWAIT .
|
||||
Do not wait for some kernel resource to become available,
|
||||
in particular,
|
||||
.Vt mbuf
|
||||
and
|
||||
.Vt sf_buf .
|
||||
The flag does not make the
|
||||
.Fn sendfile
|
||||
syscall truly non-blocking, since other resources are still allocated
|
||||
in a blocking fashion.
|
||||
.It
|
||||
.Dv SF_SYNC .
|
||||
.Bl -tag -offset indent
|
||||
.It Dv SF_NODISKIO
|
||||
This flag causes
|
||||
.Nm
|
||||
to return
|
||||
.Er EBUSY
|
||||
instead of blocking when a busy page is encountered.
|
||||
This rare situation can happen if some other process is now working
|
||||
with the same region of the file.
|
||||
It is advised to retry the operation after a short period.
|
||||
.Pp
|
||||
Note that in older
|
||||
.Fx
|
||||
versions the
|
||||
.Dv SF_NODISKIO
|
||||
had slightly different notion.
|
||||
The flag prevented
|
||||
.Nm
|
||||
to run I/O operations in case if an invalid (not cached) page is encountered,
|
||||
thus avoiding blocking on I/O.
|
||||
Starting with
|
||||
.Fx 11
|
||||
.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
|
||||
sleeps until the network stack no longer references the VM pages
|
||||
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.
|
||||
.El
|
||||
.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,
|
||||
.Fn sendfile
|
||||
may send fewer bytes than requested.
|
||||
@ -149,6 +188,18 @@ The
|
||||
.Fx
|
||||
implementation of
|
||||
.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.
|
||||
.Sh TUNING
|
||||
On some architectures, this system call internally uses a special
|
||||
@ -232,12 +283,10 @@ The
|
||||
argument
|
||||
is not a valid socket descriptor.
|
||||
.It Bq Er EBUSY
|
||||
Completing the entire transfer would have required disk I/O, so
|
||||
it was aborted.
|
||||
Partial data may have been sent.
|
||||
(This error can only occur when
|
||||
A busy page was encountered and
|
||||
.Dv SF_NODISKIO
|
||||
is specified.)
|
||||
had been specified.
|
||||
Partial data may have been sent.
|
||||
.It Bq Er EFAULT
|
||||
An invalid address was specified for an argument.
|
||||
.It Bq Er EINTR
|
||||
@ -310,9 +359,19 @@ first appeared in
|
||||
.Fx 3.0 .
|
||||
This manual page first appeared in
|
||||
.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
|
||||
The
|
||||
The initial implementation of
|
||||
.Fn sendfile
|
||||
system call
|
||||
and this manual page were written by
|
||||
.An David G. Lawrence Aq Mt dg@dglawrence.com .
|
||||
The
|
||||
.Fx 11
|
||||
implementation was written by
|
||||
.An Gleb Smirnoff Aq Mt glebius@FreeBSD.org .
|
||||
|
@ -46,7 +46,7 @@ tohex(char **buf, int len, uint32_t val)
|
||||
char *walker = *buf;
|
||||
int i;
|
||||
|
||||
for (i = len - 1; i >= 0; i++) {
|
||||
for (i = len - 1; i >= 0; i--) {
|
||||
walker[i] = hexstr[val & 0xf];
|
||||
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[4]);
|
||||
tohex(&w, 2, u->node[5]);
|
||||
*w++ - '\0';
|
||||
*w++ = '\0';
|
||||
}
|
||||
|
@ -275,6 +275,7 @@ extra_chroot_setup() {
|
||||
PBUILD_FLAGS="${PBUILD_FLAGS} OSREL=${REVISION}"
|
||||
chroot ${CHROOTDIR} make -C /usr/ports/textproc/docproj \
|
||||
${PBUILD_FLAGS} OPTIONS_UNSET="FOP IGOR" \
|
||||
FORCE_PKG_REGISTER=1 \
|
||||
install clean distclean
|
||||
fi
|
||||
fi
|
||||
|
@ -33,7 +33,7 @@
|
||||
.\"
|
||||
.\" $FreeBSD$
|
||||
.\"
|
||||
.Dd May 9, 2014
|
||||
.Dd January 11, 2016
|
||||
.Dt ISMT 4
|
||||
.Os
|
||||
.Sh NAME
|
||||
@ -54,6 +54,6 @@ in the Intel Atom S1200 and C2000 CPUs.
|
||||
The
|
||||
.Nm
|
||||
driver first appeared in
|
||||
.Fx 11.0 .
|
||||
.Fx 10.3 .
|
||||
.Sh AUTHORS
|
||||
.An Jim Harris Aq Mt jimharris@FreeBSD.org
|
||||
|
@ -1,7 +1,7 @@
|
||||
.\" DO NOT EDIT-- this file is automatically generated.
|
||||
.\" from FreeBSD: head/tools/build/options/makeman 292283 2015-12-15 18:42:30Z bdrewery
|
||||
.\" $FreeBSD$
|
||||
.Dd December 15, 2015
|
||||
.Dd January 9, 2016
|
||||
.Dt SRC.CONF 5
|
||||
.Os
|
||||
.Sh NAME
|
||||
@ -948,9 +948,30 @@ Set to not build the
|
||||
.Nm libthr
|
||||
(1:1 threading)
|
||||
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
|
||||
.\" from FreeBSD: head/tools/build/options/WITH_LLDB 255722 2013-09-20 01:52:02Z emaste
|
||||
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
|
||||
.\" from FreeBSD: head/tools/build/options/WITHOUT_LOCALES 156932 2006-03-21 07:50:50Z ru
|
||||
Set to not build localization files; see
|
||||
|
@ -344,6 +344,7 @@ adrian -> loos
|
||||
adrian -> monthadar
|
||||
adrian -> ray
|
||||
adrian -> rmh
|
||||
adrian -> sephe
|
||||
|
||||
ae -> melifaro
|
||||
|
||||
@ -404,6 +405,7 @@ das -> rodrigc
|
||||
|
||||
delphij -> gabor
|
||||
delphij -> rafan
|
||||
delphij -> sephe
|
||||
|
||||
des -> anholt
|
||||
des -> hmp
|
||||
|
@ -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.
|
||||
.if ${__T} == "aarch64" || ${__T} == "riscv64"
|
||||
BROKEN_OPTIONS+=BINUTILS BINUTILS_BOOTSTRAP GCC GCC_BOOTSTRAP GDB
|
||||
__DEFAULT_YES_OPTIONS+=ELFCOPY_AS_OBJCOPY
|
||||
__DEFAULT_YES_OPTIONS+=ELFCOPY_AS_OBJCOPY LLVM_LIBUNWIND
|
||||
.else
|
||||
__DEFAULT_NO_OPTIONS+=ELFCOPY_AS_OBJCOPY
|
||||
__DEFAULT_NO_OPTIONS+=ELFCOPY_AS_OBJCOPY LLVM_LIBUNWIND
|
||||
.endif
|
||||
.if ${__T} == "riscv64"
|
||||
BROKEN_OPTIONS+=PROFILE # "sorry, unimplemented: profiler support for RISC-V"
|
||||
|
@ -80,6 +80,7 @@ struct sysentvec elf64_freebsd_sysvec = {
|
||||
.sv_shared_page_len = PAGE_SIZE,
|
||||
.sv_schedtail = NULL,
|
||||
.sv_thread_detach = NULL,
|
||||
.sv_trap = NULL,
|
||||
};
|
||||
INIT_SYSENTVEC(elf64_sysvec, &elf64_freebsd_sysvec);
|
||||
|
||||
|
@ -322,6 +322,13 @@ trap(struct trapframe *frame)
|
||||
break;
|
||||
|
||||
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;
|
||||
i = trap_pfault(frame, TRUE);
|
||||
if (i == -1)
|
||||
|
@ -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 void linux_exec_setregs(struct thread *td, struct image_params *imgp,
|
||||
u_long stack);
|
||||
static int linux_vsyscall(struct thread *td);
|
||||
|
||||
/*
|
||||
* 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);
|
||||
}
|
||||
|
||||
#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 = {
|
||||
.sv_size = LINUX_SYS_MAXSYSCALL,
|
||||
.sv_table = linux_sysent,
|
||||
@ -778,7 +826,8 @@ struct sysentvec elf_linux_sysvec = {
|
||||
.sv_shared_page_base = SHAREDPAGE,
|
||||
.sv_shared_page_len = PAGE_SIZE,
|
||||
.sv_schedtail = linux_schedtail,
|
||||
.sv_thread_detach = linux_thread_detach
|
||||
.sv_thread_detach = linux_thread_detach,
|
||||
.sv_trap = linux_vsyscall,
|
||||
};
|
||||
|
||||
static void
|
||||
|
@ -1040,6 +1040,7 @@ struct sysentvec elf_linux_sysvec = {
|
||||
.sv_shared_page_len = PAGE_SIZE,
|
||||
.sv_schedtail = linux_schedtail,
|
||||
.sv_thread_detach = linux_thread_detach,
|
||||
.sv_trap = NULL,
|
||||
};
|
||||
|
||||
static void
|
||||
|
@ -86,6 +86,7 @@ struct sysentvec elf32_freebsd_sysvec = {
|
||||
.sv_shared_page_len = PAGE_SIZE,
|
||||
.sv_schedtail = NULL,
|
||||
.sv_thread_detach = NULL,
|
||||
.sv_trap = NULL,
|
||||
};
|
||||
INIT_SYSENTVEC(elf32_sysvec, &elf32_freebsd_sysvec);
|
||||
|
||||
|
@ -87,6 +87,8 @@ static struct sysentvec elf64_freebsd_sysvec = {
|
||||
.sv_shared_page_base = SHAREDPAGE,
|
||||
.sv_shared_page_len = PAGE_SIZE,
|
||||
.sv_schedtail = NULL,
|
||||
.sv_thread_detach = NULL,
|
||||
.sv_trap = NULL,
|
||||
};
|
||||
INIT_SYSENTVEC(elf64_sysvec, &elf64_freebsd_sysvec);
|
||||
|
||||
|
@ -211,7 +211,6 @@ fsread(ufs_ino_t inode, void *buf, size_t nbyte)
|
||||
break;
|
||||
}
|
||||
if (sblock_try[n] == -1) {
|
||||
printf("Not ufs\n");
|
||||
return -1;
|
||||
}
|
||||
dsk_meta++;
|
||||
|
@ -41,14 +41,13 @@ CFLAGS+= -fPIC
|
||||
LDFLAGS+= -Wl,-znocombreloc
|
||||
.endif
|
||||
|
||||
.if ${MACHINE_CPUARCH} == "arm" || ${MACHINE_CPUARCH} == "i386"
|
||||
#
|
||||
# Add libstand for the runtime functions used by the compiler - for example
|
||||
# __aeabi_* (arm) or __divdi3 (i386).
|
||||
# as well as required string and memory functions for all platforms.
|
||||
#
|
||||
DPADD+= ${LIBSTAND}
|
||||
LDADD+= -lstand
|
||||
.endif
|
||||
|
||||
DPADD+= ${LDSCRIPT}
|
||||
|
||||
|
@ -24,6 +24,7 @@ __FBSDID("$FreeBSD$");
|
||||
#include <sys/dirent.h>
|
||||
#include <machine/elf.h>
|
||||
#include <machine/stdarg.h>
|
||||
#include <stand.h>
|
||||
|
||||
#include <efi.h>
|
||||
#include <eficonsctl.h>
|
||||
@ -33,28 +34,8 @@ __FBSDID("$FreeBSD$");
|
||||
|
||||
#define BSIZEMAX 16384
|
||||
|
||||
typedef int putc_func_t(char c, void *arg);
|
||||
|
||||
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);
|
||||
void panic(const char *fmt, ...) __dead2;
|
||||
void putchar(int c);
|
||||
|
||||
static int domount(EFI_DEVICE_PATH *device, EFI_BLOCK_IO *blkio, int quiet);
|
||||
static void load(const char *fname);
|
||||
@ -62,39 +43,6 @@ static void load(const char *fname);
|
||||
static EFI_SYSTEM_TABLE *systab;
|
||||
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 DevicePathGUID = DEVICE_PATH_PROTOCOL;
|
||||
static EFI_GUID LoadedImageGUID = LOADED_IMAGE_PROTOCOL;
|
||||
@ -250,7 +198,6 @@ fsstat(ufs_ino_t inode)
|
||||
break;
|
||||
}
|
||||
if (sblock_try[n] == -1) {
|
||||
printf("Not ufs\n");
|
||||
return -1;
|
||||
}
|
||||
dsk_meta++;
|
||||
@ -346,38 +293,22 @@ load(const char *fname)
|
||||
EFI_ERROR_CODE(status));
|
||||
}
|
||||
|
||||
static void
|
||||
void
|
||||
panic(const char *fmt, ...)
|
||||
{
|
||||
char buf[128];
|
||||
va_list ap;
|
||||
|
||||
printf("panic: ");
|
||||
va_start(ap, fmt);
|
||||
vsnprintf(buf, sizeof buf, fmt, ap);
|
||||
printf("panic: %s\n", buf);
|
||||
vprintf(fmt, ap);
|
||||
va_end(ap);
|
||||
printf("\n");
|
||||
|
||||
while (1) {}
|
||||
}
|
||||
|
||||
static int
|
||||
printf(const char *fmt, ...)
|
||||
{
|
||||
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)
|
||||
void
|
||||
putchar(int c)
|
||||
{
|
||||
CHAR16 buf[2];
|
||||
|
||||
@ -389,187 +320,4 @@ putchar(char c, void *arg)
|
||||
buf[0] = c;
|
||||
buf[1] = 0;
|
||||
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);
|
||||
}
|
||||
|
@ -296,7 +296,8 @@ extract_currdev(void)
|
||||
}
|
||||
|
||||
#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
|
||||
|
||||
env_setenv("currdev", EV_VOLATILE, i386_fmtdev(&new_currdev),
|
||||
@ -311,9 +312,14 @@ init_zfs_bootenv(char *currdev)
|
||||
{
|
||||
char *beroot;
|
||||
|
||||
if (strlen(currdev) == 0)
|
||||
return;
|
||||
if(strncmp(currdev, "zfs:", 4) != 0)
|
||||
return;
|
||||
/* Remove the trailing : */
|
||||
currdev[strlen(currdev) - 1] = '\0';
|
||||
setenv("zfs_be_active", currdev, 1);
|
||||
setenv("zfs_be_currpage", "1", 1);
|
||||
/* Do not overwrite if already set */
|
||||
setenv("vfs.root.mountfrom", currdev, 0);
|
||||
/* Forward past zfs: */
|
||||
@ -323,9 +329,7 @@ init_zfs_bootenv(char *currdev)
|
||||
beroot = strrchr(currdev, '/');
|
||||
if (beroot != NULL)
|
||||
beroot[0] = '\0';
|
||||
|
||||
beroot = currdev;
|
||||
|
||||
setenv("zfs_be_root", beroot, 1);
|
||||
}
|
||||
#endif
|
||||
@ -394,6 +398,7 @@ static int
|
||||
command_reloadbe(int argc, char *argv[])
|
||||
{
|
||||
int err;
|
||||
char *root;
|
||||
|
||||
if (argc > 2) {
|
||||
command_errmsg = "wrong number of arguments";
|
||||
@ -403,6 +408,11 @@ command_reloadbe(int argc, char *argv[])
|
||||
if (argc == 2) {
|
||||
err = zfs_bootenv(argv[1]);
|
||||
} 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"));
|
||||
}
|
||||
|
||||
|
@ -564,10 +564,6 @@ printf(const char *fmt, ...)
|
||||
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);
|
||||
|
@ -1,136 +1,12 @@
|
||||
# $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 <bsd.own.mk>
|
||||
MK_SSP= no
|
||||
.include <src.opts.mk>
|
||||
|
||||
LIBSTAND_SRC= ${.CURDIR}/../../../../lib/libstand
|
||||
LIBC_SRC= ${LIBSTAND_SRC}/../libc
|
||||
|
||||
.PATH: ${LIBSTAND_SRC}
|
||||
LIB= stand
|
||||
INTERNALLIB=
|
||||
MK_PROFILE= no
|
||||
NO_PIC=
|
||||
INCS=
|
||||
MAN=
|
||||
.PATH: ${LIBSTAND_SRC}
|
||||
|
||||
WARNS?= 0
|
||||
|
||||
# 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>
|
||||
.include "${LIBSTAND_SRC}/Makefile"
|
||||
|
@ -6,7 +6,6 @@ DIRDEPS = \
|
||||
include/arpa \
|
||||
include/xlocale \
|
||||
lib/libbz2 \
|
||||
lib/libstand \
|
||||
|
||||
|
||||
.include <dirdeps.mk>
|
||||
|
@ -168,6 +168,7 @@ extract_currdev(void)
|
||||
zdev.d_type = zdev.d_dev->dv_type;
|
||||
|
||||
dev = *(struct disk_devdesc *)&zdev;
|
||||
init_zfs_bootenv(zfs_fmtdev(&dev));
|
||||
} else
|
||||
#endif
|
||||
|
||||
@ -191,10 +192,6 @@ extract_currdev(void)
|
||||
dev.d_unit = 0;
|
||||
}
|
||||
|
||||
#if defined(USERBOOT_ZFS_SUPPORT)
|
||||
init_zfs_bootenv(zfs_fmtdev(&dev));
|
||||
#endif
|
||||
|
||||
env_setenv("currdev", EV_VOLATILE, userboot_fmtdev(&dev),
|
||||
userboot_setcurrdev, env_nounset);
|
||||
env_setenv("loaddev", EV_VOLATILE, userboot_fmtdev(&dev),
|
||||
@ -207,9 +204,14 @@ init_zfs_bootenv(char *currdev)
|
||||
{
|
||||
char *beroot;
|
||||
|
||||
if (strlen(currdev) == 0)
|
||||
return;
|
||||
if(strncmp(currdev, "zfs:", 4) != 0)
|
||||
return;
|
||||
/* Remove the trailing : */
|
||||
currdev[strlen(currdev) - 1] = '\0';
|
||||
setenv("zfs_be_active", currdev, 1);
|
||||
setenv("zfs_be_currpage", "1", 1);
|
||||
/* Do not overwrite if already set */
|
||||
setenv("vfs.root.mountfrom", currdev, 0);
|
||||
/* Forward past zfs: */
|
||||
@ -219,9 +221,7 @@ init_zfs_bootenv(char *currdev)
|
||||
beroot = strrchr(currdev, '/');
|
||||
if (beroot != NULL)
|
||||
beroot[0] = '\0';
|
||||
|
||||
beroot = currdev;
|
||||
|
||||
setenv("zfs_be_root", beroot, 1);
|
||||
}
|
||||
|
||||
@ -273,6 +273,7 @@ static int
|
||||
command_reloadbe(int argc, char *argv[])
|
||||
{
|
||||
int err;
|
||||
char *root;
|
||||
|
||||
if (argc > 2) {
|
||||
command_errmsg = "wrong number of arguments";
|
||||
@ -282,7 +283,11 @@ command_reloadbe(int argc, char *argv[])
|
||||
if (argc == 2) {
|
||||
err = zfs_bootenv(argv[1]);
|
||||
} 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) {
|
||||
|
@ -413,7 +413,7 @@ struct zfs_probe_args {
|
||||
int fd;
|
||||
const char *devname;
|
||||
uint64_t *pool_guid;
|
||||
uint16_t secsz;
|
||||
u_int secsz;
|
||||
};
|
||||
|
||||
static int
|
||||
@ -712,13 +712,18 @@ zfs_list(const char *name)
|
||||
int
|
||||
zfs_bootenv(const char *name)
|
||||
{
|
||||
static char poolname[ZFS_MAXNAMELEN], *dsname;
|
||||
static char poolname[ZFS_MAXNAMELEN], *dsname, *root;
|
||||
char becount[4];
|
||||
uint64_t objid;
|
||||
spa_t *spa;
|
||||
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)
|
||||
return (ENOMEM);
|
||||
}
|
||||
|
@ -78,6 +78,9 @@ static void
|
||||
vdev_geom_attrchanged(struct g_consumer *cp, const char *attr)
|
||||
{
|
||||
vdev_t *vd;
|
||||
spa_t *spa;
|
||||
char *physpath;
|
||||
int error, physpath_len;
|
||||
|
||||
vd = cp->private;
|
||||
if (vd == NULL)
|
||||
@ -87,6 +90,47 @@ vdev_geom_attrchanged(struct g_consumer *cp, const char *attr)
|
||||
vdev_geom_set_rotation_rate(vd, cp);
|
||||
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
|
||||
@ -97,8 +141,10 @@ vdev_geom_orphan(struct g_consumer *cp)
|
||||
g_topology_assert();
|
||||
|
||||
vd = cp->private;
|
||||
if (vd == NULL)
|
||||
if (vd == NULL) {
|
||||
/* Vdev close in progress. Ignore the event. */
|
||||
return;
|
||||
}
|
||||
|
||||
/*
|
||||
* Orphan callbacks occur from the GEOM event thread.
|
||||
@ -120,7 +166,7 @@ vdev_geom_orphan(struct g_consumer *cp)
|
||||
}
|
||||
|
||||
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_consumer *cp;
|
||||
@ -139,6 +185,7 @@ vdev_geom_attach(struct g_provider *pp)
|
||||
if (gp == NULL) {
|
||||
gp = g_new_geomf(&zfs_vdev_class, "zfs::vdev");
|
||||
gp->orphan = vdev_geom_orphan;
|
||||
gp->attrchanged = vdev_geom_attrchanged;
|
||||
cp = g_new_consumer(gp);
|
||||
if (g_attach(cp, pp) != 0) {
|
||||
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);
|
||||
}
|
||||
}
|
||||
|
||||
/*
|
||||
* 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;
|
||||
return (cp);
|
||||
}
|
||||
|
||||
static void
|
||||
vdev_geom_detach(void *arg, int flag __unused)
|
||||
vdev_geom_close_locked(vdev_t *vd)
|
||||
{
|
||||
struct g_geom *gp;
|
||||
struct g_consumer *cp;
|
||||
|
||||
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);
|
||||
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);
|
||||
/* Destroy consumer on last close. */
|
||||
if (cp->acr == 0 && cp->ace == 0) {
|
||||
ZFS_LOG(1, "Destroyed consumer to %s.", cp->provider->name);
|
||||
if (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);
|
||||
}
|
||||
/* 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 *
|
||||
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_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);
|
||||
g_topology_lock();
|
||||
vdev_geom_detach_taster(zcp);
|
||||
if (pguid != pool_guid || vguid != vdev_guid)
|
||||
if (pguid != spa_guid(vd->vdev_spa) ||
|
||||
vguid != vd->vdev_guid)
|
||||
continue;
|
||||
cp = vdev_geom_attach(pp);
|
||||
cp = vdev_geom_attach(pp, vd);
|
||||
if (cp == NULL) {
|
||||
printf("ZFS WARNING: Unable to "
|
||||
"attach to %s.\n", pp->name);
|
||||
@ -551,7 +627,7 @@ vdev_geom_open_by_guids(vdev_t *vd)
|
||||
g_topology_assert();
|
||||
|
||||
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) {
|
||||
len = strlen(cp->provider->name) + strlen("/dev/") + 1;
|
||||
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);
|
||||
if (pp != NULL) {
|
||||
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) &&
|
||||
pp->sectorsize <= VDEV_PAD_SIZE) {
|
||||
g_topology_unlock();
|
||||
@ -593,7 +669,7 @@ vdev_geom_open_by_path(vdev_t *vd, int check_guid)
|
||||
g_topology_lock();
|
||||
if (pguid != spa_guid(vd->vdev_spa) ||
|
||||
vguid != vd->vdev_guid) {
|
||||
vdev_geom_detach(cp, 0);
|
||||
vdev_geom_close_locked(vd);
|
||||
cp = NULL;
|
||||
ZFS_LOG(1, "guid mismatch for provider %s: "
|
||||
"%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)) {
|
||||
ZFS_LOG(1, "Provider %s has unsupported sectorsize.",
|
||||
vd->vdev_path);
|
||||
vdev_geom_detach(cp, 0);
|
||||
|
||||
vdev_geom_close_locked(vd);
|
||||
error = EINVAL;
|
||||
cp = NULL;
|
||||
} 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) {
|
||||
printf("ZFS WARNING: Unable to open %s for writing (error=%d).\n",
|
||||
vd->vdev_path, error);
|
||||
vdev_geom_detach(cp, 0);
|
||||
vdev_geom_close_locked(vd);
|
||||
cp = NULL;
|
||||
}
|
||||
}
|
||||
|
||||
g_topology_unlock();
|
||||
PICKUP_GIANT();
|
||||
if (cp == NULL) {
|
||||
vd->vdev_stat.vs_aux = VDEV_AUX_OPEN_FAILED;
|
||||
return (error);
|
||||
}
|
||||
|
||||
cp->private = vd;
|
||||
vd->vdev_tsd = cp;
|
||||
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;
|
||||
|
||||
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.
|
||||
*/
|
||||
@ -744,15 +813,12 @@ vdev_geom_open(vdev_t *vd, uint64_t *psize, uint64_t *max_psize,
|
||||
static void
|
||||
vdev_geom_close(vdev_t *vd)
|
||||
{
|
||||
struct g_consumer *cp;
|
||||
|
||||
cp = vd->vdev_tsd;
|
||||
if (cp == NULL)
|
||||
return;
|
||||
vd->vdev_tsd = NULL;
|
||||
vd->vdev_delayed_close = B_FALSE;
|
||||
cp->private = NULL; /* XXX locking */
|
||||
g_post_event(vdev_geom_detach, cp, M_WAITOK, NULL);
|
||||
DROP_GIANT();
|
||||
g_topology_lock();
|
||||
vdev_geom_close_locked(vd);
|
||||
g_topology_unlock();
|
||||
PICKUP_GIANT();
|
||||
}
|
||||
|
||||
static void
|
||||
|
@ -134,6 +134,7 @@ struct sysentvec ia32_freebsd_sysvec = {
|
||||
.sv_shared_page_len = PAGE_SIZE,
|
||||
.sv_schedtail = NULL,
|
||||
.sv_thread_detach = NULL,
|
||||
.sv_trap = NULL,
|
||||
};
|
||||
INIT_SYSENTVEC(elf_ia32_sysvec, &ia32_freebsd_sysvec);
|
||||
|
||||
|
@ -1099,8 +1099,12 @@ linux_get_robust_list(struct thread *td, struct linux_get_robust_list_args *args
|
||||
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);
|
||||
}
|
||||
|
||||
em = em_find(td2);
|
||||
KASSERT(em != NULL, ("get_robust_list: emuldata notfound.\n"));
|
||||
|
@ -194,6 +194,7 @@ struct sysentvec svr4_sysvec = {
|
||||
.sv_syscallnames = NULL,
|
||||
.sv_schedtail = NULL,
|
||||
.sv_thread_detach = NULL,
|
||||
.sv_trap = NULL,
|
||||
};
|
||||
|
||||
const char svr4_emul_path[] = "/compat/svr4";
|
||||
|
@ -50,6 +50,7 @@ static const char rcsid[] = "@(#)$Id$";
|
||||
# include <net/netisr.h>
|
||||
#include <net/route.h>
|
||||
#include <netinet/in.h>
|
||||
#include <netinet/in_fib.h>
|
||||
#include <netinet/in_var.h>
|
||||
#include <netinet/in_systm.h>
|
||||
#include <netinet/ip.h>
|
||||
@ -712,17 +713,16 @@ ipf_fastroute(m0, mpp, fin, fdp)
|
||||
{
|
||||
register struct ip *ip, *mhip;
|
||||
register struct mbuf *m = *mpp;
|
||||
register struct route *ro;
|
||||
int len, off, error = 0, hlen, code;
|
||||
struct ifnet *ifp, *sifp;
|
||||
struct sockaddr_in *dst;
|
||||
struct route iproute;
|
||||
struct sockaddr_in dst;
|
||||
struct nhop4_extended nh4;
|
||||
int has_nhop = 0;
|
||||
u_long fibnum = 0;
|
||||
u_short ip_off;
|
||||
frdest_t node;
|
||||
frentry_t *fr;
|
||||
|
||||
ro = NULL;
|
||||
|
||||
#ifdef M_WRITABLE
|
||||
/*
|
||||
* HOT FIX/KLUDGE:
|
||||
@ -766,11 +766,10 @@ ipf_fastroute(m0, mpp, fin, fdp)
|
||||
/*
|
||||
* Route packet.
|
||||
*/
|
||||
ro = &iproute;
|
||||
bzero(ro, sizeof (*ro));
|
||||
dst = (struct sockaddr_in *)&ro->ro_dst;
|
||||
dst->sin_family = AF_INET;
|
||||
dst->sin_addr = ip->ip_dst;
|
||||
bzero(&dst, sizeof (dst));
|
||||
dst.sin_family = AF_INET;
|
||||
dst.sin_addr = ip->ip_dst;
|
||||
dst.sin_len = sizeof(dst);
|
||||
|
||||
fr = fin->fin_fr;
|
||||
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))
|
||||
dst->sin_addr = fdp->fd_ip;
|
||||
dst.sin_addr = fdp->fd_ip;
|
||||
|
||||
dst->sin_len = sizeof(*dst);
|
||||
in_rtalloc(ro, M_GETFIB(m0));
|
||||
|
||||
if ((ifp == NULL) && (ro->ro_rt != NULL))
|
||||
ifp = ro->ro_rt->rt_ifp;
|
||||
|
||||
if ((ro->ro_rt == NULL) || (ifp == NULL)) {
|
||||
fibnum = M_GETFIB(m0);
|
||||
if (fib4_lookup_nh_ext(fibnum, dst.sin_addr, NHR_REF, 0, &nh4) != 0) {
|
||||
if (in_localaddr(ip->ip_dst))
|
||||
error = EHOSTUNREACH;
|
||||
else
|
||||
error = ENETUNREACH;
|
||||
goto bad;
|
||||
}
|
||||
if (ro->ro_rt->rt_flags & RTF_GATEWAY)
|
||||
dst = (struct sockaddr_in *)ro->ro_rt->rt_gateway;
|
||||
if (ro->ro_rt)
|
||||
counter_u64_add(ro->ro_rt->rt_pksent, 1);
|
||||
|
||||
has_nhop = 1;
|
||||
if (ifp == NULL)
|
||||
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
|
||||
@ -852,8 +848,8 @@ ipf_fastroute(m0, mpp, fin, fdp)
|
||||
if (ntohs(ip->ip_len) <= ifp->if_mtu) {
|
||||
if (!ip->ip_sum)
|
||||
ip->ip_sum = in_cksum(m, hlen);
|
||||
error = (*ifp->if_output)(ifp, m, (struct sockaddr *)dst,
|
||||
ro
|
||||
error = (*ifp->if_output)(ifp, m, (struct sockaddr *)&dst,
|
||||
NULL
|
||||
);
|
||||
goto done;
|
||||
}
|
||||
@ -935,8 +931,8 @@ sendorfree:
|
||||
m->m_act = 0;
|
||||
if (error == 0)
|
||||
error = (*ifp->if_output)(ifp, m,
|
||||
(struct sockaddr *)dst,
|
||||
ro
|
||||
(struct sockaddr *)&dst,
|
||||
NULL
|
||||
);
|
||||
else
|
||||
FREE_MB_T(m);
|
||||
@ -948,9 +944,9 @@ done:
|
||||
else
|
||||
ipfmain.ipf_frouteok[1]++;
|
||||
|
||||
if ((ro != NULL) && (ro->ro_rt != NULL)) {
|
||||
RTFREE(ro->ro_rt);
|
||||
}
|
||||
if (has_nhop)
|
||||
fib4_free_nh_ext(fibnum, &nh4);
|
||||
|
||||
return 0;
|
||||
bad:
|
||||
if (error == EMSGSIZE) {
|
||||
@ -971,18 +967,11 @@ int
|
||||
ipf_verifysrc(fin)
|
||||
fr_info_t *fin;
|
||||
{
|
||||
struct sockaddr_in *dst;
|
||||
struct route iproute;
|
||||
struct nhop4_basic nh4;
|
||||
|
||||
bzero((char *)&iproute, sizeof(iproute));
|
||||
dst = (struct sockaddr_in *)&iproute.ro_dst;
|
||||
dst->sin_len = sizeof(*dst);
|
||||
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);
|
||||
if (fib4_lookup_nh_basic(0, fin->fin_src, 0, 0, &nh4) != 0)
|
||||
return (0);
|
||||
return (fin->fin_ifp == nh4.nh_ifp);
|
||||
}
|
||||
|
||||
|
||||
|
@ -3642,6 +3642,9 @@ setup_intr_handlers(struct adapter *sc)
|
||||
#ifdef DEV_NETMAP
|
||||
struct sge_nm_rxq *nm_rxq;
|
||||
#endif
|
||||
#ifdef RSS
|
||||
int nbuckets = rss_getnumbuckets();
|
||||
#endif
|
||||
|
||||
/*
|
||||
* Setup interrupts.
|
||||
@ -3700,6 +3703,10 @@ setup_intr_handlers(struct adapter *sc)
|
||||
t4_intr, rxq, s);
|
||||
if (rc != 0)
|
||||
return (rc);
|
||||
#ifdef RSS
|
||||
bus_bind_intr(sc->dev, irq->res,
|
||||
rss_getcpu(q % nbuckets));
|
||||
#endif
|
||||
irq++;
|
||||
rid++;
|
||||
vi->nintr++;
|
||||
|
@ -205,6 +205,7 @@
|
||||
* requires ACR[6].
|
||||
*/
|
||||
#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
|
||||
@ -220,6 +221,7 @@
|
||||
*/
|
||||
|
||||
#define com_acr 0 /* additional control register (R/W) */
|
||||
#define REG_ACR com_acr
|
||||
#define ACR_ASE 0x80 /* ASR/RFL/TFL enable */
|
||||
#define ACR_ICRE 0x40 /* ICR enable */
|
||||
#define ACR_TLE 0x20 /* TTL/RTL enable */
|
||||
|
@ -98,6 +98,9 @@ SYSCTL_INT(_kern_iscsi, OID_AUTO, maxtags, CTLFLAG_RWTUN, &maxtags,
|
||||
static int fail_on_disconnection = 0;
|
||||
SYSCTL_INT(_kern_iscsi, OID_AUTO, fail_on_disconnection, CTLFLAG_RWTUN,
|
||||
&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 uma_zone_t iscsi_outstanding_zone;
|
||||
@ -417,8 +420,6 @@ iscsi_maintenance_thread_terminate(struct iscsi_session *is)
|
||||
|
||||
sc = is->is_softc;
|
||||
sx_xlock(&sc->sc_lock);
|
||||
TAILQ_REMOVE(&sc->sc_sessions, is, is_next);
|
||||
sx_xunlock(&sc->sc_lock);
|
||||
|
||||
icl_conn_close(is->is_conn);
|
||||
callout_drain(&is->is_callout);
|
||||
@ -450,6 +451,9 @@ iscsi_maintenance_thread_terminate(struct iscsi_session *is)
|
||||
#ifdef ICL_KERNEL_PROXY
|
||||
cv_destroy(&is->is_login_cv);
|
||||
#endif
|
||||
TAILQ_REMOVE(&sc->sc_sessions, is, is_next);
|
||||
sx_xunlock(&sc->sc_lock);
|
||||
|
||||
ISCSI_SESSION_DEBUG(is, "terminated");
|
||||
free(is, M_ISCSI);
|
||||
|
||||
@ -473,12 +477,7 @@ iscsi_maintenance_thread(void *arg)
|
||||
STAILQ_EMPTY(&is->is_postponed))
|
||||
cv_wait(&is->is_maintenance_cv, &is->is_lock);
|
||||
|
||||
if (is->is_reconnecting) {
|
||||
ISCSI_SESSION_UNLOCK(is);
|
||||
iscsi_maintenance_thread_reconnect(is);
|
||||
continue;
|
||||
}
|
||||
|
||||
/* Terminate supersedes reconnect. */
|
||||
if (is->is_terminating) {
|
||||
ISCSI_SESSION_UNLOCK(is);
|
||||
iscsi_maintenance_thread_terminate(is);
|
||||
@ -486,6 +485,12 @@ iscsi_maintenance_thread(void *arg)
|
||||
return;
|
||||
}
|
||||
|
||||
if (is->is_reconnecting) {
|
||||
ISCSI_SESSION_UNLOCK(is);
|
||||
iscsi_maintenance_thread_reconnect(is);
|
||||
continue;
|
||||
}
|
||||
|
||||
iscsi_session_send_postponed(is);
|
||||
ISCSI_SESSION_UNLOCK(is);
|
||||
}
|
||||
@ -605,6 +610,11 @@ iscsi_callout(void *context)
|
||||
return;
|
||||
|
||||
out:
|
||||
if (is->is_terminating) {
|
||||
ISCSI_SESSION_UNLOCK(is);
|
||||
return;
|
||||
}
|
||||
|
||||
ISCSI_SESSION_UNLOCK(is);
|
||||
|
||||
if (reconnect_needed)
|
||||
@ -2326,30 +2336,62 @@ iscsi_poll(struct cam_sim *sim)
|
||||
}
|
||||
|
||||
static void
|
||||
iscsi_shutdown(struct iscsi_softc *sc)
|
||||
iscsi_terminate_sessions(struct iscsi_softc *sc)
|
||||
{
|
||||
struct iscsi_session *is;
|
||||
|
||||
/*
|
||||
* Trying to reconnect during system shutdown would lead to hang.
|
||||
*/
|
||||
fail_on_disconnection = 1;
|
||||
sx_slock(&sc->sc_lock);
|
||||
TAILQ_FOREACH(is, &sc->sc_sessions, is_next)
|
||||
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);
|
||||
}
|
||||
|
||||
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
|
||||
* maintenance thread to fail them immediately instead of waiting
|
||||
* 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);
|
||||
TAILQ_FOREACH(is, &sc->sc_sessions, is_next) {
|
||||
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_UNLOCK(is);
|
||||
}
|
||||
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
|
||||
iscsi_load(void)
|
||||
{
|
||||
@ -2372,8 +2414,16 @@ iscsi_load(void)
|
||||
}
|
||||
sc->sc_cdev->si_drv1 = sc;
|
||||
|
||||
sc->sc_shutdown_eh = EVENTHANDLER_REGISTER(shutdown_pre_sync,
|
||||
iscsi_shutdown, sc, SHUTDOWN_PRI_DEFAULT-1);
|
||||
sc->sc_shutdown_pre_eh = EVENTHANDLER_REGISTER(shutdown_pre_sync,
|
||||
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);
|
||||
}
|
||||
@ -2381,7 +2431,6 @@ iscsi_load(void)
|
||||
static int
|
||||
iscsi_unload(void)
|
||||
{
|
||||
struct iscsi_session *is, *tmp;
|
||||
|
||||
if (sc->sc_cdev != NULL) {
|
||||
ISCSI_DEBUG("removing device node");
|
||||
@ -2389,18 +2438,12 @@ iscsi_unload(void)
|
||||
ISCSI_DEBUG("device node removed");
|
||||
}
|
||||
|
||||
if (sc->sc_shutdown_eh != NULL)
|
||||
EVENTHANDLER_DEREGISTER(shutdown_pre_sync, sc->sc_shutdown_eh);
|
||||
if (sc->sc_shutdown_pre_eh != NULL)
|
||||
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);
|
||||
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);
|
||||
iscsi_terminate_sessions(sc);
|
||||
|
||||
uma_zdestroy(iscsi_outstanding_zone);
|
||||
sx_destroy(&sc->sc_lock);
|
||||
|
@ -131,7 +131,8 @@ struct iscsi_softc {
|
||||
TAILQ_HEAD(, iscsi_session) sc_sessions;
|
||||
struct cv sc_cv;
|
||||
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 */
|
||||
|
@ -42,12 +42,16 @@ __FBSDID("$FreeBSD$");
|
||||
#include <machine/bus.h>
|
||||
#include <sys/rman.h>
|
||||
|
||||
#include <dev/ic/ns16550.h>
|
||||
|
||||
#include <dev/pci/pcireg.h>
|
||||
#include <dev/pci/pcivar.h>
|
||||
|
||||
#include <dev/puc/puc_bus.h>
|
||||
#include <dev/puc/puc_cfg.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_diva;
|
||||
static puc_config_f puc_config_exar;
|
||||
@ -691,10 +695,25 @@ const struct puc_cfg puc_pci_devices[] = {
|
||||
.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,
|
||||
"Advantech PCI-1602",
|
||||
"Advantech PCI-1602 Rev. A",
|
||||
DEFAULT_RCLK * 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,
|
||||
@ -1255,6 +1274,92 @@ const struct puc_cfg puc_pci_devices[] = {
|
||||
{ 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
|
||||
puc_config_amc(struct puc_softc *sc __unused, enum puc_cfg_cmd cmd, int port,
|
||||
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);
|
||||
if (bar == NULL)
|
||||
return (ENXIO);
|
||||
/* Set DLAB in the LCR register of UART 0. */
|
||||
bus_write_1(bar->b_res, 3, 0x80);
|
||||
/* Write 0 to the SPR register of UART 0. */
|
||||
bus_write_1(bar->b_res, 7, 0);
|
||||
/* Read back the contents of the SPR register of UART 0. */
|
||||
v0 = bus_read_1(bar->b_res, 7);
|
||||
/* 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. */
|
||||
bus_write_1(bar->b_res, REG_LCR, LCR_DLAB);
|
||||
bus_write_1(bar->b_res, REG_SPR, 0);
|
||||
v0 = bus_read_1(bar->b_res, REG_SPR);
|
||||
bus_write_1(bar->b_res, REG_SPR, 0x80 + -cfg->clock);
|
||||
v1 = bus_read_1(bar->b_res, REG_SPR);
|
||||
bus_write_1(bar->b_res, REG_LCR, 0);
|
||||
sc->sc_cfg_data = (v0 << 8) | v1;
|
||||
if (v0 == 0 && v1 == 0x80 + -cfg->clock) {
|
||||
/*
|
||||
* 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 "
|
||||
"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) {
|
||||
/*
|
||||
* 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-
|
||||
* 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);
|
||||
}
|
||||
/*
|
||||
* The first value matched, but the second didn't. We know
|
||||
* that the SPAD jumper is not set. We also know that the
|
||||
* The first value matched, but the second didn't. We know
|
||||
* that the SPAD jumper is not set. We also know that the
|
||||
* clock rate multiplier is software controlled *and* that
|
||||
* 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
|
||||
* easy way of knowing if there's also a clock
|
||||
* rate multiplier jumper installed. Let's hope
|
||||
* not...
|
||||
* rate multiplier jumper installed. Let's hope
|
||||
* not ...
|
||||
*/
|
||||
*res = DEFAULT_RCLK;
|
||||
} 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:
|
||||
/*
|
||||
* Check if we are being called from puc_bfe_attach()
|
||||
* or puc_bfe_probe(). If puc_bfe_probe(), we cannot
|
||||
* puc_get_bar(), so we return a value of 16. This has cosmetic
|
||||
* side-effects at worst; in PUC_CFG_GET_DESC,
|
||||
* (int)sc->sc_cfg_data will not contain the true number of
|
||||
* ports in PUC_CFG_GET_DESC, but we are not implementing that
|
||||
* call for this device family anyway.
|
||||
* or puc_bfe_probe(). If puc_bfe_probe(), we cannot
|
||||
* puc_get_bar(), so we return a value of 16. This has
|
||||
* cosmetic side-effects at worst; in PUC_CFG_GET_DESC,
|
||||
* sc->sc_cfg_data will not contain the true number of
|
||||
* ports in PUC_CFG_GET_DESC, but we are not implementing
|
||||
* that call for this device family anyway.
|
||||
*
|
||||
* The check is for initialisation of sc->sc_bar[idx], which is
|
||||
* only done in puc_bfe_attach().
|
||||
* The check is for initialization of sc->sc_bar[idx],
|
||||
* which is only done in puc_bfe_attach().
|
||||
*/
|
||||
idx = 0;
|
||||
do {
|
||||
|
@ -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));
|
||||
}
|
||||
/* 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) {
|
||||
/* Use HW sequence numbering for non-QoS frames. */
|
||||
|
@ -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_SIENA 1
|
||||
#define EFSYS_OPT_HUNTINGTON 1
|
||||
#define EFSYS_OPT_MEDFORD 0
|
||||
#ifdef DEBUG
|
||||
#define EFSYS_OPT_CHECK_REG 1
|
||||
#else
|
||||
|
@ -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_len = 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);
|
||||
m[i]->m_next = m[i+1];
|
||||
}
|
||||
@ -1699,7 +1699,7 @@ nobufs:
|
||||
if (m[i])
|
||||
m_freem(m[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);
|
||||
}
|
||||
|
@ -57,6 +57,7 @@ struct ofwfb_softc {
|
||||
int iso_palette;
|
||||
};
|
||||
|
||||
static void ofwfb_initialize(struct vt_device *vd);
|
||||
static vd_probe_t ofwfb_probe;
|
||||
static vd_init_t ofwfb_init;
|
||||
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];
|
||||
} 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];
|
||||
bgc = sc->fb_cmap[bg];
|
||||
b = m = 0;
|
||||
@ -271,6 +284,11 @@ ofwfb_initialize(struct vt_device *vd)
|
||||
cell_t retval;
|
||||
uint32_t oldpix;
|
||||
|
||||
sc->fb.fb_cmsize = 16;
|
||||
|
||||
if (sc->fb.fb_flags & FB_FLAG_NOWRITE)
|
||||
return;
|
||||
|
||||
/*
|
||||
* 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);
|
||||
break;
|
||||
}
|
||||
|
||||
sc->fb.fb_cmsize = 16;
|
||||
}
|
||||
|
||||
static int
|
||||
@ -466,6 +482,11 @@ ofwfb_init(struct vt_device *vd)
|
||||
#if defined(__powerpc__)
|
||||
OF_decode_addr(node, fb_phys, &sc->sc_memt, &sc->fb.fb_vbase);
|
||||
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
|
||||
/* No ability to interpret assigned-addresses otherwise */
|
||||
return (CN_DEAD);
|
||||
|
@ -102,9 +102,6 @@ ext4_bmapext(struct vnode *vp, int32_t bn, int64_t *bnp, int *runp, int *runb)
|
||||
fs = ip->i_e2fs;
|
||||
lbn = bn;
|
||||
|
||||
/*
|
||||
* TODO: need to implement read ahead to improve the performance.
|
||||
*/
|
||||
if (runp != NULL)
|
||||
*runp = 0;
|
||||
|
||||
@ -112,15 +109,25 @@ ext4_bmapext(struct vnode *vp, int32_t bn, int64_t *bnp, int *runp, int *runb)
|
||||
*runb = 0;
|
||||
|
||||
ext4_ext_find_extent(fs, ip, lbn, &path);
|
||||
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 (path.ep_is_sparse) {
|
||||
*bnp = -1;
|
||||
if (runp != NULL)
|
||||
*runp = path.ep_sparse_ext.e_len -
|
||||
(lbn - path.ep_sparse_ext.e_blk) - 1;
|
||||
} 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)
|
||||
*bnp = -1;
|
||||
if (*bnp == 0)
|
||||
*bnp = -1;
|
||||
|
||||
if (runp != NULL)
|
||||
*runp = ep->e_len - (lbn - ep->e_blk) - 1;
|
||||
}
|
||||
}
|
||||
|
||||
if (path.ep_bp != NULL) {
|
||||
|
@ -66,13 +66,14 @@ static void
|
||||
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 *l, *r, *m;
|
||||
struct ext4_extent *first, *l, *r, *m;
|
||||
|
||||
if (ehp->eh_ecount == 0)
|
||||
return;
|
||||
|
||||
l = (struct ext4_extent *)(char *)(ehp + 1);
|
||||
r = (struct ext4_extent *)(char *)(ehp + 1) + ehp->eh_ecount - 1;
|
||||
first = (struct ext4_extent *)(char *)(ehp + 1);
|
||||
l = first;
|
||||
r = first + ehp->eh_ecount - 1;
|
||||
while (l <= r) {
|
||||
m = l + (r - l) / 2;
|
||||
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;
|
||||
}
|
||||
|
||||
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;
|
||||
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_ext = NULL;
|
||||
path->ep_index = NULL;
|
||||
path->ep_is_sparse = 0;
|
||||
|
||||
ext4_ext_binsearch(ip, path, lbn);
|
||||
return (path);
|
||||
|
@ -84,7 +84,11 @@ struct ext4_extent_cache {
|
||||
struct ext4_extent_path {
|
||||
uint16_t ep_depth;
|
||||
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_header *ep_header;
|
||||
};
|
||||
|
@ -590,7 +590,7 @@ ext2_mountfs(struct vnode *devvp, struct mount *mp)
|
||||
* while Linux keeps the super block in a locked buffer.
|
||||
*/
|
||||
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),
|
||||
M_EXT2MNT, M_WAITOK);
|
||||
mtx_init(EXT2_MTX(ump), "EXT2FS", "EXT2FS Lock", MTX_DEF);
|
||||
|
@ -1787,6 +1787,7 @@ ext2_ioctl(struct vop_ioctl_args *ap)
|
||||
static int
|
||||
ext4_ext_read(struct vop_read_args *ap)
|
||||
{
|
||||
static unsigned char zeroes[EXT2_MAX_BLOCK_SIZE];
|
||||
struct vnode *vp;
|
||||
struct inode *ip;
|
||||
struct uio *uio;
|
||||
@ -1831,11 +1832,15 @@ ext4_ext_read(struct vop_read_args *ap)
|
||||
switch (cache_type) {
|
||||
case EXT4_EXT_CACHE_NO:
|
||||
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)
|
||||
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 |
|
||||
(daddr_t)ep->e_start_hi << 32);
|
||||
@ -1848,7 +1853,7 @@ ext4_ext_read(struct vop_read_args *ap)
|
||||
|
||||
case EXT4_EXT_CACHE_GAP:
|
||||
/* block has not been allocated yet */
|
||||
return (0);
|
||||
break;
|
||||
|
||||
case EXT4_EXT_CACHE_IN:
|
||||
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__);
|
||||
}
|
||||
|
||||
error = bread(ip->i_devvp, fsbtodb(fs, newblk), size, NOCRED, &bp);
|
||||
if (error) {
|
||||
brelse(bp);
|
||||
return (error);
|
||||
}
|
||||
|
||||
size -= bp->b_resid;
|
||||
if (size < xfersize) {
|
||||
if (size == 0) {
|
||||
bqrelse(bp);
|
||||
break;
|
||||
if (cache_type == EXT4_EXT_CACHE_GAP ||
|
||||
(cache_type == EXT4_EXT_CACHE_NO && path.ep_is_sparse)) {
|
||||
if (xfersize > sizeof(zeroes))
|
||||
xfersize = sizeof(zeroes);
|
||||
error = uiomove(zeroes, xfersize, uio);
|
||||
if (error)
|
||||
return (error);
|
||||
} else {
|
||||
error = bread(ip->i_devvp, fsbtodb(fs, newblk), size,
|
||||
NOCRED, &bp);
|
||||
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);
|
||||
|
@ -333,18 +333,18 @@ smbfs_smb_flush(struct smbnode *np, struct smb_cred *scred)
|
||||
}
|
||||
|
||||
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_rq *rqp;
|
||||
struct mbchain *mbp;
|
||||
int error;
|
||||
|
||||
if (!smbfs_smb_seteof(np, (int64_t) newsize, scred)) {
|
||||
if (!smbfs_smb_seteof(np, newsize, scred)) {
|
||||
np->n_flag |= NFLUSHWIRE;
|
||||
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);
|
||||
if (error)
|
||||
return (error);
|
||||
@ -352,7 +352,7 @@ smbfs_smb_setfsize(struct smbnode *np, int newsize, struct smb_cred *scred)
|
||||
smb_rq_wstart(rqp);
|
||||
mb_put_mem(mbp, (caddr_t)&np->n_fid, 2, MB_MSYSTEM);
|
||||
mb_put_uint16le(mbp, 0);
|
||||
mb_put_uint32le(mbp, newsize);
|
||||
mb_put_uint32le(mbp, (uint32_t)newsize);
|
||||
mb_put_uint16le(mbp, 0);
|
||||
smb_rq_wend(rqp);
|
||||
smb_rq_bstart(rqp);
|
||||
|
@ -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);
|
||||
int smbfs_smb_statfs(struct smb_share *ssp, struct statfs *sbp,
|
||||
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,
|
||||
struct smbfattr *fap, struct smb_cred *scred);
|
||||
|
@ -358,7 +358,8 @@ smbfs_setattr(ap)
|
||||
doclose = 1;
|
||||
}
|
||||
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)
|
||||
smbfs_smb_close(ssp, np->n_fid, NULL, scred);
|
||||
if (error) {
|
||||
|
@ -87,6 +87,7 @@ struct sysentvec elf32_freebsd_sysvec = {
|
||||
.sv_shared_page_len = PAGE_SIZE,
|
||||
.sv_schedtail = NULL,
|
||||
.sv_thread_detach = NULL,
|
||||
.sv_trap = NULL,
|
||||
};
|
||||
INIT_SYSENTVEC(elf32_sysvec, &elf32_freebsd_sysvec);
|
||||
|
||||
|
@ -90,6 +90,7 @@ struct sysentvec ibcs2_svr3_sysvec = {
|
||||
.sv_syscallnames = NULL,
|
||||
.sv_schedtail = NULL,
|
||||
.sv_thread_detach = NULL,
|
||||
.sv_trap = NULL,
|
||||
};
|
||||
|
||||
static int
|
||||
|
@ -985,6 +985,7 @@ struct sysentvec linux_sysvec = {
|
||||
.sv_shared_page_len = PAGE_SIZE,
|
||||
.sv_schedtail = linux_schedtail,
|
||||
.sv_thread_detach = linux_thread_detach,
|
||||
.sv_trap = NULL,
|
||||
};
|
||||
INIT_SYSENTVEC(aout_sysvec, &linux_sysvec);
|
||||
|
||||
@ -1021,6 +1022,7 @@ struct sysentvec elf_linux_sysvec = {
|
||||
.sv_shared_page_len = PAGE_SIZE,
|
||||
.sv_schedtail = linux_schedtail,
|
||||
.sv_thread_detach = linux_thread_detach,
|
||||
.sv_trap = NULL,
|
||||
};
|
||||
|
||||
static void
|
||||
|
@ -97,6 +97,7 @@ struct sysentvec aout_sysvec = {
|
||||
.sv_syscallnames = syscallnames,
|
||||
.sv_schedtail = NULL,
|
||||
.sv_thread_detach = NULL,
|
||||
.sv_trap = NULL,
|
||||
};
|
||||
|
||||
#elif defined(__amd64__)
|
||||
|
@ -414,6 +414,7 @@ struct sysentvec null_sysvec = {
|
||||
.sv_syscallnames = NULL,
|
||||
.sv_schedtail = NULL,
|
||||
.sv_thread_detach = NULL,
|
||||
.sv_trap = NULL,
|
||||
};
|
||||
|
||||
/*
|
||||
|
@ -31,6 +31,7 @@ __FBSDID("$FreeBSD$");
|
||||
|
||||
#include <sys/param.h>
|
||||
#include <sys/systm.h>
|
||||
#include <sys/limits.h>
|
||||
#include <sys/lock.h>
|
||||
#include <sys/mutex.h>
|
||||
#include <sys/proc.h>
|
||||
@ -46,6 +47,17 @@ __FBSDID("$FreeBSD$");
|
||||
#include <sys/ktrace.h>
|
||||
#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.
|
||||
*/
|
||||
@ -122,7 +134,7 @@ _cv_wait(struct cv *cvp, struct lock_object *lock)
|
||||
|
||||
sleepq_lock(cvp);
|
||||
|
||||
cvp->cv_waiters++;
|
||||
CV_WAITERS_INC(cvp);
|
||||
if (lock == &Giant.lock_object)
|
||||
mtx_assert(&Giant, MA_OWNED);
|
||||
DROP_GIANT();
|
||||
@ -184,7 +196,7 @@ _cv_wait_unlock(struct cv *cvp, struct lock_object *lock)
|
||||
|
||||
sleepq_lock(cvp);
|
||||
|
||||
cvp->cv_waiters++;
|
||||
CV_WAITERS_INC(cvp);
|
||||
DROP_GIANT();
|
||||
|
||||
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);
|
||||
|
||||
cvp->cv_waiters++;
|
||||
CV_WAITERS_INC(cvp);
|
||||
if (lock == &Giant.lock_object)
|
||||
mtx_assert(&Giant, MA_OWNED);
|
||||
DROP_GIANT();
|
||||
@ -307,7 +319,7 @@ _cv_timedwait_sbt(struct cv *cvp, struct lock_object *lock, sbintime_t sbt,
|
||||
|
||||
sleepq_lock(cvp);
|
||||
|
||||
cvp->cv_waiters++;
|
||||
CV_WAITERS_INC(cvp);
|
||||
if (lock == &Giant.lock_object)
|
||||
mtx_assert(&Giant, MA_OWNED);
|
||||
DROP_GIANT();
|
||||
@ -376,7 +388,7 @@ _cv_timedwait_sig_sbt(struct cv *cvp, struct lock_object *lock,
|
||||
|
||||
sleepq_lock(cvp);
|
||||
|
||||
cvp->cv_waiters++;
|
||||
CV_WAITERS_INC(cvp);
|
||||
if (lock == &Giant.lock_object)
|
||||
mtx_assert(&Giant, MA_OWNED);
|
||||
DROP_GIANT();
|
||||
@ -422,8 +434,15 @@ cv_signal(struct cv *cvp)
|
||||
wakeup_swapper = 0;
|
||||
sleepq_lock(cvp);
|
||||
if (cvp->cv_waiters > 0) {
|
||||
cvp->cv_waiters--;
|
||||
wakeup_swapper = sleepq_signal(cvp, SLEEPQ_CONDVAR, 0, 0);
|
||||
if (cvp->cv_waiters == CV_WAITERS_BOUND &&
|
||||
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);
|
||||
if (wakeup_swapper)
|
||||
|
@ -338,6 +338,9 @@ mb_free_ext(struct mbuf *m)
|
||||
case EXT_SFBUF:
|
||||
sf_ext_free(m->m_ext.ext_arg1, m->m_ext.ext_arg2);
|
||||
break;
|
||||
case EXT_SFBUF_NOCACHE:
|
||||
sf_ext_free_nocache(m->m_ext.ext_arg1, m->m_ext.ext_arg2);
|
||||
break;
|
||||
default:
|
||||
KASSERT(m->m_ext.ext_cnt != NULL,
|
||||
("%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) {
|
||||
case EXT_SFBUF:
|
||||
case EXT_SFBUF_NOCACHE:
|
||||
sf_ext_ref(m->m_ext.ext_arg1, m->m_ext.ext_arg2);
|
||||
break;
|
||||
default:
|
||||
|
@ -68,6 +68,23 @@ static u_long sb_efficiency = 8; /* parameter for sbreserve() */
|
||||
static struct mbuf *sbcut_internal(struct sockbuf *sb, int len);
|
||||
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".
|
||||
*/
|
||||
@ -569,7 +586,7 @@ sblastmbufchk(struct sockbuf *sb, const char *file, int line)
|
||||
* are discarded and mbufs are compacted where possible.
|
||||
*/
|
||||
void
|
||||
sbappend_locked(struct sockbuf *sb, struct mbuf *m)
|
||||
sbappend_locked(struct sockbuf *sb, struct mbuf *m, int flags)
|
||||
{
|
||||
struct mbuf *n;
|
||||
|
||||
@ -577,7 +594,7 @@ sbappend_locked(struct sockbuf *sb, struct mbuf *m)
|
||||
|
||||
if (m == 0)
|
||||
return;
|
||||
m_clrprotoflags(m);
|
||||
sbm_clrprotoflags(m, flags);
|
||||
SBLASTRECORDCHK(sb);
|
||||
n = sb->sb_mb;
|
||||
if (n) {
|
||||
@ -620,11 +637,11 @@ sbappend_locked(struct sockbuf *sb, struct mbuf *m)
|
||||
* are discarded and mbufs are compacted where possible.
|
||||
*/
|
||||
void
|
||||
sbappend(struct sockbuf *sb, struct mbuf *m)
|
||||
sbappend(struct sockbuf *sb, struct mbuf *m, int flags)
|
||||
{
|
||||
|
||||
SOCKBUF_LOCK(sb);
|
||||
sbappend_locked(sb, m);
|
||||
sbappend_locked(sb, m, flags);
|
||||
SOCKBUF_UNLOCK(sb);
|
||||
}
|
||||
|
||||
|
@ -113,15 +113,6 @@ static int getpeername1(struct thread *td, struct getpeername_args *uap,
|
||||
|
||||
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
|
||||
sfstat_init(const void *unused)
|
||||
{
|
||||
@ -1858,13 +1849,12 @@ sf_ext_free(void *arg1, void *arg2)
|
||||
sf_buf_free(sf);
|
||||
|
||||
vm_page_lock(pg);
|
||||
vm_page_unwire(pg, PQ_INACTIVE);
|
||||
/*
|
||||
* Check for the object going away on us. This can
|
||||
* happen since we don't hold a reference to it.
|
||||
* 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_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)
|
||||
*
|
||||
@ -1974,103 +2001,252 @@ freebsd4_sendfile(struct thread *td, struct freebsd4_sendfile_args *uap)
|
||||
}
|
||||
#endif /* COMPAT_FREEBSD4 */
|
||||
|
||||
static int
|
||||
sendfile_readpage(vm_object_t obj, struct vnode *vp, int nd,
|
||||
off_t off, int xfsize, int bsize, struct thread *td, vm_page_t *res)
|
||||
/*
|
||||
* How much data to put into page i of n.
|
||||
* 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);
|
||||
VM_OBJECT_WLOCK(obj);
|
||||
m = vm_page_grab(obj, pindex, (vp != NULL ? VM_ALLOC_NOBUSY |
|
||||
VM_ALLOC_IGN_SBUSY : 0) | VM_ALLOC_WIRED | VM_ALLOC_NORMAL);
|
||||
if (i == 0)
|
||||
return (omin(PAGE_SIZE - (off & PAGE_MASK), len));
|
||||
|
||||
/*
|
||||
* Check if page is valid for what we need, otherwise initiate I/O.
|
||||
*
|
||||
* The non-zero nd argument prevents disk I/O, instead we
|
||||
* 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.
|
||||
*/
|
||||
if (m->valid != 0 && vm_page_is_valid(m, off & PAGE_MASK, xfsize)) {
|
||||
if (vp == NULL)
|
||||
vm_page_xunbusy(m);
|
||||
VM_OBJECT_WUNLOCK(obj);
|
||||
*res = m;
|
||||
return (0);
|
||||
} else if (nd != 0) {
|
||||
if (vp == NULL)
|
||||
vm_page_xunbusy(m);
|
||||
error = nd;
|
||||
goto free_page;
|
||||
if (i == n - 1 && ((off + len) & PAGE_MASK) > 0)
|
||||
return ((off + len) & PAGE_MASK);
|
||||
|
||||
return (PAGE_SIZE);
|
||||
}
|
||||
|
||||
/*
|
||||
* Offset within object for i page.
|
||||
*/
|
||||
static inline vm_offset_t
|
||||
vmoff(int i, off_t off)
|
||||
{
|
||||
|
||||
if (i == 0)
|
||||
return ((vm_offset_t)off);
|
||||
|
||||
return (trunc_page(off + i * PAGE_SIZE));
|
||||
}
|
||||
|
||||
/*
|
||||
* 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++;
|
||||
}
|
||||
|
||||
/*
|
||||
* Get the page from backing store.
|
||||
*/
|
||||
error = 0;
|
||||
if (vp != NULL) {
|
||||
VM_OBJECT_WUNLOCK(obj);
|
||||
readahead = sfreadahead * MAXBSIZE;
|
||||
/* Rest of pages are full sized. */
|
||||
*space -= (old - new) * PAGE_SIZE;
|
||||
|
||||
KASSERT(*space >= 0, ("%s: space went backwards", __func__));
|
||||
}
|
||||
|
||||
/*
|
||||
* 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
|
||||
* the vnode, to allow the read-ahead.
|
||||
* I/O operation failed. The state of data in the socket
|
||||
* 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
|
||||
* pass in NOCRED. This is probably wrong, but is
|
||||
* consistent with our original implementation.
|
||||
* The socket would be marked with EIO and made available
|
||||
* for read, so that application receives EIO on next
|
||||
* syscall and eventually closes the socket.
|
||||
*/
|
||||
error = vn_rdwr(UIO_READ, vp, NULL, readahead, trunc_page(off),
|
||||
UIO_NOCOPY, IO_NODELOCKED | IO_VMIO | ((readahead /
|
||||
bsize) << IO_SEQSHIFT), td->td_ucred, NOCRED, &resid, td);
|
||||
SFSTAT_INC(sf_iocnt);
|
||||
VM_OBJECT_WLOCK(obj);
|
||||
so->so_proto->pr_usrreqs->pru_abort(so);
|
||||
so->so_error = EIO;
|
||||
|
||||
m = sfio->m;
|
||||
for (int i = 0; i < sfio->npages; i++)
|
||||
m = m_free(m);
|
||||
} else {
|
||||
if (vm_pager_has_page(obj, pindex, NULL, NULL)) {
|
||||
rv = vm_pager_get_pages(obj, &m, 1, NULL, NULL);
|
||||
SFSTAT_INC(sf_iocnt);
|
||||
if (rv != VM_PAGER_OK) {
|
||||
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);
|
||||
CURVNET_SET(so->so_vnet);
|
||||
(void )(so->so_proto->pr_usrreqs->pru_ready)(so, sfio->m,
|
||||
sfio->npages);
|
||||
CURVNET_RESTORE();
|
||||
}
|
||||
if (error == 0) {
|
||||
*res = m;
|
||||
} else if (m != NULL) {
|
||||
free_page:
|
||||
vm_page_lock(m);
|
||||
vm_page_unwire(m, PQ_INACTIVE);
|
||||
|
||||
/* XXXGL: curthread */
|
||||
fdrop(sfio->sock_fp, curthread);
|
||||
free(sfio, M_TEMP);
|
||||
}
|
||||
|
||||
/*
|
||||
* 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
|
||||
* not and it is not valid, then free it.
|
||||
* Now 'i' points to first invalid page, iterate further
|
||||
* 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))
|
||||
vm_page_free(m);
|
||||
vm_page_unlock(m);
|
||||
for (j = i + 1; j < npages; j++)
|
||||
if (vm_page_is_valid(pa[j], vmoff(j, off) & PAGE_MASK,
|
||||
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);
|
||||
return (error);
|
||||
|
||||
if (nios == 0 && npages != 0)
|
||||
SFSTAT_INC(sf_noiocnt);
|
||||
|
||||
return (nios);
|
||||
}
|
||||
|
||||
static int
|
||||
@ -2178,80 +2354,65 @@ vn_sendfile(struct file *fp, int sockfd, struct uio *hdr_uio,
|
||||
struct vnode *vp;
|
||||
struct vm_object *obj;
|
||||
struct socket *so;
|
||||
struct mbuf *m;
|
||||
struct mbuf *m, *mh, *mhtail;
|
||||
struct sf_buf *sf;
|
||||
struct vm_page *pg;
|
||||
struct shmfd *shmfd;
|
||||
struct sendfile_sync *sfs;
|
||||
struct vattr va;
|
||||
off_t off, xfsize, fsbytes, sbytes, rem, obj_size;
|
||||
int error, bsize, nd, hdrlen, mnw;
|
||||
off_t off, sbytes, rem, obj_size;
|
||||
int error, softerr, bsize, hdrlen;
|
||||
|
||||
pg = NULL;
|
||||
obj = NULL;
|
||||
so = NULL;
|
||||
m = NULL;
|
||||
m = mh = NULL;
|
||||
sfs = NULL;
|
||||
fsbytes = sbytes = 0;
|
||||
hdrlen = mnw = 0;
|
||||
rem = nbytes;
|
||||
obj_size = 0;
|
||||
sbytes = 0;
|
||||
softerr = 0;
|
||||
|
||||
error = sendfile_getobj(td, fp, &obj, &vp, &shmfd, &obj_size, &bsize);
|
||||
if (error != 0)
|
||||
return (error);
|
||||
if (rem == 0)
|
||||
rem = obj_size;
|
||||
|
||||
error = kern_sendfile_getsock(td, sockfd, &sock_fp, &so);
|
||||
if (error != 0)
|
||||
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
|
||||
error = mac_socket_check_send(td->td_ucred, so);
|
||||
if (error != 0)
|
||||
goto out;
|
||||
#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 (hdr_uio != NULL) {
|
||||
if (hdr_uio != NULL && hdr_uio->uio_resid > 0) {
|
||||
hdr_uio->uio_td = td;
|
||||
hdr_uio->uio_rw = UIO_WRITE;
|
||||
if (hdr_uio->uio_resid > 0) {
|
||||
/*
|
||||
* In FBSD < 5.0 the nbytes to send also included
|
||||
* the header. If compat is specified subtract the
|
||||
* header size from nbytes.
|
||||
*/
|
||||
if (kflags & SFK_COMPAT) {
|
||||
if (nbytes > hdr_uio->uio_resid)
|
||||
nbytes -= hdr_uio->uio_resid;
|
||||
else
|
||||
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);
|
||||
/*
|
||||
* In FBSD < 5.0 the nbytes to send also included
|
||||
* the header. If compat is specified subtract the
|
||||
* header size from nbytes.
|
||||
*/
|
||||
if (kflags & SFK_COMPAT) {
|
||||
if (nbytes > hdr_uio->uio_resid)
|
||||
nbytes -= hdr_uio->uio_resid;
|
||||
else
|
||||
nbytes = 0;
|
||||
}
|
||||
}
|
||||
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.
|
||||
@ -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
|
||||
* 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;
|
||||
int loopbytes;
|
||||
int space;
|
||||
int done;
|
||||
|
||||
if ((nbytes != 0 && nbytes == fsbytes) ||
|
||||
(nbytes == 0 && obj_size == fsbytes))
|
||||
break;
|
||||
int nios, space, npages, rhpages;
|
||||
|
||||
mtail = NULL;
|
||||
loopbytes = 0;
|
||||
space = 0;
|
||||
done = 0;
|
||||
|
||||
/*
|
||||
* Check the socket state for ongoing connection,
|
||||
* no errors and space in socket buffer.
|
||||
@ -2362,49 +2515,58 @@ retry_space:
|
||||
VOP_UNLOCK(vp, 0);
|
||||
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
|
||||
* dumped into socket buffer.
|
||||
*/
|
||||
while (space > loopbytes) {
|
||||
vm_offset_t pgoff;
|
||||
pa = sfio->pa;
|
||||
for (int i = 0; i < npages; i++) {
|
||||
struct mbuf *m0;
|
||||
|
||||
/*
|
||||
* Calculate the amount to transfer.
|
||||
* Not to exceed a page, the EOF,
|
||||
* or the passed in nbytes.
|
||||
* If a page wasn't grabbed successfully, then
|
||||
* trim the array. Can happen only with SF_NODISKIO.
|
||||
*/
|
||||
pgoff = (vm_offset_t)(off & PAGE_MASK);
|
||||
rem = obj_size - offset;
|
||||
if (nbytes != 0)
|
||||
rem = omin(rem, nbytes);
|
||||
rem -= fsbytes + loopbytes;
|
||||
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 */
|
||||
if (pa[i] == NULL) {
|
||||
SFSTAT_INC(sf_busy);
|
||||
fixspace(npages, i, off, &space);
|
||||
npages = i;
|
||||
softerr = EBUSY;
|
||||
break;
|
||||
}
|
||||
|
||||
@ -2417,56 +2579,59 @@ retry_space:
|
||||
* threads might exhaust the buffers and then
|
||||
* deadlock.
|
||||
*/
|
||||
sf = sf_buf_alloc(pg, (mnw || m != NULL) ? SFB_NOWAIT :
|
||||
SFB_CATCH);
|
||||
sf = sf_buf_alloc(pa[i],
|
||||
m != NULL ? SFB_NOWAIT : SFB_CATCH);
|
||||
if (sf == NULL) {
|
||||
SFSTAT_INC(sf_allocfail);
|
||||
vm_page_lock(pg);
|
||||
vm_page_unwire(pg, PQ_INACTIVE);
|
||||
KASSERT(pg->object != NULL,
|
||||
("%s: object disappeared", __func__));
|
||||
vm_page_unlock(pg);
|
||||
for (int j = i; j < npages; j++) {
|
||||
vm_page_lock(pa[j]);
|
||||
vm_page_unwire(pa[j], PQ_INACTIVE);
|
||||
vm_page_unlock(pa[j]);
|
||||
}
|
||||
if (m == NULL)
|
||||
error = (mnw ? EAGAIN : EINTR);
|
||||
softerr = ENOBUFS;
|
||||
fixspace(npages, i, off, &space);
|
||||
npages = i;
|
||||
break;
|
||||
}
|
||||
|
||||
/*
|
||||
* Get an mbuf and set it up as having
|
||||
* 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_get(M_WAITOK, MT_DATA);
|
||||
m0->m_ext.ext_buf = (char *)sf_buf_kva(sf);
|
||||
m0->m_ext.ext_size = PAGE_SIZE;
|
||||
m0->m_ext.ext_arg1 = sf;
|
||||
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_flags |= (M_EXT|M_RDONLY);
|
||||
m0->m_data = (char *)sf_buf_kva(sf) + pgoff;
|
||||
m0->m_len = xfsize;
|
||||
m0->m_flags |= (M_EXT | M_RDONLY);
|
||||
if (nios)
|
||||
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. */
|
||||
if (mtail != NULL)
|
||||
mtail->m_next = m0;
|
||||
else if (m != NULL)
|
||||
m_last(m)->m_next = m0;
|
||||
else
|
||||
m = m0;
|
||||
mtail = m0;
|
||||
|
||||
/* Keep track of bits processed. */
|
||||
loopbytes += xfsize;
|
||||
off += xfsize;
|
||||
|
||||
if (sfs != NULL) {
|
||||
mtx_lock(&sfs->mtx);
|
||||
sfs->count++;
|
||||
@ -2477,49 +2642,60 @@ retry_space:
|
||||
if (vp != NULL)
|
||||
VOP_UNLOCK(vp, 0);
|
||||
|
||||
/* Add the buffer chain to the socket buffer. */
|
||||
if (m != NULL) {
|
||||
int mlen, err;
|
||||
/* Keep track of bytes processed. */
|
||||
off += space;
|
||||
rem -= space;
|
||||
|
||||
mlen = m_length(m, NULL);
|
||||
SOCKBUF_LOCK(&so->so_snd);
|
||||
if (so->so_snd.sb_state & SBS_CANTSENDMORE) {
|
||||
error = EPIPE;
|
||||
SOCKBUF_UNLOCK(&so->so_snd);
|
||||
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 */
|
||||
/* Prepend header, if any. */
|
||||
if (hdrlen) {
|
||||
mhtail->m_next = m;
|
||||
m = mh;
|
||||
mh = NULL;
|
||||
}
|
||||
|
||||
/* Quit outer loop on error or when we're done. */
|
||||
if (done)
|
||||
break;
|
||||
if (error != 0)
|
||||
if (m == NULL) {
|
||||
KASSERT(softerr, ("%s: m NULL, no error", __func__));
|
||||
error = softerr;
|
||||
free(sfio, M_TEMP);
|
||||
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 @@ out:
|
||||
fdrop(sock_fp, td);
|
||||
if (m)
|
||||
m_freem(m);
|
||||
if (mh)
|
||||
m_freem(mh);
|
||||
|
||||
if (sfs != NULL) {
|
||||
mtx_lock(&sfs->mtx);
|
||||
|
@ -981,7 +981,7 @@ uipc_send(struct socket *so, int flags, struct mbuf *m, struct sockaddr *nam,
|
||||
control))
|
||||
control = NULL;
|
||||
} else
|
||||
sbappend_locked(&so2->so_rcv, m);
|
||||
sbappend_locked(&so2->so_rcv, m, flags);
|
||||
break;
|
||||
|
||||
case SOCK_SEQPACKET: {
|
||||
|
@ -81,6 +81,7 @@ struct sysentvec elf64_freebsd_sysvec = {
|
||||
.sv_syscallnames = syscallnames,
|
||||
.sv_schedtail = NULL,
|
||||
.sv_thread_detach = NULL,
|
||||
.sv_trap = NULL,
|
||||
};
|
||||
|
||||
static Elf64_Brandinfo freebsd_brand_info = {
|
||||
@ -135,6 +136,7 @@ struct sysentvec elf32_freebsd_sysvec = {
|
||||
.sv_syscallnames = syscallnames,
|
||||
.sv_schedtail = NULL,
|
||||
.sv_thread_detach = NULL,
|
||||
.sv_trap = NULL,
|
||||
};
|
||||
|
||||
static Elf32_Brandinfo freebsd_brand_info = {
|
||||
|
@ -104,6 +104,7 @@ struct sysentvec elf32_freebsd_sysvec = {
|
||||
.sv_syscallnames = freebsd32_syscallnames,
|
||||
.sv_schedtail = NULL,
|
||||
.sv_thread_detach = NULL,
|
||||
.sv_trap = NULL,
|
||||
};
|
||||
INIT_SYSENTVEC(elf32_sysvec, &elf32_freebsd_sysvec);
|
||||
|
||||
|
@ -113,9 +113,8 @@ arc_output(struct ifnet *ifp, struct mbuf *m, const struct sockaddr *dst,
|
||||
|
||||
error = 0;
|
||||
#if defined(INET) || defined(INET6)
|
||||
if (ro != NULL && ro->ro_rt != NULL &&
|
||||
(ro->ro_rt->rt_flags & RTF_GATEWAY) != 0)
|
||||
is_gw = 1;
|
||||
if (ro != NULL)
|
||||
is_gw = (ro->ro_flags & RT_HAS_GW) != 0;
|
||||
#endif
|
||||
|
||||
switch (dst->sa_family) {
|
||||
|
@ -202,7 +202,6 @@ ether_resolve_addr(struct ifnet *ifp, struct mbuf *m,
|
||||
uint32_t *pflags)
|
||||
{
|
||||
struct ether_header *eh;
|
||||
struct rtentry *rt;
|
||||
uint32_t lleflags = 0;
|
||||
int error = 0;
|
||||
#if defined(INET) || defined(INET6)
|
||||
@ -253,8 +252,7 @@ ether_resolve_addr(struct ifnet *ifp, struct mbuf *m,
|
||||
}
|
||||
|
||||
if (error == EHOSTDOWN) {
|
||||
rt = (ro != NULL) ? ro->ro_rt : NULL;
|
||||
if (rt != NULL && (rt->rt_flags & RTF_GATEWAY) != 0)
|
||||
if (ro != NULL && (ro->ro_flags & RT_HAS_GW) != 0)
|
||||
error = EHOSTUNREACH;
|
||||
}
|
||||
|
||||
|
@ -119,9 +119,8 @@ fddi_output(struct ifnet *ifp, struct mbuf *m, const struct sockaddr *dst,
|
||||
getmicrotime(&ifp->if_lastchange);
|
||||
|
||||
#if defined(INET) || defined(INET6)
|
||||
if (ro != NULL && ro->ro_rt != NULL &&
|
||||
(ro->ro_rt->rt_flags & RTF_GATEWAY) != 0)
|
||||
is_gw = 1;
|
||||
if (ro != NULL)
|
||||
is_gw = (ro->ro_flags & RT_HAS_GW) != 0;
|
||||
#endif
|
||||
|
||||
switch (dst->sa_family) {
|
||||
|
@ -106,9 +106,8 @@ firewire_output(struct ifnet *ifp, struct mbuf *m, const struct sockaddr *dst,
|
||||
}
|
||||
|
||||
#if defined(INET) || defined(INET6)
|
||||
if (ro != NULL && ro->ro_rt != NULL &&
|
||||
(ro->ro_rt->rt_flags & RTF_GATEWAY) != 0)
|
||||
is_gw = 1;
|
||||
if (ro != NULL)
|
||||
is_gw = (ro->ro_flags & RT_HAS_GW) != 0;
|
||||
#endif
|
||||
/*
|
||||
* 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.
|
||||
*/
|
||||
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);
|
||||
if (error)
|
||||
return (error == EWOULDBLOCK ? 0 : error);
|
||||
|
@ -214,12 +214,8 @@ iso88025_output(struct ifnet *ifp, struct mbuf *m, const struct sockaddr *dst,
|
||||
struct rtentry *rt0 = NULL;
|
||||
int is_gw = 0;
|
||||
|
||||
if (ro != NULL) {
|
||||
rt0 = ro->ro_rt;
|
||||
if (rt0 != NULL && (rt0->rt_flags & RTF_GATEWAY) != 0)
|
||||
is_gw = 1;
|
||||
}
|
||||
|
||||
if (ro != NULL)
|
||||
is_gw = (ro->ro_flags & RT_HAS_GW) != 0;
|
||||
#ifdef MAC
|
||||
error = mac_ifnet_check_transmit(ifp, m);
|
||||
if (error)
|
||||
|
@ -202,15 +202,12 @@ looutput(struct ifnet *ifp, struct mbuf *m, const struct sockaddr *dst,
|
||||
struct route *ro)
|
||||
{
|
||||
u_int32_t af;
|
||||
struct rtentry *rt = NULL;
|
||||
#ifdef MAC
|
||||
int error;
|
||||
#endif
|
||||
|
||||
M_ASSERTPKTHDR(m); /* check if we have the packet header */
|
||||
|
||||
if (ro != NULL)
|
||||
rt = ro->ro_rt;
|
||||
#ifdef MAC
|
||||
error = mac_ifnet_check_transmit(ifp, m);
|
||||
if (error) {
|
||||
@ -219,10 +216,9 @@ looutput(struct ifnet *ifp, struct mbuf *m, const struct sockaddr *dst,
|
||||
}
|
||||
#endif
|
||||
|
||||
if (rt && rt->rt_flags & (RTF_REJECT|RTF_BLACKHOLE)) {
|
||||
if (ro != NULL && ro->ro_flags & (RT_REJECT|RT_BLACKHOLE)) {
|
||||
m_freem(m);
|
||||
return (rt->rt_flags & RTF_BLACKHOLE ? 0 :
|
||||
rt->rt_flags & RTF_HOST ? EHOSTUNREACH : ENETUNREACH);
|
||||
return (ro->ro_flags & RT_BLACKHOLE ? 0 : EHOSTUNREACH);
|
||||
}
|
||||
|
||||
if_inc_counter(ifp, IFCOUNTER_OPACKETS, 1);
|
||||
|
@ -197,14 +197,49 @@ rt_mpath_conflict(struct radix_node_head *rnh, struct rtentry *rt,
|
||||
return (0);
|
||||
}
|
||||
|
||||
void
|
||||
rtalloc_mpath_fib(struct route *ro, uint32_t hash, u_int fibnum)
|
||||
static struct rtentry *
|
||||
rt_mpath_selectrte(struct rtentry *rte, uint32_t hash)
|
||||
{
|
||||
struct radix_node *rn0, *rn;
|
||||
u_int32_t n;
|
||||
struct rtentry *rt;
|
||||
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
|
||||
* be done for sendto(3) case?
|
||||
@ -222,34 +257,18 @@ rtalloc_mpath_fib(struct route *ro, uint32_t hash, u_int fibnum)
|
||||
return;
|
||||
}
|
||||
|
||||
/* beyond here, we use rn as the master copy */
|
||||
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;
|
||||
}
|
||||
rt = rt_mpath_selectrte(ro->ro_rt, hash);
|
||||
/* XXX try filling rt_gwroute and avoid unreachable gw */
|
||||
|
||||
/* gw selection has failed - there must be only zero weight routes */
|
||||
if (!rn) {
|
||||
if (!rt) {
|
||||
RT_UNLOCK(ro->ro_rt);
|
||||
ro->ro_rt = NULL;
|
||||
return;
|
||||
}
|
||||
if (ro->ro_rt != rt) {
|
||||
RTFREE_LOCKED(ro->ro_rt);
|
||||
ro->ro_rt = (struct rtentry *)rn;
|
||||
ro->ro_rt = rt;
|
||||
RT_LOCK(ro->ro_rt);
|
||||
RT_ADDREF(ro->ro_rt);
|
||||
|
||||
|
@ -52,6 +52,7 @@ int rt_mpath_conflict(struct radix_node_head *, struct rtentry *,
|
||||
struct sockaddr *);
|
||||
void rtalloc_mpath_fib(struct route *, u_int32_t, u_int);
|
||||
#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_head *);
|
||||
int rt_mpath_deldup(struct rtentry *, struct rtentry *);
|
||||
|
@ -568,7 +568,7 @@ rtredirect_fib(struct sockaddr *dst,
|
||||
struct sockaddr *src,
|
||||
u_int fibnum)
|
||||
{
|
||||
struct rtentry *rt, *rt0 = NULL;
|
||||
struct rtentry *rt;
|
||||
int error = 0;
|
||||
short *stat = NULL;
|
||||
struct rt_addrinfo info;
|
||||
@ -627,7 +627,7 @@ rtredirect_fib(struct sockaddr *dst,
|
||||
* Create new route, rather than smashing route to net.
|
||||
*/
|
||||
create:
|
||||
rt0 = rt;
|
||||
RTFREE(rt);
|
||||
rt = NULL;
|
||||
|
||||
flags |= RTF_DYNAMIC;
|
||||
@ -637,21 +637,14 @@ rtredirect_fib(struct sockaddr *dst,
|
||||
info.rti_info[RTAX_NETMASK] = netmask;
|
||||
info.rti_ifa = ifa;
|
||||
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);
|
||||
if (rt != NULL) {
|
||||
RT_LOCK(rt);
|
||||
if (rt0 != NULL)
|
||||
EVENTHANDLER_INVOKE(route_redirect_event, rt0, rt, dst);
|
||||
flags = rt->rt_flags;
|
||||
}
|
||||
if (rt0 != NULL)
|
||||
RTFREE(rt0);
|
||||
|
||||
stat = &V_rtstat.rts_dynamic;
|
||||
} else {
|
||||
struct rtentry *gwrt;
|
||||
|
||||
/*
|
||||
* Smash the current notion of the gateway to
|
||||
@ -669,11 +662,7 @@ rtredirect_fib(struct sockaddr *dst,
|
||||
RADIX_NODE_HEAD_LOCK(rnh);
|
||||
RT_LOCK(rt);
|
||||
rt_setgate(rt, rt_key(rt), gateway);
|
||||
gwrt = rtalloc1(gateway, 1, RTF_RNH_LOCKED);
|
||||
RADIX_NODE_HEAD_UNLOCK(rnh);
|
||||
EVENTHANDLER_INVOKE(route_redirect_event, rt, gwrt, dst);
|
||||
if (gwrt)
|
||||
RTFREE_LOCKED(gwrt);
|
||||
}
|
||||
} else
|
||||
error = EHOSTUNREACH;
|
||||
@ -858,7 +847,7 @@ rt_exportinfo(struct rtentry *rt, struct rt_addrinfo *info, int flags)
|
||||
src = rt_key(rt);
|
||||
dst = info->rti_info[RTAX_DST];
|
||||
sa_len = src->sa_len;
|
||||
if (src != NULL && dst != NULL) {
|
||||
if (dst != NULL) {
|
||||
if (src->sa_len > dst->sa_len)
|
||||
return (ENOMEM);
|
||||
memcpy(dst, src, src->sa_len);
|
||||
|
@ -64,9 +64,13 @@ struct route {
|
||||
|
||||
#define RT_CACHING_CONTEXT 0x1 /* XXX: not used anywhere */
|
||||
#define RT_NORTREF 0x2 /* doesn't hold reference on ro_rt */
|
||||
#define RT_L2_ME (1 << RT_L2_ME_BIT)
|
||||
#define RT_MAY_LOOP (1 << RT_MAY_LOOP_BIT)
|
||||
#define RT_HAS_HEADER (1 << RT_HAS_HEADER_BIT)
|
||||
#define RT_L2_ME (1 << RT_L2_ME_BIT) /* 0x0004 */
|
||||
#define RT_MAY_LOOP (1 << RT_MAY_LOOP_BIT) /* 0x0008 */
|
||||
#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 {
|
||||
u_long rmx_locks; /* Kernel must leave these values alone */
|
||||
@ -215,6 +219,21 @@ fib_rte_to_nh_flags(int rt_flags)
|
||||
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.
|
||||
*/
|
||||
@ -467,9 +486,6 @@ int rib_lookup_info(uint32_t, const struct sockaddr *, uint32_t, uint32_t,
|
||||
struct rt_addrinfo *);
|
||||
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
|
||||
|
@ -34,6 +34,7 @@ __FBSDID("$FreeBSD$");
|
||||
#include <sys/param.h>
|
||||
#include <sys/kernel.h>
|
||||
#include <sys/systm.h>
|
||||
#include <sys/eventhandler.h>
|
||||
#include <sys/linker.h>
|
||||
#include <sys/mbuf.h>
|
||||
#include <sys/module.h>
|
||||
|
@ -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 */
|
||||
sbappend(&pcb->so->so_snd, m);
|
||||
sbappend(&pcb->so->so_snd, m, flags);
|
||||
m = NULL;
|
||||
|
||||
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;
|
||||
} else {
|
||||
/* Append packet to the socket receive queue */
|
||||
sbappend(&pcb->so->so_rcv, m0);
|
||||
sbappend(&pcb->so->so_rcv, m0, 0);
|
||||
m0 = NULL;
|
||||
|
||||
sorwakeup(pcb->so);
|
||||
|
@ -37,6 +37,7 @@ __FBSDID("$FreeBSD$");
|
||||
#include <sys/systm.h>
|
||||
#include <sys/counter.h>
|
||||
#include <sys/kernel.h>
|
||||
#include <sys/ktr.h>
|
||||
#include <sys/limits.h>
|
||||
#include <sys/mbuf.h>
|
||||
#include <sys/syslog.h>
|
||||
|
@ -35,6 +35,7 @@ __FBSDID("$FreeBSD$");
|
||||
#include <sys/systm.h>
|
||||
#include <sys/counter.h>
|
||||
#include <sys/kernel.h>
|
||||
#include <sys/ktr.h>
|
||||
#include <sys/limits.h>
|
||||
#include <sys/mbuf.h>
|
||||
#include <sys/syslog.h>
|
||||
|
@ -38,6 +38,7 @@ __FBSDID("$FreeBSD$");
|
||||
#include <sys/systm.h>
|
||||
#include <sys/counter.h>
|
||||
#include <sys/kernel.h>
|
||||
#include <sys/ktr.h>
|
||||
#include <sys/limits.h>
|
||||
#include <sys/mbuf.h>
|
||||
#include <sys/socket.h>
|
||||
|
@ -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);
|
||||
if (rn != NULL && ((rn->rn_flags & RNF_ROOT) == 0)) {
|
||||
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 */
|
||||
if (RT_LINK_IS_UP(rte->rt_ifp)) {
|
||||
fib4_rte_to_nh_extended(rte, dst, flags, pnh4);
|
||||
|
@ -51,6 +51,7 @@ __FBSDID("$FreeBSD$");
|
||||
#include <sys/malloc.h>
|
||||
#include <sys/mbuf.h>
|
||||
#include <sys/callout.h>
|
||||
#include <sys/eventhandler.h>
|
||||
#include <sys/domain.h>
|
||||
#include <sys/protosw.h>
|
||||
#include <sys/rmlock.h>
|
||||
|
@ -65,6 +65,8 @@ __FBSDID("$FreeBSD$");
|
||||
|
||||
#include <sys/param.h>
|
||||
#include <sys/systm.h>
|
||||
#include <sys/lock.h>
|
||||
#include <sys/mutex.h>
|
||||
#include <sys/socket.h>
|
||||
#include <sys/sockio.h>
|
||||
#include <sys/mbuf.h>
|
||||
|
@ -77,6 +77,7 @@ __FBSDID("$FreeBSD$");
|
||||
#include <sys/param.h>
|
||||
#include <sys/kernel.h>
|
||||
#include <sys/stddef.h>
|
||||
#include <sys/eventhandler.h>
|
||||
#include <sys/lock.h>
|
||||
#include <sys/ktr.h>
|
||||
#include <sys/malloc.h>
|
||||
|
@ -376,6 +376,7 @@ again:
|
||||
ia = ifatoia(rte->rt_ifa);
|
||||
ifp = rte->rt_ifp;
|
||||
counter_u64_add(rte->rt_pksent, 1);
|
||||
rt_update_ro_flags(ro);
|
||||
if (rte->rt_flags & RTF_GATEWAY)
|
||||
gw = (struct sockaddr_in *)rte->rt_gateway;
|
||||
if (rte->rt_flags & RTF_HOST)
|
||||
|
@ -40,6 +40,7 @@ __FBSDID("$FreeBSD$");
|
||||
#include <sys/param.h>
|
||||
#include <sys/jail.h>
|
||||
#include <sys/kernel.h>
|
||||
#include <sys/eventhandler.h>
|
||||
#include <sys/lock.h>
|
||||
#include <sys/malloc.h>
|
||||
#include <sys/mbuf.h>
|
||||
|
@ -38,6 +38,7 @@ __FBSDID("$FreeBSD$");
|
||||
|
||||
#include <sys/param.h>
|
||||
#include <sys/kernel.h>
|
||||
#include <sys/eventhandler.h>
|
||||
#include <sys/malloc.h>
|
||||
#include <sys/mbuf.h>
|
||||
#include <sys/socket.h>
|
||||
|
@ -41,6 +41,7 @@ __FBSDID("$FreeBSD$");
|
||||
#include <sys/param.h>
|
||||
#include <sys/systm.h>
|
||||
#include <sys/callout.h>
|
||||
#include <sys/eventhandler.h>
|
||||
#include <sys/hhook.h>
|
||||
#include <sys/kernel.h>
|
||||
#include <sys/khelp.h>
|
||||
|
@ -70,7 +70,6 @@ static TAILQ_HEAD(, toedev) toedev_list;
|
||||
static eventhandler_tag listen_start_eh;
|
||||
static eventhandler_tag listen_stop_eh;
|
||||
static eventhandler_tag lle_event_eh;
|
||||
static eventhandler_tag route_redirect_eh;
|
||||
|
||||
static int
|
||||
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);
|
||||
}
|
||||
|
||||
/*
|
||||
* 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
|
||||
* 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);
|
||||
lle_event_eh = EVENTHANDLER_REGISTER(lle_event, toe_lle_event, NULL,
|
||||
EVENTHANDLER_PRI_ANY);
|
||||
route_redirect_eh = EVENTHANDLER_REGISTER(route_redirect_event,
|
||||
toe_route_redirect_event, NULL, EVENTHANDLER_PRI_ANY);
|
||||
|
||||
return (0);
|
||||
}
|
||||
@ -553,7 +539,6 @@ toecore_unload(void)
|
||||
EVENTHANDLER_DEREGISTER(tcp_offload_listen_start, listen_start_eh);
|
||||
EVENTHANDLER_DEREGISTER(tcp_offload_listen_stop, listen_stop_eh);
|
||||
EVENTHANDLER_DEREGISTER(lle_event, lle_event_eh);
|
||||
EVENTHANDLER_DEREGISTER(route_redirect_event, route_redirect_eh);
|
||||
|
||||
mtx_unlock(&toedev_lock);
|
||||
mtx_destroy(&toedev_lock);
|
||||
|
@ -39,6 +39,7 @@ __FBSDID("$FreeBSD$");
|
||||
#include <sys/malloc.h>
|
||||
#include <sys/mbuf.h>
|
||||
#include <sys/domain.h>
|
||||
#include <sys/eventhandler.h>
|
||||
#include <sys/protosw.h>
|
||||
#include <sys/socket.h>
|
||||
#include <sys/errno.h>
|
||||
|
@ -2114,13 +2114,13 @@ icmp6_rip6_input(struct mbuf **mp, int off)
|
||||
void
|
||||
icmp6_reflect(struct mbuf *m, size_t off)
|
||||
{
|
||||
struct in6_addr src, *srcp = NULL;
|
||||
struct in6_addr src6, *srcp;
|
||||
struct ip6_hdr *ip6;
|
||||
struct icmp6_hdr *icmp6;
|
||||
struct in6_ifaddr *ia = NULL;
|
||||
struct ifnet *outif = NULL;
|
||||
int plen;
|
||||
int type, code;
|
||||
int type, code, hlim;
|
||||
|
||||
/* too short to reflect */
|
||||
if (off < sizeof(struct ip6_hdr)) {
|
||||
@ -2166,6 +2166,8 @@ icmp6_reflect(struct mbuf *m, size_t off)
|
||||
icmp6 = (struct icmp6_hdr *)(ip6 + 1);
|
||||
type = icmp6->icmp6_type; /* keep type for statistics */
|
||||
code = icmp6->icmp6_code; /* ditto. */
|
||||
hlim = 0;
|
||||
srcp = NULL;
|
||||
|
||||
/*
|
||||
* 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)) {
|
||||
ia = in6ifa_ifwithaddr(&ip6->ip6_dst, 0 /* XXX */);
|
||||
if (ia != NULL && !(ia->ia6_flags &
|
||||
(IN6_IFF_ANYCAST|IN6_IFF_NOTREADY)))
|
||||
srcp = &ia->ia_addr.sin6_addr;
|
||||
(IN6_IFF_ANYCAST|IN6_IFF_NOTREADY))) {
|
||||
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) {
|
||||
int e;
|
||||
struct sockaddr_in6 sin6;
|
||||
int error;
|
||||
struct in6_addr dst6;
|
||||
uint32_t scopeid;
|
||||
|
||||
/*
|
||||
* This case matches to multicasts, our anycast, or unicasts
|
||||
* that we do not own. Select a source address based on the
|
||||
* source address of the erroneous packet.
|
||||
*/
|
||||
bzero(&sin6, sizeof(sin6));
|
||||
sin6.sin6_family = AF_INET6;
|
||||
sin6.sin6_len = sizeof(sin6);
|
||||
sin6.sin6_addr = ip6->ip6_dst; /* zone ID should be embedded */
|
||||
in6_splitscope(&ip6->ip6_dst, &dst6, &scopeid);
|
||||
error = in6_selectsrc_addr(RT_DEFAULT_FIB, &dst6,
|
||||
scopeid, NULL, &src6, &hlim);
|
||||
|
||||
e = in6_selectsrc(&sin6, NULL, NULL, NULL, &outif, &src);
|
||||
if (e) {
|
||||
if (error) {
|
||||
char ip6buf[INET6_ADDRSTRLEN];
|
||||
nd6log((LOG_DEBUG,
|
||||
"icmp6_reflect: source can't be determined: "
|
||||
"dst=%s, error=%d\n",
|
||||
ip6_sprintf(ip6buf, &sin6.sin6_addr), e));
|
||||
ip6_sprintf(ip6buf, &ip6->ip6_dst), error));
|
||||
goto bad;
|
||||
}
|
||||
srcp = &src;
|
||||
srcp = &src6;
|
||||
}
|
||||
/*
|
||||
* 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;
|
||||
ip6->ip6_nxt = IPPROTO_ICMPV6;
|
||||
if (outif)
|
||||
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;
|
||||
ip6->ip6_hlim = hlim;
|
||||
|
||||
icmp6->icmp6_cksum = 0;
|
||||
icmp6->icmp6_cksum = in6_cksum(m, IPPROTO_ICMPV6,
|
||||
@ -2238,13 +2243,9 @@ icmp6_reflect(struct mbuf *m, size_t off)
|
||||
if (outif)
|
||||
icmp6_ifoutstat_inc(outif, type, code);
|
||||
|
||||
if (ia != NULL)
|
||||
ifa_free(&ia->ia_ifa);
|
||||
return;
|
||||
|
||||
bad:
|
||||
if (ia != NULL)
|
||||
ifa_free(&ia->ia_ifa);
|
||||
m_freem(m);
|
||||
return;
|
||||
}
|
||||
|
@ -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);
|
||||
if (rn != NULL && ((rn->rn_flags & RNF_ROOT) == 0)) {
|
||||
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 */
|
||||
if (RT_LINK_IS_UP(rte->rt_ifp)) {
|
||||
fib6_rte_to_nh_extended(rte, &sin6.sin6_addr, flags,
|
||||
|
@ -328,7 +328,6 @@ in6_pcbladdr(register struct inpcb *inp, struct sockaddr *nam,
|
||||
{
|
||||
register struct sockaddr_in6 *sin6 = (struct sockaddr_in6 *)nam;
|
||||
int error = 0;
|
||||
struct ifnet *ifp = NULL;
|
||||
int scope_ambiguous = 0;
|
||||
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)
|
||||
return (error);
|
||||
|
||||
error = in6_selectsrc(sin6, inp->in6p_outputopts,
|
||||
inp, inp->inp_cred, &ifp, &in6a);
|
||||
error = in6_selectsrc_socket(sin6, inp->in6p_outputopts,
|
||||
inp, inp->inp_cred, scope_ambiguous, &in6a, NULL);
|
||||
if (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.
|
||||
*
|
||||
* 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).
|
||||
* Is it the intended behavior?
|
||||
*/
|
||||
|
@ -107,7 +107,6 @@ in6_addroute(void *v_arg, void *n_arg, struct radix_node_head *head,
|
||||
{
|
||||
struct rtentry *rt = (struct rtentry *)treenodes;
|
||||
struct sockaddr_in6 *sin6 = (struct sockaddr_in6 *)rt_key(rt);
|
||||
struct radix_node *ret;
|
||||
|
||||
RADIX_NODE_HEAD_WLOCK_ASSERT(head);
|
||||
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);
|
||||
}
|
||||
|
||||
ret = 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);
|
||||
return (rn_addroute(v_arg, n_arg, head, treenodes));
|
||||
}
|
||||
|
||||
/*
|
||||
|
@ -136,6 +136,9 @@ static int selectroute(struct sockaddr_in6 *, struct ip6_pktopts *,
|
||||
static int in6_selectif(struct sockaddr_in6 *, struct ip6_pktopts *,
|
||||
struct ip6_moptions *, struct ifnet **,
|
||||
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 *);
|
||||
|
||||
@ -175,9 +178,9 @@ static struct in6_addrpolicy *match_addrsel_policy(struct sockaddr_in6 *);
|
||||
goto out; /* XXX: we can't use 'break' here */ \
|
||||
} while(0)
|
||||
|
||||
int
|
||||
in6_selectsrc(struct sockaddr_in6 *dstsock, struct ip6_pktopts *opts,
|
||||
struct inpcb *inp, struct ucred *cred,
|
||||
static int
|
||||
in6_selectsrc(uint32_t fibnum, struct sockaddr_in6 *dstsock,
|
||||
struct ip6_pktopts *opts, struct inpcb *inp, struct ucred *cred,
|
||||
struct ifnet **ifpp, struct in6_addr *srcp)
|
||||
{
|
||||
struct rm_priotracker in6_ifa_tracker;
|
||||
@ -228,7 +231,7 @@ in6_selectsrc(struct sockaddr_in6 *dstsock, struct ip6_pktopts *opts,
|
||||
|
||||
/* get the outgoing interface */
|
||||
if ((error = in6_selectif(dstsock, opts, mopts, &ifp, oifp,
|
||||
(inp != NULL) ? inp->inp_inc.inc_fibnum : RT_DEFAULT_FIB))
|
||||
fibnum))
|
||||
!= 0)
|
||||
return (error);
|
||||
|
||||
@ -544,6 +547,79 @@ in6_selectsrc(struct sockaddr_in6 *dstsock, struct ip6_pktopts *opts,
|
||||
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
|
||||
*/
|
||||
|
@ -418,9 +418,10 @@ int rip6_usrreq(struct socket *,
|
||||
int dest6_input(struct mbuf **, int *, int);
|
||||
int none_input(struct mbuf **, int *, int);
|
||||
|
||||
int in6_selectsrc(struct sockaddr_in6 *, struct ip6_pktopts *,
|
||||
struct inpcb *inp, struct ucred *cred,
|
||||
struct ifnet **, struct in6_addr *);
|
||||
int in6_selectsrc_socket(struct sockaddr_in6 *, struct ip6_pktopts *,
|
||||
struct inpcb *, struct ucred *, int, struct in6_addr *, int *);
|
||||
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 *,
|
||||
struct ip6_moptions *, struct route_in6 *, struct ifnet **,
|
||||
struct rtentry **);
|
||||
|
@ -481,27 +481,21 @@ nd6_ns_output_fib(struct ifnet *ifp, const struct in6_addr *saddr6,
|
||||
ifa_free(ifa);
|
||||
} else {
|
||||
int error;
|
||||
struct sockaddr_in6 dst_sa;
|
||||
struct in6_addr src_in;
|
||||
struct ifnet *oifp;
|
||||
struct in6_addr dst6, src6;
|
||||
uint32_t scopeid;
|
||||
|
||||
bzero(&dst_sa, sizeof(dst_sa));
|
||||
dst_sa.sin6_family = AF_INET6;
|
||||
dst_sa.sin6_len = sizeof(dst_sa);
|
||||
dst_sa.sin6_addr = ip6->ip6_dst;
|
||||
|
||||
oifp = ifp;
|
||||
error = in6_selectsrc(&dst_sa, NULL,
|
||||
NULL, NULL, &oifp, &src_in);
|
||||
in6_splitscope(&ip6->ip6_dst, &dst6, &scopeid);
|
||||
error = in6_selectsrc_addr(RT_DEFAULT_FIB, &dst6,
|
||||
scopeid, ifp, &src6, NULL);
|
||||
if (error) {
|
||||
char ip6buf[INET6_ADDRSTRLEN];
|
||||
nd6log((LOG_DEBUG, "%s: source can't be "
|
||||
"determined: dst=%s, error=%d\n", __func__,
|
||||
ip6_sprintf(ip6buf, &dst_sa.sin6_addr),
|
||||
ip6_sprintf(ip6buf, &dst6),
|
||||
error));
|
||||
goto bad;
|
||||
}
|
||||
ip6->ip6_src = src_in;
|
||||
ip6->ip6_src = src6;
|
||||
}
|
||||
} else {
|
||||
/*
|
||||
@ -941,12 +935,12 @@ nd6_na_output_fib(struct ifnet *ifp, const struct in6_addr *daddr6_0,
|
||||
{
|
||||
struct mbuf *m;
|
||||
struct m_tag *mtag;
|
||||
struct ifnet *oifp;
|
||||
struct ip6_hdr *ip6;
|
||||
struct nd_neighbor_advert *nd_na;
|
||||
struct ip6_moptions im6o;
|
||||
struct in6_addr src, daddr6;
|
||||
struct sockaddr_in6 dst_sa;
|
||||
struct in6_addr daddr6, dst6, src6;
|
||||
uint32_t scopeid;
|
||||
|
||||
int icmp6len, maxlen, error;
|
||||
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;
|
||||
}
|
||||
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.
|
||||
*/
|
||||
oifp = ifp;
|
||||
error = in6_selectsrc(&dst_sa, NULL, NULL, NULL, &oifp, &src);
|
||||
in6_splitscope(&daddr6, &dst6, &scopeid);
|
||||
error = in6_selectsrc_addr(RT_DEFAULT_FIB, &dst6,
|
||||
scopeid, ifp, &src6, NULL);
|
||||
if (error) {
|
||||
char ip6buf[INET6_ADDRSTRLEN];
|
||||
nd6log((LOG_DEBUG, "nd6_na_output: source can't be "
|
||||
"determined: dst=%s, error=%d\n",
|
||||
ip6_sprintf(ip6buf, &dst_sa.sin6_addr), error));
|
||||
ip6_sprintf(ip6buf, &daddr6), error));
|
||||
goto bad;
|
||||
}
|
||||
ip6->ip6_src = src;
|
||||
ip6->ip6_src = src6;
|
||||
nd_na = (struct nd_neighbor_advert *)(ip6 + 1);
|
||||
nd_na->nd_na_type = ND_NEIGHBOR_ADVERT;
|
||||
nd_na->nd_na_code = 0;
|
||||
|
@ -397,6 +397,7 @@ rip6_output(struct mbuf *m, struct socket *so, ...)
|
||||
int type = 0, code = 0; /* for ICMPv6 output statistics only */
|
||||
int scope_ambiguous = 0;
|
||||
int use_defzone = 0;
|
||||
int hlim = 0;
|
||||
struct in6_addr in6a;
|
||||
va_list ap;
|
||||
|
||||
@ -460,8 +461,9 @@ rip6_output(struct mbuf *m, struct socket *so, ...)
|
||||
/*
|
||||
* Source address selection.
|
||||
*/
|
||||
error = in6_selectsrc(dstsock, optp, in6p, so->so_cred,
|
||||
&oifp, &in6a);
|
||||
error = in6_selectsrc_socket(dstsock, optp, in6p, so->so_cred,
|
||||
scope_ambiguous, &in6a, &hlim);
|
||||
|
||||
if (error)
|
||||
goto bad;
|
||||
error = prison_check_ip6(in6p->inp_cred, &in6a);
|
||||
@ -469,19 +471,6 @@ rip6_output(struct mbuf *m, struct socket *so, ...)
|
||||
goto bad;
|
||||
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;
|
||||
|
||||
/*
|
||||
@ -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->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 ||
|
||||
in6p->in6p_cksum != -1) {
|
||||
@ -784,7 +773,6 @@ rip6_connect(struct socket *so, struct sockaddr *nam, struct thread *td)
|
||||
struct inpcb *inp;
|
||||
struct sockaddr_in6 *addr = (struct sockaddr_in6 *)nam;
|
||||
struct in6_addr in6a;
|
||||
struct ifnet *ifp = NULL;
|
||||
int error = 0, scope_ambiguous = 0;
|
||||
|
||||
inp = sotoinpcb(so);
|
||||
@ -813,21 +801,14 @@ rip6_connect(struct socket *so, struct sockaddr *nam, struct thread *td)
|
||||
INP_INFO_WLOCK(&V_ripcbinfo);
|
||||
INP_WLOCK(inp);
|
||||
/* Source address selection. XXX: need pcblookup? */
|
||||
error = in6_selectsrc(addr, inp->in6p_outputopts,
|
||||
inp, so->so_cred, &ifp, &in6a);
|
||||
error = in6_selectsrc_socket(addr, inp->in6p_outputopts,
|
||||
inp, so->so_cred, scope_ambiguous, &in6a, NULL);
|
||||
if (error) {
|
||||
INP_WUNLOCK(inp);
|
||||
INP_INFO_WUNLOCK(&V_ripcbinfo);
|
||||
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_laddr = in6a;
|
||||
soisconnected(so);
|
||||
|
@ -631,7 +631,6 @@ udp6_output(struct inpcb *inp, struct mbuf *m, struct sockaddr *addr6,
|
||||
struct udphdr *udp6;
|
||||
struct in6_addr *laddr, *faddr, in6a;
|
||||
struct sockaddr_in6 *sin6 = NULL;
|
||||
struct ifnet *oifp = NULL;
|
||||
int cscov_partial = 0;
|
||||
int scope_ambiguous = 0;
|
||||
u_short fport;
|
||||
@ -731,15 +730,10 @@ udp6_output(struct inpcb *inp, struct mbuf *m, struct sockaddr *addr6,
|
||||
}
|
||||
|
||||
if (!IN6_IS_ADDR_V4MAPPED(faddr)) {
|
||||
error = in6_selectsrc(sin6, optp, inp,
|
||||
td->td_ucred, &oifp, &in6a);
|
||||
error = in6_selectsrc_socket(sin6, optp, inp,
|
||||
td->td_ucred, scope_ambiguous, &in6a, NULL);
|
||||
if (error)
|
||||
goto release;
|
||||
if (oifp && scope_ambiguous &&
|
||||
(error = in6_setscope(&sin6->sin6_addr,
|
||||
oifp, NULL))) {
|
||||
goto release;
|
||||
}
|
||||
laddr = &in6a;
|
||||
} else
|
||||
laddr = &inp->in6p_laddr; /* XXX */
|
||||
|
@ -2097,7 +2097,7 @@ export_table_info(struct ip_fw_chain *ch, struct table_config *tc,
|
||||
i->count = table_get_count(ch, tc);
|
||||
i->limit = tc->limit;
|
||||
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);
|
||||
strlcpy(i->tablename, tc->tablename, sizeof(i->tablename));
|
||||
ti = KIDX_TO_TI(ch, tc->no.kidx);
|
||||
|
Some files were not shown because too many files have changed in this diff Show More
Loading…
x
Reference in New Issue
Block a user