From 94f0eafcd25c5e856f62c099c79fadcf7ae7cced Mon Sep 17 00:00:00 2001 From: John Baldwin Date: Thu, 5 Feb 2015 22:42:44 +0000 Subject: [PATCH 01/36] Expose the constants for internal new-bus device flags to userland. The flag value is already exposed via dv_flags, just not the meaning of the flags themselves. Use these constants to annotate devices that are disabled or suspended in devinfo output. --- lib/libdevinfo/devinfo.h | 2 +- sys/kern/subr_bus.c | 9 --------- sys/sys/bus.h | 13 ++++++++++++- usr.sbin/devinfo/devinfo.c | 4 ++++ 4 files changed, 17 insertions(+), 11 deletions(-) diff --git a/lib/libdevinfo/devinfo.h b/lib/libdevinfo/devinfo.h index c8990a6f0d13..b0b8cec49f36 100644 --- a/lib/libdevinfo/devinfo.h +++ b/lib/libdevinfo/devinfo.h @@ -50,7 +50,7 @@ struct devinfo_dev { char *dd_location; /* Where bus thinks dev at */ uint32_t dd_devflags; /* API flags */ uint16_t dd_flags; /* internal dev flags */ - devinfo_state_t dd_state; /* attacement state of dev */ + devinfo_state_t dd_state; /* attachment state of dev */ }; struct devinfo_rman { diff --git a/sys/kern/subr_bus.c b/sys/kern/subr_bus.c index a875e4b77aff..269be94322b2 100644 --- a/sys/kern/subr_bus.c +++ b/sys/kern/subr_bus.c @@ -128,15 +128,6 @@ struct device { device_state_t state; /**< current device state */ uint32_t devflags; /**< api level flags for device_get_flags() */ u_int flags; /**< internal device flags */ -#define DF_ENABLED 0x01 /* device should be probed/attached */ -#define DF_FIXEDCLASS 0x02 /* devclass specified at create time */ -#define DF_WILDCARD 0x04 /* unit was originally wildcard */ -#define DF_DESCMALLOCED 0x08 /* description was malloced */ -#define DF_QUIET 0x10 /* don't print verbose attach message */ -#define DF_DONENOMATCH 0x20 /* don't execute DEVICE_NOMATCH again */ -#define DF_EXTERNALSOFTC 0x40 /* softc not allocated by us */ -#define DF_REBID 0x80 /* Can rebid after attach */ -#define DF_SUSPENDED 0x100 /* Device is suspended. */ u_int order; /**< order from device_add_child_ordered() */ void *ivars; /**< instance variables */ void *softc; /**< current driver's variables */ diff --git a/sys/sys/bus.h b/sys/sys/bus.h index b15a5568200b..f15dd34d24c0 100644 --- a/sys/sys/bus.h +++ b/sys/sys/bus.h @@ -70,11 +70,22 @@ struct u_device { char dv_pnpinfo[128]; /**< @brief Plug and play info */ char dv_location[128]; /**< @brief Where is the device? */ uint32_t dv_devflags; /**< @brief API Flags for device */ - uint16_t dv_flags; /**< @brief flags for dev date */ + uint16_t dv_flags; /**< @brief flags for dev state */ device_state_t dv_state; /**< @brief State of attachment */ /* XXX more driver info? */ }; +/* Flags exported via dv_flags. */ +#define DF_ENABLED 0x01 /* device should be probed/attached */ +#define DF_FIXEDCLASS 0x02 /* devclass specified at create time */ +#define DF_WILDCARD 0x04 /* unit was originally wildcard */ +#define DF_DESCMALLOCED 0x08 /* description was malloced */ +#define DF_QUIET 0x10 /* don't print verbose attach message */ +#define DF_DONENOMATCH 0x20 /* don't execute DEVICE_NOMATCH again */ +#define DF_EXTERNALSOFTC 0x40 /* softc not allocated by us */ +#define DF_REBID 0x80 /* Can rebid after attach */ +#define DF_SUSPENDED 0x100 /* Device is suspended. */ + #ifdef _KERNEL #include diff --git a/usr.sbin/devinfo/devinfo.c b/usr.sbin/devinfo/devinfo.c index 32d2932b4676..40f2b0b42eba 100644 --- a/usr.sbin/devinfo/devinfo.c +++ b/usr.sbin/devinfo/devinfo.c @@ -146,6 +146,10 @@ print_device(struct devinfo_dev *dev, void *arg) printf(" pnpinfo %s", dev->dd_pnpinfo); if (vflag && *dev->dd_location) printf(" at %s", dev->dd_location); + if (!(dev->dd_flags & DF_ENABLED)) + printf(" (disabled)"); + else if (dev->dd_flags & DF_SUSPENDED) + printf(" (suspended)"); printf("\n"); if (rflag) { ia.indent = indent + 4; From 5262b957d491c244f5a75668d4dff0ec764df490 Mon Sep 17 00:00:00 2001 From: "Pedro F. Giffuni" Date: Thu, 5 Feb 2015 22:54:31 +0000 Subject: [PATCH 02/36] getdiskbyname(): plug resource leak Variable cq going out of scope leaks the storage it points to. CID: 270511 Phabric: D1775 Reviewed by: imp Obtained from: NetBSD (CVS rev. 1.34) MFC after: 2 weeks --- lib/libc/gen/disklabel.c | 24 ++++++++++++++++-------- 1 file changed, 16 insertions(+), 8 deletions(-) diff --git a/lib/libc/gen/disklabel.c b/lib/libc/gen/disklabel.c index bd15a47318e0..5c7aa96a9a0a 100644 --- a/lib/libc/gen/disklabel.c +++ b/lib/libc/gen/disklabel.c @@ -85,10 +85,13 @@ getdiskbyname(const char *name) cq++, cp++; *cq = '\0'; - if (cgetstr(buf, "ty", &cq) > 0 && strcmp(cq, "removable") == 0) - dp->d_flags |= D_REMOVABLE; - else if (cq && strcmp(cq, "simulated") == 0) - dp->d_flags |= D_RAMDISK; + if (cgetstr(buf, "ty", &cq) > 0) { + if (strcmp(cq, "removable") == 0) + dp->d_flags |= D_REMOVABLE; + else if (cq && strcmp(cq, "simulated") == 0) + dp->d_flags |= D_RAMDISK; + free(cq); + } if (cgetcap(buf, "sf", ':') != NULL) dp->d_flags |= D_BADSECT; @@ -100,9 +103,10 @@ getdiskbyname(const char *name) getnumdflt(dp->d_nsectors, "ns", 0); getnumdflt(dp->d_ncylinders, "nc", 0); - if (cgetstr(buf, "dt", &cq) > 0) + if (cgetstr(buf, "dt", &cq) > 0) { dp->d_type = gettype(cq, dktypenames); - else + free(cq); + } else getnumdflt(dp->d_type, "dt", 0); getnumdflt(dp->d_secpercyl, "sc", dp->d_nsectors * dp->d_ntracks); getnumdflt(dp->d_secperunit, "su", dp->d_secpercyl * dp->d_ncylinders); @@ -140,8 +144,11 @@ getdiskbyname(const char *name) pp->p_frag = 8; } getnumdflt(pp->p_fstype, ptype, 0); - if (pp->p_fstype == 0 && cgetstr(buf, ptype, &cq) > 0) - pp->p_fstype = gettype(cq, fstypenames); + if (pp->p_fstype == 0) + if (cgetstr(buf, ptype, &cq) >= 0) { + pp->p_fstype = gettype(cq, fstypenames); + free(cq); + } max = p; } } @@ -155,5 +162,6 @@ getdiskbyname(const char *name) dp->d_magic = DISKMAGIC; dp->d_magic2 = DISKMAGIC; free(buf); + (void)cgetclose(); return (dp); } From b20592de1b2a780f7610dba094fbb7331f31a264 Mon Sep 17 00:00:00 2001 From: "Pedro F. Giffuni" Date: Thu, 5 Feb 2015 23:02:43 +0000 Subject: [PATCH 03/36] tdelete(3): don't delete the node we are about to return. CID: 272528 Obtained from: NetBSD (CVS rev. 1.4) MFC after: 2 weeks --- lib/libc/stdlib/tdelete.c | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/lib/libc/stdlib/tdelete.c b/lib/libc/stdlib/tdelete.c index c83afb8cf3f1..a27802e84e8b 100644 --- a/lib/libc/stdlib/tdelete.c +++ b/lib/libc/stdlib/tdelete.c @@ -65,7 +65,8 @@ tdelete(const void * __restrict vkey, void ** __restrict vrootp, q->rlink = (*rootp)->rlink; } } - free(*rootp); /* D4: Free node */ + if (p != *rootp) + free(*rootp); /* D4: Free node */ *rootp = q; /* link parent to new node */ return p; } From a23f83b922cc30bb5bb5582641e4465f46cd3e84 Mon Sep 17 00:00:00 2001 From: Rui Paulo Date: Fri, 6 Feb 2015 00:02:00 +0000 Subject: [PATCH 04/36] Don't add static IPv6 routes when to all FIBs when net.add_addr_allfibs is 0. This avoids a bunch of boot time warnings when rc.d/routing runs. MFC after: 1 week --- etc/rc.d/routing | 5 +++-- 1 file changed, 3 insertions(+), 2 deletions(-) diff --git a/etc/rc.d/routing b/etc/rc.d/routing index b38147153b0a..7a3c1ab4c2e7 100755 --- a/etc/rc.d/routing +++ b/etc/rc.d/routing @@ -165,13 +165,14 @@ static_inet() static_inet6() { - local _action _if _skip fibmod fibs + local _action _if _skip fibmod fibs allfibs _action=$1 _if=$2 # get the number of FIBs supported. fibs=$((`${SYSCTL_N} net.fibs` - 1)) - if [ "$fibs" -gt 0 ]; then + allfibs=`${SYSCTL_N} net.add_addr_allfibs` + if [ "$fibs" -gt 0 ] && [ "$allfibs" -ne 0 ]; then fibmod="-fib 0-$fibs" else fibmod= From 85dc477798e186639ed14c70ac63a2a74fa72d48 Mon Sep 17 00:00:00 2001 From: Navdeep Parhar Date: Fri, 6 Feb 2015 01:10:04 +0000 Subject: [PATCH 05/36] cxgbe(4): Add a minimal if_cxl module that pulls in the real driver as a dependency. This ensures "ifconfig cxl ..." does the right thing even when it's run with no driver loaded. if_cxl.ko is the tiniest module in /boot/kernel. MFC after: 2 weeks --- sys/dev/cxgbe/if_cxl.c | 44 +++++++++++++++++++++++++++++++ sys/modules/cxgbe/Makefile | 1 + sys/modules/cxgbe/if_cxl/Makefile | 11 ++++++++ 3 files changed, 56 insertions(+) create mode 100644 sys/dev/cxgbe/if_cxl.c create mode 100644 sys/modules/cxgbe/if_cxl/Makefile diff --git a/sys/dev/cxgbe/if_cxl.c b/sys/dev/cxgbe/if_cxl.c new file mode 100644 index 000000000000..2b498dc5c449 --- /dev/null +++ b/sys/dev/cxgbe/if_cxl.c @@ -0,0 +1,44 @@ +/*- + * Copyright (c) 2015 Chelsio Communications, Inc. + * All rights reserved. + * Written by: Navdeep Parhar + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * 2. Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * + * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND + * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE + * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE + * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE + * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL + * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS + * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) + * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT + * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY + * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF + * SUCH DAMAGE. + */ + +#include +__FBSDID("$FreeBSD$"); + +#include +#include +#include + +static int +mod_event(module_t mod, int cmd, void *arg) +{ + + return (0); +} +static moduledata_t if_cxl_mod = {"if_cxl", mod_event}; +DECLARE_MODULE(if_cxl, if_cxl_mod, SI_SUB_EXEC, SI_ORDER_ANY); +MODULE_VERSION(if_cxl, 1); +MODULE_DEPEND(if_cxl, cxl, 1, 1, 1); diff --git a/sys/modules/cxgbe/Makefile b/sys/modules/cxgbe/Makefile index f7862b5cd722..a46850c1afcf 100644 --- a/sys/modules/cxgbe/Makefile +++ b/sys/modules/cxgbe/Makefile @@ -6,6 +6,7 @@ SYSDIR?=${.CURDIR}/../.. .include "${SYSDIR}/conf/kern.opts.mk" SUBDIR= if_cxgbe +SUBDIR+= if_cxl SUBDIR+= t4_firmware SUBDIR+= t5_firmware SUBDIR+= ${_tom} diff --git a/sys/modules/cxgbe/if_cxl/Makefile b/sys/modules/cxgbe/if_cxl/Makefile new file mode 100644 index 000000000000..ec4ff1ed1802 --- /dev/null +++ b/sys/modules/cxgbe/if_cxl/Makefile @@ -0,0 +1,11 @@ +# +# $FreeBSD$ +# + +CXGBE= ${.CURDIR}/../../../dev/cxgbe +.PATH: ${CXGBE} + +KMOD= if_cxl +SRCS= if_cxl.c + +.include From a1d03f4480b6aba71e524d840d9b941b77a21b13 Mon Sep 17 00:00:00 2001 From: Rui Paulo Date: Fri, 6 Feb 2015 01:42:17 +0000 Subject: [PATCH 06/36] Add a FAT label to the EFI boot1 partition. MFC after: 1 week --- sys/boot/amd64/boot1.efi/fat.tmpl.bz2.uu | 29 ++++++++++++------------ sys/boot/amd64/boot1.efi/generate-fat.sh | 2 +- 2 files changed, 15 insertions(+), 16 deletions(-) diff --git a/sys/boot/amd64/boot1.efi/fat.tmpl.bz2.uu b/sys/boot/amd64/boot1.efi/fat.tmpl.bz2.uu index 52ed67a468cb..c9044eece9a6 100644 --- a/sys/boot/amd64/boot1.efi/fat.tmpl.bz2.uu +++ b/sys/boot/amd64/boot1.efi/fat.tmpl.bz2.uu @@ -2,20 +2,19 @@ FAT template boot filesystem created by generate-fat.sh DO NOT EDIT $FreeBSD$ begin 644 fat.tmpl.bz2 -M0EIH.3%!62936=AO?&0`&J9____[ZZKJJ_^N_ZO^Z_^[OO_\`5`(0!0&#$D" -M0$)$2&(H:`81HT#)D!H-#U`T#31IH-&(``R8$9_I)6[MY/, -M(H=/()+4&!(3V0"20C3J5$L5@2`219,"T6JI,@0"2*2\=LAD6=>N6(8QSW'U+N42P^'5X@7X``23=EA``#Z,O)^-VTX@ -M`+E!=,&6PV11C:*D8K#^<%FTG-%!@PR72@\ZU0BF1Y] -MF-FPGL2L>4QCU&O/>89^#H$6^<;&WKC9W52KUX."CM6+GD;(=1!MUD,,?Y[] -MTLAG0];,:B^]M%BH0J1":_C-*2I9R3AS#,&0>$RCY'T/R?HR!?'5$MILQ:!" -M+;10A*!&^<(_/8>D8I-DTU,)ZAZ0VA-!M0T'J`>H#"9 +M'I#0-H&HQI&0&3&FH>H>*`JHHU3V]1%/4/2``T#0`!H``#0`````#1H,@``6 +M'1&G'&@?$6[T#A)?X8$A160"20BO#")0J4TB1*4GXF$B4I,&>43+=_?K=#3* +M6]R"ZNKJZI,9*68E8*E2Q +M4J5*E3'(1830A"$(12A-"<(0A#]VD)H0A"$,>I0FA"$(0I\>P^=F5:M6K5JU +M:DI3:64UN;[7%5B]Y-^\]@_K@B:N\/,5F%&H<\G#IXQXAEFC&D?![6%0'6MR +MX1@@%FC"FD`M7,/SXFNG:2`'-0<-C$8^+$N.7M1B,^6)9,DV9,0A\OL<:C"L +ML1V&,<\9YRB>XV#BG")'6NKRK^("UF2XO?_L!#29">MGDF$R3).!PX&%E,4C +M''=(FL1.`_3?CN@-IB2PI3!FF\<8X.X@D,>CA90I)#M$XRPNDFJELL<3=1?8 +M2B7\5Z64,!7Z;EEBW-MXN-4IJ@W$462]-*\YCR,-B,5[W?=3&L/U>SX,WV#\ +M\B`:I"'0Z)5"$1B.E)(K[5I4RS`%R$>Y\D0NR*,;<9CZ:^V3P(I?D Date: Fri, 6 Feb 2015 02:35:29 +0000 Subject: [PATCH 07/36] Add a comment explaining why gcc is needed. X-MFC-With: 278231 MFC after: 2 weeks --- lib/csu/powerpc64/Makefile | 4 ++++ 1 file changed, 4 insertions(+) diff --git a/lib/csu/powerpc64/Makefile b/lib/csu/powerpc64/Makefile index dd6e9fb2b501..1c93355b7c48 100644 --- a/lib/csu/powerpc64/Makefile +++ b/lib/csu/powerpc64/Makefile @@ -9,6 +9,10 @@ CFLAGS+= -I${.CURDIR}/../common \ -I${.CURDIR}/../../libc/include \ -mlongcall +# XXX: See the log for r232932 as to why the above -mlongcall is needed. Since +# clang doesn't support -mlongcall, and testing shows a clang linked with a +# clang-built csu segfaults, this must currently be compiled with gcc. Once +# clang supports -mlongcall, or we get a fixed ld, this can be revisited. CC:= gcc COMPILER_TYPE:= gcc From 85a61b4f1145c43ba179cee462ba4a671558c998 Mon Sep 17 00:00:00 2001 From: Davide Italiano Date: Fri, 6 Feb 2015 03:49:31 +0000 Subject: [PATCH 08/36] Always prefer double dashes for GNU LD long options. I discovered this while working on llvm/lld and realized export-dynamic only supported --. Although upstream will eventually grow to support both - and --, switch this in our build system, because GNU ld supports both modes, and because there's some hope lld will become the default linker for FreeBSD in the future. Discussed with: emaste, rdivacky --- sys/conf/kern.pre.mk | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/sys/conf/kern.pre.mk b/sys/conf/kern.pre.mk index cf60a770de43..f0e57361d3a5 100644 --- a/sys/conf/kern.pre.mk +++ b/sys/conf/kern.pre.mk @@ -174,7 +174,7 @@ SYSTEM_OBJS= locore.o ${MDOBJS} ${OBJS} SYSTEM_OBJS+= ${SYSTEM_CFILES:.c=.o} SYSTEM_OBJS+= hack.So SYSTEM_LD= @${LD} -Bdynamic -T ${LDSCRIPT} ${_LDFLAGS} --no-warn-mismatch \ - -warn-common -export-dynamic -dynamic-linker /red/herring \ + --warn-common --export-dynamic --dynamic-linker /red/herring \ -o ${.TARGET} -X ${SYSTEM_OBJS} vers.o SYSTEM_LD_TAIL= @${OBJCOPY} --strip-symbol gcc2_compiled. ${.TARGET} ; \ ${SIZE} ${.TARGET} ; chmod 755 ${.TARGET} From 78a786f909374eac718be84a7161381cfd489ce5 Mon Sep 17 00:00:00 2001 From: Alexander Motin Date: Fri, 6 Feb 2015 09:41:16 +0000 Subject: [PATCH 09/36] Some NetGraph debug polishing. Submitted by: Dmitry Luhtionov MFC after: 2 weeks --- lib/libnetgraph/debug.c | 29 ++++++++++++++++++++++------- 1 file changed, 22 insertions(+), 7 deletions(-) diff --git a/lib/libnetgraph/debug.c b/lib/libnetgraph/debug.c index 6d0579faef6e..f44504140b8b 100644 --- a/lib/libnetgraph/debug.c +++ b/lib/libnetgraph/debug.c @@ -62,12 +62,15 @@ __FBSDID("$FreeBSD$"); #include #include #include +#include #include +#include #include #include #include #include #include +#include #include #include #include @@ -81,15 +84,20 @@ __FBSDID("$FreeBSD$"); #include #include #include +#include #include +#include +#include #include #include #include +#include #include #include #include #include #include +#include #include #include #include @@ -129,12 +137,15 @@ static const struct ng_cookie cookies[] = { COOKIE(ATMLLC), COOKIE(BPF), COOKIE(BRIDGE), + COOKIE(CAR), COOKIE(CISCO), + COOKIE(DEFLATE), COOKIE(DEVICE), COOKIE(ECHO), COOKIE(EIFACE), COOKIE(ETF), COOKIE(ETHER), + COOKIE(ETHER_ECHO), COOKIE(FRAMERELAY), COOKIE(GIF), COOKIE(GIF_DEMUX), @@ -149,15 +160,20 @@ static const struct ng_cookie cookies[] = { COOKIE(LMI), COOKIE(MPPC), COOKIE(NAT), + COOKIE(NETFLOW), COOKIE(ONE2MANY), + COOKIE(PATCH), + COOKIE(PIPE), COOKIE(PPP), COOKIE(PPPOE), COOKIE(PPTPGRE), + COOKIE(PRED1), COOKIE(RFC1490), COOKIE(SOCKET), COOKIE(SOURCE), COOKIE(SPLIT), COOKIE(SPPP), + COOKIE(TAG), COOKIE(TCPMSS), COOKIE(TEE), COOKIE(TTY), @@ -181,9 +197,8 @@ NgSetDebug(int level) { int old = _gNgDebugLevel; - if (level < 0) - level = old; - _gNgDebugLevel = level; + if (level >= 0) + _gNgDebugLevel = level; return (old); } @@ -225,10 +240,10 @@ _NgDebugMsg(const struct ng_mesg *msg, const char *path) /* Display header stuff */ NGLOGX("NG_MESG :"); NGLOGX(" vers %d", msg->header.version); - NGLOGX(" arglen %d", msg->header.arglen); - NGLOGX(" flags %ld", msg->header.flags); - NGLOGX(" token %lu", (u_long)msg->header.token); - NGLOGX(" cookie %s (%d)", + NGLOGX(" arglen %u", msg->header.arglen); + NGLOGX(" flags %x", msg->header.flags); + NGLOGX(" token %u", msg->header.token); + NGLOGX(" cookie %s (%u)", NgCookie(msg->header.typecookie), msg->header.typecookie); /* At lower debugging levels, skip ASCII translation */ From 83d74204c863dd2988604f6532522fc611a3047f Mon Sep 17 00:00:00 2001 From: Konstantin Belousov Date: Fri, 6 Feb 2015 12:18:38 +0000 Subject: [PATCH 10/36] Fully initialize allocated memory for the new barrier. The b_destroying member was left uninitialized, which caused spurious EBUSY. PR: 197365 Noted by: Florent Guiliani Sponsored by: The FreeBSD Foundation MFC after: 1 week --- lib/libthr/thread/thr_barrier.c | 5 +---- 1 file changed, 1 insertion(+), 4 deletions(-) diff --git a/lib/libthr/thread/thr_barrier.c b/lib/libthr/thread/thr_barrier.c index 86f880efac1d..10b634608241 100644 --- a/lib/libthr/thread/thr_barrier.c +++ b/lib/libthr/thread/thr_barrier.c @@ -86,16 +86,13 @@ _pthread_barrier_init(pthread_barrier_t *barrier, if (barrier == NULL || count <= 0) return (EINVAL); - bar = malloc(sizeof(struct pthread_barrier)); + bar = calloc(1, sizeof(struct pthread_barrier)); if (bar == NULL) return (ENOMEM); _thr_umutex_init(&bar->b_lock); _thr_ucond_init(&bar->b_cv); - bar->b_cycle = 0; - bar->b_waiters = 0; bar->b_count = count; - bar->b_refcount = 0; *barrier = bar; return (0); From 24ef1d7ab6e7931630c0e0fd907f6c3f4cc37991 Mon Sep 17 00:00:00 2001 From: "Pedro F. Giffuni" Date: Fri, 6 Feb 2015 14:07:01 +0000 Subject: [PATCH 11/36] Drop cgetclose() from getdiskbyname(). This was a local addition to the original change from NetBSD. Being this libc there is some chance for it to interfere with user's cget*() functions usage. The memory leak was finely plugged by r278300. Pointed out by: ache --- lib/libc/gen/disklabel.c | 1 - 1 file changed, 1 deletion(-) diff --git a/lib/libc/gen/disklabel.c b/lib/libc/gen/disklabel.c index 5c7aa96a9a0a..8780573d1c5d 100644 --- a/lib/libc/gen/disklabel.c +++ b/lib/libc/gen/disklabel.c @@ -162,6 +162,5 @@ getdiskbyname(const char *name) dp->d_magic = DISKMAGIC; dp->d_magic2 = DISKMAGIC; free(buf); - (void)cgetclose(); return (dp); } From 02aa7d7b57f1037b0449603b4a20df6939328999 Mon Sep 17 00:00:00 2001 From: "Pedro F. Giffuni" Date: Fri, 6 Feb 2015 14:22:00 +0000 Subject: [PATCH 12/36] Update comment and NetBSD ID tag. The NetBSD revisions correspond to changes we have already done like __P() removal and ANSI-fication of definitions. --- lib/libc/stdlib/tdelete.c | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/lib/libc/stdlib/tdelete.c b/lib/libc/stdlib/tdelete.c index a27802e84e8b..bef187e81a2d 100644 --- a/lib/libc/stdlib/tdelete.c +++ b/lib/libc/stdlib/tdelete.c @@ -14,7 +14,7 @@ #include #if 0 #if defined(LIBC_SCCS) && !defined(lint) -__RCSID("$NetBSD: tdelete.c,v 1.2 1999/09/16 11:45:37 lukem Exp $"); +__RCSID("$NetBSD: tdelete.c,v 1.6 2012/06/25 22:32:45 abs Exp $"); #endif /* LIBC_SCCS and not lint */ #endif __FBSDID("$FreeBSD$"); @@ -25,9 +25,9 @@ __FBSDID("$FreeBSD$"); /* - * delete node with given key + * find a node with given key * - * vkey: key to be deleted + * vkey: key to be found * vrootp: address of the root of the tree * compar: function to carry out node comparisons */ From b56a6368c70ffab6ee40c71c56346793d5a88abc Mon Sep 17 00:00:00 2001 From: Edward Tomasz Napierala Date: Fri, 6 Feb 2015 14:44:29 +0000 Subject: [PATCH 13/36] Make "ctladm islist" ignore unknown elements, so the old version continues to work with newer kernel. Other ctladm(8) "*list" subcommands seem to already handle it in a reasonable way. MFC after: 1 month Sponsored by: The FreeBSD Foundation --- usr.sbin/ctladm/ctladm.c | 8 ++++++-- 1 file changed, 6 insertions(+), 2 deletions(-) diff --git a/usr.sbin/ctladm/ctladm.c b/usr.sbin/ctladm/ctladm.c index f2e933a77cc1..03c751b21f31 100644 --- a/usr.sbin/ctladm/ctladm.c +++ b/usr.sbin/ctladm/ctladm.c @@ -3559,8 +3559,12 @@ cctl_islist_end_element(void *user_data, const char *name) } else if (strcmp(name, "connection") == 0) { islist->cur_conn = NULL; } else if (strcmp(name, "ctlislist") == 0) { - } else - errx(1, "unknown element %s", name); + /* Nothing. */ + } else { + /* + * Unknown element; ignore it for forward compatiblity. + */ + } free(str); } From 63ed8a4e4b6cb8d9fc3b1fb49b6dd9d398abac7d Mon Sep 17 00:00:00 2001 From: Ed Maste Date: Fri, 6 Feb 2015 15:34:10 +0000 Subject: [PATCH 14/36] Handle invocation with neither of -e / -f Reviewed by: brooks Differential Revision: https://reviews.freebsd.org/D1780 --- tools/tools/makeroot/makeroot.sh | 4 +++- 1 file changed, 3 insertions(+), 1 deletion(-) diff --git a/tools/tools/makeroot/makeroot.sh b/tools/tools/makeroot/makeroot.sh index 1ef376b3c13b..ed448191d585 100755 --- a/tools/tools/makeroot/makeroot.sh +++ b/tools/tools/makeroot/makeroot.sh @@ -165,13 +165,15 @@ if [ -n "${FILELIST}" ]; then awk ' !/ type=/ { file = $1 } / type=/ { if ($1 == file) {print} }' >> ${manifest} -else +elif [ -n "${EXTRAS}" ]; then # Start with all the files in BSDROOT/METALOG except those in # one of the EXTRAS manifests. grep -h type=file ${EXTRAS} | cut -d' ' -f1 | \ sort -u ${BSDROOT}/METALOG - | awk ' !/ type=/ { file = $1 } / type=/ { if ($1 != file) {print} }' >> ${manifest} +else + sort -u ${BSDROOT}/METALOG >> ${manifest} fi # For each extras file, add contents keys relative to the directory the From b01589c956fab839123e07a0551d344fac67e7f3 Mon Sep 17 00:00:00 2001 From: Ed Maste Date: Fri, 6 Feb 2015 15:38:11 +0000 Subject: [PATCH 15/36] makeroot: Add -l option to set file system volume label Reviewed by: brooks Differential Revision: https://reviews.freebsd.org/D1782 --- tools/tools/makeroot/makeroot.8 | 3 +++ tools/tools/makeroot/makeroot.sh | 8 ++++++-- 2 files changed, 9 insertions(+), 2 deletions(-) diff --git a/tools/tools/makeroot/makeroot.8 b/tools/tools/makeroot/makeroot.8 index 379187c910dd..0ba3fdcad05c 100644 --- a/tools/tools/makeroot/makeroot.8 +++ b/tools/tools/makeroot/makeroot.8 @@ -41,6 +41,7 @@ .Op Fl e Ar extras-manifest .Op Fl f Ar filelist .Op Fl k Ar keydir Op Fl K Ar user +.Op Fl l Ar label .Op Fl p Ar master.passwd Op Fl g Ar group .Op Fl s Ar size .Ar image-file @@ -94,6 +95,8 @@ If no .Fl K argument is supplied then the files will be installed in the root user's directory. +.It Fl l Ar label +Set the file system volume label. .It Fl p Ar master.passwd Op Fl g Ar group Install an alternate .Ar master.passwd diff --git a/tools/tools/makeroot/makeroot.sh b/tools/tools/makeroot/makeroot.sh index ed448191d585..a1e669766bf0 100755 --- a/tools/tools/makeroot/makeroot.sh +++ b/tools/tools/makeroot/makeroot.sh @@ -75,7 +75,7 @@ KEYDIR= KEYUSERS= PASSWD= -while getopts "B:de:f:g:K:k:p:s:" opt; do +while getopts "B:de:f:g:K:k:l:p:s:" opt; do case "$opt" in B) BFLAG="-B ${OPTARG}" ;; d) DEBUG=1 ;; @@ -84,6 +84,7 @@ while getopts "B:de:f:g:K:k:p:s:" opt; do g) GROUP="${OPTARG}" ;; K) KEYUSERS="${KEYUSERS} ${OPTARG}" ;; k) KEYDIR="${OPTARG}" ;; + l) LABEL="${OPTARG}" ;; p) PASSWD="${OPTARG}" ;; s) SIZE="${OPTARG}" ;; *) usage ;; @@ -230,9 +231,12 @@ if [ -n "${KEYDIR}" ]; then done fi +if [ -n "${LABEL}" ]; then +LABELFLAG="-o label=${LABEL}" +fi if [ -n "${SIZE}" ]; then SIZEFLAG="-s ${SIZE}" fi cd ${BSDROOT}; makefs ${DUPFLAG} -N ${DBDIR} ${SIZEFLAG} ${BFLAG} \ - -t ffs -f 256 ${IMGFILE} ${manifest} + -t ffs ${LABELFLAG} -f 256 ${IMGFILE} ${manifest} From 64de80195bba295c961a4cdf96dbe0e4979bdf2a Mon Sep 17 00:00:00 2001 From: John Baldwin Date: Fri, 6 Feb 2015 16:09:01 +0000 Subject: [PATCH 16/36] Add a new device control utility for new-bus devices called devctl. This allows the user to request administrative changes to individual devices such as attach or detaching drivers or disabling and re-enabling devices. - Add a new /dev/devctl2 character device which uses ioctls for device requests. The ioctls use a common 'struct devreq' which is somewhat similar to 'struct ifreq'. - The ioctls identify the device to operate on via a string. This string can either by the device's name, or it can be a bus-specific address. (For unattached devices, a bus address is the only way to locate a device.) Bus drivers register an eventhandler to claim unrecognized device names that the driver recognizes as a valid address. Two buses currently support addresses: ACPI recognizes any device in the ACPI namespace via its full path starting with "\" and the PCI bus driver recognizes an address specification of 'pci[:]::' (identical to the PCI selector strings supported by pciconf). - To make it easier to cut and paste, change the PnP location string in the PCI bus driver to output a full PCI selector string rather than 'slot= function='. - Add a devctl(3) interface in libdevctl which provides a wrapper around the ioctls and is the preferred interface for other userland code. - Add a devctl(8) program which is a simple wrapper around the requests supported by devctl(3). - Add a device_is_suspended() function to check DF_SUSPENDED. - Add a resource_unset_value() function that can be used to remove a hint from the kernel environment. This is used to clear a hint...disabled hint when re-enabling a boot-time disabled device. Reviewed by: imp (parts) Requested by: imp (changing PCI location string) Relnotes: yes --- contrib/mdocml/lib.in | 1 + lib/Makefile | 1 + lib/libdevctl/Makefile | 8 ++ lib/libdevctl/devctl.3 | 295 +++++++++++++++++++++++++++++++++++++++ lib/libdevctl/devctl.c | 124 ++++++++++++++++ lib/libdevctl/devctl.h | 42 ++++++ share/mk/bsd.libnames.mk | 1 + share/mk/src.libnames.mk | 1 + sys/dev/acpica/acpi.c | 30 +++- sys/dev/pci/pci.c | 59 +++++++- sys/kern/subr_bus.c | 263 ++++++++++++++++++++++++++++++++++ sys/kern/subr_hints.c | 28 ++++ sys/sys/bus.h | 50 ++++++- usr.sbin/Makefile | 1 + usr.sbin/devctl/Makefile | 9 ++ usr.sbin/devctl/devctl.8 | 137 ++++++++++++++++++ usr.sbin/devctl/devctl.c | 282 +++++++++++++++++++++++++++++++++++++ 17 files changed, 1328 insertions(+), 4 deletions(-) create mode 100644 lib/libdevctl/Makefile create mode 100644 lib/libdevctl/devctl.3 create mode 100644 lib/libdevctl/devctl.c create mode 100644 lib/libdevctl/devctl.h create mode 100644 usr.sbin/devctl/Makefile create mode 100644 usr.sbin/devctl/devctl.8 create mode 100644 usr.sbin/devctl/devctl.c diff --git a/contrib/mdocml/lib.in b/contrib/mdocml/lib.in index a5522ef7034f..a1ce062f75fc 100644 --- a/contrib/mdocml/lib.in +++ b/contrib/mdocml/lib.in @@ -41,6 +41,7 @@ LINE("libcrypt", "Crypt Library (libcrypt, \\-lcrypt)") LINE("libcurses", "Curses Library (libcurses, \\-lcurses)") LINE("libcuse", "Userland Character Device Library (libcuse, \\-lcuse)") LINE("libdevattr", "Device attribute and event library (libdevattr, \\-ldevattr)") +LINE("libdevctl", "Device Control Library (libdevctl, \\-ldevctl)") LINE("libdevinfo", "Device and Resource Information Utility Library (libdevinfo, \\-ldevinfo)") LINE("libdevstat", "Device Statistics Library (libdevstat, \\-ldevstat)") LINE("libdisk", "Interface to Slice and Partition Labels Library (libdisk, \\-ldisk)") diff --git a/lib/Makefile b/lib/Makefile index c00af75f70b4..fdab45351e55 100644 --- a/lib/Makefile +++ b/lib/Makefile @@ -41,6 +41,7 @@ SUBDIR= ${SUBDIR_ORDERED} \ ${_libcom_err} \ libcompat \ libcrypt \ + libdevctl \ libdevinfo \ libdevstat \ libdpv \ diff --git a/lib/libdevctl/Makefile b/lib/libdevctl/Makefile new file mode 100644 index 000000000000..74687ecc2bd2 --- /dev/null +++ b/lib/libdevctl/Makefile @@ -0,0 +1,8 @@ +# $FreeBSD$ + +LIB= devctl +SRCS= devctl.c +INCS= devctl.h +MAN= devctl.3 + +.include diff --git a/lib/libdevctl/devctl.3 b/lib/libdevctl/devctl.3 new file mode 100644 index 000000000000..be869f9d9868 --- /dev/null +++ b/lib/libdevctl/devctl.3 @@ -0,0 +1,295 @@ +.\" +.\" Copyright (c) 2014 John Baldwin +.\" All rights reserved. +.\" +.\" Redistribution and use in source and binary forms, with or without +.\" modification, are permitted provided that the following conditions +.\" are met: +.\" 1. Redistributions of source code must retain the above copyright +.\" notice, this list of conditions and the following disclaimer. +.\" 2. Redistributions in binary form must reproduce the above copyright +.\" notice, this list of conditions and the following disclaimer in the +.\" documentation and/or other materials provided with the distribution. +.\" +.\" THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND +.\" ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE +.\" IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE +.\" ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE +.\" FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL +.\" DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS +.\" OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) +.\" HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT +.\" LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY +.\" OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF +.\" SUCH DAMAGE. +.\" +.\" $FreeBSD$ +.\" +.Dd December 26, 2014 +.Dt DEVCTL 3 +.Os +.Sh NAME +.Nm devctl , +.Nm devctl_attach , +.Nm devctl_detach , +.Nm devctl_disable , +.Nm devctl_enable , +.Nm devctl_resume , +.Nm devctl_suspend +.Nd device control library +.Sh LIBRARY +.Lb libdevctl +.Sh SYNOPSIS +.In devctl.h +.Ft int +.Fn devctl_attach "const char *device" +.Ft int +.Fn devctl_detach "const char *device" "bool force" +.Ft int +.Fn devctl_disable "const char *device" "bool force_detach" +.Ft int +.Fn devctl_enable "const char *device" +.Ft int +.Fn devctl_resume "const char *device" +.Ft int +.Fn devctl_suspend "const char *device" +.Ft int +.Fn devctl_set_driver "const char *device" "const char *driver" "bool force" +.Sh DESCRIPTION +The +.Nm +library adjusts the state of devices in the kernel's internal device +hierarchy. +Each control operation accepts a +.Fa device +argument that identifies the device to adjust. +The +.Fa device +may be specified as either the name of an existing device or as a +bus-specific address. +The following bus-specific address formats are currently supported: +.Bl -tag -offset indent +.It Sy pci Ns Fa domain Ns : Ns Fa bus Ns : Ns Fa slot Ns : Ns Fa function +A PCI device with the specified +.Fa domain , +.Fa bus , +.Fa slot , +and +.Fa function . +.It Sy pci Ns Fa bus Ns : Ns Fa slot Ns : Ns Fa function +A PCI device in domain zero with the specified +.Fa bus , +.Fa slot , +and +.Fa function . +.It Fa handle +A device with an ACPI handle of +.Fa handle . +The handle must be specified as an absolute path and must begin with a +.Dq \e . +.El +.Pp +The +.Fn devctl_attach +function probes a device and attaches a suitable device driver if one is +found. +.Pp +The +.Fn devctl_detach +function detaches a device from its current device driver. +The device is left detached until either a new driver for its parent +bus is loaded or the device is explicitly probed via +.Fn devctl_attach . +If +.Fa force +is true, +the current device driver will be detached even if the device is busy. +.Pp +The +.Fn devctl_disable +function disables a device. +If the device is currently attached to a device driver, +the device driver will be detached from the device, +but the device will retain its current name. +If +.Fa force_detach +is true, +the current device driver will be detached even if the device is busy. +The device will remain disabled and detached until it is explicitly enabled +via +.Fn devctl_enable . +.Pp +The +.Fn devctl_enable +function re-enables a disabled device. +The device will probe and attach if a suitable device driver is found. +.Pp +The +.Fn devctl_suspend +function suspends a device. +This may include placing the device in a reduced power state, +but any device driver currently attached to the device will remain attached. +.Pp +The +.Fn devctl_resume +function resumes a suspended device to a fully working state. +.Pp +The +.Fn devctl_set_driver +function attaches a device driver named +.Fa driver +to a device. +If the device is already attached and +.Fa force +is false, +the request will fail. +If the device is already attached and +.Fa force +is true, +the device will be detached from its current device driver before it is +attached to the new device driver. +.Sh RETURN VALUES +.Rv -std devctl_attach devctl_detach devctl_disable devctl_enable \ +devctl_suspend devctl_resume devctl_set_driver +.Sh ERRORS +In addition to specific errors noted below, +all of the +.Nm +functions may fail for any of the errors described in +.Xr open 2 +as well as: +.Bl -tag -width Er +.It Bq Er EINVAL +The device name is too long. +.It Bq Er ENOENT +No existing device matches the specified name or location. +.It Bq Er EPERM +The current process is not permitted to adjust the state of +.Fa device . +.El +.Pp +The +.Fn devctl_attach +function may fail if: +.Bl -tag -width Er +.It Bq Er EBUSY +The device is already attached. +.It Bq Er ENOMEM +An internal memory allocation request failed. +.It Bq Er ENXIO +The device is disabled. +.It Bq Er ENXIO +No suitable driver for the device could be found, +or the driver failed to attach. +.El +.Pp +The +.Fn devctl_detach +function may fail if: +.Bl -tag -width Er +.It Bq Er EBUSY +The current device driver for +.Fa device +is busy and cannot detach at this time. +Note that some drivers may return this even if +.Fa force +is true. +.It Bq Er ENXIO +The device is not attached to a driver. +.It Bq Er ENXIO +The current device driver for +.Fa device +does not support detaching. +.El +.Pp +The +.Fn devctl_enable +function may fail if: +.Bl -tag -width Er +.It Bq Er EBUSY +The device is already enabled. +.It Bq Er ENOMEM +An internal memory allocation request failed. +.It Bq Er ENXIO +No suitable driver for the device could be found, +or the driver failed to attach. +.El +.Pp +The +.Fn devctl_disable +function may fail if: +.Bl -tag -width Er +.It Bq Er EBUSY +The current device driver for +.Fa device +is busy and cannot detach at this time. +Note that some drivers may return this even if +.Fa force_detach +is true. +.It Bq Er ENXIO +The device is already disabled. +.It Bq Er ENXIO +The current device driver for +.Fa device +does not support detaching. +.El +.Pp +The +.Fn devctl_suspend +function may fail if: +.Bl -tag -width Er +.It Bq Er EBUSY +The device is already suspended. +.It Bq Er EINVAL +The device to be suspended is the root bus device. +.El +.Pp +The +.Fn devctl_resume +function may fail if: +.Bl -tag -width Er +.It Bq Er EINVAL +The device is not suspended. +.It Bq Er EINVAL +The device to be resumed is the root bus device. +.El +.Pp +The +.Fn devctl_set_driver +function may fail if: +.Bl -tag -width Er +.It Bq Er EBUSY +The device is currently attached to a device driver and +.Fa force +is false. +.It Bq Er EBUSY +The current device driver for +.Fa device +is busy and cannot detach at this time. +.It Bq Er EFAULT +The +.Fa driver +argument points outside the process' allocated address space. +.It Bq Er ENOENT +No device driver with the requested name exists. +.It Bq Er ENOMEM +An internal memory allocation request failed. +.It Bq Er ENXIO +The device is disabled. +.It Bq Er ENXIO +The new device driver failed to attach. +.El +.Sh SEE ALSO +.Xr devinfo 3 , +.Xr devstat 3 , +.Xr devctl 8 +.Sh HISTORY +The +.Nm +library first appeared in +.Fx 11.0 . +.Sh BUGS +If a device is suspended individually via +.Fn devctl_suspend +and the entire machine is subsequently suspended, +the device will be resumed when the machine resumes. diff --git a/lib/libdevctl/devctl.c b/lib/libdevctl/devctl.c new file mode 100644 index 000000000000..7be431e9bf53 --- /dev/null +++ b/lib/libdevctl/devctl.c @@ -0,0 +1,124 @@ +/*- + * Copyright (c) 2014 John Baldwin + * All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * 2. Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * + * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND + * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE + * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE + * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE + * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL + * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS + * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) + * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT + * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY + * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF + * SUCH DAMAGE. + */ + +#include +__FBSDID("$FreeBSD$"); + +#include +#include +#include +#include +#include +#include "devctl.h" + +static int +devctl_request(u_long cmd, struct devreq *req) +{ + static int devctl2_fd = -1; + + if (devctl2_fd == -1) { + devctl2_fd = open("/dev/devctl2", O_RDONLY); + if (devctl2_fd == -1) + return (-1); + } + return (ioctl(devctl2_fd, cmd, req)); +} + +static int +devctl_simple_request(u_long cmd, const char *name, int flags) +{ + struct devreq req; + + memset(&req, 0, sizeof(req)); + if (strlcpy(req.dr_name, name, sizeof(req.dr_name)) >= + sizeof(req.dr_name)) { + errno = EINVAL; + return (-1); + } + req.dr_flags = flags; + return (devctl_request(cmd, &req)); +} + +int +devctl_attach(const char *device) +{ + + return (devctl_simple_request(DEV_ATTACH, device, 0)); +} + +int +devctl_detach(const char *device, bool force) +{ + + return (devctl_simple_request(DEV_DETACH, device, force ? + DEVF_FORCE_DETACH : 0)); +} + +int +devctl_enable(const char *device) +{ + + return (devctl_simple_request(DEV_ENABLE, device, 0)); +} + +int +devctl_disable(const char *device, bool force_detach) +{ + + return (devctl_simple_request(DEV_DISABLE, device, force_detach ? + DEVF_FORCE_DETACH : 0)); +} + +int +devctl_suspend(const char *device) +{ + + return (devctl_simple_request(DEV_SUSPEND, device, 0)); +} + +int +devctl_resume(const char *device) +{ + + return (devctl_simple_request(DEV_RESUME, device, 0)); +} + +int +devctl_set_driver(const char *device, const char *driver, bool force) +{ + struct devreq req; + + memset(&req, 0, sizeof(req)); + if (strlcpy(req.dr_name, device, sizeof(req.dr_name)) >= + sizeof(req.dr_name)) { + errno = EINVAL; + return (-1); + } + req.dr_data = __DECONST(char *, driver); + if (force) + req.dr_flags |= DEVF_SET_DRIVER_DETACH; + return (devctl_request(DEV_SET_DRIVER, &req)); +} diff --git a/lib/libdevctl/devctl.h b/lib/libdevctl/devctl.h new file mode 100644 index 000000000000..f773b11dd43a --- /dev/null +++ b/lib/libdevctl/devctl.h @@ -0,0 +1,42 @@ +/*- + * Copyright (c) 2014 John Baldwin + * All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * 2. Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * + * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND + * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE + * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE + * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE + * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL + * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS + * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) + * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT + * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY + * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF + * SUCH DAMAGE. + * + * $FreeBSD$ + */ + +#ifndef __DEVCTL_H__ +#define __DEVCTL_H__ + +#include + +int devctl_attach(const char *device); +int devctl_detach(const char *device, bool force); +int devctl_enable(const char *device); +int devctl_disable(const char *device, bool force_detach); +int devctl_suspend(const char *device); +int devctl_resume(const char *device); +int devctl_set_driver(const char *device, const char *driver, bool force); + +#endif /* !__DEVCTL_H__ */ diff --git a/share/mk/bsd.libnames.mk b/share/mk/bsd.libnames.mk index 00f0a0adf0cf..d84747e45767 100644 --- a/share/mk/bsd.libnames.mk +++ b/share/mk/bsd.libnames.mk @@ -39,6 +39,7 @@ LIBCRYPT?= ${DESTDIR}${LIBDIR}/libcrypt.a LIBCRYPTO?= ${DESTDIR}${LIBDIR}/libcrypto.a LIBCTF?= ${DESTDIR}${LIBDIR}/libctf.a LIBCURSES?= ${DESTDIR}${LIBDIR}/libcurses.a +LIBDEVCTL?= ${DESTDIR}${LIBDIR}/libdevctl.a LIBDEVINFO?= ${DESTDIR}${LIBDIR}/libdevinfo.a LIBDEVSTAT?= ${DESTDIR}${LIBDIR}/libdevstat.a LIBDIALOG?= ${DESTDIR}${LIBDIR}/libdialog.a diff --git a/share/mk/src.libnames.mk b/share/mk/src.libnames.mk index b8570ed6b5bc..a6880892caac 100644 --- a/share/mk/src.libnames.mk +++ b/share/mk/src.libnames.mk @@ -72,6 +72,7 @@ _LIBRARIES= \ ctf \ cuse \ cxxrt \ + devctl \ devinfo \ devstat \ dialog \ diff --git a/sys/dev/acpica/acpi.c b/sys/dev/acpica/acpi.c index a4732c47a647..bf2cc5498b43 100644 --- a/sys/dev/acpica/acpi.c +++ b/sys/dev/acpica/acpi.c @@ -101,6 +101,7 @@ int acpi_quirks; /* Supported sleep states. */ static BOOLEAN acpi_sleep_states[ACPI_S_STATE_COUNT]; +static void acpi_lookup(void *arg, const char *name, device_t *dev); static int acpi_modevent(struct module *mod, int event, void *junk); static int acpi_probe(device_t dev); static int acpi_attach(device_t dev); @@ -671,8 +672,10 @@ acpi_attach(device_t dev) /* Register ACPI again to pass the correct argument of pm_func. */ power_pm_register(POWER_PM_TYPE_ACPI, acpi_pm_func, sc); - if (!acpi_disabled("bus")) + if (!acpi_disabled("bus")) { + EVENTHANDLER_REGISTER(dev_lookup, acpi_lookup, NULL, 1000); acpi_probe_children(dev); + } /* Update all GPEs and enable runtime GPEs. */ status = AcpiUpdateAllGpes(); @@ -3401,6 +3404,31 @@ acpi_disabled(char *subsys) return (0); } +static void +acpi_lookup(void *arg, const char *name, device_t *dev) +{ + ACPI_HANDLE handle; + + if (*dev != NULL) + return; + + /* + * Allow any handle name that is specified as an absolute path and + * starts with '\'. We could restrict this to \_SB and friends, + * but see acpi_probe_children() for notes on why we scan the entire + * namespace for devices. + * + * XXX: The pathname argument to AcpiGetHandle() should be fixed to + * be const. + */ + if (name[0] != '\\') + return; + if (ACPI_FAILURE(AcpiGetHandle(ACPI_ROOT_OBJECT, __DECONST(char *, name), + &handle))) + return; + *dev = acpi_get_device(handle); +} + /* * Control interface. * diff --git a/sys/dev/pci/pci.c b/sys/dev/pci/pci.c index 8f87851da6ac..263904bc1783 100644 --- a/sys/dev/pci/pci.c +++ b/sys/dev/pci/pci.c @@ -35,6 +35,7 @@ __FBSDID("$FreeBSD$"); #include #include #include +#include #include #include #include @@ -4824,8 +4825,8 @@ pci_child_location_str_method(device_t dev, device_t child, char *buf, size_t buflen) { - snprintf(buf, buflen, "slot=%d function=%d", pci_get_slot(child), - pci_get_function(child)); + snprintf(buf, buflen, "pci%d:%d:%d:%d", pci_get_domain(child), + pci_get_bus(child), pci_get_slot(child), pci_get_function(child)); return (0); } @@ -4855,10 +4856,60 @@ pci_assign_interrupt_method(device_t dev, device_t child) cfg->intpin)); } +static void +pci_lookup(void *arg, const char *name, device_t *dev) +{ + long val; + char *end; + int domain, bus, slot, func; + + if (*dev != NULL) + return; + + /* + * Accept pciconf-style selectors of either pciD:B:S:F or + * pciB:S:F. In the latter case, the domain is assumed to + * be zero. + */ + if (strncmp(name, "pci", 3) != 0) + return; + val = strtol(name + 3, &end, 10); + if (val < 0 || val > INT_MAX || *end != ':') + return; + domain = val; + val = strtol(end + 1, &end, 10); + if (val < 0 || val > INT_MAX || *end != ':') + return; + bus = val; + val = strtol(end + 1, &end, 10); + if (val < 0 || val > INT_MAX) + return; + slot = val; + if (*end == ':') { + val = strtol(end + 1, &end, 10); + if (val < 0 || val > INT_MAX || *end != '\0') + return; + func = val; + } else if (*end == '\0') { + func = slot; + slot = bus; + bus = domain; + domain = 0; + } else + return; + + if (domain > PCI_DOMAINMAX || bus > PCI_BUSMAX || slot > PCI_SLOTMAX || + func > PCIE_ARI_FUNCMAX || (slot != 0 && func > PCI_FUNCMAX)) + return; + + *dev = pci_find_dbsf(domain, bus, slot, func); +} + static int pci_modevent(module_t mod, int what, void *arg) { static struct cdev *pci_cdev; + static eventhandler_tag tag; switch (what) { case MOD_LOAD: @@ -4867,9 +4918,13 @@ pci_modevent(module_t mod, int what, void *arg) pci_cdev = make_dev(&pcicdev, 0, UID_ROOT, GID_WHEEL, 0644, "pci"); pci_load_vendor_data(); + tag = EVENTHANDLER_REGISTER(dev_lookup, pci_lookup, NULL, + 1000); break; case MOD_UNLOAD: + if (tag != NULL) + EVENTHANDLER_DEREGISTER(dev_lookup, tag); destroy_dev(pci_cdev); break; } diff --git a/sys/kern/subr_bus.c b/sys/kern/subr_bus.c index 269be94322b2..1c7b21ca7d9e 100644 --- a/sys/kern/subr_bus.c +++ b/sys/kern/subr_bus.c @@ -41,6 +41,7 @@ __FBSDID("$FreeBSD$"); #include #include #include +#include #include #include #include @@ -139,6 +140,8 @@ struct device { static MALLOC_DEFINE(M_BUS, "bus", "Bus data structures"); static MALLOC_DEFINE(M_BUS_SC, "bus-sc", "Bus data structures, softc"); +static void devctl2_init(void); + #ifdef BUS_DEBUG static int bus_debug = 1; @@ -423,6 +426,7 @@ devinit(void) cv_init(&devsoftc.cv, "dev cv"); TAILQ_INIT(&devsoftc.devq); knlist_init_mtx(&devsoftc.sel.si_note, &devsoftc.mtx); + devctl2_init(); } static int @@ -2638,6 +2642,15 @@ device_is_attached(device_t dev) return (dev->state >= DS_ATTACHED); } +/** + * @brief Return non-zero if the device is currently suspended. + */ +int +device_is_suspended(device_t dev) +{ + return ((dev->flags & DF_SUSPENDED) != 0); +} + /** * @brief Set the devclass of a device * @see devclass_add_device(). @@ -5022,3 +5035,253 @@ bus_free_resource(device_t dev, int type, struct resource *r) return (0); return (bus_release_resource(dev, type, rman_get_rid(r), r)); } + +/* + * /dev/devctl2 implementation. The existing /dev/devctl device has + * implicit semantics on open, so it could not be reused for this. + * Another option would be to call this /dev/bus? + */ +static int +find_device(struct devreq *req, device_t *devp) +{ + device_t dev; + + /* + * First, ensure that the name is nul terminated. + */ + if (memchr(req->dr_name, '\0', sizeof(req->dr_name)) == NULL) + return (EINVAL); + + /* + * Second, try to find an attached device whose name matches + * 'name'. + */ + TAILQ_FOREACH(dev, &bus_data_devices, devlink) { + if (dev->nameunit != NULL && + strcmp(dev->nameunit, req->dr_name) == 0) { + *devp = dev; + return (0); + } + } + + /* Finally, give device enumerators a chance. */ + dev = NULL; + EVENTHANDLER_INVOKE(dev_lookup, req->dr_name, &dev); + if (dev == NULL) + return (ENOENT); + *devp = dev; + return (0); +} + +static bool +driver_exists(struct device *bus, const char *driver) +{ + devclass_t dc; + + for (dc = bus->devclass; dc != NULL; dc = dc->parent) { + if (devclass_find_driver_internal(dc, driver) != NULL) + return (true); + } + return (false); +} + +static int +devctl2_ioctl(struct cdev *cdev, u_long cmd, caddr_t data, int fflag, + struct thread *td) +{ + struct devreq *req; + device_t dev; + int error, old; + + /* Locate the device to control. */ + mtx_lock(&Giant); + req = (struct devreq *)data; + switch (cmd) { + case DEV_ATTACH: + case DEV_DETACH: + case DEV_ENABLE: + case DEV_DISABLE: + case DEV_SUSPEND: + case DEV_RESUME: + case DEV_SET_DRIVER: + error = priv_check(td, PRIV_DRIVER); + if (error == 0) + error = find_device(req, &dev); + break; + default: + error = ENOTTY; + break; + } + if (error) { + mtx_unlock(&Giant); + return (error); + } + + /* Perform the requested operation. */ + switch (cmd) { + case DEV_ATTACH: + if (device_is_attached(dev) && (dev->flags & DF_REBID) == 0) + error = EBUSY; + else if (!device_is_enabled(dev)) + error = ENXIO; + else + error = device_probe_and_attach(dev); + break; + case DEV_DETACH: + if (!device_is_attached(dev)) { + error = ENXIO; + break; + } + if (!(req->dr_flags & DEVF_FORCE_DETACH)) { + error = device_quiesce(dev); + if (error) + break; + } + error = device_detach(dev); + break; + case DEV_ENABLE: + if (device_is_enabled(dev)) { + error = EBUSY; + break; + } + + /* + * If the device has been probed but not attached (e.g. + * when it has been disabled by a loader hint), just + * attach the device rather than doing a full probe. + */ + device_enable(dev); + if (device_is_alive(dev)) { + /* + * If the device was disabled via a hint, clear + * the hint. + */ + if (resource_disabled(dev->driver->name, dev->unit)) + resource_unset_value(dev->driver->name, + dev->unit, "disabled"); + error = device_attach(dev); + } else + error = device_probe_and_attach(dev); + break; + case DEV_DISABLE: + if (!device_is_enabled(dev)) { + error = ENXIO; + break; + } + + if (!(req->dr_flags & DEVF_FORCE_DETACH)) { + error = device_quiesce(dev); + if (error) + break; + } + + /* + * Force DF_FIXEDCLASS on around detach to preserve + * the existing name. + */ + old = dev->flags; + dev->flags |= DF_FIXEDCLASS; + error = device_detach(dev); + if (!(old & DF_FIXEDCLASS)) + dev->flags &= ~DF_FIXEDCLASS; + if (error == 0) + device_disable(dev); + break; + case DEV_SUSPEND: + if (device_is_suspended(dev)) { + error = EBUSY; + break; + } + if (device_get_parent(dev) == NULL) { + error = EINVAL; + break; + } + error = BUS_SUSPEND_CHILD(device_get_parent(dev), dev); + break; + case DEV_RESUME: + if (!device_is_suspended(dev)) { + error = EINVAL; + break; + } + if (device_get_parent(dev) == NULL) { + error = EINVAL; + break; + } + error = BUS_RESUME_CHILD(device_get_parent(dev), dev); + break; + case DEV_SET_DRIVER: { + devclass_t dc; + char driver[128]; + + error = copyinstr(req->dr_data, driver, sizeof(driver), NULL); + if (error) + break; + if (driver[0] == '\0') { + error = EINVAL; + break; + } + if (dev->devclass != NULL && + strcmp(driver, dev->devclass->name) == 0) + /* XXX: Could possibly force DF_FIXEDCLASS on? */ + break; + + /* + * Scan drivers for this device's bus looking for at + * least one matching driver. + */ + if (dev->parent == NULL) { + error = EINVAL; + break; + } + if (!driver_exists(dev->parent, driver)) { + error = ENOENT; + break; + } + dc = devclass_create(driver); + if (dc == NULL) { + error = ENOMEM; + break; + } + + /* Detach device if necessary. */ + if (device_is_attached(dev)) { + if (req->dr_flags & DEVF_SET_DRIVER_DETACH) + error = device_detach(dev); + else + error = EBUSY; + if (error) + break; + } + + /* Clear any previously-fixed device class and unit. */ + if (dev->flags & DF_FIXEDCLASS) + devclass_delete_device(dev->devclass, dev); + dev->flags |= DF_WILDCARD; + dev->unit = -1; + + /* Force the new device class. */ + error = devclass_add_device(dc, dev); + if (error) + break; + dev->flags |= DF_FIXEDCLASS; + error = device_probe_and_attach(dev); + break; + } + } + mtx_unlock(&Giant); + return (error); +} + +static struct cdevsw devctl2_cdevsw = { + .d_version = D_VERSION, + .d_ioctl = devctl2_ioctl, + .d_name = "devctl2", +}; + +static void +devctl2_init(void) +{ + + make_dev_credf(MAKEDEV_ETERNAL, &devctl2_cdevsw, 0, NULL, + UID_ROOT, GID_WHEEL, 0600, "devctl2"); +} diff --git a/sys/kern/subr_hints.c b/sys/kern/subr_hints.c index 25838ee34136..00cfbf1bfb88 100644 --- a/sys/kern/subr_hints.c +++ b/sys/kern/subr_hints.c @@ -461,3 +461,31 @@ resource_disabled(const char *name, int unit) return (0); return (value); } + +/* + * Clear a value associated with a device by removing it from + * the kernel environment. This only removes a hint for an + * exact unit. + */ +int +resource_unset_value(const char *name, int unit, const char *resname) +{ + char varname[128]; + const char *retname, *retvalue; + int error, line; + size_t len; + + line = 0; + error = resource_find(&line, NULL, name, &unit, resname, NULL, + &retname, NULL, NULL, NULL, NULL, &retvalue); + if (error) + return (error); + + retname -= strlen("hint."); + len = retvalue - retname - 1; + if (len > sizeof(varname) - 1) + return (ENAMETOOLONG); + memcpy(varname, retname, len); + varname[len] = '\0'; + return (kern_unsetenv(varname)); +} diff --git a/sys/sys/bus.h b/sys/sys/bus.h index f15dd34d24c0..d6dc53585eba 100644 --- a/sys/sys/bus.h +++ b/sys/sys/bus.h @@ -31,6 +31,7 @@ #include #include +#include /** * @defgroup NEWBUS newbus - a generic framework for managing devices @@ -86,9 +87,45 @@ struct u_device { #define DF_REBID 0x80 /* Can rebid after attach */ #define DF_SUSPENDED 0x100 /* Device is suspended. */ +/** + * @brief Device request structure used for ioctl's. + * + * Used for ioctl's on /dev/devctl2. All device ioctl's + * must have parameter definitions which begin with dr_name. + */ +struct devreq_buffer { + void *buffer; + size_t length; +}; + +struct devreq { + char dr_name[128]; + int dr_flags; /* request-specific flags */ + union { + struct devreq_buffer dru_buffer; + void *dru_data; + } dr_dru; +#define dr_buffer dr_dru.dru_buffer /* variable-sized buffer */ +#define dr_data dr_dru.dru_data /* fixed-size buffer */ +}; + +#define DEV_ATTACH _IOW('D', 1, struct devreq) +#define DEV_DETACH _IOW('D', 2, struct devreq) +#define DEV_ENABLE _IOW('D', 3, struct devreq) +#define DEV_DISABLE _IOW('D', 4, struct devreq) +#define DEV_SUSPEND _IOW('D', 5, struct devreq) +#define DEV_RESUME _IOW('D', 6, struct devreq) +#define DEV_SET_DRIVER _IOW('D', 7, struct devreq) + +/* Flags for DEV_DETACH and DEV_DISABLE. */ +#define DEVF_FORCE_DETACH 0x0000001 + +/* Flags for DEV_SET_DRIVER. */ +#define DEVF_SET_DRIVER_DETACH 0x0000001 /* Detach existing driver. */ + #ifdef _KERNEL -#include +#include #include /** @@ -104,6 +141,14 @@ void devctl_notify(const char *__system, const char *__subsystem, void devctl_queue_data_f(char *__data, int __flags); void devctl_queue_data(char *__data); +/** + * Device name parsers. Hook to allow device enumerators to map + * scheme-specific names to a device. + */ +typedef void (*dev_lookup_fn)(void *arg, const char *name, + device_t *result); +EVENTHANDLER_DECLARE(dev_lookup, dev_lookup_fn); + /** * @brief A device driver (included mainly for compatibility with * FreeBSD 4.x). @@ -465,6 +510,7 @@ struct sysctl_oid *device_get_sysctl_tree(device_t dev); int device_is_alive(device_t dev); /* did probe succeed? */ int device_is_attached(device_t dev); /* did attach succeed? */ int device_is_enabled(device_t dev); +int device_is_suspended(device_t dev); int device_is_quiet(device_t dev); int device_print_prettyname(device_t dev); int device_printf(device_t dev, const char *, ...) __printflike(2, 3); @@ -528,6 +574,8 @@ int resource_set_long(const char *name, int unit, const char *resname, long value); int resource_set_string(const char *name, int unit, const char *resname, const char *value); +int resource_unset_value(const char *name, int unit, const char *resname); + /* * Functions for maintaining and checking consistency of * bus information exported to userspace. diff --git a/usr.sbin/Makefile b/usr.sbin/Makefile index 918678b8cbb1..30d843dfbd59 100644 --- a/usr.sbin/Makefile +++ b/usr.sbin/Makefile @@ -19,6 +19,7 @@ SUBDIR= adduser \ ctld \ daemon \ dconschat \ + devctl \ devinfo \ digictl \ diskinfo \ diff --git a/usr.sbin/devctl/Makefile b/usr.sbin/devctl/Makefile new file mode 100644 index 000000000000..5a6e19d761a3 --- /dev/null +++ b/usr.sbin/devctl/Makefile @@ -0,0 +1,9 @@ +# $FreeBSD$ + +PROG= devctl +MAN= devctl.8 +MAN= + +LIBADD= devctl + +.include diff --git a/usr.sbin/devctl/devctl.8 b/usr.sbin/devctl/devctl.8 new file mode 100644 index 000000000000..77c803a7af29 --- /dev/null +++ b/usr.sbin/devctl/devctl.8 @@ -0,0 +1,137 @@ +.\" +.\" Copyright (c) 2015 John Baldwin +.\" All rights reserved. +.\" +.\" Redistribution and use in source and binary forms, with or without +.\" modification, are permitted provided that the following conditions +.\" are met: +.\" 1. Redistributions of source code must retain the above copyright +.\" notice, this list of conditions and the following disclaimer. +.\" 2. Redistributions in binary form must reproduce the above copyright +.\" notice, this list of conditions and the following disclaimer in the +.\" documentation and/or other materials provided with the distribution. +.\" +.\" THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND +.\" ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE +.\" IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE +.\" ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE +.\" FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL +.\" DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS +.\" OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) +.\" HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT +.\" LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY +.\" OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF +.\" SUCH DAMAGE. +.\" +.\" $FreeBSD$ +.\" +.Dd February 5, 2015 +.Dt DEVCTL 8 +.Os +.Sh NAME +.Nm devctl +.Nd device control utility +.Sh SYNOPSIS +.Nm +.Cm attach +.Ar device +.Nm +.Cm detach +.Op Fl f +.Ar device +.Nm +.Cm disable +.Op Fl f +.Ar device +.Nm +.Cm enable +.Ar device +.Nm +.Cm suspend +.Ar device +.Nm +.Cm resume +.Ar device +.Nm +.Cm set driver +.Op Fl f +.Ar device driver +.Sh DESCRIPTION +The +.Nm +utility adjusts the state of individual devices in the kernel's +internal device hierarchy. +Each invocation of +.Nm +consists of a single command followed by command-specific arguments. +Each command operates on a single device specified via the +.Ar device +argument. +The +.Ar device +may be specified either as the name of an existing device or as a +bus-specific address. +More details on supported address formats can be found in +.Xr devctl 3 . +.Pp +The following commands are supported: +.Bl -tag -width indent +.It Cm attach Ar device +Force the kernel to re-probe the device. +If a suitable driver is found, +it is attached to the device. +.It Xo Cm detach +.Op Fl f +.Ar device +.Xc +Detach the device from its current device driver. +If the +.Fl f +flag is specified, +the device driver will be detached even if the device is busy. +.It Xo Cm disable +.Op Fl f +.Ar device +.Xc +Disable a device. +If the device is currently attached to a device driver, +the device driver will be detached from the device, +but the device will retain its current name. +If the +.Fl f +flag is specified, +the device driver will be detached even if the device is busy. +.It Cm enable Ar device +Enable a device. +The device will probe and attach if a suitable device driver is found. +Note that this can re-enable a device disabled at boot time via a +loader tunable. +.It Cm suspend Ar device +Suspend a device. +This may include placing the device in a reduced power state. +.It Cm resume device +Resume a suspended device to a fully working state. +.It Xo Cm set driver +.Op Fl f +.Ar device driver +.Xc +Force the device to use a device driver named +.Ar driver . +If the device is already attached to a device driver and the +.Fl f +flag is specified, +the device will be detached from its current device driver before it is +attached to the new device driver. +If the device is already attached to a device driver and the +.Fl f +flag is not specified, +the device will not be changed. +.El +.Sh SEE ALSO +.Xr devctl 3 , +.Xr devinfo 8 +.Sh HISTORY +The +.Nm +utility first appeared in +.Fx 11.0 . diff --git a/usr.sbin/devctl/devctl.c b/usr.sbin/devctl/devctl.c new file mode 100644 index 000000000000..076c6503885e --- /dev/null +++ b/usr.sbin/devctl/devctl.c @@ -0,0 +1,282 @@ +/*- + * Copyright (c) 2014 John Baldwin + * All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * 2. Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * + * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND + * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE + * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE + * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE + * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL + * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS + * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) + * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT + * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY + * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF + * SUCH DAMAGE. + */ + +#include +__FBSDID("$FreeBSD$"); + +#include +#include +#include +#include +#include +#include +#include +#include +#include + +struct devctl_command { + const char *name; + int (*handler)(int ac, char **av); +}; + +#define DEVCTL_DATASET(name) devctl_ ## name ## _table + +#define DEVCTL_COMMAND(set, name, function) \ + static struct devctl_command function ## _devctl_command = \ + { #name, function }; \ + DATA_SET(DEVCTL_DATASET(set), function ## _devctl_command) + +#define DEVCTL_TABLE(set, name) \ + SET_DECLARE(DEVCTL_DATASET(name), struct devctl_command); \ + \ + static int \ + devctl_ ## name ## _table_handler(int ac, char **av) \ + { \ + return (devctl_table_handler(SET_BEGIN(DEVCTL_DATASET(name)), \ + SET_LIMIT(DEVCTL_DATASET(name)), ac, av)); \ + } \ + DEVCTL_COMMAND(set, name, devctl_ ## name ## _table_handler) + +static int devctl_table_handler(struct devctl_command **start, + struct devctl_command **end, int ac, char **av); + +SET_DECLARE(DEVCTL_DATASET(top), struct devctl_command); + +DEVCTL_TABLE(top, set); + +static void +usage(void) +{ + fprintf(stderr, "%s\n%s\n%s\n%s\n%s\n%s\n%s\n", + "usage: devctl attach device", + " devctl detach [-f] device", + " devctl disable [-f] device", + " devctl enable device", + " devctl suspend device", + " devctl resume device", + " devctl set driver [-f] device driver"); + exit(1); +} + +static int +devctl_table_handler(struct devctl_command **start, + struct devctl_command **end, int ac, char **av) +{ + struct devctl_command **cmd; + + if (ac < 2) { + warnx("The %s command requires a sub-command.", av[0]); + return (EINVAL); + } + for (cmd = start; cmd < end; cmd++) { + if (strcmp((*cmd)->name, av[1]) == 0) + return ((*cmd)->handler(ac - 1, av + 1)); + } + + warnx("%s is not a valid sub-command of %s.", av[1], av[0]); + return (ENOENT); +} + +static int +help(int ac __unused, char **av __unused) +{ + + usage(); + return (0); +} +DEVCTL_COMMAND(top, help, help); + +static int +attach(int ac, char **av) +{ + + if (ac != 2) + usage(); + if (devctl_attach(av[1]) < 0) + err(1, "Failed to attach %s", av[1]); + return (0); +} +DEVCTL_COMMAND(top, attach, attach); + +static void +detach_usage(void) +{ + + fprintf(stderr, "usage: devctl detach [-f] device\n"); + exit(1); +} + +static int +detach(int ac, char **av) +{ + bool force; + int ch; + + force = false; + while ((ch = getopt(ac, av, "f")) != -1) + switch (ch) { + case 'f': + force = true; + break; + default: + detach_usage(); + } + ac -= optind; + av += optind; + + if (ac != 1) + detach_usage(); + if (devctl_detach(av[0], force) < 0) + err(1, "Failed to detach %s", av[0]); + return (0); +} +DEVCTL_COMMAND(top, detach, detach); + +static void +disable_usage(void) +{ + + fprintf(stderr, "usage: devctl disable [-f] device\n"); + exit(1); +} + +static int +disable(int ac, char **av) +{ + bool force; + int ch; + + force = false; + while ((ch = getopt(ac, av, "f")) != -1) + switch (ch) { + case 'f': + force = true; + break; + default: + disable_usage(); + } + ac -= optind; + av += optind; + + if (ac != 1) + disable_usage(); + if (devctl_disable(av[0], force) < 0) + err(1, "Failed to disable %s", av[0]); + return (0); +} +DEVCTL_COMMAND(top, disable, disable); + +static int +enable(int ac, char **av) +{ + + if (ac != 2) + usage(); + if (devctl_enable(av[1]) < 0) + err(1, "Failed to enable %s", av[1]); + return (0); +} +DEVCTL_COMMAND(top, enable, enable); + +static int +suspend(int ac, char **av) +{ + + if (ac != 2) + usage(); + if (devctl_suspend(av[1]) < 0) + err(1, "Failed to suspend %s", av[1]); + return (0); +} +DEVCTL_COMMAND(top, suspend, suspend); + +static int +resume(int ac, char **av) +{ + + if (ac != 2) + usage(); + if (devctl_resume(av[1]) < 0) + err(1, "Failed to resume %s", av[1]); + return (0); +} +DEVCTL_COMMAND(top, resume, resume); + +static void +set_driver_usage(void) +{ + + fprintf(stderr, "usage: devctl set driver [-f] device driver\n"); + exit(1); +} + +static int +set_driver(int ac, char **av) +{ + bool force; + int ch; + + force = false; + while ((ch = getopt(ac, av, "f")) != -1) + switch (ch) { + case 'f': + force = true; + break; + default: + set_driver_usage(); + } + ac -= optind; + av += optind; + + if (ac != 2) + set_driver_usage(); + if (devctl_set_driver(av[0], av[1], force) < 0) + err(1, "Failed to set %s driver to %s", av[0], av[1]); + return (0); +} +DEVCTL_COMMAND(set, driver, set_driver); + +int +main(int ac, char *av[]) +{ + struct devctl_command **cmd; + + if (ac == 1) + usage(); + ac--; + av++; + + SET_FOREACH(cmd, DEVCTL_DATASET(top)) { + if (strcmp((*cmd)->name, av[0]) == 0) { + if ((*cmd)->handler(ac, av) != 0) + return (1); + else + return (0); + } + } + warnx("Unknown command %s.", av[0]); + return (1); +} From c869aa71f056ba8078a9db78290c295a644cad84 Mon Sep 17 00:00:00 2001 From: John Baldwin Date: Fri, 6 Feb 2015 16:45:10 +0000 Subject: [PATCH 17/36] Use direct hardware access for internal requests for KCS and SMIC. In particular, updates to the watchdog should no longer sleep. - Add a new IPMI_IO_LOCK for low-level I/O access. Use this for kcs_polled_request() and smic_polled_request(). - Add a new backend callback "ipmi_driver_request" to handle a driver request. The new callback performs the request sychronously for KCS and SMIC. SSIF still defers the work to the worker thread since the worker thread sleeps during request processing anyway. - Allocate driver requests on the stack rather than using malloc(). Differential Revision: https://reviews.freebsd.org/D1723 Tested by: scottl MFC after: 2 weeks --- sys/dev/ipmi/ipmi.c | 104 ++++++++++++++++++++------------------- sys/dev/ipmi/ipmi_kcs.c | 20 ++++++++ sys/dev/ipmi/ipmi_smic.c | 24 ++++++++- sys/dev/ipmi/ipmi_ssif.c | 17 +++++++ sys/dev/ipmi/ipmivars.h | 15 +++--- 5 files changed, 122 insertions(+), 58 deletions(-) diff --git a/sys/dev/ipmi/ipmi.c b/sys/dev/ipmi/ipmi.c index 5e30770cb669..a1edbf64524b 100644 --- a/sys/dev/ipmi/ipmi.c +++ b/sys/dev/ipmi/ipmi.c @@ -49,6 +49,23 @@ __FBSDID("$FreeBSD$"); #include #endif +/* + * Driver request structures are allocated on the stack via alloca() to + * avoid calling malloc(), especially for the watchdog handler. + * To avoid too much stack growth, a previously allocated structure can + * be reused via IPMI_INIT_DRIVER_REQUEST(), but the caller should ensure + * that there is adequate reply/request space in the original allocation. + */ +#define IPMI_INIT_DRIVER_REQUEST(req, addr, cmd, reqlen, replylen) \ + bzero((req), sizeof(struct ipmi_request)); \ + ipmi_init_request((req), NULL, 0, (addr), (cmd), (reqlen), (replylen)) + +#define IPMI_ALLOC_DRIVER_REQUEST(req, addr, cmd, reqlen, replylen) \ + (req) = __builtin_alloca(sizeof(struct ipmi_request) + \ + (reqlen) + (replylen)); \ + IPMI_INIT_DRIVER_REQUEST((req), (addr), (cmd), (reqlen), \ + (replylen)) + #ifdef IPMB static int ipmi_ipmb_checksum(u_char, int); static int ipmi_ipmb_send_message(device_t, u_char, u_char, u_char, @@ -181,8 +198,8 @@ ipmi_dtor(void *arg) */ dev->ipmi_closing = 1; while (dev->ipmi_requests > 0) { - msleep(&dev->ipmi_requests, &sc->ipmi_lock, PWAIT, - "ipmidrain", 0); + msleep(&dev->ipmi_requests, &sc->ipmi_requests_lock, + PWAIT, "ipmidrain", 0); ipmi_purge_completed_requests(dev); } } @@ -215,7 +232,7 @@ ipmi_ipmb_send_message(device_t dev, u_char channel, u_char netfn, u_char slave_addr = 0x52; int error; - req = ipmi_alloc_driver_request(IPMI_ADDR(IPMI_APP_REQUEST, 0), + IPMI_ALLOC_DRIVER_REQUEST(req, IPMI_ADDR(IPMI_APP_REQUEST, 0), IPMI_SEND_MSG, data_len + 8, 0); req->ir_request[0] = channel; req->ir_request[1] = slave_addr; @@ -231,7 +248,6 @@ ipmi_ipmb_send_message(device_t dev, u_char channel, u_char netfn, ipmi_submit_driver_request(sc, req); error = req->ir_error; - ipmi_free_request(req); return (error); } @@ -243,7 +259,7 @@ ipmi_handle_attn(struct ipmi_softc *sc) int error; device_printf(sc->ipmi_dev, "BMC has a message\n"); - req = ipmi_alloc_driver_request(IPMI_ADDR(IPMI_APP_REQUEST, 0), + IPMI_ALLOC_DRIVER_REQUEST(req, IPMI_ADDR(IPMI_APP_REQUEST, 0), IPMI_GET_MSG_FLAGS, 0, 1); ipmi_submit_driver_request(sc, req); @@ -257,9 +273,7 @@ ipmi_handle_attn(struct ipmi_softc *sc) "watchdog about to go off"); } if (req->ir_reply[0] & IPMI_MSG_AVAILABLE) { - ipmi_free_request(req); - - req = ipmi_alloc_driver_request( + IPMI_ALLOC_DRIVER_REQUEST(req, IPMI_ADDR(IPMI_APP_REQUEST, 0), IPMI_GET_MSG, 0, 16); @@ -268,7 +282,6 @@ ipmi_handle_attn(struct ipmi_softc *sc) } } error = req->ir_error; - ipmi_free_request(req); return (error); } @@ -478,15 +491,11 @@ ipmi_ioctl(struct cdev *cdev, u_long cmd, caddr_t data, * Request management. */ -/* Allocate a new request with request and reply buffers. */ -struct ipmi_request * -ipmi_alloc_request(struct ipmi_device *dev, long msgid, uint8_t addr, - uint8_t command, size_t requestlen, size_t replylen) +static __inline void +ipmi_init_request(struct ipmi_request *req, struct ipmi_device *dev, long msgid, + uint8_t addr, uint8_t command, size_t requestlen, size_t replylen) { - struct ipmi_request *req; - req = malloc(sizeof(struct ipmi_request) + requestlen + replylen, - M_IPMI, M_WAITOK | M_ZERO); req->ir_owner = dev; req->ir_msgid = msgid; req->ir_addr = addr; @@ -499,6 +508,18 @@ ipmi_alloc_request(struct ipmi_device *dev, long msgid, uint8_t addr, req->ir_reply = (char *)&req[1] + requestlen; req->ir_replybuflen = replylen; } +} + +/* Allocate a new request with request and reply buffers. */ +struct ipmi_request * +ipmi_alloc_request(struct ipmi_device *dev, long msgid, uint8_t addr, + uint8_t command, size_t requestlen, size_t replylen) +{ + struct ipmi_request *req; + + req = malloc(sizeof(struct ipmi_request) + requestlen + replylen, + M_IPMI, M_WAITOK | M_ZERO); + ipmi_init_request(req, dev, msgid, addr, command, requestlen, replylen); return (req); } @@ -533,21 +554,13 @@ ipmi_complete_request(struct ipmi_softc *sc, struct ipmi_request *req) } } -/* Enqueue an internal driver request and wait until it is completed. */ +/* Perform an internal driver request. */ int ipmi_submit_driver_request(struct ipmi_softc *sc, struct ipmi_request *req, int timo) { - int error; - IPMI_LOCK(sc); - error = sc->ipmi_enqueue_request(sc, req); - if (error == 0) - error = msleep(req, &sc->ipmi_lock, 0, "ipmireq", timo); - if (error == 0) - error = req->ir_error; - IPMI_UNLOCK(sc); - return (error); + return (sc->ipmi_driver_request(sc, req, timo)); } /* @@ -564,7 +577,7 @@ ipmi_dequeue_request(struct ipmi_softc *sc) IPMI_LOCK_ASSERT(sc); while (!sc->ipmi_detaching && TAILQ_EMPTY(&sc->ipmi_pending_requests)) - cv_wait(&sc->ipmi_request_added, &sc->ipmi_lock); + cv_wait(&sc->ipmi_request_added, &sc->ipmi_requests_lock); if (sc->ipmi_detaching) return (NULL); @@ -598,7 +611,7 @@ ipmi_set_watchdog(struct ipmi_softc *sc, unsigned int sec) if (sec > 0xffff / 10) return (EINVAL); - req = ipmi_alloc_driver_request(IPMI_ADDR(IPMI_APP_REQUEST, 0), + IPMI_ALLOC_DRIVER_REQUEST(req, IPMI_ADDR(IPMI_APP_REQUEST, 0), IPMI_SET_WDOG, 6, 0); if (sec) { @@ -622,9 +635,7 @@ ipmi_set_watchdog(struct ipmi_softc *sc, unsigned int sec) if (error) device_printf(sc->ipmi_dev, "Failed to set watchdog\n"); else if (sec) { - ipmi_free_request(req); - - req = ipmi_alloc_driver_request(IPMI_ADDR(IPMI_APP_REQUEST, 0), + IPMI_INIT_DRIVER_REQUEST(req, IPMI_ADDR(IPMI_APP_REQUEST, 0), IPMI_RESET_WDOG, 0, 0); error = ipmi_submit_driver_request(sc, req, 0); @@ -633,7 +644,6 @@ ipmi_set_watchdog(struct ipmi_softc *sc, unsigned int sec) "Failed to reset watchdog\n"); } - ipmi_free_request(req); return (error); /* dump_watchdog(sc); @@ -680,7 +690,8 @@ ipmi_startup(void *arg) dev = sc->ipmi_dev; /* Initialize interface-independent state. */ - mtx_init(&sc->ipmi_lock, device_get_nameunit(dev), "ipmi", MTX_DEF); + mtx_init(&sc->ipmi_requests_lock, "ipmi requests", NULL, MTX_DEF); + mtx_init(&sc->ipmi_io_lock, "ipmi io", NULL, MTX_DEF); cv_init(&sc->ipmi_request_added, "ipmireq"); TAILQ_INIT(&sc->ipmi_pending_requests); @@ -693,28 +704,24 @@ ipmi_startup(void *arg) } /* Send a GET_DEVICE_ID request. */ - req = ipmi_alloc_driver_request(IPMI_ADDR(IPMI_APP_REQUEST, 0), + IPMI_ALLOC_DRIVER_REQUEST(req, IPMI_ADDR(IPMI_APP_REQUEST, 0), IPMI_GET_DEVICE_ID, 0, 15); error = ipmi_submit_driver_request(sc, req, MAX_TIMEOUT); if (error == EWOULDBLOCK) { device_printf(dev, "Timed out waiting for GET_DEVICE_ID\n"); - ipmi_free_request(req); return; } else if (error) { device_printf(dev, "Failed GET_DEVICE_ID: %d\n", error); - ipmi_free_request(req); return; } else if (req->ir_compcode != 0) { device_printf(dev, "Bad completion code for GET_DEVICE_ID: %d\n", req->ir_compcode); - ipmi_free_request(req); return; } else if (req->ir_replylen < 5) { device_printf(dev, "Short reply for GET_DEVICE_ID: %d\n", req->ir_replylen); - ipmi_free_request(req); return; } @@ -724,9 +731,7 @@ ipmi_startup(void *arg) req->ir_reply[2] & 0x7f, req->ir_reply[3] >> 4, req->ir_reply[3] & 0x0f, req->ir_reply[4] & 0x0f, req->ir_reply[4] >> 4); - ipmi_free_request(req); - - req = ipmi_alloc_driver_request(IPMI_ADDR(IPMI_APP_REQUEST, 0), + IPMI_INIT_DRIVER_REQUEST(req, IPMI_ADDR(IPMI_APP_REQUEST, 0), IPMI_CLEAR_FLAGS, 1, 0); ipmi_submit_driver_request(sc, req, 0); @@ -738,25 +743,21 @@ ipmi_startup(void *arg) if (req->ir_compcode == 0xc1) { device_printf(dev, "Clear flags illegal\n"); } - ipmi_free_request(req); for (i = 0; i < 8; i++) { - req = ipmi_alloc_driver_request(IPMI_ADDR(IPMI_APP_REQUEST, 0), + IPMI_INIT_DRIVER_REQUEST(req, IPMI_ADDR(IPMI_APP_REQUEST, 0), IPMI_GET_CHANNEL_INFO, 1, 0); req->ir_request[0] = i; ipmi_submit_driver_request(sc, req, 0); - if (req->ir_compcode != 0) { - ipmi_free_request(req); + if (req->ir_compcode != 0) break; - } - ipmi_free_request(req); } device_printf(dev, "Number of channels %d\n", i); /* probe for watchdog */ - req = ipmi_alloc_driver_request(IPMI_ADDR(IPMI_APP_REQUEST, 0), + IPMI_INIT_DRIVER_REQUEST(req, IPMI_ADDR(IPMI_APP_REQUEST, 0), IPMI_GET_WDOG, 0, 0); ipmi_submit_driver_request(sc, req, 0); @@ -767,7 +768,6 @@ ipmi_startup(void *arg) sc->ipmi_watchdog_tag = EVENTHANDLER_REGISTER(watchdog_list, ipmi_wd_event, sc, 0); } - ipmi_free_request(req); sc->ipmi_cdev = make_dev(&ipmi_cdevsw, device_get_unit(dev), UID_ROOT, GID_OPERATOR, 0660, "ipmi%d", device_get_unit(dev)); @@ -834,14 +834,16 @@ ipmi_detach(device_t dev) sc->ipmi_detaching = 1; if (sc->ipmi_kthread) { cv_broadcast(&sc->ipmi_request_added); - msleep(sc->ipmi_kthread, &sc->ipmi_lock, 0, "ipmi_wait", 0); + msleep(sc->ipmi_kthread, &sc->ipmi_requests_lock, 0, + "ipmi_wait", 0); } IPMI_UNLOCK(sc); if (sc->ipmi_irq) bus_teardown_intr(dev, sc->ipmi_irq_res, sc->ipmi_irq); ipmi_release_resources(dev); - mtx_destroy(&sc->ipmi_lock); + mtx_destroy(&sc->ipmi_io_lock); + mtx_destroy(&sc->ipmi_requests_lock); return (0); } diff --git a/sys/dev/ipmi/ipmi_kcs.c b/sys/dev/ipmi/ipmi_kcs.c index eb5884a86b57..1c586467667b 100644 --- a/sys/dev/ipmi/ipmi_kcs.c +++ b/sys/dev/ipmi/ipmi_kcs.c @@ -321,6 +321,8 @@ kcs_polled_request(struct ipmi_softc *sc, struct ipmi_request *req) u_char *cp, data; int i, state; + IPMI_IO_LOCK(sc); + /* Send the request. */ if (!kcs_start_write(sc)) { device_printf(sc->ipmi_dev, "KCS: Failed to start write\n"); @@ -444,6 +446,7 @@ kcs_polled_request(struct ipmi_softc *sc, struct ipmi_request *req) } i++; } + IPMI_IO_UNLOCK(sc); req->ir_replylen = i; #ifdef KCS_DEBUG device_printf(sc->ipmi_dev, "KCS: READ finished (%d bytes)\n", i); @@ -457,6 +460,7 @@ kcs_polled_request(struct ipmi_softc *sc, struct ipmi_request *req) return (1); fail: kcs_error(sc); + IPMI_IO_UNLOCK(sc); return (0); } @@ -492,6 +496,21 @@ kcs_startup(struct ipmi_softc *sc) device_get_nameunit(sc->ipmi_dev))); } +static int +kcs_driver_request(struct ipmi_softc *sc, struct ipmi_request *req, int timo) +{ + int i, ok; + + ok = 0; + for (i = 0; i < 3 && !ok; i++) + ok = kcs_polled_request(sc, req); + if (ok) + req->ir_error = 0; + else + req->ir_error = EIO; + return (req->ir_error); +} + int ipmi_kcs_attach(struct ipmi_softc *sc) { @@ -500,6 +519,7 @@ ipmi_kcs_attach(struct ipmi_softc *sc) /* Setup function pointers. */ sc->ipmi_startup = kcs_startup; sc->ipmi_enqueue_request = ipmi_polled_enqueue_request; + sc->ipmi_driver_request = kcs_driver_request; /* See if we can talk to the controller. */ status = INB(sc, KCS_CTL_STS); diff --git a/sys/dev/ipmi/ipmi_smic.c b/sys/dev/ipmi/ipmi_smic.c index c79c86d574fb..4e26553e98e7 100644 --- a/sys/dev/ipmi/ipmi_smic.c +++ b/sys/dev/ipmi/ipmi_smic.c @@ -364,8 +364,11 @@ smic_loop(void *arg) while ((req = ipmi_dequeue_request(sc)) != NULL) { IPMI_UNLOCK(sc); ok = 0; - for (i = 0; i < 3 && !ok; i++) + for (i = 0; i < 3 && !ok; i++) { + IPMI_IO_LOCK(sc); ok = smic_polled_request(sc, req); + IPMI_IO_UNLOCK(sc); + } if (ok) req->ir_error = 0; else @@ -385,6 +388,24 @@ smic_startup(struct ipmi_softc *sc) "%s: smic", device_get_nameunit(sc->ipmi_dev))); } +static int +smic_driver_request(struct ipmi_softc *sc, struct ipmi_request *req, int timo) +{ + int i, ok; + + ok = 0; + for (i = 0; i < 3 && !ok; i++) { + IPMI_IO_LOCK(sc); + ok = smic_polled_request(sc, req); + IPMI_IO_UNLOCK(sc); + } + if (ok) + req->ir_error = 0; + else + req->ir_error = EIO; + return (req->ir_error); +} + int ipmi_smic_attach(struct ipmi_softc *sc) { @@ -393,6 +414,7 @@ ipmi_smic_attach(struct ipmi_softc *sc) /* Setup function pointers. */ sc->ipmi_startup = smic_startup; sc->ipmi_enqueue_request = ipmi_polled_enqueue_request; + sc->ipmi_driver_request = smic_driver_request; /* See if we can talk to the controller. */ flags = INB(sc, SMIC_FLAGS); diff --git a/sys/dev/ipmi/ipmi_ssif.c b/sys/dev/ipmi/ipmi_ssif.c index 2256de16e7ef..e5d5d3aa8cdd 100644 --- a/sys/dev/ipmi/ipmi_ssif.c +++ b/sys/dev/ipmi/ipmi_ssif.c @@ -359,6 +359,22 @@ ssif_startup(struct ipmi_softc *sc) "%s: ssif", device_get_nameunit(sc->ipmi_dev))); } +static int +ssif_driver_request(struct ipmi_softc *sc, struct ipmi_request *req, int timo) +{ + int error; + + IPMI_LOCK(sc); + error = ipmi_polled_enqueue_request(sc, req); + if (error == 0) + error = msleep(req, &sc->ipmi_requests_lock, 0, "ipmireq", + timo); + if (error == 0) + error = req->ir_error; + IPMI_UNLOCK(sc); + return (error); +} + int ipmi_ssif_attach(struct ipmi_softc *sc, device_t smbus, int smbus_address) { @@ -370,6 +386,7 @@ ipmi_ssif_attach(struct ipmi_softc *sc, device_t smbus, int smbus_address) /* Setup function pointers. */ sc->ipmi_startup = ssif_startup; sc->ipmi_enqueue_request = ipmi_polled_enqueue_request; + sc->ipmi_driver_request = ssif_driver_request; return (0); } diff --git a/sys/dev/ipmi/ipmivars.h b/sys/dev/ipmi/ipmivars.h index 8e9e130d3ca7..9d7dc3220893 100644 --- a/sys/dev/ipmi/ipmivars.h +++ b/sys/dev/ipmi/ipmivars.h @@ -95,6 +95,7 @@ struct ipmi_softc { } _iface; int ipmi_io_rid; int ipmi_io_type; + struct mtx ipmi_io_lock; struct resource *ipmi_io_res[MAX_RES]; int ipmi_io_spacing; int ipmi_irq_rid; @@ -107,12 +108,13 @@ struct ipmi_softc { eventhandler_tag ipmi_watchdog_tag; int ipmi_watchdog_active; struct intr_config_hook ipmi_ich; - struct mtx ipmi_lock; + struct mtx ipmi_requests_lock; struct cv ipmi_request_added; struct proc *ipmi_kthread; driver_intr_t *ipmi_intr; int (*ipmi_startup)(struct ipmi_softc *); int (*ipmi_enqueue_request)(struct ipmi_softc *, struct ipmi_request *); + int (*ipmi_driver_request)(struct ipmi_softc *, struct ipmi_request *, int); }; #define ipmi_ssif_smbus_address _iface.ssif.smbus_address @@ -183,12 +185,13 @@ struct ipmi_ipmb { #define IPMI_ADDR(netfn, lun) ((netfn) << 2 | (lun)) #define IPMI_REPLY_ADDR(addr) ((addr) + 0x4) -#define IPMI_LOCK(sc) mtx_lock(&(sc)->ipmi_lock) -#define IPMI_UNLOCK(sc) mtx_unlock(&(sc)->ipmi_lock) -#define IPMI_LOCK_ASSERT(sc) mtx_assert(&(sc)->ipmi_lock, MA_OWNED) +#define IPMI_LOCK(sc) mtx_lock(&(sc)->ipmi_requests_lock) +#define IPMI_UNLOCK(sc) mtx_unlock(&(sc)->ipmi_requests_lock) +#define IPMI_LOCK_ASSERT(sc) mtx_assert(&(sc)->ipmi_requests_lock, MA_OWNED) -#define ipmi_alloc_driver_request(addr, cmd, reqlen, replylen) \ - ipmi_alloc_request(NULL, 0, (addr), (cmd), (reqlen), (replylen)) +#define IPMI_IO_LOCK(sc) mtx_lock(&(sc)->ipmi_io_lock) +#define IPMI_IO_UNLOCK(sc) mtx_unlock(&(sc)->ipmi_io_lock) +#define IPMI_IO_LOCK_ASSERT(sc) mtx_assert(&(sc)->ipmi_io_lock, MA_OWNED) #if __FreeBSD_version < 601105 #define bus_read_1(r, o) \ From 92847ee1f364687be3ec9aed6e1837e0b3c349f5 Mon Sep 17 00:00:00 2001 From: Alexander Motin Date: Fri, 6 Feb 2015 17:43:13 +0000 Subject: [PATCH 18/36] Add support for multiple portal groups per target. This change allows multiple "portal-group" options to be specified per target. Each of them may include new optional auth-group name parameter to override per-target auth parameters for specific portal group. Kernel side support was added earlier at r278161. MFC after: 2 weeks Sponsored by: iXsystems, Inc. --- usr.sbin/ctld/ctl.conf.5 | 9 ++- usr.sbin/ctld/ctld.c | 160 +++++++++++++++++++++++++++----------- usr.sbin/ctld/ctld.h | 35 +++++++-- usr.sbin/ctld/discovery.c | 41 +++++----- usr.sbin/ctld/kernel.c | 85 +++++++++++++------- usr.sbin/ctld/login.c | 9 ++- usr.sbin/ctld/parse.y | 49 ++++++++++-- 7 files changed, 278 insertions(+), 110 deletions(-) diff --git a/usr.sbin/ctld/ctl.conf.5 b/usr.sbin/ctld/ctl.conf.5 index 789161f90bb8..fa053b0f20cf 100644 --- a/usr.sbin/ctld/ctl.conf.5 +++ b/usr.sbin/ctld/ctl.conf.5 @@ -27,7 +27,7 @@ .\" .\" $FreeBSD$ .\" -.Dd February 1, 2015 +.Dd February 6, 2015 .Dt CTL.CONF 5 .Os .Sh NAME @@ -66,7 +66,7 @@ file is: .No target Ar name { .Dl auth-group Ar name -.Dl portal-group Ar name +.Dl portal-group Ar name Op Ar agname .Dl lun Ar number Ar name .Dl lun Ar number No { .Dl path Ar path @@ -310,12 +310,15 @@ This clause is mutually exclusive with .Sy auth-group ; one cannot use both in a single target. -.It Ic portal-group Ar name +.It Ic portal-group Ar name Op Ar agname Assign a previously defined portal group to the target. The default portal group is .Qq Ar default , which makes the target available on TCP port 3260 on all configured IPv4 and IPv6 addresses. +Optional second argument specifies auth group name for connections +to this specific portal group. +If second argument is not specified, target auth group is used. .It Ic redirect Aq Ar address IPv4 or IPv6 address to redirect initiators to. When configured, all initiators attempting to connect to this target diff --git a/usr.sbin/ctld/ctld.c b/usr.sbin/ctld/ctld.c index c19b55a4c1d6..513e073630b1 100644 --- a/usr.sbin/ctld/ctld.c +++ b/usr.sbin/ctld/ctld.c @@ -91,6 +91,7 @@ conf_new(void) TAILQ_INIT(&conf->conf_luns); TAILQ_INIT(&conf->conf_targets); TAILQ_INIT(&conf->conf_auth_groups); + TAILQ_INIT(&conf->conf_ports); TAILQ_INIT(&conf->conf_portal_groups); TAILQ_INIT(&conf->conf_isns); @@ -124,6 +125,7 @@ conf_delete(struct conf *conf) portal_group_delete(pg); TAILQ_FOREACH_SAFE(is, &conf->conf_isns, i_next, istmp) isns_delete(is); + assert(TAILQ_EMPTY(&conf->conf_ports)); free(conf->conf_pidfile_path); free(conf); } @@ -609,6 +611,7 @@ portal_group_new(struct conf *conf, const char *name) log_err(1, "calloc"); pg->pg_name = checked_strdup(name); TAILQ_INIT(&pg->pg_portals); + TAILQ_INIT(&pg->pg_ports); pg->pg_conf = conf; pg->pg_tag = 0; /* Assigned later in conf_apply(). */ TAILQ_INSERT_TAIL(&conf->conf_portal_groups, pg, pg_next); @@ -620,7 +623,10 @@ void portal_group_delete(struct portal_group *pg) { struct portal *portal, *tmp; + struct port *port, *tport; + TAILQ_FOREACH_SAFE(port, &pg->pg_ports, p_pgs, tport) + port_delete(port); TAILQ_REMOVE(&pg->pg_conf->conf_portal_groups, pg, pg_next); TAILQ_FOREACH_SAFE(portal, &pg->pg_portals, p_next, tmp) @@ -784,6 +790,7 @@ isns_do_register(struct isns *isns, int s, const char *hostname) struct target *target; struct portal *portal; struct portal_group *pg; + struct port *port; struct isns_req *req; int res = 0; uint32_t error; @@ -807,11 +814,14 @@ isns_do_register(struct isns *isns, int s, const char *hostname) isns_req_add_32(req, 33, 1); /* 1 -- Target*/ if (target->t_alias != NULL) isns_req_add_str(req, 34, target->t_alias); - pg = target->t_portal_group; - isns_req_add_32(req, 51, pg->pg_tag); - TAILQ_FOREACH(portal, &pg->pg_portals, p_next) { - isns_req_add_addr(req, 49, portal->p_ai); - isns_req_add_port(req, 50, portal->p_ai); + TAILQ_FOREACH(port, &target->t_ports, p_ts) { + if ((pg = port->p_portal_group) == NULL) + continue; + isns_req_add_32(req, 51, pg->pg_tag); + TAILQ_FOREACH(portal, &pg->pg_portals, p_next) { + isns_req_add_addr(req, 49, portal->p_ai); + isns_req_add_port(req, 50, portal->p_ai); + } } } res = isns_req_send(s, req); @@ -1123,6 +1133,68 @@ valid_iscsi_name(const char *name) return (true); } +struct port * +port_new(struct conf *conf, struct target *target, struct portal_group *pg) +{ + struct port *port; + + port = calloc(1, sizeof(*port)); + if (port == NULL) + log_err(1, "calloc"); + asprintf(&port->p_name, "%s-%s", pg->pg_name, target->t_name); + if (port_find(conf, port->p_name) != NULL) { + log_warnx("duplicate port \"%s\"", port->p_name); + free(port); + return (NULL); + } + port->p_conf = conf; + TAILQ_INSERT_TAIL(&conf->conf_ports, port, p_next); + TAILQ_INSERT_TAIL(&target->t_ports, port, p_ts); + port->p_target = target; + TAILQ_INSERT_TAIL(&pg->pg_ports, port, p_pgs); + port->p_portal_group = pg; + return (port); +} + +struct port * +port_find(const struct conf *conf, const char *name) +{ + struct port *port; + + TAILQ_FOREACH(port, &conf->conf_ports, p_next) { + if (strcasecmp(port->p_name, name) == 0) + return (port); + } + + return (NULL); +} + +struct port * +port_find_in_pg(const struct portal_group *pg, const char *target) +{ + struct port *port; + + TAILQ_FOREACH(port, &pg->pg_ports, p_pgs) { + if (strcasecmp(port->p_target->t_name, target) == 0) + return (port); + } + + return (NULL); +} + +void +port_delete(struct port *port) +{ + + if (port->p_portal_group) + TAILQ_REMOVE(&port->p_portal_group->pg_ports, port, p_pgs); + if (port->p_target) + TAILQ_REMOVE(&port->p_target->t_ports, port, p_ts); + TAILQ_REMOVE(&port->p_conf->conf_ports, port, p_next); + free(port->p_name); + free(port); +} + struct target * target_new(struct conf *conf, const char *name) { @@ -1151,6 +1223,7 @@ target_new(struct conf *conf, const char *name) targ->t_name[i] = tolower(targ->t_name[i]); targ->t_conf = conf; + TAILQ_INIT(&targ->t_ports); TAILQ_INSERT_TAIL(&conf->conf_targets, targ, t_next); return (targ); @@ -1159,7 +1232,10 @@ target_new(struct conf *conf, const char *name) void target_delete(struct target *targ) { + struct port *port, *tport; + TAILQ_FOREACH_SAFE(port, &targ->t_ports, p_ts, tport) + port_delete(port); TAILQ_REMOVE(&targ->t_conf->conf_targets, targ, t_next); free(targ->t_name); @@ -1196,13 +1272,6 @@ target_set_redirection(struct target *target, const char *addr) return (0); } -void -target_set_ctl_port(struct target *target, uint32_t value) -{ - - target->t_ctl_port = value; -} - struct lun * lun_new(struct conf *conf, const char *name) { @@ -1508,6 +1577,7 @@ conf_verify(struct conf *conf) { struct auth_group *ag; struct portal_group *pg; + struct port *port; struct target *targ; struct lun *lun; bool found; @@ -1527,10 +1597,10 @@ conf_verify(struct conf *conf) "default"); assert(targ->t_auth_group != NULL); } - if (targ->t_portal_group == NULL) { - targ->t_portal_group = portal_group_find(conf, - "default"); - assert(targ->t_portal_group != NULL); + if (TAILQ_EMPTY(&targ->t_ports)) { + pg = portal_group_find(conf, "default"); + assert(pg != NULL); + port_new(conf, targ, pg); } found = false; for (i = 0; i < MAX_LUNS; i++) { @@ -1558,20 +1628,14 @@ conf_verify(struct conf *conf) if (pg->pg_discovery_filter == PG_FILTER_UNKNOWN) pg->pg_discovery_filter = PG_FILTER_NONE; - TAILQ_FOREACH(targ, &conf->conf_targets, t_next) { - if (targ->t_portal_group == pg) - break; - } - if (pg->pg_redirection != NULL) { - if (targ != NULL) { + if (!TAILQ_EMPTY(&pg->pg_ports)) { + if (pg->pg_redirection != NULL) { log_debugx("portal-group \"%s\" assigned " - "to target \"%s\", but configured " + "to target, but configured " "for redirection", - pg->pg_name, targ->t_name); + pg->pg_name); } pg->pg_unassigned = false; - } else if (targ != NULL) { - pg->pg_unassigned = false; } else { if (strcmp(pg->pg_name, "default") != 0) log_warnx("portal-group \"%s\" not assigned " @@ -1592,6 +1656,12 @@ conf_verify(struct conf *conf) break; } } + TAILQ_FOREACH(port, &conf->conf_ports, p_next) { + if (port->p_auth_group == ag) { + found = true; + break; + } + } TAILQ_FOREACH(pg, &conf->conf_portal_groups, pg_next) { if (pg->pg_discovery_auth_group == ag) { found = true; @@ -1613,10 +1683,10 @@ conf_verify(struct conf *conf) static int conf_apply(struct conf *oldconf, struct conf *newconf) { - struct target *oldtarg, *newtarg, *tmptarg; struct lun *oldlun, *newlun, *tmplun; struct portal_group *oldpg, *newpg; struct portal *oldp, *newp; + struct port *oldport, *newport, *tmpport; struct isns *oldns, *newns; pid_t otherpid; int changed, cumulated_error = 0, error, sockbuf; @@ -1684,17 +1754,17 @@ conf_apply(struct conf *oldconf, struct conf *newconf) * really happen, so leave it as it is for now. */ /* - * First, remove any targets present in the old configuration + * First, remove any ports present in the old configuration * and missing in the new one. */ - TAILQ_FOREACH_SAFE(oldtarg, &oldconf->conf_targets, t_next, tmptarg) { - newtarg = target_find(newconf, oldtarg->t_name); - if (newtarg != NULL) + TAILQ_FOREACH_SAFE(oldport, &oldconf->conf_ports, p_next, tmpport) { + newport = port_find(newconf, oldport->p_name); + if (newport != NULL) continue; - error = kernel_port_remove(oldtarg); + error = kernel_port_remove(oldport); if (error != 0) { - log_warnx("failed to remove target %s", - oldtarg->t_name); + log_warnx("failed to remove port %s", + oldport->p_name); /* * XXX: Uncomment after fixing the root cause. * @@ -1809,21 +1879,21 @@ conf_apply(struct conf *oldconf, struct conf *newconf) } /* - * Now add new targets or modify existing ones. + * Now add new ports or modify existing ones. */ - TAILQ_FOREACH(newtarg, &newconf->conf_targets, t_next) { - oldtarg = target_find(oldconf, newtarg->t_name); + TAILQ_FOREACH(newport, &newconf->conf_ports, p_next) { + oldport = port_find(oldconf, newport->p_name); - if (oldtarg == NULL) - error = kernel_port_add(newtarg); - else { - target_set_ctl_port(newtarg, oldtarg->t_ctl_port); - error = kernel_port_update(newtarg); + if (oldport == NULL) { + error = kernel_port_add(newport); + } else { + newport->p_ctl_port = oldport->p_ctl_port; + error = kernel_port_update(newport); } if (error != 0) { - log_warnx("failed to %s target %s", - (oldtarg == NULL) ? "add" : "update", - newtarg->t_name); + log_warnx("failed to %s port %s", + (oldport == NULL) ? "add" : "update", + newport->p_name); /* * XXX: Uncomment after fixing the root cause. * diff --git a/usr.sbin/ctld/ctld.h b/usr.sbin/ctld/ctld.h index 251351d9b663..e213e0bcbb82 100644 --- a/usr.sbin/ctld/ctld.h +++ b/usr.sbin/ctld/ctld.h @@ -119,11 +119,25 @@ struct portal_group { int pg_discovery_filter; bool pg_unassigned; TAILQ_HEAD(, portal) pg_portals; + TAILQ_HEAD(, port) pg_ports; char *pg_redirection; uint16_t pg_tag; }; +struct port { + TAILQ_ENTRY(port) p_next; + TAILQ_ENTRY(port) p_pgs; + TAILQ_ENTRY(port) p_ts; + struct conf *p_conf; + char *p_name; + struct auth_group *p_auth_group; + struct portal_group *p_portal_group; + struct target *p_target; + + uint32_t p_ctl_port; +}; + struct lun_option { TAILQ_ENTRY(lun_option) lo_next; struct lun *lo_lun; @@ -152,12 +166,10 @@ struct target { struct conf *t_conf; struct lun *t_luns[MAX_LUNS]; struct auth_group *t_auth_group; - struct portal_group *t_portal_group; + TAILQ_HEAD(, port) t_ports; char *t_name; char *t_alias; char *t_redirection; - - uint32_t t_ctl_port; }; struct isns { @@ -172,6 +184,7 @@ struct conf { TAILQ_HEAD(, lun) conf_luns; TAILQ_HEAD(, target) conf_targets; TAILQ_HEAD(, auth_group) conf_auth_groups; + TAILQ_HEAD(, port) conf_ports; TAILQ_HEAD(, portal_group) conf_portal_groups; TAILQ_HEAD(, isns) conf_isns; int conf_isns_period; @@ -199,6 +212,7 @@ struct conf { struct connection { struct portal *conn_portal; + struct port *conn_port; struct target *conn_target; int conn_socket; int conn_session_type; @@ -317,14 +331,19 @@ void isns_register(struct isns *isns, struct isns *oldisns); void isns_check(struct isns *isns); void isns_deregister(struct isns *isns); +struct port *port_new(struct conf *conf, struct target *target, + struct portal_group *pg); +struct port *port_find(const struct conf *conf, const char *name); +struct port *port_find_in_pg(const struct portal_group *pg, + const char *target); +void port_delete(struct port *port); + struct target *target_new(struct conf *conf, const char *name); void target_delete(struct target *target); struct target *target_find(struct conf *conf, const char *name); int target_set_redirection(struct target *target, const char *addr); -void target_set_ctl_port(struct target *target, - uint32_t value); struct lun *lun_new(struct conf *conf, const char *name); void lun_delete(struct lun *lun); @@ -351,9 +370,9 @@ int kernel_lun_add(struct lun *lun); int kernel_lun_resize(struct lun *lun); int kernel_lun_remove(struct lun *lun); void kernel_handoff(struct connection *conn); -int kernel_port_add(struct target *targ); -int kernel_port_update(struct target *targ); -int kernel_port_remove(struct target *targ); +int kernel_port_add(struct port *port); +int kernel_port_update(struct port *port); +int kernel_port_remove(struct port *port); void kernel_capsicate(void); #ifdef ICL_KERNEL_PROXY diff --git a/usr.sbin/ctld/discovery.c b/usr.sbin/ctld/discovery.c index b370e0be5867..88ca64c96ba7 100644 --- a/usr.sbin/ctld/discovery.c +++ b/usr.sbin/ctld/discovery.c @@ -162,6 +162,7 @@ logout_new_response(struct pdu *request) static void discovery_add_target(struct keys *response_keys, const struct target *targ) { + struct port *port; struct portal *portal; char *buf; char hbuf[NI_MAXHOST], sbuf[NI_MAXSERV]; @@ -169,7 +170,10 @@ discovery_add_target(struct keys *response_keys, const struct target *targ) int ret; keys_add(response_keys, "TargetName", targ->t_name); - TAILQ_FOREACH(portal, &targ->t_portal_group->pg_portals, p_next) { + TAILQ_FOREACH(port, &targ->t_ports, p_ts) { + if (port->p_portal_group == NULL) + continue; + TAILQ_FOREACH(portal, &port->p_portal_group->pg_portals, p_next) { ai = portal->p_ai; ret = getnameinfo(ai->ai_addr, ai->ai_addrlen, hbuf, sizeof(hbuf), sbuf, sizeof(sbuf), @@ -183,13 +187,13 @@ discovery_add_target(struct keys *response_keys, const struct target *targ) if (strcmp(hbuf, "0.0.0.0") == 0) continue; ret = asprintf(&buf, "%s:%s,%d", hbuf, sbuf, - targ->t_portal_group->pg_tag); + port->p_portal_group->pg_tag); break; case AF_INET6: if (strcmp(hbuf, "::") == 0) continue; ret = asprintf(&buf, "[%s]:%s,%d", hbuf, sbuf, - targ->t_portal_group->pg_tag); + port->p_portal_group->pg_tag); break; default: continue; @@ -198,19 +202,24 @@ discovery_add_target(struct keys *response_keys, const struct target *targ) log_err(1, "asprintf"); keys_add(response_keys, "TargetAddress", buf); free(buf); + } } } static bool discovery_target_filtered_out(const struct connection *conn, - const struct target *targ) + const struct port *port) { const struct auth_group *ag; const struct portal_group *pg; + const struct target *targ; const struct auth *auth; int error; - ag = targ->t_auth_group; + targ = port->p_target; + ag = port->p_auth_group; + if (ag == NULL) + ag = targ->t_auth_group; pg = conn->conn_portal->p_portal_group; assert(pg->pg_discovery_auth_group != PG_FILTER_UNKNOWN); @@ -265,8 +274,8 @@ discovery(struct connection *conn) { struct pdu *request, *response; struct keys *request_keys, *response_keys; + const struct port *port; const struct portal_group *pg; - const struct target *targ; const char *send_targets; pg = conn->conn_portal->p_portal_group; @@ -284,29 +293,23 @@ discovery(struct connection *conn) response_keys = keys_new(); if (strcmp(send_targets, "All") == 0) { - TAILQ_FOREACH(targ, &pg->pg_conf->conf_targets, t_next) { - if (targ->t_portal_group != pg) { - log_debugx("not returning target \"%s\"; " - "belongs to a different portal group", - targ->t_name); - continue; - } - if (discovery_target_filtered_out(conn, targ)) { + TAILQ_FOREACH(port, &pg->pg_ports, p_pgs) { + if (discovery_target_filtered_out(conn, port)) { /* Ignore this target. */ continue; } - discovery_add_target(response_keys, targ); + discovery_add_target(response_keys, port->p_target); } } else { - targ = target_find(pg->pg_conf, send_targets); - if (targ == NULL) { + port = port_find_in_pg(pg, send_targets); + if (port == NULL) { log_debugx("initiator requested information on unknown " "target \"%s\"; returning nothing", send_targets); } else { - if (discovery_target_filtered_out(conn, targ)) { + if (discovery_target_filtered_out(conn, port)) { /* Ignore this target. */ } else { - discovery_add_target(response_keys, targ); + discovery_add_target(response_keys, port->p_target); } } } diff --git a/usr.sbin/ctld/kernel.c b/usr.sbin/ctld/kernel.c index 0c5d2ce07306..f36bdcb77f73 100644 --- a/usr.sbin/ctld/kernel.c +++ b/usr.sbin/ctld/kernel.c @@ -121,9 +121,10 @@ struct cctl_lun { struct cctl_port { uint32_t port_id; - int cfiscsi_status; + int cfiscsi_state; char *cfiscsi_target; uint16_t cfiscsi_portal_group_tag; + char *ctld_portal_group_name; STAILQ_HEAD(,cctl_lun_nv) attr_list; STAILQ_ENTRY(cctl_port) links; }; @@ -332,10 +333,13 @@ cctl_end_pelement(void *user_data, const char *name) if (strcmp(name, "cfiscsi_target") == 0) { cur_port->cfiscsi_target = str; str = NULL; - } else if (strcmp(name, "cfiscsi_status") == 0) { - cur_port->cfiscsi_status = strtoul(str, NULL, 0); + } else if (strcmp(name, "cfiscsi_state") == 0) { + cur_port->cfiscsi_state = strtoul(str, NULL, 0); } else if (strcmp(name, "cfiscsi_portal_group_tag") == 0) { cur_port->cfiscsi_portal_group_tag = strtoul(str, NULL, 0); + } else if (strcmp(name, "ctld_portal_group_name") == 0) { + cur_port->ctld_portal_group_name = str; + str = NULL; } else if (strcmp(name, "targ_port") == 0) { devlist->cur_port = NULL; } else if (strcmp(name, "ctlportlist") == 0) { @@ -373,6 +377,8 @@ conf_new_from_kernel(void) { struct conf *conf = NULL; struct target *targ; + struct portal_group *pg; + struct port *cp; struct lun *cl; struct lun_option *lo; struct ctl_lun_list list; @@ -496,9 +502,9 @@ conf_new_from_kernel(void) "ignoring", (uintmax_t)port->port_id); continue; } - if (port->cfiscsi_status != 1) { + if (port->cfiscsi_state != 1) { log_debugx("CTL port %ju is not active (%d); ignoring", - (uintmax_t)port->port_id, port->cfiscsi_status); + (uintmax_t)port->port_id, port->cfiscsi_state); continue; } @@ -514,6 +520,28 @@ conf_new_from_kernel(void) continue; } } + + if (port->ctld_portal_group_name == NULL) + continue; + pg = portal_group_find(conf, port->ctld_portal_group_name); + if (pg == NULL) { +#if 0 + log_debugx("found new kernel portal group %s for CTL port %ld", + port->ctld_portal_group_name, port->port_id); +#endif + pg = portal_group_new(conf, port->ctld_portal_group_name); + if (pg == NULL) { + log_warnx("portal_group_new failed"); + continue; + } + } + pg->pg_tag = port->cfiscsi_portal_group_tag; + cp = port_new(conf, targ, pg); + if (cp == NULL) { + log_warnx("port_new failed"); + continue; + } + cp->p_ctl_port = port->port_id; } STAILQ_FOREACH(lun, &devlist.lun_list, links) { @@ -804,32 +832,34 @@ kernel_handoff(struct connection *conn) } int -kernel_port_add(struct target *targ) +kernel_port_add(struct port *port) { struct ctl_port_entry entry; struct ctl_req req; struct ctl_lun_map lm; + struct target *targ = port->p_target; + struct portal_group *pg = port->p_portal_group; char tagstr[16]; - int error, i; + int error, i, n; /* Create iSCSI port. */ bzero(&req, sizeof(req)); strlcpy(req.driver, "iscsi", sizeof(req.driver)); req.reqtype = CTL_REQ_CREATE; - req.num_args = 4; req.args = malloc(req.num_args * sizeof(*req.args)); - req.args[0].namelen = sizeof("port_id"); - req.args[0].name = __DECONST(char *, "port_id"); - req.args[0].vallen = sizeof(targ->t_ctl_port); - req.args[0].value = &targ->t_ctl_port; - req.args[0].flags = CTL_BEARG_WR; - str_arg(&req.args[1], "cfiscsi_target", targ->t_name); - snprintf(tagstr, sizeof(tagstr), "%d", targ->t_portal_group->pg_tag); - str_arg(&req.args[2], "cfiscsi_portal_group_tag", tagstr); + n = 0; + req.args[n].namelen = sizeof("port_id"); + req.args[n].name = __DECONST(char *, "port_id"); + req.args[n].vallen = sizeof(port->p_ctl_port); + req.args[n].value = &port->p_ctl_port; + req.args[n++].flags = CTL_BEARG_WR; + str_arg(&req.args[n++], "cfiscsi_target", targ->t_name); + snprintf(tagstr, sizeof(tagstr), "%d", pg->pg_tag); + str_arg(&req.args[n++], "cfiscsi_portal_group_tag", tagstr); if (targ->t_alias) - str_arg(&req.args[3], "cfiscsi_target_alias", targ->t_alias); - else - req.num_args--; + str_arg(&req.args[n++], "cfiscsi_target_alias", targ->t_alias); + str_arg(&req.args[n++], "ctld_portal_group_name", pg->pg_name); + req.num_args = n; error = ioctl(ctl_fd, CTL_PORT_REQ, &req); free(req.args); if (error != 0) { @@ -848,7 +878,7 @@ kernel_port_add(struct target *targ) } /* Explicitly enable mapping to block any access except allowed. */ - lm.port = targ->t_ctl_port; + lm.port = port->p_ctl_port; lm.plun = UINT32_MAX; lm.lun = 0; error = ioctl(ctl_fd, CTL_LUN_MAP, &lm); @@ -859,7 +889,7 @@ kernel_port_add(struct target *targ) for (i = 0; i < MAX_LUNS; i++) { if (targ->t_luns[i] == NULL) continue; - lm.port = targ->t_ctl_port; + lm.port = port->p_ctl_port; lm.plun = i; lm.lun = targ->t_luns[i]->l_ctl_lun; error = ioctl(ctl_fd, CTL_LUN_MAP, &lm); @@ -869,7 +899,7 @@ kernel_port_add(struct target *targ) /* Enable port */ bzero(&entry, sizeof(entry)); - entry.targ_port = targ->t_ctl_port; + entry.targ_port = port->p_ctl_port; error = ioctl(ctl_fd, CTL_ENABLE_PORT, &entry); if (error != 0) { log_warn("CTL_ENABLE_PORT ioctl failed"); @@ -880,14 +910,15 @@ kernel_port_add(struct target *targ) } int -kernel_port_update(struct target *targ) +kernel_port_update(struct port *port) { struct ctl_lun_map lm; + struct target *targ = port->p_target; int error, i; /* Map configured LUNs and unmap others */ for (i = 0; i < MAX_LUNS; i++) { - lm.port = targ->t_ctl_port; + lm.port = port->p_ctl_port; lm.plun = i; if (targ->t_luns[i] == NULL) lm.lun = UINT32_MAX; @@ -901,10 +932,12 @@ kernel_port_update(struct target *targ) } int -kernel_port_remove(struct target *targ) +kernel_port_remove(struct port *port) { struct ctl_req req; char tagstr[16]; + struct target *targ = port->p_target; + struct portal_group *pg = port->p_portal_group; int error; bzero(&req, sizeof(req)); @@ -913,7 +946,7 @@ kernel_port_remove(struct target *targ) req.num_args = 2; req.args = malloc(req.num_args * sizeof(*req.args)); str_arg(&req.args[0], "cfiscsi_target", targ->t_name); - snprintf(tagstr, sizeof(tagstr), "%d", targ->t_portal_group->pg_tag); + snprintf(tagstr, sizeof(tagstr), "%d", pg->pg_tag); str_arg(&req.args[1], "cfiscsi_portal_group_tag", tagstr); error = ioctl(ctl_fd, CTL_PORT_REQ, &req); diff --git a/usr.sbin/ctld/login.c b/usr.sbin/ctld/login.c index 5358e4b979a1..865a19a73ab0 100644 --- a/usr.sbin/ctld/login.c +++ b/usr.sbin/ctld/login.c @@ -827,19 +827,22 @@ login(struct connection *conn) log_errx(1, "received Login PDU without TargetName"); } - conn->conn_target = target_find(pg->pg_conf, target_name); - if (conn->conn_target == NULL) { + conn->conn_port = port_find_in_pg(pg, target_name); + if (conn->conn_port == NULL) { login_send_error(request, 0x02, 0x03); log_errx(1, "requested target \"%s\" not found", target_name); } + conn->conn_target = conn->conn_port->p_target; } /* * At this point we know what kind of authentication we need. */ if (conn->conn_session_type == CONN_SESSION_TYPE_NORMAL) { - ag = conn->conn_target->t_auth_group; + ag = conn->conn_port->p_auth_group; + if (ag == NULL) + ag = conn->conn_target->t_auth_group; if (ag->ag_name != NULL) { log_debugx("initiator requests to connect " "to target \"%s\"; auth-group \"%s\"", diff --git a/usr.sbin/ctld/parse.y b/usr.sbin/ctld/parse.y index fead2ea8a258..d0b2c514ca0b 100644 --- a/usr.sbin/ctld/parse.y +++ b/usr.sbin/ctld/parse.y @@ -652,21 +652,58 @@ target_initiator_portal: INITIATOR_PORTAL STR } ; -target_portal_group: PORTAL_GROUP STR +target_portal_group: PORTAL_GROUP STR STR { - if (target->t_portal_group != NULL) { - log_warnx("portal-group for target \"%s\" " - "specified more than once", target->t_name); + struct portal_group *tpg; + struct auth_group *tag; + struct port *tp; + + tpg = portal_group_find(conf, $2); + if (tpg == NULL) { + log_warnx("unknown portal-group \"%s\" for target " + "\"%s\"", $2, target->t_name); + free($2); + free($3); + return (1); + } + tag = auth_group_find(conf, $3); + if (tag == NULL) { + log_warnx("unknown auth-group \"%s\" for target " + "\"%s\"", $3, target->t_name); + free($2); + free($3); + return (1); + } + tp = port_new(conf, target, tpg); + if (tp == NULL) { + log_warnx("can't link portal-group \"%s\" to target " + "\"%s\"", $2, target->t_name); free($2); return (1); } - target->t_portal_group = portal_group_find(conf, $2); - if (target->t_portal_group == NULL) { + tp->p_auth_group = tag; + free($2); + free($3); + } + | PORTAL_GROUP STR + { + struct portal_group *tpg; + struct port *tp; + + tpg = portal_group_find(conf, $2); + if (tpg == NULL) { log_warnx("unknown portal-group \"%s\" for target " "\"%s\"", $2, target->t_name); free($2); return (1); } + tp = port_new(conf, target, tpg); + if (tp == NULL) { + log_warnx("can't link portal-group \"%s\" to target " + "\"%s\"", $2, target->t_name); + free($2); + return (1); + } free($2); } ; From 07a7869fb2d0d626a6f8a412bb4a2482bb8e3f84 Mon Sep 17 00:00:00 2001 From: Jamie Gritton Date: Fri, 6 Feb 2015 17:54:53 +0000 Subject: [PATCH 19/36] Add mount.procfs jail parameter, so procfs can be mounted when a prison's root is in its fstab. Also fix a typo while I'm at it. PR: 197237 197066 MFC after: 3 days --- etc/rc.d/jail | 5 ++--- usr.sbin/jail/command.c | 32 ++++++++++++++++++++++++++++++++ usr.sbin/jail/config.c | 1 + usr.sbin/jail/jail.8 | 9 ++++++++- usr.sbin/jail/jail.c | 2 ++ usr.sbin/jail/jailp.h | 1 + 6 files changed, 46 insertions(+), 4 deletions(-) diff --git a/etc/rc.d/jail b/etc/rc.d/jail index 0b886fd56b59..ea62f4839db4 100755 --- a/etc/rc.d/jail +++ b/etc/rc.d/jail @@ -28,7 +28,7 @@ extra_commands="config console status" need_dad_wait= -# extact_var jail name param num defval +# extract_var jail name param num defval # Extract value from ${jail_$jail_$name} or ${jail_$name} and # set it to $param. If not defined, $defval is used. # When $num is [0-9]*, ${jail_$jail_$name$num} are looked up and @@ -233,8 +233,7 @@ parse_options() fi eval : \${jail_${_j}_procfs_enable:=${jail_procfs_enable:-NO}} if checkyesno jail_${_j}_procfs_enable; then - echo " mount += " \ - "\"procfs ${_rootdir%/}/proc procfs rw 0 0\";" + echo " mount.procfs;" fi eval : \${jail_${_j}_mount_enable:=${jail_mount_enable:-NO}} diff --git a/usr.sbin/jail/command.c b/usr.sbin/jail/command.c index 6fefe414be67..f6f9db3a9fe2 100644 --- a/usr.sbin/jail/command.c +++ b/usr.sbin/jail/command.c @@ -112,6 +112,12 @@ next_command(struct cfjail *j) if (!bool_param(j->intparams[IP_MOUNT_FDESCFS])) continue; j->comstring = &dummystring; + break; + case IP_MOUNT_PROCFS: + if (!bool_param(j->intparams[IP_MOUNT_PROCFS])) + continue; + j->comstring = &dummystring; + break; case IP__OP: case IP_STOP_TIMEOUT: j->comstring = &dummystring; @@ -528,6 +534,32 @@ run_command(struct cfjail *j) } break; + case IP_MOUNT_PROCFS: + argv = alloca(7 * sizeof(char *)); + path = string_param(j->intparams[KP_PATH]); + if (path == NULL) { + jail_warnx(j, "mount.procfs: no path"); + return -1; + } + devpath = alloca(strlen(path) + 6); + sprintf(devpath, "%s/proc", path); + if (check_path(j, "mount.procfs", devpath, 0, + down ? "procfs" : NULL) < 0) + return -1; + if (down) { + argv[0] = "/sbin/umount"; + argv[1] = devpath; + argv[2] = NULL; + } else { + argv[0] = _PATH_MOUNT; + argv[1] = "-t"; + argv[2] = "procfs"; + argv[3] = "."; + argv[4] = devpath; + argv[5] = NULL; + } + break; + case IP_COMMAND: if (j->name != NULL) goto default_command; diff --git a/usr.sbin/jail/config.c b/usr.sbin/jail/config.c index cd02a500c544..582020965136 100644 --- a/usr.sbin/jail/config.c +++ b/usr.sbin/jail/config.c @@ -84,6 +84,7 @@ static const struct ipspec intparams[] = { [IP_MOUNT] = {"mount", PF_INTERNAL | PF_REV}, [IP_MOUNT_DEVFS] = {"mount.devfs", PF_INTERNAL | PF_BOOL}, [IP_MOUNT_FDESCFS] = {"mount.fdescfs", PF_INTERNAL | PF_BOOL}, + [IP_MOUNT_PROCFS] = {"mount.procfs", PF_INTERNAL | PF_BOOL}, [IP_MOUNT_FSTAB] = {"mount.fstab", PF_INTERNAL}, [IP_STOP_TIMEOUT] = {"stop.timeout", PF_INTERNAL | PF_INT}, [IP_VNET_INTERFACE] = {"vnet.interface", PF_INTERNAL}, diff --git a/usr.sbin/jail/jail.8 b/usr.sbin/jail/jail.8 index d580c2553dbf..bc5886a5a01f 100644 --- a/usr.sbin/jail/jail.8 +++ b/usr.sbin/jail/jail.8 @@ -25,7 +25,7 @@ .\" .\" $FreeBSD$ .\" -.Dd January 28, 2015 +.Dd February 6, 2015 .Dt JAIL 8 .Os .Sh NAME @@ -753,6 +753,12 @@ Mount a filesystem on the chrooted .Pa /dev/fd directory. +.It Va mount.procfs +Mount a +.Xr procfs 5 +filesystem on the chrooted +.Pa /proc +directory. .It Va allow.dying Allow making changes to a .Va dying @@ -1207,6 +1213,7 @@ environment of the first jail. .Xr jls 8 , .Xr mount 8 , .Xr named 8 , +.Xr procfs 5 , .Xr reboot 8 , .Xr rpcbind 8 , .Xr sendmail 8 , diff --git a/usr.sbin/jail/jail.c b/usr.sbin/jail/jail.c index b8f57793d868..e42afa41f875 100644 --- a/usr.sbin/jail/jail.c +++ b/usr.sbin/jail/jail.c @@ -93,6 +93,7 @@ static const enum intparam startcommands[] = { IP__MOUNT_FROM_FSTAB, IP_MOUNT_DEVFS, IP_MOUNT_FDESCFS, + IP_MOUNT_PROCFS, IP_EXEC_PRESTART, IP__OP, IP_VNET_INTERFACE, @@ -109,6 +110,7 @@ static const enum intparam stopcommands[] = { IP_STOP_TIMEOUT, IP__OP, IP_EXEC_POSTSTOP, + IP_MOUNT_PROCFS, IP_MOUNT_FDESCFS, IP_MOUNT_DEVFS, IP__MOUNT_FROM_FSTAB, diff --git a/usr.sbin/jail/jailp.h b/usr.sbin/jail/jailp.h index 3f893920ab21..bfefca56c10b 100644 --- a/usr.sbin/jail/jailp.h +++ b/usr.sbin/jail/jailp.h @@ -96,6 +96,7 @@ enum intparam { IP_MOUNT, /* Mount points in fstab(5) form */ IP_MOUNT_DEVFS, /* Mount /dev under prison root */ IP_MOUNT_FDESCFS, /* Mount /dev/fd under prison root */ + IP_MOUNT_PROCFS, /* Mount /proc under prison root */ IP_MOUNT_FSTAB, /* A standard fstab(5) file */ IP_STOP_TIMEOUT, /* Time to wait after sending SIGTERM */ IP_VNET_INTERFACE, /* Assign interface(s) to vnet jail */ From f418f79ce29992c6d572b3148a46c867e014044f Mon Sep 17 00:00:00 2001 From: John Baldwin Date: Fri, 6 Feb 2015 18:19:59 +0000 Subject: [PATCH 20/36] Revert the IPI startup sequence to match what is described in the Intel Multiprocessor Specification v1.4. The Intel SDM claims that the INIT IPIs here are invalid, but other systems follow the MP spec instead. While here, fix the IPI wait routine to accept a timeout in microseconds instead of a raw spin count, and don't spin forever during AP startup. Instead, panic if a STARTUP IPI is not delivered after 20 us. PR: 196542 Differential Revision: https://reviews.freebsd.org/D1719 MFC after: 2 weeks --- sys/amd64/amd64/mp_machdep.c | 30 ++++++++++++++++++++++++------ sys/i386/i386/mp_machdep.c | 30 ++++++++++++++++++++++++------ sys/x86/x86/local_apic.c | 28 ++++++++++++++-------------- 3 files changed, 62 insertions(+), 26 deletions(-) diff --git a/sys/amd64/amd64/mp_machdep.c b/sys/amd64/amd64/mp_machdep.c index 3184f1325374..91b5c9f002e3 100644 --- a/sys/amd64/amd64/mp_machdep.c +++ b/sys/amd64/amd64/mp_machdep.c @@ -1064,15 +1064,28 @@ void ipi_startup(int apic_id, int vector) { + /* + * This attempts to follow the algorithm described in the + * Intel Multiprocessor Specification v1.4 in section B.4. + * For each IPI, we allow the local APIC ~20us to deliver the + * IPI. If that times out, we panic. + */ + /* * first we do an INIT IPI: this INIT IPI might be run, resetting * and running the target CPU. OR this INIT IPI might be latched (P5 * bug), CPU waiting for STARTUP IPI. OR this INIT IPI might be * ignored. */ - lapic_ipi_raw(APIC_DEST_DESTFLD | APIC_TRIGMOD_EDGE | + lapic_ipi_raw(APIC_DEST_DESTFLD | APIC_TRIGMOD_LEVEL | APIC_LEVEL_ASSERT | APIC_DESTMODE_PHY | APIC_DELMODE_INIT, apic_id); - lapic_ipi_wait(-1); + lapic_ipi_wait(20); + + /* Explicitly deassert the INIT IPI. */ + lapic_ipi_raw(APIC_DEST_DESTFLD | APIC_TRIGMOD_LEVEL | + APIC_LEVEL_DEASSERT | APIC_DESTMODE_PHY | APIC_DELMODE_INIT, + apic_id); + DELAY(10000); /* wait ~10mS */ /* @@ -1084,9 +1097,11 @@ ipi_startup(int apic_id, int vector) * will run. */ lapic_ipi_raw(APIC_DEST_DESTFLD | APIC_TRIGMOD_EDGE | - APIC_LEVEL_DEASSERT | APIC_DESTMODE_PHY | APIC_DELMODE_STARTUP | + APIC_LEVEL_ASSERT | APIC_DESTMODE_PHY | APIC_DELMODE_STARTUP | vector, apic_id); - lapic_ipi_wait(-1); + if (!lapic_ipi_wait(20)) + panic("Failed to deliver first STARTUP IPI to APIC %d", + apic_id); DELAY(200); /* wait ~200uS */ /* @@ -1096,9 +1111,12 @@ ipi_startup(int apic_id, int vector) * recognized after hardware RESET or INIT IPI. */ lapic_ipi_raw(APIC_DEST_DESTFLD | APIC_TRIGMOD_EDGE | - APIC_LEVEL_DEASSERT | APIC_DESTMODE_PHY | APIC_DELMODE_STARTUP | + APIC_LEVEL_ASSERT | APIC_DESTMODE_PHY | APIC_DELMODE_STARTUP | vector, apic_id); - lapic_ipi_wait(-1); + if (!lapic_ipi_wait(20)) + panic("Failed to deliver second STARTUP IPI to APIC %d", + apic_id); + DELAY(200); /* wait ~200uS */ } diff --git a/sys/i386/i386/mp_machdep.c b/sys/i386/i386/mp_machdep.c index 288be908d1b9..72d3fe94d5dc 100644 --- a/sys/i386/i386/mp_machdep.c +++ b/sys/i386/i386/mp_machdep.c @@ -1137,15 +1137,28 @@ void ipi_startup(int apic_id, int vector) { + /* + * This attempts to follow the algorithm described in the + * Intel Multiprocessor Specification v1.4 in section B.4. + * For each IPI, we allow the local APIC ~20us to deliver the + * IPI. If that times out, we panic. + */ + /* * first we do an INIT IPI: this INIT IPI might be run, resetting * and running the target CPU. OR this INIT IPI might be latched (P5 * bug), CPU waiting for STARTUP IPI. OR this INIT IPI might be * ignored. */ - lapic_ipi_raw(APIC_DEST_DESTFLD | APIC_TRIGMOD_EDGE | + lapic_ipi_raw(APIC_DEST_DESTFLD | APIC_TRIGMOD_LEVEL | APIC_LEVEL_ASSERT | APIC_DESTMODE_PHY | APIC_DELMODE_INIT, apic_id); - lapic_ipi_wait(-1); + lapic_ipi_wait(20); + + /* Explicitly deassert the INIT IPI. */ + lapic_ipi_raw(APIC_DEST_DESTFLD | APIC_TRIGMOD_LEVEL | + APIC_LEVEL_DEASSERT | APIC_DESTMODE_PHY | APIC_DELMODE_INIT, + apic_id); + DELAY(10000); /* wait ~10mS */ /* @@ -1157,9 +1170,11 @@ ipi_startup(int apic_id, int vector) * will run. */ lapic_ipi_raw(APIC_DEST_DESTFLD | APIC_TRIGMOD_EDGE | - APIC_LEVEL_DEASSERT | APIC_DESTMODE_PHY | APIC_DELMODE_STARTUP | + APIC_LEVEL_ASSERT | APIC_DESTMODE_PHY | APIC_DELMODE_STARTUP | vector, apic_id); - lapic_ipi_wait(-1); + if (!lapic_ipi_wait(20)) + panic("Failed to deliver first STARTUP IPI to APIC %d", + apic_id); DELAY(200); /* wait ~200uS */ /* @@ -1169,9 +1184,12 @@ ipi_startup(int apic_id, int vector) * recognized after hardware RESET or INIT IPI. */ lapic_ipi_raw(APIC_DEST_DESTFLD | APIC_TRIGMOD_EDGE | - APIC_LEVEL_DEASSERT | APIC_DESTMODE_PHY | APIC_DELMODE_STARTUP | + APIC_LEVEL_ASSERT | APIC_DESTMODE_PHY | APIC_DELMODE_STARTUP | vector, apic_id); - lapic_ipi_wait(-1); + if (!lapic_ipi_wait(20)) + panic("Failed to deliver second STARTUP IPI to APIC %d", + apic_id); + DELAY(200); /* wait ~200uS */ } diff --git a/sys/x86/x86/local_apic.c b/sys/x86/x86/local_apic.c index e3228ce34952..080822b29fd4 100644 --- a/sys/x86/x86/local_apic.c +++ b/sys/x86/x86/local_apic.c @@ -1452,22 +1452,22 @@ SYSINIT(apic_setup_io, SI_SUB_INTR, SI_ORDER_THIRD, apic_setup_io, NULL); static int native_lapic_ipi_wait(int delay) { - int x, incr; + int x; /* - * Wait delay loops for IPI to be sent. This is highly bogus - * since this is sensitive to CPU clock speed. If delay is + * Wait delay microseconds for IPI to be sent. If delay is * -1, we wait forever. */ if (delay == -1) { - incr = 0; - delay = 1; - } else - incr = 1; - for (x = 0; x < delay; x += incr) { + while ((lapic->icr_lo & APIC_DELSTAT_MASK) != APIC_DELSTAT_IDLE) + ia32_pause(); + return (1); + } + + for (x = 0; x < delay; x += 5) { if ((lapic->icr_lo & APIC_DELSTAT_MASK) == APIC_DELSTAT_IDLE) return (1); - ia32_pause(); + DELAY(5); } return (0); } @@ -1501,9 +1501,9 @@ native_lapic_ipi_raw(register_t icrlo, u_int dest) intr_restore(saveintr); } -#define BEFORE_SPIN 1000000 +#define BEFORE_SPIN 50000 #ifdef DETECT_DEADLOCK -#define AFTER_SPIN 1000 +#define AFTER_SPIN 50 #endif static void @@ -1514,7 +1514,7 @@ native_lapic_ipi_vectored(u_int vector, int dest) KASSERT((vector & ~APIC_VECTOR_MASK) == 0, ("%s: invalid vector %d", __func__, vector)); - icrlo = APIC_DESTMODE_PHY | APIC_TRIGMOD_EDGE; + icrlo = APIC_DESTMODE_PHY | APIC_TRIGMOD_EDGE | APIC_LEVEL_ASSERT; /* * IPI_STOP_HARD is just a "fake" vector used to send a NMI. @@ -1522,9 +1522,9 @@ native_lapic_ipi_vectored(u_int vector, int dest) * the vector. */ if (vector == IPI_STOP_HARD) - icrlo |= APIC_DELMODE_NMI | APIC_LEVEL_ASSERT; + icrlo |= APIC_DELMODE_NMI; else - icrlo |= vector | APIC_DELMODE_FIXED | APIC_LEVEL_DEASSERT; + icrlo |= vector | APIC_DELMODE_FIXED; destfield = 0; switch (dest) { case APIC_IPI_DEST_SELF: From 330c544318ac2cc80dcadfcee93a18a48e7bf812 Mon Sep 17 00:00:00 2001 From: John Baldwin Date: Fri, 6 Feb 2015 19:41:23 +0000 Subject: [PATCH 21/36] Change ktrdump to use the more standard -M/-N flags to specify the path to a crash dump and kernel, respectively. The existing -m/-e flags are still supported for backwards compatiblity but are no longer documented. Requested by: np MFC after: 2 weeks --- usr.bin/ktrdump/ktrdump.8 | 12 ++++++------ usr.bin/ktrdump/ktrdump.c | 18 ++++++++++-------- 2 files changed, 16 insertions(+), 14 deletions(-) diff --git a/usr.bin/ktrdump/ktrdump.8 b/usr.bin/ktrdump/ktrdump.8 index 697e418479fb..8dade5598ea2 100644 --- a/usr.bin/ktrdump/ktrdump.8 +++ b/usr.bin/ktrdump/ktrdump.8 @@ -25,7 +25,7 @@ .\" .\" $FreeBSD$ .\" -.Dd March 8, 2005 +.Dd February 6, 2015 .Dt KTRDUMP 8 .Os .Sh NAME @@ -34,9 +34,9 @@ .Sh SYNOPSIS .Nm .Op Fl cfqrtH -.Op Fl e Ar execfile .Op Fl i Ar ktrfile -.Op Fl m Ar corefile +.Op Fl M Ar core +.Op Fl N Ar system .Op Fl o Ar outfile .Sh DESCRIPTION The @@ -44,7 +44,7 @@ The utility is used to dump the contents of the kernel ktr trace buffer. .Pp The following options are available: -.Bl -tag -width ".Fl e Ar execfile" +.Bl -tag -width ".Fl i Ar ktrfile" .It Fl c Print the CPU number that each entry was logged from. .It Fl f @@ -61,11 +61,11 @@ Print the thread ID for each entry. File containing saved ktr trace events; for more information see the .Xr ktr 4 manual page. -.It Fl e Ar execfile +.It Fl N Ar system The kernel image to resolve symbols from. The default is the value returned via .Xr getbootfile 3 . -.It Fl m Ar corefile +.It Fl M Ar core The core file or memory image to read from. The default is .Pa /dev/mem . diff --git a/usr.bin/ktrdump/ktrdump.c b/usr.bin/ktrdump/ktrdump.c index 11e78e92bf8b..84ab3a837fba 100644 --- a/usr.bin/ktrdump/ktrdump.c +++ b/usr.bin/ktrdump/ktrdump.c @@ -46,7 +46,7 @@ __FBSDID("$FreeBSD$"); #define SBUFLEN 128 #define USAGE \ - "usage: ktrdump [-cfqrtH] [-e execfile] [-i ktrfile] [-m corefile] [-o outfile]\n" + "usage: ktrdump [-cfqrtH] [-i ktrfile] [-M core] [-N system] [-o outfile]\n" static void usage(void); @@ -59,9 +59,9 @@ static struct nlist nl[] = { }; static int cflag; -static int eflag; static int fflag; -static int mflag; +static int Mflag; +static int Nflag; static int qflag; static int rflag; static int tflag; @@ -103,16 +103,17 @@ main(int ac, char **av) * Parse commandline arguments. */ out = stdout; - while ((c = getopt(ac, av, "cfqrtHe:i:m:o:")) != -1) + while ((c = getopt(ac, av, "cfqrtHe:i:m:M:N:o:")) != -1) switch (c) { case 'c': cflag = 1; break; + case 'N': case 'e': if (strlcpy(execfile, optarg, sizeof(execfile)) >= sizeof(execfile)) errx(1, "%s: File name too long", optarg); - eflag = 1; + Nflag = 1; break; case 'f': fflag = 1; @@ -122,11 +123,12 @@ main(int ac, char **av) if ((in = open(optarg, O_RDONLY)) == -1) err(1, "%s", optarg); break; + case 'M': case 'm': if (strlcpy(corefile, optarg, sizeof(corefile)) >= sizeof(corefile)) errx(1, "%s: File name too long", optarg); - mflag = 1; + Mflag = 1; break; case 'o': if ((out = fopen(optarg, "w")) == NULL) @@ -157,8 +159,8 @@ main(int ac, char **av) * Open our execfile and corefile, resolve needed symbols and read in * the trace buffer. */ - if ((kd = kvm_openfiles(eflag ? execfile : NULL, - mflag ? corefile : NULL, NULL, O_RDONLY, errbuf)) == NULL) + if ((kd = kvm_openfiles(Nflag ? execfile : NULL, + Mflag ? corefile : NULL, NULL, O_RDONLY, errbuf)) == NULL) errx(1, "%s", errbuf); if (kvm_nlist(kd, nl) != 0 || kvm_read(kd, nl[0].n_value, &version, sizeof(version)) == -1) From e15131d39cd116cc8e3a280760a2ed8c680e6e66 Mon Sep 17 00:00:00 2001 From: Enji Cooper Date: Fri, 6 Feb 2015 20:46:46 +0000 Subject: [PATCH 22/36] Document WITNESS_COUNT and WITNESS_NO_VNODE Reviewed by: bcr, kib Differential Revision: D1789 MFC after: 3 days Sponsored by: EMC / Isilon Storage Division --- share/man/man4/witness.4 | 24 ++++++++++++++++++++++++ 1 file changed, 24 insertions(+) diff --git a/share/man/man4/witness.4 b/share/man/man4/witness.4 index ffd9f8fe0c14..e887c1d48b40 100644 --- a/share/man/man4/witness.4 +++ b/share/man/man4/witness.4 @@ -32,7 +32,9 @@ .Nd lock validation facility .Sh SYNOPSIS .Cd options WITNESS +.Cd options WITNESS_COUNT .Cd options WITNESS_KDB +.Cd options WITNESS_NO_VNODE .Cd options WITNESS_SKIPSPIN .Sh DESCRIPTION The @@ -56,6 +58,28 @@ does not recurse on a non-recursive lock, or attempt an upgrade on a shared lock held by another thread. If any of these checks fail, then the kernel will panic. .Pp +The +.Dv WITNESS_COUNT +kernel option controls the maximum number of +.Xr witness 4 +entries that are tracked in the kernel. +The maximum number of entries can be queried via the +.Va debug.witness.count +sysctl. +It can also be set from the +.Xr loader 8 +via the +.Va debug.witness.count +environment variable. +.Pp +The +.Dv WITNESS_NO_VNODE +kernel option tells +.Xr witness 4 +to ignore locking issues between +.Xr vnode 9 +objects. +.Pp The flag that controls whether or not the kernel debugger is entered when a lock order violation is detected can be set in a variety of ways. By default, the flag is off, but if the From 6b83df33ad281a4c366426773b627c9f611b99a8 Mon Sep 17 00:00:00 2001 From: Enji Cooper Date: Fri, 6 Feb 2015 20:52:01 +0000 Subject: [PATCH 23/36] Bump .Dd per r278329 --- share/man/man4/witness.4 | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/share/man/man4/witness.4 b/share/man/man4/witness.4 index e887c1d48b40..14f2646350a7 100644 --- a/share/man/man4/witness.4 +++ b/share/man/man4/witness.4 @@ -24,7 +24,7 @@ .\" .\" $FreeBSD$ .\" -.Dd May 30, 2012 +.Dd February 6, 2015 .Dt WITNESS 4 .Os .Sh NAME From 07b49a3eedf48582c20197a84133fabdc05fa0a0 Mon Sep 17 00:00:00 2001 From: Edward Tomasz Napierala Date: Fri, 6 Feb 2015 21:03:25 +0000 Subject: [PATCH 24/36] Make it possible to set (via ctl.conf(5)) and query (via ctladm islist -v) target iSCSI offload. Add mechanism to query maximum receive data segment size supported by chosen hardware offload module, and use it in ctld(8) to determine the value to advertise to the other side. MFC after: 1 month Sponsored by: The FreeBSD Foundation --- sys/cam/ctl/ctl_frontend_iscsi.c | 39 ++++++++++++++++++++++++++++---- sys/cam/ctl/ctl_ioctl.h | 16 +++++++++++-- usr.sbin/ctladm/ctladm.c | 5 ++++ usr.sbin/ctld/ctl.conf.5 | 2 ++ usr.sbin/ctld/ctld.c | 18 +++++++++++++++ usr.sbin/ctld/ctld.h | 6 +++++ usr.sbin/ctld/kernel.c | 37 ++++++++++++++++++++++++++++++ usr.sbin/ctld/login.c | 33 +++++++++++++++++++-------- usr.sbin/ctld/parse.y | 15 +++++++++++- usr.sbin/ctld/token.l | 1 + 10 files changed, 154 insertions(+), 18 deletions(-) diff --git a/sys/cam/ctl/ctl_frontend_iscsi.c b/sys/cam/ctl/ctl_frontend_iscsi.c index 817f9ffbdb96..4b8b4923d304 100644 --- a/sys/cam/ctl/ctl_frontend_iscsi.c +++ b/sys/cam/ctl/ctl_frontend_iscsi.c @@ -1222,7 +1222,7 @@ cfiscsi_session_unregister_initiator(struct cfiscsi_session *cs) } static struct cfiscsi_session * -cfiscsi_session_new(struct cfiscsi_softc *softc) +cfiscsi_session_new(struct cfiscsi_softc *softc, const char *offload) { struct cfiscsi_session *cs; int error; @@ -1242,7 +1242,11 @@ cfiscsi_session_new(struct cfiscsi_softc *softc) cv_init(&cs->cs_login_cv, "cfiscsi_login"); #endif - cs->cs_conn = icl_new_conn(NULL, "cfiscsi", &cs->cs_lock); + cs->cs_conn = icl_new_conn(offload, "cfiscsi", &cs->cs_lock); + if (cs->cs_conn == NULL) { + free(cs, M_CFISCSI); + return (NULL); + } cs->cs_conn->ic_receive = cfiscsi_receive_callback; cs->cs_conn->ic_error = cfiscsi_error_callback; cs->cs_conn->ic_prv0 = cs; @@ -1325,7 +1329,7 @@ cfiscsi_accept(struct socket *so, struct sockaddr *sa, int portal_id) { struct cfiscsi_session *cs; - cs = cfiscsi_session_new(&cfiscsi_softc); + cs = cfiscsi_session_new(&cfiscsi_softc, NULL); if (cs == NULL) { CFISCSI_WARN("failed to create session"); return; @@ -1469,7 +1473,7 @@ cfiscsi_ioctl_handoff(struct ctl_iscsi *ci) mtx_unlock(&cfiscsi_softc.lock); } else { #endif - cs = cfiscsi_session_new(softc); + cs = cfiscsi_session_new(softc, cihp->offload); if (cs == NULL) { ci->status = CTL_ISCSI_ERROR; snprintf(ci->error_str, sizeof(ci->error_str), @@ -1620,6 +1624,7 @@ cfiscsi_ioctl_list(struct ctl_iscsi *ci) "%zd" "%d" "%d" + "%s" "\n", cs->cs_id, cs->cs_initiator_name, cs->cs_initiator_addr, cs->cs_initiator_alias, @@ -1629,7 +1634,8 @@ cfiscsi_ioctl_list(struct ctl_iscsi *ci) cs->cs_conn->ic_data_crc32c ? "CRC32C" : "None", cs->cs_max_data_segment_length, cs->cs_immediate_data, - cs->cs_conn->ic_iser); + cs->cs_conn->ic_iser, + cs->cs_conn->ic_offload); if (error != 0) break; } @@ -1749,6 +1755,26 @@ cfiscsi_ioctl_logout(struct ctl_iscsi *ci) ci->status = CTL_ISCSI_OK; } +static void +cfiscsi_ioctl_limits(struct ctl_iscsi *ci) +{ + struct ctl_iscsi_limits_params *cilp; + int error; + + cilp = (struct ctl_iscsi_limits_params *)&(ci->data); + + error = icl_limits(cilp->offload, &cilp->data_segment_limit); + if (error != 0) { + ci->status = CTL_ISCSI_ERROR; + snprintf(ci->error_str, sizeof(ci->error_str), + "%s: icl_limits failed with error %d", + __func__, error); + return; + } + + ci->status = CTL_ISCSI_OK; +} + #ifdef ICL_KERNEL_PROXY static void cfiscsi_ioctl_listen(struct ctl_iscsi *ci) @@ -2176,6 +2202,9 @@ cfiscsi_ioctl(struct cdev *dev, case CTL_ISCSI_LOGOUT: cfiscsi_ioctl_logout(ci); break; + case CTL_ISCSI_LIMITS: + cfiscsi_ioctl_limits(ci); + break; #ifdef ICL_KERNEL_PROXY case CTL_ISCSI_LISTEN: cfiscsi_ioctl_listen(ci); diff --git a/sys/cam/ctl/ctl_ioctl.h b/sys/cam/ctl/ctl_ioctl.h index 532953fb7fab..c7a3c2938400 100644 --- a/sys/cam/ctl/ctl_ioctl.h +++ b/sys/cam/ctl/ctl_ioctl.h @@ -657,6 +657,7 @@ typedef enum { CTL_ISCSI_LIST, CTL_ISCSI_LOGOUT, CTL_ISCSI_TERMINATE, + CTL_ISCSI_LIMITS, #if defined(ICL_KERNEL_PROXY) || 1 /* * We actually need those in all cases, but leave the ICL_KERNEL_PROXY, @@ -677,6 +678,7 @@ typedef enum { #define CTL_ISCSI_NAME_LEN 224 /* 223 bytes, by RFC 3720, + '\0' */ #define CTL_ISCSI_ADDR_LEN 47 /* INET6_ADDRSTRLEN + '\0' */ #define CTL_ISCSI_ALIAS_LEN 128 /* Arbitrary. */ +#define CTL_ISCSI_OFFLOAD_LEN 8 /* Arbitrary. */ struct ctl_iscsi_handoff_params { char initiator_name[CTL_ISCSI_NAME_LEN]; @@ -698,11 +700,12 @@ struct ctl_iscsi_handoff_params { uint32_t max_burst_length; uint32_t first_burst_length; uint32_t immediate_data; + char offload[CTL_ISCSI_OFFLOAD_LEN]; #ifdef ICL_KERNEL_PROXY int connection_id; - int spare[3]; + int spare[1]; #else - int spare[4]; + int spare[2]; #endif }; @@ -733,6 +736,14 @@ struct ctl_iscsi_terminate_params { int spare[4]; }; +struct ctl_iscsi_limits_params { + char offload[CTL_ISCSI_OFFLOAD_LEN]; + /* passed to kernel */ + size_t data_segment_limit; + /* passed to userland */ + int spare[4]; +}; + #ifdef ICL_KERNEL_PROXY struct ctl_iscsi_listen_params { int iser; @@ -780,6 +791,7 @@ union ctl_iscsi_data { struct ctl_iscsi_list_params list; struct ctl_iscsi_logout_params logout; struct ctl_iscsi_terminate_params terminate; + struct ctl_iscsi_limits_params limits; #ifdef ICL_KERNEL_PROXY struct ctl_iscsi_listen_params listen; struct ctl_iscsi_accept_params accept; diff --git a/usr.sbin/ctladm/ctladm.c b/usr.sbin/ctladm/ctladm.c index 03c751b21f31..aefba042aa54 100644 --- a/usr.sbin/ctladm/ctladm.c +++ b/usr.sbin/ctladm/ctladm.c @@ -3439,6 +3439,7 @@ struct cctl_islist_conn { char *header_digest; char *data_digest; char *max_data_segment_length;; + char *offload;; int immediate_data; int iser; STAILQ_ENTRY(cctl_islist_conn) links; @@ -3552,6 +3553,9 @@ cctl_islist_end_element(void *user_data, const char *name) } else if (strcmp(name, "max_data_segment_length") == 0) { cur_conn->max_data_segment_length = str; str = NULL; + } else if (strcmp(name, "offload") == 0) { + cur_conn->offload = str; + str = NULL; } else if (strcmp(name, "immediate_data") == 0) { cur_conn->immediate_data = atoi(str); } else if (strcmp(name, "iser") == 0) { @@ -3672,6 +3676,7 @@ cctl_islist(int fd, int argc, char **argv, char *combinedopt) printf("DataSegmentLen: %s\n", conn->max_data_segment_length); printf("ImmediateData: %s\n", conn->immediate_data ? "Yes" : "No"); printf("iSER (RDMA): %s\n", conn->iser ? "Yes" : "No"); + printf("Offload driver: %s\n", conn->offload); printf("\n"); } } else { diff --git a/usr.sbin/ctld/ctl.conf.5 b/usr.sbin/ctld/ctl.conf.5 index fa053b0f20cf..404699829920 100644 --- a/usr.sbin/ctld/ctl.conf.5 +++ b/usr.sbin/ctld/ctl.conf.5 @@ -310,6 +310,8 @@ This clause is mutually exclusive with .Sy auth-group ; one cannot use both in a single target. +.It Ic offload Ar driver +Define iSCSI hardware offload driver to use for this target. .It Ic portal-group Ar name Op Ar agname Assign a previously defined portal group to the target. The default portal group is diff --git a/usr.sbin/ctld/ctld.c b/usr.sbin/ctld/ctld.c index 513e073630b1..dd864b95d286 100644 --- a/usr.sbin/ctld/ctld.c +++ b/usr.sbin/ctld/ctld.c @@ -1272,6 +1272,22 @@ target_set_redirection(struct target *target, const char *addr) return (0); } +int +target_set_offload(struct target *target, const char *offload) +{ + + if (target->t_offload != NULL) { + log_warnx("cannot set offload to \"%s\" for " + "target \"%s\"; already defined", + offload, target->t_name); + return (1); + } + + target->t_offload = checked_strdup(offload); + + return (0); +} + struct lun * lun_new(struct conf *conf, const char *name) { @@ -1514,6 +1530,8 @@ conf_print(struct conf *conf) fprintf(stderr, "target %s {\n", targ->t_name); if (targ->t_alias != NULL) fprintf(stderr, "\t alias %s\n", targ->t_alias); + if (targ->t_offload != NULL) + fprintf(stderr, "\t offload %s\n", targ->t_offload); fprintf(stderr, "}\n"); } } diff --git a/usr.sbin/ctld/ctld.h b/usr.sbin/ctld/ctld.h index e213e0bcbb82..395b0144ae55 100644 --- a/usr.sbin/ctld/ctld.h +++ b/usr.sbin/ctld/ctld.h @@ -169,6 +169,7 @@ struct target { TAILQ_HEAD(, port) t_ports; char *t_name; char *t_alias; + char *t_offload; char *t_redirection; }; @@ -223,6 +224,7 @@ struct connection { struct sockaddr_storage conn_initiator_sa; uint32_t conn_cmdsn; uint32_t conn_statsn; + size_t conn_data_segment_limit; size_t conn_max_data_segment_length; size_t conn_max_burst_length; int conn_immediate_data; @@ -344,6 +346,8 @@ struct target *target_find(struct conf *conf, const char *name); int target_set_redirection(struct target *target, const char *addr); +int target_set_offload(struct target *target, + const char *offload); struct lun *lun_new(struct conf *conf, const char *name); void lun_delete(struct lun *lun); @@ -370,6 +374,8 @@ int kernel_lun_add(struct lun *lun); int kernel_lun_resize(struct lun *lun); int kernel_lun_remove(struct lun *lun); void kernel_handoff(struct connection *conn); +void kernel_limits(const char *offload, + size_t *max_data_segment_length); int kernel_port_add(struct port *port); int kernel_port_update(struct port *port); int kernel_port_remove(struct port *port); diff --git a/usr.sbin/ctld/kernel.c b/usr.sbin/ctld/kernel.c index f36bdcb77f73..47dc56aa3be3 100644 --- a/usr.sbin/ctld/kernel.c +++ b/usr.sbin/ctld/kernel.c @@ -799,6 +799,10 @@ kernel_handoff(struct connection *conn) sizeof(req.data.handoff.initiator_isid)); strlcpy(req.data.handoff.target_name, conn->conn_target->t_name, sizeof(req.data.handoff.target_name)); + if (conn->conn_target->t_offload != NULL) { + strlcpy(req.data.handoff.offload, + conn->conn_target->t_offload, sizeof(req.data.handoff.offload)); + } #ifdef ICL_KERNEL_PROXY if (proxy_mode) req.data.handoff.connection_id = conn->conn_socket; @@ -831,6 +835,39 @@ kernel_handoff(struct connection *conn) } } +void +kernel_limits(const char *offload, size_t *max_data_segment_length) +{ + struct ctl_iscsi req; + + bzero(&req, sizeof(req)); + + req.type = CTL_ISCSI_LIMITS; + if (offload != NULL) { + strlcpy(req.data.limits.offload, offload, + sizeof(req.data.limits.offload)); + } + + if (ioctl(ctl_fd, CTL_ISCSI, &req) == -1) { + log_err(1, "error issuing CTL_ISCSI ioctl; " + "dropping connection"); + } + + if (req.status != CTL_ISCSI_OK) { + log_errx(1, "error returned from CTL iSCSI limits request: " + "%s; dropping connection", req.error_str); + } + + *max_data_segment_length = req.data.limits.data_segment_limit; + if (offload != NULL) { + log_debugx("MaxRecvDataSegment kernel limit for offload " + "\"%s\" is %zd", offload, *max_data_segment_length); + } else { + log_debugx("MaxRecvDataSegment kernel limit is %zd", + *max_data_segment_length); + } +} + int kernel_port_add(struct port *port) { diff --git a/usr.sbin/ctld/login.c b/usr.sbin/ctld/login.c index 865a19a73ab0..11d97cfae793 100644 --- a/usr.sbin/ctld/login.c +++ b/usr.sbin/ctld/login.c @@ -453,7 +453,8 @@ static void login_negotiate_key(struct pdu *request, const char *name, const char *value, bool skipped_security, struct keys *response_keys) { - int which, tmp; + int which; + size_t tmp; struct connection *conn; conn = request->pdu_connection; @@ -552,13 +553,13 @@ login_negotiate_key(struct pdu *request, const char *name, log_errx(1, "received invalid " "MaxRecvDataSegmentLength"); } - if (tmp > MAX_DATA_SEGMENT_LENGTH) { + if (tmp > conn->conn_data_segment_limit) { log_debugx("capping MaxRecvDataSegmentLength " - "from %d to %d", tmp, MAX_DATA_SEGMENT_LENGTH); - tmp = MAX_DATA_SEGMENT_LENGTH; + "from %zd to %zd", tmp, conn->conn_data_segment_limit); + tmp = conn->conn_data_segment_limit; } conn->conn_max_data_segment_length = tmp; - keys_add_int(response_keys, name, MAX_DATA_SEGMENT_LENGTH); + keys_add_int(response_keys, name, tmp); } else if (strcmp(name, "MaxBurstLength") == 0) { tmp = strtoul(value, NULL, 10); if (tmp <= 0) { @@ -566,7 +567,7 @@ login_negotiate_key(struct pdu *request, const char *name, log_errx(1, "received invalid MaxBurstLength"); } if (tmp > MAX_BURST_LENGTH) { - log_debugx("capping MaxBurstLength from %d to %d", + log_debugx("capping MaxBurstLength from %zd to %d", tmp, MAX_BURST_LENGTH); tmp = MAX_BURST_LENGTH; } @@ -579,10 +580,10 @@ login_negotiate_key(struct pdu *request, const char *name, log_errx(1, "received invalid " "FirstBurstLength"); } - if (tmp > MAX_DATA_SEGMENT_LENGTH) { - log_debugx("capping FirstBurstLength from %d to %d", - tmp, MAX_DATA_SEGMENT_LENGTH); - tmp = MAX_DATA_SEGMENT_LENGTH; + if (tmp > conn->conn_data_segment_limit) { + log_debugx("capping FirstBurstLength from %zd to %zd", + tmp, conn->conn_data_segment_limit); + tmp = conn->conn_data_segment_limit; } /* * We don't pass the value to the kernel; it only enforces @@ -680,6 +681,18 @@ login_negotiate(struct connection *conn, struct pdu *request) int i; bool redirected, skipped_security; + if (conn->conn_session_type == CONN_SESSION_TYPE_NORMAL) { + /* + * Query the kernel for MaxDataSegmentLength it can handle. + * In case of offload, it depends on hardware capabilities. + */ + assert(conn->conn_target != NULL); + kernel_limits(conn->conn_target->t_offload, + &conn->conn_data_segment_limit); + } else { + conn->conn_data_segment_limit = MAX_DATA_SEGMENT_LENGTH; + } + if (request == NULL) { log_debugx("beginning operational parameter negotiation; " "waiting for Login PDU"); diff --git a/usr.sbin/ctld/parse.y b/usr.sbin/ctld/parse.y index d0b2c514ca0b..5eaffe4e324a 100644 --- a/usr.sbin/ctld/parse.y +++ b/usr.sbin/ctld/parse.y @@ -60,7 +60,7 @@ extern void yyrestart(FILE *); %token ALIAS AUTH_GROUP AUTH_TYPE BACKEND BLOCKSIZE CHAP CHAP_MUTUAL %token CLOSING_BRACKET DEBUG DEVICE_ID DISCOVERY_AUTH_GROUP DISCOVERY_FILTER %token INITIATOR_NAME INITIATOR_PORTAL ISNS_SERVER ISNS_PERIOD ISNS_TIMEOUT -%token LISTEN LISTEN_ISER LUN MAXPROC OPENING_BRACKET OPTION +%token LISTEN LISTEN_ISER LUN MAXPROC OFFLOAD OPENING_BRACKET OPTION %token PATH PIDFILE PORTAL_GROUP REDIRECT SEMICOLON SERIAL SIZE STR %token TARGET TIMEOUT @@ -463,6 +463,8 @@ target_entry: | target_initiator_portal | + target_offload + | target_portal_group | target_redirect @@ -652,6 +654,17 @@ target_initiator_portal: INITIATOR_PORTAL STR } ; +target_offload: OFFLOAD STR + { + int error; + + error = target_set_offload(target, $2); + free($2); + if (error != 0) + return (1); + } + ; + target_portal_group: PORTAL_GROUP STR STR { struct portal_group *tpg; diff --git a/usr.sbin/ctld/token.l b/usr.sbin/ctld/token.l index d4bf823b8b08..fd274983f447 100644 --- a/usr.sbin/ctld/token.l +++ b/usr.sbin/ctld/token.l @@ -65,6 +65,7 @@ listen { return LISTEN; } listen-iser { return LISTEN_ISER; } lun { return LUN; } maxproc { return MAXPROC; } +offload { return OFFLOAD; } option { return OPTION; } path { return PATH; } pidfile { return PIDFILE; } From d33946470c0d937d9c568f997e2b7006cdbbf23c Mon Sep 17 00:00:00 2001 From: Devin Teske Date: Fri, 6 Feb 2015 23:19:17 +0000 Subject: [PATCH 25/36] Revert SVN r277693. Discussed on: src-committers Approved by: core (emaste) --- sys/boot/forth/beastie.4th | 11 ++++++----- sys/boot/forth/brand.4th | 3 ++- 2 files changed, 8 insertions(+), 6 deletions(-) diff --git a/sys/boot/forth/beastie.4th b/sys/boot/forth/beastie.4th index 6512d739c271..8d2424408bbc 100644 --- a/sys/boot/forth/beastie.4th +++ b/sys/boot/forth/beastie.4th @@ -89,7 +89,7 @@ variable logoY 0 25 at-xy ; -: fbsdbw-logo ( x y -- ) \ "FreeBSD" logo in B/W (12 rows x 21 columns) +: fbsdbw-logo ( x y -- ) \ "FreeBSD" logo in B/W (13 rows x 21 columns) \ We used to use the beastie himself as our default... until the \ eventual complaint derided his reign of the advanced boot-menu. @@ -106,16 +106,17 @@ variable logoY 5 + swap 6 + swap 2dup at-xy ." ______" 1+ - 2dup at-xy ." | ____|" 1+ - 2dup at-xy ." | |__ _ __ ___ ___ " 1+ - 2dup at-xy ." | __|| '__/ _ \/ _ \" 1+ - 2dup at-xy ." | | | | | __/ __/" 1+ + 2dup at-xy ." | ____| __ ___ ___ " 1+ + 2dup at-xy ." | |__ | '__/ _ \/ _ \" 1+ + 2dup at-xy ." | __|| | | __/ __/" 1+ + 2dup at-xy ." | | | | | | |" 1+ 2dup at-xy ." |_| |_| \___|\___|" 1+ 2dup at-xy ." ____ _____ _____" 1+ 2dup at-xy ." | _ \ / ____| __ \" 1+ 2dup at-xy ." | |_) | (___ | | | |" 1+ 2dup at-xy ." | _ < \___ \| | | |" 1+ 2dup at-xy ." | |_) |____) | |__| |" 1+ + 2dup at-xy ." | | | |" 1+ at-xy ." |____/|_____/|_____/" \ Put the cursor back at the bottom diff --git a/sys/boot/forth/brand.4th b/sys/boot/forth/brand.4th index 3dda97cc3e2f..28d3c5c1d26f 100644 --- a/sys/boot/forth/brand.4th +++ b/sys/boot/forth/brand.4th @@ -33,13 +33,14 @@ variable brandY 2 brandX ! 1 brandY ! -: fbsd-logo ( x y -- ) \ "FreeBSD" [wide] logo in B/W (6 rows x 42 columns) +: fbsd-logo ( x y -- ) \ "FreeBSD" [wide] logo in B/W (7 rows x 42 columns) 2dup at-xy ." ______ ____ _____ _____ " 1+ 2dup at-xy ." | ____| | _ \ / ____| __ \ " 1+ 2dup at-xy ." | |___ _ __ ___ ___ | |_) | (___ | | | |" 1+ 2dup at-xy ." | ___| '__/ _ \/ _ \| _ < \___ \| | | |" 1+ 2dup at-xy ." | | | | | __/ __/| |_) |____) | |__| |" 1+ + 2dup at-xy ." | | | | | | || | | |" 1+ at-xy ." |_| |_| \___|\___||____/|_____/|_____/ " \ Put the cursor back at the bottom From f1c3d09a423b89bb39e33a0a9dcdf78bda30c564 Mon Sep 17 00:00:00 2001 From: Enji Cooper Date: Fri, 6 Feb 2015 23:34:40 +0000 Subject: [PATCH 26/36] Unbreak the build (memchr is explicitly required by devctl(9) after r278320) Submitted by: Michael Butler Reported by: O. Hartmann --- sys/conf/files | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/sys/conf/files b/sys/conf/files index 97bbe5914762..e10fd5e44173 100644 --- a/sys/conf/files +++ b/sys/conf/files @@ -3193,7 +3193,7 @@ libkern/jenkins_hash.c standard libkern/murmur3_32.c standard libkern/mcount.c optional profiling-routine libkern/memcchr.c standard -libkern/memchr.c optional fdt | gdb +libkern/memchr.c standard libkern/memcmp.c standard libkern/memmem.c optional gdb libkern/qsort.c standard From 722d81b510094d25a1d02cd96adce5571036fd48 Mon Sep 17 00:00:00 2001 From: Brooks Davis Date: Fri, 6 Feb 2015 23:44:16 +0000 Subject: [PATCH 27/36] When upgrading, install the ELF runtime linkers before libraries. This is required to prevent problems with nss modules that use libthr when upgrading from releases prior to 10.1. PR: 197366 Sponsored by: DARPA, AFRL Differential Revision: D1790 Reviewed by: cperciva MFC after: 3 days --- usr.sbin/freebsd-update/freebsd-update.sh | 9 +++++++++ 1 file changed, 9 insertions(+) diff --git a/usr.sbin/freebsd-update/freebsd-update.sh b/usr.sbin/freebsd-update/freebsd-update.sh index 4979c0148257..3b784c810f7c 100644 --- a/usr.sbin/freebsd-update/freebsd-update.sh +++ b/usr.sbin/freebsd-update/freebsd-update.sh @@ -2828,18 +2828,27 @@ Kernel updates have been installed. Please reboot and run grep -E '^[^|]+\|d\|' > INDEX-NEW install_from_index INDEX-NEW || return 1 + # Install new runtime linker + grep -vE '^/boot/' $1/INDEX-NEW | + grep -vE '^[^|]+\|d\|' | + grep -E '^/libexec/ld-elf[^|]*\.so\.[0-9]+\|' > INDEX-NEW + install_from_index INDEX-NEW || return 1 + # Install new shared libraries next grep -vE '^/boot/' $1/INDEX-NEW | grep -vE '^[^|]+\|d\|' | + grep -vE '^/libexec/ld-elf[^|]*\.so\.[0-9]+\|' | grep -E '^[^|]*/lib/[^|]*\.so\.[0-9]+\|' > INDEX-NEW install_from_index INDEX-NEW || return 1 # Deal with everything else grep -vE '^/boot/' $1/INDEX-OLD | grep -vE '^[^|]+\|d\|' | + grep -vE '^/libexec/ld-elf[^|]*\.so\.[0-9]+\|' | grep -vE '^[^|]*/lib/[^|]*\.so\.[0-9]+\|' > INDEX-OLD grep -vE '^/boot/' $1/INDEX-NEW | grep -vE '^[^|]+\|d\|' | + grep -vE '^/libexec/ld-elf[^|]*\.so\.[0-9]+\|' | grep -vE '^[^|]*/lib/[^|]*\.so\.[0-9]+\|' > INDEX-NEW install_from_index INDEX-NEW || return 1 install_delete INDEX-OLD INDEX-NEW || return 1 From 4ef0c81f7dc4cf6bc47608941b3a3b8e5440dce9 Mon Sep 17 00:00:00 2001 From: Warner Losh Date: Sat, 7 Feb 2015 00:13:36 +0000 Subject: [PATCH 28/36] Create a module to install the Raspberry Pi dtb files. --- sys/modules/dtb/rpi/Makefile | 5 +++++ 1 file changed, 5 insertions(+) create mode 100644 sys/modules/dtb/rpi/Makefile diff --git a/sys/modules/dtb/rpi/Makefile b/sys/modules/dtb/rpi/Makefile new file mode 100644 index 000000000000..9ea76638bd52 --- /dev/null +++ b/sys/modules/dtb/rpi/Makefile @@ -0,0 +1,5 @@ +# $FreeBSD$ +# DTS files for the Raspberry Pi-B +DTS=rpi.dts + +.include From dc98c004640831c88d7d4c25966674ba226ccbb2 Mon Sep 17 00:00:00 2001 From: Steve Kargl Date: Sat, 7 Feb 2015 00:38:18 +0000 Subject: [PATCH 29/36] Truncate the exponent 'n' of type long to a domain contained within [INT_MIN, INT_MAX] where the magnitude of the lower and upper bounds are sufficiently large to span the range of scalbn[fl]. While here, remove the GNU style bug in the function declarations. Reviewed by: bde, pfg --- lib/msun/src/s_scalbln.c | 32 +++++++++++--------------------- 1 file changed, 11 insertions(+), 21 deletions(-) diff --git a/lib/msun/src/s_scalbln.c b/lib/msun/src/s_scalbln.c index dcf2c789ec32..5e4e42e9dcf0 100644 --- a/lib/msun/src/s_scalbln.c +++ b/lib/msun/src/s_scalbln.c @@ -27,38 +27,28 @@ #include __FBSDID("$FreeBSD$"); -#include #include -double -scalbln (double x, long n) -{ - int in; +#define NMAX 65536 +#define NMIN -65536 - in = (int)n; - if (in != n) - in = (n > 0) ? INT_MAX: INT_MIN; - return (scalbn(x, in)); +double +scalbln(double x, long n) +{ + + return (scalbn(x, (n > NMAX) ? NMAX : (n < NMIN) ? NMIN : (int)n)); } float -scalblnf (float x, long n) +scalblnf(float x, long n) { - int in; - in = (int)n; - if (in != n) - in = (n > 0) ? INT_MAX: INT_MIN; - return (scalbnf(x, in)); + return (scalbnf(x, (n > NMAX) ? NMAX : (n < NMIN) ? NMIN : (int)n)); } long double -scalblnl (long double x, long n) +scalblnl(long double x, long n) { - int in; - in = (int)n; - if (in != n) - in = (n > 0) ? INT_MAX: INT_MIN; - return (scalbnl(x, in)); + return (scalbnl(x, (n > NMAX) ? NMAX : (n < NMIN) ? NMIN : (int)n)); } From 854739a4aa2ce8628dfee131f9018a6604218ef3 Mon Sep 17 00:00:00 2001 From: Warner Losh Date: Sat, 7 Feb 2015 00:41:08 +0000 Subject: [PATCH 30/36] Pull in the rpi.dts -> rpi.dtb module (dtb/rpi) and have it install rpi.dtb in /boot/dtb by default. --- sys/arm/conf/RPI-B | 3 ++- sys/modules/Makefile | 2 ++ 2 files changed, 4 insertions(+), 1 deletion(-) diff --git a/sys/arm/conf/RPI-B b/sys/arm/conf/RPI-B index 0b886dd0582e..1c28f105a964 100644 --- a/sys/arm/conf/RPI-B +++ b/sys/arm/conf/RPI-B @@ -134,4 +134,5 @@ options FDT # Configure using FDT/DTB data # Note: DTB is normally loaded and modified by RPi boot loader, then # handed to kernel via U-Boot and ubldr. #options FDT_DTB_STATIC -makeoptions FDT_DTS_FILE=rpi.dts +#makeoptions FDT_DTS_FILE=rpi.dts +makeoptions MODULES_EXTRA=dtb/rpi diff --git a/sys/modules/Makefile b/sys/modules/Makefile index 7498dab0792a..7f917d6e5c6a 100644 --- a/sys/modules/Makefile +++ b/sys/modules/Makefile @@ -735,6 +735,8 @@ _zfs= zfs .endif +SUBDIR+=${MODULES_EXTRA} + .for reject in ${WITHOUT_MODULES} SUBDIR:= ${SUBDIR:N${reject}} .endfor From 939099221bfccf3667c622075888e27f8ba30b49 Mon Sep 17 00:00:00 2001 From: Oleksandr Tymoshenko Date: Sat, 7 Feb 2015 01:03:45 +0000 Subject: [PATCH 31/36] Make VCHI driver optional and add "device vchiq" to default RPI-B config --- sys/arm/broadcom/bcm2835/files.bcm2835 | 18 +++++++++--------- sys/arm/conf/RPI-B | 2 ++ 2 files changed, 11 insertions(+), 9 deletions(-) diff --git a/sys/arm/broadcom/bcm2835/files.bcm2835 b/sys/arm/broadcom/bcm2835/files.bcm2835 index 95bb9c519cf6..416fb4adb7e2 100644 --- a/sys/arm/broadcom/bcm2835/files.bcm2835 +++ b/sys/arm/broadcom/bcm2835/files.bcm2835 @@ -29,21 +29,21 @@ dev/mbox/mbox_if.m standard dev/ofw/ofw_cpu.c standard # VideoCore driver -contrib/vchiq/interface/compat/vchi_bsd.c standard \ +contrib/vchiq/interface/compat/vchi_bsd.c optional vchiq \ compile-with "${NORMAL_C} -DUSE_VCHIQ_ARM -D__VCCOREVER__=0x04000000 -I$S/contrib/vchiq" -contrib/vchiq/interface/vchiq_arm/vchiq_2835_arm.c standard \ +contrib/vchiq/interface/vchiq_arm/vchiq_2835_arm.c optional vchiq \ compile-with "${NORMAL_C} -Wno-unused -DUSE_VCHIQ_ARM -D__VCCOREVER__=0x04000000 -I$S/contrib/vchiq" -contrib/vchiq/interface/vchiq_arm/vchiq_arm.c standard \ +contrib/vchiq/interface/vchiq_arm/vchiq_arm.c optional vchiq \ compile-with "${NORMAL_C} -Wno-unused -DUSE_VCHIQ_ARM -D__VCCOREVER__=0x04000000 -I$S/contrib/vchiq" -contrib/vchiq/interface/vchiq_arm/vchiq_connected.c standard \ +contrib/vchiq/interface/vchiq_arm/vchiq_connected.c optional vchiq \ compile-with "${NORMAL_C} -DUSE_VCHIQ_ARM -D__VCCOREVER__=0x04000000 -I$S/contrib/vchiq" -contrib/vchiq/interface/vchiq_arm/vchiq_core.c standard \ +contrib/vchiq/interface/vchiq_arm/vchiq_core.c optional vchiq \ compile-with "${NORMAL_C} -DUSE_VCHIQ_ARM -D__VCCOREVER__=0x04000000 -I$S/contrib/vchiq" -contrib/vchiq/interface/vchiq_arm/vchiq_kern_lib.c standard \ +contrib/vchiq/interface/vchiq_arm/vchiq_kern_lib.c optional vchiq \ compile-with "${NORMAL_C} -DUSE_VCHIQ_ARM -D__VCCOREVER__=0x04000000 -I$S/contrib/vchiq" -contrib/vchiq/interface/vchiq_arm/vchiq_kmod.c standard \ +contrib/vchiq/interface/vchiq_arm/vchiq_kmod.c optional vchiq \ compile-with "${NORMAL_C} -DUSE_VCHIQ_ARM -D__VCCOREVER__=0x04000000 -I$S/contrib/vchiq" -contrib/vchiq/interface/vchiq_arm/vchiq_shim.c standard \ +contrib/vchiq/interface/vchiq_arm/vchiq_shim.c optional vchiq \ compile-with "${NORMAL_C} -DUSE_VCHIQ_ARM -D__VCCOREVER__=0x04000000 -I$S/contrib/vchiq" -contrib/vchiq/interface/vchiq_arm/vchiq_util.c standard \ +contrib/vchiq/interface/vchiq_arm/vchiq_util.c optional vchiq \ compile-with "${NORMAL_C} -DUSE_VCHIQ_ARM -D__VCCOREVER__=0x04000000 -I$S/contrib/vchiq" diff --git a/sys/arm/conf/RPI-B b/sys/arm/conf/RPI-B index 1c28f105a964..41566efecc6c 100644 --- a/sys/arm/conf/RPI-B +++ b/sys/arm/conf/RPI-B @@ -129,6 +129,8 @@ device smsc device spibus device bcm2835_spi +device vchiq + # Flattened Device Tree options FDT # Configure using FDT/DTB data # Note: DTB is normally loaded and modified by RPi boot loader, then From cb6c101a86f388c2c23a11cbd253c30b8baec3d8 Mon Sep 17 00:00:00 2001 From: Navdeep Parhar Date: Sat, 7 Feb 2015 01:50:32 +0000 Subject: [PATCH 32/36] cxgbe(4): fix a test made while enabling TOE. MFC after: 1 week --- sys/dev/cxgbe/t4_main.c | 7 ++++++- 1 file changed, 6 insertions(+), 1 deletion(-) diff --git a/sys/dev/cxgbe/t4_main.c b/sys/dev/cxgbe/t4_main.c index 7f59e840de27..e2f3c594df4b 100644 --- a/sys/dev/cxgbe/t4_main.c +++ b/sys/dev/cxgbe/t4_main.c @@ -8215,7 +8215,12 @@ toe_capability(struct port_info *pi, int enable) return (ENODEV); if (enable) { - if (!(sc->flags & FULL_INIT_DONE)) { + /* + * We need the port's queues around so that we're able to send + * and receive CPLs to/from the TOE even if the ifnet for this + * port has never been UP'd administratively. + */ + if (!(pi->flags & PORT_INIT_DONE)) { rc = cxgbe_init_synchronized(pi); if (rc) return (rc); From 3f920f3f44651ba63c96580fd9a6d390f2f2a477 Mon Sep 17 00:00:00 2001 From: Jamie Gritton Date: Sat, 7 Feb 2015 05:02:10 +0000 Subject: [PATCH 33/36] Revert the rc part of r278323 until I can figure out what Jenkins is doing. --- etc/rc.d/jail | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/etc/rc.d/jail b/etc/rc.d/jail index ea62f4839db4..393e35526574 100755 --- a/etc/rc.d/jail +++ b/etc/rc.d/jail @@ -233,7 +233,8 @@ parse_options() fi eval : \${jail_${_j}_procfs_enable:=${jail_procfs_enable:-NO}} if checkyesno jail_${_j}_procfs_enable; then - echo " mount.procfs;" + echo " mount += " \ + "\"procfs ${_rootdir%/}/proc procfs rw 0 0\";" fi eval : \${jail_${_j}_mount_enable:=${jail_mount_enable:-NO}} From 772400696c24f031c88cec16a8d636b19ed32c70 Mon Sep 17 00:00:00 2001 From: Dimitry Andric Date: Sat, 7 Feb 2015 12:20:33 +0000 Subject: [PATCH 34/36] Fix a number of -Wcast-qual warnings in ath's ar9300_attach.c, by making the ia_array field of struct ar9300_ini_array const, and removing the const-dropping casts. No functional change. Reviewed by: adrian MFC after: 3 days Differential Revision: https://reviews.freebsd.org/D1725 --- sys/contrib/dev/ath/ath_hal/ar9300/ar9300.h | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/sys/contrib/dev/ath/ath_hal/ar9300/ar9300.h b/sys/contrib/dev/ath/ath_hal/ar9300/ar9300.h index 30c55a077ffe..f16ef6b12fcb 100644 --- a/sys/contrib/dev/ath/ath_hal/ar9300/ar9300.h +++ b/sys/contrib/dev/ath/ath_hal/ar9300/ar9300.h @@ -317,12 +317,12 @@ typedef struct { /* Support for multiple INIs */ struct ar9300_ini_array { - u_int32_t *ia_array; + const u_int32_t *ia_array; u_int32_t ia_rows; u_int32_t ia_columns; }; #define INIT_INI_ARRAY(iniarray, array, rows, columns) do { \ - (iniarray)->ia_array = (u_int32_t *)(array); \ + (iniarray)->ia_array = (const u_int32_t *)(array); \ (iniarray)->ia_rows = (rows); \ (iniarray)->ia_columns = (columns); \ } while (0) From 12752a4a78d2f70401d720dee9463c3140ede1e0 Mon Sep 17 00:00:00 2001 From: Dimitry Andric Date: Sat, 7 Feb 2015 12:50:33 +0000 Subject: [PATCH 35/36] Pull in r224884 from upstream llvm trunk (by Keno Fischer): [FastIsel][X86] Fix invalid register replacement for bool args Summary: Consider the following IR: %3 = load i8* undef %4 = trunc i8 %3 to i1 %5 = call %jl_value_t.0* @foo(..., i1 %4, ...) ret %jl_value_t.0* %5 Bools (that are the result of direct truncs) are lowered as whatever the argument to the trunc was and a "and 1", causing the part of the MBB responsible for this argument to look something like this: %vreg8 = AND8ri %vreg7, 1, %EFLAGS; GR8:%vreg8,%vreg7 Later, when the load is lowered, it will insert %vreg15 = MOV8rm %vreg14, 1, %noreg, 0, %noreg; mem:LD1[undef] GR8:%vreg15 GR64:%vreg14 but remember to (at the end of isel) replace vreg7 by vreg15. Now for the bug. In fast isel lowering, we mistakenly mark vreg8 as the result of the load instead of the trunc. This adds a fixup to have vreg8 replaced by whatever the result of the load is as well, so we end up with %vreg15 = AND8ri %vreg15, 1, %EFLAGS; GR8:%vreg15 which is an SSA violation and causes problems later down the road. This fixes PR21557. Test Plan: Test test case from PR21557 is added to the test suite. Reviewers: ributzka Reviewed By: ributzka Subscribers: llvm-commits Differential Revision: http://reviews.llvm.org/D6245 This fixes a possible assertion failure when compiling toolbox.cxx from LibreOffice 4.3.5. Reported by: kwm --- contrib/llvm/lib/Target/X86/X86FastISel.cpp | 54 ++++++++++----------- 1 file changed, 27 insertions(+), 27 deletions(-) diff --git a/contrib/llvm/lib/Target/X86/X86FastISel.cpp b/contrib/llvm/lib/Target/X86/X86FastISel.cpp index ae3eea4943d7..14084c6013f3 100644 --- a/contrib/llvm/lib/Target/X86/X86FastISel.cpp +++ b/contrib/llvm/lib/Target/X86/X86FastISel.cpp @@ -2699,6 +2699,9 @@ bool X86FastISel::FastLowerCall(CallLoweringInfo &CLI) { TM.Options.GuaranteedTailCallOpt)) return false; + SmallVector OutVTs; + SmallVector ArgRegs; + // If this is a constant i1/i8/i16 argument, promote to i32 to avoid an extra // instruction. This is safe because it is common to all FastISel supported // calling conventions on x86. @@ -2716,28 +2719,34 @@ bool X86FastISel::FastLowerCall(CallLoweringInfo &CLI) { // Passing bools around ends up doing a trunc to i1 and passing it. // Codegen this as an argument + "and 1". - if (auto *TI = dyn_cast(Val)) { - if (TI->getType()->isIntegerTy(1) && CLI.CS && - (TI->getParent() == CLI.CS->getInstruction()->getParent()) && - TI->hasOneUse()) { - Val = cast(Val)->getOperand(0); - unsigned ResultReg = getRegForValue(Val); + MVT VT; + auto *TI = dyn_cast(Val); + unsigned ResultReg; + if (TI && TI->getType()->isIntegerTy(1) && CLI.CS && + (TI->getParent() == CLI.CS->getInstruction()->getParent()) && + TI->hasOneUse()) { + Value *PrevVal = TI->getOperand(0); + ResultReg = getRegForValue(PrevVal); - if (!ResultReg) - return false; + if (!ResultReg) + return false; - MVT ArgVT; - if (!isTypeLegal(Val->getType(), ArgVT)) - return false; + if (!isTypeLegal(PrevVal->getType(), VT)) + return false; - ResultReg = - FastEmit_ri(ArgVT, ArgVT, ISD::AND, ResultReg, Val->hasOneUse(), 1); + ResultReg = + FastEmit_ri(VT, VT, ISD::AND, ResultReg, hasTrivialKill(PrevVal), 1); - if (!ResultReg) - return false; - UpdateValueMap(Val, ResultReg); - } + if (!ResultReg) + return false; + } else { + if (!isTypeLegal(Val->getType(), VT)) + return false; + ResultReg = getRegForValue(Val); } + + ArgRegs.push_back(ResultReg); + OutVTs.push_back(VT); } // Analyze operands of the call, assigning locations to each operand. @@ -2749,13 +2758,6 @@ bool X86FastISel::FastLowerCall(CallLoweringInfo &CLI) { if (IsWin64) CCInfo.AllocateStack(32, 8); - SmallVector OutVTs; - for (auto *Val : OutVals) { - MVT VT; - if (!isTypeLegal(Val->getType(), VT)) - return false; - OutVTs.push_back(VT); - } CCInfo.AnalyzeCallOperands(OutVTs, OutFlags, CC_X86); // Get a count of how many bytes are to be pushed on the stack. @@ -2777,9 +2779,7 @@ bool X86FastISel::FastLowerCall(CallLoweringInfo &CLI) { if (ArgVT == MVT::x86mmx) return false; - unsigned ArgReg = getRegForValue(ArgVal); - if (!ArgReg) - return false; + unsigned ArgReg = ArgRegs[VA.getValNo()]; // Promote the value if needed. switch (VA.getLocInfo()) { From 6a0d02c731cd40fc4a716eb472e7297618fc77eb Mon Sep 17 00:00:00 2001 From: Dimitry Andric Date: Sat, 7 Feb 2015 12:52:34 +0000 Subject: [PATCH 36/36] Add llvm patch corresponding to r278349. --- ...-llvm-r224884-invalid-reg-replacement.diff | 164 ++++++++++++++++++ 1 file changed, 164 insertions(+) create mode 100644 contrib/llvm/patches/patch-32-llvm-r224884-invalid-reg-replacement.diff diff --git a/contrib/llvm/patches/patch-32-llvm-r224884-invalid-reg-replacement.diff b/contrib/llvm/patches/patch-32-llvm-r224884-invalid-reg-replacement.diff new file mode 100644 index 000000000000..dc39636201b2 --- /dev/null +++ b/contrib/llvm/patches/patch-32-llvm-r224884-invalid-reg-replacement.diff @@ -0,0 +1,164 @@ +Pull in r224884 from upstream llvm trunk (by Keno Fischer): + + [FastIsel][X86] Fix invalid register replacement for bool args + + Summary: + Consider the following IR: + + %3 = load i8* undef + %4 = trunc i8 %3 to i1 + %5 = call %jl_value_t.0* @foo(..., i1 %4, ...) + ret %jl_value_t.0* %5 + + Bools (that are the result of direct truncs) are lowered as whatever + the argument to the trunc was and a "and 1", causing the part of the + MBB responsible for this argument to look something like this: + + %vreg8 = AND8ri %vreg7, 1, %EFLAGS; GR8:%vreg8,%vreg7 + + Later, when the load is lowered, it will insert + + %vreg15 = MOV8rm %vreg14, 1, %noreg, 0, %noreg; mem:LD1[undef] GR8:%vreg15 GR64:%vreg14 + + but remember to (at the end of isel) replace vreg7 by vreg15. Now for + the bug. In fast isel lowering, we mistakenly mark vreg8 as the result + of the load instead of the trunc. This adds a fixup to have + vreg8 replaced by whatever the result of the load is as well, so + we end up with + + %vreg15 = AND8ri %vreg15, 1, %EFLAGS; GR8:%vreg15 + + which is an SSA violation and causes problems later down the road. + + This fixes PR21557. + + Test Plan: Test test case from PR21557 is added to the test suite. + + Reviewers: ributzka + + Reviewed By: ributzka + + Subscribers: llvm-commits + + Differential Revision: http://reviews.llvm.org/D6245 + +This fixes a possible assertion failure when compiling toolbox.cxx from +LibreOffice 4.3.5. + +Introduced here: http://svnweb.freebsd.org/changeset/base/278349 + +Index: lib/Target/X86/X86FastISel.cpp +=================================================================== +--- lib/Target/X86/X86FastISel.cpp ++++ lib/Target/X86/X86FastISel.cpp +@@ -2699,6 +2699,9 @@ bool X86FastISel::FastLowerCall(CallLoweringInfo & + TM.Options.GuaranteedTailCallOpt)) + return false; + ++ SmallVector OutVTs; ++ SmallVector ArgRegs; ++ + // If this is a constant i1/i8/i16 argument, promote to i32 to avoid an extra + // instruction. This is safe because it is common to all FastISel supported + // calling conventions on x86. +@@ -2716,28 +2719,34 @@ bool X86FastISel::FastLowerCall(CallLoweringInfo & + + // Passing bools around ends up doing a trunc to i1 and passing it. + // Codegen this as an argument + "and 1". +- if (auto *TI = dyn_cast(Val)) { +- if (TI->getType()->isIntegerTy(1) && CLI.CS && +- (TI->getParent() == CLI.CS->getInstruction()->getParent()) && +- TI->hasOneUse()) { +- Val = cast(Val)->getOperand(0); +- unsigned ResultReg = getRegForValue(Val); ++ MVT VT; ++ auto *TI = dyn_cast(Val); ++ unsigned ResultReg; ++ if (TI && TI->getType()->isIntegerTy(1) && CLI.CS && ++ (TI->getParent() == CLI.CS->getInstruction()->getParent()) && ++ TI->hasOneUse()) { ++ Value *PrevVal = TI->getOperand(0); ++ ResultReg = getRegForValue(PrevVal); + +- if (!ResultReg) +- return false; ++ if (!ResultReg) ++ return false; + +- MVT ArgVT; +- if (!isTypeLegal(Val->getType(), ArgVT)) +- return false; ++ if (!isTypeLegal(PrevVal->getType(), VT)) ++ return false; + +- ResultReg = +- FastEmit_ri(ArgVT, ArgVT, ISD::AND, ResultReg, Val->hasOneUse(), 1); ++ ResultReg = ++ FastEmit_ri(VT, VT, ISD::AND, ResultReg, hasTrivialKill(PrevVal), 1); + +- if (!ResultReg) +- return false; +- UpdateValueMap(Val, ResultReg); +- } ++ if (!ResultReg) ++ return false; ++ } else { ++ if (!isTypeLegal(Val->getType(), VT)) ++ return false; ++ ResultReg = getRegForValue(Val); + } ++ ++ ArgRegs.push_back(ResultReg); ++ OutVTs.push_back(VT); + } + + // Analyze operands of the call, assigning locations to each operand. +@@ -2749,13 +2758,6 @@ bool X86FastISel::FastLowerCall(CallLoweringInfo & + if (IsWin64) + CCInfo.AllocateStack(32, 8); + +- SmallVector OutVTs; +- for (auto *Val : OutVals) { +- MVT VT; +- if (!isTypeLegal(Val->getType(), VT)) +- return false; +- OutVTs.push_back(VT); +- } + CCInfo.AnalyzeCallOperands(OutVTs, OutFlags, CC_X86); + + // Get a count of how many bytes are to be pushed on the stack. +@@ -2777,9 +2779,7 @@ bool X86FastISel::FastLowerCall(CallLoweringInfo & + if (ArgVT == MVT::x86mmx) + return false; + +- unsigned ArgReg = getRegForValue(ArgVal); +- if (!ArgReg) +- return false; ++ unsigned ArgReg = ArgRegs[VA.getValNo()]; + + // Promote the value if needed. + switch (VA.getLocInfo()) { +Index: test/CodeGen/X86/fast-isel-call-bool.ll +=================================================================== +--- test/CodeGen/X86/fast-isel-call-bool.ll ++++ test/CodeGen/X86/fast-isel-call-bool.ll +@@ -0,0 +1,19 @@ ++; RUN: llc < %s -fast-isel -mcpu=core2 -O1 | FileCheck %s ++; See PR21557 ++ ++target datalayout = "e-m:e-i64:64-f80:128-n8:16:32:64-S128" ++target triple = "x86_64-apple-darwin14.0.0" ++ ++declare i64 @bar(i1) ++ ++define i64 @foo(i8* %arg) { ++; CHECK-LABEL: foo: ++top: ++ %0 = load i8* %arg ++; CHECK: movb ++ %1 = trunc i8 %0 to i1 ++; CHECK: andb $1, ++ %2 = call i64 @bar(i1 %1) ++; CHECK: callq ++ ret i64 %2 ++}