From b1dd9554ee8515cbcb2ec7c1fc2473ba9e5eae51 Mon Sep 17 00:00:00 2001 From: dteske Date: Mon, 28 Dec 2015 17:50:31 +0000 Subject: MFC r290337: Add sysrc(8) support for "rc.conf.d" Differential Revision: https://reviews.freebsd.org/D3551 Reviewed by: allanjude Relnotes: yes --- usr.sbin/sysrc/sysrc | 181 ++++++++++++++++++++++++++++++++++++++++++++++--- usr.sbin/sysrc/sysrc.8 | 69 ++++++++++++++++++- 2 files changed, 238 insertions(+), 12 deletions(-) diff --git a/usr.sbin/sysrc/sysrc b/usr.sbin/sysrc/sysrc index 2a24551..e384dff 100644 --- a/usr.sbin/sysrc/sysrc +++ b/usr.sbin/sysrc/sysrc @@ -40,18 +40,23 @@ BSDCFG_SHARE="/usr/share/bsdconfig" # # Version information # -SYSRC_VERSION="6.5 Sep-1,2015" +SYSRC_VERSION="7.0 Sep-13,2015" # # Options # CHECK_ONLY= +DEFAULT= DELETE= DESCRIBE= +EXISTING_ONLY= IGNORE_UNKNOWNS= JAIL= +LIST_SERVICE_CONFS= +LIST_CONFS= QUIET= ROOTDIR= +SERVICE= SHOW_ALL= SHOW_EQUALS= SHOW_FILE= @@ -80,7 +85,8 @@ die() # usage() { - f_err "Usage: %s [OPTIONS] name[[+|-]=value] ...\n" "$pgm" + f_err "Usage: %s [OPTIONS] %s\n" "$pgm" \ + "{name[[+|-]=value] ... | -a | -A | -l | -L [name ...]}" f_err "Try \`%s --help' for more information.\n" "$pgm" die } @@ -95,6 +101,8 @@ help() local envfmt="\t%-17s%s\n" f_err "Usage: %s [OPTIONS] name[[+|-]=value] ...\n" "$pgm" + f_err "Usage: %s [OPTIONS] -a | -A\n" "$pgm" + f_err "Usage: %s [OPTIONS] -l | -L [name ...]\n" "$pgm" f_err "OPTIONS:\n" f_err "$optfmt" "-a" \ @@ -113,6 +121,8 @@ help() "Print query results as \`var=value' (useful for producing" f_err "$optfmt" "" \ "output to be fed back in). Ignored if \`-n' is specified." + f_err "$optfmt" "-E" \ + "Existing files only with \`-[lL]' or when changing a setting." f_err "$optfmt" "-f file" \ "Operate on the specified file(s) instead of rc_conf_files." f_err "$optfmt" "" \ @@ -129,12 +139,20 @@ help() "The jid or name of the jail to operate within (overrides" f_err "$optfmt" "" \ "\`-R dir'; requires jexec(8))." + f_err "$optfmt" "-l" \ + "List configuration files used at startup on stdout and exit." + f_err "$optfmt" "-L" \ + "List all configuration files including rc.conf.d entries." f_err "$optfmt" "-n" \ "Show only variable values, not their names." f_err "$optfmt" "-N" \ "Show only variable names, not their values." f_err "$optfmt" "-q" \ "Quiet. Disable verbose and hide certain errors." + f_err "$optfmt" "-s name" \ + "Process additional \`rc.conf.d' entries for service name." + f_err "$optfmt" "" \ + "Ignored if \`-f file' is given." f_err "$optfmt" "-R dir" \ "Operate within the root directory \`dir' rather than \`/'." f_err "$optfmt" "-v" \ @@ -245,27 +263,33 @@ unset arg # # Process command-line flags # -while getopts aAcdDef:Fhij:nNqR:vxX flag; do +while getopts aAcdDeEf:Fhij:lLnNqR:s:vxX flag; do case "$flag" in a) SHOW_ALL=${SHOW_ALL:-1} ;; A) SHOW_ALL=2 ;; c) CHECK_ONLY=1 ;; d) DESCRIBE=1 ;; - D) RC_CONFS= ;; + D) DEFAULT=1 RC_CONFS= ;; e) SHOW_EQUALS=1 ;; - f) RC_CONFS="$RC_CONFS${RC_CONFS:+ }$OPTARG" ;; + E) EXISTING_ONLY=1 ;; + f) DEFAULT= RC_CONFS="$RC_CONFS${RC_CONFS:+ }$OPTARG" ;; F) SHOW_FILE=1 ;; h) usage ;; # NOTREACHED i) IGNORE_UNKNOWNS=1 ;; j) [ "$OPTARG" ] || die "%s: Missing or null argument to \`-j' flag" "$pgm" JAIL="$OPTARG" ;; + l) LIST_CONFS=1 ;; + L) LIST_SERVICE_CONFS=1 ;; n) SHOW_NAME= ;; N) SHOW_VALUE= ;; q) QUIET=1 VERBOSE= ;; R) [ "$OPTARG" ] || die "%s: Missing or null argument to \`-R' flag" "$pgm" ROOTDIR="$OPTARG" ;; + s) [ "$OPTARG" ] || + die "%s: Missing or null argument to \`-s' flag" "$pgm" + SERVICE="$OPTARG" ;; v) VERBOSE=1 QUIET= ;; x) DELETE=${DELETE:-1} ;; X) DELETE=2 ;; @@ -275,6 +299,129 @@ done shift $(( $OPTIND - 1 )) # +# Process `-L' flag +# +if [ "$LIST_SERVICE_CONFS" ]; then + list= + + # + # List rc_conf_files if no service names given + # + files= + [ $# -eq 0 ] && files=$( f_sysrc_get rc_conf_files ) + for file in $files; do + if [ "$EXISTING_ONLY" ]; then + [ -e "$file" -a ! -d "$file" ] || continue + fi + case "$list" in + "$file"|*" $file"|"$file "*|*" $file "*) continue ;; + esac + list="$list $file" + done + list="${list# }" + if [ $# -eq 0 ]; then + if [ "$VERBOSE" ]; then + echo rc_conf_files: $list + elif [ "$SHOW_EQUALS" ]; then + echo "rc_conf_files=\"$list\"" + fi + fi + + # + # List rc.conf.d entries + # + retval=$SUCCESS + for service in ${*:-$( service -l )}; do + slist= + f_sysrc_service_configs $service files || retval=$? continue + for file in $files; do + if [ "$EXISTING_ONLY" ]; then + [ -e "$file" -a ! -d "$file" ] || continue + fi + if [ ! "$VERBOSE" -a ! "$SHOW_EQUALS" ]; then + case "$list" in + "$file"|*" $file"|"$file "*|*" $file "*) + continue ;; + esac + fi + slist="$slist $file" + done + slist="${slist# }" + if [ $# -gt 0 ]; then + [ "$slist" ] || retval=$? + fi + if [ "$VERBOSE" ]; then + [ "$slist" ] && echo "$service: $slist" + continue + elif [ "$SHOW_EQUALS" ]; then + [ "$slist" ] && echo "$service=\"$slist\"" + continue + fi + list="$list${slist:+ }$slist" + done + if [ ! "$VERBOSE" -a ! "$SHOW_EQUALS" ]; then + if [ $# -eq 0 -o ! "$QUIET" ]; then + list="${list# }" + [ "$list" ] && echo $list + fi + fi + + exit $retval +fi + +# +# Process `-s name' argument +# +if [ "$SERVICE" -a ! "${RC_CONFS+set}" ]; then + if f_sysrc_service_configs "$SERVICE" RC_CONFS; then + rc_conf_files=$( f_sysrc_get rc_conf_files ) + RC_CONFS="$rc_conf_files${RC_CONFS:+ }$RC_CONFS" + unset rc_conf_files + else + unset RC_CONFS + fi +fi + +# +# Process `-E' option flag +# +if [ "$EXISTING_ONLY" ]; then + # + # To get f_sysrc_*() to ignore missing rc_conf_files, we have to use + # RC_CONFS to override the unpreened value. If RC_CONFS already has a + # value (`-D', `-f file', `-s name', or inherited from parent), use it. + # Otherwise, include filtered contents of rc_conf_files. + # + RC_CONFS=$( + if [ "${RC_CONFS+set}" ]; then + set -- $RC_CONFS + else + set -- $( f_sysrc_get rc_conf_files ) + fi + while [ $# -gt 0 ]; do + [ -f "$1" ] && echo -n " $1" + shift + done + ) + RC_CONFS="${RC_CONFS# }" +fi + +# +# Process `-l' option flag +# +if [ "$LIST_CONFS" ]; then + [ $# -eq 0 ] || usage + if [ "$DEFAULT" ]; then + echo "$RC_DEFAULTS" + elif [ "${RC_CONFS+set}" ]; then + echo "$RC_CONFS" + else + f_sysrc_get rc_conf_files + fi + exit $SUCCESS +fi + +# # [More] Sanity checks (e.g., "sysrc --") # [ $# -eq 0 -a ! "$SHOW_ALL" ] && usage # NOTREACHED @@ -344,6 +491,10 @@ if [ "$JAIL" -o "$ROOTDIR" ]; then $( [ "$SHOW_ALL" = "1" ] && echo \ -a ) $( [ "$SHOW_ALL" = "2" ] && echo \ -A ) ${CHECK_ONLY:+-c} + ${DEFAULT:+-D} + ${EXISTING_ONLY:+-E} + ${LIST_CONFS:+-l} + ${LIST_SERVICE_CONFS:+-L} ${DESCRIBE:+-d} ${SHOW_EQUALS:+-e} ${IGNORE_UNKNOWNS:+-i} @@ -351,6 +502,11 @@ if [ "$JAIL" -o "$ROOTDIR" ]; then $( [ "$SHOW_VALUE" ] || echo \ -N ) $( [ "$SHOW_FILE" ] && echo \ -F ) " + if [ "$SERVICE" ]; then + escape "$SERVICE" _SERVICE + args="$args -s '$_SERVICE'" + unset _SERVICE + fi if [ "${RC_CONFS+set}" ]; then escape "$RC_CONFS" _RC_CONFS args="$args -f '$_RC_CONFS'" @@ -454,9 +610,10 @@ if [ "$SHOW_ALL" ]; then # IFS="$IFS|" EXCEPT="IFS|EXCEPT|PATH|RC_DEFAULTS|OPTIND|DESCRIBE|SEP" - EXCEPT="$EXCEPT|DELETE|SHOW_ALL|SHOW_EQUALS|SHOW_NAME" - EXCEPT="$EXCEPT|SHOW_VALUE|SHOW_FILE|VERBOSE|RC_CONFS" - EXCEPT="$EXCEPT|pgm|SUCCESS|FAILURE|CHECK_ONLY" + EXCEPT="$EXCEPT|DELETE|SHOW_ALL|SHOW_EQUALS|SHOW_NAME|DEFAULT" + EXCEPT="$EXCEPT|SHOW_VALUE|SHOW_FILE|VERBOSE|RC_CONFS|SERVICE" + EXCEPT="$EXCEPT|pgm|SUCCESS|FAILURE|CHECK_ONLY|EXISTING_ONLY" + EXCEPT="$EXCEPT|LIST_CONFS|LIST_SERVICE_CONFS" EXCEPT="$EXCEPT|f_sysrc_desc_awk|f_sysrc_delete_awk" # @@ -479,7 +636,13 @@ if [ "$SHOW_ALL" ]; then # explicit value, modifying the default behavior of # source_rc_confs(). # - [ "${RC_CONFS+set}" ] && rc_conf_files="$RC_CONFS" + if [ "${RC_CONFS+set}" ]; then + [ "$SHOW_ALL" = "1" -a "$SERVICE" -a \ + ! "$DEFAULT" ] || rc_conf_files= + rc_conf_files="$rc_conf_files $RC_CONFS" + rc_conf_files="${rc_conf_files# }" + rc_conf_files="${rc_conf_files% }" + fi source_rc_confs diff --git a/usr.sbin/sysrc/sysrc.8 b/usr.sbin/sysrc/sysrc.8 index 2634e31..1047e15 100644 --- a/usr.sbin/sysrc/sysrc.8 +++ b/usr.sbin/sysrc/sysrc.8 @@ -24,7 +24,7 @@ .\" .\" $FreeBSD$ .\" -.Dd September 2, 2015 +.Dd September 12, 2015 .Dt SYSRC 8 .Os .Sh NAME @@ -32,16 +32,27 @@ .Nd safely edit system rc files .Sh SYNOPSIS .Nm -.Op Fl cdDeFhinNqvx +.Op Fl cdDeEFhinNqvx +.Op Fl s Ar name .Op Fl f Ar file .Op Fl j Ar jail | Fl R Ar dir .Ar name Ns Op Ns Oo +|- Oc Ns = Ns Ar value .Ar ... .Nm -.Op Fl cdDeFhinNqvx +.Op Fl cdDeEFhinNqvx +.Op Fl s Ar name .Op Fl f Ar file .Op Fl j Ar jail | Fl R Ar dir .Fl a | A +.Nm +.Op Fl E +.Op Fl s Ar name +.Op Fl f Ar file +.Fl l +.Nm +.Op Fl eEqv +.Fl L +.Op Ar name ... .Sh DESCRIPTION The .Nm @@ -81,6 +92,13 @@ Ignored if either or .Ql Fl F is specified. +.It Fl E +When given +.Sq Fl l +or +.Sq Fl L +to list configuration files, only list those that exist. +When changing a setting, prefer to modify existing files. .It Fl f Ar file Operate on the specified file(s) instead of the files obtained by reading the .Sq rc_conf_files @@ -105,6 +123,17 @@ or name of the .Ar jail to operate within .Pq overrides So Fl R Ar dir Sc ; requires Xr jexec 8 . +.It Fl l +List configuration files used at startup on stdout and exit. +.It Fl L +List all configuration files including rc.conf.d entries on stdout and exit. +Can be combined with +.Sq Fl v +or +.Sq Fl e +to show service names. +.Nm +exits with success if all named services are installed, failure otherwise. .It Fl n Show only variable values, not their names. .It Fl N @@ -112,11 +141,40 @@ Show only variable names, not their values. .It Fl q Quiet. Disable verbose and hide certain errors. +When combined with +.Sq Fl L +and one or more +.Li Ar name +arguments, provide only exit status and no output. .It Fl R Ar dir Operate within the root directory .Sq Ar dir rather than .Sq / . +.It Fl s Ar name +If an +.Li rc.d +script of +.Ar name +exists +.Po +in +.Dq /etc/rc.d +or +.Li local_startup +directories +.Pc , +process its +.Dq rc.conf.d +entries as potential overrides to +.Sq rc_conf_files . +See +.Xr rc.subr 8 +for additional information on +.Dq rc.conf.d . +Can be combined with +.Sq Fl l +to list configuration files used by service at startup. .It Fl v Verbose. Print the pathname of the specific @@ -336,6 +394,10 @@ and .It Pa /etc/defaults/rc.conf .It Pa /etc/rc.conf .It Pa /etc/rc.conf.local +.It Pa /etc/rc.conf.d/name +.It Pa /etc/rc.conf.d/name/* +.It Pa /usr/local/etc/rc.conf.d/name +.It Pa /usr/local/etc/rc.conf.d/name/* .El .Sh EXAMPLES Below are some simple examples of how @@ -397,6 +459,7 @@ cloned_interfaces+"alternate" .Sh SEE ALSO .Xr jls 1 , .Xr rc.conf 5 , +.Xr rc.subr 8 , .Xr jail 8 , .Xr jexec 8 , .Xr rc 8 , -- cgit v1.1 From b079803a46b21fa20a04cbf83b39134b2a45cf02 Mon Sep 17 00:00:00 2001 From: jilles Date: Mon, 28 Dec 2015 21:35:06 +0000 Subject: MFC r290515: periodic: Fix backwards compatibility for daily_status_security_* vars. Most daily_status_security_* variables in periodic.conf were changed to security_status_* in SVN r254974. The compatibility code for the old names did not work. PR: 204331 Submitted by: martin at lispworks.com --- etc/defaults/periodic.conf | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/etc/defaults/periodic.conf b/etc/defaults/periodic.conf index 14f1a08..d97bd93 100644 --- a/etc/defaults/periodic.conf +++ b/etc/defaults/periodic.conf @@ -319,8 +319,8 @@ if [ -z "${source_periodic_confs_defined}" ]; then "use \$$var instead." >&2 case "$value" in [Yy][Ee][Ss]) - $var=YES - $periodvar=daily + eval $var=YES + eval $periodvar=daily ;; *) eval $var=\"$value\" -- cgit v1.1 From 938f5957c28188809a40dded6925c8b75c06f30f Mon Sep 17 00:00:00 2001 From: ngie Date: Mon, 28 Dec 2015 23:05:13 +0000 Subject: MFC r292317,r292318,r292323,r292324,r292665: r292317: Integrate tools/regression/lib/libc/resolv into the FreeBSD test suite as lib/libc/tests/resolv Convert the testcases to ATF Sponsored by: EMC / Isilon Storage Division r292318: Add Makefile accidentally missed in r292317 Sponsored by: EMC / Isilon Storage Division r292323: Integrate tools/regression/lib/libc/nss into the FreeBSD test suite as lib/libc/tests/nss - Convert the testcases to ATF - Do some style(9) cleanups: -- Sort headers -- Apply indentation fixes -- Remove superfluous parentheses - Explicitly print out debug printfs for use with `kyua {debug,report}`; for items that were overly noisy, they've been put behind #ifdef DEBUG conditionals - Fix some format strings Sponsored by: EMC / Isilon Storage Division r292324: Iterate down lib/libc/tests/nss... Sponsored by: EMC / Isilon Storage Division r292665: Increase the timeout for resolv_test from the default (300 seconds) to 450 seconds This is required on slower network connections, and on older releases (stable/10 seems to be slower as far as name resolution goes.. not sure why yet). Remove an outdated comment in the Makefile from when I was working on this code over a year ago on github Sponsored by: EMC / Isilon Storage Division --- etc/mtree/BSD.tests.dist | 4 + lib/libc/tests/Makefile | 2 + lib/libc/tests/nss/Makefile | 22 + lib/libc/tests/nss/getaddrinfo_test.c | 556 ++++++++++++ lib/libc/tests/nss/getgr_test.c | 541 ++++++++++++ lib/libc/tests/nss/gethostby_test.c | 1506 ++++++++++++++++++++++++++++++++ lib/libc/tests/nss/getproto_test.c | 556 ++++++++++++ lib/libc/tests/nss/getpw_test.c | 530 +++++++++++ lib/libc/tests/nss/getrpc_test.c | 560 ++++++++++++ lib/libc/tests/nss/getserv_test.c | 570 ++++++++++++ lib/libc/tests/nss/getusershell_test.c | 225 +++++ lib/libc/tests/nss/testutil.h | 333 +++++++ lib/libc/tests/resolv/Makefile | 15 + lib/libc/tests/resolv/mach | 46 + lib/libc/tests/resolv/resolv_test.c | 331 +++++++ 15 files changed, 5797 insertions(+) create mode 100644 lib/libc/tests/nss/Makefile create mode 100644 lib/libc/tests/nss/getaddrinfo_test.c create mode 100644 lib/libc/tests/nss/getgr_test.c create mode 100644 lib/libc/tests/nss/gethostby_test.c create mode 100644 lib/libc/tests/nss/getproto_test.c create mode 100644 lib/libc/tests/nss/getpw_test.c create mode 100644 lib/libc/tests/nss/getrpc_test.c create mode 100644 lib/libc/tests/nss/getserv_test.c create mode 100644 lib/libc/tests/nss/getusershell_test.c create mode 100644 lib/libc/tests/nss/testutil.h create mode 100644 lib/libc/tests/resolv/Makefile create mode 100644 lib/libc/tests/resolv/mach create mode 100644 lib/libc/tests/resolv/resolv_test.c diff --git a/etc/mtree/BSD.tests.dist b/etc/mtree/BSD.tests.dist index c6b1486..e49b6bb 100644 --- a/etc/mtree/BSD.tests.dist +++ b/etc/mtree/BSD.tests.dist @@ -109,10 +109,14 @@ .. .. .. + nss + .. regex data .. .. + resolv + .. rpc .. ssp diff --git a/lib/libc/tests/Makefile b/lib/libc/tests/Makefile index bf5bf25..15db4fd 100644 --- a/lib/libc/tests/Makefile +++ b/lib/libc/tests/Makefile @@ -12,7 +12,9 @@ TESTS_SUBDIRS+= gen TESTS_SUBDIRS+= hash TESTS_SUBDIRS+= inet TESTS_SUBDIRS+= net +TESTS_SUBDIRS+= nss TESTS_SUBDIRS+= regex +TESTS_SUBDIRS+= resolv TESTS_SUBDIRS+= rpc TESTS_SUBDIRS+= stdio TESTS_SUBDIRS+= stdlib diff --git a/lib/libc/tests/nss/Makefile b/lib/libc/tests/nss/Makefile new file mode 100644 index 0000000..1b777c2 --- /dev/null +++ b/lib/libc/tests/nss/Makefile @@ -0,0 +1,22 @@ +# $FreeBSD$ + +TESTSDIR= ${TESTSBASE}/lib/libc/nss +BINDIR= ${TESTSDIR} + +.PATH: ${.CURDIR:H}/resolv + +FILES+= mach + +CFLAGS+= -I${SRCTOP}/tests + +ATF_TESTS_C+= getaddrinfo_test +ATF_TESTS_C+= getgr_test +ATF_TESTS_C+= gethostby_test +TEST_METADATA.gethostby_test= timeout="1200" +ATF_TESTS_C+= getpw_test +ATF_TESTS_C+= getproto_test +ATF_TESTS_C+= getrpc_test +ATF_TESTS_C+= getserv_test +ATF_TESTS_C+= getusershell_test + +.include diff --git a/lib/libc/tests/nss/getaddrinfo_test.c b/lib/libc/tests/nss/getaddrinfo_test.c new file mode 100644 index 0000000..0c9704f --- /dev/null +++ b/lib/libc/tests/nss/getaddrinfo_test.c @@ -0,0 +1,556 @@ +/*- + * Copyright (c) 2006 Michael Bushkov + * 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 +#include +#include +#include + +#include + +#include "freebsd_test_suite/macros.h" +#include "testutil.h" + +enum test_methods { + TEST_GETADDRINFO, + TEST_BUILD_SNAPSHOT +}; + +static struct addrinfo hints; +static enum test_methods method = TEST_GETADDRINFO; + +DECLARE_TEST_DATA(addrinfo) +DECLARE_TEST_FILE_SNAPSHOT(addrinfo) +DECLARE_2PASS_TEST(addrinfo) + +static void clone_addrinfo(struct addrinfo *, struct addrinfo const *); +static int compare_addrinfo(struct addrinfo *, struct addrinfo *, void *); +static void dump_addrinfo(struct addrinfo *); + +static void sdump_addrinfo(struct addrinfo *, char *, size_t); + +IMPLEMENT_TEST_DATA(addrinfo) +IMPLEMENT_TEST_FILE_SNAPSHOT(addrinfo) +IMPLEMENT_2PASS_TEST(addrinfo) + +static void +clone_addrinfo(struct addrinfo *dest, struct addrinfo const *src) +{ + + ATF_REQUIRE(dest != NULL); + ATF_REQUIRE(src != NULL); + + memcpy(dest, src, sizeof(struct addrinfo)); + if (src->ai_canonname != NULL) + dest->ai_canonname = strdup(src->ai_canonname); + + if (src->ai_addr != NULL) { + dest->ai_addr = malloc(src->ai_addrlen); + ATF_REQUIRE(dest->ai_addr != NULL); + memcpy(dest->ai_addr, src->ai_addr, src->ai_addrlen); + } + + if (src->ai_next != NULL) { + dest->ai_next = malloc(sizeof(struct addrinfo)); + ATF_REQUIRE(dest->ai_next != NULL); + clone_addrinfo(dest->ai_next, src->ai_next); + } +} + +static int +compare_addrinfo_(struct addrinfo *ai1, struct addrinfo *ai2) +{ + + if ((ai1 == NULL) || (ai2 == NULL)) + return (-1); + + if (ai1->ai_flags != ai2->ai_flags || + ai1->ai_family != ai2->ai_family || + ai1->ai_socktype != ai2->ai_socktype || + ai1->ai_protocol != ai2->ai_protocol || + ai1->ai_addrlen != ai2->ai_addrlen || + ((ai1->ai_addr == NULL || ai2->ai_addr == NULL) && + ai1->ai_addr != ai2->ai_addr) || + ((ai1->ai_canonname == NULL || ai2->ai_canonname == NULL) && + ai1->ai_canonname != ai2->ai_canonname)) + return (-1); + + if (ai1->ai_canonname != NULL && + strcmp(ai1->ai_canonname, ai2->ai_canonname) != 0) + return (-1); + + if (ai1->ai_addr != NULL && + memcmp(ai1->ai_addr, ai2->ai_addr, ai1->ai_addrlen) != 0) + return (-1); + + if (ai1->ai_next == NULL && ai2->ai_next == NULL) + return (0); + else + return (compare_addrinfo_(ai1->ai_next, ai2->ai_next)); +} + +static int +compare_addrinfo(struct addrinfo *ai1, struct addrinfo *ai2, void *mdata) +{ + int rv; + + printf("testing equality of 2 addrinfo structures\n"); + + rv = compare_addrinfo_(ai1, ai2); + + if (rv == 0) + printf("equal\n"); + else { + dump_addrinfo(ai1); + dump_addrinfo(ai2); + printf("not equal\n"); + } + + return (rv); +} + +void +free_addrinfo(struct addrinfo *ai) +{ + if (ai == NULL) + return; + + free(ai->ai_addr); + free(ai->ai_canonname); + free_addrinfo(ai->ai_next); +} + +void +sdump_addrinfo(struct addrinfo *ai, char *buffer, size_t buflen) +{ + int written, i; + + written = snprintf(buffer, buflen, "%d %d %d %d %d ", + ai->ai_flags, ai->ai_family, ai->ai_socktype, ai->ai_protocol, + ai->ai_addrlen); + buffer += written; + if (written > buflen) + return; + buflen -= written; + + written = snprintf(buffer, buflen, "%s ", + ai->ai_canonname == NULL ? "(null)" : ai->ai_canonname); + buffer += written; + if (written > buflen) + return; + buflen -= written; + + if (ai->ai_addr == NULL) { + written = snprintf(buffer, buflen, "(null)"); + buffer += written; + if (written > buflen) + return; + buflen -= written; + } else { + for (i = 0; i < ai->ai_addrlen; i++) { + written = snprintf(buffer, buflen, + i + 1 != ai->ai_addrlen ? "%d." : "%d", + ((unsigned char *)ai->ai_addr)[i]); + buffer += written; + if (written > buflen) + return; + buflen -= written; + + if (buflen == 0) + return; + } + } + + if (ai->ai_next != NULL) { + written = snprintf(buffer, buflen, ":"); + buffer += written; + if (written > buflen) + return; + buflen -= written; + + sdump_addrinfo(ai->ai_next, buffer, buflen); + } +} + +void +dump_addrinfo(struct addrinfo *result) +{ + if (result != NULL) { + char buffer[2048]; + sdump_addrinfo(result, buffer, sizeof(buffer)); + printf("%s\n", buffer); + } else + printf("(null)\n"); +} + +static int +addrinfo_read_snapshot_addr(char *addr, unsigned char *result, size_t len) +{ + char *s, *ps, *ts; + + ps = addr; + while ((s = strsep(&ps, ".")) != NULL) { + if (len == 0) + return (-1); + + *result = (unsigned char)strtol(s, &ts, 10); + ++result; + if (*ts != '\0') + return (-1); + + --len; + } + if (len != 0) + return (-1); + else + return (0); +} + +static int +addrinfo_read_snapshot_ai(struct addrinfo *ai, char *line) +{ + char *s, *ps, *ts; + int i, rv, *pi; + + rv = 0; + i = 0; + ps = line; + memset(ai, 0, sizeof(struct addrinfo)); + while ((s = strsep(&ps, " ")) != NULL) { + switch (i) { + case 0: + case 1: + case 2: + case 3: + pi = &ai->ai_flags + i; + *pi = (int)strtol(s, &ts, 10); + if (*ts != '\0') + goto fin; + break; + case 4: + ai->ai_addrlen = (socklen_t)strtol(s, &ts, 10); + if (*ts != '\0') + goto fin; + break; + case 5: + if (strcmp(s, "(null)") != 0) { + ai->ai_canonname = strdup(s); + ATF_REQUIRE(ai->ai_canonname != NULL); + } + break; + case 6: + if (strcmp(s, "(null)") != 0) { + ai->ai_addr = calloc(1, ai->ai_addrlen); + ATF_REQUIRE(ai->ai_addr != NULL); + rv = addrinfo_read_snapshot_addr(s, + (unsigned char *)ai->ai_addr, + ai->ai_addrlen); + + if (rv != 0) + goto fin; + } + break; + default: + /* NOTE: should not be reachable */ + rv = -1; + goto fin; + } + + ++i; + } + +fin: + if (i != 7 || rv != 0) { + free_addrinfo(ai); + ai = NULL; + return (-1); + } + + return (0); +} + +static int +addrinfo_read_snapshot_func(struct addrinfo *ai, char *line) +{ + struct addrinfo *ai2; + char *s, *ps; + int i, rv; + + printf("1 line read from snapshot:\n%s\n", line); + + rv = 0; + i = 0; + ps = line; + + s = strsep(&ps, ":"); + if (s == NULL) + return (-1); + + rv = addrinfo_read_snapshot_ai(ai, s); + if (rv != 0) + return (-1); + + ai2 = ai; + while ((s = strsep(&ps, ":")) != NULL) { + ai2->ai_next = calloc(1, sizeof(struct addrinfo)); + ATF_REQUIRE(ai2->ai_next != NULL); + + rv = addrinfo_read_snapshot_ai(ai2->ai_next, s); + if (rv != 0) { + free_addrinfo(ai); + ai = NULL; + return (-1); + } + + ai2 = ai2->ai_next; + } + + return (0); +} + +static int +addrinfo_test_correctness(struct addrinfo *ai, void *mdata) +{ + + printf("testing correctness with the following data:\n"); + dump_addrinfo(ai); + + if (ai == NULL) + goto errfin; + + if (!(ai->ai_family >= 0 && ai->ai_family < AF_MAX)) + goto errfin; + + if (ai->ai_socktype != 0 && ai->ai_socktype != SOCK_STREAM && + ai->ai_socktype != SOCK_DGRAM && ai->ai_socktype != SOCK_RAW) + goto errfin; + + if (ai->ai_protocol != 0 && ai->ai_protocol != IPPROTO_UDP && + ai->ai_protocol != IPPROTO_TCP) + goto errfin; + + if ((ai->ai_flags & ~(AI_CANONNAME | AI_NUMERICHOST | AI_PASSIVE)) != 0) + goto errfin; + + if (ai->ai_addrlen != ai->ai_addr->sa_len || + ai->ai_family != ai->ai_addr->sa_family) + goto errfin; + + printf("correct\n"); + + return (0); +errfin: + printf("incorrect\n"); + + return (-1); +} + +static int +addrinfo_read_hostlist_func(struct addrinfo *ai, char *line) +{ + struct addrinfo *result; + int rv; + + printf("resolving %s: ", line); + rv = getaddrinfo(line, NULL, &hints, &result); + if (rv == 0) { + printf("found\n"); + + rv = addrinfo_test_correctness(result, NULL); + if (rv != 0) { + freeaddrinfo(result); + result = NULL; + return (rv); + } + + clone_addrinfo(ai, result); + freeaddrinfo(result); + result = NULL; + } else { + printf("not found\n"); + + memset(ai, 0, sizeof(struct addrinfo)); + } + return (0); +} + +void +run_tests(char *hostlist_file, char *snapshot_file, int ai_family) +{ + struct addrinfo_test_data td, td_snap; + int rv; + + memset(&hints, 0, sizeof(struct addrinfo)); + hints.ai_family = ai_family; + hints.ai_flags = AI_CANONNAME; + + if (snapshot_file != NULL) + method = TEST_BUILD_SNAPSHOT; + + TEST_DATA_INIT(addrinfo, &td, clone_addrinfo, free_addrinfo); + TEST_DATA_INIT(addrinfo, &td_snap, clone_addrinfo, free_addrinfo); + + ATF_REQUIRE_MSG(access(hostlist_file, R_OK) == 0, + "can't access the hostlist file %s\n", hostlist_file); + + printf("building host lists from %s\n", hostlist_file); + + rv = TEST_SNAPSHOT_FILE_READ(addrinfo, hostlist_file, &td, + addrinfo_read_hostlist_func); + if (rv != 0) + goto fin; + + if (snapshot_file != NULL) { + if (access(snapshot_file, W_OK | R_OK) != 0) { + if (errno == ENOENT) + method = TEST_BUILD_SNAPSHOT; + else { + printf("can't access the snapshot " + "file %s\n", snapshot_file); + + rv = -1; + goto fin; + } + } else { + rv = TEST_SNAPSHOT_FILE_READ(addrinfo, snapshot_file, + &td_snap, addrinfo_read_snapshot_func); + if (rv != 0) { + printf("error reading snapshot file: %s\n", + strerror(errno)); + goto fin; + } + } + } + + switch (method) { + case TEST_GETADDRINFO: + if (snapshot_file != NULL) + ATF_CHECK(DO_2PASS_TEST(addrinfo, &td, &td_snap, + compare_addrinfo, NULL) == 0); + break; + case TEST_BUILD_SNAPSHOT: + if (snapshot_file != NULL) { + ATF_CHECK(TEST_SNAPSHOT_FILE_WRITE(addrinfo, + snapshot_file, &td, sdump_addrinfo) == 0); + } + break; + default: + break; + } + +fin: + TEST_DATA_DESTROY(addrinfo, &td_snap); + TEST_DATA_DESTROY(addrinfo, &td); + + free(hostlist_file); + free(snapshot_file); +} + +#define HOSTLIST_FILE "mach" +#define RUN_TESTS(tc, snapshot_file, ai_family) do { \ + char *_hostlist_file; \ + char *_snapshot_file; \ + ATF_REQUIRE(0 < asprintf(&_hostlist_file, "%s/%s", \ + atf_tc_get_config_var(tc, "srcdir"), HOSTLIST_FILE)); \ + if (snapshot_file == NULL) \ + _snapshot_file = NULL; \ + else { \ + _snapshot_file = strdup(snapshot_file); \ + ATF_REQUIRE(_snapshot_file != NULL); \ + } \ + run_tests(_hostlist_file, _snapshot_file, ai_family); \ +} while(0) + +ATF_TC_WITHOUT_HEAD(pf_unspec); +ATF_TC_BODY(pf_unspec, tc) +{ + + RUN_TESTS(tc, NULL, AF_UNSPEC); +} + +ATF_TC_WITHOUT_HEAD(pf_unspec_with_snapshot); +ATF_TC_BODY(pf_unspec_with_snapshot, tc) +{ + + RUN_TESTS(tc, "snapshot_ai", AF_UNSPEC); +} + +ATF_TC_WITHOUT_HEAD(pf_inet); +ATF_TC_BODY(pf_inet, tc) +{ + + ATF_REQUIRE_FEATURE("inet"); + RUN_TESTS(tc, NULL, AF_INET); +} + +ATF_TC_WITHOUT_HEAD(pf_inet_with_snapshot); +ATF_TC_BODY(pf_inet_with_snapshot, tc) +{ + + ATF_REQUIRE_FEATURE("inet"); + RUN_TESTS(tc, "snapshot_ai4", AF_INET); +} + +ATF_TC_WITHOUT_HEAD(pf_inet6); +ATF_TC_BODY(pf_inet6, tc) +{ + + ATF_REQUIRE_FEATURE("inet6"); + RUN_TESTS(tc, NULL, AF_INET6); +} + +ATF_TC_WITHOUT_HEAD(pf_inet6_with_snapshot); +ATF_TC_BODY(pf_inet6_with_snapshot, tc) +{ + + ATF_REQUIRE_FEATURE("inet6"); + RUN_TESTS(tc, "snapshot_ai6", AF_INET6); +} + +ATF_TP_ADD_TCS(tp) +{ + + ATF_TP_ADD_TC(tp, pf_unspec); + ATF_TP_ADD_TC(tp, pf_unspec_with_snapshot); + ATF_TP_ADD_TC(tp, pf_inet); + ATF_TP_ADD_TC(tp, pf_inet_with_snapshot); + ATF_TP_ADD_TC(tp, pf_inet6); + ATF_TP_ADD_TC(tp, pf_inet6_with_snapshot); + + return (atf_no_error()); +} diff --git a/lib/libc/tests/nss/getgr_test.c b/lib/libc/tests/nss/getgr_test.c new file mode 100644 index 0000000..d9851ef --- /dev/null +++ b/lib/libc/tests/nss/getgr_test.c @@ -0,0 +1,541 @@ +/*- + * Copyright (c) 2006 Michael Bushkov + * 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 + +#include "testutil.h" + +enum test_methods { + TEST_GETGRENT = 1, + TEST_GETGRNAM = 2, + TEST_GETGRGID = 4, + TEST_GETGRENT_2PASS = 8, + TEST_BUILD_SNAPSHOT = 16, +}; + +static enum test_methods method = TEST_BUILD_SNAPSHOT; + +DECLARE_TEST_DATA(group) +DECLARE_TEST_FILE_SNAPSHOT(group) +DECLARE_1PASS_TEST(group) +DECLARE_2PASS_TEST(group) + +static void clone_group(struct group *, struct group const *); +static int compare_group(struct group *, struct group *, void *); +static void dump_group(struct group *); +static void free_group(struct group *); + +static void sdump_group(struct group *, char *, size_t); +static int group_read_snapshot_func(struct group *, char *); + +static int group_check_ambiguity(struct group_test_data *, + struct group *); +static int group_fill_test_data(struct group_test_data *); +static int group_test_correctness(struct group *, void *); +static int group_test_getgrnam(struct group *, void *); +static int group_test_getgrgid(struct group *, void *); +static int group_test_getgrent(struct group *, void *); + +IMPLEMENT_TEST_DATA(group) +IMPLEMENT_TEST_FILE_SNAPSHOT(group) +IMPLEMENT_1PASS_TEST(group) +IMPLEMENT_2PASS_TEST(group) + +static void +clone_group(struct group *dest, struct group const *src) +{ + ATF_REQUIRE(dest != NULL); + ATF_REQUIRE(src != NULL); + + char **cp; + int members_num; + + memset(dest, 0, sizeof(struct group)); + + if (src->gr_name != NULL) { + dest->gr_name = strdup(src->gr_name); + ATF_REQUIRE(dest->gr_name != NULL); + } + + if (src->gr_passwd != NULL) { + dest->gr_passwd = strdup(src->gr_passwd); + ATF_REQUIRE(dest->gr_passwd != NULL); + } + dest->gr_gid = src->gr_gid; + + if (src->gr_mem != NULL) { + members_num = 0; + for (cp = src->gr_mem; *cp; ++cp) + ++members_num; + + dest->gr_mem = calloc(1, (members_num + 1) * sizeof(char *)); + ATF_REQUIRE(dest->gr_mem != NULL); + + for (cp = src->gr_mem; *cp; ++cp) { + dest->gr_mem[cp - src->gr_mem] = strdup(*cp); + ATF_REQUIRE(dest->gr_mem[cp - src->gr_mem] != NULL); + } + } +} + +static void +free_group(struct group *grp) +{ + char **cp; + + ATF_REQUIRE(grp != NULL); + + free(grp->gr_name); + free(grp->gr_passwd); + + for (cp = grp->gr_mem; *cp; ++cp) + free(*cp); + free(grp->gr_mem); +} + +static int +compare_group(struct group *grp1, struct group *grp2, void *mdata) +{ + char **c1, **c2; + + if (grp1 == grp2) + return (0); + + if (grp1 == NULL || grp2 == NULL) + goto errfin; + + if (strcmp(grp1->gr_name, grp2->gr_name) != 0 || + strcmp(grp1->gr_passwd, grp2->gr_passwd) != 0 || + grp1->gr_gid != grp2->gr_gid) + goto errfin; + + c1 = grp1->gr_mem; + c2 = grp2->gr_mem; + + if (grp1->gr_mem == NULL || grp2->gr_mem == NULL) + goto errfin; + + for (; *c1 && *c2; ++c1, ++c2) + if (strcmp(*c1, *c2) != 0) + goto errfin; + + if (*c1 != '\0' || *c2 != '\0') + goto errfin; + + return 0; + +errfin: + if (mdata == NULL) { + printf("following structures are not equal:\n"); + dump_group(grp1); + dump_group(grp2); + } + + return (-1); +} + +static void +sdump_group(struct group *grp, char *buffer, size_t buflen) +{ + char **cp; + int written; + + written = snprintf(buffer, buflen, "%s %s %d", + grp->gr_name, grp->gr_passwd, grp->gr_gid); + buffer += written; + if (written > buflen) + return; + buflen -= written; + + if (grp->gr_mem != NULL) { + if (*(grp->gr_mem) != '\0') { + for (cp = grp->gr_mem; *cp; ++cp) { + written = snprintf(buffer, buflen, " %s",*cp); + buffer += written; + if (written > buflen) + return; + buflen -= written; + + if (buflen == 0) + return; + } + } else + snprintf(buffer, buflen, " nomem"); + } else + snprintf(buffer, buflen, " (null)"); +} + +static int +group_read_snapshot_func(struct group *grp, char *line) +{ + StringList *sl; + char *s, *ps, *ts; + int i; + + printf("1 line read from snapshot:\n%s\n", line); + + i = 0; + sl = NULL; + ps = line; + memset(grp, 0, sizeof(struct group)); + while ((s = strsep(&ps, " ")) != NULL) { + switch (i) { + case 0: + grp->gr_name = strdup(s); + ATF_REQUIRE(grp->gr_name != NULL); + break; + + case 1: + grp->gr_passwd = strdup(s); + ATF_REQUIRE(grp->gr_passwd != NULL); + break; + + case 2: + grp->gr_gid = (gid_t)strtol(s, &ts, 10); + if (*ts != '\0') { + free(grp->gr_name); + free(grp->gr_passwd); + grp->gr_name = NULL; + grp->gr_passwd = NULL; + return (-1); + } + break; + + default: + if (sl == NULL) { + if (strcmp(s, "(null)") == 0) + return (0); + + sl = sl_init(); + ATF_REQUIRE(sl != NULL); + + if (strcmp(s, "nomem") != 0) { + ts = strdup(s); + ATF_REQUIRE(ts != NULL); + sl_add(sl, ts); + } + } else { + ts = strdup(s); + ATF_REQUIRE(ts != NULL); + sl_add(sl, ts); + } + break; + } + ++i; + } + + if (i < 3) { + free(grp->gr_name); + free(grp->gr_passwd); + memset(grp, 0, sizeof(struct group)); + return (-1); + } + + sl_add(sl, NULL); + grp->gr_mem = sl->sl_str; + + /* NOTE: is it a dirty hack or not? */ + free(sl); + return (0); +} + +static void +dump_group(struct group *result) +{ + if (result != NULL) { + char buffer[1024]; + sdump_group(result, buffer, sizeof(buffer)); + printf("%s\n", buffer); + } else + printf("(null)\n"); +} + +static int +group_fill_test_data(struct group_test_data *td) +{ + struct group *grp; + + setgroupent(1); + while ((grp = getgrent()) != NULL) { + if (group_test_correctness(grp, NULL) == 0) + TEST_DATA_APPEND(group, td, grp); + else + return (-1); + } + endgrent(); + + return (0); +} + +static int +group_test_correctness(struct group *grp, void *mdata) +{ + printf("testing correctness with the following data:\n"); + dump_group(grp); + + if (grp == NULL) + goto errfin; + + if (grp->gr_name == NULL) + goto errfin; + + if (grp->gr_passwd == NULL) + goto errfin; + + if (grp->gr_mem == NULL) + goto errfin; + + printf("correct\n"); + + return (0); +errfin: + printf("incorrect\n"); + + return (-1); +} + +/* group_check_ambiguity() is needed here because when doing the getgrent() + * calls sequence, records from different nsswitch sources can be different, + * though having the same pw_name/pw_uid */ +static int +group_check_ambiguity(struct group_test_data *td, struct group *pwd) +{ + + return (TEST_DATA_FIND(group, td, pwd, compare_group, + NULL) != NULL ? 0 : -1); +} + +static int +group_test_getgrnam(struct group *grp_model, void *mdata) +{ + struct group *grp; + + printf("testing getgrnam() with the following data:\n"); + dump_group(grp_model); + + grp = getgrnam(grp_model->gr_name); + if (group_test_correctness(grp, NULL) != 0) + goto errfin; + + if (compare_group(grp, grp_model, NULL) != 0 && + group_check_ambiguity((struct group_test_data *)mdata, grp) != 0) + goto errfin; + + return (0); + +errfin: + return (-1); +} + +static int +group_test_getgrgid(struct group *grp_model, void *mdata) +{ + struct group *grp; + + printf("testing getgrgid() with the following data...\n"); + dump_group(grp_model); + + grp = getgrgid(grp_model->gr_gid); + if (group_test_correctness(grp, NULL) != 0 || + (compare_group(grp, grp_model, NULL) != 0 && + group_check_ambiguity((struct group_test_data *)mdata, grp) != 0)) { + return (-1); + } else { + return (0); + } +} + +static int +group_test_getgrent(struct group *grp, void *mdata) +{ + /* Only correctness can be checked when doing 1-pass test for + * getgrent(). */ + return (group_test_correctness(grp, NULL)); +} + +static int +run_tests(const char *snapshot_file, enum test_methods method) +{ + struct group_test_data td, td_snap, td_2pass; + int rv; + + TEST_DATA_INIT(group, &td, clone_group, free_group); + TEST_DATA_INIT(group, &td_snap, clone_group, free_group); + if (snapshot_file != NULL) { + if (access(snapshot_file, W_OK | R_OK) != 0) { + if (errno == ENOENT) + method = TEST_BUILD_SNAPSHOT; + else { + printf("can't access the file %s\n", + snapshot_file); + + rv = -1; + goto fin; + } + } else { + if (method == TEST_BUILD_SNAPSHOT) { + rv = 0; + goto fin; + } + + TEST_SNAPSHOT_FILE_READ(group, snapshot_file, + &td_snap, group_read_snapshot_func); + } + } + + rv = group_fill_test_data(&td); + if (rv == -1) + return (-1); + switch (method) { + case TEST_GETGRNAM: + if (snapshot_file == NULL) + rv = DO_1PASS_TEST(group, &td, + group_test_getgrnam, (void *)&td); + else + rv = DO_1PASS_TEST(group, &td_snap, + group_test_getgrnam, (void *)&td_snap); + break; + case TEST_GETGRGID: + if (snapshot_file == NULL) + rv = DO_1PASS_TEST(group, &td, + group_test_getgrgid, (void *)&td); + else + rv = DO_1PASS_TEST(group, &td_snap, + group_test_getgrgid, (void *)&td_snap); + break; + case TEST_GETGRENT: + if (snapshot_file == NULL) + rv = DO_1PASS_TEST(group, &td, group_test_getgrent, + (void *)&td); + else + rv = DO_2PASS_TEST(group, &td, &td_snap, + compare_group, NULL); + break; + case TEST_GETGRENT_2PASS: + TEST_DATA_INIT(group, &td_2pass, clone_group, free_group); + rv = group_fill_test_data(&td_2pass); + if (rv != -1) + rv = DO_2PASS_TEST(group, &td, &td_2pass, + compare_group, NULL); + TEST_DATA_DESTROY(group, &td_2pass); + break; + case TEST_BUILD_SNAPSHOT: + if (snapshot_file != NULL) + rv = TEST_SNAPSHOT_FILE_WRITE(group, snapshot_file, &td, + sdump_group); + break; + default: + rv = 0; + break; + } + +fin: + TEST_DATA_DESTROY(group, &td_snap); + TEST_DATA_DESTROY(group, &td); + + return (rv); +} + +#define SNAPSHOT_FILE "snapshot_grp" + +ATF_TC_BODY(getgrent, tc) +{ + + ATF_REQUIRE(run_tests(SNAPSHOT_FILE, TEST_GETGRENT) == 0); +} + +ATF_TC_WITHOUT_HEAD(getgrent_with_snapshot); +ATF_TC_BODY(getgrent_with_snapshot, tc) +{ + + ATF_REQUIRE(run_tests(SNAPSHOT_FILE, TEST_BUILD_SNAPSHOT) == 0); + ATF_REQUIRE(run_tests(SNAPSHOT_FILE, TEST_GETGRENT) == 0); +} + +ATF_TC_WITHOUT_HEAD(getgrent_with_two_pass); +ATF_TC_BODY(getgrent_with_two_pass, tc) +{ + + ATF_REQUIRE(run_tests(SNAPSHOT_FILE, TEST_GETGRENT_2PASS) == 0); +} + +ATF_TC_WITHOUT_HEAD(getgrgid); +ATF_TC_BODY(getgrgid, tc) +{ + + ATF_REQUIRE(run_tests(SNAPSHOT_FILE, TEST_GETGRGID) == 0); +} + +ATF_TC_WITHOUT_HEAD(getgrgid_with_snapshot); +ATF_TC_BODY(getgrgid_with_snapshot, tc) +{ + + ATF_REQUIRE(run_tests(SNAPSHOT_FILE, TEST_BUILD_SNAPSHOT) == 0); + ATF_REQUIRE(run_tests(SNAPSHOT_FILE, TEST_GETGRGID) == 0); +} + +ATF_TC_WITHOUT_HEAD(getgrnam); +ATF_TC_BODY(getgrnam, tc) +{ + + ATF_REQUIRE(run_tests(SNAPSHOT_FILE, TEST_GETGRNAM) == 0); +} + +ATF_TC_WITHOUT_HEAD(getgrnam_with_snapshot); +ATF_TC_BODY(getgrnam_with_snapshot, tc) +{ + + ATF_REQUIRE(run_tests(SNAPSHOT_FILE, TEST_BUILD_SNAPSHOT) == 0); + ATF_REQUIRE(run_tests(SNAPSHOT_FILE, TEST_GETGRNAM) == 0); +} + +ATF_TC_WITHOUT_HEAD(getgrent); +ATF_TP_ADD_TCS(tp) +{ + + ATF_TP_ADD_TC(tp, getgrent); + ATF_TP_ADD_TC(tp, getgrent_with_snapshot); + ATF_TP_ADD_TC(tp, getgrent_with_two_pass); + ATF_TP_ADD_TC(tp, getgrgid); + ATF_TP_ADD_TC(tp, getgrgid_with_snapshot); + ATF_TP_ADD_TC(tp, getgrnam); + ATF_TP_ADD_TC(tp, getgrnam_with_snapshot); + + return (atf_no_error()); +} diff --git a/lib/libc/tests/nss/gethostby_test.c b/lib/libc/tests/nss/gethostby_test.c new file mode 100644 index 0000000..bdeafbc --- /dev/null +++ b/lib/libc/tests/nss/gethostby_test.c @@ -0,0 +1,1506 @@ +/*- + * Copyright (c) 2006 Michael Bushkov + * 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 +#include +#include +#include + +#include + +#include "freebsd_test_suite/macros.h" +#include "testutil.h" + +enum test_methods { + TEST_GETHOSTBYNAME2, + TEST_GETHOSTBYADDR, + TEST_GETHOSTBYNAME2_GETADDRINFO, + TEST_GETHOSTBYADDR_GETNAMEINFO, + TEST_BUILD_SNAPSHOT, + TEST_BUILD_ADDR_SNAPSHOT +}; + +static int ipnode_flags = 0; +static int af_type = AF_INET; +static bool use_ipnode_functions; + +DECLARE_TEST_DATA(hostent) +DECLARE_TEST_FILE_SNAPSHOT(hostent) +DECLARE_1PASS_TEST(hostent) +DECLARE_2PASS_TEST(hostent) + +/* These stubs will use gethostby***() or getipnodeby***() functions, + * depending on the use_ipnode_functions global variable value */ +static struct hostent *__gethostbyname2(const char *, int); +static struct hostent *__gethostbyaddr(const void *, socklen_t, int); +static void __freehostent(struct hostent *); + +static void clone_hostent(struct hostent *, struct hostent const *); +static int compare_hostent(struct hostent *, struct hostent *, void *); +static void dump_hostent(struct hostent *); +static void free_hostent(struct hostent *); + +static int is_hostent_equal(struct hostent *, struct addrinfo *); + +static void sdump_hostent(struct hostent *, char *, size_t); +static int hostent_read_hostlist_func(struct hostent *, char *); +static int hostent_read_snapshot_addr(char *, unsigned char *, size_t); +static int hostent_read_snapshot_func(struct hostent *, char *); + +static int hostent_test_correctness(struct hostent *, void *); +static int hostent_test_gethostbyaddr(struct hostent *, void *); +static int hostent_test_getaddrinfo_eq(struct hostent *, void *); +static int hostent_test_getnameinfo_eq(struct hostent *, void *); + +static void usage(void) __attribute__((__noreturn__)); + +IMPLEMENT_TEST_DATA(hostent) +IMPLEMENT_TEST_FILE_SNAPSHOT(hostent) +IMPLEMENT_1PASS_TEST(hostent) +IMPLEMENT_2PASS_TEST(hostent) + +static struct hostent * +__gethostbyname2(const char *name, int af) +{ + struct hostent *he; + int error; + + if (use_ipnode_functions) { + error = 0; + he = getipnodebyname(name, af, ipnode_flags, &error); + if (he == NULL) + errno = error; + } else + he = gethostbyname2(name, af); + + return (he); +} + +static struct hostent * +__gethostbyaddr(const void *addr, socklen_t len, int af) +{ + struct hostent *he; + int error; + + if (use_ipnode_functions) { + error = 0; + he = getipnodebyaddr(addr, len, af, &error); + if (he == NULL) + errno = error; + } else + he = gethostbyaddr(addr, len, af); + + return (he); +} + +static void +__freehostent(struct hostent *he) +{ + + /* NOTE: checking for he != NULL - just in case */ + if (use_ipnode_functions && he != NULL) + freehostent(he); +} + +static void +clone_hostent(struct hostent *dest, struct hostent const *src) +{ + ATF_REQUIRE(dest != NULL); + ATF_REQUIRE(src != NULL); + + char **cp; + int aliases_num; + int addrs_num; + size_t offset; + + memset(dest, 0, sizeof(struct hostent)); + + if (src->h_name != NULL) { + dest->h_name = strdup(src->h_name); + ATF_REQUIRE(dest->h_name != NULL); + } + + dest->h_addrtype = src->h_addrtype; + dest->h_length = src->h_length; + + if (src->h_aliases != NULL) { + aliases_num = 0; + for (cp = src->h_aliases; *cp; ++cp) + ++aliases_num; + + dest->h_aliases = calloc(1, (aliases_num + 1) * + sizeof(char *)); + ATF_REQUIRE(dest->h_aliases != NULL); + + for (cp = src->h_aliases; *cp; ++cp) { + dest->h_aliases[cp - src->h_aliases] = strdup(*cp); + ATF_REQUIRE(dest->h_aliases[cp - src->h_aliases] != NULL); + } + } + + if (src->h_addr_list != NULL) { + addrs_num = 0; + for (cp = src->h_addr_list; *cp; ++cp) + ++addrs_num; + + dest->h_addr_list = calloc(1, (addrs_num + 1) * sizeof(char *)); + ATF_REQUIRE(dest->h_addr_list != NULL); + + for (cp = src->h_addr_list; *cp; ++cp) { + offset = cp - src->h_addr_list; + dest->h_addr_list[offset] = malloc(src->h_length); + ATF_REQUIRE(dest->h_addr_list[offset] != NULL); + memcpy(dest->h_addr_list[offset], + src->h_addr_list[offset], src->h_length); + } + } +} + +static void +free_hostent(struct hostent *ht) +{ + char **cp; + + ATF_REQUIRE(ht != NULL); + + free(ht->h_name); + + if (ht->h_aliases != NULL) { + for (cp = ht->h_aliases; *cp; ++cp) + free(*cp); + free(ht->h_aliases); + } + + if (ht->h_addr_list != NULL) { + for (cp = ht->h_addr_list; *cp; ++cp) + free(*cp); + free(ht->h_addr_list); + } +} + +static int +compare_hostent(struct hostent *ht1, struct hostent *ht2, void *mdata) +{ + char **c1, **c2, **ct, **cb; + int b; + + if (ht1 == ht2) + return 0; + + if (ht1 == NULL || ht2 == NULL) + goto errfin; + + if (ht1->h_name == NULL || ht2->h_name == NULL) + goto errfin; + + if (ht1->h_addrtype != ht2->h_addrtype || + ht1->h_length != ht2->h_length || + strcmp(ht1->h_name, ht2->h_name) != 0) + goto errfin; + + c1 = ht1->h_aliases; + c2 = ht2->h_aliases; + + if ((ht1->h_aliases == NULL || ht2->h_aliases == NULL) && + ht1->h_aliases != ht2->h_aliases) + goto errfin; + + if (c1 != NULL && c2 != NULL) { + cb = c1; + for (;*c1; ++c1) { + b = 0; + for (ct = c2; *ct; ++ct) { + if (strcmp(*c1, *ct) == 0) { + b = 1; + break; + } + } + if (b == 0) { + printf("h1 aliases item can't be found in h2 " + "aliases\n"); + goto errfin; + } + } + + c1 = cb; + for (;*c2; ++c2) { + b = 0; + for (ct = c1; *ct; ++ct) { + if (strcmp(*c2, *ct) == 0) { + b = 1; + break; + } + } + if (b == 0) { + printf("h2 aliases item can't be found in h1 " + "aliases\n"); + goto errfin; + } + } + } + + c1 = ht1->h_addr_list; + c2 = ht2->h_addr_list; + + if ((ht1->h_addr_list == NULL || ht2->h_addr_list== NULL) && + ht1->h_addr_list != ht2->h_addr_list) + goto errfin; + + if (c1 != NULL && c2 != NULL) { + cb = c1; + for (; *c1; ++c1) { + b = 0; + for (ct = c2; *ct; ++ct) { + if (memcmp(*c1, *ct, ht1->h_length) == 0) { + b = 1; + break; + } + } + if (b == 0) { + printf("h1 addresses item can't be found in " + "h2 addresses\n"); + goto errfin; + } + } + + c1 = cb; + for (; *c2; ++c2) { + b = 0; + for (ct = c1; *ct; ++ct) { + if (memcmp(*c2, *ct, ht1->h_length) == 0) { + b = 1; + break; + } + } + if (b == 0) { + printf("h2 addresses item can't be found in " + "h1 addresses\n"); + goto errfin; + } + } + } + + return 0; + +errfin: + if (mdata == NULL) { + printf("following structures are not equal:\n"); + dump_hostent(ht1); + dump_hostent(ht2); + } + + return (-1); +} + +static int +check_addrinfo_for_name(struct addrinfo *ai, char const *name) +{ + struct addrinfo *ai2; + + for (ai2 = ai; ai2 != NULL; ai2 = ai2->ai_next) { + if (strcmp(ai2->ai_canonname, name) == 0) + return (0); + } + + return (-1); +} + +static int +check_addrinfo_for_addr(struct addrinfo *ai, char const *addr, + socklen_t addrlen, int af) +{ + struct addrinfo *ai2; + + for (ai2 = ai; ai2 != NULL; ai2 = ai2->ai_next) { + if (af != ai2->ai_family) + continue; + + switch (af) { + case AF_INET: + if (memcmp(addr, + (void *)&((struct sockaddr_in *)ai2->ai_addr)->sin_addr, + MIN(addrlen, ai2->ai_addrlen)) == 0) + return (0); + break; + case AF_INET6: + if (memcmp(addr, + (void *)&((struct sockaddr_in6 *)ai2->ai_addr)->sin6_addr, + MIN(addrlen, ai2->ai_addrlen)) == 0) + return (0); + break; + default: + break; + } + } + + return (-1); +} + +static int +is_hostent_equal(struct hostent *he, struct addrinfo *ai) +{ + char **cp; + int rv; + +#ifdef DEBUG + printf("checking equality of he and ai\n"); +#endif + + rv = check_addrinfo_for_name(ai, he->h_name); + if (rv != 0) { + printf("not equal - he->h_name couldn't be found\n"); + return (rv); + } + + for (cp = he->h_addr_list; *cp; ++cp) { + rv = check_addrinfo_for_addr(ai, *cp, he->h_length, + he->h_addrtype); + if (rv != 0) { + printf("not equal - one of he->h_addr_list couldn't be found\n"); + return (rv); + } + } + +#ifdef DEBUG + printf("equal\n"); +#endif + + return (0); +} + +static void +sdump_hostent(struct hostent *ht, char *buffer, size_t buflen) +{ + char **cp; + size_t i; + int written; + + written = snprintf(buffer, buflen, "%s %d %d", + ht->h_name, ht->h_addrtype, ht->h_length); + buffer += written; + if (written > buflen) + return; + buflen -= written; + + if (ht->h_aliases != NULL) { + if (*(ht->h_aliases) != NULL) { + for (cp = ht->h_aliases; *cp; ++cp) { + written = snprintf(buffer, buflen, " %s",*cp); + buffer += written; + if (written > buflen) + return; + buflen -= written; + + if (buflen == 0) + return; + } + } else { + written = snprintf(buffer, buflen, " noaliases"); + buffer += written; + if (written > buflen) + return; + buflen -= written; + } + } else { + written = snprintf(buffer, buflen, " (null)"); + buffer += written; + if (written > buflen) + return; + buflen -= written; + } + + written = snprintf(buffer, buflen, " : "); + buffer += written; + if (written > buflen) + return; + buflen -= written; + + if (ht->h_addr_list != NULL) { + if (*(ht->h_addr_list) != NULL) { + for (cp = ht->h_addr_list; *cp; ++cp) { + for (i = 0; i < ht->h_length; ++i ) { + written = snprintf(buffer, buflen, + i + 1 != ht->h_length ? "%d." : "%d", + (unsigned char)(*cp)[i]); + buffer += written; + if (written > buflen) + return; + buflen -= written; + + if (buflen == 0) + return; + } + + if (*(cp + 1) ) { + written = snprintf(buffer, buflen, " "); + buffer += written; + if (written > buflen) + return; + buflen -= written; + } + } + } else { + written = snprintf(buffer, buflen, " noaddrs"); + buffer += written; + if (written > buflen) + return; + buflen -= written; + } + } else { + written = snprintf(buffer, buflen, " (null)"); + buffer += written; + if (written > buflen) + return; + buflen -= written; + } +} + +static int +hostent_read_hostlist_func(struct hostent *he, char *line) +{ + struct hostent *result; + int rv; + +#ifdef DEBUG + printf("resolving %s: ", line); +#endif + result = __gethostbyname2(line, af_type); + if (result != NULL) { +#ifdef DEBUG + printf("found\n"); +#endif + + rv = hostent_test_correctness(result, NULL); + if (rv != 0) { + __freehostent(result); + return (rv); + } + + clone_hostent(he, result); + __freehostent(result); + } else { +#ifdef DEBUG + printf("not found\n"); +#endif + memset(he, 0, sizeof(struct hostent)); + he->h_name = strdup(line); + ATF_REQUIRE(he->h_name != NULL); + } + return (0); +} + +static int +hostent_read_snapshot_addr(char *addr, unsigned char *result, size_t len) +{ + char *s, *ps, *ts; + + ps = addr; + while ( (s = strsep(&ps, ".")) != NULL) { + if (len == 0) + return (-1); + + *result = (unsigned char)strtol(s, &ts, 10); + ++result; + if (*ts != '\0') + return (-1); + + --len; + } + if (len != 0) + return (-1); + else + return (0); +} + +static int +hostent_read_snapshot_func(struct hostent *ht, char *line) +{ + StringList *sl1, *sl2; + char *s, *ps, *ts; + int i, rv; + +#ifdef DEBUG + printf("1 line read from snapshot:\n%s\n", line); +#endif + + rv = 0; + i = 0; + sl1 = sl2 = NULL; + ps = line; + memset(ht, 0, sizeof(struct hostent)); + while ((s = strsep(&ps, " ")) != NULL) { + switch (i) { + case 0: + ht->h_name = strdup(s); + ATF_REQUIRE(ht->h_name != NULL); + break; + + case 1: + ht->h_addrtype = (int)strtol(s, &ts, 10); + if (*ts != '\0') + goto fin; + break; + + case 2: + ht->h_length = (int)strtol(s, &ts, 10); + if (*ts != '\0') + goto fin; + break; + + case 3: + if (sl1 == NULL) { + if (strcmp(s, "(null)") == 0) + return (0); + + sl1 = sl_init(); + ATF_REQUIRE(sl1 != NULL); + + if (strcmp(s, "noaliases") != 0) { + ts = strdup(s); + ATF_REQUIRE(ts != NULL); + sl_add(sl1, ts); + } + } else { + if (strcmp(s, ":") == 0) + ++i; + else { + ts = strdup(s); + ATF_REQUIRE(ts != NULL); + sl_add(sl1, ts); + } + } + break; + + case 4: + if (sl2 == NULL) { + if (strcmp(s, "(null)") == 0) + return (0); + + sl2 = sl_init(); + ATF_REQUIRE(sl2 != NULL); + + if (strcmp(s, "noaddrs") != 0) { + ts = calloc(1, ht->h_length); + ATF_REQUIRE(ts != NULL); + rv = hostent_read_snapshot_addr(s, + (unsigned char *)ts, + ht->h_length); + sl_add(sl2, ts); + if (rv != 0) + goto fin; + } + } else { + ts = calloc(1, ht->h_length); + ATF_REQUIRE(ts != NULL); + rv = hostent_read_snapshot_addr(s, + (unsigned char *)ts, ht->h_length); + sl_add(sl2, ts); + if (rv != 0) + goto fin; + } + break; + default: + break; + } + + if (i != 3 && i != 4) + ++i; + } + +fin: + if (sl1 != NULL) { + sl_add(sl1, NULL); + ht->h_aliases = sl1->sl_str; + } + if (sl2 != NULL) { + sl_add(sl2, NULL); + ht->h_addr_list = sl2->sl_str; + } + + if ((i != 4) || (rv != 0)) { + free_hostent(ht); + memset(ht, 0, sizeof(struct hostent)); + return (-1); + } + + /* NOTE: is it a dirty hack or not? */ + free(sl1); + free(sl2); + return (0); +} + +static void +dump_hostent(struct hostent *result) +{ + if (result != NULL) { + char buffer[1024]; + sdump_hostent(result, buffer, sizeof(buffer)); + printf("%s\n", buffer); + } else + printf("(null)\n"); +} + +static int +hostent_test_correctness(struct hostent *ht, void *mdata) +{ + +#ifdef DEBUG + printf("testing correctness with the following data:\n"); + dump_hostent(ht); +#endif + + if (ht == NULL) + goto errfin; + + if (ht->h_name == NULL) + goto errfin; + + if (!((ht->h_addrtype >= 0) && (ht->h_addrtype < AF_MAX))) + goto errfin; + + if ((ht->h_length != sizeof(struct in_addr)) && + (ht->h_length != sizeof(struct in6_addr))) + goto errfin; + + if (ht->h_aliases == NULL) + goto errfin; + + if (ht->h_addr_list == NULL) + goto errfin; + +#ifdef DEBUG + printf("correct\n"); +#endif + + return (0); +errfin: + printf("incorrect\n"); + + return (-1); +} + +static int +hostent_test_gethostbyaddr(struct hostent *he, void *mdata) +{ + struct hostent *result; + struct hostent_test_data *addr_test_data; + int rv; + + addr_test_data = (struct hostent_test_data *)mdata; + + /* We should omit unresolved hostents */ + if (he->h_addr_list != NULL) { + char **cp; + for (cp = he->h_addr_list; *cp; ++cp) { +#ifdef DEBUG + printf("doing reverse lookup for %s\n", he->h_name); +#endif + + result = __gethostbyaddr(*cp, he->h_length, + he->h_addrtype); + if (result == NULL) { +#ifdef DEBUG + printf("%s: warning: reverse lookup failed " + "for %s: %s\n", __func__, he->h_name, + strerror(errno)); +#endif + continue; + } + rv = hostent_test_correctness(result, NULL); + if (rv != 0) { + __freehostent(result); + return (rv); + } + + if (addr_test_data != NULL) + TEST_DATA_APPEND(hostent, addr_test_data, + result); + + __freehostent(result); + } + } + + return (0); +} + +static int +hostent_test_getaddrinfo_eq(struct hostent *he, void *mdata) +{ + struct addrinfo *ai, hints; + int rv; + + ai = NULL; + memset(&hints, 0, sizeof(struct addrinfo)); + hints.ai_family = af_type; + hints.ai_flags = AI_CANONNAME; + + printf("using getaddrinfo() to resolve %s\n", he->h_name); + + /* struct hostent *he was not resolved */ + if (he->h_addr_list == NULL) { + /* We can be sure that he->h_name is not NULL */ + rv = getaddrinfo(he->h_name, NULL, &hints, &ai); + if (rv == 0) { + printf("not ok - shouldn't have been resolved\n"); + return (-1); + } + } else { + rv = getaddrinfo(he->h_name, NULL, &hints, &ai); + if (rv != 0) { + printf("not ok - should have been resolved\n"); + return (-1); + } + + rv = is_hostent_equal(he, ai); + if (rv != 0) { + printf("not ok - addrinfo and hostent are not equal\n"); + return (-1); + } + + } + + return (0); +} + +static int +hostent_test_getnameinfo_eq(struct hostent *he, void *mdata) +{ + char **cp; + char buffer[NI_MAXHOST]; + struct sockaddr_in sin; + struct sockaddr_in6 sin6; + struct sockaddr *saddr; + struct hostent *result; + int i, rv; + + if (he->h_addr_list == NULL) + return (0); + + for (cp = he->h_addr_list; *cp; ++cp) { +#ifdef DEBUG + printf("doing reverse lookup for %s\n", he->h_name); +#endif + result = __gethostbyaddr(*cp, he->h_length, + he->h_addrtype); + if (result != NULL) { + rv = hostent_test_correctness(result, NULL); + if (rv != 0) { + __freehostent(result); + return (rv); + } + } else + printf("%s: warning: reverse lookup failed " + "for %s: %s\n", __func__, he->h_name, + strerror(errno)); + + switch (he->h_addrtype) { + case AF_INET: + memset(&sin, 0, sizeof(struct sockaddr_in)); + sin.sin_len = sizeof(struct sockaddr_in); + sin.sin_family = AF_INET; + memcpy(&sin.sin_addr, *cp, he->h_length); + + saddr = (struct sockaddr *)&sin; + break; + case AF_INET6: + memset(&sin6, 0, sizeof(struct sockaddr_in6)); + sin6.sin6_len = sizeof(struct sockaddr_in6); + sin6.sin6_family = AF_INET6; + memcpy(&sin6.sin6_addr, *cp, he->h_length); + + saddr = (struct sockaddr *)&sin6; + break; + default: + printf("warning: %d family is unsupported\n", + he->h_addrtype); + continue; + } + + ATF_REQUIRE(saddr != NULL); + rv = getnameinfo(saddr, saddr->sa_len, buffer, + sizeof(buffer), NULL, 0, NI_NAMEREQD); + + if (rv != 0 && result != NULL) { + printf("getnameinfo() didn't make the reverse " + "lookup, when it should have (%s)\n", + gai_strerror(rv)); + return (rv); + } + + if (rv == 0 && result == NULL) { + printf("getnameinfo() made the " + "reverse lookup, when it shouldn't have\n"); + return (rv); + } + + if (rv != 0 && result == NULL) { +#ifdef DEBUG + printf("both getnameinfo() and ***byaddr() failed as " + "expected\n"); +#endif + continue; + } + +#ifdef DEBUG + printf("comparing %s with %s\n", result->h_name, + buffer); +#endif + + /* + * An address might reverse resolve to hostname alias or the + * official hostname, e.g. moon.vub.ac.be. + */ + bool found_a_match; + + if (strcmp(result->h_name, buffer) == 0) { + found_a_match = true; +#ifdef DEBUG + printf("matched official hostname\n"); +#endif + } else { + for (i = 0; i < nitems(result->h_aliases); i++) { + printf("[%d] resolved: %s\n", i, + result->h_aliases[i]); + if (strcmp(result->h_aliases[i], + buffer) == 0) { + printf("matched hostname alias\n"); + found_a_match = true; + break; + } + } + } + __freehostent(result); + + if (found_a_match) { +#ifdef DEBUG + printf("getnameinfo() and ***byaddr() results are " + "equal\n"); +#endif + } else { + printf("getnameinfo() and ***byaddr() results are not " + "equal for %s\n", he->h_name); + return (-1); + } + } + + return (0); +} + +int +run_tests(const char *hostlist_file, const char *snapshot_file, int af_type, + enum test_methods method, bool use_ipv6_mapping) +{ + struct hostent_test_data td, td_addr, td_snap; + res_state statp; + int rv = -2; + + switch (af_type) { + case AF_INET: + ATF_REQUIRE_FEATURE("inet"); + ATF_REQUIRE(!use_ipv6_mapping); + break; + case AF_INET6: + ATF_REQUIRE_FEATURE("inet6"); + break; + default: + atf_tc_fail("unhandled address family: %d", af_type); + break; + } + + if (!use_ipnode_functions) { + statp = __res_state(); + if (statp == NULL || ((statp->options & RES_INIT) == 0 && + res_ninit(statp) == -1)) { + printf("error: can't init res_state\n"); + + return (-1); + } + + if (use_ipv6_mapping) + statp->options |= RES_USE_INET6; + else + statp->options &= ~RES_USE_INET6; + } + + TEST_DATA_INIT(hostent, &td, clone_hostent, free_hostent); + TEST_DATA_INIT(hostent, &td_addr, clone_hostent, free_hostent); + TEST_DATA_INIT(hostent, &td_snap, clone_hostent, free_hostent); + + if (access(hostlist_file, R_OK) != 0) { + printf("can't access the hostlist file %s\n", hostlist_file); + rv = -1; + goto fin; + } + +#ifdef DEBUG + printf("building host lists from %s\n", hostlist_file); +#endif + + rv = TEST_SNAPSHOT_FILE_READ(hostent, hostlist_file, &td, + hostent_read_hostlist_func); + if (rv != 0) { + printf("failed to read the host list file: %s\n", + hostlist_file); + goto fin; + } + + if (snapshot_file != NULL) { + if (access(snapshot_file, W_OK | R_OK) != 0) { + if (errno == ENOENT) { + if (method != TEST_GETHOSTBYADDR) + method = TEST_BUILD_SNAPSHOT; + else + method = TEST_BUILD_ADDR_SNAPSHOT; + } else { + printf("can't access the snapshot file %s\n", + snapshot_file); + rv = -1; + goto fin; + } + } else { + rv = TEST_SNAPSHOT_FILE_READ(hostent, snapshot_file, + &td_snap, hostent_read_snapshot_func); + if (rv != 0) { + printf("error reading snapshot file\n"); + goto fin; + } + } + } + + switch (method) { + case TEST_GETHOSTBYNAME2: + if (snapshot_file != NULL) + rv = DO_2PASS_TEST(hostent, &td, &td_snap, + compare_hostent, NULL); + break; + case TEST_GETHOSTBYADDR: + rv = DO_1PASS_TEST(hostent, &td, + hostent_test_gethostbyaddr, (void *)&td_addr); + if (rv != 0) + goto fin; + + if (snapshot_file != NULL) + rv = DO_2PASS_TEST(hostent, &td_addr, &td_snap, + compare_hostent, NULL); + break; + case TEST_GETHOSTBYNAME2_GETADDRINFO: + rv = DO_1PASS_TEST(hostent, &td, + hostent_test_getaddrinfo_eq, NULL); + break; + case TEST_GETHOSTBYADDR_GETNAMEINFO: + rv = DO_1PASS_TEST(hostent, &td, + hostent_test_getnameinfo_eq, NULL); + break; + case TEST_BUILD_SNAPSHOT: + if (snapshot_file != NULL) { + rv = TEST_SNAPSHOT_FILE_WRITE(hostent, snapshot_file, + &td, sdump_hostent); + } + break; + case TEST_BUILD_ADDR_SNAPSHOT: + if (snapshot_file != NULL) { + rv = DO_1PASS_TEST(hostent, &td, + hostent_test_gethostbyaddr, (void *)&td_addr); + if (rv != 0) + goto fin; + rv = TEST_SNAPSHOT_FILE_WRITE(hostent, snapshot_file, + &td_addr, sdump_hostent); + } + break; + default: + rv = 0; + break; + } + +fin: + TEST_DATA_DESTROY(hostent, &td_snap); + TEST_DATA_DESTROY(hostent, &td_addr); + TEST_DATA_DESTROY(hostent, &td); + + return (rv); +} + +#define HOSTLIST_FILE "mach" + +#define _RUN_TESTS(tc, snapshot_file, af_type, method, use_ipv6_mapping) \ +do { \ + char *_hostlist_file; \ + char *_snapshot_file; \ + ATF_REQUIRE(0 < asprintf(&_hostlist_file, "%s/%s", \ + atf_tc_get_config_var(tc, "srcdir"), HOSTLIST_FILE)); \ + if (snapshot_file == NULL) \ + _snapshot_file = NULL; \ + else { \ + _snapshot_file = strdup(snapshot_file); \ + ATF_REQUIRE(_snapshot_file != NULL); \ + } \ + ATF_REQUIRE(run_tests(_hostlist_file, _snapshot_file, af_type, \ + method, use_ipv6_mapping) == 0); \ +} while(0) + +#define RUN_HOST_TESTS(tc, snapshot_file, af_type, method, use_ipv6_mapping) \ +do { \ + use_ipnode_functions = false; \ + _RUN_TESTS(tc, snapshot_file, af_type, method, use_ipv6_mapping); \ +} while(0) + +#define RUN_IPNODE_TESTS(tc, snapshot_file, af_type, method, use_ipv6_mapping) \ +do { \ + use_ipnode_functions = true; \ + _RUN_TESTS(tc, snapshot_file, af_type, method, use_ipv6_mapping); \ +} while(0) + +ATF_TC_WITHOUT_HEAD(gethostbyaddr_ipv4); +ATF_TC_BODY(gethostbyaddr_ipv4, tc) +{ + + RUN_HOST_TESTS(tc, NULL, AF_INET, TEST_GETHOSTBYADDR, false); +} + +ATF_TC_WITHOUT_HEAD(gethostbyaddr_ipv4_with_snapshot); +ATF_TC_BODY(gethostbyaddr_ipv4_with_snapshot, tc) +{ + + RUN_HOST_TESTS(tc, "snapshot_htaddr4", AF_INET, TEST_GETHOSTBYADDR, false); +} + +ATF_TC_WITHOUT_HEAD(gethostbyaddr_ipv6); +ATF_TC_BODY(gethostbyaddr_ipv6, tc) +{ + + RUN_HOST_TESTS(tc, NULL, AF_INET6, TEST_GETHOSTBYADDR, false); +} + +ATF_TC_WITHOUT_HEAD(gethostbyaddr_ipv6_AI_V4MAPPED); +ATF_TC_BODY(gethostbyaddr_ipv6_AI_V4MAPPED, tc) +{ + + ipnode_flags = AI_V4MAPPED; + RUN_HOST_TESTS(tc, NULL, AF_INET6, TEST_GETHOSTBYADDR, true); +} + +ATF_TC_WITHOUT_HEAD(gethostbyaddr_ipv6_with_snapshot); +ATF_TC_BODY(gethostbyaddr_ipv6_with_snapshot, tc) +{ + + RUN_HOST_TESTS(tc, "snapshot_htaddr6", AF_INET6, TEST_GETHOSTBYADDR, false); +} + +ATF_TC_WITHOUT_HEAD(gethostbyaddr_ipv6_with_snapshot_AI_V4MAPPED); +ATF_TC_BODY(gethostbyaddr_ipv6_with_snapshot_AI_V4MAPPED, tc) +{ + + ipnode_flags = AI_V4MAPPED; + RUN_HOST_TESTS(tc, "snapshot_htaddr6map", AF_INET6, TEST_GETHOSTBYADDR, true); +} + +ATF_TC_WITHOUT_HEAD(gethostbyname2_getaddrinfo_ipv4); +ATF_TC_BODY(gethostbyname2_getaddrinfo_ipv4, tc) +{ + + RUN_HOST_TESTS(tc, NULL, AF_INET, TEST_GETHOSTBYNAME2_GETADDRINFO, false); +} + +ATF_TC_WITHOUT_HEAD(gethostbyname2_getaddrinfo_ipv6); +ATF_TC_BODY(gethostbyname2_getaddrinfo_ipv6, tc) +{ + + RUN_HOST_TESTS(tc, NULL, AF_INET6, TEST_GETHOSTBYNAME2_GETADDRINFO, false); +} + +ATF_TC_WITHOUT_HEAD(gethostbyaddr_getnameinfo_ipv4); +ATF_TC_BODY(gethostbyaddr_getnameinfo_ipv4, tc) +{ + + RUN_HOST_TESTS(tc, NULL, AF_INET, TEST_GETHOSTBYADDR_GETNAMEINFO, false); +} + +ATF_TC_WITHOUT_HEAD(gethostbyaddr_getnameinfo_ipv6); +ATF_TC_BODY(gethostbyaddr_getnameinfo_ipv6, tc) +{ + + RUN_HOST_TESTS(tc, NULL, AF_INET6, TEST_GETHOSTBYADDR_GETNAMEINFO, false); +} + +ATF_TC_WITHOUT_HEAD(gethostbyname2_ipv4); +ATF_TC_BODY(gethostbyname2_ipv4, tc) +{ + + RUN_HOST_TESTS(tc, NULL, AF_INET, TEST_GETHOSTBYNAME2, false); +} + +ATF_TC_WITHOUT_HEAD(gethostbyname2_ipv4_with_snapshot); +ATF_TC_BODY(gethostbyname2_ipv4_with_snapshot, tc) +{ + + RUN_HOST_TESTS(tc, "snapshot_htname4", AF_INET, TEST_GETHOSTBYNAME2, false); +} + +ATF_TC_WITHOUT_HEAD(gethostbyname2_ipv6); +ATF_TC_BODY(gethostbyname2_ipv6, tc) +{ + + RUN_HOST_TESTS(tc, NULL, AF_INET6, TEST_GETHOSTBYNAME2, false); +} + +ATF_TC_WITHOUT_HEAD(gethostbyname2_ipv6_AI_V4MAPPED); +ATF_TC_BODY(gethostbyname2_ipv6_AI_V4MAPPED, tc) +{ + + ipnode_flags = AI_V4MAPPED; + RUN_HOST_TESTS(tc, NULL, AF_INET6, TEST_GETHOSTBYNAME2, true); +} + +ATF_TC_WITHOUT_HEAD(gethostbyname2_ipv6_with_snapshot); +ATF_TC_BODY(gethostbyname2_ipv6_with_snapshot, tc) +{ + + RUN_HOST_TESTS(tc, "snapshot_htname6", AF_INET6, TEST_GETHOSTBYNAME2, false); +} + +ATF_TC_WITHOUT_HEAD(gethostbyname2_ipv6_with_snapshot_AI_V4MAPPED); +ATF_TC_BODY(gethostbyname2_ipv6_with_snapshot_AI_V4MAPPED, tc) +{ + + ipnode_flags = AI_V4MAPPED; + RUN_HOST_TESTS(tc, "snapshot_htname6map", AF_INET6, TEST_GETHOSTBYNAME2, true); +} + +ATF_TC_WITHOUT_HEAD(getipnodebyaddr_ipv4); +ATF_TC_BODY(getipnodebyaddr_ipv4, tc) +{ + + RUN_IPNODE_TESTS(tc, NULL, AF_INET, TEST_GETHOSTBYADDR, false); +} + +ATF_TC_WITHOUT_HEAD(getipnodebyaddr_ipv4_with_snapshot); +ATF_TC_BODY(getipnodebyaddr_ipv4_with_snapshot, tc) +{ + + RUN_IPNODE_TESTS(tc, "snapshot_ipnodeaddr4", AF_INET, TEST_GETHOSTBYADDR, false); +} + +ATF_TC_WITHOUT_HEAD(getipnodebyaddr_getnameinfo_ipv4); +ATF_TC_BODY(getipnodebyaddr_getnameinfo_ipv4, tc) +{ + + RUN_IPNODE_TESTS(tc, NULL, AF_INET, TEST_GETHOSTBYADDR_GETNAMEINFO, false); +} + +ATF_TC_WITHOUT_HEAD(getipnodebyaddr_ipv6); +ATF_TC_BODY(getipnodebyaddr_ipv6, tc) +{ + + RUN_IPNODE_TESTS(tc, NULL, AF_INET6, TEST_GETHOSTBYADDR, false); +} + +ATF_TC_WITHOUT_HEAD(getipnodebyaddr_ipv6_AI_V4MAPPED); +ATF_TC_BODY(getipnodebyaddr_ipv6_AI_V4MAPPED, tc) +{ + + ipnode_flags = AI_V4MAPPED; + RUN_IPNODE_TESTS(tc, NULL, AF_INET6, TEST_GETHOSTBYADDR, true); +} + +ATF_TC_WITHOUT_HEAD(getipnodebyaddr_ipv6_AI_V4MAPPED_CFG); +ATF_TC_BODY(getipnodebyaddr_ipv6_AI_V4MAPPED_CFG, tc) +{ + + ipnode_flags = AI_V4MAPPED_CFG; + RUN_IPNODE_TESTS(tc, NULL, AF_INET6, TEST_GETHOSTBYADDR, true); +} + +ATF_TC_WITHOUT_HEAD(getipnodebyaddr_ipv6_AI_V4MAPPED_CFG_AI_ALL); +ATF_TC_BODY(getipnodebyaddr_ipv6_AI_V4MAPPED_CFG_AI_ALL, tc) +{ + + ipnode_flags = AI_V4MAPPED_CFG | AI_ALL; + RUN_IPNODE_TESTS(tc, NULL, AF_INET6, TEST_GETHOSTBYADDR, true); +} + +ATF_TC_WITHOUT_HEAD(getipnodebyaddr_ipv6_with_snapshot); +ATF_TC_BODY(getipnodebyaddr_ipv6_with_snapshot, tc) +{ + + RUN_IPNODE_TESTS(tc, "snapshot_ipnodeaddr6", AF_INET6, TEST_GETHOSTBYADDR, false); +} + +ATF_TC_WITHOUT_HEAD(getipnodebyaddr_ipv6_with_snapshot_AI_V4MAPPED); +ATF_TC_BODY(getipnodebyaddr_ipv6_with_snapshot_AI_V4MAPPED, tc) +{ + + ipnode_flags = AI_V4MAPPED; + RUN_IPNODE_TESTS(tc, + "snapshot_ipnodeaddr6_AI_V4MAPPED", AF_INET6, + TEST_GETHOSTBYADDR, true); +} + +ATF_TC_WITHOUT_HEAD(getipnodebyaddr_ipv6_with_snapshot_AI_V4MAPPED_CFG); +ATF_TC_BODY(getipnodebyaddr_ipv6_with_snapshot_AI_V4MAPPED_CFG, tc) +{ + + ipnode_flags = AI_V4MAPPED_CFG; + RUN_IPNODE_TESTS(tc, + "snapshot_ipnodeaddr6_AI_V4MAPPED_CFG", AF_INET6, + TEST_GETHOSTBYADDR, true); +} + +ATF_TC_WITHOUT_HEAD(getipnodebyaddr_ipv6_with_snapshot_AI_V4MAPPED_CFG_AI_ALL); +ATF_TC_BODY(getipnodebyaddr_ipv6_with_snapshot_AI_V4MAPPED_CFG_AI_ALL, tc) +{ + + ipnode_flags = AI_V4MAPPED_CFG | AI_ALL; + RUN_IPNODE_TESTS(tc, + "snapshot_ipnodeaddr6_AI_V4MAPPED_CFG_AI_ALL", AF_INET6, + TEST_GETHOSTBYADDR, true); +} + +ATF_TC_WITHOUT_HEAD(getipnodebyaddr_getnameinfo_ipv6); +ATF_TC_BODY(getipnodebyaddr_getnameinfo_ipv6, tc) +{ + + RUN_IPNODE_TESTS(tc, NULL, AF_INET6, TEST_GETHOSTBYADDR_GETNAMEINFO, false); +} + +ATF_TC_WITHOUT_HEAD(getipnodebyname_ipv4); +ATF_TC_BODY(getipnodebyname_ipv4, tc) +{ + + RUN_IPNODE_TESTS(tc, NULL, AF_INET, TEST_GETHOSTBYNAME2, false); +} + +ATF_TC_WITHOUT_HEAD(getipnodebyname_ipv4_with_snapshot); +ATF_TC_BODY(getipnodebyname_ipv4_with_snapshot, tc) +{ + + RUN_IPNODE_TESTS(tc, "snapshot_ipnodename4", AF_INET, TEST_GETHOSTBYNAME2, false); +} + +ATF_TC_WITHOUT_HEAD(getipnodebyname_ipv4_AI_ADDRCONFIG); +ATF_TC_BODY(getipnodebyname_ipv4_AI_ADDRCONFIG, tc) +{ + + ipnode_flags = AI_ADDRCONFIG; + RUN_IPNODE_TESTS(tc, NULL, AF_INET, TEST_GETHOSTBYNAME2, false); +} + +ATF_TC_WITHOUT_HEAD(getipnodebyname_ipv4_with_snapshot_AI_ADDRCONFIG); +ATF_TC_BODY(getipnodebyname_ipv4_with_snapshot_AI_ADDRCONFIG, tc) +{ + + ipnode_flags = AI_ADDRCONFIG; + RUN_IPNODE_TESTS(tc, "snapshot_ipnodename4_AI_ADDRCONFIG", AF_INET, + TEST_GETHOSTBYNAME2, false); +} + +ATF_TC_WITHOUT_HEAD(getipnodebyname_getaddrinfo_ipv4); +ATF_TC_BODY(getipnodebyname_getaddrinfo_ipv4, tc) +{ + + RUN_IPNODE_TESTS(tc, NULL, AF_INET, TEST_GETHOSTBYNAME2_GETADDRINFO, false); +} + +ATF_TC_WITHOUT_HEAD(getipnodebyname_ipv6); +ATF_TC_BODY(getipnodebyname_ipv6, tc) +{ + + RUN_IPNODE_TESTS(tc, NULL, AF_INET6, TEST_GETHOSTBYNAME2, false); +} + +ATF_TC_WITHOUT_HEAD(getipnodebyname_ipv6_with_snapshot); +ATF_TC_BODY(getipnodebyname_ipv6_with_snapshot, tc) +{ + + RUN_IPNODE_TESTS(tc, "snapshot_ipnodename6", AF_INET6, TEST_GETHOSTBYNAME2, false); +} + +ATF_TC_WITHOUT_HEAD(getipnodebyname_ipv6_AI_ADDRCONFIG); +ATF_TC_BODY(getipnodebyname_ipv6_AI_ADDRCONFIG, tc) +{ + + ipnode_flags = AI_ADDRCONFIG; + RUN_IPNODE_TESTS(tc, NULL, AF_INET6, TEST_GETHOSTBYNAME2, false); +} + +ATF_TC_WITHOUT_HEAD(getipnodebyname_ipv6_AI_V4MAPPED); +ATF_TC_BODY(getipnodebyname_ipv6_AI_V4MAPPED, tc) +{ + + ipnode_flags = AI_V4MAPPED; + RUN_IPNODE_TESTS(tc, NULL, AF_INET6, TEST_GETHOSTBYNAME2, true); +} + +ATF_TC_WITHOUT_HEAD(getipnodebyname_ipv6_AI_V4MAPPED_CFG); +ATF_TC_BODY(getipnodebyname_ipv6_AI_V4MAPPED_CFG, tc) +{ + + ipnode_flags = AI_V4MAPPED_CFG; + RUN_IPNODE_TESTS(tc, NULL, AF_INET6, TEST_GETHOSTBYNAME2, true); +} + +ATF_TC_WITHOUT_HEAD(getipnodebyname_ipv6_AI_V4MAPPED_CFG_AI_ADDRCONFIG); +ATF_TC_BODY(getipnodebyname_ipv6_AI_V4MAPPED_CFG_AI_ADDRCONFIG, tc) +{ + + ipnode_flags = AI_V4MAPPED_CFG | AI_ADDRCONFIG; + RUN_IPNODE_TESTS(tc, NULL, AF_INET6, TEST_GETHOSTBYNAME2, false); +} + +ATF_TC_WITHOUT_HEAD(getipnodebyname_ipv6_AI_V4MAPPED_CFG_AI_ALL); +ATF_TC_BODY(getipnodebyname_ipv6_AI_V4MAPPED_CFG_AI_ALL, tc) +{ + + ipnode_flags = AI_V4MAPPED_CFG | AI_ALL; + RUN_IPNODE_TESTS(tc, NULL, AF_INET6, TEST_GETHOSTBYNAME2, true); +} + +ATF_TC_WITHOUT_HEAD(getipnodebyname_ipv6_with_snapshot_AI_V4MAPPED); +ATF_TC_BODY(getipnodebyname_ipv6_with_snapshot_AI_V4MAPPED, tc) +{ + + ipnode_flags = AI_V4MAPPED; + RUN_IPNODE_TESTS(tc, + "snapshot_ipnodename6_AI_V4MAPPED", AF_INET6, + TEST_GETHOSTBYNAME2, true); +} + +ATF_TC_WITHOUT_HEAD(getipnodebyname_ipv6_with_snapshot_AI_V4MAPPED_CFG); +ATF_TC_BODY(getipnodebyname_ipv6_with_snapshot_AI_V4MAPPED_CFG, tc) +{ + + ipnode_flags = AI_V4MAPPED_CFG; + RUN_IPNODE_TESTS(tc, + "snapshot_ipnodename6_AI_V4MAPPED_CFG", AF_INET6, + TEST_GETHOSTBYNAME2, true); +} + +ATF_TC_WITHOUT_HEAD(getipnodebyname_ipv6_with_snapshot_AI_V4MAPPED_CFG_AI_ADDRCONFIG); +ATF_TC_BODY(getipnodebyname_ipv6_with_snapshot_AI_V4MAPPED_CFG_AI_ADDRCONFIG, tc) +{ + + ipnode_flags = AI_V4MAPPED_CFG | AI_ADDRCONFIG; + RUN_IPNODE_TESTS(tc, + "snapshot_ipnodename6_AI_V4MAPPED_CFG_AI_ADDRCONFIG", AF_INET6, + TEST_GETHOSTBYNAME2, false); +} + +ATF_TC_WITHOUT_HEAD(getipnodebyname_ipv6_with_snapshot_AI_V4MAPPED_CFG_AI_ALL); +ATF_TC_BODY(getipnodebyname_ipv6_with_snapshot_AI_V4MAPPED_CFG_AI_ALL, tc) +{ + + ipnode_flags = AI_V4MAPPED_CFG | AI_ALL; + RUN_IPNODE_TESTS(tc, + "snapshot_ipnodename6_AI_V4MAPPED_CFG_AI_ALL", AF_INET6, + TEST_GETHOSTBYNAME2, true); +} + +ATF_TC_WITHOUT_HEAD(getipnodebyname_ipv6_with_snapshot_AI_ADDRCONFIG); +ATF_TC_BODY(getipnodebyname_ipv6_with_snapshot_AI_ADDRCONFIG, tc) +{ + + ipnode_flags = AI_ADDRCONFIG; + RUN_IPNODE_TESTS(tc, "snapshot_ipnodename6_AI_ADDRCONFIG", AF_INET6, + TEST_GETHOSTBYNAME2, false); +} + +ATF_TC_WITHOUT_HEAD(getipnodebyname_getaddrinfo_ipv6); +ATF_TC_BODY(getipnodebyname_getaddrinfo_ipv6, tc) +{ + + RUN_IPNODE_TESTS(tc, NULL, AF_INET6, TEST_GETHOSTBYNAME2_GETADDRINFO, false); +} + +ATF_TP_ADD_TCS(tp) +{ + + /* gethostbyaddr */ + ATF_TP_ADD_TC(tp, gethostbyaddr_ipv4); + ATF_TP_ADD_TC(tp, gethostbyaddr_ipv4_with_snapshot); + ATF_TP_ADD_TC(tp, gethostbyaddr_ipv6); + ATF_TP_ADD_TC(tp, gethostbyaddr_ipv6_AI_V4MAPPED); /* XXX */ + ATF_TP_ADD_TC(tp, gethostbyaddr_ipv6_with_snapshot); + ATF_TP_ADD_TC(tp, gethostbyaddr_ipv6_with_snapshot_AI_V4MAPPED); + ATF_TP_ADD_TC(tp, gethostbyaddr_getnameinfo_ipv4); + ATF_TP_ADD_TC(tp, gethostbyaddr_getnameinfo_ipv6); + + /* gethostbyname2 */ + ATF_TP_ADD_TC(tp, gethostbyname2_getaddrinfo_ipv4); + ATF_TP_ADD_TC(tp, gethostbyname2_getaddrinfo_ipv6); + ATF_TP_ADD_TC(tp, gethostbyname2_ipv4); + ATF_TP_ADD_TC(tp, gethostbyname2_ipv4_with_snapshot); + ATF_TP_ADD_TC(tp, gethostbyname2_ipv6); + ATF_TP_ADD_TC(tp, gethostbyname2_ipv6_AI_V4MAPPED); + ATF_TP_ADD_TC(tp, gethostbyname2_ipv6_with_snapshot); + ATF_TP_ADD_TC(tp, gethostbyname2_ipv6_with_snapshot_AI_V4MAPPED); + + /* getipnodebyaddr */ + ATF_TP_ADD_TC(tp, getipnodebyaddr_ipv4); + ATF_TP_ADD_TC(tp, getipnodebyaddr_ipv4_with_snapshot); + ATF_TP_ADD_TC(tp, getipnodebyaddr_getnameinfo_ipv4); + ATF_TP_ADD_TC(tp, getipnodebyaddr_ipv6); + ATF_TP_ADD_TC(tp, getipnodebyaddr_ipv6_AI_V4MAPPED); + ATF_TP_ADD_TC(tp, getipnodebyaddr_ipv6_AI_V4MAPPED_CFG); + ATF_TP_ADD_TC(tp, getipnodebyaddr_ipv6_AI_V4MAPPED_CFG_AI_ALL); + ATF_TP_ADD_TC(tp, getipnodebyaddr_ipv6_with_snapshot); + ATF_TP_ADD_TC(tp, getipnodebyaddr_ipv6_with_snapshot_AI_V4MAPPED); + ATF_TP_ADD_TC(tp, getipnodebyaddr_ipv6_with_snapshot_AI_V4MAPPED_CFG); + ATF_TP_ADD_TC(tp, getipnodebyaddr_ipv6_with_snapshot_AI_V4MAPPED_CFG_AI_ALL); + ATF_TP_ADD_TC(tp, getipnodebyaddr_getnameinfo_ipv6); + + /* getipnodebyname */ + ATF_TP_ADD_TC(tp, getipnodebyname_ipv4); + ATF_TP_ADD_TC(tp, getipnodebyname_ipv4_with_snapshot); + ATF_TP_ADD_TC(tp, getipnodebyname_ipv4_AI_ADDRCONFIG); + ATF_TP_ADD_TC(tp, getipnodebyname_ipv4_with_snapshot_AI_ADDRCONFIG); + ATF_TP_ADD_TC(tp, getipnodebyname_getaddrinfo_ipv4); + ATF_TP_ADD_TC(tp, getipnodebyname_ipv6); + ATF_TP_ADD_TC(tp, getipnodebyname_ipv6_with_snapshot); + ATF_TP_ADD_TC(tp, getipnodebyname_ipv6_AI_ADDRCONFIG); + ATF_TP_ADD_TC(tp, getipnodebyname_ipv6_AI_V4MAPPED); + ATF_TP_ADD_TC(tp, getipnodebyname_ipv6_AI_V4MAPPED_CFG); + ATF_TP_ADD_TC(tp, getipnodebyname_ipv6_AI_V4MAPPED_CFG_AI_ADDRCONFIG); + ATF_TP_ADD_TC(tp, getipnodebyname_ipv6_AI_V4MAPPED_CFG_AI_ALL); + ATF_TP_ADD_TC(tp, getipnodebyname_ipv6_with_snapshot_AI_V4MAPPED); + ATF_TP_ADD_TC(tp, getipnodebyname_ipv6_with_snapshot_AI_V4MAPPED_CFG); + ATF_TP_ADD_TC(tp, getipnodebyname_ipv6_with_snapshot_AI_V4MAPPED_CFG_AI_ADDRCONFIG); + ATF_TP_ADD_TC(tp, getipnodebyname_ipv6_with_snapshot_AI_V4MAPPED_CFG_AI_ALL); + ATF_TP_ADD_TC(tp, getipnodebyname_ipv6_with_snapshot_AI_ADDRCONFIG); + ATF_TP_ADD_TC(tp, getipnodebyname_getaddrinfo_ipv6); + + return (atf_no_error()); +} diff --git a/lib/libc/tests/nss/getproto_test.c b/lib/libc/tests/nss/getproto_test.c new file mode 100644 index 0000000..fdb6804 --- /dev/null +++ b/lib/libc/tests/nss/getproto_test.c @@ -0,0 +1,556 @@ +/*- + * Copyright (c) 2006 Michael Bushkov + * 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 + +#include + +#include "testutil.h" + +enum test_methods { + TEST_GETPROTOENT, + TEST_GETPROTOBYNAME, + TEST_GETPROTOBYNUMBER, + TEST_GETPROTOENT_2PASS, + TEST_BUILD_SNAPSHOT +}; + +DECLARE_TEST_DATA(protoent) +DECLARE_TEST_FILE_SNAPSHOT(protoent) +DECLARE_1PASS_TEST(protoent) +DECLARE_2PASS_TEST(protoent) + +static void clone_protoent(struct protoent *, struct protoent const *); +static int compare_protoent(struct protoent *, struct protoent *, void *); +static void dump_protoent(struct protoent *); +static void free_protoent(struct protoent *); + +static void sdump_protoent(struct protoent *, char *, size_t); +static int protoent_read_snapshot_func(struct protoent *, char *); + +static int protoent_check_ambiguity(struct protoent_test_data *, + struct protoent *); +static int protoent_fill_test_data(struct protoent_test_data *); +static int protoent_test_correctness(struct protoent *, void *); +static int protoent_test_getprotobyname(struct protoent *, void *); +static int protoent_test_getprotobynumber(struct protoent *, void *); +static int protoent_test_getprotoent(struct protoent *, void *); + +IMPLEMENT_TEST_DATA(protoent) +IMPLEMENT_TEST_FILE_SNAPSHOT(protoent) +IMPLEMENT_1PASS_TEST(protoent) +IMPLEMENT_2PASS_TEST(protoent) + +static void +clone_protoent(struct protoent *dest, struct protoent const *src) +{ + assert(dest != NULL); + assert(src != NULL); + + char **cp; + int aliases_num; + + memset(dest, 0, sizeof(struct protoent)); + + if (src->p_name != NULL) { + dest->p_name = strdup(src->p_name); + assert(dest->p_name != NULL); + } + + dest->p_proto = src->p_proto; + + if (src->p_aliases != NULL) { + aliases_num = 0; + for (cp = src->p_aliases; *cp; ++cp) + ++aliases_num; + + dest->p_aliases = calloc(1, (aliases_num+1) * sizeof(char *)); + assert(dest->p_aliases != NULL); + + for (cp = src->p_aliases; *cp; ++cp) { + dest->p_aliases[cp - src->p_aliases] = strdup(*cp); + assert(dest->p_aliases[cp - src->p_aliases] != NULL); + } + } +} + +static void +free_protoent(struct protoent *pe) +{ + char **cp; + + assert(pe != NULL); + + free(pe->p_name); + + for (cp = pe->p_aliases; *cp; ++cp) + free(*cp); + free(pe->p_aliases); +} + +static int +compare_protoent(struct protoent *pe1, struct protoent *pe2, void *mdata) +{ + char **c1, **c2; + + if (pe1 == pe2) + return 0; + + if ((pe1 == NULL) || (pe2 == NULL)) + goto errfin; + + if ((strcmp(pe1->p_name, pe2->p_name) != 0) || + (pe1->p_proto != pe2->p_proto)) + goto errfin; + + c1 = pe1->p_aliases; + c2 = pe2->p_aliases; + + if ((pe1->p_aliases == NULL) || (pe2->p_aliases == NULL)) + goto errfin; + + for (;*c1 && *c2; ++c1, ++c2) + if (strcmp(*c1, *c2) != 0) + goto errfin; + + if ((*c1 != '\0') || (*c2 != '\0')) + goto errfin; + + return 0; + +errfin: + if (mdata == NULL) { + printf("following structures are not equal:\n"); + dump_protoent(pe1); + dump_protoent(pe2); + } + + return (-1); +} + +static void +sdump_protoent(struct protoent *pe, char *buffer, size_t buflen) +{ + char **cp; + int written; + + written = snprintf(buffer, buflen, "%s %d", + pe->p_name, pe->p_proto); + buffer += written; + if (written > buflen) + return; + buflen -= written; + + if (pe->p_aliases != NULL) { + if (*(pe->p_aliases) != '\0') { + for (cp = pe->p_aliases; *cp; ++cp) { + written = snprintf(buffer, buflen, " %s",*cp); + buffer += written; + if (written > buflen) + return; + buflen -= written; + + if (buflen == 0) + return; + } + } else + snprintf(buffer, buflen, " noaliases"); + } else + snprintf(buffer, buflen, " (null)"); +} + +static int +protoent_read_snapshot_func(struct protoent *pe, char *line) +{ + StringList *sl; + char *s, *ps, *ts; + int i; + + printf("1 line read from snapshot:\n%s\n", line); + + i = 0; + sl = NULL; + ps = line; + memset(pe, 0, sizeof(struct protoent)); + while ( (s = strsep(&ps, " ")) != NULL) { + switch (i) { + case 0: + pe->p_name = strdup(s); + assert(pe->p_name != NULL); + break; + + case 1: + pe->p_proto = (int)strtol(s, &ts, 10); + if (*ts != '\0') { + free(pe->p_name); + return (-1); + } + break; + + default: + if (sl == NULL) { + if (strcmp(s, "(null)") == 0) + return (0); + + sl = sl_init(); + assert(sl != NULL); + + if (strcmp(s, "noaliases") != 0) { + ts = strdup(s); + assert(ts != NULL); + sl_add(sl, ts); + } + } else { + ts = strdup(s); + assert(ts != NULL); + sl_add(sl, ts); + } + break; + } + ++i; + } + + if (i < 3) { + free(pe->p_name); + memset(pe, 0, sizeof(struct protoent)); + return (-1); + } + + sl_add(sl, NULL); + pe->p_aliases = sl->sl_str; + + /* NOTE: is it a dirty hack or not? */ + free(sl); + return (0); +} + +static void +dump_protoent(struct protoent *result) +{ + if (result != NULL) { + char buffer[1024]; + sdump_protoent(result, buffer, sizeof(buffer)); + printf("%s\n", buffer); + } else + printf("(null)\n"); +} + +static int +protoent_fill_test_data(struct protoent_test_data *td) +{ + struct protoent *pe; + + setprotoent(1); + while ((pe = getprotoent()) != NULL) { + if (protoent_test_correctness(pe, NULL) == 0) + TEST_DATA_APPEND(protoent, td, pe); + else + return (-1); + } + endprotoent(); + + return (0); +} + +static int +protoent_test_correctness(struct protoent *pe, void *mdata) +{ + printf("testing correctness with the following data:\n"); + dump_protoent(pe); + + if (pe == NULL) + goto errfin; + + if (pe->p_name == NULL) + goto errfin; + + if (pe->p_proto < 0) + goto errfin; + + if (pe->p_aliases == NULL) + goto errfin; + + printf("correct\n"); + + return (0); +errfin: + printf("incorrect\n"); + + return (-1); +} + +/* protoent_check_ambiguity() is needed when one port+proto is associated with + * more than one peice (these cases are usually marked as PROBLEM in + * /etc/peices. This functions is needed also when one peice+proto is + * associated with several ports. We have to check all the protoent structures + * to make sure that pe really exists and correct */ +static int +protoent_check_ambiguity(struct protoent_test_data *td, struct protoent *pe) +{ + + return (TEST_DATA_FIND(protoent, td, pe, compare_protoent, + NULL) != NULL ? 0 : -1); +} + +static int +protoent_test_getprotobyname(struct protoent *pe_model, void *mdata) +{ + char **alias; + struct protoent *pe; + + printf("testing getprotobyname() with the following data:\n"); + dump_protoent(pe_model); + + pe = getprotobyname(pe_model->p_name); + if (protoent_test_correctness(pe, NULL) != 0) + goto errfin; + + if ((compare_protoent(pe, pe_model, NULL) != 0) && + (protoent_check_ambiguity((struct protoent_test_data *)mdata, pe) + !=0)) + goto errfin; + + for (alias = pe_model->p_aliases; *alias; ++alias) { + pe = getprotobyname(*alias); + + if (protoent_test_correctness(pe, NULL) != 0) + goto errfin; + + if ((compare_protoent(pe, pe_model, NULL) != 0) && + (protoent_check_ambiguity( + (struct protoent_test_data *)mdata, pe) != 0)) + goto errfin; + } + + printf("ok\n"); + return (0); + +errfin: + printf("not ok\n"); + + return (-1); +} + +static int +protoent_test_getprotobynumber(struct protoent *pe_model, void *mdata) +{ + struct protoent *pe; + + printf("testing getprotobyport() with the following data...\n"); + dump_protoent(pe_model); + + pe = getprotobynumber(pe_model->p_proto); + if ((protoent_test_correctness(pe, NULL) != 0) || + ((compare_protoent(pe, pe_model, NULL) != 0) && + (protoent_check_ambiguity((struct protoent_test_data *)mdata, pe) + != 0))) { + printf("not ok\n"); + return (-1); + } else { + printf("ok\n"); + return (0); + } +} + +static int +protoent_test_getprotoent(struct protoent *pe, void *mdata) +{ + /* Only correctness can be checked when doing 1-pass test for + * getprotoent(). */ + return (protoent_test_correctness(pe, NULL)); +} + +int +run_tests(const char *snapshot_file, enum test_methods method) +{ + struct protoent_test_data td, td_snap, td_2pass; + int rv; + + TEST_DATA_INIT(protoent, &td, clone_protoent, free_protoent); + TEST_DATA_INIT(protoent, &td_snap, clone_protoent, free_protoent); + if (snapshot_file != NULL) { + if (access(snapshot_file, W_OK | R_OK) != 0) { + if (errno == ENOENT) + method = TEST_BUILD_SNAPSHOT; + else { + printf("can't access the file %s\n", + snapshot_file); + + rv = -1; + goto fin; + } + } else { + if (method == TEST_BUILD_SNAPSHOT) { + rv = 0; + goto fin; + } + + TEST_SNAPSHOT_FILE_READ(protoent, snapshot_file, + &td_snap, protoent_read_snapshot_func); + } + } + + rv = protoent_fill_test_data(&td); + if (rv == -1) + return (-1); + switch (method) { + case TEST_GETPROTOBYNAME: + if (snapshot_file == NULL) + rv = DO_1PASS_TEST(protoent, &td, + protoent_test_getprotobyname, (void *)&td); + else + rv = DO_1PASS_TEST(protoent, &td_snap, + protoent_test_getprotobyname, (void *)&td_snap); + break; + case TEST_GETPROTOBYNUMBER: + if (snapshot_file == NULL) + rv = DO_1PASS_TEST(protoent, &td, + protoent_test_getprotobynumber, (void *)&td); + else + rv = DO_1PASS_TEST(protoent, &td_snap, + protoent_test_getprotobynumber, (void *)&td_snap); + break; + case TEST_GETPROTOENT: + if (snapshot_file == NULL) + rv = DO_1PASS_TEST(protoent, &td, + protoent_test_getprotoent, (void *)&td); + else + rv = DO_2PASS_TEST(protoent, &td, &td_snap, + compare_protoent, NULL); + break; + case TEST_GETPROTOENT_2PASS: + TEST_DATA_INIT(protoent, &td_2pass, clone_protoent, + free_protoent); + rv = protoent_fill_test_data(&td_2pass); + if (rv != -1) + rv = DO_2PASS_TEST(protoent, &td, &td_2pass, + compare_protoent, NULL); + TEST_DATA_DESTROY(protoent, &td_2pass); + break; + case TEST_BUILD_SNAPSHOT: + if (snapshot_file != NULL) + rv = TEST_SNAPSHOT_FILE_WRITE(protoent, snapshot_file, + &td, sdump_protoent); + break; + default: + rv = 0; + break; + } + +fin: + TEST_DATA_DESTROY(protoent, &td_snap); + TEST_DATA_DESTROY(protoent, &td); + + return (rv); +} + +#define SNAPSHOT_FILE "snapshot_proto" + +ATF_TC_WITHOUT_HEAD(build_snapshot); +ATF_TC_BODY(build_snapshot, tc) +{ + + ATF_REQUIRE(run_tests(SNAPSHOT_FILE, TEST_BUILD_SNAPSHOT) == 0); +} + +ATF_TC_WITHOUT_HEAD(getprotoent); +ATF_TC_BODY(getprotoent, tc) +{ + + ATF_REQUIRE(run_tests(NULL, TEST_GETPROTOENT) == 0); +} + +ATF_TC_WITHOUT_HEAD(getprotoent_with_snapshot); +ATF_TC_BODY(getprotoent_with_snapshot, tc) +{ + + ATF_REQUIRE(run_tests(SNAPSHOT_FILE, TEST_BUILD_SNAPSHOT) == 0); + ATF_REQUIRE(run_tests(SNAPSHOT_FILE, TEST_GETPROTOENT) == 0); +} + +ATF_TC_WITHOUT_HEAD(getprotoent_with_two_pass); +ATF_TC_BODY(getprotoent_with_two_pass, tc) +{ + + ATF_REQUIRE(run_tests(NULL, TEST_GETPROTOENT_2PASS) == 0); +} + +ATF_TC_WITHOUT_HEAD(getprotobyname); +ATF_TC_BODY(getprotobyname, tc) +{ + + ATF_REQUIRE(run_tests(NULL, TEST_GETPROTOBYNAME) == 0); +} + +ATF_TC_WITHOUT_HEAD(getprotobyname_with_snapshot); +ATF_TC_BODY(getprotobyname_with_snapshot, tc) +{ + + ATF_REQUIRE(run_tests(SNAPSHOT_FILE, TEST_BUILD_SNAPSHOT) == 0); + ATF_REQUIRE(run_tests(SNAPSHOT_FILE, TEST_GETPROTOBYNAME) == 0); +} + +ATF_TC_WITHOUT_HEAD(getprotobynumber); +ATF_TC_BODY(getprotobynumber, tc) +{ + + ATF_REQUIRE(run_tests(NULL, TEST_GETPROTOBYNUMBER) == 0); +} + +ATF_TC_WITHOUT_HEAD(getprotobynumber_with_snapshot); +ATF_TC_BODY(getprotobynumber_with_snapshot, tc) +{ + + ATF_REQUIRE(run_tests(SNAPSHOT_FILE, TEST_BUILD_SNAPSHOT) == 0); + ATF_REQUIRE(run_tests(SNAPSHOT_FILE, TEST_GETPROTOBYNUMBER) == 0); +} + +ATF_TP_ADD_TCS(tp) +{ + + ATF_TP_ADD_TC(tp, build_snapshot); + ATF_TP_ADD_TC(tp, getprotoent); + ATF_TP_ADD_TC(tp, getprotoent_with_snapshot); + ATF_TP_ADD_TC(tp, getprotoent_with_two_pass); + ATF_TP_ADD_TC(tp, getprotobyname); + ATF_TP_ADD_TC(tp, getprotobyname_with_snapshot); + ATF_TP_ADD_TC(tp, getprotobynumber); + ATF_TP_ADD_TC(tp, getprotobynumber_with_snapshot); + + return (atf_no_error()); +} diff --git a/lib/libc/tests/nss/getpw_test.c b/lib/libc/tests/nss/getpw_test.c new file mode 100644 index 0000000..98f890f --- /dev/null +++ b/lib/libc/tests/nss/getpw_test.c @@ -0,0 +1,530 @@ +/*- + * Copyright (c) 2006 Michael Bushkov + * 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 "testutil.h" + +enum test_methods { + TEST_GETPWENT, + TEST_GETPWNAM, + TEST_GETPWUID, + TEST_GETPWENT_2PASS, + TEST_BUILD_SNAPSHOT +}; + +static enum test_methods method = TEST_BUILD_SNAPSHOT; + +DECLARE_TEST_DATA(passwd) +DECLARE_TEST_FILE_SNAPSHOT(passwd) +DECLARE_1PASS_TEST(passwd) +DECLARE_2PASS_TEST(passwd) + +static void clone_passwd(struct passwd *, struct passwd const *); +static int compare_passwd(struct passwd *, struct passwd *, void *); +static void free_passwd(struct passwd *); + +static void sdump_passwd(struct passwd *, char *, size_t); +static void dump_passwd(struct passwd *); + +static int passwd_read_snapshot_func(struct passwd *, char *); + +static int passwd_check_ambiguity(struct passwd_test_data *, struct passwd *); +static int passwd_fill_test_data(struct passwd_test_data *); +static int passwd_test_correctness(struct passwd *, void *); +static int passwd_test_getpwnam(struct passwd *, void *); +static int passwd_test_getpwuid(struct passwd *, void *); +static int passwd_test_getpwent(struct passwd *, void *); + +IMPLEMENT_TEST_DATA(passwd) +IMPLEMENT_TEST_FILE_SNAPSHOT(passwd) +IMPLEMENT_1PASS_TEST(passwd) +IMPLEMENT_2PASS_TEST(passwd) + +static void +clone_passwd(struct passwd *dest, struct passwd const *src) +{ + ATF_REQUIRE(dest != NULL); + ATF_REQUIRE(src != NULL); + + memcpy(dest, src, sizeof(struct passwd)); + if (src->pw_name != NULL) + dest->pw_name = strdup(src->pw_name); + if (src->pw_passwd != NULL) + dest->pw_passwd = strdup(src->pw_passwd); + if (src->pw_class != NULL) + dest->pw_class = strdup(src->pw_class); + if (src->pw_gecos != NULL) + dest->pw_gecos = strdup(src->pw_gecos); + if (src->pw_dir != NULL) + dest->pw_dir = strdup(src->pw_dir); + if (src->pw_shell != NULL) + dest->pw_shell = strdup(dest->pw_shell); +} + +static int +compare_passwd(struct passwd *pwd1, struct passwd *pwd2, void *mdata) +{ + ATF_REQUIRE(pwd1 != NULL); + ATF_REQUIRE(pwd2 != NULL); + + if (pwd1 == pwd2) + return (0); + + if (pwd1->pw_uid != pwd2->pw_uid || + pwd1->pw_gid != pwd2->pw_gid || + pwd1->pw_change != pwd2->pw_change || + pwd1->pw_expire != pwd2->pw_expire || + pwd1->pw_fields != pwd2->pw_fields || + strcmp(pwd1->pw_name, pwd2->pw_name) != 0 || + strcmp(pwd1->pw_passwd, pwd2->pw_passwd) != 0 || + strcmp(pwd1->pw_class, pwd2->pw_class) != 0 || + strcmp(pwd1->pw_gecos, pwd2->pw_gecos) != 0 || + strcmp(pwd1->pw_dir, pwd2->pw_dir) != 0 || + strcmp(pwd1->pw_shell, pwd2->pw_shell) != 0) + return (-1); + else + return (0); +} + +static void +free_passwd(struct passwd *pwd) +{ + free(pwd->pw_name); + free(pwd->pw_passwd); + free(pwd->pw_class); + free(pwd->pw_gecos); + free(pwd->pw_dir); + free(pwd->pw_shell); +} + +static void +sdump_passwd(struct passwd *pwd, char *buffer, size_t buflen) +{ + snprintf(buffer, buflen, "%s:%s:%d:%d:%jd:%s:%s:%s:%s:%jd:%d", + pwd->pw_name, pwd->pw_passwd, pwd->pw_uid, pwd->pw_gid, + (uintmax_t)pwd->pw_change, pwd->pw_class, pwd->pw_gecos, + pwd->pw_dir, pwd->pw_shell, (uintmax_t)pwd->pw_expire, + pwd->pw_fields); +} + +static void +dump_passwd(struct passwd *pwd) +{ + if (pwd != NULL) { + char buffer[2048]; + sdump_passwd(pwd, buffer, sizeof(buffer)); + printf("%s\n", buffer); + } else + printf("(null)\n"); +} + +static int +passwd_read_snapshot_func(struct passwd *pwd, char *line) +{ + char *s, *ps, *ts; + int i; + +#ifdef DEBUG + printf("1 line read from snapshot:\n%s\n", line); +#endif + + i = 0; + ps = line; + memset(pwd, 0, sizeof(struct passwd)); + while ((s = strsep(&ps, ":")) != NULL) { + switch (i) { + case 0: + pwd->pw_name = strdup(s); + ATF_REQUIRE(pwd->pw_name != NULL); + break; + case 1: + pwd->pw_passwd = strdup(s); + ATF_REQUIRE(pwd->pw_passwd != NULL); + break; + case 2: + pwd->pw_uid = (uid_t)strtol(s, &ts, 10); + if (*ts != '\0') + goto fin; + break; + case 3: + pwd->pw_gid = (gid_t)strtol(s, &ts, 10); + if (*ts != '\0') + goto fin; + break; + case 4: + pwd->pw_change = (time_t)strtol(s, &ts, 10); + if (*ts != '\0') + goto fin; + break; + case 5: + pwd->pw_class = strdup(s); + ATF_REQUIRE(pwd->pw_class != NULL); + break; + case 6: + pwd->pw_gecos = strdup(s); + ATF_REQUIRE(pwd->pw_gecos != NULL); + break; + case 7: + pwd->pw_dir = strdup(s); + ATF_REQUIRE(pwd->pw_dir != NULL); + break; + case 8: + pwd->pw_shell = strdup(s); + ATF_REQUIRE(pwd->pw_shell != NULL); + break; + case 9: + pwd->pw_expire = (time_t)strtol(s, &ts, 10); + if (*ts != '\0') + goto fin; + break; + case 10: + pwd->pw_fields = (int)strtol(s, &ts, 10); + if (*ts != '\0') + goto fin; + break; + default: + break; + } + ++i; + } + +fin: + if (i != 11) { + free_passwd(pwd); + memset(pwd, 0, sizeof(struct passwd)); + return (-1); + } + + return (0); +} + +static int +passwd_fill_test_data(struct passwd_test_data *td) +{ + struct passwd *pwd; + + setpassent(1); + while ((pwd = getpwent()) != NULL) { + if (passwd_test_correctness(pwd, NULL) == 0) + TEST_DATA_APPEND(passwd, td, pwd); + else + return (-1); + } + endpwent(); + + return (0); +} + +static int +passwd_test_correctness(struct passwd *pwd, void *mdata) +{ + +#ifdef DEBUG + printf("testing correctness with the following data:\n"); + dump_passwd(pwd); +#endif + + if (pwd == NULL) + return (-1); + + if (pwd->pw_name == NULL) + goto errfin; + + if (pwd->pw_passwd == NULL) + goto errfin; + + if (pwd->pw_class == NULL) + goto errfin; + + if (pwd->pw_gecos == NULL) + goto errfin; + + if (pwd->pw_dir == NULL) + goto errfin; + + if (pwd->pw_shell == NULL) + goto errfin; + +#ifdef DEBUG + printf("correct\n"); +#endif + + return (0); +errfin: +#ifdef DEBUG + printf("incorrect\n"); +#endif + + return (-1); +} + +/* passwd_check_ambiguity() is needed here because when doing the getpwent() + * calls sequence, records from different nsswitch sources can be different, + * though having the same pw_name/pw_uid */ +static int +passwd_check_ambiguity(struct passwd_test_data *td, struct passwd *pwd) +{ + + return (TEST_DATA_FIND(passwd, td, pwd, compare_passwd, + NULL) != NULL ? 0 : -1); +} + +static int +passwd_test_getpwnam(struct passwd *pwd_model, void *mdata) +{ + struct passwd *pwd; + +#ifdef DEBUG + printf("testing getpwnam() with the following data:\n"); + dump_passwd(pwd_model); +#endif + + pwd = getpwnam(pwd_model->pw_name); + if (passwd_test_correctness(pwd, NULL) != 0) + goto errfin; + + if ((compare_passwd(pwd, pwd_model, NULL) != 0) && + (passwd_check_ambiguity((struct passwd_test_data *)mdata, pwd) + !=0)) + goto errfin; + +#ifdef DEBUG + printf("ok\n"); +#endif + return (0); + +errfin: +#ifdef DEBUG + printf("not ok\n"); +#endif + return (-1); +} + +static int +passwd_test_getpwuid(struct passwd *pwd_model, void *mdata) +{ + struct passwd *pwd; + +#ifdef DEBUG + printf("testing getpwuid() with the following data...\n"); + dump_passwd(pwd_model); +#endif + + pwd = getpwuid(pwd_model->pw_uid); + if ((passwd_test_correctness(pwd, NULL) != 0) || + ((compare_passwd(pwd, pwd_model, NULL) != 0) && + (passwd_check_ambiguity((struct passwd_test_data *)mdata, pwd) + != 0))) { +#ifdef DEBUG + printf("not ok\n"); +#endif + return (-1); + } else { +#ifdef DEBUG + printf("ok\n"); +#endif + return (0); + } +} + +static int +passwd_test_getpwent(struct passwd *pwd, void *mdata) +{ + /* Only correctness can be checked when doing 1-pass test for + * getpwent(). */ + return (passwd_test_correctness(pwd, NULL)); +} + +static int +run_tests(const char *snapshot_file, enum test_methods method) +{ + struct passwd_test_data td, td_snap, td_2pass; + int rv; + + TEST_DATA_INIT(passwd, &td, clone_passwd, free_passwd); + TEST_DATA_INIT(passwd, &td_snap, clone_passwd, free_passwd); + if (snapshot_file != NULL) { + if (access(snapshot_file, W_OK | R_OK) != 0) { + if (errno == ENOENT) + method = TEST_BUILD_SNAPSHOT; + else { + printf("can't access the file %s\n", + snapshot_file); + rv = -1; + goto fin; + } + } else { + if (method == TEST_BUILD_SNAPSHOT) { + rv = 0; + goto fin; + } + + TEST_SNAPSHOT_FILE_READ(passwd, snapshot_file, + &td_snap, passwd_read_snapshot_func); + } + } + + rv = passwd_fill_test_data(&td); + if (rv == -1) + return (-1); + + switch (method) { + case TEST_GETPWNAM: + if (snapshot_file == NULL) + rv = DO_1PASS_TEST(passwd, &td, + passwd_test_getpwnam, (void *)&td); + else + rv = DO_1PASS_TEST(passwd, &td_snap, + passwd_test_getpwnam, (void *)&td_snap); + break; + case TEST_GETPWUID: + if (snapshot_file == NULL) + rv = DO_1PASS_TEST(passwd, &td, + passwd_test_getpwuid, (void *)&td); + else + rv = DO_1PASS_TEST(passwd, &td_snap, + passwd_test_getpwuid, (void *)&td_snap); + break; + case TEST_GETPWENT: + if (snapshot_file == NULL) + rv = DO_1PASS_TEST(passwd, &td, passwd_test_getpwent, + (void *)&td); + else + rv = DO_2PASS_TEST(passwd, &td, &td_snap, + compare_passwd, NULL); + break; + case TEST_GETPWENT_2PASS: + TEST_DATA_INIT(passwd, &td_2pass, clone_passwd, free_passwd); + rv = passwd_fill_test_data(&td_2pass); + if (rv != -1) + rv = DO_2PASS_TEST(passwd, &td, &td_2pass, + compare_passwd, NULL); + TEST_DATA_DESTROY(passwd, &td_2pass); + break; + case TEST_BUILD_SNAPSHOT: + if (snapshot_file != NULL) + rv = TEST_SNAPSHOT_FILE_WRITE(passwd, snapshot_file, + &td, sdump_passwd); + break; + default: + rv = 0; + break; + } + +fin: + TEST_DATA_DESTROY(passwd, &td_snap); + TEST_DATA_DESTROY(passwd, &td); + + return (rv); +} + +#define SNAPSHOT_FILE "snapshot_pwd" + +ATF_TC_WITHOUT_HEAD(build_snapshot); +ATF_TC_BODY(build_snapshot, tc) +{ + + ATF_REQUIRE(run_tests(SNAPSHOT_FILE, TEST_BUILD_SNAPSHOT) == 0); +} + +ATF_TC_WITHOUT_HEAD(getpwent); +ATF_TC_BODY(getpwent, tc) +{ + + ATF_REQUIRE(run_tests(SNAPSHOT_FILE, TEST_GETPWENT) == 0); +} + +ATF_TC_WITHOUT_HEAD(getpwent_with_snapshot); +ATF_TC_BODY(getpwent_with_snapshot, tc) +{ + + ATF_REQUIRE(run_tests(SNAPSHOT_FILE, TEST_BUILD_SNAPSHOT) == 0); + ATF_REQUIRE(run_tests(SNAPSHOT_FILE, TEST_GETPWENT) == 0); +} + +ATF_TC_WITHOUT_HEAD(getpwent_with_two_pass); +ATF_TC_BODY(getpwent_with_two_pass, tc) +{ + + ATF_REQUIRE(run_tests(SNAPSHOT_FILE, TEST_GETPWENT_2PASS) == 0); +} + +ATF_TC_WITHOUT_HEAD(getpwnam); +ATF_TC_BODY(getpwnam, tc) +{ + + ATF_REQUIRE(run_tests(SNAPSHOT_FILE, TEST_GETPWNAM) == 0); +} + +ATF_TC_WITHOUT_HEAD(getpwnam_with_snapshot); +ATF_TC_BODY(getpwnam_with_snapshot, tc) +{ + + ATF_REQUIRE(run_tests(SNAPSHOT_FILE, TEST_BUILD_SNAPSHOT) == 0); + ATF_REQUIRE(run_tests(SNAPSHOT_FILE, TEST_GETPWNAM) == 0); +} + +ATF_TC_WITHOUT_HEAD(getpwuid); +ATF_TC_BODY(getpwuid, tc) +{ + + ATF_REQUIRE(run_tests(SNAPSHOT_FILE, TEST_GETPWUID) == 0); +} + +ATF_TC_WITHOUT_HEAD(getpwuid_with_snapshot); +ATF_TC_BODY(getpwuid_with_snapshot, tc) +{ + + ATF_REQUIRE(run_tests(SNAPSHOT_FILE, TEST_BUILD_SNAPSHOT) == 0); + ATF_REQUIRE(run_tests(SNAPSHOT_FILE, TEST_GETPWUID) == 0); +} + +ATF_TP_ADD_TCS(tp) +{ + + ATF_TP_ADD_TC(tp, build_snapshot); + ATF_TP_ADD_TC(tp, getpwent); + ATF_TP_ADD_TC(tp, getpwent_with_snapshot); + ATF_TP_ADD_TC(tp, getpwent_with_two_pass); + ATF_TP_ADD_TC(tp, getpwnam); + ATF_TP_ADD_TC(tp, getpwnam_with_snapshot); + ATF_TP_ADD_TC(tp, getpwuid); + ATF_TP_ADD_TC(tp, getpwuid_with_snapshot); + + return (atf_no_error()); +} diff --git a/lib/libc/tests/nss/getrpc_test.c b/lib/libc/tests/nss/getrpc_test.c new file mode 100644 index 0000000..89de986 --- /dev/null +++ b/lib/libc/tests/nss/getrpc_test.c @@ -0,0 +1,560 @@ +/*- + * Copyright (c) 2006 Michael Bushkov + * 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 + +#include "testutil.h" + +enum test_methods { + TEST_GETRPCENT, + TEST_GETRPCBYNAME, + TEST_GETRPCBYNUMBER, + TEST_GETRPCENT_2PASS, + TEST_BUILD_SNAPSHOT +}; + +DECLARE_TEST_DATA(rpcent) +DECLARE_TEST_FILE_SNAPSHOT(rpcent) +DECLARE_1PASS_TEST(rpcent) +DECLARE_2PASS_TEST(rpcent) + +static void clone_rpcent(struct rpcent *, struct rpcent const *); +static int compare_rpcent(struct rpcent *, struct rpcent *, void *); +static void dump_rpcent(struct rpcent *); +static void free_rpcent(struct rpcent *); + +static void sdump_rpcent(struct rpcent *, char *, size_t); +static int rpcent_read_snapshot_func(struct rpcent *, char *); + +static int rpcent_check_ambiguity(struct rpcent_test_data *, + struct rpcent *); +static int rpcent_fill_test_data(struct rpcent_test_data *); +static int rpcent_test_correctness(struct rpcent *, void *); +static int rpcent_test_getrpcbyname(struct rpcent *, void *); +static int rpcent_test_getrpcbynumber(struct rpcent *, void *); +static int rpcent_test_getrpcent(struct rpcent *, void *); + +static void usage(void) __attribute__((__noreturn__)); + +IMPLEMENT_TEST_DATA(rpcent) +IMPLEMENT_TEST_FILE_SNAPSHOT(rpcent) +IMPLEMENT_1PASS_TEST(rpcent) +IMPLEMENT_2PASS_TEST(rpcent) + +static void +clone_rpcent(struct rpcent *dest, struct rpcent const *src) +{ + ATF_REQUIRE(dest != NULL); + ATF_REQUIRE(src != NULL); + + char **cp; + int aliases_num; + + memset(dest, 0, sizeof(struct rpcent)); + + if (src->r_name != NULL) { + dest->r_name = strdup(src->r_name); + ATF_REQUIRE(dest->r_name != NULL); + } + + dest->r_number = src->r_number; + + if (src->r_aliases != NULL) { + aliases_num = 0; + for (cp = src->r_aliases; *cp; ++cp) + ++aliases_num; + + dest->r_aliases = calloc(1, (aliases_num + 1) * sizeof(char *)); + ATF_REQUIRE(dest->r_aliases != NULL); + + for (cp = src->r_aliases; *cp; ++cp) { + dest->r_aliases[cp - src->r_aliases] = strdup(*cp); + ATF_REQUIRE(dest->r_aliases[cp - src->r_aliases] != NULL); + } + } +} + +static void +free_rpcent(struct rpcent *rpc) +{ + char **cp; + + ATF_REQUIRE(rpc != NULL); + + free(rpc->r_name); + + for (cp = rpc->r_aliases; *cp; ++cp) + free(*cp); + free(rpc->r_aliases); +} + +static int +compare_rpcent(struct rpcent *rpc1, struct rpcent *rpc2, void *mdata) +{ + char **c1, **c2; + + if (rpc1 == rpc2) + return 0; + + if ((rpc1 == NULL) || (rpc2 == NULL)) + goto errfin; + + if ((strcmp(rpc1->r_name, rpc2->r_name) != 0) || + (rpc1->r_number != rpc2->r_number)) + goto errfin; + + c1 = rpc1->r_aliases; + c2 = rpc2->r_aliases; + + if ((rpc1->r_aliases == NULL) || (rpc2->r_aliases == NULL)) + goto errfin; + + for (;*c1 && *c2; ++c1, ++c2) + if (strcmp(*c1, *c2) != 0) + goto errfin; + + if ((*c1 != '\0') || (*c2 != '\0')) + goto errfin; + + return 0; + +errfin: + if (mdata == NULL) { + printf("following structures are not equal:\n"); + dump_rpcent(rpc1); + dump_rpcent(rpc2); + } + + return (-1); +} + +static void +sdump_rpcent(struct rpcent *rpc, char *buffer, size_t buflen) +{ + char **cp; + int written; + + written = snprintf(buffer, buflen, "%s %d", + rpc->r_name, rpc->r_number); + buffer += written; + if (written > buflen) + return; + buflen -= written; + + if (rpc->r_aliases != NULL) { + if (*(rpc->r_aliases) != '\0') { + for (cp = rpc->r_aliases; *cp; ++cp) { + written = snprintf(buffer, buflen, " %s",*cp); + buffer += written; + if (written > buflen) + return; + buflen -= written; + + if (buflen == 0) + return; + } + } else + snprintf(buffer, buflen, " noaliases"); + } else + snprintf(buffer, buflen, " (null)"); +} + +static int +rpcent_read_snapshot_func(struct rpcent *rpc, char *line) +{ + StringList *sl; + char *s, *ps, *ts; + int i; + + printf("1 line read from snapshot:\n%s\n", line); + + i = 0; + sl = NULL; + ps = line; + memset(rpc, 0, sizeof(struct rpcent)); + while ((s = strsep(&ps, " ")) != NULL) { + switch (i) { + case 0: + rpc->r_name = strdup(s); + ATF_REQUIRE(rpc->r_name != NULL); + break; + + case 1: + rpc->r_number = (int)strtol(s, &ts, 10); + if (*ts != '\0') { + free(rpc->r_name); + return (-1); + } + break; + + default: + if (sl == NULL) { + if (strcmp(s, "(null)") == 0) + return (0); + + sl = sl_init(); + ATF_REQUIRE(sl != NULL); + + if (strcmp(s, "noaliases") != 0) { + ts = strdup(s); + ATF_REQUIRE(ts != NULL); + sl_add(sl, ts); + } + } else { + ts = strdup(s); + ATF_REQUIRE(ts != NULL); + sl_add(sl, ts); + } + break; + } + i++; + } + + if (i < 3) { + free(rpc->r_name); + memset(rpc, 0, sizeof(struct rpcent)); + return (-1); + } + + sl_add(sl, NULL); + rpc->r_aliases = sl->sl_str; + + /* NOTE: is it a dirty hack or not? */ + free(sl); + return (0); +} + +static void +dump_rpcent(struct rpcent *result) +{ + if (result != NULL) { + char buffer[1024]; + sdump_rpcent(result, buffer, sizeof(buffer)); + printf("%s\n", buffer); + } else + printf("(null)\n"); +} + +static int +rpcent_fill_test_data(struct rpcent_test_data *td) +{ + struct rpcent *rpc; + + setrpcent(1); + while ((rpc = getrpcent()) != NULL) { + if (rpcent_test_correctness(rpc, NULL) == 0) + TEST_DATA_APPEND(rpcent, td, rpc); + else + return (-1); + } + endrpcent(); + + return (0); +} + +static int +rpcent_test_correctness(struct rpcent *rpc, void *mdata) +{ + + printf("testing correctness with the following data:\n"); + dump_rpcent(rpc); + + if (rpc == NULL) + goto errfin; + + if (rpc->r_name == NULL) + goto errfin; + + if (rpc->r_number < 0) + goto errfin; + + if (rpc->r_aliases == NULL) + goto errfin; + + printf("correct\n"); + + return (0); +errfin: + printf("incorrect\n"); + + return (-1); +} + +/* rpcent_check_ambiguity() is needed when one port+rpc is associated with + * more than one peice (these cases are usually marked as PROBLEM in + * /etc/peices. This functions is needed also when one peice+rpc is + * associated with several ports. We have to check all the rpcent structures + * to make sure that rpc really exists and correct */ +static int +rpcent_check_ambiguity(struct rpcent_test_data *td, struct rpcent *rpc) +{ + + return (TEST_DATA_FIND(rpcent, td, rpc, compare_rpcent, + NULL) != NULL ? 0 : -1); +} + +static int +rpcent_test_getrpcbyname(struct rpcent *rpc_model, void *mdata) +{ + char **alias; + struct rpcent *rpc; + + printf("testing getrpcbyname() with the following data:\n"); + dump_rpcent(rpc_model); + + rpc = getrpcbyname(rpc_model->r_name); + if (rpcent_test_correctness(rpc, NULL) != 0) + goto errfin; + + if ((compare_rpcent(rpc, rpc_model, NULL) != 0) && + (rpcent_check_ambiguity((struct rpcent_test_data *)mdata, rpc) + !=0)) + goto errfin; + + for (alias = rpc_model->r_aliases; *alias; ++alias) { + rpc = getrpcbyname(*alias); + + if (rpcent_test_correctness(rpc, NULL) != 0) + goto errfin; + + if ((compare_rpcent(rpc, rpc_model, NULL) != 0) && + (rpcent_check_ambiguity( + (struct rpcent_test_data *)mdata, rpc) != 0)) + goto errfin; + } + + printf("ok\n"); + return (0); + +errfin: + printf("not ok\n"); + + return (-1); +} + +static int +rpcent_test_getrpcbynumber(struct rpcent *rpc_model, void *mdata) +{ + struct rpcent *rpc; + + printf("testing getrpcbyport() with the following data...\n"); + dump_rpcent(rpc_model); + + rpc = getrpcbynumber(rpc_model->r_number); + if (rpcent_test_correctness(rpc, NULL) != 0 || + (compare_rpcent(rpc, rpc_model, NULL) != 0 && + rpcent_check_ambiguity((struct rpcent_test_data *)mdata, rpc) + != 0)) { + printf("not ok\n"); + return (-1); + } else { + printf("ok\n"); + return (0); + } +} + +static int +rpcent_test_getrpcent(struct rpcent *rpc, void *mdata) +{ + + /* + * Only correctness can be checked when doing 1-pass test for + * getrpcent(). + */ + return (rpcent_test_correctness(rpc, NULL)); +} + +int +run_tests(const char *snapshot_file, enum test_methods method) +{ + struct rpcent_test_data td, td_snap, td_2pass; + int rv; + + TEST_DATA_INIT(rpcent, &td, clone_rpcent, free_rpcent); + TEST_DATA_INIT(rpcent, &td_snap, clone_rpcent, free_rpcent); + if (snapshot_file != NULL) { + if (access(snapshot_file, W_OK | R_OK) != 0) { + if (errno == ENOENT) + method = TEST_BUILD_SNAPSHOT; + else { + printf("can't access the file %s\n", + snapshot_file); + + rv = -1; + goto fin; + } + } else { + if (method == TEST_BUILD_SNAPSHOT) { + rv = 0; + goto fin; + } + + TEST_SNAPSHOT_FILE_READ(rpcent, snapshot_file, + &td_snap, rpcent_read_snapshot_func); + } + } + + rv = rpcent_fill_test_data(&td); + if (rv == -1) + return (-1); + switch (method) { + case TEST_GETRPCBYNAME: + if (snapshot_file == NULL) + rv = DO_1PASS_TEST(rpcent, &td, + rpcent_test_getrpcbyname, (void *)&td); + else + rv = DO_1PASS_TEST(rpcent, &td_snap, + rpcent_test_getrpcbyname, (void *)&td_snap); + break; + case TEST_GETRPCBYNUMBER: + if (snapshot_file == NULL) + rv = DO_1PASS_TEST(rpcent, &td, + rpcent_test_getrpcbynumber, (void *)&td); + else + rv = DO_1PASS_TEST(rpcent, &td_snap, + rpcent_test_getrpcbynumber, (void *)&td_snap); + break; + case TEST_GETRPCENT: + if (snapshot_file == NULL) + rv = DO_1PASS_TEST(rpcent, &td, rpcent_test_getrpcent, + (void *)&td); + else + rv = DO_2PASS_TEST(rpcent, &td, &td_snap, + compare_rpcent, NULL); + break; + case TEST_GETRPCENT_2PASS: + TEST_DATA_INIT(rpcent, &td_2pass, clone_rpcent, free_rpcent); + rv = rpcent_fill_test_data(&td_2pass); + if (rv != -1) + rv = DO_2PASS_TEST(rpcent, &td, &td_2pass, + compare_rpcent, NULL); + TEST_DATA_DESTROY(rpcent, &td_2pass); + break; + case TEST_BUILD_SNAPSHOT: + if (snapshot_file != NULL) + rv = TEST_SNAPSHOT_FILE_WRITE(rpcent, snapshot_file, &td, + sdump_rpcent); + break; + default: + rv = 0; + break; + } + +fin: + TEST_DATA_DESTROY(rpcent, &td_snap); + TEST_DATA_DESTROY(rpcent, &td); + + return (rv); +} + +#define SNAPSHOT_FILE "snapshot_rpc" + +ATF_TC_WITHOUT_HEAD(build_snapshot); +ATF_TC_BODY(build_snapshot, tc) +{ + + ATF_REQUIRE(run_tests(SNAPSHOT_FILE, TEST_BUILD_SNAPSHOT) == 0); +} + +ATF_TC_WITHOUT_HEAD(getrpcbyname); +ATF_TC_BODY(getrpcbyname, tc) +{ + + ATF_REQUIRE(run_tests(NULL, TEST_GETRPCBYNAME) == 0); +} + +ATF_TC_WITHOUT_HEAD(getrpcbyname_with_snapshot); +ATF_TC_BODY(getrpcbyname_with_snapshot, tc) +{ + + ATF_REQUIRE(run_tests(SNAPSHOT_FILE, TEST_BUILD_SNAPSHOT) == 0); + ATF_REQUIRE(run_tests(SNAPSHOT_FILE, TEST_GETRPCBYNAME) == 0); +} + +ATF_TC_WITHOUT_HEAD(getrpcbynumber); +ATF_TC_BODY(getrpcbynumber, tc) +{ + + ATF_REQUIRE(run_tests(NULL, TEST_GETRPCBYNUMBER) == 0); +} + +ATF_TC_WITHOUT_HEAD(getrpcbynumber_with_snapshot); +ATF_TC_BODY(getrpcbynumber_with_snapshot, tc) +{ + + ATF_REQUIRE(run_tests(SNAPSHOT_FILE, TEST_BUILD_SNAPSHOT) == 0); + ATF_REQUIRE(run_tests(SNAPSHOT_FILE, TEST_GETRPCBYNUMBER) == 0); +} + +ATF_TC_WITHOUT_HEAD(getrpcbyent); +ATF_TC_BODY(getrpcbyent, tc) +{ + + ATF_REQUIRE(run_tests(NULL, TEST_GETRPCENT) == 0); +} + +ATF_TC_WITHOUT_HEAD(getrpcbyent_with_snapshot); +ATF_TC_BODY(getrpcbyent_with_snapshot, tc) +{ + + ATF_REQUIRE(run_tests(SNAPSHOT_FILE, TEST_BUILD_SNAPSHOT) == 0); + ATF_REQUIRE(run_tests(SNAPSHOT_FILE, TEST_GETRPCENT) == 0); +} + +ATF_TC_WITHOUT_HEAD(getrpcbyent_with_two_pass); +ATF_TC_BODY(getrpcbyent_with_two_pass, tc) +{ + + ATF_REQUIRE(run_tests(NULL, TEST_GETRPCENT_2PASS) == 0); +} + +ATF_TP_ADD_TCS(tp) +{ + + ATF_TP_ADD_TC(tp, build_snapshot); + ATF_TP_ADD_TC(tp, getrpcbyname); + ATF_TP_ADD_TC(tp, getrpcbyname_with_snapshot); + ATF_TP_ADD_TC(tp, getrpcbynumber); + ATF_TP_ADD_TC(tp, getrpcbynumber_with_snapshot); + ATF_TP_ADD_TC(tp, getrpcbyent); + ATF_TP_ADD_TC(tp, getrpcbyent_with_snapshot); + ATF_TP_ADD_TC(tp, getrpcbyent_with_two_pass); + + return (atf_no_error()); +} diff --git a/lib/libc/tests/nss/getserv_test.c b/lib/libc/tests/nss/getserv_test.c new file mode 100644 index 0000000..29c1dfa --- /dev/null +++ b/lib/libc/tests/nss/getserv_test.c @@ -0,0 +1,570 @@ +/*- + * Copyright (c) 2006 Michael Bushkov + * 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 + +#include "testutil.h" + +enum test_methods { + TEST_GETSERVENT, + TEST_GETSERVBYNAME, + TEST_GETSERVBYPORT, + TEST_GETSERVENT_2PASS, + TEST_BUILD_SNAPSHOT +}; + +DECLARE_TEST_DATA(servent) +DECLARE_TEST_FILE_SNAPSHOT(servent) +DECLARE_1PASS_TEST(servent) +DECLARE_2PASS_TEST(servent) + +static void clone_servent(struct servent *, struct servent const *); +static int compare_servent(struct servent *, struct servent *, void *); +static void dump_servent(struct servent *); +static void free_servent(struct servent *); + +static void sdump_servent(struct servent *, char *, size_t); +static int servent_read_snapshot_func(struct servent *, char *); + +static int servent_check_ambiguity(struct servent_test_data *, + struct servent *); +static int servent_fill_test_data(struct servent_test_data *); +static int servent_test_correctness(struct servent *, void *); +static int servent_test_getservbyname(struct servent *, void *); +static int servent_test_getservbyport(struct servent *, void *); +static int servent_test_getservent(struct servent *, void *); + +IMPLEMENT_TEST_DATA(servent) +IMPLEMENT_TEST_FILE_SNAPSHOT(servent) +IMPLEMENT_1PASS_TEST(servent) +IMPLEMENT_2PASS_TEST(servent) + +static void +clone_servent(struct servent *dest, struct servent const *src) +{ + ATF_REQUIRE(dest != NULL); + ATF_REQUIRE(src != NULL); + + char **cp; + int aliases_num; + + memset(dest, 0, sizeof(struct servent)); + + if (src->s_name != NULL) { + dest->s_name = strdup(src->s_name); + ATF_REQUIRE(dest->s_name != NULL); + } + + if (src->s_proto != NULL) { + dest->s_proto = strdup(src->s_proto); + ATF_REQUIRE(dest->s_proto != NULL); + } + dest->s_port = src->s_port; + + if (src->s_aliases != NULL) { + aliases_num = 0; + for (cp = src->s_aliases; *cp; ++cp) + ++aliases_num; + + dest->s_aliases = calloc(1, (aliases_num + 1) * sizeof(char *)); + ATF_REQUIRE(dest->s_aliases != NULL); + + for (cp = src->s_aliases; *cp; ++cp) { + dest->s_aliases[cp - src->s_aliases] = strdup(*cp); + ATF_REQUIRE(dest->s_aliases[cp - src->s_aliases] != NULL); + } + } +} + +static void +free_servent(struct servent *serv) +{ + char **cp; + + ATF_REQUIRE(serv != NULL); + + free(serv->s_name); + free(serv->s_proto); + + for (cp = serv->s_aliases; *cp; ++cp) + free(*cp); + free(serv->s_aliases); +} + +static int +compare_servent(struct servent *serv1, struct servent *serv2, void *mdata) +{ + char **c1, **c2; + + if (serv1 == serv2) + return 0; + + if ((serv1 == NULL) || (serv2 == NULL)) + goto errfin; + + if ((strcmp(serv1->s_name, serv2->s_name) != 0) || + (strcmp(serv1->s_proto, serv2->s_proto) != 0) || + (serv1->s_port != serv2->s_port)) + goto errfin; + + c1 = serv1->s_aliases; + c2 = serv2->s_aliases; + + if ((serv1->s_aliases == NULL) || (serv2->s_aliases == NULL)) + goto errfin; + + for (;*c1 && *c2; ++c1, ++c2) + if (strcmp(*c1, *c2) != 0) + goto errfin; + + if ((*c1 != '\0') || (*c2 != '\0')) + goto errfin; + + return 0; + +errfin: + if (mdata == NULL) { + printf("following structures are not equal:\n"); + dump_servent(serv1); + dump_servent(serv2); + } + + return (-1); +} + +static void +sdump_servent(struct servent *serv, char *buffer, size_t buflen) +{ + char **cp; + int written; + + written = snprintf(buffer, buflen, "%s %d %s", + serv->s_name, ntohs(serv->s_port), serv->s_proto); + buffer += written; + if (written > buflen) + return; + buflen -= written; + + if (serv->s_aliases != NULL) { + if (*(serv->s_aliases) != '\0') { + for (cp = serv->s_aliases; *cp; ++cp) { + written = snprintf(buffer, buflen, " %s",*cp); + buffer += written; + if (written > buflen) + return; + buflen -= written; + + if (buflen == 0) + return; + } + } else + snprintf(buffer, buflen, " noaliases"); + } else + snprintf(buffer, buflen, " (null)"); +} + +static int +servent_read_snapshot_func(struct servent *serv, char *line) +{ + StringList *sl; + char *s, *ps, *ts; + int i; + + printf("1 line read from snapshot:\n%s\n", line); + + i = 0; + sl = NULL; + ps = line; + memset(serv, 0, sizeof(struct servent)); + while ( (s = strsep(&ps, " ")) != NULL) { + switch (i) { + case 0: + serv->s_name = strdup(s); + ATF_REQUIRE(serv->s_name != NULL); + break; + + case 1: + serv->s_port = htons( + (int)strtol(s, &ts, 10)); + if (*ts != '\0') { + free(serv->s_name); + return (-1); + } + break; + + case 2: + serv->s_proto = strdup(s); + ATF_REQUIRE(serv->s_proto != NULL); + break; + + default: + if (sl == NULL) { + if (strcmp(s, "(null)") == 0) + return (0); + + sl = sl_init(); + ATF_REQUIRE(sl != NULL); + + if (strcmp(s, "noaliases") != 0) { + ts = strdup(s); + ATF_REQUIRE(ts != NULL); + sl_add(sl, ts); + } + } else { + ts = strdup(s); + ATF_REQUIRE(ts != NULL); + sl_add(sl, ts); + } + break; + } + ++i; + } + + if (i < 3) { + free(serv->s_name); + free(serv->s_proto); + memset(serv, 0, sizeof(struct servent)); + return (-1); + } + + sl_add(sl, NULL); + serv->s_aliases = sl->sl_str; + + /* NOTE: is it a dirty hack or not? */ + free(sl); + return (0); +} + +static void +dump_servent(struct servent *result) +{ + if (result != NULL) { + char buffer[1024]; + sdump_servent(result, buffer, sizeof(buffer)); + printf("%s\n", buffer); + } else + printf("(null)\n"); +} + +static int +servent_fill_test_data(struct servent_test_data *td) +{ + struct servent *serv; + + setservent(1); + while ((serv = getservent()) != NULL) { + if (servent_test_correctness(serv, NULL) == 0) + TEST_DATA_APPEND(servent, td, serv); + else + return (-1); + } + endservent(); + + return (0); +} + +static int +servent_test_correctness(struct servent *serv, void *mdata) +{ + printf("testing correctness with the following data:\n"); + dump_servent(serv); + + if (serv == NULL) + goto errfin; + + if (serv->s_name == NULL) + goto errfin; + + if (serv->s_proto == NULL) + goto errfin; + + if (ntohs(serv->s_port < 0)) + goto errfin; + + if (serv->s_aliases == NULL) + goto errfin; + + printf("correct\n"); + + return (0); +errfin: + printf("incorrect\n"); + + return (-1); +} + +/* servent_check_ambiguity() is needed when one port+proto is associated with + * more than one service (these cases are usually marked as PROBLEM in + * /etc/services. This functions is needed also when one service+proto is + * associated with several ports. We have to check all the servent structures + * to make sure that serv really exists and correct */ +static int +servent_check_ambiguity(struct servent_test_data *td, struct servent *serv) +{ + + return (TEST_DATA_FIND(servent, td, serv, compare_servent, + NULL) != NULL ? 0 : -1); +} + +static int +servent_test_getservbyname(struct servent *serv_model, void *mdata) +{ + char **alias; + struct servent *serv; + + printf("testing getservbyname() with the following data:\n"); + dump_servent(serv_model); + + serv = getservbyname(serv_model->s_name, serv_model->s_proto); + if (servent_test_correctness(serv, NULL) != 0) + goto errfin; + + if ((compare_servent(serv, serv_model, NULL) != 0) && + (servent_check_ambiguity((struct servent_test_data *)mdata, serv) + !=0)) + goto errfin; + + for (alias = serv_model->s_aliases; *alias; ++alias) { + serv = getservbyname(*alias, serv_model->s_proto); + + if (servent_test_correctness(serv, NULL) != 0) + goto errfin; + + if ((compare_servent(serv, serv_model, NULL) != 0) && + (servent_check_ambiguity( + (struct servent_test_data *)mdata, serv) != 0)) + goto errfin; + } + + printf("ok\n"); + return (0); + +errfin: + printf("not ok\n"); + + return (-1); +} + +static int +servent_test_getservbyport(struct servent *serv_model, void *mdata) +{ + struct servent *serv; + + printf("testing getservbyport() with the following data...\n"); + dump_servent(serv_model); + + serv = getservbyport(serv_model->s_port, serv_model->s_proto); + if ((servent_test_correctness(serv, NULL) != 0) || + ((compare_servent(serv, serv_model, NULL) != 0) && + (servent_check_ambiguity((struct servent_test_data *)mdata, serv) + != 0))) { + printf("not ok\n"); + return (-1); + } else { + printf("ok\n"); + return (0); + } +} + +static int +servent_test_getservent(struct servent *serv, void *mdata) +{ + /* Only correctness can be checked when doing 1-pass test for + * getservent(). */ + return (servent_test_correctness(serv, NULL)); +} + +int +run_tests(const char *snapshot_file, enum test_methods method) +{ + struct servent_test_data td, td_snap, td_2pass; + int rv; + + TEST_DATA_INIT(servent, &td, clone_servent, free_servent); + TEST_DATA_INIT(servent, &td_snap, clone_servent, free_servent); + if (snapshot_file != NULL) { + if (access(snapshot_file, W_OK | R_OK) != 0) { + if (errno == ENOENT) + method = TEST_BUILD_SNAPSHOT; + else { + printf("can't access the file %s\n", + snapshot_file); + + rv = -1; + goto fin; + } + } else { + if (method == TEST_BUILD_SNAPSHOT) { + rv = 0; + goto fin; + } + + TEST_SNAPSHOT_FILE_READ(servent, snapshot_file, + &td_snap, servent_read_snapshot_func); + } + } + + rv = servent_fill_test_data(&td); + if (rv == -1) + return (-1); + switch (method) { + case TEST_GETSERVBYNAME: + if (snapshot_file == NULL) + rv = DO_1PASS_TEST(servent, &td, + servent_test_getservbyname, (void *)&td); + else + rv = DO_1PASS_TEST(servent, &td_snap, + servent_test_getservbyname, (void *)&td_snap); + break; + case TEST_GETSERVBYPORT: + if (snapshot_file == NULL) + rv = DO_1PASS_TEST(servent, &td, + servent_test_getservbyport, (void *)&td); + else + rv = DO_1PASS_TEST(servent, &td_snap, + servent_test_getservbyport, (void *)&td_snap); + break; + case TEST_GETSERVENT: + if (snapshot_file == NULL) + rv = DO_1PASS_TEST(servent, &td, servent_test_getservent, + (void *)&td); + else + rv = DO_2PASS_TEST(servent, &td, &td_snap, + compare_servent, NULL); + break; + case TEST_GETSERVENT_2PASS: + TEST_DATA_INIT(servent, &td_2pass, clone_servent, free_servent); + rv = servent_fill_test_data(&td_2pass); + if (rv != -1) + rv = DO_2PASS_TEST(servent, &td, &td_2pass, + compare_servent, NULL); + TEST_DATA_DESTROY(servent, &td_2pass); + break; + case TEST_BUILD_SNAPSHOT: + if (snapshot_file != NULL) + rv = TEST_SNAPSHOT_FILE_WRITE(servent, snapshot_file, &td, + sdump_servent); + break; + default: + rv = 0; + break; + } + +fin: + TEST_DATA_DESTROY(servent, &td_snap); + TEST_DATA_DESTROY(servent, &td); + + return (rv); +} + +#define SNAPSHOT_FILE "snapshot_serv" + +ATF_TC_WITHOUT_HEAD(build_snapshot); +ATF_TC_BODY(build_snapshot, tc) +{ + + ATF_REQUIRE(run_tests(SNAPSHOT_FILE, TEST_BUILD_SNAPSHOT) == 0); +} + +ATF_TC_WITHOUT_HEAD(getservbyname); +ATF_TC_BODY(getservbyname, tc) +{ + + ATF_REQUIRE(run_tests(NULL, TEST_GETSERVBYNAME) == 0); +} + +ATF_TC_WITHOUT_HEAD(getservbyname_with_snapshot); +ATF_TC_BODY(getservbyname_with_snapshot, tc) +{ + + ATF_REQUIRE(run_tests(SNAPSHOT_FILE, TEST_BUILD_SNAPSHOT) == 0); + ATF_REQUIRE(run_tests(SNAPSHOT_FILE, TEST_GETSERVBYNAME) == 0); +} + +ATF_TC_WITHOUT_HEAD(getservbyport); +ATF_TC_BODY(getservbyport, tc) +{ + + ATF_REQUIRE(run_tests(NULL, TEST_GETSERVBYPORT) == 0); +} + +ATF_TC_WITHOUT_HEAD(getservbyport_with_snapshot); +ATF_TC_BODY(getservbyport_with_snapshot, tc) +{ + + ATF_REQUIRE(run_tests(SNAPSHOT_FILE, TEST_BUILD_SNAPSHOT) == 0); + ATF_REQUIRE(run_tests(SNAPSHOT_FILE, TEST_GETSERVBYPORT) == 0); +} + +ATF_TC_WITHOUT_HEAD(getservbyent); +ATF_TC_BODY(getservbyent, tc) +{ + + ATF_REQUIRE(run_tests(NULL, TEST_GETSERVENT) == 0); +} + +ATF_TC_WITHOUT_HEAD(getservbyent_with_snapshot); +ATF_TC_BODY(getservbyent_with_snapshot, tc) +{ + + ATF_REQUIRE(run_tests(SNAPSHOT_FILE, TEST_BUILD_SNAPSHOT) == 0); + ATF_REQUIRE(run_tests(SNAPSHOT_FILE, TEST_GETSERVENT) == 0); +} + +ATF_TC_WITHOUT_HEAD(getservbyent_with_two_pass); +ATF_TC_BODY(getservbyent_with_two_pass, tc) +{ + + ATF_REQUIRE(run_tests(NULL, TEST_GETSERVENT_2PASS) == 0); +} + +ATF_TP_ADD_TCS(tp) +{ + + ATF_TP_ADD_TC(tp, build_snapshot); + ATF_TP_ADD_TC(tp, getservbyent); + ATF_TP_ADD_TC(tp, getservbyent_with_snapshot); + ATF_TP_ADD_TC(tp, getservbyent_with_two_pass); + ATF_TP_ADD_TC(tp, getservbyname); + ATF_TP_ADD_TC(tp, getservbyname_with_snapshot); + ATF_TP_ADD_TC(tp, getservbyport); + ATF_TP_ADD_TC(tp, getservbyport_with_snapshot); + + return (atf_no_error()); +} diff --git a/lib/libc/tests/nss/getusershell_test.c b/lib/libc/tests/nss/getusershell_test.c new file mode 100644 index 0000000..ccd8cf9 --- /dev/null +++ b/lib/libc/tests/nss/getusershell_test.c @@ -0,0 +1,225 @@ +/*- + * Copyright (c) 2006 Michael Bushkov + * 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 "testutil.h" + +enum test_methods { + TEST_GETUSERSHELL, + TEST_BUILD_SNAPSHOT +}; + +struct usershell { + char *path; +}; + +static enum test_methods method = TEST_GETUSERSHELL; + +DECLARE_TEST_DATA(usershell) +DECLARE_TEST_FILE_SNAPSHOT(usershell) +DECLARE_2PASS_TEST(usershell) + +static void clone_usershell(struct usershell *, struct usershell const *); +static int compare_usershell(struct usershell *, struct usershell *, void *); +static void free_usershell(struct usershell *); + +static void sdump_usershell(struct usershell *, char *, size_t); +static void dump_usershell(struct usershell *); + +IMPLEMENT_TEST_DATA(usershell) +IMPLEMENT_TEST_FILE_SNAPSHOT(usershell) +IMPLEMENT_2PASS_TEST(usershell) + +static void +clone_usershell(struct usershell *dest, struct usershell const *src) +{ + assert(dest != NULL); + assert(src != NULL); + + if (src->path != NULL) { + dest->path = strdup(src->path); + assert(dest->path != NULL); + } +} + +static int +compare_usershell(struct usershell *us1, struct usershell *us2, void *mdata) +{ + int rv; + + assert(us1 != NULL); + assert(us2 != NULL); + + dump_usershell(us1); + dump_usershell(us2); + + if (us1 == us2) + return (0); + + rv = strcmp(us1->path, us2->path); + if (rv != 0) { + printf("following structures are not equal:\n"); + dump_usershell(us1); + dump_usershell(us2); + } + + return (rv); +} + +static void +free_usershell(struct usershell *us) +{ + free(us->path); +} + +static void +sdump_usershell(struct usershell *us, char *buffer, size_t buflen) +{ + snprintf(buffer, buflen, "%s", us->path); +} + +static void +dump_usershell(struct usershell *us) +{ + if (us != NULL) { + char buffer[2048]; + sdump_usershell(us, buffer, sizeof(buffer)); + printf("%s\n", buffer); + } else + printf("(null)\n"); +} + +static int +usershell_read_snapshot_func(struct usershell *us, char *line) +{ + + us->path = strdup(line); + ATF_REQUIRE(us->path != NULL); + + return (0); +} + +int +run_tests(const char *snapshot_file, enum test_methods method) +{ + struct usershell_test_data td, td_snap; + struct usershell ushell; + int rv; + + rv = 0; + + TEST_DATA_INIT(usershell, &td, clone_usershell, free_usershell); + TEST_DATA_INIT(usershell, &td_snap, clone_usershell, free_usershell); + + setusershell(); + while ((ushell.path = getusershell()) != NULL) { + printf("usershell found:\n"); + dump_usershell(&ushell); + TEST_DATA_APPEND(usershell, &td, &ushell); + } + endusershell(); + + if (snapshot_file != NULL) { + if (access(snapshot_file, W_OK | R_OK) != 0) { + if (errno == ENOENT) + method = TEST_BUILD_SNAPSHOT; + else { + printf("can't access the snapshot file %s\n", + snapshot_file); + + rv = -1; + goto fin; + } + } else { + rv = TEST_SNAPSHOT_FILE_READ(usershell, snapshot_file, + &td_snap, usershell_read_snapshot_func); + if (rv != 0) { + printf("error reading snapshot file\n"); + goto fin; + } + } + } + + switch (method) { + case TEST_GETUSERSHELL: + rv = DO_2PASS_TEST(usershell, &td, &td_snap, + compare_usershell, NULL); + break; + case TEST_BUILD_SNAPSHOT: + if (snapshot_file != NULL) { + rv = TEST_SNAPSHOT_FILE_WRITE(usershell, snapshot_file, + &td, sdump_usershell); + } + break; + default: + rv = 0; + break; + } + +fin: + TEST_DATA_DESTROY(usershell, &td_snap); + TEST_DATA_DESTROY(usershell, &td); + + return (rv); +} + +#define SNAPSHOT_FILE "snapshot_usershell" + +ATF_TC_WITHOUT_HEAD(getusershell_with_snapshot); +ATF_TC_BODY(getusershell_with_snapshot, tc) +{ + + ATF_REQUIRE(run_tests(SNAPSHOT_FILE, TEST_BUILD_SNAPSHOT) == 0); +} + +ATF_TC_WITHOUT_HEAD(getusershell_with_two_pass); +ATF_TC_BODY(getusershell_with_two_pass, tc) +{ + + ATF_REQUIRE(run_tests(SNAPSHOT_FILE, TEST_BUILD_SNAPSHOT) == 0); + ATF_REQUIRE(run_tests(SNAPSHOT_FILE, TEST_GETUSERSHELL) == 0); +} + +ATF_TP_ADD_TCS(tp) +{ + + ATF_TP_ADD_TC(tp, getusershell_with_snapshot); + ATF_TP_ADD_TC(tp, getusershell_with_two_pass); + + return (atf_no_error()); +} diff --git a/lib/libc/tests/nss/testutil.h b/lib/libc/tests/nss/testutil.h new file mode 100644 index 0000000..39c4f41 --- /dev/null +++ b/lib/libc/tests/nss/testutil.h @@ -0,0 +1,333 @@ +/*- + * Copyright (c) 2006 Michael Bushkov + * + * 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$ + */ + +#include + +#define DECLARE_TEST_DATA(ent) \ +struct ent##_entry { \ + struct ent data; \ + STAILQ_ENTRY(ent##_entry) entries; \ +}; \ + \ +struct ent##_test_data { \ + void (*clone_func)(struct ent *, struct ent const *); \ + void (*free_func)(struct ent *); \ + \ + STAILQ_HEAD(ent_head, ent##_entry) snapshot_data; \ +}; \ + \ +void __##ent##_test_data_init(struct ent##_test_data *, \ + void (*)(struct ent *, struct ent const *), \ + void (*freef)(struct ent *)); \ +void __##ent##_test_data_destroy(struct ent##_test_data *); \ + \ +void __##ent##_test_data_append(struct ent##_test_data *, struct ent *data);\ +int __##ent##_test_data_foreach(struct ent##_test_data *, \ + int (*)(struct ent *, void *), void *); \ +int __##ent##_test_data_compare(struct ent##_test_data *, \ + struct ent##_test_data *, int (*)(struct ent *, struct ent *, \ + void *), void *); \ +struct ent *__##ent##_test_data_find(struct ent##_test_data *, struct ent *,\ + int (*)(struct ent *, struct ent *, void *), void *); \ +void __##ent##_test_data_clear(struct ent##_test_data *); + +#define TEST_DATA_INIT(ent, td, clonef, freef)\ + __##ent##_test_data_init(td, clonef, freef) +#define TEST_DATA_DESTROY(ent, td) __##ent##_test_data_destroy(td) +#define TEST_DATA_APPEND(ent, td, d) __##ent##_test_data_append(td, d) +#define TEST_DATA_FOREACH(ent, td, f, mdata)\ + __##ent##_test_data_foreach(td, f, mdata) +#define TEST_DATA_COMPARE(ent, td1, td2, fcmp, mdata)\ + __##ent##_test_data_compare(td1, td2, fcmp, mdata); +#define TEST_DATA_FIND(ent, td, d, fcmp, mdata)\ + __##ent##_test_data_find(td, d, fcmp, mdata) +#define TEST_DATA_CLEAR(ent, td) __##ent##_test_data_clear(td) + +#define IMPLEMENT_TEST_DATA(ent) \ +void \ +__##ent##_test_data_init(struct ent##_test_data *td, \ + void (*clonef)(struct ent *, struct ent const *), \ + void (*freef)(struct ent *)) \ +{ \ + ATF_REQUIRE(td != NULL); \ + ATF_REQUIRE(clonef != NULL); \ + ATF_REQUIRE(freef != NULL); \ + \ + memset(td, 0, sizeof(*td)); \ + td->clone_func = clonef; \ + td->free_func = freef; \ + STAILQ_INIT(&td->snapshot_data); \ +} \ + \ +void \ +__##ent##_test_data_destroy(struct ent##_test_data *td) \ +{ \ + __##ent##_test_data_clear(td); \ +} \ + \ +void \ +__##ent##_test_data_append(struct ent##_test_data *td, struct ent *app_data)\ +{ \ + struct ent##_entry *e; \ + \ + ATF_REQUIRE(td != NULL); \ + ATF_REQUIRE(app_data != NULL); \ + \ + e = (struct ent##_entry *)malloc(sizeof(struct ent##_entry)); \ + ATF_REQUIRE(e != NULL); \ + memset(e, 0, sizeof(struct ent##_entry)); \ + \ + td->clone_func(&e->data, app_data); \ + STAILQ_INSERT_TAIL(&td->snapshot_data, e, entries); \ +} \ + \ +int \ +__##ent##_test_data_foreach(struct ent##_test_data *td, \ + int (*forf)(struct ent *, void *), void *mdata) \ +{ \ + struct ent##_entry *e; \ + int rv; \ + \ + ATF_REQUIRE(td != NULL); \ + ATF_REQUIRE(forf != NULL); \ + \ + rv = 0; \ + STAILQ_FOREACH(e, &td->snapshot_data, entries) { \ + rv = forf(&e->data, mdata); \ + if (rv != 0) \ + break; \ + } \ + \ + return (rv); \ +} \ + \ +int \ +__##ent##_test_data_compare(struct ent##_test_data *td1, struct ent##_test_data *td2,\ + int (*cmp_func)(struct ent *, struct ent *, void *), void *mdata)\ +{ \ + struct ent##_entry *e1, *e2; \ + int rv; \ + \ + ATF_REQUIRE(td1 != NULL); \ + ATF_REQUIRE(td2 != NULL); \ + ATF_REQUIRE(cmp_func != NULL); \ + \ + e1 = STAILQ_FIRST(&td1->snapshot_data); \ + e2 = STAILQ_FIRST(&td2->snapshot_data); \ + \ + rv = 0; \ + do { \ + if ((e1 == NULL) || (e2 == NULL)) { \ + if (e1 == e2) \ + return (0); \ + else \ + return (-1); \ + } \ + \ + rv = cmp_func(&e1->data, &e2->data, mdata); \ + e1 = STAILQ_NEXT(e1, entries); \ + e2 = STAILQ_NEXT(e2, entries); \ + } while (rv == 0); \ + \ + return (rv); \ +} \ + \ +struct ent * \ +__##ent##_test_data_find(struct ent##_test_data *td, struct ent *data, \ + int (*cmp)(struct ent *, struct ent *, void *), void *mdata) \ +{ \ + struct ent##_entry *e; \ + struct ent *result; \ + \ + ATF_REQUIRE(td != NULL); \ + ATF_REQUIRE(cmp != NULL); \ + \ + result = NULL; \ + STAILQ_FOREACH(e, &td->snapshot_data, entries) { \ + if (cmp(&e->data, data, mdata) == 0) { \ + result = &e->data; \ + break; \ + } \ + } \ + \ + return (result); \ +} \ + \ + \ +void \ +__##ent##_test_data_clear(struct ent##_test_data *td) \ +{ \ + struct ent##_entry *e; \ + ATF_REQUIRE(td != NULL); \ + \ + while (!STAILQ_EMPTY(&td->snapshot_data)) { \ + e = STAILQ_FIRST(&td->snapshot_data); \ + STAILQ_REMOVE_HEAD(&td->snapshot_data, entries); \ + \ + td->free_func(&e->data); \ + free(e); \ + e = NULL; \ + } \ +} + +#define DECLARE_TEST_FILE_SNAPSHOT(ent) \ +struct ent##_snp_param { \ + FILE *fp; \ + void (*sdump_func)(struct ent *, char *, size_t); \ +}; \ + \ +int __##ent##_snapshot_write_func(struct ent *, void *); \ +int __##ent##_snapshot_write(char const *, struct ent##_test_data *, \ + void (*)(struct ent *, char *, size_t)); \ +int __##ent##_snapshot_read(char const *, struct ent##_test_data *, \ + int (*)(struct ent *, char *)); + +#define TEST_SNAPSHOT_FILE_WRITE(ent, fname, td, f) \ + __##ent##_snapshot_write(fname, td, f) +#define TEST_SNAPSHOT_FILE_READ(ent, fname, td, f) \ + __##ent##_snapshot_read(fname, td, f) + +#define IMPLEMENT_TEST_FILE_SNAPSHOT(ent) \ +int \ +__##ent##_snapshot_write_func(struct ent *data, void *mdata) \ +{ \ + char buffer[1024]; \ + struct ent##_snp_param *param; \ + \ + ATF_REQUIRE(data != NULL); \ + \ + param = (struct ent##_snp_param *)mdata; \ + param->sdump_func(data, buffer, sizeof(buffer)); \ + fputs(buffer, param->fp); \ + fputc('\n', param->fp); \ + \ + return (0); \ +} \ + \ +int \ +__##ent##_snapshot_write(char const *fname, struct ent##_test_data *td, \ + void (*sdump_func)(struct ent *, char *, size_t)) \ +{ \ + struct ent##_snp_param param; \ + \ + ATF_REQUIRE(fname != NULL); \ + ATF_REQUIRE(td != NULL); \ + \ + param.fp = fopen(fname, "w"); \ + if (param.fp == NULL) \ + return (-1); \ + \ + param.sdump_func = sdump_func; \ + __##ent##_test_data_foreach(td, __##ent##_snapshot_write_func, ¶m);\ + fclose(param.fp); \ + \ + return (0); \ +} \ + \ +int \ +__##ent##_snapshot_read(char const *fname, struct ent##_test_data *td, \ + int (*read_func)(struct ent *, char *)) \ +{ \ + char buffer[1024]; \ + struct ent data; \ + char *s; \ + FILE *fi; \ + size_t len; \ + int rv; \ + \ + ATF_REQUIRE(fname != NULL); \ + ATF_REQUIRE(td != NULL); \ + \ + fi = fopen(fname, "r"); \ + if (fi == NULL) \ + return (-1); \ + \ + rv = 0; \ + memset(buffer, 0, sizeof(buffer)); \ + while (!feof(fi)) { \ + s = fgets(buffer, sizeof(buffer), fi); \ + if (s != NULL && s[0] != '#') { \ + len = strlen(s); \ + if (len == 0) \ + continue; \ + if (buffer[len - 1] == '\n') \ + buffer[len -1] = '\0'; \ + \ + rv = read_func(&data, s); \ + if (rv == 0) { \ + __##ent##_test_data_append(td, &data); \ + td->free_func(&data); \ + } else \ + goto fin; \ + } \ + } \ + \ +fin: \ + fclose(fi); \ + return (rv); \ +} + +#define DECLARE_1PASS_TEST(ent) \ +int __##ent##_1pass_test(struct ent##_test_data *, \ + int (*)(struct ent *, void *), \ + void *); + +#define DO_1PASS_TEST(ent, td, f, mdata) \ + __##ent##_1pass_test(td, f, mdata) + +#define IMPLEMENT_1PASS_TEST(ent) \ +int \ +__##ent##_1pass_test(struct ent##_test_data *td, \ + int (*tf)(struct ent *, void *), \ + void *mdata) \ +{ \ + int rv; \ + rv = __##ent##_test_data_foreach(td, tf, mdata); \ + \ + return (rv); \ +} + +#define DECLARE_2PASS_TEST(ent) \ +int __##ent##_2pass_test(struct ent##_test_data *, \ + struct ent##_test_data *, \ + int (*)(struct ent *, struct ent *, void *), void *); + +#define DO_2PASS_TEST(ent, td1, td2, f, mdata) \ + __##ent##_2pass_test(td1, td2, f, mdata) + +#define IMPLEMENT_2PASS_TEST(ent) \ +int \ +__##ent##_2pass_test(struct ent##_test_data *td1, \ + struct ent##_test_data *td2, \ + int (*cmp_func)(struct ent *, struct ent *, void *), \ + void *cmp_mdata) \ +{ \ + int rv; \ + \ + rv = __##ent##_test_data_compare(td1, td2, cmp_func, cmp_mdata); \ + return (rv); \ +} diff --git a/lib/libc/tests/resolv/Makefile b/lib/libc/tests/resolv/Makefile new file mode 100644 index 0000000..c6d9900 --- /dev/null +++ b/lib/libc/tests/resolv/Makefile @@ -0,0 +1,15 @@ +# $FreeBSD$ + +TESTSDIR= ${TESTSBASE}/lib/libc/resolv +BINDIR= ${TESTSDIR} + +FILES+= mach + +ATF_TESTS_C+= resolv_test + +# Note: this test relies on being dynamically linked. You will get a +# spurious PASS for a statically linked test. +DPADD.resolv_test+= ${LIBPTHREAD} +LDADD.resolv_test+= -lpthread + +.include diff --git a/lib/libc/tests/resolv/mach b/lib/libc/tests/resolv/mach new file mode 100644 index 0000000..4b47ebb --- /dev/null +++ b/lib/libc/tests/resolv/mach @@ -0,0 +1,46 @@ +# $FreeBSD$ +localhost +anoncvs.cirr.com +anoncvs.netbsd.se +antioche.antioche.eu.org +centaurus.4web.cz +chur.math.ntnu.no +console.netbsd.org +cvs.netbsd.org +cvsup.netbsd.se +ftp.chg.ru +ftp.estpak.ee +ftp.fsn.hu +ftp.funet.fi +ftp.netbsd.org +ftp.nluug.nl +ftp.plig.org +ftp.uni-erlangen.de +ftp.xgate.co.kr +gd.tuwien.ac.at +gort.ludd.luth.se +irc.warped.net +knug.youn.co.kr +mail.jp.netbsd.org +mail.netbsd.org +melanoma.cs.rmit.edu.au +mirror.aarnet.edu.au +moon.vub.ac.be +net.bsd.cz +netbsd.3miasto.net +netbsd.4ka.mipt.ru +netbsd.csie.nctu.edu.tw +netbsd.enderunix.org +netbsd.ftp.fu-berlin.de +netbsd.pair.com +netbsdiso.interoute.net.uk +netbsdwww.cs.rmit.edu.au +netbsdwww.interoute.net.uk +ns.netbsd.org +skeleton.phys.spbu.ru +www.en.netbsd.de +www.netbsd.cl +www.netbsd.nl +www.netbsd.org +www.netbsd.ro +zeppo.rediris.es diff --git a/lib/libc/tests/resolv/resolv_test.c b/lib/libc/tests/resolv/resolv_test.c new file mode 100644 index 0000000..74e89b1 --- /dev/null +++ b/lib/libc/tests/resolv/resolv_test.c @@ -0,0 +1,331 @@ +/* $NetBSD: resolv.c,v 1.6 2004/05/23 16:59:11 christos Exp $ */ + +/*- + * Copyright (c) 2004 The NetBSD Foundation, Inc. + * All rights reserved. + * + * This code is derived from software contributed to The NetBSD Foundation + * by Christos Zoulas. + * + * 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 NETBSD FOUNDATION, INC. 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 FOUNDATION 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$ */ +#include +__RCSID("$NetBSD: resolv.c,v 1.6 2004/05/23 16:59:11 christos Exp $"); + +#include +#include +#include +#include +#include +#include +#include +#include +#include + +#include + +#define NTHREADS 10 +#define NHOSTS 100 +#define WS " \t\n\r" + +enum method { + METHOD_GETADDRINFO, + METHOD_GETHOSTBY, + METHOD_GETIPNODEBY +}; + +static StringList *hosts = NULL; +static enum method method = METHOD_GETADDRINFO; +static int *ask = NULL; +static int *got = NULL; + +static void load(const char *); +static void resolvone(int); +static void *resolvloop(void *); +static void run(int *); + +static pthread_mutex_t stats = PTHREAD_MUTEX_INITIALIZER; + +static void +load(const char *fname) +{ + FILE *fp; + size_t len; + char *line; + + if ((fp = fopen(fname, "r")) == NULL) + ATF_REQUIRE(fp != NULL); + while ((line = fgetln(fp, &len)) != NULL) { + char c = line[len]; + char *ptr; + line[len] = '\0'; + for (ptr = strtok(line, WS); ptr; ptr = strtok(NULL, WS)) { + if (ptr == '\0' || ptr[0] == '#') + continue; + sl_add(hosts, strdup(ptr)); + } + line[len] = c; + } + + (void)fclose(fp); +} + +static int +resolv_getaddrinfo(pthread_t self, char *host, int port) +{ + char portstr[6], buf[1024], hbuf[NI_MAXHOST], pbuf[NI_MAXSERV]; + struct addrinfo hints, *res; + int error, len; + + snprintf(portstr, sizeof(portstr), "%d", port); + memset(&hints, 0, sizeof(hints)); + hints.ai_family = AF_UNSPEC; + hints.ai_flags = AI_PASSIVE; + hints.ai_socktype = SOCK_STREAM; + error = getaddrinfo(host, portstr, &hints, &res); + len = snprintf(buf, sizeof(buf), "%p: host %s %s\n", + self, host, error ? "not found" : "ok"); + (void)write(STDOUT_FILENO, buf, len); + if (error == 0) { + memset(hbuf, 0, sizeof(hbuf)); + memset(pbuf, 0, sizeof(pbuf)); + getnameinfo(res->ai_addr, res->ai_addrlen, hbuf, sizeof(hbuf), + pbuf, sizeof(pbuf), 0); + len = snprintf(buf, sizeof(buf), + "%p: reverse %s %s\n", self, hbuf, pbuf); + (void)write(STDOUT_FILENO, buf, len); + } + if (error == 0) + freeaddrinfo(res); + return error; +} + +static int +resolv_gethostby(pthread_t self, char *host) +{ + char buf[1024]; + struct hostent *hp, *hp2; + int len; + + hp = gethostbyname(host); + len = snprintf(buf, sizeof(buf), "%p: host %s %s\n", + self, host, (hp == NULL) ? "not found" : "ok"); + (void)write(STDOUT_FILENO, buf, len); + if (hp) { + memcpy(buf, hp->h_addr, hp->h_length); + hp2 = gethostbyaddr(buf, hp->h_length, hp->h_addrtype); + if (hp2) { + len = snprintf(buf, sizeof(buf), + "%p: reverse %s\n", self, hp2->h_name); + (void)write(STDOUT_FILENO, buf, len); + } + } + return hp ? 0 : -1; +} + +static int +resolv_getipnodeby(pthread_t self, char *host) +{ + char buf[1024]; + struct hostent *hp, *hp2; + int len, h_error; + + hp = getipnodebyname(host, AF_INET, 0, &h_error); + len = snprintf(buf, sizeof(buf), "%p: host %s %s\n", + self, host, (hp == NULL) ? "not found" : "ok"); + (void)write(STDOUT_FILENO, buf, len); + if (hp) { + memcpy(buf, hp->h_addr, hp->h_length); + hp2 = getipnodebyaddr(buf, hp->h_length, hp->h_addrtype, + &h_error); + if (hp2) { + len = snprintf(buf, sizeof(buf), + "%p: reverse %s\n", self, hp2->h_name); + (void)write(STDOUT_FILENO, buf, len); + } + if (hp2) + freehostent(hp2); + } + if (hp) + freehostent(hp); + return hp ? 0 : -1; +} + +static void +resolvone(int n) +{ + char buf[1024]; + pthread_t self = pthread_self(); + size_t i = (random() & 0x0fffffff) % hosts->sl_cur; + char *host = hosts->sl_str[i]; + struct addrinfo hints, *res; + int error, len; + + len = snprintf(buf, sizeof(buf), "%p: %d resolving %s %d\n", + self, n, host, (int)i); + (void)write(STDOUT_FILENO, buf, len); + switch (method) { + case METHOD_GETADDRINFO: + error = resolv_getaddrinfo(self, host, i); + break; + case METHOD_GETHOSTBY: + error = resolv_gethostby(self, host); + break; + case METHOD_GETIPNODEBY: + error = resolv_getipnodeby(self, host); + break; + default: + break; + } + pthread_mutex_lock(&stats); + ask[i]++; + got[i] += error == 0; + pthread_mutex_unlock(&stats); +} + +static void * +resolvloop(void *p) +{ + int *nhosts = (int *)p; + if (*nhosts == 0) + return NULL; + do + resolvone(*nhosts); + while (--(*nhosts)); + return NULL; +} + +static void +run(int *nhosts) +{ + pthread_t self; + int rc; + + self = pthread_self(); + rc = pthread_create(&self, NULL, resolvloop, nhosts); + ATF_REQUIRE_MSG(rc == 0, "pthread_create failed: %s", strerror(rc)); +} + +static int +run_tests(const char *hostlist_file, enum method method) +{ + int nthreads = NTHREADS; + int nhosts = NHOSTS; + int i, c, done, *nleft; + hosts = sl_init(); + + srandom(1234); + + load(hostlist_file); + + ATF_REQUIRE_MSG(0 < hosts->sl_cur, "0 hosts in %s", hostlist_file); + + nleft = malloc(nthreads * sizeof(int)); + ATF_REQUIRE(nleft != NULL); + + ask = calloc(hosts->sl_cur, sizeof(int)); + ATF_REQUIRE(ask != NULL); + + got = calloc(hosts->sl_cur, sizeof(int)); + ATF_REQUIRE(got != NULL); + + for (i = 0; i < nthreads; i++) { + nleft[i] = nhosts; + run(&nleft[i]); + } + + for (done = 0; !done;) { + done = 1; + for (i = 0; i < nthreads; i++) { + if (nleft[i] != 0) { + done = 0; + break; + } + } + sleep(1); + } + c = 0; + for (i = 0; i < hosts->sl_cur; i++) { + if (ask[i] != got[i] && got[i] != 0) { + printf("Error: host %s ask %d got %d\n", + hosts->sl_str[i], ask[i], got[i]); + c++; + } + } + free(nleft); + free(ask); + free(got); + sl_free(hosts, 1); + return c; +} + +#define HOSTLIST_FILE "mach" + +#define RUN_TESTS(tc, method) \ +do { \ + char *_hostlist_file; \ + ATF_REQUIRE(0 < asprintf(&_hostlist_file, "%s/%s", \ + atf_tc_get_config_var(tc, "srcdir"), HOSTLIST_FILE)); \ + ATF_REQUIRE(run_tests(_hostlist_file, method) == 0); \ +} while(0) + +ATF_TC(getaddrinfo_test); +ATF_TC_HEAD(getaddrinfo_test, tc) { + atf_tc_set_md_var(tc, "timeout", "450"); +} +ATF_TC_BODY(getaddrinfo_test, tc) +{ + + RUN_TESTS(tc, METHOD_GETADDRINFO); +} + +ATF_TC(gethostby_test); +ATF_TC_HEAD(gethostby_test, tc) { + atf_tc_set_md_var(tc, "timeout", "450"); +} +ATF_TC_BODY(gethostby_test, tc) +{ + + RUN_TESTS(tc, METHOD_GETHOSTBY); +} + +ATF_TC(getipnodeby_test); +ATF_TC_HEAD(getipnodeby_test, tc) { + + atf_tc_set_md_var(tc, "timeout", "450"); +} +ATF_TC_BODY(getipnodeby_test, tc) +{ + + RUN_TESTS(tc, METHOD_GETIPNODEBY); +} + +ATF_TP_ADD_TCS(tp) +{ + + ATF_TP_ADD_TC(tp, getaddrinfo_test); + ATF_TP_ADD_TC(tp, gethostby_test); + ATF_TP_ADD_TC(tp, getipnodeby_test); + + return (atf_no_error()); +} -- cgit v1.1 From 113fbc51614b9d1c6c59058c966e50e4ace42e48 Mon Sep 17 00:00:00 2001 From: ngie Date: Mon, 28 Dec 2015 23:32:27 +0000 Subject: MFC r292569: Make the mac_portacl testcases work / more robust - A trap(1) call has been added to the test scripts to better ensure that the tests do a better job at trying to restore the test host state at the end of the tests (if the test was interrupted before it would leave the system in an odd state, potentially making the test results for subsequent runs non-deterministic). - Add root user checks - Fix nc(1) usage: -- -o is deprecated -- Using `-w 10` will make the call timeout after 10 seconds so it doesn't block indefinitely - Use local variables - Be more terse in the error messages - Parameterize out "127.0.0.1" Sponsored by: EMC / Isilon Storage Division --- tools/regression/mac/mac_portacl/misc.sh | 44 +++++++++++++++++++------------ tools/regression/mac/mac_portacl/nobody.t | 4 +-- tools/regression/mac/mac_portacl/root.t | 4 +-- 3 files changed, 31 insertions(+), 21 deletions(-) diff --git a/tools/regression/mac/mac_portacl/misc.sh b/tools/regression/mac/mac_portacl/misc.sh index a1f152b..5a9e67b 100755 --- a/tools/regression/mac/mac_portacl/misc.sh +++ b/tools/regression/mac/mac_portacl/misc.sh @@ -6,10 +6,18 @@ if [ $? -ne 0 ]; then echo "1..0 # SKIP MAC_PORTACL is unavailable." exit 0 fi +if [ $(id -u) -ne 0 ]; then + echo "1..0 # SKIP testcases must be run as root" + exit 0 +fi ntest=1 check_bind() { + local host idtype name proto port udpflag + + host="127.0.0.1" + idtype=${1} name=${2} proto=${3} @@ -17,10 +25,10 @@ check_bind() { [ "${proto}" = "udp" ] && udpflag="-u" - out=`( + out=$( case "${idtype}" in uid|gid) - ( echo -n | su -m ${name} -c "nc ${udpflag} -o -l 127.0.0.1 $port" 2>&1 ) & + ( echo -n | su -m ${name} -c "nc ${udpflag} -l -w 10 $host $port" 2>&1 ) & ;; jail) kill $$ @@ -29,9 +37,9 @@ check_bind() { kill $$ esac sleep 0.3 - echo | nc ${udpflag} -o 127.0.0.1 $port >/dev/null 2>&1 + echo | nc ${udpflag} -w 10 $host $port >/dev/null 2>&1 wait - )` + ) case "${out}" in "nc: Permission denied"*|"nc: Operation not permitted"*) echo fl @@ -46,6 +54,8 @@ check_bind() { } bind_test() { + local expect_without_rule expect_with_rule idtype name proto port + expect_without_rule=${1} expect_with_rule=${2} idtype=${3} @@ -54,40 +64,40 @@ bind_test() { port=${6} sysctl security.mac.portacl.rules= >/dev/null - out=`check_bind ${idtype} ${name} ${proto} ${port}` + out=$(check_bind ${idtype} ${name} ${proto} ${port}) if [ "${out}" = "${expect_without_rule}" ]; then echo "ok ${ntest}" elif [ "${out}" = "ok" -o "${out}" = "fl" ]; then - echo "not ok ${ntest}" + echo "not ok ${ntest} # '${out}' != '${expect_without_rule}'" else - echo "not ok ${ntest} # ${out}" + echo "not ok ${ntest} # unexpected output: '${out}'" fi - ntest=$((ntest+1)) + : $(( ntest += 1 )) if [ "${idtype}" = "uid" ]; then - idstr=`id -u ${name}` + idstr=$(id -u ${name}) elif [ "${idtype}" = "gid" ]; then - idstr=`id -g ${name}` + idstr=$(id -g ${name}) else idstr=${name} fi sysctl security.mac.portacl.rules=${idtype}:${idstr}:${proto}:${port} >/dev/null - out=`check_bind ${idtype} ${name} ${proto} ${port}` + out=$(check_bind ${idtype} ${name} ${proto} ${port}) if [ "${out}" = "${expect_with_rule}" ]; then echo "ok ${ntest}" elif [ "${out}" = "ok" -o "${out}" = "fl" ]; then - echo "not ok ${ntest}" + echo "not ok ${ntest} # '${out}' != '${expect_with_rule}'" else - echo "not ok ${ntest} # ${out}" + echo "not ok ${ntest} # unexpected output: '${out}'" fi - ntest=$((ntest+1)) + : $(( ntest += 1 )) sysctl security.mac.portacl.rules= >/dev/null } -reserved_high=`sysctl -n net.inet.ip.portrange.reservedhigh` -suser_exempt=`sysctl -n security.mac.portacl.suser_exempt` -port_high=`sysctl -n security.mac.portacl.port_high` +reserved_high=$(sysctl -n net.inet.ip.portrange.reservedhigh) +suser_exempt=$(sysctl -n security.mac.portacl.suser_exempt) +port_high=$(sysctl -n security.mac.portacl.port_high) restore_settings() { sysctl -n net.inet.ip.portrange.reservedhigh=${reserved_high} >/dev/null diff --git a/tools/regression/mac/mac_portacl/nobody.t b/tools/regression/mac/mac_portacl/nobody.t index c0754eb..7d8dbd6 100755 --- a/tools/regression/mac/mac_portacl/nobody.t +++ b/tools/regression/mac/mac_portacl/nobody.t @@ -10,6 +10,8 @@ echo "1..64" # behaviour. # mac_portacl has no impact on ports <= net.inet.ip.portrange.reservedhigh. +trap restore_settings EXIT INT TERM + sysctl security.mac.portacl.suser_exempt=1 >/dev/null sysctl net.inet.ip.portrange.reservedhigh=78 >/dev/null @@ -63,5 +65,3 @@ bind_test fl ok gid nobody tcp 77 bind_test ok ok gid nobody tcp 7777 bind_test fl ok gid nobody udp 77 bind_test ok ok gid nobody udp 7777 - -restore_settings diff --git a/tools/regression/mac/mac_portacl/root.t b/tools/regression/mac/mac_portacl/root.t index 626bdfa..9ed452f 100755 --- a/tools/regression/mac/mac_portacl/root.t +++ b/tools/regression/mac/mac_portacl/root.t @@ -8,6 +8,8 @@ echo "1..48" # Verify if security.mac.portacl.suser_exempt=1 really exempts super-user. +trap restore_settings EXIT INT TERM + sysctl security.mac.portacl.suser_exempt=1 >/dev/null bind_test ok ok uid root tcp 77 @@ -47,5 +49,3 @@ bind_test fl ok gid root tcp 77 bind_test fl ok gid root tcp 7777 bind_test fl ok gid root udp 77 bind_test fl ok gid root udp 7777 - -restore_settings -- cgit v1.1 From 8dfa514cac3d4d5ea56e3fdb2f700bfd6750b8a6 Mon Sep 17 00:00:00 2001 From: ume Date: Tue, 29 Dec 2015 00:42:35 +0000 Subject: MFC r292550, r292595: Simplify _map_v4v6_address(). We don't need to use a temporary buffer, here. --- lib/libc/net/map_v4v6.c | 16 ++++------------ 1 file changed, 4 insertions(+), 12 deletions(-) diff --git a/lib/libc/net/map_v4v6.c b/lib/libc/net/map_v4v6.c index dbc7e70..871cfda 100644 --- a/lib/libc/net/map_v4v6.c +++ b/lib/libc/net/map_v4v6.c @@ -77,19 +77,11 @@ typedef union { void _map_v4v6_address(const char *src, char *dst) { - u_char *p = (u_char *)dst; - char tmp[NS_INADDRSZ]; - int i; - - /* Stash a temporary copy so our caller can update in place. */ - memcpy(tmp, src, NS_INADDRSZ); + /* Our caller may update in place. */ + memmove(&dst[12], src, NS_INADDRSZ); /* Mark this ipv6 addr as a mapped ipv4. */ - for (i = 0; i < 10; i++) - *p++ = 0x00; - *p++ = 0xff; - *p++ = 0xff; - /* Retrieve the saved copy and we're done. */ - memcpy((void*)p, tmp, NS_INADDRSZ); + memset(&dst[10], 0xff, 2); + memset(&dst[0], 0, 10); } void -- cgit v1.1 From 1afba7abbc9faeab77bb817b6aa853997479ee09 Mon Sep 17 00:00:00 2001 From: ngie Date: Tue, 29 Dec 2015 01:05:48 +0000 Subject: MFC r292578: Don't dump core files with lib/libc/ssp/ssp_test and lib/libc/gen/assert_test The default `sysctl kern.corefile` value is compatible with `kyua test` (FreeBSD will dump to the current directory). If it's set to an absolute path however, `kyua test` will not be able to clean up the corefiles after the fact The corefiles have little value when testing the behavior of feature behavior, so just disable corefile generation Obtained from: Isilon OneFS (^/onefs/head@r511419) Sponsored by: EMC / Isilon Storage Division --- contrib/netbsd-tests/lib/libc/gen/t_assert.c | 23 +++++++++++++++++++++++ contrib/netbsd-tests/lib/libc/ssp/t_ssp.sh | 1 + 2 files changed, 24 insertions(+) diff --git a/contrib/netbsd-tests/lib/libc/gen/t_assert.c b/contrib/netbsd-tests/lib/libc/gen/t_assert.c index 140417a..a09c130 100644 --- a/contrib/netbsd-tests/lib/libc/gen/t_assert.c +++ b/contrib/netbsd-tests/lib/libc/gen/t_assert.c @@ -40,6 +40,23 @@ __RCSID("$NetBSD: t_assert.c,v 1.2 2011/06/14 05:28:00 jruoho Exp $"); #include #include +#ifdef __FreeBSD__ +#include +#include +#include + +static void +disable_corefile(void) +{ + struct rlimit limits; + + limits.rlim_cur = 0; + limits.rlim_max = 0; + + ATF_REQUIRE(setrlimit(RLIMIT_CORE, &limits) == 0); +} +#endif + static void handler(int); static void @@ -65,6 +82,9 @@ ATF_TC_BODY(assert_false, tc) if (pid == 0) { +#ifdef __FreeBSD__ + disable_corefile(); +#endif (void)closefrom(0); (void)memset(&sa, 0, sizeof(struct sigaction)); @@ -102,6 +122,9 @@ ATF_TC_BODY(assert_true, tc) if (pid == 0) { +#ifdef __FreeBSD__ + disable_corefile(); +#endif (void)closefrom(0); (void)memset(&sa, 0, sizeof(struct sigaction)); diff --git a/contrib/netbsd-tests/lib/libc/ssp/t_ssp.sh b/contrib/netbsd-tests/lib/libc/ssp/t_ssp.sh index 04adc67..2986ccf 100755 --- a/contrib/netbsd-tests/lib/libc/ssp/t_ssp.sh +++ b/contrib/netbsd-tests/lib/libc/ssp/t_ssp.sh @@ -35,6 +35,7 @@ h_fail() { echo "Executing command [ $2$1 ]" # Begin FreeBSD + ulimit -c 0 if true; then eval $2 atf_check -s signal -o ignore -e ignore $1 else -- cgit v1.1 From 27241dd28beeb2415d518a2877d94c8f4056a0a9 Mon Sep 17 00:00:00 2001 From: ngie Date: Tue, 29 Dec 2015 01:07:00 +0000 Subject: MFC r292581: Use stable output to a test file instead of depending on the OS name being grep'able in /bin/sh This fixes the situation where the OS has been rebranded to something other than `FreeBSD` Obtained from: Isilon OneFS (^/onefs/head@r511419) Reviewed by: cem, Daniel O'Connor Sponsored by: EMC / Isilon Storage Division --- contrib/netbsd-tests/usr.bin/grep/d_binary.out | 2 +- contrib/netbsd-tests/usr.bin/grep/t_grep.sh | 13 +++++++++++++ 2 files changed, 14 insertions(+), 1 deletion(-) diff --git a/contrib/netbsd-tests/usr.bin/grep/d_binary.out b/contrib/netbsd-tests/usr.bin/grep/d_binary.out index ce03056..f0ef988 100644 --- a/contrib/netbsd-tests/usr.bin/grep/d_binary.out +++ b/contrib/netbsd-tests/usr.bin/grep/d_binary.out @@ -1 +1 @@ -Binary file /bin/sh matches +Binary file test.file matches diff --git a/contrib/netbsd-tests/usr.bin/grep/t_grep.sh b/contrib/netbsd-tests/usr.bin/grep/t_grep.sh index f2d70f0..7e53016 100755 --- a/contrib/netbsd-tests/usr.bin/grep/t_grep.sh +++ b/contrib/netbsd-tests/usr.bin/grep/t_grep.sh @@ -43,7 +43,20 @@ binary_head() } binary_body() { + # Begin FreeBSD + # + # Generate stable output instead of depending on uname to match the + # branded OS name of /bin/sh + if true; then + dd if=/dev/zero count=1 of=test.file + echo -n "foobar" >> test.file + atf_check -o file:"$(atf_get_srcdir)/d_binary.out" grep foobar test.file + else + # End FreeBSD atf_check -o file:"$(atf_get_srcdir)/d_binary.out" grep $(uname) /bin/sh + # Begin FreeBSD + fi + # End FreeBSD } atf_test_case recurse -- cgit v1.1 From 5d20de4a86d8a94c79847288c10ae3de90145c67 Mon Sep 17 00:00:00 2001 From: ngie Date: Tue, 29 Dec 2015 01:08:07 +0000 Subject: MFC r292582: Dump out the output from flock_helper on failure so failures with the test app can be debugged Obtained from: Isilon OneFS (^/onefs/head@r511419) Sponsored by: EMC / Isilon Storage Division --- tests/sys/file/flock_test.sh | 5 +++-- 1 file changed, 3 insertions(+), 2 deletions(-) diff --git a/tests/sys/file/flock_test.sh b/tests/sys/file/flock_test.sh index ac3e799..ffd3d18 100755 --- a/tests/sys/file/flock_test.sh +++ b/tests/sys/file/flock_test.sh @@ -48,10 +48,11 @@ for n in `seq 1 $last_testcase`; do todomsg=" # TODO: racy testcase (doesn't handle EINTR properly)" fi - $(dirname $0)/flock_helper . $n | grep -q SUCCEED - if [ $? -eq 0 ]; then + output=$($(dirname $0)/flock_helper . $n) + if echo "$output" | grep -q SUCCEED; then echo "ok $n$todomsg" else echo "not ok $n$todomsg" + echo "$output" >&2 fi done -- cgit v1.1 From 6a3209fa7085d7589c9a7ce26e2616583bb6d964 Mon Sep 17 00:00:00 2001 From: ngie Date: Tue, 29 Dec 2015 01:08:58 +0000 Subject: MFC r292585: Prevent use-after-free with ctx->ns in set_nameservers(..), which could occur if the memory wasn't allocated again later on Reported by: Coverity Submitted by: Miles Ohlrich Sponsored by: EMC / Isilon Storage Division --- usr.sbin/uhsoctl/uhsoctl.c | 1 + 1 file changed, 1 insertion(+) diff --git a/usr.sbin/uhsoctl/uhsoctl.c b/usr.sbin/uhsoctl/uhsoctl.c index 21b6220..92efed8 100644 --- a/usr.sbin/uhsoctl/uhsoctl.c +++ b/usr.sbin/uhsoctl/uhsoctl.c @@ -453,6 +453,7 @@ set_nameservers(struct ctx *ctx, const char *respath, int ns, ...) free(ctx->ns[i]); } free(ctx->ns); + ctx->ns = NULL; } fd = open(respath, O_RDWR | O_CREAT | O_NOFOLLOW, 0666); -- cgit v1.1 From 8a5352a05efd1beaf7bfba09905615c8a8a7e5bf Mon Sep 17 00:00:00 2001 From: kib Date: Tue, 29 Dec 2015 16:09:15 +0000 Subject: MFC r292620: Show the actual error code when interpreter cannot be loaded. --- sys/kern/imgact_elf.c | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/sys/kern/imgact_elf.c b/sys/kern/imgact_elf.c index 520cc8b..eaa3ee1 100644 --- a/sys/kern/imgact_elf.c +++ b/sys/kern/imgact_elf.c @@ -993,7 +993,8 @@ __CONCAT(exec_, __elfN(imgact))(struct image_params *imgp) } vn_lock(imgp->vp, LK_EXCLUSIVE | LK_RETRY); if (error != 0) { - uprintf("ELF interpreter %s not found\n", interp); + uprintf("ELF interpreter %s not found, error %d\n", + interp, error); goto ret; } } else -- cgit v1.1 From 9de1d6b4e9c4dd38e957590cbca5b951e2a3f7fe Mon Sep 17 00:00:00 2001 From: kib Date: Tue, 29 Dec 2015 16:11:43 +0000 Subject: MFC r292621: Keep devfs mount locked for the whole duration of the devfs_setattr(), and ensure that our dirent is instantiated. --- sys/fs/devfs/devfs_vnops.c | 21 ++++++++++++++------- 1 file changed, 14 insertions(+), 7 deletions(-) diff --git a/sys/fs/devfs/devfs_vnops.c b/sys/fs/devfs/devfs_vnops.c index 17a336f..816a340 100644 --- a/sys/fs/devfs/devfs_vnops.c +++ b/sys/fs/devfs/devfs_vnops.c @@ -1533,11 +1533,15 @@ devfs_setattr(struct vop_setattr_args *ap) return (EINVAL); } + error = devfs_populate_vp(vp); + if (error != 0) + return (error); + de = vp->v_data; if (vp->v_type == VDIR) de = de->de_dir; - error = c = 0; + c = 0; if (vap->va_uid == (uid_t)VNOVAL) uid = de->de_uid; else @@ -1550,8 +1554,8 @@ devfs_setattr(struct vop_setattr_args *ap) if ((ap->a_cred->cr_uid != de->de_uid) || uid != de->de_uid || (gid != de->de_gid && !groupmember(gid, ap->a_cred))) { error = priv_check(td, PRIV_VFS_CHOWN); - if (error) - return (error); + if (error != 0) + goto ret; } de->de_uid = uid; de->de_gid = gid; @@ -1561,8 +1565,8 @@ devfs_setattr(struct vop_setattr_args *ap) if (vap->va_mode != (mode_t)VNOVAL) { if (ap->a_cred->cr_uid != de->de_uid) { error = priv_check(td, PRIV_VFS_ADMIN); - if (error) - return (error); + if (error != 0) + goto ret; } de->de_mode = vap->va_mode; c = 1; @@ -1571,7 +1575,7 @@ devfs_setattr(struct vop_setattr_args *ap) if (vap->va_atime.tv_sec != VNOVAL || vap->va_mtime.tv_sec != VNOVAL) { error = vn_utimes_perm(vp, vap, ap->a_cred, td); if (error != 0) - return (error); + goto ret; if (vap->va_atime.tv_sec != VNOVAL) { if (vp->v_type == VCHR) vp->v_rdev->si_atime = vap->va_atime; @@ -1593,7 +1597,10 @@ devfs_setattr(struct vop_setattr_args *ap) else vfs_timestamp(&de->de_mtime); } - return (0); + +ret: + sx_xunlock(&VFSTODEVFS(vp->v_mount)->dm_lock); + return (error); } #ifdef MAC -- cgit v1.1 From 3b6f2bf3ae76b7e065823a23f43ce979f2ed65fa Mon Sep 17 00:00:00 2001 From: ngie Date: Tue, 29 Dec 2015 18:22:06 +0000 Subject: MFC r265842,r266120,r266121,r266959,r267148,r269985,r281789,r282261,r285064: r265842 (by eadler): arcconfig: add one Add a .arcconfig to allow arc to work in its usual way. r266120 (by bapt): Add project name to the arc config it is still required when arcanist is used with SVN r266121 (by bapt): Add the missing coma r266959 (by eadler): arc: add linting for python files r267148 (by bapt): Prevent arc commands from overwriting history r269985 (by gjb): Update the URL to the phabricator instance. Sponsored by: The FreeBSD Foundation r281789 (by eadler): phabricator related changes: - don't lint either contrib or crypto: these are both externally written directories - add additional linters for spelling (check common typos like teh -> the) - chmod linter checks for executible bit on bad files - merge-conflict checks for merge conflict tokens then may have been resolved incorrectly - filename checks for back characters in filenames - json for json syntax correctness - remove history.immutable: it is meaningless on subversion, and causes workflow problems when trying to use git. It it set to 'true' by default with hg r282261 (by eadler): Phabricator: enable "history.immutable": With certain arc workflows leaving history.immutable as false results in using the upstream template instead of our usual commit template. Since the git workflow issues alluded to in my prior commit message can be worked around, set history.immutable once again. r285064 (by mat): Add repository.callsign, to help arcanist figure out what repo it's doing things on when not using Subversion. With hat: phabric-admin@ Sponsored by: Absolight --- .arcconfig | 6 ++++++ .arclint | 25 +++++++++++++++++++++++++ 2 files changed, 31 insertions(+) create mode 100644 .arcconfig create mode 100644 .arclint diff --git a/.arcconfig b/.arcconfig new file mode 100644 index 0000000..54153b9 --- /dev/null +++ b/.arcconfig @@ -0,0 +1,6 @@ +{ + "project.name": "S", + "repository.callsign" : "S", + "phabricator.uri" : "https://reviews.freebsd.org/", + "history.immutable" : true +} diff --git a/.arclint b/.arclint new file mode 100644 index 0000000..31bda09 --- /dev/null +++ b/.arclint @@ -0,0 +1,25 @@ +{ + "exclude": "(contrib|crypto)", + "linters": { + "python": { + "type": "pep8", + "include": "(\\.py$)" + }, + "spelling": { + "type": "spelling" + }, + "chmod": { + "type": "chmod" + }, + "merge-conflict": { + "type": "merge-conflict" + }, + "filename": { + "type": "filename" + }, + "json": { + "type": "json", + "include": "(\\.arclint|\\.json$)" + } + } +} -- cgit v1.1 From 9b5243984615bae99fea2b4182c3d21480a7c076 Mon Sep 17 00:00:00 2001 From: emaste Date: Tue, 29 Dec 2015 20:36:11 +0000 Subject: crunchide: Restore IA-64 support accidentally lost in r292421 mismerge Reported by: ngie --- usr.sbin/crunch/crunchide/exec_elf32.c | 1 + 1 file changed, 1 insertion(+) diff --git a/usr.sbin/crunch/crunchide/exec_elf32.c b/usr.sbin/crunch/crunchide/exec_elf32.c index 52a340c..efbc60a 100644 --- a/usr.sbin/crunch/crunchide/exec_elf32.c +++ b/usr.sbin/crunch/crunchide/exec_elf32.c @@ -183,6 +183,7 @@ ELFNAMEEND(check)(int fd, const char *fn) #endif case EM_AARCH64: break; case EM_ARM: break; + case EM_IA_64: break; case EM_MIPS: break; case /* EM_MIPS_RS3_LE */ EM_MIPS_RS4_BE: break; case EM_PPC: break; -- cgit v1.1 From a63a2e809b7e3f890e88ecd9f77d97fa5fd83a9a Mon Sep 17 00:00:00 2001 From: mckusick Date: Wed, 30 Dec 2015 00:04:33 +0000 Subject: MFC of 291244, 291380, 291459, 291460, 291671, and 291743: This MFC includes changes to better manage the vnode freelist and to streamline the allocation and freeing of vnodes. Note that to maintain the KPI the VI_AGE flag is left defined in sys/vnode.h though its use is dropped as described in 291380. To maintain KBI the vfs.vlru_alloc_cache_src sysctl variable remains though it no longer has any effect as described in 291244. MFC of 291244: Move the comment about resident pages preventing vnode from leaving active list, into the header comment for vdrop(), which is the function that decides whether to leave the vnode on the list. Note that dirty page write-out in vinactive() is asynchronous. Discussed with: alc Sponsored by: The FreeBSD Foundation MFC of 291380: Remove VI_AGE vnode iflag, it is unused. Noted by: bde Sponsored by: The FreeBSD Foundation MFC of 291459: For performance reasons, it is useful to have a single string used as the name of a filesystem when setting it as the first parameter to the getnewvnode() function. Most filesystems call getnewvnode from just one place so can use a literal string as the first parameter. However, NFS calls getnewvnode from two places, so we create a global constant string that can be used by the two instances. This change also collapses two instances of getnewvnode() in the UFS filesystem to a single call. Reviewed by: kib Tested by: Peter Holm MFC of 291460: As the kernel allocates and frees vnodes, it fully initializes them on every allocation and fully releases them on every free. These are not trivial costs: it starts by zeroing a large structure then initializes a mutex, a lock manager lock, an rw lock, four lists, and six pointers. And looking at vfs.vnodes_created, these operations are being done millions of times an hour on a busy machine. As a performance optimization, this code update uses the uma_init and uma_fini routines to do these initializations and cleanups only as the vnodes enter and leave the vnode_zone. With this change the initializations are only done kern.maxvnodes times at system startup and then only rarely again. The frees are done only if the vnode_zone shrinks which never happens in practice. For those curious about the avoided work, look at the vnode_init() and vnode_fini() functions in kern/vfs_subr.c to see the code that has been removed from the main vnode allocation/free path. Reviewed by: kib Tested by: Peter Holm MFC of 291671: We need to zero out the union of pointers in a freed vnode structure. Fix from: Mateusz Guzik Tested by: Jason Unovitch MFC of 291743: We need to zero out the clustering variables in a freed vnode structure. For completeness add a VNASSERT that there are no threads waiting on a range lock (this was previously checked on every vnode free). Reported by; Rick Macklem Fix from: Mateusz Guzik --- sys/fs/nfs/nfsport.h | 7 + sys/fs/nfsclient/nfs_clnode.c | 5 +- sys/fs/nfsclient/nfs_clport.c | 2 +- sys/kern/vfs_subr.c | 475 +++++++++++++++++++++++++++++++----------- sys/ufs/ffs/ffs_vfsops.c | 6 +- 5 files changed, 364 insertions(+), 131 deletions(-) diff --git a/sys/fs/nfs/nfsport.h b/sys/fs/nfs/nfsport.h index b46aef7..eea9df0 100644 --- a/sys/fs/nfs/nfsport.h +++ b/sys/fs/nfs/nfsport.h @@ -981,6 +981,13 @@ struct nfsreq { #define NFSVNO_DELEGOK(v) (1) #endif +/* + * Name used by getnewvnode() to describe filesystem, "newnfs". + * For perfomance reasons it is useful to have the same string + * used in both places that call getnewvnode(). + */ +extern const char nfs_vnode_tag[]; + #endif /* _KERNEL */ #endif /* _NFS_NFSPORT_H */ diff --git a/sys/fs/nfsclient/nfs_clnode.c b/sys/fs/nfsclient/nfs_clnode.c index 0cd503c..263185f 100644 --- a/sys/fs/nfsclient/nfs_clnode.c +++ b/sys/fs/nfsclient/nfs_clnode.c @@ -66,6 +66,8 @@ MALLOC_DECLARE(M_NEWNFSREQ); uma_zone_t newnfsnode_zone; +const char nfs_vnode_tag[] = "newnfs"; + static void nfs_freesillyrename(void *arg, __unused int pending); void @@ -124,7 +126,7 @@ ncl_nget(struct mount *mntp, u_int8_t *fhp, int fhsize, struct nfsnode **npp, } np = uma_zalloc(newnfsnode_zone, M_WAITOK | M_ZERO); - error = getnewvnode("newnfs", mntp, &newnfs_vnodeops, &nvp); + error = getnewvnode(nfs_vnode_tag, mntp, &newnfs_vnodeops, &nvp); if (error) { uma_zfree(newnfsnode_zone, np); return (error); @@ -332,4 +334,3 @@ ncl_invalcaches(struct vnode *vp) KDTRACE_NFS_ATTRCACHE_FLUSH_DONE(vp); mtx_unlock(&np->n_mtx); } - diff --git a/sys/fs/nfsclient/nfs_clport.c b/sys/fs/nfsclient/nfs_clport.c index 8c2e84b..f6919ab 100644 --- a/sys/fs/nfsclient/nfs_clport.c +++ b/sys/fs/nfsclient/nfs_clport.c @@ -199,7 +199,7 @@ nfscl_nget(struct mount *mntp, struct vnode *dvp, struct nfsfh *nfhp, } np = uma_zalloc(newnfsnode_zone, M_WAITOK | M_ZERO); - error = getnewvnode("newnfs", mntp, &newnfs_vnodeops, &nvp); + error = getnewvnode(nfs_vnode_tag, mntp, &newnfs_vnodeops, &nvp); if (error) { uma_zfree(newnfsnode_zone, np); FREE((caddr_t)nfhp, M_NFSFH); diff --git a/sys/kern/vfs_subr.c b/sys/kern/vfs_subr.c index 2df1e25..bad816b 100644 --- a/sys/kern/vfs_subr.c +++ b/sys/kern/vfs_subr.c @@ -145,24 +145,51 @@ int vttoif_tab[10] = { static TAILQ_HEAD(freelst, vnode) vnode_free_list; /* - * Free vnode target. Free vnodes may simply be files which have been stat'd - * but not read. This is somewhat common, and a small cache of such files - * should be kept to avoid recreation costs. + * "Free" vnode target. Free vnodes are rarely completely free, but are + * just ones that are cheap to recycle. Usually they are for files which + * have been stat'd but not read; these usually have inode and namecache + * data attached to them. This target is the preferred minimum size of a + * sub-cache consisting mostly of such files. The system balances the size + * of this sub-cache with its complement to try to prevent either from + * thrashing while the other is relatively inactive. The targets express + * a preference for the best balance. + * + * "Above" this target there are 2 further targets (watermarks) related + * to recyling of free vnodes. In the best-operating case, the cache is + * exactly full, the free list has size between vlowat and vhiwat above the + * free target, and recycling from it and normal use maintains this state. + * Sometimes the free list is below vlowat or even empty, but this state + * is even better for immediate use provided the cache is not full. + * Otherwise, vnlru_proc() runs to reclaim enough vnodes (usually non-free + * ones) to reach one of these states. The watermarks are currently hard- + * coded as 4% and 9% of the available space higher. These and the default + * of 25% for wantfreevnodes are too large if the memory size is large. + * E.g., 9% of 75% of MAXVNODES is more than 566000 vnodes to reclaim + * whenever vnlru_proc() becomes active. */ static u_long wantfreevnodes; -SYSCTL_ULONG(_vfs, OID_AUTO, wantfreevnodes, CTLFLAG_RW, &wantfreevnodes, 0, ""); -/* Number of vnodes in the free list. */ +SYSCTL_ULONG(_vfs, OID_AUTO, wantfreevnodes, CTLFLAG_RW, + &wantfreevnodes, 0, "Target for minimum number of \"free\" vnodes"); static u_long freevnodes; -SYSCTL_ULONG(_vfs, OID_AUTO, freevnodes, CTLFLAG_RD, &freevnodes, 0, - "Number of vnodes in the free list"); +SYSCTL_ULONG(_vfs, OID_AUTO, freevnodes, CTLFLAG_RD, + &freevnodes, 0, "Number of \"free\" vnodes"); +/* + * The vfs.vlru_allow_cache_src sysctl variable is no longer used but + * the sysctl remains to provide ABI compatibility. The new code frees + * namecache sources as the last chance to satisfy the highest watermark, + * instead of selecting the source vnodes randomly. This provides good + * enough behaviour to keep vn_fullpath() working in most situations. + * The filesystem layout with deep trees, where the depricated knob was + * required, is thus handled automatically. + */ static int vlru_allow_cache_src; SYSCTL_INT(_vfs, OID_AUTO, vlru_allow_cache_src, CTLFLAG_RW, - &vlru_allow_cache_src, 0, "Allow vlru to reclaim source vnode"); + &vlru_allow_cache_src, 0, "Placeholder for API compatibility (unused)"); static u_long recycles_count; SYSCTL_ULONG(_vfs, OID_AUTO, recycles, CTLFLAG_RD, &recycles_count, 0, - "Number of vnodes recycled to avoid exceding kern.maxvnodes"); + "Number of vnodes recycled to meet vnode cache targets"); /* * Various variables used for debugging the new implementation of @@ -272,14 +299,13 @@ static int syncer_worklist_len; static enum { SYNCER_RUNNING, SYNCER_SHUTTING_DOWN, SYNCER_FINAL_DELAY } syncer_state; -/* - * Number of vnodes we want to exist at any one time. This is mostly used - * to size hash tables in vnode-related code. It is normally not used in - * getnewvnode(), as wantfreevnodes is normally nonzero.) - * - * XXX desiredvnodes is historical cruft and should not exist. - */ +/* Target for maximum number of vnodes. */ int desiredvnodes; +static int gapvnodes; /* gap between wanted and desired */ +static int vhiwat; /* enough extras after expansion */ +static int vlowat; /* minimal extras before expansion */ +static int vstir; /* nonzero to stir non-free vnodes */ +static volatile int vsmalltrigger = 8; /* pref to keep if > this many pages */ static int sysctl_update_desiredvnodes(SYSCTL_HANDLER_ARGS) @@ -290,6 +316,8 @@ sysctl_update_desiredvnodes(SYSCTL_HANDLER_ARGS) if ((error = sysctl_handle_int(oidp, arg1, arg2, req)) != 0) return (error); if (old_desiredvnodes != desiredvnodes) { + wantfreevnodes = desiredvnodes / 4; + /* XXX locking seems to be incomplete. */ vfs_hash_changesize(desiredvnodes); cache_changesize(desiredvnodes); } @@ -298,9 +326,9 @@ sysctl_update_desiredvnodes(SYSCTL_HANDLER_ARGS) SYSCTL_PROC(_kern, KERN_MAXVNODES, maxvnodes, CTLTYPE_INT | CTLFLAG_MPSAFE | CTLFLAG_RW, &desiredvnodes, 0, - sysctl_update_desiredvnodes, "I", "Maximum number of vnodes"); + sysctl_update_desiredvnodes, "I", "Target for maximum number of vnodes"); SYSCTL_ULONG(_kern, OID_AUTO, minvnodes, CTLFLAG_RW, - &wantfreevnodes, 0, "Minimum number of vnodes (legacy)"); + &wantfreevnodes, 0, "Old name for vfs.wantfreevnodes (legacy)"); static int vnlru_nowhere; SYSCTL_INT(_debug, OID_AUTO, vnlru_nowhere, CTLFLAG_RW, &vnlru_nowhere, 0, "Number of times the vnlru process ran without success"); @@ -331,11 +359,71 @@ PCTRIE_DEFINE(BUF, buf, b_lblkno, buf_trie_alloc, buf_trie_free); * * Reevaluate the following cap on the number of vnodes after the physical * memory size exceeds 512GB. In the limit, as the physical memory size - * grows, the ratio of physical pages to vnodes approaches sixteen to one. + * grows, the ratio of the memory size in KB to to vnodes approaches 64:1. */ #ifndef MAXVNODES_MAX -#define MAXVNODES_MAX (512 * (1024 * 1024 * 1024 / (int)PAGE_SIZE / 16)) +#define MAXVNODES_MAX (512 * 1024 * 1024 / 64) /* 8M */ #endif + +/* + * Initialize a vnode as it first enters the zone. + */ +static int +vnode_init(void *mem, int size, int flags) +{ + struct vnode *vp; + struct bufobj *bo; + + vp = mem; + bzero(vp, size); + /* + * Setup locks. + */ + vp->v_vnlock = &vp->v_lock; + mtx_init(&vp->v_interlock, "vnode interlock", NULL, MTX_DEF); + /* + * By default, don't allow shared locks unless filesystems opt-in. + */ + lockinit(vp->v_vnlock, PVFS, "vnode", VLKTIMEOUT, + LK_NOSHARE | LK_IS_VNODE); + /* + * Initialize bufobj. + */ + bo = &vp->v_bufobj; + bo->__bo_vnode = vp; + rw_init(BO_LOCKPTR(bo), "bufobj interlock"); + bo->bo_private = vp; + TAILQ_INIT(&bo->bo_clean.bv_hd); + TAILQ_INIT(&bo->bo_dirty.bv_hd); + /* + * Initialize namecache. + */ + LIST_INIT(&vp->v_cache_src); + TAILQ_INIT(&vp->v_cache_dst); + /* + * Initialize rangelocks. + */ + rangelock_init(&vp->v_rl); + return (0); +} + +/* + * Free a vnode when it is cleared from the zone. + */ +static void +vnode_fini(void *mem, int size) +{ + struct vnode *vp; + struct bufobj *bo; + + vp = mem; + rangelock_destroy(&vp->v_rl); + lockdestroy(vp->v_vnlock); + mtx_destroy(&vp->v_interlock); + bo = &vp->v_bufobj; + rw_destroy(BO_LOCKPTR(bo)); +} + static void vntblinit(void *dummy __unused) { @@ -345,15 +433,16 @@ vntblinit(void *dummy __unused) /* * Desiredvnodes is a function of the physical memory size and the * kernel's heap size. Generally speaking, it scales with the - * physical memory size. The ratio of desiredvnodes to physical pages - * is one to four until desiredvnodes exceeds 98,304. Thereafter, the - * marginal ratio of desiredvnodes to physical pages is one to - * sixteen. However, desiredvnodes is limited by the kernel's heap + * physical memory size. The ratio of desiredvnodes to the physical + * memory size is 1:16 until desiredvnodes exceeds 98,304. + * Thereafter, the + * marginal ratio of desiredvnodes to the physical memory size is + * 1:64. However, desiredvnodes is limited by the kernel's heap * size. The memory required by desiredvnodes vnodes and vm objects - * may not exceed one seventh of the kernel's heap size. + * must not exceed 1/7th of the kernel's heap size. */ - physvnodes = maxproc + cnt.v_page_count / 16 + 3 * min(98304 * 4, - cnt.v_page_count) / 16; + physvnodes = maxproc + pgtok(cnt.v_page_count) / 64 + + 3 * min(98304 * 16, pgtok(cnt.v_page_count)) / 64; virtvnodes = vm_kmem_size / (7 * (sizeof(struct vm_object) + sizeof(struct vnode))); desiredvnodes = min(physvnodes, virtvnodes); @@ -368,7 +457,7 @@ vntblinit(void *dummy __unused) TAILQ_INIT(&vnode_free_list); mtx_init(&vnode_free_list_mtx, "vnode_free_list", NULL, MTX_DEF); vnode_zone = uma_zcreate("VNODE", sizeof (struct vnode), NULL, NULL, - NULL, NULL, UMA_ALIGN_PTR, 0); + vnode_init, vnode_fini, UMA_ALIGN_PTR, 0); vnodepoll_zone = uma_zcreate("VNODEPOLL", sizeof (struct vpollinfo), NULL, NULL, NULL, NULL, UMA_ALIGN_PTR, 0); /* @@ -742,35 +831,41 @@ vattr_null(struct vattr *vap) * you set kern.maxvnodes to. Do not set kern.maxvnodes too low. */ static int -vlrureclaim(struct mount *mp) +vlrureclaim(struct mount *mp, int reclaim_nc_src, int trigger) { struct vnode *vp; - int done; - int trigger; - int usevnodes; - int count; + int count, done, target; - /* - * Calculate the trigger point, don't allow user - * screwups to blow us up. This prevents us from - * recycling vnodes with lots of resident pages. We - * aren't trying to free memory, we are trying to - * free vnodes. - */ - usevnodes = desiredvnodes; - if (usevnodes <= 0) - usevnodes = 1; - trigger = cnt.v_page_count * 2 / usevnodes; done = 0; vn_start_write(NULL, &mp, V_WAIT); MNT_ILOCK(mp); - count = mp->mnt_nvnodelistsize / 10 + 1; - while (count != 0) { + count = mp->mnt_nvnodelistsize; + target = count * (int64_t)gapvnodes / imax(desiredvnodes, 1); + target = target / 10 + 1; + while (count != 0 && done < target) { vp = TAILQ_FIRST(&mp->mnt_nvnodelist); while (vp != NULL && vp->v_type == VMARKER) vp = TAILQ_NEXT(vp, v_nmntvnodes); if (vp == NULL) break; + /* + * XXX LRU is completely broken for non-free vnodes. First + * by calling here in mountpoint order, then by moving + * unselected vnodes to the end here, and most grossly by + * removing the vlruvp() function that was supposed to + * maintain the order. (This function was born broken + * since syncer problems prevented it doing anything.) The + * order is closer to LRC (C = Created). + * + * LRU reclaiming of vnodes seems to have last worked in + * FreeBSD-3 where LRU wasn't mentioned under any spelling. + * Then there was no hold count, and inactive vnodes were + * simply put on the free list in LRU order. The separate + * lists also break LRU. We prefer to reclaim from the + * free list for technical reasons. This tends to thrash + * the free list to keep very unrecently used held vnodes. + * The problem is mitigated by keeping the free list large. + */ TAILQ_REMOVE(&mp->mnt_nvnodelist, vp, v_nmntvnodes); TAILQ_INSERT_TAIL(&mp->mnt_nvnodelist, vp, v_nmntvnodes); --count; @@ -779,10 +874,12 @@ vlrureclaim(struct mount *mp) /* * If it's been deconstructed already, it's still * referenced, or it exceeds the trigger, skip it. + * Also skip free vnodes. We are trying to make space + * to expand the free list, not reduce it. */ if (vp->v_usecount || - (!vlru_allow_cache_src && - !LIST_EMPTY(&(vp)->v_cache_src)) || + (!reclaim_nc_src && !LIST_EMPTY(&vp->v_cache_src)) || + ((vp->v_iflag & VI_FREE) != 0) || (vp->v_iflag & VI_DOOMED) != 0 || (vp->v_object != NULL && vp->v_object->resident_page_count > trigger)) { VI_UNLOCK(vp); @@ -808,8 +905,8 @@ vlrureclaim(struct mount *mp) * vnode lock before our VOP_LOCK() call fails. */ if (vp->v_usecount || - (!vlru_allow_cache_src && - !LIST_EMPTY(&(vp)->v_cache_src)) || + (!reclaim_nc_src && !LIST_EMPTY(&vp->v_cache_src)) || + (vp->v_iflag & VI_FREE) != 0 || (vp->v_object != NULL && vp->v_object->resident_page_count > trigger)) { VOP_UNLOCK(vp, LK_INTERLOCK); @@ -842,7 +939,7 @@ relock_mnt: } /* - * Attempt to keep the free list at wantfreevnodes length. + * Attempt to reduce the free list by the requested amount. */ static void vnlru_free(int count) @@ -899,6 +996,24 @@ vnlru_free(int count) mtx_lock(&vnode_free_list_mtx); } } + +/* XXX some names and initialization are bad for limits and watermarks. */ +static int +vspace(void) +{ + int space; + + gapvnodes = imax(desiredvnodes - wantfreevnodes, 100); + vhiwat = gapvnodes / 11; /* 9% -- just under the 10% in vlrureclaim() */ + vlowat = vhiwat / 2; + if (numvnodes > desiredvnodes) + return (0); + space = desiredvnodes - numvnodes; + if (freevnodes > wantfreevnodes) + space += freevnodes - wantfreevnodes; + return (space); +} + /* * Attempt to recycle vnodes in a context that is always safe to block. * Calling vlrurecycle() from the bowels of filesystem code has some @@ -911,18 +1026,36 @@ static void vnlru_proc(void) { struct mount *mp, *nmp; - int done; - struct proc *p = vnlruproc; + unsigned long ofreevnodes, onumvnodes; + int done, force, reclaim_nc_src, trigger, usevnodes; - EVENTHANDLER_REGISTER(shutdown_pre_sync, kproc_shutdown, p, + EVENTHANDLER_REGISTER(shutdown_pre_sync, kproc_shutdown, vnlruproc, SHUTDOWN_PRI_FIRST); + force = 0; for (;;) { - kproc_suspend_check(p); + kproc_suspend_check(vnlruproc); mtx_lock(&vnode_free_list_mtx); - if (freevnodes > wantfreevnodes) - vnlru_free(freevnodes - wantfreevnodes); - if (numvnodes <= desiredvnodes * 9 / 10) { + /* + * If numvnodes is too large (due to desiredvnodes being + * adjusted using its sysctl, or emergency growth), first + * try to reduce it by discarding from the free list. + */ + if (numvnodes > desiredvnodes && freevnodes > 0) + vnlru_free(ulmin(numvnodes - desiredvnodes, + freevnodes)); + /* + * Sleep if the vnode cache is in a good state. This is + * when it is not over-full and has space for about a 4% + * or 9% expansion (by growing its size or inexcessively + * reducing its free list). Otherwise, try to reclaim + * space for a 10% expansion. + */ + if (vstir && force == 0) { + force = 1; + vstir = 0; + } + if (vspace() >= vlowat && force == 0) { vnlruproc_sig = 0; wakeup(&vnlruproc_sig); msleep(vnlruproc, &vnode_free_list_mtx, @@ -931,30 +1064,66 @@ vnlru_proc(void) } mtx_unlock(&vnode_free_list_mtx); done = 0; + ofreevnodes = freevnodes; + onumvnodes = numvnodes; + /* + * Calculate parameters for recycling. These are the same + * throughout the loop to give some semblance of fairness. + * The trigger point is to avoid recycling vnodes with lots + * of resident pages. We aren't trying to free memory; we + * are trying to recycle or at least free vnodes. + */ + if (numvnodes <= desiredvnodes) + usevnodes = numvnodes - freevnodes; + else + usevnodes = numvnodes; + if (usevnodes <= 0) + usevnodes = 1; + /* + * The trigger value is is chosen to give a conservatively + * large value to ensure that it alone doesn't prevent + * making progress. The value can easily be so large that + * it is effectively infinite in some congested and + * misconfigured cases, and this is necessary. Normally + * it is about 8 to 100 (pages), which is quite large. + */ + trigger = cnt.v_page_count * 2 / usevnodes; + if (force < 2) + trigger = vsmalltrigger; + reclaim_nc_src = force >= 3; mtx_lock(&mountlist_mtx); for (mp = TAILQ_FIRST(&mountlist); mp != NULL; mp = nmp) { if (vfs_busy(mp, MBF_NOWAIT | MBF_MNTLSTLOCK)) { nmp = TAILQ_NEXT(mp, mnt_list); continue; } - done += vlrureclaim(mp); + done += vlrureclaim(mp, reclaim_nc_src, trigger); mtx_lock(&mountlist_mtx); nmp = TAILQ_NEXT(mp, mnt_list); vfs_unbusy(mp); } mtx_unlock(&mountlist_mtx); + if (onumvnodes > desiredvnodes && numvnodes <= desiredvnodes) + uma_reclaim(); if (done == 0) { -#if 0 - /* These messages are temporary debugging aids */ - if (vnlru_nowhere < 5) - printf("vnlru process getting nowhere..\n"); - else if (vnlru_nowhere == 5) - printf("vnlru process messages stopped.\n"); -#endif + if (force == 0 || force == 1) { + force = 2; + continue; + } + if (force == 2) { + force = 3; + continue; + } + force = 0; vnlru_nowhere++; tsleep(vnlruproc, PPAUSE, "vlrup", hz * 3); } else kern_yield(PRI_USER); + /* + * After becoming active to expand above low water, keep + * active until above high water. + */ + force = vspace() < vhiwat; } } @@ -1028,22 +1197,31 @@ vtryrecycle(struct vnode *vp) return (0); } +static void +vcheckspace(void) +{ + + if (vspace() < vlowat && vnlruproc_sig == 0) { + vnlruproc_sig = 1; + wakeup(vnlruproc); + } +} + /* - * Wait for available vnodes. + * Wait if necessary for space for a new vnode. */ static int getnewvnode_wait(int suspended) { mtx_assert(&vnode_free_list_mtx, MA_OWNED); - if (numvnodes > desiredvnodes) { + if (numvnodes >= desiredvnodes) { if (suspended) { /* - * File system is beeing suspended, we cannot risk a - * deadlock here, so allocate new vnode anyway. + * The file system is being suspended. We cannot + * risk a deadlock here, so allow allocation of + * another vnode even if this would give too many. */ - if (freevnodes > wantfreevnodes) - vnlru_free(freevnodes - wantfreevnodes); return (0); } if (vnlruproc_sig == 0) { @@ -1053,18 +1231,34 @@ getnewvnode_wait(int suspended) msleep(&vnlruproc_sig, &vnode_free_list_mtx, PVFS, "vlruwk", hz); } - return (numvnodes > desiredvnodes ? ENFILE : 0); + /* Post-adjust like the pre-adjust in getnewvnode(). */ + if (numvnodes + 1 > desiredvnodes && freevnodes > 1) + vnlru_free(1); + return (numvnodes >= desiredvnodes ? ENFILE : 0); } +/* + * This hack is fragile, and probably not needed any more now that the + * watermark handling works. + */ void getnewvnode_reserve(u_int count) { struct thread *td; + /* Pre-adjust like the pre-adjust in getnewvnode(), with any count. */ + /* XXX no longer so quick, but this part is not racy. */ + mtx_lock(&vnode_free_list_mtx); + if (numvnodes + count > desiredvnodes && freevnodes > wantfreevnodes) + vnlru_free(ulmin(numvnodes + count - desiredvnodes, + freevnodes - wantfreevnodes)); + mtx_unlock(&vnode_free_list_mtx); + td = curthread; /* First try to be quick and racy. */ if (atomic_fetchadd_long(&numvnodes, count) + count <= desiredvnodes) { td->td_vp_reserv += count; + vcheckspace(); /* XXX no longer so quick, but more racy */ return; } else atomic_subtract_long(&numvnodes, count); @@ -1077,9 +1271,18 @@ getnewvnode_reserve(u_int count) atomic_add_long(&numvnodes, 1); } } + vcheckspace(); mtx_unlock(&vnode_free_list_mtx); } +/* + * This hack is fragile, especially if desiredvnodes or wantvnodes are + * misconfgured or changed significantly. Reducing desiredvnodes below + * the reserved amount should cause bizarre behaviour like reducing it + * below the number of active vnodes -- the system will try to reduce + * numvnodes to match, but should fail, so the subtraction below should + * not overflow. + */ void getnewvnode_drop_reserve(void) { @@ -1098,8 +1301,9 @@ getnewvnode(const char *tag, struct mount *mp, struct vop_vector *vops, struct vnode **vpp) { struct vnode *vp; - struct bufobj *bo; struct thread *td; + struct lock_object *lo; + static int cyclecount; int error; CTR3(KTR_VFS, "%s: mp %p with tag %s", __func__, mp, tag); @@ -1110,57 +1314,77 @@ getnewvnode(const char *tag, struct mount *mp, struct vop_vector *vops, goto alloc; } mtx_lock(&vnode_free_list_mtx); + if (numvnodes < desiredvnodes) + cyclecount = 0; + else if (cyclecount++ >= freevnodes) { + cyclecount = 0; + vstir = 1; + } /* - * Lend our context to reclaim vnodes if they've exceeded the max. + * Grow the vnode cache if it will not be above its target max + * after growing. Otherwise, if the free list is nonempty, try + * to reclaim 1 item from it before growing the cache (possibly + * above its target max if the reclamation failed or is delayed). + * Otherwise, wait for some space. In all cases, schedule + * vnlru_proc() if we are getting short of space. The watermarks + * should be chosen so that we never wait or even reclaim from + * the free list to below its target minimum. */ - if (freevnodes > wantfreevnodes) + if (numvnodes + 1 <= desiredvnodes) + ; + else if (freevnodes > 0) vnlru_free(1); - error = getnewvnode_wait(mp != NULL && (mp->mnt_kern_flag & - MNTK_SUSPEND)); + else { + error = getnewvnode_wait(mp != NULL && (mp->mnt_kern_flag & + MNTK_SUSPEND)); #if 0 /* XXX Not all VFS_VGET/ffs_vget callers check returns. */ - if (error != 0) { - mtx_unlock(&vnode_free_list_mtx); - return (error); - } + if (error != 0) { + mtx_unlock(&vnode_free_list_mtx); + return (error); + } #endif + } + vcheckspace(); atomic_add_long(&numvnodes, 1); mtx_unlock(&vnode_free_list_mtx); alloc: atomic_add_long(&vnodes_created, 1); - vp = (struct vnode *) uma_zalloc(vnode_zone, M_WAITOK|M_ZERO); - /* - * Setup locks. - */ - vp->v_vnlock = &vp->v_lock; - mtx_init(&vp->v_interlock, "vnode interlock", NULL, MTX_DEF); - /* - * By default, don't allow shared locks unless filesystems - * opt-in. - */ - lockinit(vp->v_vnlock, PVFS, tag, VLKTIMEOUT, LK_NOSHARE | LK_IS_VNODE); + vp = (struct vnode *) uma_zalloc(vnode_zone, M_WAITOK); /* - * Initialize bufobj. + * Locks are given the generic name "vnode" when created. + * Follow the historic practice of using the filesystem + * name when they allocated, e.g., "zfs", "ufs", "nfs, etc. + * + * Locks live in a witness group keyed on their name. Thus, + * when a lock is renamed, it must also move from the witness + * group of its old name to the witness group of its new name. + * + * The change only needs to be made when the vnode moves + * from one filesystem type to another. We ensure that each + * filesystem use a single static name pointer for its tag so + * that we can compare pointers rather than doing a strcmp(). */ - bo = &vp->v_bufobj; - bo->__bo_vnode = vp; - rw_init(BO_LOCKPTR(bo), "bufobj interlock"); - bo->bo_ops = &buf_ops_bio; - bo->bo_private = vp; - TAILQ_INIT(&bo->bo_clean.bv_hd); - TAILQ_INIT(&bo->bo_dirty.bv_hd); + lo = &vp->v_vnlock->lock_object; + if (lo->lo_name != tag) { + lo->lo_name = tag; + WITNESS_DESTROY(lo); + WITNESS_INIT(lo, tag); + } /* - * Initialize namecache. + * By default, don't allow shared locks unless filesystems opt-in. */ - LIST_INIT(&vp->v_cache_src); - TAILQ_INIT(&vp->v_cache_dst); + vp->v_vnlock->lock_object.lo_flags |= LK_NOSHARE; /* * Finalize various vnode identity bits. */ + KASSERT(vp->v_object == NULL, ("stale v_object %p", vp)); + KASSERT(vp->v_lockf == NULL, ("stale v_lockf %p", vp)); + KASSERT(vp->v_pollinfo == NULL, ("stale v_pollinfo %p", vp)); vp->v_type = VNON; vp->v_tag = tag; vp->v_op = vops; v_incr_usecount(vp); - vp->v_data = NULL; + vp->v_bufobj.bo_ops = &buf_ops_bio; #ifdef MAC mac_vnode_init(vp); if (mp != NULL && (mp->mnt_flag & MNT_MULTILABEL) == 0) @@ -1169,11 +1393,10 @@ alloc: printf("NULL mp in getnewvnode()\n"); #endif if (mp != NULL) { - bo->bo_bsize = mp->mnt_stat.f_iosize; + vp->v_bufobj.bo_bsize = mp->mnt_stat.f_iosize; if ((mp->mnt_kern_flag & MNTK_NOKNOTE) != 0) vp->v_vflag |= VV_NOKNOTE; } - rangelock_init(&vp->v_rl); /* * For the filesystems which do not use vfs_hash_insert(), @@ -2399,7 +2622,7 @@ vholdl(struct vnode *vp) mtx_lock(&vnode_free_list_mtx); TAILQ_REMOVE(&vnode_free_list, vp, v_actfreelist); freevnodes--; - vp->v_iflag &= ~(VI_FREE|VI_AGE); + vp->v_iflag &= ~VI_FREE; KASSERT((vp->v_iflag & VI_ACTIVE) == 0, ("Activating already active vnode")); vp->v_iflag |= VI_ACTIVE; @@ -2467,15 +2690,9 @@ vdropl(struct vnode *vp) v_actfreelist); mp->mnt_activevnodelistsize--; } - if (vp->v_iflag & VI_AGE) { - TAILQ_INSERT_HEAD(&vnode_free_list, vp, - v_actfreelist); - } else { - TAILQ_INSERT_TAIL(&vnode_free_list, vp, - v_actfreelist); - } + TAILQ_INSERT_TAIL(&vnode_free_list, vp, + v_actfreelist); freevnodes++; - vp->v_iflag &= ~VI_AGE; vp->v_iflag |= VI_FREE; mtx_unlock(&vnode_free_list_mtx); } else { @@ -2486,6 +2703,12 @@ vdropl(struct vnode *vp) } /* * The vnode has been marked for destruction, so free it. + * + * The vnode will be returned to the zone where it will + * normally remain until it is needed for another vnode. We + * need to cleanup (or verify that the cleanup has already + * been done) any residual data left from its current use + * so as not to contaminate the freshly allocated vnode. */ CTR2(KTR_VFS, "%s: destroying the vnode %p", __func__, vp); atomic_subtract_long(&numvnodes, 1); @@ -2506,20 +2729,25 @@ vdropl(struct vnode *vp) VNASSERT(TAILQ_EMPTY(&vp->v_cache_dst), vp, ("vp has namecache dst")); VNASSERT(LIST_EMPTY(&vp->v_cache_src), vp, ("vp has namecache src")); VNASSERT(vp->v_cache_dd == NULL, vp, ("vp has namecache for ..")); + VNASSERT(TAILQ_EMPTY(&vp->v_rl.rl_waiters), vp, + ("Dangling rangelock waiters")); VI_UNLOCK(vp); #ifdef MAC mac_vnode_destroy(vp); #endif - if (vp->v_pollinfo != NULL) + if (vp->v_pollinfo != NULL) { destroy_vpollinfo(vp->v_pollinfo); + vp->v_pollinfo = NULL; + } #ifdef INVARIANTS /* XXX Elsewhere we detect an already freed vnode via NULL v_op. */ vp->v_op = NULL; #endif - rangelock_destroy(&vp->v_rl); - lockdestroy(vp->v_vnlock); - mtx_destroy(&vp->v_interlock); - rw_destroy(BO_LOCKPTR(bo)); + bzero(&vp->v_un, sizeof(vp->v_un)); + vp->v_lasta = vp->v_clen = vp->v_cstart = vp->v_lastw = 0; + vp->v_iflag = 0; + vp->v_vflag = 0; + bo->bo_flag = 0; uma_zfree(vnode_zone, vp); } @@ -2884,6 +3112,7 @@ vgonel(struct vnode *vp) * Clear the advisory locks and wake up waiting threads. */ (void)VOP_ADVLOCKPURGE(vp); + vp->v_lockf = NULL; /* * Delete from old mount point vnode list. */ @@ -2986,8 +3215,6 @@ vn_printf(struct vnode *vp, const char *fmt, ...) } if (vp->v_iflag & VI_MOUNT) strlcat(buf, "|VI_MOUNT", sizeof(buf)); - if (vp->v_iflag & VI_AGE) - strlcat(buf, "|VI_AGE", sizeof(buf)); if (vp->v_iflag & VI_DOOMED) strlcat(buf, "|VI_DOOMED", sizeof(buf)); if (vp->v_iflag & VI_FREE) @@ -2998,7 +3225,7 @@ vn_printf(struct vnode *vp, const char *fmt, ...) strlcat(buf, "|VI_DOINGINACT", sizeof(buf)); if (vp->v_iflag & VI_OWEINACT) strlcat(buf, "|VI_OWEINACT", sizeof(buf)); - flags = vp->v_iflag & ~(VI_MOUNT | VI_AGE | VI_DOOMED | VI_FREE | + flags = vp->v_iflag & ~(VI_MOUNT | VI_DOOMED | VI_FREE | VI_ACTIVE | VI_DOINGINACT | VI_OWEINACT); if (flags != 0) { snprintf(buf2, sizeof(buf2), "|VI(0x%lx)", flags); diff --git a/sys/ufs/ffs/ffs_vfsops.c b/sys/ufs/ffs/ffs_vfsops.c index 26c0286..1c7b9db 100644 --- a/sys/ufs/ffs/ffs_vfsops.c +++ b/sys/ufs/ffs/ffs_vfsops.c @@ -1670,10 +1670,8 @@ ffs_vgetf(mp, ino, flags, vpp, ffs_flags) ip = uma_zalloc(uma_inode, M_WAITOK | M_ZERO); /* Allocate a new vnode/inode. */ - if (fs->fs_magic == FS_UFS1_MAGIC) - error = getnewvnode("ufs", mp, &ffs_vnodeops1, &vp); - else - error = getnewvnode("ufs", mp, &ffs_vnodeops2, &vp); + error = getnewvnode("ufs", mp, fs->fs_magic == FS_UFS1_MAGIC ? + &ffs_vnodeops1 : &ffs_vnodeops2, &vp); if (error) { *vpp = NULL; uma_zfree(uma_inode, ip); -- cgit v1.1 From c48693418e100bebee76155f54e84a1e171e34e8 Mon Sep 17 00:00:00 2001 From: emaste Date: Wed, 30 Dec 2015 01:02:22 +0000 Subject: MFC r292658: Install ld also as ld.bfd, for use with cc -fuse-ld=bfd --- gnu/usr.bin/binutils/ld/Makefile | 1 + 1 file changed, 1 insertion(+) diff --git a/gnu/usr.bin/binutils/ld/Makefile b/gnu/usr.bin/binutils/ld/Makefile index 9e2acd8..58a6848 100644 --- a/gnu/usr.bin/binutils/ld/Makefile +++ b/gnu/usr.bin/binutils/ld/Makefile @@ -52,6 +52,7 @@ CLEANFILES+= ldemul-list.h stringify.sed FILES= ${LDSCRIPTS:S|^|ldscripts/|} FILESDIR= ${SCRIPTDIR} +LINKS= ${BINDIR}/ld ${BINDIR}/ld.bfd HOST= ${TARGET_TUPLE} LIBSEARCHPATH= \"=/lib\":\"=/usr/lib\" -- cgit v1.1 From a3b7fafab78043fe8355bb68596028cb9bba40ad Mon Sep 17 00:00:00 2001 From: royger Date: Wed, 30 Dec 2015 08:15:43 +0000 Subject: MFC r267858: xen/virtio: fix balloon drivers to not mark pages as WIRED In the Xen case make sure pages are zeroed before giving them back to the hypervisor, or else we might be leaking data. Also remove the balloon_{append/retrieve} and link pages directly into the ballooned_pages queue using the plinks.q field in the page struct. Sponsored by: Citrix Systems R&D Requested by: bapt --- sys/dev/virtio/balloon/virtio_balloon.c | 4 +- sys/dev/xen/balloon/balloon.c | 89 +++++++++------------------------ 2 files changed, 25 insertions(+), 68 deletions(-) diff --git a/sys/dev/virtio/balloon/virtio_balloon.c b/sys/dev/virtio/balloon/virtio_balloon.c index a90a653..6d00ef3 100644 --- a/sys/dev/virtio/balloon/virtio_balloon.c +++ b/sys/dev/virtio/balloon/virtio_balloon.c @@ -438,8 +438,7 @@ vtballoon_alloc_page(struct vtballoon_softc *sc) { vm_page_t m; - m = vm_page_alloc(NULL, 0, VM_ALLOC_NORMAL | VM_ALLOC_WIRED | - VM_ALLOC_NOOBJ); + m = vm_page_alloc(NULL, 0, VM_ALLOC_NORMAL | VM_ALLOC_NOOBJ); if (m != NULL) sc->vtballoon_current_npages++; @@ -450,7 +449,6 @@ static void vtballoon_free_page(struct vtballoon_softc *sc, vm_page_t m) { - vm_page_unwire(m, 0); vm_page_free(m); sc->vtballoon_current_npages--; } diff --git a/sys/dev/xen/balloon/balloon.c b/sys/dev/xen/balloon/balloon.c index 2df9c8b..6503a00 100644 --- a/sys/dev/xen/balloon/balloon.c +++ b/sys/dev/xen/balloon/balloon.c @@ -94,13 +94,8 @@ SYSCTL_ULONG(_dev_xen_balloon, OID_AUTO, low_mem, CTLFLAG_RD, SYSCTL_ULONG(_dev_xen_balloon, OID_AUTO, high_mem, CTLFLAG_RD, &bs.balloon_high, 0, "High-mem balloon"); -struct balloon_entry { - vm_page_t page; - STAILQ_ENTRY(balloon_entry) list; -}; - /* List of ballooned pages, threaded through the mem_map array. */ -static STAILQ_HEAD(,balloon_entry) ballooned_pages; +static TAILQ_HEAD(,vm_page) ballooned_pages; /* Main work function, always executed in process context. */ static void balloon_process(void *unused); @@ -110,47 +105,6 @@ static void balloon_process(void *unused); #define WPRINTK(fmt, args...) \ printk(KERN_WARNING "xen_mem: " fmt, ##args) -/* balloon_append: add the given page to the balloon. */ -static int -balloon_append(vm_page_t page) -{ - struct balloon_entry *entry; - - mtx_assert(&balloon_mutex, MA_OWNED); - - entry = malloc(sizeof(struct balloon_entry), M_BALLOON, M_NOWAIT); - if (!entry) - return (ENOMEM); - entry->page = page; - STAILQ_INSERT_HEAD(&ballooned_pages, entry, list); - bs.balloon_low++; - - return (0); -} - -/* balloon_retrieve: rescue a page from the balloon, if it is not empty. */ -static vm_page_t -balloon_retrieve(void) -{ - vm_page_t page; - struct balloon_entry *entry; - - mtx_assert(&balloon_mutex, MA_OWNED); - - if (STAILQ_EMPTY(&ballooned_pages)) - return (NULL); - - entry = STAILQ_FIRST(&ballooned_pages); - STAILQ_REMOVE_HEAD(&ballooned_pages, list); - - page = entry->page; - free(entry, M_BALLOON); - - bs.balloon_low--; - - return (page); -} - static unsigned long current_target(void) { @@ -203,7 +157,6 @@ static int increase_reservation(unsigned long nr_pages) { unsigned long pfn, i; - struct balloon_entry *entry; vm_page_t page; long rc; struct xen_memory_reservation reservation = { @@ -217,10 +170,9 @@ increase_reservation(unsigned long nr_pages) if (nr_pages > nitems(frame_list)) nr_pages = nitems(frame_list); - for (entry = STAILQ_FIRST(&ballooned_pages), i = 0; - i < nr_pages; i++, entry = STAILQ_NEXT(entry, list)) { - KASSERT(entry, ("ballooned_pages list corrupt")); - page = entry->page; + for (page = TAILQ_FIRST(&ballooned_pages), i = 0; + i < nr_pages; i++, page = TAILQ_NEXT(page, plinks.q)) { + KASSERT(page != NULL, ("ballooned_pages list corrupt")); frame_list[i] = (VM_PAGE_TO_PHYS(page) >> PAGE_SHIFT); } @@ -245,8 +197,10 @@ increase_reservation(unsigned long nr_pages) } for (i = 0; i < nr_pages; i++) { - page = balloon_retrieve(); - KASSERT(page, ("balloon_retrieve failed")); + page = TAILQ_FIRST(&ballooned_pages); + KASSERT(page != NULL, ("Unable to get ballooned page")); + TAILQ_REMOVE(&ballooned_pages, page, plinks.q); + bs.balloon_low--; pfn = (VM_PAGE_TO_PHYS(page) >> PAGE_SHIFT); KASSERT((xen_feature(XENFEAT_auto_translated_physmap) || @@ -255,7 +209,6 @@ increase_reservation(unsigned long nr_pages) set_phys_to_machine(pfn, frame_list[i]); - vm_page_unwire(page, 0); vm_page_free(page); } @@ -286,24 +239,29 @@ decrease_reservation(unsigned long nr_pages) for (i = 0; i < nr_pages; i++) { if ((page = vm_page_alloc(NULL, 0, VM_ALLOC_NORMAL | VM_ALLOC_NOOBJ | - VM_ALLOC_WIRED | VM_ALLOC_ZERO)) == NULL) { + VM_ALLOC_ZERO)) == NULL) { nr_pages = i; need_sleep = 1; break; } + if ((page->flags & PG_ZERO) == 0) { + /* + * Zero the page, or else we might be leaking + * important data to other domains on the same + * host. Xen doesn't scrub ballooned out memory + * pages, the guest is in charge of making + * sure that no information is leaked. + */ + pmap_zero_page(page); + } + pfn = (VM_PAGE_TO_PHYS(page) >> PAGE_SHIFT); frame_list[i] = PFNTOMFN(pfn); set_phys_to_machine(pfn, INVALID_P2M_ENTRY); - if (balloon_append(page) != 0) { - vm_page_unwire(page, 0); - vm_page_free(page); - - nr_pages = i; - need_sleep = 1; - break; - } + TAILQ_INSERT_HEAD(&ballooned_pages, page, plinks.q); + bs.balloon_low++; } set_xen_guest_handle(reservation.extent_start, frame_list); @@ -438,7 +396,8 @@ balloon_init(void *arg) /* Initialise the balloon with excess memory space. */ for (pfn = xen_start_info->nr_pages; pfn < max_pfn; pfn++) { page = PHYS_TO_VM_PAGE(pfn << PAGE_SHIFT); - balloon_append(page); + TAILQ_INSERT_HEAD(&ballooned_pages, page, plinks.q); + bs.balloon_low++; } #undef max_pfn #endif -- cgit v1.1 From a84969ed1aae79dccc82d27cf0016394808c7320 Mon Sep 17 00:00:00 2001 From: ngie Date: Wed, 30 Dec 2015 08:52:03 +0000 Subject: MFC r270212,r270332: This helps reduce the diff in pci(4) between head and stable/10 to help pave the way for bringing in IOV/nv(9) more cleanly Differential Revision: https://reviews.freebsd.org/D4728 Relnotes: yes Reviewed by: hselasky (ofed piece), royger (overall change) Sponsored by: EMC / Isilon Storage Division r270212 (by royger): pci: make MSI(-X) enable and disable methods of the PCI bus Make the functions pci_disable_msi, pci_enable_msi and pci_enable_msix methods of the newbus PCI bus. This code should not include any functional change. Sponsored by: Citrix Systems R&D Reviewed by: imp, jhb Differential Revision: https://reviews.freebsd.org/D354 dev/pci/pci.c: - Convert the mentioned functions to newbus methods. - Fix the callers of the converted functions. sys/dev/pci/pci_private.h: dev/pci/pci_if.m: - Declare the new methods. dev/pci/pcivar.h: - Add helpers to call the newbus methods. ofed/include/linux/pci.h: - Add define to prevent the ofed version of pci_enable_msix from clashing with the FreeBSD native version. r270332 (by royger): pci: add a new pci_child_added newbus method. This is needed so when running under Xen the calls to pci_child_added can be intercepted and a custom Xen method can be used to register those devices with Xen. This should not include any functional change, since the Xen implementation will be added in a following patch and the native implementation is a noop. Sponsored by: Citrix Systems R&D Reviewed by: jhb dev/pci/pci.c: dev/pci/pci_if.m: dev/pci/pci_private.h: dev/pci/pcivar.h: - Add the pci_child_added newbus method. --- sys/dev/pci/pci.c | 52 +++++++++++++++++++++++++------------------- sys/dev/pci/pci_if.m | 24 ++++++++++++++++++++ sys/dev/pci/pci_private.h | 6 +++++ sys/dev/pci/pcivar.h | 25 +++++++++++++++++++++ sys/ofed/include/linux/pci.h | 4 ++++ 5 files changed, 89 insertions(+), 22 deletions(-) diff --git a/sys/dev/pci/pci.c b/sys/dev/pci/pci.c index fb9a202..a9c33ae 100644 --- a/sys/dev/pci/pci.c +++ b/sys/dev/pci/pci.c @@ -110,11 +110,6 @@ static int pci_write_vpd_reg(device_t pcib, pcicfgregs *cfg, int reg, uint32_t data); #endif static void pci_read_vpd(device_t pcib, pcicfgregs *cfg); -static void pci_disable_msi(device_t dev); -static void pci_enable_msi(device_t dev, uint64_t address, - uint16_t data); -static void pci_enable_msix(device_t dev, u_int index, - uint64_t address, uint32_t data); static void pci_mask_msix(device_t dev, u_int index); static void pci_unmask_msix(device_t dev, u_int index); static int pci_msi_blacklisted(void); @@ -180,11 +175,15 @@ static device_method_t pci_methods[] = { DEVMETHOD(pci_find_htcap, pci_find_htcap_method), DEVMETHOD(pci_alloc_msi, pci_alloc_msi_method), DEVMETHOD(pci_alloc_msix, pci_alloc_msix_method), + DEVMETHOD(pci_enable_msi, pci_enable_msi_method), + DEVMETHOD(pci_enable_msix, pci_enable_msix_method), + DEVMETHOD(pci_disable_msi, pci_disable_msi_method), DEVMETHOD(pci_remap_msix, pci_remap_msix_method), DEVMETHOD(pci_release_msi, pci_release_msi_method), DEVMETHOD(pci_msi_count, pci_msi_count_method), DEVMETHOD(pci_msix_count, pci_msix_count_method), DEVMETHOD(pci_get_rid, pci_get_rid_method), + DEVMETHOD(pci_child_added, pci_child_added_method), DEVMETHOD_END }; @@ -1374,9 +1373,10 @@ pci_find_extcap_method(device_t dev, device_t child, int capability, * Support for MSI-X message interrupts. */ void -pci_enable_msix(device_t dev, u_int index, uint64_t address, uint32_t data) +pci_enable_msix_method(device_t dev, device_t child, u_int index, + uint64_t address, uint32_t data) { - struct pci_devinfo *dinfo = device_get_ivars(dev); + struct pci_devinfo *dinfo = device_get_ivars(child); struct pcicfg_msix *msix = &dinfo->cfg.msix; uint32_t offset; @@ -1387,7 +1387,7 @@ pci_enable_msix(device_t dev, u_int index, uint64_t address, uint32_t data) bus_write_4(msix->msix_table_res, offset + 8, data); /* Enable MSI -> HT mapping. */ - pci_ht_map_msi(dev, address); + pci_ht_map_msi(child, address); } void @@ -1956,45 +1956,46 @@ pcie_adjust_config(device_t dev, int reg, uint32_t mask, uint32_t value, * Support for MSI message signalled interrupts. */ void -pci_enable_msi(device_t dev, uint64_t address, uint16_t data) +pci_enable_msi_method(device_t dev, device_t child, uint64_t address, + uint16_t data) { - struct pci_devinfo *dinfo = device_get_ivars(dev); + struct pci_devinfo *dinfo = device_get_ivars(child); struct pcicfg_msi *msi = &dinfo->cfg.msi; /* Write data and address values. */ - pci_write_config(dev, msi->msi_location + PCIR_MSI_ADDR, + pci_write_config(child, msi->msi_location + PCIR_MSI_ADDR, address & 0xffffffff, 4); if (msi->msi_ctrl & PCIM_MSICTRL_64BIT) { - pci_write_config(dev, msi->msi_location + PCIR_MSI_ADDR_HIGH, + pci_write_config(child, msi->msi_location + PCIR_MSI_ADDR_HIGH, address >> 32, 4); - pci_write_config(dev, msi->msi_location + PCIR_MSI_DATA_64BIT, + pci_write_config(child, msi->msi_location + PCIR_MSI_DATA_64BIT, data, 2); } else - pci_write_config(dev, msi->msi_location + PCIR_MSI_DATA, data, + pci_write_config(child, msi->msi_location + PCIR_MSI_DATA, data, 2); /* Enable MSI in the control register. */ msi->msi_ctrl |= PCIM_MSICTRL_MSI_ENABLE; - pci_write_config(dev, msi->msi_location + PCIR_MSI_CTRL, msi->msi_ctrl, - 2); + pci_write_config(child, msi->msi_location + PCIR_MSI_CTRL, + msi->msi_ctrl, 2); /* Enable MSI -> HT mapping. */ - pci_ht_map_msi(dev, address); + pci_ht_map_msi(child, address); } void -pci_disable_msi(device_t dev) +pci_disable_msi_method(device_t dev, device_t child) { - struct pci_devinfo *dinfo = device_get_ivars(dev); + struct pci_devinfo *dinfo = device_get_ivars(child); struct pcicfg_msi *msi = &dinfo->cfg.msi; /* Disable MSI -> HT mapping. */ - pci_ht_map_msi(dev, 0); + pci_ht_map_msi(child, 0); /* Disable MSI in the control register. */ msi->msi_ctrl &= ~PCIM_MSICTRL_MSI_ENABLE; - pci_write_config(dev, msi->msi_location + PCIR_MSI_CTRL, msi->msi_ctrl, - 2); + pci_write_config(child, msi->msi_location + PCIR_MSI_CTRL, + msi->msi_ctrl, 2); } /* @@ -3604,6 +3605,13 @@ pci_add_child(device_t bus, struct pci_devinfo *dinfo) pci_cfg_restore(dinfo->cfg.dev, dinfo); pci_print_verbose(dinfo); pci_add_resources(bus, dinfo->cfg.dev, 0, 0); + pci_child_added(dinfo->cfg.dev); +} + +void +pci_child_added_method(device_t dev, device_t child) +{ + } static int diff --git a/sys/dev/pci/pci_if.m b/sys/dev/pci/pci_if.m index 82864eb..227d362 100644 --- a/sys/dev/pci/pci_if.m +++ b/sys/dev/pci/pci_if.m @@ -138,6 +138,26 @@ METHOD int alloc_msix { int *count; }; +METHOD void enable_msi { + device_t dev; + device_t child; + uint64_t address; + uint16_t data; +}; + +METHOD void enable_msix { + device_t dev; + device_t child; + u_int index; + uint64_t address; + uint32_t data; +}; + +METHOD void disable_msi { + device_t dev; + device_t child; +}; + METHOD int remap_msix { device_t dev; device_t child; @@ -165,3 +185,7 @@ METHOD uint16_t get_rid { device_t child; }; +METHOD void child_added { + device_t dev; + device_t child; +}; diff --git a/sys/dev/pci/pci_private.h b/sys/dev/pci/pci_private.h index 0223ee8..5a90ce9 100644 --- a/sys/dev/pci/pci_private.h +++ b/sys/dev/pci/pci_private.h @@ -90,6 +90,11 @@ int pci_find_htcap_method(device_t dev, device_t child, int capability, int *capreg); int pci_alloc_msi_method(device_t dev, device_t child, int *count); int pci_alloc_msix_method(device_t dev, device_t child, int *count); +void pci_enable_msi_method(device_t dev, device_t child, + uint64_t address, uint16_t data); +void pci_enable_msix_method(device_t dev, device_t child, + u_int index, uint64_t address, uint32_t data); +void pci_disable_msi_method(device_t dev, device_t child); int pci_remap_msix_method(device_t dev, device_t child, int count, const u_int *vectors); int pci_release_msi_method(device_t dev, device_t child); @@ -120,6 +125,7 @@ int pci_assign_interrupt_method(device_t dev, device_t child); int pci_resume(device_t dev); int pci_suspend(device_t dev); bus_dma_tag_t pci_get_dma_tag(device_t bus, device_t dev); +void pci_child_added_method(device_t dev, device_t child); /** Restore the config register state. The state must be previously * saved with pci_cfg_save. However, the pci bus driver takes care of diff --git a/sys/dev/pci/pcivar.h b/sys/dev/pci/pcivar.h index 4b570d0..2bb26bd 100644 --- a/sys/dev/pci/pcivar.h +++ b/sys/dev/pci/pcivar.h @@ -458,6 +458,24 @@ pci_alloc_msix(device_t dev, int *count) return (PCI_ALLOC_MSIX(device_get_parent(dev), dev, count)); } +static __inline void +pci_enable_msi(device_t dev, uint64_t address, uint16_t data) +{ + PCI_ENABLE_MSI(device_get_parent(dev), dev, address, data); +} + +static __inline void +pci_enable_msix(device_t dev, u_int index, uint64_t address, uint32_t data) +{ + PCI_ENABLE_MSIX(device_get_parent(dev), dev, index, address, data); +} + +static __inline void +pci_disable_msi(device_t dev) +{ + PCI_DISABLE_MSI(device_get_parent(dev), dev); +} + static __inline int pci_remap_msix(device_t dev, int count, const u_int *vectors) { @@ -488,6 +506,13 @@ pci_get_rid(device_t dev) return (PCI_GET_RID(device_get_parent(dev), dev)); } +static __inline void +pci_child_added(device_t dev) +{ + + return (PCI_CHILD_ADDED(device_get_parent(dev), dev)); +} + device_t pci_find_bsf(uint8_t, uint8_t, uint8_t); device_t pci_find_dbsf(uint32_t, uint8_t, uint8_t, uint8_t); device_t pci_find_device(uint16_t, uint16_t); diff --git a/sys/ofed/include/linux/pci.h b/sys/ofed/include/linux/pci.h index a2f02b5..2e6eef4 100644 --- a/sys/ofed/include/linux/pci.h +++ b/sys/ofed/include/linux/pci.h @@ -566,7 +566,11 @@ struct msix_entry { /* * Enable msix, positive errors indicate actual number of available * vectors. Negative errors are failures. + * + * NB: define added to prevent this definition of pci_enable_msix from + * clashing with the native FreeBSD version. */ +#define pci_enable_msix linux_pci_enable_msix static inline int pci_enable_msix(struct pci_dev *pdev, struct msix_entry *entries, int nreq) { -- cgit v1.1 From f504ae473f11afa88a2ab816cce909b680ee38ef Mon Sep 17 00:00:00 2001 From: ngie Date: Wed, 30 Dec 2015 08:53:12 +0000 Subject: Bump __FreeBSD_version per pci(4) changes made in r292907 Sponsored by: EMC / Isilon Storage Division --- sys/sys/param.h | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/sys/sys/param.h b/sys/sys/param.h index 3acaad7..e58c77e 100644 --- a/sys/sys/param.h +++ b/sys/sys/param.h @@ -58,7 +58,7 @@ * in the range 5 to 9. */ #undef __FreeBSD_version -#define __FreeBSD_version 1002504 /* Master, propagated to newvers */ +#define __FreeBSD_version 1002505 /* Master, propagated to newvers */ /* * __FreeBSD_kernel__ indicates that this system uses the kernel of FreeBSD, -- cgit v1.1 From e02caf9619483dc84e812c0941f185de2f110e3c Mon Sep 17 00:00:00 2001 From: mav Date: Wed, 30 Dec 2015 11:47:33 +0000 Subject: MFC r292610: Fix speed setting by NVRAM for 24xx and above chips. --- sys/dev/isp/isp.c | 28 ++++++++++++++++++++++++++-- 1 file changed, 26 insertions(+), 2 deletions(-) diff --git a/sys/dev/isp/isp.c b/sys/dev/isp/isp.c index d394011..a23cdab 100644 --- a/sys/dev/isp/isp.c +++ b/sys/dev/isp/isp.c @@ -2142,19 +2142,41 @@ isp_fibre_init_2400(ispsoftc_t *isp) if ((icbp->icb_fwoptions3 & ICB2400_OPT3_RSPSZ_MASK) == 0) { icbp->icb_fwoptions3 |= ICB2400_OPT3_RSPSZ_24; } - icbp->icb_fwoptions3 &= ~ICB2400_OPT3_RATE_AUTO; if (isp->isp_confopts & ISP_CFG_1GB) { + icbp->icb_fwoptions3 &= ~ICB2400_OPT3_RATE_MASK; icbp->icb_fwoptions3 |= ICB2400_OPT3_RATE_1GB; } else if (isp->isp_confopts & ISP_CFG_2GB) { + icbp->icb_fwoptions3 &= ~ICB2400_OPT3_RATE_MASK; icbp->icb_fwoptions3 |= ICB2400_OPT3_RATE_2GB; } else if (isp->isp_confopts & ISP_CFG_4GB) { + icbp->icb_fwoptions3 &= ~ICB2400_OPT3_RATE_MASK; icbp->icb_fwoptions3 |= ICB2400_OPT3_RATE_4GB; } else if (isp->isp_confopts & ISP_CFG_8GB) { + icbp->icb_fwoptions3 &= ~ICB2400_OPT3_RATE_MASK; icbp->icb_fwoptions3 |= ICB2400_OPT3_RATE_8GB; } else if (isp->isp_confopts & ISP_CFG_16GB) { + icbp->icb_fwoptions3 &= ~ICB2400_OPT3_RATE_MASK; icbp->icb_fwoptions3 |= ICB2400_OPT3_RATE_16GB; } else { - icbp->icb_fwoptions3 |= ICB2400_OPT3_RATE_AUTO; + switch (icbp->icb_fwoptions3 & ICB2400_OPT3_RATE_MASK) { + case ICB2400_OPT3_RATE_4GB: + case ICB2400_OPT3_RATE_8GB: + case ICB2400_OPT3_RATE_16GB: + case ICB2400_OPT3_RATE_AUTO: + break; + case ICB2400_OPT3_RATE_2GB: + if (isp->isp_type <= ISP_HA_FC_2500) + break; + /*FALLTHROUGH*/ + case ICB2400_OPT3_RATE_1GB: + if (isp->isp_type <= ISP_HA_FC_2400) + break; + /*FALLTHROUGH*/ + default: + icbp->icb_fwoptions3 &= ~ICB2400_OPT3_RATE_MASK; + icbp->icb_fwoptions3 |= ICB2400_OPT3_RATE_AUTO; + break; + } } icbp->icb_logintime = ICB_LOGIN_TOV; @@ -7632,6 +7654,7 @@ isp_setdfltfcparm(ispsoftc_t *isp, int chan) fcp->isp_fwoptions |= ICB2400_OPT1_FULL_DUPLEX; } fcp->isp_fwoptions |= ICB2400_OPT1_BOTH_WWNS; + fcp->isp_zfwoptions |= ICB2400_OPT3_RATE_AUTO; } else { fcp->isp_fwoptions |= ICBOPT_FAIRNESS; fcp->isp_fwoptions |= ICBOPT_PDBCHANGE_AE; @@ -7644,6 +7667,7 @@ isp_setdfltfcparm(ispsoftc_t *isp, int chan) * extended options from NVRAM */ fcp->isp_fwoptions &= ~ICBOPT_EXTENDED; + fcp->isp_zfwoptions |= ICBZOPT_RATE_AUTO; } -- cgit v1.1 From 082234e18734a3caf9f4c53761f44d0e3647c3b6 Mon Sep 17 00:00:00 2001 From: mav Date: Wed, 30 Dec 2015 11:48:17 +0000 Subject: MFC r292690: Some polishing for command timeouts handling. --- sys/dev/isp/isp.c | 32 +++++++++++++++++--------------- sys/dev/isp/isp_freebsd.c | 9 +++++---- sys/dev/isp/ispmbox.h | 2 +- 3 files changed, 23 insertions(+), 20 deletions(-) diff --git a/sys/dev/isp/isp.c b/sys/dev/isp/isp.c index a23cdab..3350044 100644 --- a/sys/dev/isp/isp.c +++ b/sys/dev/isp/isp.c @@ -2446,7 +2446,8 @@ isp_plogx(ispsoftc_t *isp, int chan, uint16_t handle, uint32_t portid, int flags scp = fcp->isp_scratch; isp_put_plogx(isp, plp, (isp_plogx_t *) scp); - MBSINIT(&mbs, MBOX_EXEC_COMMAND_IOCB_A64, MBLOGALL, 500000); + MBSINIT(&mbs, MBOX_EXEC_COMMAND_IOCB_A64, MBLOGALL, + MBCMD_DEFAULT_TIMEOUT + ICB_LOGIN_TOV * 1000000); mbs.param[1] = QENTRY_LEN; mbs.param[2] = DMA_WD1(fcp->isp_scdma); mbs.param[3] = DMA_WD0(fcp->isp_scdma); @@ -3390,7 +3391,7 @@ isp_gid_ft_ct_passthru(ispsoftc_t *isp, int chan) pt->ctp_nphdl = fcp->isp_sns_hdl; pt->ctp_cmd_cnt = 1; pt->ctp_vpidx = ISP_GET_VPIDX(isp, chan); - pt->ctp_time = 30; + pt->ctp_time = 10; pt->ctp_rsp_cnt = 1; pt->ctp_rsp_bcnt = GIDLEN; pt->ctp_cmd_bcnt = sizeof (*ct) + sizeof (uint32_t); @@ -3426,7 +3427,8 @@ isp_gid_ft_ct_passthru(ispsoftc_t *isp, int chan) sizeof (*ct) + sizeof (uint32_t), &scp[XTXOFF]); } ISP_MEMZERO(&scp[ZTXOFF], QENTRY_LEN); - MBSINIT(&mbs, MBOX_EXEC_COMMAND_IOCB_A64, MBLOGALL, 500000); + MBSINIT(&mbs, MBOX_EXEC_COMMAND_IOCB_A64, MBLOGALL, + MBCMD_DEFAULT_TIMEOUT + pt->ctp_time * 1000000); mbs.param[1] = QENTRY_LEN; mbs.param[2] = DMA_WD1(fcp->isp_scdma + CTXOFF); mbs.param[3] = DMA_WD0(fcp->isp_scdma + CTXOFF); @@ -3861,7 +3863,7 @@ isp_register_fc4_type_24xx(ispsoftc_t *isp, int chan) pt->ctp_nphdl = fcp->isp_sns_hdl; pt->ctp_cmd_cnt = 1; pt->ctp_vpidx = ISP_GET_VPIDX(isp, chan); - pt->ctp_time = 1; + pt->ctp_time = 4; pt->ctp_rsp_cnt = 1; pt->ctp_rsp_bcnt = sizeof (ct_hdr_t); pt->ctp_cmd_bcnt = sizeof (rft_id_t); @@ -3900,7 +3902,8 @@ isp_register_fc4_type_24xx(ispsoftc_t *isp, int chan) ISP_MEMZERO(&scp[ZTXOFF], sizeof (ct_hdr_t)); - MBSINIT(&mbs, MBOX_EXEC_COMMAND_IOCB_A64, MBLOGALL, 1000000); + MBSINIT(&mbs, MBOX_EXEC_COMMAND_IOCB_A64, MBLOGALL, + MBCMD_DEFAULT_TIMEOUT + pt->ctp_time * 1000000); mbs.param[1] = QENTRY_LEN; mbs.param[2] = DMA_WD1(fcp->isp_scdma + CTXOFF); mbs.param[3] = DMA_WD0(fcp->isp_scdma + CTXOFF); @@ -3972,7 +3975,7 @@ isp_register_fc4_features_24xx(ispsoftc_t *isp, int chan) pt->ctp_nphdl = fcp->isp_sns_hdl; pt->ctp_cmd_cnt = 1; pt->ctp_vpidx = ISP_GET_VPIDX(isp, chan); - pt->ctp_time = 1; + pt->ctp_time = 4; pt->ctp_rsp_cnt = 1; pt->ctp_rsp_bcnt = sizeof (ct_hdr_t); pt->ctp_cmd_bcnt = sizeof (rff_id_t); @@ -4016,7 +4019,8 @@ isp_register_fc4_features_24xx(ispsoftc_t *isp, int chan) ISP_MEMZERO(&scp[ZTXOFF], sizeof (ct_hdr_t)); - MBSINIT(&mbs, MBOX_EXEC_COMMAND_IOCB_A64, MBLOGALL, 1000000); + MBSINIT(&mbs, MBOX_EXEC_COMMAND_IOCB_A64, MBLOGALL, + MBCMD_DEFAULT_TIMEOUT + pt->ctp_time * 1000000); mbs.param[1] = QENTRY_LEN; mbs.param[2] = DMA_WD1(fcp->isp_scdma + CTXOFF); mbs.param[3] = DMA_WD0(fcp->isp_scdma + CTXOFF); @@ -4403,10 +4407,7 @@ isp_start(XS_T *xs) } ISP_MEMCPY(cdbp, XS_CDBP(xs), cdblen); - *tptr = XS_TIME(xs) / 1000; - if (*tptr == 0 && XS_TIME(xs)) { - *tptr = 1; - } + *tptr = (XS_TIME(xs) + 999) / 1000; if (IS_24XX(isp) && *tptr > 0x1999) { *tptr = 0x1999; } @@ -4512,13 +4513,14 @@ isp_control(ispsoftc_t *isp, ispctl_t ctl, ...) tmf->tmf_header.rqs_entry_count = 1; tmf->tmf_nphdl = lp->handle; tmf->tmf_delay = 2; - tmf->tmf_timeout = 2; + tmf->tmf_timeout = 4; tmf->tmf_flags = ISP24XX_TMF_TARGET_RESET; tmf->tmf_tidlo = lp->portid; tmf->tmf_tidhi = lp->portid >> 16; tmf->tmf_vpidx = ISP_GET_VPIDX(isp, chan); isp_prt(isp, ISP_LOGALL, "Chan %d Reset N-Port Handle 0x%04x @ Port 0x%06x", chan, lp->handle, lp->portid); - MBSINIT(&mbs, MBOX_EXEC_COMMAND_IOCB_A64, MBLOGALL, 5000000); + MBSINIT(&mbs, MBOX_EXEC_COMMAND_IOCB_A64, MBLOGALL, + MBCMD_DEFAULT_TIMEOUT + tmf->tmf_timeout * 1000000); mbs.param[1] = QENTRY_LEN; mbs.param[2] = DMA_WD1(fcp->isp_scdma); mbs.param[3] = DMA_WD0(fcp->isp_scdma); @@ -6901,7 +6903,7 @@ static const uint32_t mbpfc[] = { ISP_FC_OPMAP(0x01, 0x07), /* 0x1f: MBOX_GET_FIRMWARE_STATUS */ ISP_FC_OPMAP_HALF(0x2, 0x01, 0x7e, 0xcf), /* 0x20: MBOX_GET_LOOP_ID */ ISP_FC_OPMAP(0x00, 0x00), /* 0x21: */ - ISP_FC_OPMAP(0x01, 0x07), /* 0x22: MBOX_GET_RETRY_COUNT */ + ISP_FC_OPMAP(0x03, 0x4b), /* 0x22: MBOX_GET_TIMEOUT_PARAMS */ ISP_FC_OPMAP(0x00, 0x00), /* 0x23: */ ISP_FC_OPMAP(0x00, 0x00), /* 0x24: */ ISP_FC_OPMAP(0x00, 0x00), /* 0x25: */ @@ -6917,7 +6919,7 @@ static const uint32_t mbpfc[] = { ISP_FC_OPMAP(0x00, 0x00), /* 0x2f: */ ISP_FC_OPMAP(0x00, 0x00), /* 0x30: */ ISP_FC_OPMAP(0x00, 0x00), /* 0x31: */ - ISP_FC_OPMAP(0x07, 0x07), /* 0x32: MBOX_SET_RETRY_COUNT */ + ISP_FC_OPMAP(0x4b, 0x4b), /* 0x32: MBOX_SET_TIMEOUT_PARAMS */ ISP_FC_OPMAP(0x00, 0x00), /* 0x33: */ ISP_FC_OPMAP(0x00, 0x00), /* 0x34: */ ISP_FC_OPMAP(0x00, 0x00), /* 0x35: */ diff --git a/sys/dev/isp/isp_freebsd.c b/sys/dev/isp/isp_freebsd.c index c533d69..69b5a5c 100644 --- a/sys/dev/isp/isp_freebsd.c +++ b/sys/dev/isp/isp_freebsd.c @@ -632,7 +632,7 @@ ispioctl(struct cdev *dev, u_long c, caddr_t addr, int flags, struct thread *td) tmf->tmf_header.rqs_entry_count = 1; tmf->tmf_nphdl = lp->handle; tmf->tmf_delay = 2; - tmf->tmf_timeout = 2; + tmf->tmf_timeout = 4; tmf->tmf_tidlo = lp->portid; tmf->tmf_tidhi = lp->portid >> 16; tmf->tmf_vpidx = ISP_GET_VPIDX(isp, chan); @@ -668,7 +668,8 @@ ispioctl(struct cdev *dev, u_long c, caddr_t addr, int flags, struct thread *td) ISP_UNLOCK(isp); break; } - MBSINIT(&mbs, MBOX_EXEC_COMMAND_IOCB_A64, MBLOGALL, 5000000); + MBSINIT(&mbs, MBOX_EXEC_COMMAND_IOCB_A64, MBLOGALL, + MBCMD_DEFAULT_TIMEOUT + tmf->tmf_timeout * 1000000); mbs.param[1] = QENTRY_LEN; mbs.param[2] = DMA_WD1(fcp->isp_scdma); mbs.param[3] = DMA_WD0(fcp->isp_scdma); @@ -1403,7 +1404,7 @@ isp_target_start_ctio(ispsoftc_t *isp, union ccb *ccb, enum Start_Ctio_How how) cto->ct_iid_hi = atp->portid >> 16; cto->ct_oxid = atp->oxid; cto->ct_vpidx = ISP_GET_VPIDX(isp, XS_CHANNEL(ccb)); - cto->ct_timeout = 120; + cto->ct_timeout = (XS_TIME(ccb) + 999) / 1000; cto->ct_flags = atp->tattr << CT7_TASK_ATTR_SHIFT; /* @@ -1555,7 +1556,7 @@ isp_target_start_ctio(ispsoftc_t *isp, union ccb *ccb, enum Start_Ctio_How how) cto->ct_lun = ccb->ccb_h.target_lun; } } - cto->ct_timeout = 10; + cto->ct_timeout = (XS_TIME(ccb) + 999) / 1000; cto->ct_rxid = cso->tag_id; /* diff --git a/sys/dev/isp/ispmbox.h b/sys/dev/isp/ispmbox.h index a89228b..5a1306f 100644 --- a/sys/dev/isp/ispmbox.h +++ b/sys/dev/isp/ispmbox.h @@ -1086,7 +1086,7 @@ typedef struct { #define ICB_DFLT_RDELAY 5 #define ICB_DFLT_RCOUNT 3 -#define ICB_LOGIN_TOV 30 +#define ICB_LOGIN_TOV 10 #define ICB_LUN_ENABLE_TOV 15 -- cgit v1.1 From d4b9f20402a6d7261e6e6d8ea2ea402a189c08d8 Mon Sep 17 00:00:00 2001 From: mav Date: Wed, 30 Dec 2015 11:49:04 +0000 Subject: MFC r292715: Clear virtual port's port database when disabling it. Previously it was done only on full chip reinit, that caused old ports resurrect in case of virtual port reenabling. --- sys/dev/isp/isp.c | 153 +++++++++++++++++++++++++++++++++++++++++++ sys/dev/isp/isp_library.c | 162 ---------------------------------------------- sys/dev/isp/isp_library.h | 3 - 3 files changed, 153 insertions(+), 165 deletions(-) diff --git a/sys/dev/isp/isp.c b/sys/dev/isp/isp.c index 3350044..4f29cb0 100644 --- a/sys/dev/isp/isp.c +++ b/sys/dev/isp/isp.c @@ -2344,6 +2344,159 @@ isp_fibre_init_2400(ispsoftc_t *isp) isp->isp_state = ISP_RUNSTATE; } +static int +isp_fc_enable_vp(ispsoftc_t *isp, int chan) +{ + fcparam *fcp = FCPARAM(isp, chan); + mbreg_t mbs; + vp_modify_t *vp; + uint8_t qe[QENTRY_LEN], *scp; + + ISP_MEMZERO(qe, QENTRY_LEN); + if (FC_SCRATCH_ACQUIRE(isp, chan)) { + return (EBUSY); + } + scp = fcp->isp_scratch; + + /* Build a VP MODIFY command in memory */ + vp = (vp_modify_t *) qe; + vp->vp_mod_hdr.rqs_entry_type = RQSTYPE_VP_MODIFY; + vp->vp_mod_hdr.rqs_entry_count = 1; + vp->vp_mod_cnt = 1; + vp->vp_mod_idx0 = chan; + vp->vp_mod_cmd = VP_MODIFY_ENA; + vp->vp_mod_ports[0].options = ICB2400_VPOPT_ENABLED | + ICB2400_VPOPT_ENA_SNSLOGIN; + if (fcp->role & ISP_ROLE_INITIATOR) { + vp->vp_mod_ports[0].options |= ICB2400_VPOPT_INI_ENABLE; + } + if ((fcp->role & ISP_ROLE_TARGET) == 0) { + vp->vp_mod_ports[0].options |= ICB2400_VPOPT_TGT_DISABLE; + } + if (fcp->isp_loopid < LOCAL_LOOP_LIM) { + vp->vp_mod_ports[0].loopid = fcp->isp_loopid; + if (isp->isp_confopts & ISP_CFG_OWNLOOPID) + vp->vp_mod_ports[0].options |= + ICB2400_VPOPT_HARD_ADDRESS; + else + vp->vp_mod_ports[0].options |= + ICB2400_VPOPT_PREV_ADDRESS; + } + MAKE_NODE_NAME_FROM_WWN(vp->vp_mod_ports[0].wwpn, fcp->isp_wwpn); + MAKE_NODE_NAME_FROM_WWN(vp->vp_mod_ports[0].wwnn, fcp->isp_wwnn); + isp_put_vp_modify(isp, vp, (vp_modify_t *) scp); + + /* Build a EXEC IOCB A64 command that points to the VP MODIFY command */ + MBSINIT(&mbs, MBOX_EXEC_COMMAND_IOCB_A64, MBLOGALL, 0); + mbs.param[1] = QENTRY_LEN; + mbs.param[2] = DMA_WD1(fcp->isp_scdma); + mbs.param[3] = DMA_WD0(fcp->isp_scdma); + mbs.param[6] = DMA_WD3(fcp->isp_scdma); + mbs.param[7] = DMA_WD2(fcp->isp_scdma); + MEMORYBARRIER(isp, SYNC_SFORDEV, 0, 2 * QENTRY_LEN, chan); + isp_control(isp, ISPCTL_RUN_MBOXCMD, &mbs); + if (mbs.param[0] != MBOX_COMMAND_COMPLETE) { + FC_SCRATCH_RELEASE(isp, chan); + return (EIO); + } + MEMORYBARRIER(isp, SYNC_SFORCPU, QENTRY_LEN, QENTRY_LEN, chan); + isp_get_vp_modify(isp, (vp_modify_t *)&scp[QENTRY_LEN], vp); + + FC_SCRATCH_RELEASE(isp, chan); + + if (vp->vp_mod_status != VP_STS_OK) { + isp_prt(isp, ISP_LOGERR, "%s: VP_MODIFY of Chan %d failed with status %d", __func__, chan, vp->vp_mod_status); + return (EIO); + } + return (0); +} + +static int +isp_fc_disable_vp(ispsoftc_t *isp, int chan) +{ + fcparam *fcp = FCPARAM(isp, chan); + mbreg_t mbs; + vp_ctrl_info_t *vp; + uint8_t qe[QENTRY_LEN], *scp; + + ISP_MEMZERO(qe, QENTRY_LEN); + if (FC_SCRATCH_ACQUIRE(isp, chan)) { + return (EBUSY); + } + scp = fcp->isp_scratch; + + /* Build a VP CTRL command in memory */ + vp = (vp_ctrl_info_t *) qe; + vp->vp_ctrl_hdr.rqs_entry_type = RQSTYPE_VP_CTRL; + vp->vp_ctrl_hdr.rqs_entry_count = 1; + if (ISP_CAP_VP0(isp)) { + vp->vp_ctrl_status = 1; + } else { + vp->vp_ctrl_status = 0; + chan--; /* VP0 can not be controlled in this case. */ + } + vp->vp_ctrl_command = VP_CTRL_CMD_DISABLE_VP_LOGO_ALL; + vp->vp_ctrl_vp_count = 1; + vp->vp_ctrl_idmap[chan / 16] |= (1 << chan % 16); + isp_put_vp_ctrl_info(isp, vp, (vp_ctrl_info_t *) scp); + + /* Build a EXEC IOCB A64 command that points to the VP CTRL command */ + MBSINIT(&mbs, MBOX_EXEC_COMMAND_IOCB_A64, MBLOGALL, 0); + mbs.param[1] = QENTRY_LEN; + mbs.param[2] = DMA_WD1(fcp->isp_scdma); + mbs.param[3] = DMA_WD0(fcp->isp_scdma); + mbs.param[6] = DMA_WD3(fcp->isp_scdma); + mbs.param[7] = DMA_WD2(fcp->isp_scdma); + MEMORYBARRIER(isp, SYNC_SFORDEV, 0, 2 * QENTRY_LEN, chan); + isp_control(isp, ISPCTL_RUN_MBOXCMD, &mbs); + if (mbs.param[0] != MBOX_COMMAND_COMPLETE) { + FC_SCRATCH_RELEASE(isp, chan); + return (EIO); + } + MEMORYBARRIER(isp, SYNC_SFORCPU, QENTRY_LEN, QENTRY_LEN, chan); + isp_get_vp_ctrl_info(isp, (vp_ctrl_info_t *)&scp[QENTRY_LEN], vp); + + FC_SCRATCH_RELEASE(isp, chan); + + if (vp->vp_ctrl_status != 0) { + isp_prt(isp, ISP_LOGERR, + "%s: VP_CTRL of Chan %d failed with status %d %d", + __func__, chan, vp->vp_ctrl_status, vp->vp_ctrl_index_fail); + return (EIO); + } + return (0); +} + +static int +isp_fc_change_role(ispsoftc_t *isp, int chan, int new_role) +{ + fcparam *fcp = FCPARAM(isp, chan); + int i, was, res = 0; + + if (chan >= isp->isp_nchan) { + isp_prt(isp, ISP_LOGWARN, "%s: bad channel %d", __func__, chan); + return (ENXIO); + } + if (fcp->role == new_role) + return (0); + for (was = 0, i = 0; i < isp->isp_nchan; i++) { + if (FCPARAM(isp, i)->role != ISP_ROLE_NONE) + was++; + } + if (was == 0 || (was == 1 && fcp->role != ISP_ROLE_NONE)) { + fcp->role = new_role; + return (isp_reinit(isp, 0)); + } + if (fcp->role != ISP_ROLE_NONE) { + res = isp_fc_disable_vp(isp, chan); + isp_clear_portdb(isp, chan); + } + fcp->role = new_role; + if (fcp->role != ISP_ROLE_NONE) + res = isp_fc_enable_vp(isp, chan); + return (res); +} + static void isp_clear_portdb(ispsoftc_t *isp, int chan) { diff --git a/sys/dev/isp/isp_library.c b/sys/dev/isp/isp_library.c index ec99244..28b51a3 100644 --- a/sys/dev/isp/isp_library.c +++ b/sys/dev/isp/isp_library.c @@ -573,168 +573,6 @@ isp_fc_toponame(fcparam *fcp) } } -static int -isp_fc_enable_vp(ispsoftc_t *isp, int chan) -{ - fcparam *fcp = FCPARAM(isp, chan); - mbreg_t mbs; - vp_modify_t *vp; - uint8_t qe[QENTRY_LEN], *scp; - - ISP_MEMZERO(qe, QENTRY_LEN); - if (FC_SCRATCH_ACQUIRE(isp, chan)) { - return (EBUSY); - } - scp = fcp->isp_scratch; - - /* - * Build a VP MODIFY command in memory - */ - vp = (vp_modify_t *) qe; - vp->vp_mod_hdr.rqs_entry_type = RQSTYPE_VP_MODIFY; - vp->vp_mod_hdr.rqs_entry_count = 1; - vp->vp_mod_cnt = 1; - vp->vp_mod_idx0 = chan; - vp->vp_mod_cmd = VP_MODIFY_ENA; - vp->vp_mod_ports[0].options = ICB2400_VPOPT_ENABLED | - ICB2400_VPOPT_ENA_SNSLOGIN; - if (fcp->role & ISP_ROLE_INITIATOR) { - vp->vp_mod_ports[0].options |= ICB2400_VPOPT_INI_ENABLE; - } - if ((fcp->role & ISP_ROLE_TARGET) == 0) { - vp->vp_mod_ports[0].options |= ICB2400_VPOPT_TGT_DISABLE; - } - if (fcp->isp_loopid < LOCAL_LOOP_LIM) { - vp->vp_mod_ports[0].loopid = fcp->isp_loopid; - if (isp->isp_confopts & ISP_CFG_OWNLOOPID) - vp->vp_mod_ports[0].options |= - ICB2400_VPOPT_HARD_ADDRESS; - else - vp->vp_mod_ports[0].options |= - ICB2400_VPOPT_PREV_ADDRESS; - } - MAKE_NODE_NAME_FROM_WWN(vp->vp_mod_ports[0].wwpn, fcp->isp_wwpn); - MAKE_NODE_NAME_FROM_WWN(vp->vp_mod_ports[0].wwnn, fcp->isp_wwnn); - isp_put_vp_modify(isp, vp, (vp_modify_t *) scp); - - /* - * Build a EXEC IOCB A64 command that points to the VP MODIFY command - */ - MBSINIT(&mbs, MBOX_EXEC_COMMAND_IOCB_A64, MBLOGALL, 0); - mbs.param[1] = QENTRY_LEN; - mbs.param[2] = DMA_WD1(fcp->isp_scdma); - mbs.param[3] = DMA_WD0(fcp->isp_scdma); - mbs.param[6] = DMA_WD3(fcp->isp_scdma); - mbs.param[7] = DMA_WD2(fcp->isp_scdma); - MEMORYBARRIER(isp, SYNC_SFORDEV, 0, 2 * QENTRY_LEN, chan); - isp_control(isp, ISPCTL_RUN_MBOXCMD, &mbs); - if (mbs.param[0] != MBOX_COMMAND_COMPLETE) { - FC_SCRATCH_RELEASE(isp, chan); - return (EIO); - } - MEMORYBARRIER(isp, SYNC_SFORCPU, QENTRY_LEN, QENTRY_LEN, chan); - isp_get_vp_modify(isp, (vp_modify_t *)&scp[QENTRY_LEN], vp); - - FC_SCRATCH_RELEASE(isp, chan); - - if (vp->vp_mod_status != VP_STS_OK) { - isp_prt(isp, ISP_LOGERR, "%s: VP_MODIFY of Chan %d failed with status %d", __func__, chan, vp->vp_mod_status); - return (EIO); - } - return (0); -} - -static int -isp_fc_disable_vp(ispsoftc_t *isp, int chan) -{ - fcparam *fcp = FCPARAM(isp, chan); - mbreg_t mbs; - vp_ctrl_info_t *vp; - uint8_t qe[QENTRY_LEN], *scp; - - ISP_MEMZERO(qe, QENTRY_LEN); - if (FC_SCRATCH_ACQUIRE(isp, chan)) { - return (EBUSY); - } - scp = fcp->isp_scratch; - - /* - * Build a VP CTRL command in memory - */ - vp = (vp_ctrl_info_t *) qe; - vp->vp_ctrl_hdr.rqs_entry_type = RQSTYPE_VP_CTRL; - vp->vp_ctrl_hdr.rqs_entry_count = 1; - if (ISP_CAP_VP0(isp)) { - vp->vp_ctrl_status = 1; - } else { - vp->vp_ctrl_status = 0; - chan--; /* VP0 can not be controlled in this case. */ - } - vp->vp_ctrl_command = VP_CTRL_CMD_DISABLE_VP_LOGO_ALL; - vp->vp_ctrl_vp_count = 1; - vp->vp_ctrl_idmap[chan / 16] |= (1 << chan % 16); - isp_put_vp_ctrl_info(isp, vp, (vp_ctrl_info_t *) scp); - - /* - * Build a EXEC IOCB A64 command that points to the VP CTRL command - */ - MBSINIT(&mbs, MBOX_EXEC_COMMAND_IOCB_A64, MBLOGALL, 0); - mbs.param[1] = QENTRY_LEN; - mbs.param[2] = DMA_WD1(fcp->isp_scdma); - mbs.param[3] = DMA_WD0(fcp->isp_scdma); - mbs.param[6] = DMA_WD3(fcp->isp_scdma); - mbs.param[7] = DMA_WD2(fcp->isp_scdma); - MEMORYBARRIER(isp, SYNC_SFORDEV, 0, 2 * QENTRY_LEN, chan); - isp_control(isp, ISPCTL_RUN_MBOXCMD, &mbs); - if (mbs.param[0] != MBOX_COMMAND_COMPLETE) { - FC_SCRATCH_RELEASE(isp, chan); - return (EIO); - } - MEMORYBARRIER(isp, SYNC_SFORCPU, QENTRY_LEN, QENTRY_LEN, chan); - isp_get_vp_ctrl_info(isp, (vp_ctrl_info_t *)&scp[QENTRY_LEN], vp); - - FC_SCRATCH_RELEASE(isp, chan); - - if (vp->vp_ctrl_status != 0) { - isp_prt(isp, ISP_LOGERR, - "%s: VP_CTRL of Chan %d failed with status %d %d", - __func__, chan, vp->vp_ctrl_status, vp->vp_ctrl_index_fail); - return (EIO); - } - return (0); -} - -/* - * Change Roles - */ -int -isp_fc_change_role(ispsoftc_t *isp, int chan, int new_role) -{ - fcparam *fcp = FCPARAM(isp, chan); - int i, was, res = 0; - - if (chan >= isp->isp_nchan) { - isp_prt(isp, ISP_LOGWARN, "%s: bad channel %d", __func__, chan); - return (ENXIO); - } - if (fcp->role == new_role) - return (0); - for (was = 0, i = 0; i < isp->isp_nchan; i++) { - if (FCPARAM(isp, i)->role != ISP_ROLE_NONE) - was++; - } - if (was == 0 || (was == 1 && fcp->role != ISP_ROLE_NONE)) { - fcp->role = new_role; - return (isp_reinit(isp, 0)); - } - if (fcp->role != ISP_ROLE_NONE) - res = isp_fc_disable_vp(isp, chan); - fcp->role = new_role; - if (fcp->role != ISP_ROLE_NONE) - res = isp_fc_enable_vp(isp, chan); - return (res); -} - void isp_clear_commands(ispsoftc_t *isp) { diff --git a/sys/dev/isp/isp_library.h b/sys/dev/isp/isp_library.h index efe4e0e..9f3cbcd 100644 --- a/sys/dev/isp/isp_library.h +++ b/sys/dev/isp/isp_library.h @@ -72,9 +72,6 @@ const char *isp_fc_fw_statename(int); const char *isp_fc_loop_statename(int); const char *isp_fc_toponame(fcparam *); -int isp_fc_change_role(ispsoftc_t *, int, int); - - /* * Cleanup */ -- cgit v1.1 From a4b1c16e98e75f90d54e9dbd7a1fdb698da68539 Mon Sep 17 00:00:00 2001 From: mav Date: Wed, 30 Dec 2015 11:49:48 +0000 Subject: MFC r292725: Unify handles allocation for initiator and target IOCBs. I am not sure why this was split long ago, but I see no reason for it. At this point this unification just slightly reduces memory usage, but as next step I plan to reuse shared handle space for other IOCB types. --- sys/dev/isp/isp.c | 16 ++--- sys/dev/isp/isp_freebsd.c | 11 ++-- sys/dev/isp/isp_library.c | 161 ++++++++++++---------------------------------- sys/dev/isp/isp_library.h | 12 +--- sys/dev/isp/isp_pci.c | 24 ------- sys/dev/isp/isp_target.c | 4 +- sys/dev/isp/ispvar.h | 23 ++----- 7 files changed, 60 insertions(+), 191 deletions(-) diff --git a/sys/dev/isp/isp.c b/sys/dev/isp/isp.c index 4f29cb0..66eff1e 100644 --- a/sys/dev/isp/isp.c +++ b/sys/dev/isp/isp.c @@ -4269,7 +4269,7 @@ int isp_start(XS_T *xs) { ispsoftc_t *isp; - uint32_t handle, cdblen; + uint32_t cdblen; uint8_t local[QENTRY_LEN]; ispreq_t *reqp; void *cdbp, *qep; @@ -4565,13 +4565,13 @@ isp_start(XS_T *xs) *tptr = 0x1999; } - if (isp_allocate_xs(isp, xs, &handle)) { + /* Whew. Thankfully the same for type 7 requests */ + reqp->req_handle = isp_allocate_handle(isp, xs, ISP_HANDLE_INITIATOR); + if (reqp->req_handle == 0) { isp_prt(isp, ISP_LOG_WARN1, "out of xflist pointers"); XS_SETERR(xs, HBA_BOTCH); return (CMD_EAGAIN); } - /* Whew. Thankfully the same for type 7 requests */ - reqp->req_handle = handle; /* * Set up DMA and/or do any platform dependent swizzling of the request entry @@ -4581,7 +4581,7 @@ isp_start(XS_T *xs) */ dmaresult = ISP_DMASETUP(isp, xs, reqp); if (dmaresult != CMD_QUEUED) { - isp_destroy_handle(isp, handle); + isp_destroy_handle(isp, reqp->req_handle); /* * dmasetup sets actual error in packet, and * return what we were given to return. @@ -5310,12 +5310,6 @@ again: } } - if (!ISP_VALID_HANDLE(isp, sp->req_handle)) { - isp_prt(isp, ISP_LOGERR, "bad request handle 0x%x (iocb type 0x%x)", sp->req_handle, etype); - ISP_MEMZERO(hp, QENTRY_LEN); /* PERF */ - last_etype = etype; - continue; - } xs = isp_find_xs(isp, sp->req_handle); if (xs == NULL) { uint8_t ts = completion_status & 0xff; diff --git a/sys/dev/isp/isp_freebsd.c b/sys/dev/isp/isp_freebsd.c index 69b5a5c..cbf1262 100644 --- a/sys/dev/isp/isp_freebsd.c +++ b/sys/dev/isp/isp_freebsd.c @@ -1694,7 +1694,8 @@ isp_target_start_ctio(ispsoftc_t *isp, union ccb *ccb, enum Start_Ctio_How how) TAILQ_INSERT_HEAD(&tptr->waitq, &ccb->ccb_h, periph_links.tqe); break; } - if (isp_allocate_xs_tgt(isp, ccb, &handle)) { + handle = isp_allocate_handle(isp, ccb, ISP_HANDLE_TARGET); + if (handle == 0) { ISP_PATH_PRT(isp, ISP_LOGWARN, ccb->ccb_h.path, "No XFLIST pointers for %s\n", __func__); TAILQ_INSERT_HEAD(&tptr->waitq, &ccb->ccb_h, periph_links.tqe); isp_free_pcmd(isp, ccb); @@ -1723,7 +1724,7 @@ isp_target_start_ctio(ispsoftc_t *isp, union ccb *ccb, enum Start_Ctio_How how) dmaresult = ISP_DMASETUP(isp, cso, (ispreq_t *) local); if (dmaresult != CMD_QUEUED) { - isp_destroy_tgt_handle(isp, handle); + isp_destroy_handle(isp, handle); isp_free_pcmd(isp, ccb); if (dmaresult == CMD_EAGAIN) { TAILQ_INSERT_HEAD(&tptr->waitq, &ccb->ccb_h, periph_links.tqe); @@ -2380,12 +2381,12 @@ isp_handle_platform_ctio(ispsoftc_t *isp, void *arg) uint32_t handle, moved_data = 0, data_requested; handle = ((ct2_entry_t *)arg)->ct_syshandle; - ccb = isp_find_xs_tgt(isp, handle); + ccb = isp_find_xs(isp, handle); if (ccb == NULL) { isp_print_bytes(isp, "null ccb in isp_handle_platform_ctio", QENTRY_LEN, arg); return; } - isp_destroy_tgt_handle(isp, handle); + isp_destroy_handle(isp, handle); data_requested = PISP_PCMD(ccb)->datalen; isp_free_pcmd(isp, ccb); if (isp->isp_nactive) { @@ -3321,7 +3322,7 @@ isp_loop_dead(ispsoftc_t *isp, int chan) for (i = 0; i < isp->isp_maxcmds; i++) { struct ccb_scsiio *xs; - if (!ISP_VALID_HANDLE(isp, isp->isp_xflist[i].handle)) { + if (ISP_H2HT(isp->isp_xflist[i].handle) != ISP_HANDLE_INITIATOR) { continue; } if ((xs = isp->isp_xflist[i].cmd) == NULL) { diff --git a/sys/dev/isp/isp_library.c b/sys/dev/isp/isp_library.c index 28b51a3..76890dc 100644 --- a/sys/dev/isp/isp_library.c +++ b/sys/dev/isp/isp_library.c @@ -247,28 +247,26 @@ copy_and_sync: return (CMD_QUEUED); } -int -isp_allocate_xs(ispsoftc_t *isp, XS_T *xs, uint32_t *handlep) +uint32_t +isp_allocate_handle(ispsoftc_t *isp, void *xs, int type) { isp_hdl_t *hdp; hdp = isp->isp_xffree; - if (hdp == NULL) { - return (-1); - } + if (hdp == NULL) + return (ISP_HANDLE_FREE); isp->isp_xffree = hdp->cmd; hdp->cmd = xs; hdp->handle = (hdp - isp->isp_xflist); - hdp->handle |= (ISP_HANDLE_INITIATOR << ISP_HANDLE_USAGE_SHIFT); + hdp->handle |= (type << ISP_HANDLE_USAGE_SHIFT); hdp->handle |= (isp->isp_seqno++ << ISP_HANDLE_SEQ_SHIFT); - *handlep = hdp->handle; - return (0); + return (hdp->handle); } -XS_T * +void * isp_find_xs(ispsoftc_t *isp, uint32_t handle) { - if (!ISP_VALID_INI_HANDLE(isp, handle)) { + if (!ISP_VALID_HANDLE(isp, handle)) { isp_prt(isp, ISP_LOGERR, "%s: bad handle 0x%x", __func__, handle); return (NULL); } @@ -276,7 +274,7 @@ isp_find_xs(ispsoftc_t *isp, uint32_t handle) } uint32_t -isp_find_handle(ispsoftc_t *isp, XS_T *xs) +isp_find_handle(ispsoftc_t *isp, void *xs) { uint32_t i, foundhdl = ISP_HANDLE_FREE; @@ -292,21 +290,10 @@ isp_find_handle(ispsoftc_t *isp, XS_T *xs) return (foundhdl); } -uint32_t -isp_handle_index(ispsoftc_t *isp, uint32_t handle) -{ - if (!ISP_VALID_HANDLE(isp, handle)) { - isp_prt(isp, ISP_LOGERR, "%s: bad handle 0x%x", __func__, handle); - return (ISP_BAD_HANDLE_INDEX); - } else { - return (handle & ISP_HANDLE_CMD_MASK); - } -} - void isp_destroy_handle(ispsoftc_t *isp, uint32_t handle) { - if (!ISP_VALID_INI_HANDLE(isp, handle)) { + if (!ISP_VALID_HANDLE(isp, handle)) { isp_prt(isp, ISP_LOGERR, "%s: bad handle 0x%x", __func__, handle); } else { isp->isp_xflist[(handle & ISP_HANDLE_CMD_MASK)].handle = ISP_HANDLE_FREE; @@ -583,46 +570,41 @@ isp_clear_commands(ispsoftc_t *isp) #endif for (tmp = 0; isp->isp_xflist && tmp < isp->isp_maxcmds; tmp++) { - XS_T *xs; hdp = &isp->isp_xflist[tmp]; - if (hdp->handle == ISP_HANDLE_FREE) { - continue; - } - xs = hdp->cmd; - if (XS_XFRLEN(xs)) { - ISP_DMAFREE(isp, xs, hdp->handle); - XS_SET_RESID(xs, XS_XFRLEN(xs)); - } else { - XS_SET_RESID(xs, 0); - } - hdp->handle = 0; - hdp->cmd = NULL; - XS_SETERR(xs, HBA_BUSRESET); - isp_done(xs); - } + if (ISP_H2HT(hdp->handle) == ISP_HANDLE_INITIATOR) { + XS_T *xs = hdp->cmd; + if (XS_XFRLEN(xs)) { + ISP_DMAFREE(isp, xs, hdp->handle); + XS_SET_RESID(xs, XS_XFRLEN(xs)); + } else { + XS_SET_RESID(xs, 0); + } + hdp->handle = 0; + hdp->cmd = NULL; + XS_SETERR(xs, HBA_BUSRESET); + isp_done(xs); #ifdef ISP_TARGET_MODE - for (tmp = 0; isp->isp_tgtlist && tmp < isp->isp_maxcmds; tmp++) { - uint8_t local[QENTRY_LEN]; - hdp = &isp->isp_tgtlist[tmp]; - if (hdp->handle == ISP_HANDLE_FREE) { - continue; - } - ISP_DMAFREE(isp, hdp->cmd, hdp->handle); - ISP_MEMZERO(local, QENTRY_LEN); - if (IS_24XX(isp)) { - ct7_entry_t *ctio = (ct7_entry_t *) local; - ctio->ct_syshandle = hdp->handle; - ctio->ct_nphdl = CT_HBA_RESET; - ctio->ct_header.rqs_entry_type = RQSTYPE_CTIO7; - } else { - ct2_entry_t *ctio = (ct2_entry_t *) local; - ctio->ct_syshandle = hdp->handle; - ctio->ct_status = CT_HBA_RESET; - ctio->ct_header.rqs_entry_type = RQSTYPE_CTIO2; + } else if (ISP_H2HT(hdp->handle) == ISP_HANDLE_TARGET) { + uint8_t local[QENTRY_LEN]; + ISP_DMAFREE(isp, hdp->cmd, hdp->handle); + ISP_MEMZERO(local, QENTRY_LEN); + if (IS_24XX(isp)) { + ct7_entry_t *ctio = (ct7_entry_t *) local; + ctio->ct_syshandle = hdp->handle; + ctio->ct_nphdl = CT_HBA_RESET; + ctio->ct_header.rqs_entry_type = RQSTYPE_CTIO7; + } else { + ct2_entry_t *ctio = (ct2_entry_t *) local; + ctio->ct_syshandle = hdp->handle; + ctio->ct_status = CT_HBA_RESET; + ctio->ct_header.rqs_entry_type = RQSTYPE_CTIO2; + } + isp_async(isp, ISPASYNC_TARGET_ACTION, local); +#endif } - isp_async(isp, ISPASYNC_TARGET_ACTION, local); } +#ifdef ISP_TARGET_MODE for (tmp = 0; tmp < isp->isp_nchan; tmp++) { ISP_MEMZERO(¬ify, sizeof (isp_notify_t)); notify.nt_ncode = NT_HBA_RESET; @@ -2223,69 +2205,6 @@ isp_send_tgt_cmd(ispsoftc_t *isp, void *fqe, void *segp, uint32_t nsegs, uint32_ return (CMD_QUEUED); } -int -isp_allocate_xs_tgt(ispsoftc_t *isp, void *xs, uint32_t *handlep) -{ - isp_hdl_t *hdp; - - hdp = isp->isp_tgtfree; - if (hdp == NULL) { - return (-1); - } - isp->isp_tgtfree = hdp->cmd; - hdp->cmd = xs; - hdp->handle = (hdp - isp->isp_tgtlist); - hdp->handle |= (ISP_HANDLE_TARGET << ISP_HANDLE_USAGE_SHIFT); - /* - * Target handles for SCSI cards are only 16 bits, so - * sequence number protection will be ommitted. - */ - if (IS_FC(isp)) { - hdp->handle |= (isp->isp_seqno++ << ISP_HANDLE_SEQ_SHIFT); - } - *handlep = hdp->handle; - return (0); -} - -void * -isp_find_xs_tgt(ispsoftc_t *isp, uint32_t handle) -{ - if (!ISP_VALID_TGT_HANDLE(isp, handle)) { - isp_prt(isp, ISP_LOGERR, "%s: bad handle 0x%x", __func__, handle); - return (NULL); - } - return (isp->isp_tgtlist[(handle & ISP_HANDLE_CMD_MASK)].cmd); -} - -uint32_t -isp_find_tgt_handle(ispsoftc_t *isp, void *xs) -{ - uint32_t i, foundhdl = ISP_HANDLE_FREE; - - if (xs != NULL) { - for (i = 0; i < isp->isp_maxcmds; i++) { - if (isp->isp_tgtlist[i].cmd != xs) { - continue; - } - foundhdl = isp->isp_tgtlist[i].handle; - break; - } - } - return (foundhdl); -} - -void -isp_destroy_tgt_handle(ispsoftc_t *isp, uint32_t handle) -{ - if (!ISP_VALID_TGT_HANDLE(isp, handle)) { - isp_prt(isp, ISP_LOGERR, "%s: bad handle 0x%x", __func__, handle); - } else { - isp->isp_tgtlist[(handle & ISP_HANDLE_CMD_MASK)].handle = ISP_HANDLE_FREE; - isp->isp_tgtlist[(handle & ISP_HANDLE_CMD_MASK)].cmd = isp->isp_tgtfree; - isp->isp_tgtfree = &isp->isp_tgtlist[(handle & ISP_HANDLE_CMD_MASK)]; - } -} - #endif /* diff --git a/sys/dev/isp/isp_library.h b/sys/dev/isp/isp_library.h index 9f3cbcd..922a98b 100644 --- a/sys/dev/isp/isp_library.h +++ b/sys/dev/isp/isp_library.h @@ -43,10 +43,9 @@ int isp_send_cmd(ispsoftc_t *, void *, void *, uint32_t, uint32_t, isp_ddir_t, i * * These handles are associate with a command. */ -int isp_allocate_xs(ispsoftc_t *, XS_T *, uint32_t *); -XS_T * isp_find_xs(ispsoftc_t *, uint32_t); -uint32_t isp_find_handle(ispsoftc_t *, XS_T *); -uint32_t isp_handle_index(ispsoftc_t *, uint32_t); +uint32_t isp_allocate_handle(ispsoftc_t *, void *, int); +void *isp_find_xs(ispsoftc_t *, uint32_t); +uint32_t isp_find_handle(ispsoftc_t *, void *); void isp_destroy_handle(ispsoftc_t *, uint32_t); /* @@ -162,11 +161,6 @@ void isp_put_fcp_rsp_iu(ispsoftc_t *isp, fcp_rsp_iu_t *, fcp_rsp_iu_t *); #endif int isp_send_tgt_cmd(ispsoftc_t *, void *, void *, uint32_t, uint32_t, isp_ddir_t, void *, uint32_t); - -int isp_allocate_xs_tgt(ispsoftc_t *, void *, uint32_t *); -void *isp_find_xs_tgt(ispsoftc_t *, uint32_t); -uint32_t isp_find_tgt_handle(ispsoftc_t *, void *); -void isp_destroy_tgt_handle(ispsoftc_t *, uint32_t); #endif int isp_find_pdb_empty(ispsoftc_t *, int, fcportdb_t **); int isp_find_pdb_by_wwpn(ispsoftc_t *, int, uint64_t, fcportdb_t **); diff --git a/sys/dev/isp/isp_pci.c b/sys/dev/isp/isp_pci.c index e5ea359..1701e81 100644 --- a/sys/dev/isp/isp_pci.c +++ b/sys/dev/isp/isp_pci.c @@ -1684,21 +1684,6 @@ isp_pci_mbxdma(ispsoftc_t *isp) isp->isp_xflist[len].cmd = &isp->isp_xflist[len+1]; } isp->isp_xffree = isp->isp_xflist; -#ifdef ISP_TARGET_MODE - len = sizeof (isp_hdl_t) * isp->isp_maxcmds; - isp->isp_tgtlist = (isp_hdl_t *) malloc(len, M_DEVBUF, M_WAITOK | M_ZERO); - if (isp->isp_tgtlist == NULL) { - free(isp->isp_osinfo.pcmd_pool, M_DEVBUF); - free(isp->isp_xflist, M_DEVBUF); - ISP_LOCK(isp); - isp_prt(isp, ISP_LOGERR, "cannot alloc tgtlist array"); - return (1); - } - for (len = 0; len < isp->isp_maxcmds - 1; len++) { - isp->isp_tgtlist[len].cmd = &isp->isp_tgtlist[len+1]; - } - isp->isp_tgtfree = isp->isp_tgtlist; -#endif /* * Allocate and map the request and result queues (and ATIO queue @@ -1725,9 +1710,6 @@ isp_pci_mbxdma(ispsoftc_t *isp) isp_prt(isp, ISP_LOGERR, "cannot create a dma tag for control spaces"); free(isp->isp_osinfo.pcmd_pool, M_DEVBUF); free(isp->isp_xflist, M_DEVBUF); -#ifdef ISP_TARGET_MODE - free(isp->isp_tgtlist, M_DEVBUF); -#endif ISP_LOCK(isp); return (1); } @@ -1737,9 +1719,6 @@ isp_pci_mbxdma(ispsoftc_t *isp) bus_dma_tag_destroy(isp->isp_osinfo.cdmat); free(isp->isp_osinfo.pcmd_pool, M_DEVBUF); free(isp->isp_xflist, M_DEVBUF); -#ifdef ISP_TARGET_MODE - free(isp->isp_tgtlist, M_DEVBUF); -#endif ISP_LOCK(isp); return (1); } @@ -1828,9 +1807,6 @@ bad: bus_dmamem_free(isp->isp_osinfo.cdmat, base, isp->isp_osinfo.cdmap); bus_dma_tag_destroy(isp->isp_osinfo.cdmat); free(isp->isp_xflist, M_DEVBUF); -#ifdef ISP_TARGET_MODE - free(isp->isp_tgtlist, M_DEVBUF); -#endif free(isp->isp_osinfo.pcmd_pool, M_DEVBUF); isp->isp_rquest = NULL; ISP_LOCK(isp); diff --git a/sys/dev/isp/isp_target.c b/sys/dev/isp/isp_target.c index c6e48fe..c6af888 100644 --- a/sys/dev/isp/isp_target.c +++ b/sys/dev/isp/isp_target.c @@ -1094,7 +1094,7 @@ isp_handle_ctio2(ispsoftc_t *isp, ct2_entry_t *ct) char *fmsg = NULL; if (ct->ct_syshandle) { - xs = isp_find_xs_tgt(isp, ct->ct_syshandle); + xs = isp_find_xs(isp, ct->ct_syshandle); if (xs == NULL) { pl = ISP_LOGALL; } @@ -1249,7 +1249,7 @@ isp_handle_ctio7(ispsoftc_t *isp, ct7_entry_t *ct) char *fmsg = NULL; if (ct->ct_syshandle) { - xs = isp_find_xs_tgt(isp, ct->ct_syshandle); + xs = isp_find_xs(isp, ct->ct_syshandle); if (xs == NULL) { pl = ISP_LOGALL; } diff --git a/sys/dev/isp/ispvar.h b/sys/dev/isp/ispvar.h index 0c42642..ba285fb 100644 --- a/sys/dev/isp/ispvar.h +++ b/sys/dev/isp/ispvar.h @@ -318,18 +318,11 @@ typedef struct { #define ISP_HANDLE_SEQ_MASK 0xffff0000 #define ISP_HANDLE_SEQ_SHIFT 16 #define ISP_H2SEQ(hdl) ((hdl & ISP_HANDLE_SEQ_MASK) >> ISP_HANDLE_SEQ_SHIFT) -#define ISP_VALID_INI_HANDLE(c, hdl) \ - (ISP_H2HT(hdl) == ISP_HANDLE_INITIATOR && (hdl & ISP_HANDLE_CMD_MASK) < (c)->isp_maxcmds && \ - ISP_H2SEQ(hdl) == ISP_H2SEQ((c)->isp_xflist[hdl & ISP_HANDLE_CMD_MASK].handle)) -#ifdef ISP_TARGET_MODE -#define ISP_VALID_TGT_HANDLE(c, hdl) \ - (ISP_H2HT(hdl) == ISP_HANDLE_TARGET && (hdl & ISP_HANDLE_CMD_MASK) < (c)->isp_maxcmds && \ - ISP_H2SEQ(hdl) == ISP_H2SEQ((c)->isp_tgtlist[hdl & ISP_HANDLE_CMD_MASK].handle)) #define ISP_VALID_HANDLE(c, hdl) \ - (ISP_VALID_INI_HANDLE((c), hdl) || ISP_VALID_TGT_HANDLE((c), hdl)) -#else -#define ISP_VALID_HANDLE ISP_VALID_INI_HANDLE -#endif + ((ISP_H2HT(hdl) == ISP_HANDLE_INITIATOR || \ + ISP_H2HT(hdl) == ISP_HANDLE_TARGET) && \ + ((hdl) & ISP_HANDLE_CMD_MASK) < (c)->isp_maxcmds && \ + (hdl) == ((c)->isp_xflist[(hdl) & ISP_HANDLE_CMD_MASK].handle)) #define ISP_BAD_HANDLE_INDEX 0xffffffff @@ -598,14 +591,6 @@ struct ispsoftc { isp_hdl_t *isp_xflist; isp_hdl_t *isp_xffree; -#ifdef ISP_TARGET_MODE - /* - * Active target commands are stored here, indexed by handle functions. - */ - isp_hdl_t *isp_tgtlist; - isp_hdl_t *isp_tgtfree; -#endif - /* * request/result queue pointers and DMA handles for them. */ -- cgit v1.1 From 27a8f09a1b080c3913553e9a747a1e1b1ddde85b Mon Sep 17 00:00:00 2001 From: mav Date: Wed, 30 Dec 2015 11:50:52 +0000 Subject: MFC r292739: Make virtual ports control asynchronous. Before this change virtual ports control IOCBs were executed synchronously via Execute IOCB mailbox command. It required exclusive use of scratch space of driver and mailbox registers of the hardware. Because of that shared resources use this code could not really sleep, having to spin for completion, blocking any other operation. This change introduces new asynchronous design, sending the IOCBs directly on request queue and gracefully waiting for their return on response queue. Returned IOCBs are identified with unified handle space from r292725. --- sys/dev/isp/isp.c | 178 +++++++++++++++++++++++++--------------------- sys/dev/isp/isp_library.c | 16 +++-- sys/dev/isp/ispvar.h | 4 +- 3 files changed, 111 insertions(+), 87 deletions(-) diff --git a/sys/dev/isp/isp.c b/sys/dev/isp/isp.c index 66eff1e..b5385bc 100644 --- a/sys/dev/isp/isp.c +++ b/sys/dev/isp/isp.c @@ -2348,64 +2348,64 @@ static int isp_fc_enable_vp(ispsoftc_t *isp, int chan) { fcparam *fcp = FCPARAM(isp, chan); - mbreg_t mbs; - vp_modify_t *vp; - uint8_t qe[QENTRY_LEN], *scp; - - ISP_MEMZERO(qe, QENTRY_LEN); - if (FC_SCRATCH_ACQUIRE(isp, chan)) { - return (EBUSY); - } - scp = fcp->isp_scratch; + vp_modify_t vp; + void *reqp; + uint8_t resp[QENTRY_LEN]; /* Build a VP MODIFY command in memory */ - vp = (vp_modify_t *) qe; - vp->vp_mod_hdr.rqs_entry_type = RQSTYPE_VP_MODIFY; - vp->vp_mod_hdr.rqs_entry_count = 1; - vp->vp_mod_cnt = 1; - vp->vp_mod_idx0 = chan; - vp->vp_mod_cmd = VP_MODIFY_ENA; - vp->vp_mod_ports[0].options = ICB2400_VPOPT_ENABLED | + ISP_MEMZERO(&vp, sizeof(vp)); + vp.vp_mod_hdr.rqs_entry_type = RQSTYPE_VP_MODIFY; + vp.vp_mod_hdr.rqs_entry_count = 1; + vp.vp_mod_cnt = 1; + vp.vp_mod_idx0 = chan; + vp.vp_mod_cmd = VP_MODIFY_ENA; + vp.vp_mod_ports[0].options = ICB2400_VPOPT_ENABLED | ICB2400_VPOPT_ENA_SNSLOGIN; - if (fcp->role & ISP_ROLE_INITIATOR) { - vp->vp_mod_ports[0].options |= ICB2400_VPOPT_INI_ENABLE; - } - if ((fcp->role & ISP_ROLE_TARGET) == 0) { - vp->vp_mod_ports[0].options |= ICB2400_VPOPT_TGT_DISABLE; - } + if (fcp->role & ISP_ROLE_INITIATOR) + vp.vp_mod_ports[0].options |= ICB2400_VPOPT_INI_ENABLE; + if ((fcp->role & ISP_ROLE_TARGET) == 0) + vp.vp_mod_ports[0].options |= ICB2400_VPOPT_TGT_DISABLE; if (fcp->isp_loopid < LOCAL_LOOP_LIM) { - vp->vp_mod_ports[0].loopid = fcp->isp_loopid; + vp.vp_mod_ports[0].loopid = fcp->isp_loopid; if (isp->isp_confopts & ISP_CFG_OWNLOOPID) - vp->vp_mod_ports[0].options |= - ICB2400_VPOPT_HARD_ADDRESS; + vp.vp_mod_ports[0].options |= ICB2400_VPOPT_HARD_ADDRESS; else - vp->vp_mod_ports[0].options |= - ICB2400_VPOPT_PREV_ADDRESS; + vp.vp_mod_ports[0].options |= ICB2400_VPOPT_PREV_ADDRESS; } - MAKE_NODE_NAME_FROM_WWN(vp->vp_mod_ports[0].wwpn, fcp->isp_wwpn); - MAKE_NODE_NAME_FROM_WWN(vp->vp_mod_ports[0].wwnn, fcp->isp_wwnn); - isp_put_vp_modify(isp, vp, (vp_modify_t *) scp); + MAKE_NODE_NAME_FROM_WWN(vp.vp_mod_ports[0].wwpn, fcp->isp_wwpn); + MAKE_NODE_NAME_FROM_WWN(vp.vp_mod_ports[0].wwnn, fcp->isp_wwnn); - /* Build a EXEC IOCB A64 command that points to the VP MODIFY command */ - MBSINIT(&mbs, MBOX_EXEC_COMMAND_IOCB_A64, MBLOGALL, 0); - mbs.param[1] = QENTRY_LEN; - mbs.param[2] = DMA_WD1(fcp->isp_scdma); - mbs.param[3] = DMA_WD0(fcp->isp_scdma); - mbs.param[6] = DMA_WD3(fcp->isp_scdma); - mbs.param[7] = DMA_WD2(fcp->isp_scdma); - MEMORYBARRIER(isp, SYNC_SFORDEV, 0, 2 * QENTRY_LEN, chan); - isp_control(isp, ISPCTL_RUN_MBOXCMD, &mbs); - if (mbs.param[0] != MBOX_COMMAND_COMPLETE) { - FC_SCRATCH_RELEASE(isp, chan); + /* Prepare space for response in memory */ + memset(resp, 0xff, sizeof(resp)); + vp.vp_mod_hdl = isp_allocate_handle(isp, resp, ISP_HANDLE_CTRL); + if (vp.vp_mod_hdl == 0) { + isp_prt(isp, ISP_LOGERR, + "%s: VP_MODIFY of Chan %d out of handles", __func__, chan); return (EIO); } - MEMORYBARRIER(isp, SYNC_SFORCPU, QENTRY_LEN, QENTRY_LEN, chan); - isp_get_vp_modify(isp, (vp_modify_t *)&scp[QENTRY_LEN], vp); - FC_SCRATCH_RELEASE(isp, chan); + /* Send request and wait for response. */ + reqp = isp_getrqentry(isp); + if (reqp == NULL) { + isp_prt(isp, ISP_LOGERR, + "%s: VP_MODIFY of Chan %d out of rqent", __func__, chan); + isp_destroy_handle(isp, vp.vp_mod_hdl); + return (EIO); + } + isp_put_vp_modify(isp, &vp, (vp_modify_t *)reqp); + ISP_SYNC_REQUEST(isp); + if (msleep(resp, &isp->isp_lock, 0, "VP_MODIFY", 5*hz) == EWOULDBLOCK) { + isp_prt(isp, ISP_LOGERR, + "%s: VP_MODIFY of Chan %d timed out", __func__, chan); + isp_destroy_handle(isp, vp.vp_mod_hdl); + return (EIO); + } + isp_get_vp_modify(isp, (vp_modify_t *)resp, &vp); - if (vp->vp_mod_status != VP_STS_OK) { - isp_prt(isp, ISP_LOGERR, "%s: VP_MODIFY of Chan %d failed with status %d", __func__, chan, vp->vp_mod_status); + if (vp.vp_mod_hdr.rqs_flags != 0 || vp.vp_mod_status != VP_STS_OK) { + isp_prt(isp, ISP_LOGERR, + "%s: VP_MODIFY of Chan %d failed with flags %x status %d", + __func__, chan, vp.vp_mod_hdr.rqs_flags, vp.vp_mod_status); return (EIO); } return (0); @@ -2414,54 +2414,56 @@ isp_fc_enable_vp(ispsoftc_t *isp, int chan) static int isp_fc_disable_vp(ispsoftc_t *isp, int chan) { - fcparam *fcp = FCPARAM(isp, chan); - mbreg_t mbs; - vp_ctrl_info_t *vp; - uint8_t qe[QENTRY_LEN], *scp; - - ISP_MEMZERO(qe, QENTRY_LEN); - if (FC_SCRATCH_ACQUIRE(isp, chan)) { - return (EBUSY); - } - scp = fcp->isp_scratch; + vp_ctrl_info_t vp; + void *reqp; + uint8_t resp[QENTRY_LEN]; /* Build a VP CTRL command in memory */ - vp = (vp_ctrl_info_t *) qe; - vp->vp_ctrl_hdr.rqs_entry_type = RQSTYPE_VP_CTRL; - vp->vp_ctrl_hdr.rqs_entry_count = 1; + ISP_MEMZERO(&vp, sizeof(vp)); + vp.vp_ctrl_hdr.rqs_entry_type = RQSTYPE_VP_CTRL; + vp.vp_ctrl_hdr.rqs_entry_count = 1; if (ISP_CAP_VP0(isp)) { - vp->vp_ctrl_status = 1; + vp.vp_ctrl_status = 1; } else { - vp->vp_ctrl_status = 0; + vp.vp_ctrl_status = 0; chan--; /* VP0 can not be controlled in this case. */ } - vp->vp_ctrl_command = VP_CTRL_CMD_DISABLE_VP_LOGO_ALL; - vp->vp_ctrl_vp_count = 1; - vp->vp_ctrl_idmap[chan / 16] |= (1 << chan % 16); - isp_put_vp_ctrl_info(isp, vp, (vp_ctrl_info_t *) scp); + vp.vp_ctrl_command = VP_CTRL_CMD_DISABLE_VP_LOGO_ALL; + vp.vp_ctrl_vp_count = 1; + vp.vp_ctrl_idmap[chan / 16] |= (1 << chan % 16); - /* Build a EXEC IOCB A64 command that points to the VP CTRL command */ - MBSINIT(&mbs, MBOX_EXEC_COMMAND_IOCB_A64, MBLOGALL, 0); - mbs.param[1] = QENTRY_LEN; - mbs.param[2] = DMA_WD1(fcp->isp_scdma); - mbs.param[3] = DMA_WD0(fcp->isp_scdma); - mbs.param[6] = DMA_WD3(fcp->isp_scdma); - mbs.param[7] = DMA_WD2(fcp->isp_scdma); - MEMORYBARRIER(isp, SYNC_SFORDEV, 0, 2 * QENTRY_LEN, chan); - isp_control(isp, ISPCTL_RUN_MBOXCMD, &mbs); - if (mbs.param[0] != MBOX_COMMAND_COMPLETE) { - FC_SCRATCH_RELEASE(isp, chan); + /* Prepare space for response in memory */ + memset(resp, 0xff, sizeof(resp)); + vp.vp_ctrl_handle = isp_allocate_handle(isp, resp, ISP_HANDLE_CTRL); + if (vp.vp_ctrl_handle == 0) { + isp_prt(isp, ISP_LOGERR, + "%s: VP_CTRL of Chan %d out of handles", __func__, chan); return (EIO); } - MEMORYBARRIER(isp, SYNC_SFORCPU, QENTRY_LEN, QENTRY_LEN, chan); - isp_get_vp_ctrl_info(isp, (vp_ctrl_info_t *)&scp[QENTRY_LEN], vp); - FC_SCRATCH_RELEASE(isp, chan); + /* Send request and wait for response. */ + reqp = isp_getrqentry(isp); + if (reqp == NULL) { + isp_prt(isp, ISP_LOGERR, + "%s: VP_CTRL of Chan %d out of rqent", __func__, chan); + isp_destroy_handle(isp, vp.vp_ctrl_handle); + return (EIO); + } + isp_put_vp_ctrl_info(isp, &vp, (vp_ctrl_info_t *)reqp); + ISP_SYNC_REQUEST(isp); + if (msleep(resp, &isp->isp_lock, 0, "VP_CTRL", 5*hz) == EWOULDBLOCK) { + isp_prt(isp, ISP_LOGERR, + "%s: VP_CTRL of Chan %d timed out", __func__, chan); + isp_destroy_handle(isp, vp.vp_ctrl_handle); + return (EIO); + } + isp_get_vp_ctrl_info(isp, (vp_ctrl_info_t *)resp, &vp); - if (vp->vp_ctrl_status != 0) { + if (vp.vp_ctrl_hdr.rqs_flags != 0 || vp.vp_ctrl_status != 0) { isp_prt(isp, ISP_LOGERR, - "%s: VP_CTRL of Chan %d failed with status %d %d", - __func__, chan, vp->vp_ctrl_status, vp->vp_ctrl_index_fail); + "%s: VP_CTRL of Chan %d failed with flags %x status %d %d", + __func__, chan, vp.vp_ctrl_hdr.rqs_flags, + vp.vp_ctrl_status, vp.vp_ctrl_index_fail); return (EIO); } return (0); @@ -6123,6 +6125,8 @@ isp_handle_other_response(ispsoftc_t *isp, int type, isphdr_t *hp, uint32_t *opt { isp_ridacq_t rid; int chan, c; + uint32_t hdl; + void *ptr; switch (type) { case RQSTYPE_STATUS_CONT: @@ -6164,6 +6168,16 @@ isp_handle_other_response(ispsoftc_t *isp, int type, isphdr_t *hp, uint32_t *opt } } return (1); + case RQSTYPE_VP_MODIFY: + case RQSTYPE_VP_CTRL: + ISP_IOXGET_32(isp, (uint32_t *)(hp + 1), hdl); + ptr = isp_find_xs(isp, hdl); + if (ptr != NULL) { + isp_destroy_handle(isp, hdl); + memcpy(ptr, hp, QENTRY_LEN); + wakeup(ptr); + } + return (1); case RQSTYPE_ATIO: case RQSTYPE_CTIO: case RQSTYPE_ENABLE_LUN: diff --git a/sys/dev/isp/isp_library.c b/sys/dev/isp/isp_library.c index 76890dc..78c7f6f 100644 --- a/sys/dev/isp/isp_library.c +++ b/sys/dev/isp/isp_library.c @@ -572,7 +572,8 @@ isp_clear_commands(ispsoftc_t *isp) for (tmp = 0; isp->isp_xflist && tmp < isp->isp_maxcmds; tmp++) { hdp = &isp->isp_xflist[tmp]; - if (ISP_H2HT(hdp->handle) == ISP_HANDLE_INITIATOR) { + switch (ISP_H2HT(hdp->handle)) { + case ISP_HANDLE_INITIATOR: { XS_T *xs = hdp->cmd; if (XS_XFRLEN(xs)) { ISP_DMAFREE(isp, xs, hdp->handle); @@ -580,12 +581,13 @@ isp_clear_commands(ispsoftc_t *isp) } else { XS_SET_RESID(xs, 0); } - hdp->handle = 0; - hdp->cmd = NULL; + isp_destroy_handle(isp, hdp->handle); XS_SETERR(xs, HBA_BUSRESET); isp_done(xs); + break; + } #ifdef ISP_TARGET_MODE - } else if (ISP_H2HT(hdp->handle) == ISP_HANDLE_TARGET) { + case ISP_HANDLE_TARGET: { uint8_t local[QENTRY_LEN]; ISP_DMAFREE(isp, hdp->cmd, hdp->handle); ISP_MEMZERO(local, QENTRY_LEN); @@ -601,7 +603,13 @@ isp_clear_commands(ispsoftc_t *isp) ctio->ct_header.rqs_entry_type = RQSTYPE_CTIO2; } isp_async(isp, ISPASYNC_TARGET_ACTION, local); + break; + } #endif + case ISP_HANDLE_CTRL: + wakeup(hdp->cmd); + isp_destroy_handle(isp, hdp->handle); + break; } } #ifdef ISP_TARGET_MODE diff --git a/sys/dev/isp/ispvar.h b/sys/dev/isp/ispvar.h index ba285fb..f752254 100644 --- a/sys/dev/isp/ispvar.h +++ b/sys/dev/isp/ispvar.h @@ -315,12 +315,14 @@ typedef struct { # define ISP_HANDLE_NONE 0 # define ISP_HANDLE_INITIATOR 1 # define ISP_HANDLE_TARGET 2 +# define ISP_HANDLE_CTRL 3 #define ISP_HANDLE_SEQ_MASK 0xffff0000 #define ISP_HANDLE_SEQ_SHIFT 16 #define ISP_H2SEQ(hdl) ((hdl & ISP_HANDLE_SEQ_MASK) >> ISP_HANDLE_SEQ_SHIFT) #define ISP_VALID_HANDLE(c, hdl) \ ((ISP_H2HT(hdl) == ISP_HANDLE_INITIATOR || \ - ISP_H2HT(hdl) == ISP_HANDLE_TARGET) && \ + ISP_H2HT(hdl) == ISP_HANDLE_TARGET || \ + ISP_H2HT(hdl) == ISP_HANDLE_CTRL) && \ ((hdl) & ISP_HANDLE_CMD_MASK) < (c)->isp_maxcmds && \ (hdl) == ((c)->isp_xflist[(hdl) & ISP_HANDLE_CMD_MASK].handle)) #define ISP_BAD_HANDLE_INDEX 0xffffffff -- cgit v1.1 From 5f12b30bfc3ad667d7db2668014bbda968c1001c Mon Sep 17 00:00:00 2001 From: mav Date: Wed, 30 Dec 2015 11:51:35 +0000 Subject: MFC r292741: Make port logins asynchronous, following r292739 logic. This is even more important since it involves more network operations and more prone to delays and timeouts. --- sys/dev/isp/isp.c | 121 +++++++++++++++++++++++++----------------------------- 1 file changed, 55 insertions(+), 66 deletions(-) diff --git a/sys/dev/isp/isp.c b/sys/dev/isp/isp.c index b5385bc..95f0302 100644 --- a/sys/dev/isp/isp.c +++ b/sys/dev/isp/isp.c @@ -108,7 +108,7 @@ static void isp_fibre_init(ispsoftc_t *); static void isp_fibre_init_2400(ispsoftc_t *); static void isp_clear_portdb(ispsoftc_t *, int); static void isp_mark_portdb(ispsoftc_t *, int); -static int isp_plogx(ispsoftc_t *, int, uint16_t, uint32_t, int, int); +static int isp_plogx(ispsoftc_t *, int, uint16_t, uint32_t, int); static int isp_port_login(ispsoftc_t *, uint16_t, uint32_t); static int isp_port_logout(ispsoftc_t *, uint16_t, uint32_t); static int isp_getpdb(ispsoftc_t *, int, uint16_t, isp_pdb_t *, int); @@ -2550,13 +2550,11 @@ isp_mark_portdb(ispsoftc_t *isp, int chan) * or via FABRIC LOGIN/FABRIC LOGOUT for other cards. */ static int -isp_plogx(ispsoftc_t *isp, int chan, uint16_t handle, uint32_t portid, int flags, int gs) +isp_plogx(ispsoftc_t *isp, int chan, uint16_t handle, uint32_t portid, int flags) { - mbreg_t mbs; - uint8_t q[QENTRY_LEN]; - isp_plogx_t *plp; - fcparam *fcp; - uint8_t *scp; + isp_plogx_t pl; + void *reqp; + uint8_t resp[QENTRY_LEN]; uint32_t sst, parm1; int rval, lev; const char *msg; @@ -2576,64 +2574,58 @@ isp_plogx(ispsoftc_t *isp, int chan, uint16_t handle, uint32_t portid, int flags } } - ISP_MEMZERO(q, QENTRY_LEN); - plp = (isp_plogx_t *) q; - plp->plogx_header.rqs_entry_count = 1; - plp->plogx_header.rqs_entry_type = RQSTYPE_LOGIN; - plp->plogx_handle = 0xffffffff; - plp->plogx_nphdl = handle; - plp->plogx_vphdl = chan; - plp->plogx_portlo = portid; - plp->plogx_rspsz_porthi = (portid >> 16) & 0xff; - plp->plogx_flags = flags; + ISP_MEMZERO(&pl, sizeof(pl)); + pl.plogx_header.rqs_entry_count = 1; + pl.plogx_header.rqs_entry_type = RQSTYPE_LOGIN; + pl.plogx_nphdl = handle; + pl.plogx_vphdl = chan; + pl.plogx_portlo = portid; + pl.plogx_rspsz_porthi = (portid >> 16) & 0xff; + pl.plogx_flags = flags; - if (isp->isp_dblev & ISP_LOGDEBUG1) { - isp_print_bytes(isp, "IOCB LOGX", QENTRY_LEN, plp); - } - - if (gs == 0) { - if (FC_SCRATCH_ACQUIRE(isp, chan)) { - isp_prt(isp, ISP_LOGERR, sacq); - return (-1); - } + /* Prepare space for response in memory */ + memset(resp, 0xff, sizeof(resp)); + pl.plogx_handle = isp_allocate_handle(isp, resp, ISP_HANDLE_CTRL); + if (pl.plogx_handle == 0) { + isp_prt(isp, ISP_LOGERR, + "%s: PLOGX of Chan %d out of handles", __func__, chan); + return (-1); } - fcp = FCPARAM(isp, chan); - scp = fcp->isp_scratch; - isp_put_plogx(isp, plp, (isp_plogx_t *) scp); - MBSINIT(&mbs, MBOX_EXEC_COMMAND_IOCB_A64, MBLOGALL, - MBCMD_DEFAULT_TIMEOUT + ICB_LOGIN_TOV * 1000000); - mbs.param[1] = QENTRY_LEN; - mbs.param[2] = DMA_WD1(fcp->isp_scdma); - mbs.param[3] = DMA_WD0(fcp->isp_scdma); - mbs.param[6] = DMA_WD3(fcp->isp_scdma); - mbs.param[7] = DMA_WD2(fcp->isp_scdma); - MEMORYBARRIER(isp, SYNC_SFORDEV, 0, QENTRY_LEN, chan); - isp_mboxcmd(isp, &mbs); - if (mbs.param[0] != MBOX_COMMAND_COMPLETE) { - rval = mbs.param[0]; - goto out; + /* Send request and wait for response. */ + reqp = isp_getrqentry(isp); + if (reqp == NULL) { + isp_prt(isp, ISP_LOGERR, + "%s: PLOGX of Chan %d out of rqent", __func__, chan); + isp_destroy_handle(isp, pl.plogx_handle); + return (-1); } - MEMORYBARRIER(isp, SYNC_SFORCPU, QENTRY_LEN, QENTRY_LEN, chan); - scp += QENTRY_LEN; - isp_get_plogx(isp, (isp_plogx_t *) scp, plp); - if (isp->isp_dblev & ISP_LOGDEBUG1) { - isp_print_bytes(isp, "IOCB LOGX response", QENTRY_LEN, plp); + if (isp->isp_dblev & ISP_LOGDEBUG1) + isp_print_bytes(isp, "IOCB LOGX", QENTRY_LEN, &pl); + isp_put_plogx(isp, &pl, (isp_plogx_t *)reqp); + ISP_SYNC_REQUEST(isp); + if (msleep(resp, &isp->isp_lock, 0, "PLOGX", 3 * ICB_LOGIN_TOV * hz) + == EWOULDBLOCK) { + isp_prt(isp, ISP_LOGERR, + "%s: PLOGX of Chan %d timed out", __func__, chan); + isp_destroy_handle(isp, pl.plogx_handle); + return (-1); } + isp_get_plogx(isp, (isp_plogx_t *)resp, &pl); + if (isp->isp_dblev & ISP_LOGDEBUG1) + isp_print_bytes(isp, "IOCB LOGX response", QENTRY_LEN, &pl); - if (plp->plogx_status == PLOGX_STATUS_OK) { - rval = 0; - goto out; - } else if (plp->plogx_status != PLOGX_STATUS_IOCBERR) { + if (pl.plogx_status == PLOGX_STATUS_OK) { + return (0); + } else if (pl.plogx_status != PLOGX_STATUS_IOCBERR) { isp_prt(isp, ISP_LOGWARN, "status 0x%x on port login IOCB channel %d", - plp->plogx_status, chan); - rval = -1; - goto out; + pl.plogx_status, chan); + return (-1); } - sst = plp->plogx_ioparm[0].lo16 | (plp->plogx_ioparm[0].hi16 << 16); - parm1 = plp->plogx_ioparm[1].lo16 | (plp->plogx_ioparm[1].hi16 << 16); + sst = pl.plogx_ioparm[0].lo16 | (pl.plogx_ioparm[0].hi16 << 16); + parm1 = pl.plogx_ioparm[1].lo16 | (pl.plogx_ioparm[1].hi16 << 16); rval = -1; lev = ISP_LOGERR; @@ -2694,17 +2686,13 @@ isp_plogx(ispsoftc_t *isp, int chan, uint16_t handle, uint32_t portid, int flags msg = "no FLOGI_ACC"; break; default: - ISP_SNPRINTF(buf, sizeof (buf), "status %x from %x", plp->plogx_status, flags); + ISP_SNPRINTF(buf, sizeof (buf), "status %x from %x", pl.plogx_status, flags); msg = buf; break; } if (msg) { isp_prt(isp, ISP_LOGERR, "Chan %d PLOGX PortID 0x%06x to N-Port handle 0x%x: %s", chan, portid, handle, msg); } -out: - if (gs == 0) { - FC_SCRATCH_RELEASE(isp, chan); - } return (rval); } @@ -3196,7 +3184,7 @@ isp_pdb_sync(ispsoftc_t *isp, int chan) lp->portid, PLOGX_FLG_CMD_LOGO | PLOGX_FLG_IMPLICIT | - PLOGX_FLG_FREE_NPHDL, 0); + PLOGX_FLG_FREE_NPHDL); } /* * Note that we might come out of this with our state @@ -3883,7 +3871,7 @@ isp_login_device(ispsoftc_t *isp, int chan, uint32_t portid, isp_pdb_t *p, uint1 /* * Now try and log into the device */ - r = isp_plogx(isp, chan, handle, portid, PLOGX_FLG_CMD_PLOGI, 1); + r = isp_plogx(isp, chan, handle, portid, PLOGX_FLG_CMD_PLOGI); if (r == 0) { break; } else if ((r & 0xffff) == MBOX_PORT_ID_USED) { @@ -3892,12 +3880,12 @@ isp_login_device(ispsoftc_t *isp, int chan, uint32_t portid, isp_pdb_t *p, uint1 * handle. We need to break that association. We used to try and just substitute the handle, but then * failed to get any data via isp_getpdb (below). */ - if (isp_plogx(isp, chan, r >> 16, portid, PLOGX_FLG_CMD_LOGO | PLOGX_FLG_IMPLICIT | PLOGX_FLG_FREE_NPHDL, 1)) { + if (isp_plogx(isp, chan, r >> 16, portid, PLOGX_FLG_CMD_LOGO | PLOGX_FLG_IMPLICIT | PLOGX_FLG_FREE_NPHDL)) { isp_prt(isp, ISP_LOGERR, "baw... logout of %x failed", r >> 16); } if (FCPARAM(isp, chan)->isp_loopstate != LOOP_SCANNING_FABRIC) return (-1); - r = isp_plogx(isp, chan, handle, portid, PLOGX_FLG_CMD_PLOGI, 1); + r = isp_plogx(isp, chan, handle, portid, PLOGX_FLG_CMD_PLOGI); if (r != 0) i = lim; break; @@ -4937,11 +4925,11 @@ isp_control(ispsoftc_t *isp, ispctl_t ctl, ...) va_end(ap); if ((p->flags & PLOGX_FLG_CMD_MASK) != PLOGX_FLG_CMD_PLOGI || (p->handle != NIL_HANDLE)) { - return (isp_plogx(isp, p->channel, p->handle, p->portid, p->flags, 0)); + return (isp_plogx(isp, p->channel, p->handle, p->portid, p->flags)); } do { isp_next_handle(isp, &p->handle); - r = isp_plogx(isp, p->channel, p->handle, p->portid, p->flags, 0); + r = isp_plogx(isp, p->channel, p->handle, p->portid, p->flags); if ((r & 0xffff) == MBOX_PORT_ID_USED) { p->handle = r >> 16; r = 0; @@ -6170,6 +6158,7 @@ isp_handle_other_response(ispsoftc_t *isp, int type, isphdr_t *hp, uint32_t *opt return (1); case RQSTYPE_VP_MODIFY: case RQSTYPE_VP_CTRL: + case RQSTYPE_LOGIN: ISP_IOXGET_32(isp, (uint32_t *)(hp + 1), hdl); ptr = isp_find_xs(isp, hdl); if (ptr != NULL) { -- cgit v1.1 From 9380c877989caf1e4aed7015c88816f3cbfec737 Mon Sep 17 00:00:00 2001 From: mav Date: Wed, 30 Dec 2015 11:53:21 +0000 Subject: MFC r292745: Use single DMA tag for scratch areas of all virtual ports. --- sys/dev/isp/isp_freebsd.h | 14 +++++++------- sys/dev/isp/isp_pci.c | 46 +++++++++++++++++++++++++--------------------- 2 files changed, 32 insertions(+), 28 deletions(-) diff --git a/sys/dev/isp/isp_freebsd.h b/sys/dev/isp/isp_freebsd.h index 9a9093a..e4c2bd1 100644 --- a/sys/dev/isp/isp_freebsd.h +++ b/sys/dev/isp/isp_freebsd.h @@ -225,8 +225,7 @@ struct isp_fc { struct cam_path *path; struct ispsoftc *isp; struct proc *kproc; - bus_dma_tag_t tdmat; - bus_dmamap_t tdmap; + bus_dmamap_t scmap; uint64_t def_wwpn; uint64_t def_wwnn; time_t loop_down_time; @@ -285,13 +284,14 @@ struct isposinfo { const struct firmware * fw; /* - * DMA related sdtuff + * DMA related stuff */ struct resource * regs; struct resource * regs2; bus_dma_tag_t dmat; bus_dma_tag_t cdmat; bus_dmamap_t cdmap; + bus_dma_tag_t scdmat; /* * Command and transaction related related stuff @@ -409,7 +409,7 @@ switch (type) { \ case SYNC_SFORDEV: \ { \ struct isp_fc *fc = ISP_FC_PC(isp, chan); \ - bus_dmamap_sync(fc->tdmat, fc->tdmap, \ + bus_dmamap_sync(isp->isp_osinfo.scdmat, fc->scmap, \ BUS_DMASYNC_PREREAD | BUS_DMASYNC_PREWRITE); \ break; \ } \ @@ -421,7 +421,7 @@ case SYNC_REQUEST: \ case SYNC_SFORCPU: \ { \ struct isp_fc *fc = ISP_FC_PC(isp, chan); \ - bus_dmamap_sync(fc->tdmat, fc->tdmap, \ + bus_dmamap_sync(isp->isp_osinfo.scdmat, fc->scmap, \ BUS_DMASYNC_POSTREAD | BUS_DMASYNC_POSTWRITE); \ break; \ } \ @@ -443,7 +443,7 @@ switch (type) { \ case SYNC_SFORDEV: \ { \ struct isp_fc *fc = ISP_FC_PC(isp, chan); \ - bus_dmamap_sync(fc->tdmat, fc->tdmap, \ + bus_dmamap_sync(isp->isp_osinfo.scdmat, fc->scmap, \ BUS_DMASYNC_PREWRITE); \ break; \ } \ @@ -454,7 +454,7 @@ case SYNC_REQUEST: \ case SYNC_SFORCPU: \ { \ struct isp_fc *fc = ISP_FC_PC(isp, chan); \ - bus_dmamap_sync(fc->tdmat, fc->tdmap, \ + bus_dmamap_sync(isp->isp_osinfo.scdmat, fc->scmap, \ BUS_DMASYNC_POSTWRITE); \ break; \ } \ diff --git a/sys/dev/isp/isp_pci.c b/sys/dev/isp/isp_pci.c index 1701e81..9c9d7ea 100644 --- a/sys/dev/isp/isp_pci.c +++ b/sys/dev/isp/isp_pci.c @@ -1604,11 +1604,8 @@ imc1(void *arg, bus_dma_segment_t *segs, int nseg, int error) imushp->error = error; return; } - if (nseg != 1) { - imushp->error = EINVAL; - return; - } - isp_prt(imushp->isp, ISP_LOGDEBUG0, "scdma @ 0x%jx/0x%jx", (uintmax_t) segs->ds_addr, (uintmax_t) segs->ds_len); + isp_prt(imushp->isp, ISP_LOGDEBUG0, "scdma @ 0x%jx/0x%jx", + (uintmax_t) segs->ds_addr, (uintmax_t) segs->ds_len); FCPARAM(imushp->isp, imushp->chan)->isp_scdma = segs->ds_addr; FCPARAM(imushp->isp, imushp->chan)->isp_scratch = imushp->vbase; } @@ -1735,23 +1732,27 @@ isp_pci_mbxdma(ispsoftc_t *isp) } if (IS_FC(isp)) { + if (isp_dma_tag_create(isp->isp_osinfo.dmat, 64, slim, + BUS_SPACE_MAXADDR, BUS_SPACE_MAXADDR, NULL, NULL, + ISP_FC_SCRLEN, 1, ISP_FC_SCRLEN, 0, &isp->isp_osinfo.scdmat)) { + goto bad; + } for (cmap = 0; cmap < isp->isp_nchan; cmap++) { struct isp_fc *fc = ISP_FC_PC(isp, cmap); - if (isp_dma_tag_create(isp->isp_osinfo.dmat, 64, slim, BUS_SPACE_MAXADDR_32BIT, BUS_SPACE_MAXADDR, NULL, NULL, ISP_FC_SCRLEN, 1, slim, 0, &fc->tdmat)) { - goto bad; - } - if (bus_dmamem_alloc(fc->tdmat, (void **)&base, BUS_DMA_NOWAIT | BUS_DMA_COHERENT, &fc->tdmap) != 0) { - bus_dma_tag_destroy(fc->tdmat); + if (bus_dmamem_alloc(isp->isp_osinfo.scdmat, + (void **)&base, BUS_DMA_NOWAIT | BUS_DMA_COHERENT, + &fc->scmap) != 0) { goto bad; } im.isp = isp; im.chan = cmap; im.vbase = base; im.error = 0; - bus_dmamap_load(fc->tdmat, fc->tdmap, base, ISP_FC_SCRLEN, imc1, &im, 0); + bus_dmamap_load(isp->isp_osinfo.scdmat, fc->scmap, + base, ISP_FC_SCRLEN, imc1, &im, 0); if (im.error) { - bus_dmamem_free(fc->tdmat, base, fc->tdmap); - bus_dma_tag_destroy(fc->tdmat); + bus_dmamem_free(isp->isp_osinfo.scdmat, + base, fc->scmap); goto bad; } if (!IS_2100(isp)) { @@ -1794,15 +1795,18 @@ isp_pci_mbxdma(ispsoftc_t *isp) return (0); bad: - while (--cmap >= 0) { - struct isp_fc *fc = ISP_FC_PC(isp, cmap); - bus_dmamem_free(fc->tdmat, base, fc->tdmap); - bus_dma_tag_destroy(fc->tdmat); - while (fc->nexus_free_list) { - struct isp_nexus *n = fc->nexus_free_list; - fc->nexus_free_list = n->next; - free(n, M_DEVBUF); + if (IS_FC(isp)) { + while (--cmap >= 0) { + struct isp_fc *fc = ISP_FC_PC(isp, cmap); + bus_dmamap_unload(isp->isp_osinfo.scdmat, fc->scmap); + bus_dmamem_free(isp->isp_osinfo.scdmat, base, fc->scmap); + while (fc->nexus_free_list) { + struct isp_nexus *n = fc->nexus_free_list; + fc->nexus_free_list = n->next; + free(n, M_DEVBUF); + } } + bus_dma_tag_destroy(isp->isp_osinfo.scdmat); } bus_dmamem_free(isp->isp_osinfo.cdmat, base, isp->isp_osinfo.cdmap); bus_dma_tag_destroy(isp->isp_osinfo.cdmat); -- cgit v1.1 From c5a9a1606d1050511a94dd3142301b48f9e55ed6 Mon Sep 17 00:00:00 2001 From: mav Date: Wed, 30 Dec 2015 11:54:37 +0000 Subject: MFC r292764: Split DMA buffers for request, response and ATIO queues. --- sys/dev/isp/isp_freebsd.h | 42 ++++---- sys/dev/isp/isp_pci.c | 240 +++++++++++++++++++++++++--------------------- sys/dev/isp/isp_sbus.c | 120 +++++++++++++---------- 3 files changed, 222 insertions(+), 180 deletions(-) diff --git a/sys/dev/isp/isp_freebsd.h b/sys/dev/isp/isp_freebsd.h index e4c2bd1..7702ee6 100644 --- a/sys/dev/isp/isp_freebsd.h +++ b/sys/dev/isp/isp_freebsd.h @@ -289,9 +289,13 @@ struct isposinfo { struct resource * regs; struct resource * regs2; bus_dma_tag_t dmat; - bus_dma_tag_t cdmat; - bus_dmamap_t cdmap; + bus_dma_tag_t reqdmat; + bus_dma_tag_t respdmat; + bus_dma_tag_t atiodmat; bus_dma_tag_t scdmat; + bus_dmamap_t reqmap; + bus_dmamap_t respmap; + bus_dmamap_t atiomap; /* * Command and transaction related related stuff @@ -406,6 +410,14 @@ struct isposinfo { #define MEMORYBARRIER(isp, type, offset, size, chan) \ switch (type) { \ +case SYNC_REQUEST: \ + bus_dmamap_sync(isp->isp_osinfo.reqdmat, \ + isp->isp_osinfo.reqmap, BUS_DMASYNC_PREWRITE); \ + break; \ +case SYNC_RESULT: \ + bus_dmamap_sync(isp->isp_osinfo.respdmat, \ + isp->isp_osinfo.respmap, BUS_DMASYNC_POSTREAD); \ + break; \ case SYNC_SFORDEV: \ { \ struct isp_fc *fc = ISP_FC_PC(isp, chan); \ @@ -413,11 +425,6 @@ case SYNC_SFORDEV: \ BUS_DMASYNC_PREREAD | BUS_DMASYNC_PREWRITE); \ break; \ } \ -case SYNC_REQUEST: \ - bus_dmamap_sync(isp->isp_osinfo.cdmat, \ - isp->isp_osinfo.cdmap, \ - BUS_DMASYNC_PREREAD | BUS_DMASYNC_PREWRITE); \ - break; \ case SYNC_SFORCPU: \ { \ struct isp_fc *fc = ISP_FC_PC(isp, chan); \ @@ -425,21 +432,24 @@ case SYNC_SFORCPU: \ BUS_DMASYNC_POSTREAD | BUS_DMASYNC_POSTWRITE); \ break; \ } \ -case SYNC_RESULT: \ - bus_dmamap_sync(isp->isp_osinfo.cdmat, \ - isp->isp_osinfo.cdmap, \ - BUS_DMASYNC_POSTREAD | BUS_DMASYNC_POSTWRITE); \ - break; \ case SYNC_REG: \ bus_barrier(isp->isp_osinfo.regs, offset, size, \ BUS_SPACE_BARRIER_READ | BUS_SPACE_BARRIER_WRITE); \ break; \ +case SYNC_ATIOQ: \ + bus_dmamap_sync(isp->isp_osinfo.atiodmat, \ + isp->isp_osinfo.atiomap, BUS_DMASYNC_POSTREAD); \ + break; \ default: \ break; \ } #define MEMORYBARRIERW(isp, type, offset, size, chan) \ switch (type) { \ +case SYNC_REQUEST: \ + bus_dmamap_sync(isp->isp_osinfo.reqdmat, \ + isp->isp_osinfo.reqmap, BUS_DMASYNC_PREWRITE); \ + break; \ case SYNC_SFORDEV: \ { \ struct isp_fc *fc = ISP_FC_PC(isp, chan); \ @@ -447,10 +457,6 @@ case SYNC_SFORDEV: \ BUS_DMASYNC_PREWRITE); \ break; \ } \ -case SYNC_REQUEST: \ - bus_dmamap_sync(isp->isp_osinfo.cdmat, \ - isp->isp_osinfo.cdmap, BUS_DMASYNC_PREWRITE); \ - break; \ case SYNC_SFORCPU: \ { \ struct isp_fc *fc = ISP_FC_PC(isp, chan); \ @@ -458,10 +464,6 @@ case SYNC_SFORCPU: \ BUS_DMASYNC_POSTWRITE); \ break; \ } \ -case SYNC_RESULT: \ - bus_dmamap_sync(isp->isp_osinfo.cdmat, \ - isp->isp_osinfo.cdmap, BUS_DMASYNC_POSTWRITE); \ - break; \ case SYNC_REG: \ bus_barrier(isp->isp_osinfo.regs, offset, size, \ BUS_SPACE_BARRIER_WRITE); \ diff --git a/sys/dev/isp/isp_pci.c b/sys/dev/isp/isp_pci.c index 9c9d7ea..11386ee 100644 --- a/sys/dev/isp/isp_pci.c +++ b/sys/dev/isp/isp_pci.c @@ -1539,75 +1539,17 @@ isp_pci_wr_reg_2600(ispsoftc_t *isp, int regoff, uint32_t val) struct imush { - ispsoftc_t *isp; - caddr_t vbase; - int chan; + bus_addr_t maddr; int error; }; -static void imc(void *, bus_dma_segment_t *, int, int); -static void imc1(void *, bus_dma_segment_t *, int, int); - static void imc(void *arg, bus_dma_segment_t *segs, int nseg, int error) { struct imush *imushp = (struct imush *) arg; - isp_ecmd_t *ecmd; - if (error) { - imushp->error = error; - return; - } - if (nseg != 1) { - imushp->error = EINVAL; - return; - } - isp_prt(imushp->isp, ISP_LOGDEBUG0, "request/result area @ 0x%jx/0x%jx", (uintmax_t) segs->ds_addr, (uintmax_t) segs->ds_len); - - imushp->isp->isp_rquest = imushp->vbase; - imushp->isp->isp_rquest_dma = segs->ds_addr; - segs->ds_addr += ISP_QUEUE_SIZE(RQUEST_QUEUE_LEN(imushp->isp)); - imushp->vbase += ISP_QUEUE_SIZE(RQUEST_QUEUE_LEN(imushp->isp)); - - imushp->isp->isp_result_dma = segs->ds_addr; - imushp->isp->isp_result = imushp->vbase; - segs->ds_addr += ISP_QUEUE_SIZE(RESULT_QUEUE_LEN(imushp->isp)); - imushp->vbase += ISP_QUEUE_SIZE(RESULT_QUEUE_LEN(imushp->isp)); - - if (imushp->isp->isp_type >= ISP_HA_FC_2200) { - imushp->isp->isp_osinfo.ecmd_dma = segs->ds_addr; - imushp->isp->isp_osinfo.ecmd_free = (isp_ecmd_t *)imushp->vbase; - imushp->isp->isp_osinfo.ecmd_base = imushp->isp->isp_osinfo.ecmd_free; - for (ecmd = imushp->isp->isp_osinfo.ecmd_free; ecmd < &imushp->isp->isp_osinfo.ecmd_free[N_XCMDS]; ecmd++) { - if (ecmd == &imushp->isp->isp_osinfo.ecmd_free[N_XCMDS - 1]) { - ecmd->next = NULL; - } else { - ecmd->next = ecmd + 1; - } - } - } -#ifdef ISP_TARGET_MODE - segs->ds_addr += (N_XCMDS * XCMD_SIZE); - imushp->vbase += (N_XCMDS * XCMD_SIZE); - if (IS_24XX(imushp->isp)) { - imushp->isp->isp_atioq_dma = segs->ds_addr; - imushp->isp->isp_atioq = imushp->vbase; - } -#endif -} - -static void -imc1(void *arg, bus_dma_segment_t *segs, int nseg, int error) -{ - struct imush *imushp = (struct imush *) arg; - if (error) { - imushp->error = error; - return; - } - isp_prt(imushp->isp, ISP_LOGDEBUG0, "scdma @ 0x%jx/0x%jx", - (uintmax_t) segs->ds_addr, (uintmax_t) segs->ds_len); - FCPARAM(imushp->isp, imushp->chan)->isp_scdma = segs->ds_addr; - FCPARAM(imushp->isp, imushp->chan)->isp_scratch = imushp->vbase; + if (!(imushp->error = error)) + imushp->maddr = segs[0].ds_addr; } static int @@ -1620,6 +1562,7 @@ isp_pci_mbxdma(ispsoftc_t *isp) bus_addr_t llim; /* low limit of unavailable dma */ bus_addr_t hlim; /* high limit of unavailable dma */ struct imush im; + isp_ecmd_t *ecmd; /* * Already been here? If so, leave... @@ -1683,53 +1626,106 @@ isp_pci_mbxdma(ispsoftc_t *isp) isp->isp_xffree = isp->isp_xflist; /* - * Allocate and map the request and result queues (and ATIO queue - * if we're a 2400 supporting target mode), and a region for - * external dma addressable command/status structures (23XX and - * later). + * Allocate and map the request queue and a region for external + * DMA addressable command/status structures (22XX and later). */ len = ISP_QUEUE_SIZE(RQUEST_QUEUE_LEN(isp)); - len += ISP_QUEUE_SIZE(RESULT_QUEUE_LEN(isp)); -#ifdef ISP_TARGET_MODE - if (IS_24XX(isp)) { - len += ISP_QUEUE_SIZE(RESULT_QUEUE_LEN(isp)); - } -#endif - if (isp->isp_type >= ISP_HA_FC_2200) { + if (isp->isp_type >= ISP_HA_FC_2200) len += (N_XCMDS * XCMD_SIZE); + if (isp_dma_tag_create(isp->isp_osinfo.dmat, QENTRY_LEN, slim, + BUS_SPACE_MAXADDR_32BIT, BUS_SPACE_MAXADDR, NULL, NULL, + len, 1, len, 0, &isp->isp_osinfo.reqdmat)) { + isp_prt(isp, ISP_LOGERR, "cannot create request DMA tag"); + goto bad1; + } + if (bus_dmamem_alloc(isp->isp_osinfo.reqdmat, (void **)&base, + BUS_DMA_COHERENT, &isp->isp_osinfo.reqmap) != 0) { + isp_prt(isp, ISP_LOGERR, "cannot allocate request DMA memory"); + bus_dma_tag_destroy(isp->isp_osinfo.reqdmat); + goto bad1; + } + isp->isp_rquest = base; + im.error = 0; + if (bus_dmamap_load(isp->isp_osinfo.reqdmat, isp->isp_osinfo.reqmap, + base, len, imc, &im, 0) || im.error) { + isp_prt(isp, ISP_LOGERR, "error loading request DMA map %d", im.error); + goto bad1; + } + isp_prt(isp, ISP_LOGDEBUG0, "request area @ 0x%jx/0x%jx", + (uintmax_t)im.maddr, (uintmax_t)len); + isp->isp_rquest_dma = im.maddr; + base += ISP_QUEUE_SIZE(RQUEST_QUEUE_LEN(isp)); + im.maddr += ISP_QUEUE_SIZE(RQUEST_QUEUE_LEN(isp)); + if (isp->isp_type >= ISP_HA_FC_2200) { + isp->isp_osinfo.ecmd_dma = im.maddr; + isp->isp_osinfo.ecmd_free = (isp_ecmd_t *)base; + isp->isp_osinfo.ecmd_base = isp->isp_osinfo.ecmd_free; + for (ecmd = isp->isp_osinfo.ecmd_free; + ecmd < &isp->isp_osinfo.ecmd_free[N_XCMDS]; ecmd++) { + if (ecmd == &isp->isp_osinfo.ecmd_free[N_XCMDS - 1]) + ecmd->next = NULL; + else + ecmd->next = ecmd + 1; + } } /* - * Create a tag for the control spaces. We don't always need this - * to be 32 bits, but we do this for simplicity and speed's sake. + * Allocate and map the result queue. */ - if (isp_dma_tag_create(isp->isp_osinfo.dmat, QENTRY_LEN, slim, BUS_SPACE_MAXADDR_32BIT, BUS_SPACE_MAXADDR, NULL, NULL, len, 1, slim, 0, &isp->isp_osinfo.cdmat)) { - isp_prt(isp, ISP_LOGERR, "cannot create a dma tag for control spaces"); - free(isp->isp_osinfo.pcmd_pool, M_DEVBUF); - free(isp->isp_xflist, M_DEVBUF); - ISP_LOCK(isp); - return (1); - } - - if (bus_dmamem_alloc(isp->isp_osinfo.cdmat, (void **)&base, BUS_DMA_NOWAIT | BUS_DMA_COHERENT, &isp->isp_osinfo.cdmap) != 0) { - isp_prt(isp, ISP_LOGERR, "cannot allocate %d bytes of CCB memory", len); - bus_dma_tag_destroy(isp->isp_osinfo.cdmat); - free(isp->isp_osinfo.pcmd_pool, M_DEVBUF); - free(isp->isp_xflist, M_DEVBUF); - ISP_LOCK(isp); - return (1); - } - - im.isp = isp; - im.chan = 0; - im.vbase = base; + len = ISP_QUEUE_SIZE(RESULT_QUEUE_LEN(isp)); + if (isp_dma_tag_create(isp->isp_osinfo.dmat, QENTRY_LEN, slim, + BUS_SPACE_MAXADDR_32BIT, BUS_SPACE_MAXADDR, NULL, NULL, + len, 1, len, 0, &isp->isp_osinfo.respdmat)) { + isp_prt(isp, ISP_LOGERR, "cannot create response DMA tag"); + goto bad1; + } + if (bus_dmamem_alloc(isp->isp_osinfo.respdmat, (void **)&base, + BUS_DMA_COHERENT, &isp->isp_osinfo.respmap) != 0) { + isp_prt(isp, ISP_LOGERR, "cannot allocate response DMA memory"); + bus_dma_tag_destroy(isp->isp_osinfo.respdmat); + goto bad1; + } + isp->isp_result = base; im.error = 0; + if (bus_dmamap_load(isp->isp_osinfo.respdmat, isp->isp_osinfo.respmap, + base, len, imc, &im, 0) || im.error) { + isp_prt(isp, ISP_LOGERR, "error loading response DMA map %d", im.error); + goto bad1; + } + isp_prt(isp, ISP_LOGDEBUG0, "response area @ 0x%jx/0x%jx", + (uintmax_t)im.maddr, (uintmax_t)len); + isp->isp_result_dma = im.maddr; - bus_dmamap_load(isp->isp_osinfo.cdmat, isp->isp_osinfo.cdmap, base, len, imc, &im, 0); - if (im.error) { - isp_prt(isp, ISP_LOGERR, "error %d loading dma map for control areas", im.error); - goto bad; +#ifdef ISP_TARGET_MODE + /* + * Allocate and map ATIO queue on 24xx with target mode. + */ + if (IS_24XX(isp)) { + len = ISP_QUEUE_SIZE(RESULT_QUEUE_LEN(isp)); + if (isp_dma_tag_create(isp->isp_osinfo.dmat, QENTRY_LEN, slim, + BUS_SPACE_MAXADDR_32BIT, BUS_SPACE_MAXADDR, NULL, NULL, + len, 1, len, 0, &isp->isp_osinfo.atiodmat)) { + isp_prt(isp, ISP_LOGERR, "cannot create ATIO DMA tag"); + goto bad1; + } + if (bus_dmamem_alloc(isp->isp_osinfo.atiodmat, (void **)&base, + BUS_DMA_COHERENT, &isp->isp_osinfo.atiomap) != 0) { + isp_prt(isp, ISP_LOGERR, "cannot allocate ATIO DMA memory"); + bus_dma_tag_destroy(isp->isp_osinfo.atiodmat); + goto bad1; + } + isp->isp_atioq = base; + im.error = 0; + if (bus_dmamap_load(isp->isp_osinfo.atiodmat, isp->isp_osinfo.atiomap, + base, len, imc, &im, 0) || im.error) { + isp_prt(isp, ISP_LOGERR, "error loading ATIO DMA map %d", im.error); + goto bad; + } + isp_prt(isp, ISP_LOGDEBUG0, "ATIO area @ 0x%jx/0x%jx", + (uintmax_t)im.maddr, (uintmax_t)len); + isp->isp_atioq_dma = im.maddr; } +#endif if (IS_FC(isp)) { if (isp_dma_tag_create(isp->isp_osinfo.dmat, 64, slim, @@ -1740,21 +1736,17 @@ isp_pci_mbxdma(ispsoftc_t *isp) for (cmap = 0; cmap < isp->isp_nchan; cmap++) { struct isp_fc *fc = ISP_FC_PC(isp, cmap); if (bus_dmamem_alloc(isp->isp_osinfo.scdmat, - (void **)&base, BUS_DMA_NOWAIT | BUS_DMA_COHERENT, - &fc->scmap) != 0) { + (void **)&base, BUS_DMA_COHERENT, &fc->scmap) != 0) goto bad; - } - im.isp = isp; - im.chan = cmap; - im.vbase = base; + FCPARAM(isp, cmap)->isp_scratch = base; im.error = 0; - bus_dmamap_load(isp->isp_osinfo.scdmat, fc->scmap, - base, ISP_FC_SCRLEN, imc1, &im, 0); - if (im.error) { + if (bus_dmamap_load(isp->isp_osinfo.scdmat, fc->scmap, + base, ISP_FC_SCRLEN, imc, &im, 0) || im.error) { bus_dmamem_free(isp->isp_osinfo.scdmat, base, fc->scmap); goto bad; } + FCPARAM(isp, cmap)->isp_scdma = im.maddr; if (!IS_2100(isp)) { for (i = 0; i < INITIAL_NEXUS_COUNT; i++) { struct isp_nexus *n = malloc(sizeof (struct isp_nexus), M_DEVBUF, M_NOWAIT | M_ZERO); @@ -1808,8 +1800,38 @@ bad: } bus_dma_tag_destroy(isp->isp_osinfo.scdmat); } - bus_dmamem_free(isp->isp_osinfo.cdmat, base, isp->isp_osinfo.cdmap); - bus_dma_tag_destroy(isp->isp_osinfo.cdmat); +bad1: + if (isp->isp_rquest_dma != 0) { + bus_dmamap_unload(isp->isp_osinfo.reqdmat, + isp->isp_osinfo.reqmap); + } + if (isp->isp_rquest != NULL) { + bus_dmamem_free(isp->isp_osinfo.reqdmat, isp->isp_rquest, + isp->isp_osinfo.reqmap); + bus_dma_tag_destroy(isp->isp_osinfo.reqdmat); + } + if (isp->isp_result_dma != 0) { + bus_dmamap_unload(isp->isp_osinfo.respdmat, + isp->isp_osinfo.respmap); + } + if (isp->isp_result != NULL) { + bus_dmamem_free(isp->isp_osinfo.respdmat, isp->isp_result, + isp->isp_osinfo.respmap); + bus_dma_tag_destroy(isp->isp_osinfo.respdmat); + } +#ifdef ISP_TARGET_MODE + if (IS_24XX(isp)) { + if (isp->isp_atioq_dma != 0) { + bus_dmamap_unload(isp->isp_osinfo.atiodmat, + isp->isp_osinfo.atiomap); + } + if (isp->isp_atioq != NULL) { + bus_dmamem_free(isp->isp_osinfo.reqdmat, isp->isp_atioq, + isp->isp_osinfo.atiomap); + bus_dma_tag_destroy(isp->isp_osinfo.atiodmat); + } + } +#endif free(isp->isp_xflist, M_DEVBUF); free(isp->isp_osinfo.pcmd_pool, M_DEVBUF); isp->isp_rquest = NULL; diff --git a/sys/dev/isp/isp_sbus.c b/sys/dev/isp/isp_sbus.c index 2abfc64..f1ca83c 100644 --- a/sys/dev/isp/isp_sbus.c +++ b/sys/dev/isp/isp_sbus.c @@ -413,7 +413,7 @@ isp_sbus_wr_reg(ispsoftc_t *isp, int regoff, uint32_t val) } struct imush { - ispsoftc_t *isp; + bus_addr_t maddr; int error; }; @@ -423,16 +423,9 @@ static void imc(void *arg, bus_dma_segment_t *segs, int nseg, int error) { struct imush *imushp = (struct imush *) arg; - if (error) { - imushp->error = error; - } else { - ispsoftc_t *isp =imushp->isp; - bus_addr_t addr = segs->ds_addr; - isp->isp_rquest_dma = addr; - addr += ISP_QUEUE_SIZE(RQUEST_QUEUE_LEN(isp)); - isp->isp_result_dma = addr; - } + if (!(imushp->error = error)) + imushp->maddr = segs[0].ds_addr; } static int @@ -479,40 +472,62 @@ isp_sbus_mbxdma(ispsoftc_t *isp) BUS_SPACE_MAXADDR_32BIT, NULL, NULL, BUS_SPACE_MAXSIZE_32BIT, ISP_NSEG_MAX, BUS_SPACE_MAXADDR_24BIT, 0, &isp->isp_osinfo.dmat)) { isp_prt(isp, ISP_LOGERR, "could not create master dma tag"); - free(isp->isp_osinfo.pcmd_pool, M_DEVBUF); - free(isp->isp_xflist, M_DEVBUF); - ISP_LOCK(isp); - return(1); + goto bad; } /* - * Allocate and map the request, result queues, plus FC scratch area. + * Allocate and map the request queue. */ len = ISP_QUEUE_SIZE(RQUEST_QUEUE_LEN(isp)); - len += ISP_QUEUE_SIZE(RESULT_QUEUE_LEN(isp)); - - if (isp_dma_tag_create(isp->isp_osinfo.dmat, QENTRY_LEN, - BUS_SPACE_MAXADDR_24BIT+1, BUS_SPACE_MAXADDR_32BIT, - BUS_SPACE_MAXADDR_32BIT, NULL, NULL, len, 1, - BUS_SPACE_MAXADDR_24BIT, 0, &isp->isp_osinfo.cdmat)) { - isp_prt(isp, ISP_LOGERR, - "cannot create a dma tag for control spaces"); - free(isp->isp_osinfo.pcmd_pool, M_DEVBUF); - free(isp->isp_xflist, M_DEVBUF); - ISP_LOCK(isp); - return (1); + if (isp_dma_tag_create(isp->isp_osinfo.dmat, QENTRY_LEN, BUS_SPACE_MAXADDR_24BIT+1, + BUS_SPACE_MAXADDR_32BIT, BUS_SPACE_MAXADDR, NULL, NULL, + len, 1, len, 0, &isp->isp_osinfo.reqdmat)) { + isp_prt(isp, ISP_LOGERR, "cannot create request DMA tag"); + goto bad; + } + if (bus_dmamem_alloc(isp->isp_osinfo.reqdmat, (void **)&base, + BUS_DMA_COHERENT, &isp->isp_osinfo.reqmap) != 0) { + isp_prt(isp, ISP_LOGERR, "cannot allocate request DMA memory"); + bus_dma_tag_destroy(isp->isp_osinfo.reqdmat); + goto bad; + } + im.error = 0; + if (bus_dmamap_load(isp->isp_osinfo.reqdmat, isp->isp_osinfo.reqmap, + base, len, imc, &im, 0) || im.error) { + isp_prt(isp, ISP_LOGERR, "error loading request DMA map %d", im.error); + goto bad; } + isp_prt(isp, ISP_LOGDEBUG0, "request area @ 0x%jx/0x%jx", + (uintmax_t)im.maddr, (uintmax_t)len); + isp->isp_rquest = base; + isp->isp_rquest_dma = im.maddr; - if (bus_dmamem_alloc(isp->isp_osinfo.cdmat, (void **)&base, BUS_DMA_NOWAIT | BUS_DMA_COHERENT, - &isp->isp_osinfo.cdmap) != 0) { - isp_prt(isp, ISP_LOGERR, - "cannot allocate %d bytes of CCB memory", len); - bus_dma_tag_destroy(isp->isp_osinfo.cdmat); - free(isp->isp_osinfo.pcmd_pool, M_DEVBUF); - free(isp->isp_xflist, M_DEVBUF); - ISP_LOCK(isp); - return (1); + /* + * Allocate and map the result queue. + */ + len = ISP_QUEUE_SIZE(RESULT_QUEUE_LEN(isp)); + if (isp_dma_tag_create(isp->isp_osinfo.dmat, QENTRY_LEN, BUS_SPACE_MAXADDR_24BIT+1, + BUS_SPACE_MAXADDR_32BIT, BUS_SPACE_MAXADDR, NULL, NULL, + len, 1, len, 0, &isp->isp_osinfo.respdmat)) { + isp_prt(isp, ISP_LOGERR, "cannot create response DMA tag"); + goto bad; } + if (bus_dmamem_alloc(isp->isp_osinfo.respdmat, (void **)&base, + BUS_DMA_COHERENT, &isp->isp_osinfo.respmap) != 0) { + isp_prt(isp, ISP_LOGERR, "cannot allocate response DMA memory"); + bus_dma_tag_destroy(isp->isp_osinfo.respdmat); + goto bad; + } + im.error = 0; + if (bus_dmamap_load(isp->isp_osinfo.respdmat, isp->isp_osinfo.respmap, + base, len, imc, &im, 0) || im.error) { + isp_prt(isp, ISP_LOGERR, "error loading response DMA map %d", im.error); + goto bad; + } + isp_prt(isp, ISP_LOGDEBUG0, "response area @ 0x%jx/0x%jx", + (uintmax_t)im.maddr, (uintmax_t)len); + isp->isp_result = base; + isp->isp_result_dma = im.maddr; for (i = 0; i < isp->isp_maxcmds; i++) { struct isp_pcmd *pcmd = &isp->isp_osinfo.pcmd_pool[i]; @@ -534,25 +549,28 @@ isp_sbus_mbxdma(ispsoftc_t *isp) } } isp->isp_osinfo.pcmd_free = &isp->isp_osinfo.pcmd_pool[0]; - - im.isp = isp; - im.error = 0; - bus_dmamap_load(isp->isp_osinfo.cdmat, isp->isp_osinfo.cdmap, base, len, imc, &im, 0); - if (im.error) { - isp_prt(isp, ISP_LOGERR, - "error %d loading dma map for control areas", im.error); - goto bad; - } - - isp->isp_rquest = base; - base += ISP_QUEUE_SIZE(RQUEST_QUEUE_LEN(isp)); - isp->isp_result = base; ISP_LOCK(isp); return (0); bad: - bus_dmamem_free(isp->isp_osinfo.cdmat, base, isp->isp_osinfo.cdmap); - bus_dma_tag_destroy(isp->isp_osinfo.cdmat); + if (isp->isp_rquest_dma != 0) { + bus_dmamap_unload(isp->isp_osinfo.reqdmat, + isp->isp_osinfo.reqmap); + } + if (isp->isp_rquest != NULL) { + bus_dmamem_free(isp->isp_osinfo.reqdmat, isp->isp_rquest, + isp->isp_osinfo.reqmap); + bus_dma_tag_destroy(isp->isp_osinfo.reqdmat); + } + if (isp->isp_result_dma != 0) { + bus_dmamap_unload(isp->isp_osinfo.respdmat, + isp->isp_osinfo.respmap); + } + if (isp->isp_result != NULL) { + bus_dmamem_free(isp->isp_osinfo.respdmat, isp->isp_result, + isp->isp_osinfo.respmap); + bus_dma_tag_destroy(isp->isp_osinfo.respdmat); + } free(isp->isp_xflist, M_DEVBUF); free(isp->isp_osinfo.pcmd_pool, M_DEVBUF); isp->isp_rquest = NULL; -- cgit v1.1 From 94016106c52f332b53a31b4dc66d1007814ab1a6 Mon Sep 17 00:00:00 2001 From: mav Date: Wed, 30 Dec 2015 11:55:19 +0000 Subject: MFC r292765: Allocate separate scratch space for scanner purposes. This space does not require DMA syncing. It reduces lock scope of the DMA scratch space. It allows whole DMA scratch space to be used to I/O, so now we can fetch up to ~1000 ports from SNS. Due to the last fact, increase maximal number of ports from 256 to 1024. --- sys/dev/isp/isp.c | 205 +++++++++++++++++++++++---------------------------- sys/dev/isp/ispvar.h | 4 +- 2 files changed, 95 insertions(+), 114 deletions(-) diff --git a/sys/dev/isp/isp.c b/sys/dev/isp/isp.c index 95f0302..d5c393b 100644 --- a/sys/dev/isp/isp.c +++ b/sys/dev/isp/isp.c @@ -111,9 +111,9 @@ static void isp_mark_portdb(ispsoftc_t *, int); static int isp_plogx(ispsoftc_t *, int, uint16_t, uint32_t, int); static int isp_port_login(ispsoftc_t *, uint16_t, uint32_t); static int isp_port_logout(ispsoftc_t *, uint16_t, uint32_t); -static int isp_getpdb(ispsoftc_t *, int, uint16_t, isp_pdb_t *, int); -static int isp_gethandles(ispsoftc_t *, int, uint16_t *, int *, int, int); -static void isp_dump_chip_portdb(ispsoftc_t *, int, int); +static int isp_getpdb(ispsoftc_t *, int, uint16_t, isp_pdb_t *); +static int isp_gethandles(ispsoftc_t *, int, uint16_t *, int *, int); +static void isp_dump_chip_portdb(ispsoftc_t *, int); static uint64_t isp_get_wwn(ispsoftc_t *, int, int, int); static int isp_fclink_test(ispsoftc_t *, int, int); static int isp_pdb_sync(ispsoftc_t *, int); @@ -2762,7 +2762,7 @@ isp_port_logout(ispsoftc_t *isp, uint16_t handle, uint32_t portid) } static int -isp_getpdb(ispsoftc_t *isp, int chan, uint16_t id, isp_pdb_t *pdb, int dolock) +isp_getpdb(ispsoftc_t *isp, int chan, uint16_t id, isp_pdb_t *pdb) { fcparam *fcp = FCPARAM(isp, chan); mbreg_t mbs; @@ -2786,18 +2786,14 @@ isp_getpdb(ispsoftc_t *isp, int chan, uint16_t id, isp_pdb_t *pdb, int dolock) mbs.param[3] = DMA_WD0(fcp->isp_scdma); mbs.param[6] = DMA_WD3(fcp->isp_scdma); mbs.param[7] = DMA_WD2(fcp->isp_scdma); - if (dolock) { - if (FC_SCRATCH_ACQUIRE(isp, chan)) { - isp_prt(isp, ISP_LOGERR, sacq); - return (-1); - } + if (FC_SCRATCH_ACQUIRE(isp, chan)) { + isp_prt(isp, ISP_LOGERR, sacq); + return (-1); } MEMORYBARRIER(isp, SYNC_SFORDEV, 0, sizeof (un), chan); isp_mboxcmd(isp, &mbs); if (mbs.param[0] != MBOX_COMMAND_COMPLETE) { - if (dolock) { - FC_SCRATCH_RELEASE(isp, chan); - } + FC_SCRATCH_RELEASE(isp, chan); return (mbs.param[0] | (mbs.param[1] << 16)); } if (IS_24XX(isp)) { @@ -2813,9 +2809,7 @@ isp_getpdb(ispsoftc_t *isp, int chan, uint16_t id, isp_pdb_t *pdb, int dolock) un.bill.pdb_curstate); if (un.bill.pdb_curstate < PDB2400_STATE_PLOGI_DONE || un.bill.pdb_curstate > PDB2400_STATE_LOGGED_IN) { mbs.param[0] = MBOX_NOT_LOGGED_IN; - if (dolock) { - FC_SCRATCH_RELEASE(isp, chan); - } + FC_SCRATCH_RELEASE(isp, chan); return (mbs.param[0]); } } else { @@ -2828,15 +2822,12 @@ isp_getpdb(ispsoftc_t *isp, int chan, uint16_t id, isp_pdb_t *pdb, int dolock) isp_prt(isp, ISP_LOGDEBUG1, "Chan %d handle 0x%x Port 0x%06x", chan, id, pdb->portid); } - if (dolock) { - FC_SCRATCH_RELEASE(isp, chan); - } + FC_SCRATCH_RELEASE(isp, chan); return (0); } static int -isp_gethandles(ispsoftc_t *isp, int chan, uint16_t *handles, int *num, - int dolock, int loop) +isp_gethandles(ispsoftc_t *isp, int chan, uint16_t *handles, int *num, int loop) { fcparam *fcp = FCPARAM(isp, chan); mbreg_t mbs; @@ -2862,18 +2853,14 @@ isp_gethandles(ispsoftc_t *isp, int chan, uint16_t *handles, int *num, mbs.param[3] = DMA_WD3(fcp->isp_scdma); mbs.param[6] = DMA_WD2(fcp->isp_scdma); } - if (dolock) { - if (FC_SCRATCH_ACQUIRE(isp, chan)) { - isp_prt(isp, ISP_LOGERR, sacq); - return (-1); - } + if (FC_SCRATCH_ACQUIRE(isp, chan)) { + isp_prt(isp, ISP_LOGERR, sacq); + return (-1); } MEMORYBARRIER(isp, SYNC_SFORDEV, 0, ISP_FC_SCRLEN, chan); isp_mboxcmd(isp, &mbs); if (mbs.param[0] != MBOX_COMMAND_COMPLETE) { - if (dolock) { - FC_SCRATCH_RELEASE(isp, chan); - } + FC_SCRATCH_RELEASE(isp, chan); return (mbs.param[0] | (mbs.param[1] << 16)); } elp1 = fcp->isp_scratch; @@ -2901,13 +2888,12 @@ isp_gethandles(ispsoftc_t *isp, int chan, uint16_t *handles, int *num, handles[j++] = h; } *num = j; - if (dolock) - FC_SCRATCH_RELEASE(isp, chan); + FC_SCRATCH_RELEASE(isp, chan); return (0); } static void -isp_dump_chip_portdb(ispsoftc_t *isp, int chan, int dolock) +isp_dump_chip_portdb(ispsoftc_t *isp, int chan) { isp_pdb_t pdb; uint16_t lim, nphdl; @@ -2919,7 +2905,7 @@ isp_dump_chip_portdb(ispsoftc_t *isp, int chan, int dolock) lim = NPH_MAX; } for (nphdl = 0; nphdl != lim; nphdl++) { - if (isp_getpdb(isp, chan, nphdl, &pdb, dolock)) { + if (isp_getpdb(isp, chan, nphdl, &pdb)) { continue; } isp_prt(isp, ISP_LOG_SANCFG|ISP_LOGINFO, "Chan %d Handle 0x%04x " @@ -3069,7 +3055,7 @@ isp_fclink_test(ispsoftc_t *isp, int chan, int usdelay) if (fcp->isp_topo == TOPO_F_PORT || fcp->isp_topo == TOPO_FL_PORT) { nphdl = IS_24XX(isp) ? NPH_FL_ID : FL_ID; - r = isp_getpdb(isp, chan, nphdl, &pdb, 1); + r = isp_getpdb(isp, chan, nphdl, &pdb); if (r != 0 || pdb.portid == 0) { if (IS_2100(isp)) { fcp->isp_topo = TOPO_NL_PORT; @@ -3311,7 +3297,7 @@ isp_fix_portids(ispsoftc_t *isp, int chan) if (VALID_PORT(lp->portid)) continue; - r = isp_getpdb(isp, chan, lp->handle, &pdb, 1); + r = isp_getpdb(isp, chan, lp->handle, &pdb); if (fcp->isp_loopstate < LOOP_SCANNING_LOOP) return; if (r != 0) { @@ -3340,7 +3326,7 @@ isp_scan_loop(ispsoftc_t *isp, int chan) fcparam *fcp = FCPARAM(isp, chan); int idx, lim, r; isp_pdb_t pdb; - uint16_t handles[LOCAL_LOOP_LIM]; + uint16_t *handles; uint16_t handle; if (fcp->isp_loopstate < LOOP_LTEST_DONE) @@ -3362,8 +3348,9 @@ isp_scan_loop(ispsoftc_t *isp, int chan) return (0); } - lim = LOCAL_LOOP_LIM; - r = isp_gethandles(isp, chan, handles, &lim, 1, 1); + handles = (uint16_t *)fcp->isp_scanscratch; + lim = ISP_FC_SCRLEN / 2; + r = isp_gethandles(isp, chan, handles, &lim, 1); if (r != 0) { isp_prt(isp, ISP_LOG_SANCFG, "Chan %d Getting list of handles failed with %x", chan, r); @@ -3413,7 +3400,7 @@ abort: /* * Get the port database entity for this index. */ - r = isp_getpdb(isp, chan, handle, &pdb, 1); + r = isp_getpdb(isp, chan, handle, &pdb); if (fcp->isp_loopstate < LOOP_SCANNING_LOOP) goto abort; if (r != 0) { @@ -3442,20 +3429,10 @@ abort: * * For the 24XX card, we have to use CT-Pass through run via the Execute IOCB * mailbox command. - * - * The net result is to leave the list of Port IDs setting untranslated in - * offset IGPOFF of the FC scratch area, whereupon we'll canonicalize it to - * host order at OGPOFF. */ - -/* - * Take half of our scratch area to store Port IDs - */ -#define GIDLEN (ISP_FC_SCRLEN >> 1) +#define GIDLEN (ISP_FC_SCRLEN - (3 * QENTRY_LEN)) #define NGENT ((GIDLEN - 16) >> 2) -#define IGPOFF (0) -#define OGPOFF (ISP_FC_SCRLEN >> 1) #define XTXOFF (ISP_FC_SCRLEN - (3 * QENTRY_LEN)) /* CT request */ #define CTXOFF (ISP_FC_SCRLEN - (2 * QENTRY_LEN)) /* Request IOCB */ #define ZTXOFF (ISP_FC_SCRLEN - (1 * QENTRY_LEN)) /* Response IOCB */ @@ -3472,21 +3449,25 @@ isp_gid_ft_sns(ispsoftc_t *isp, int chan) uint8_t *scp = fcp->isp_scratch; mbreg_t mbs; - isp_prt(isp, ISP_LOGDEBUG0, "Chan %d scanning fabric (GID_FT) via SNS", chan); + isp_prt(isp, ISP_LOGDEBUG0, "Chan %d requesting GID_FT via SNS", chan); + if (FC_SCRATCH_ACQUIRE(isp, chan)) { + isp_prt(isp, ISP_LOGERR, sacq); + return (-1); + } ISP_MEMZERO(rq, SNS_GID_FT_REQ_SIZE); rq->snscb_rblen = GIDLEN >> 1; - rq->snscb_addr[RQRSP_ADDR0015] = DMA_WD0(fcp->isp_scdma + IGPOFF); - rq->snscb_addr[RQRSP_ADDR1631] = DMA_WD1(fcp->isp_scdma + IGPOFF); - rq->snscb_addr[RQRSP_ADDR3247] = DMA_WD2(fcp->isp_scdma + IGPOFF); - rq->snscb_addr[RQRSP_ADDR4863] = DMA_WD3(fcp->isp_scdma + IGPOFF); + rq->snscb_addr[RQRSP_ADDR0015] = DMA_WD0(fcp->isp_scdma); + rq->snscb_addr[RQRSP_ADDR1631] = DMA_WD1(fcp->isp_scdma); + rq->snscb_addr[RQRSP_ADDR3247] = DMA_WD2(fcp->isp_scdma); + rq->snscb_addr[RQRSP_ADDR4863] = DMA_WD3(fcp->isp_scdma); rq->snscb_sblen = 6; rq->snscb_cmd = SNS_GID_FT; rq->snscb_mword_div_2 = NGENT; rq->snscb_fc4_type = FC4_SCSI; isp_put_gid_ft_request(isp, rq, (sns_gid_ft_req_t *)&scp[CTXOFF]); - MEMORYBARRIER(isp, SYNC_SFORDEV, 0, SNS_GID_FT_REQ_SIZE, chan); + MEMORYBARRIER(isp, SYNC_SFORDEV, CTXOFF, SNS_GID_FT_REQ_SIZE, chan); MBSINIT(&mbs, MBOX_SEND_SNS, MBLOGALL, 10000000); mbs.param[0] = MBOX_SEND_SNS; @@ -3503,6 +3484,12 @@ isp_gid_ft_sns(ispsoftc_t *isp, int chan) return (-1); } } + MEMORYBARRIER(isp, SYNC_SFORCPU, 0, GIDLEN, chan); + if (isp->isp_dblev & ISP_LOGDEBUG1) + isp_print_bytes(isp, "CT response", GIDLEN, scp); + isp_get_gid_ft_response(isp, (sns_gid_ft_rsp_t *)scp, + (sns_gid_ft_rsp_t *)fcp->isp_scanscratch, NGENT); + FC_SCRATCH_RELEASE(isp, chan); return (0); } @@ -3521,7 +3508,11 @@ isp_gid_ft_ct_passthru(ispsoftc_t *isp, int chan) uint32_t *rp; uint8_t *scp = fcp->isp_scratch; - isp_prt(isp, ISP_LOGDEBUG0, "Chan %d scanning fabric (GID_FT) via CT", chan); + isp_prt(isp, ISP_LOGDEBUG0, "Chan %d requesting GID_FT via CT", chan); + if (FC_SCRATCH_ACQUIRE(isp, chan)) { + isp_prt(isp, ISP_LOGERR, sacq); + return (-1); + } /* * Build a Passthrough IOCB in memory. @@ -3541,8 +3532,8 @@ isp_gid_ft_ct_passthru(ispsoftc_t *isp, int chan) pt->ctp_dataseg[0].ds_base = DMA_LO32(fcp->isp_scdma+XTXOFF); pt->ctp_dataseg[0].ds_basehi = DMA_HI32(fcp->isp_scdma+XTXOFF); pt->ctp_dataseg[0].ds_count = sizeof (*ct) + sizeof (uint32_t); - pt->ctp_dataseg[1].ds_base = DMA_LO32(fcp->isp_scdma+IGPOFF); - pt->ctp_dataseg[1].ds_basehi = DMA_HI32(fcp->isp_scdma+IGPOFF); + pt->ctp_dataseg[1].ds_base = DMA_LO32(fcp->isp_scdma); + pt->ctp_dataseg[1].ds_basehi = DMA_HI32(fcp->isp_scdma); pt->ctp_dataseg[1].ds_count = GIDLEN; if (isp->isp_dblev & ISP_LOGDEBUG1) { isp_print_bytes(isp, "ct IOCB", QENTRY_LEN, pt); @@ -3582,7 +3573,7 @@ isp_gid_ft_ct_passthru(ispsoftc_t *isp, int chan) if (mbs.param[0] != MBOX_COMMAND_COMPLETE) { return (-1); } - MEMORYBARRIER(isp, SYNC_SFORCPU, ZTXOFF, QENTRY_LEN, chan); + MEMORYBARRIER(isp, SYNC_SFORCPU, 0, ISP_FC_SCRLEN, chan); pt = &un.plocal; isp_get_ct_pt(isp, (isp_ct_pt_t *) &scp[ZTXOFF], pt); if (isp->isp_dblev & ISP_LOGDEBUG1) { @@ -3591,14 +3582,15 @@ isp_gid_ft_ct_passthru(ispsoftc_t *isp, int chan) if (pt->ctp_status && pt->ctp_status != RQCS_DATA_UNDERRUN) { isp_prt(isp, ISP_LOGWARN, - "Chan %d ISP GID FT CT Passthrough returned 0x%x", + "Chan %d GID_FT CT Passthrough returned 0x%x", chan, pt->ctp_status); return (-1); } - MEMORYBARRIER(isp, SYNC_SFORCPU, IGPOFF, GIDLEN, chan); - if (isp->isp_dblev & ISP_LOGDEBUG1) { - isp_print_bytes(isp, "CT response", GIDLEN, &scp[IGPOFF]); - } + if (isp->isp_dblev & ISP_LOGDEBUG1) + isp_print_bytes(isp, "CT response", GIDLEN, scp); + isp_get_gid_ft_response(isp, (sns_gid_ft_rsp_t *)scp, + (sns_gid_ft_rsp_t *)fcp->isp_scanscratch, NGENT); + FC_SCRATCH_RELEASE(isp, chan); return (0); } @@ -3611,7 +3603,7 @@ isp_scan_fabric(ispsoftc_t *isp, int chan) uint16_t nphdl; isp_pdb_t pdb; int portidx, portlim, r; - sns_gid_ft_rsp_t *rs0, *rs1; + sns_gid_ft_rsp_t *rs; if (fcp->isp_loopstate < LOOP_LSCAN_DONE) return (-1); @@ -3627,13 +3619,6 @@ isp_scan_fabric(ispsoftc_t *isp, int chan) return (0); } - if (FC_SCRATCH_ACQUIRE(isp, chan)) { - isp_prt(isp, ISP_LOGERR, sacq); -fail: - isp_prt(isp, ISP_LOG_SANCFG, - "Chan %d FC fabric scan done (bad)", chan); - return (-1); - } if (fcp->isp_loopstate < LOOP_SCANNING_FABRIC) { abort: FC_SCRATCH_RELEASE(isp, chan); @@ -3646,14 +3631,16 @@ abort: * Make sure we still are logged into the fabric controller. */ nphdl = IS_24XX(isp) ? NPH_FL_ID : FL_ID; - r = isp_getpdb(isp, chan, nphdl, &pdb, 0); + r = isp_getpdb(isp, chan, nphdl, &pdb); if ((r & 0xffff) == MBOX_NOT_LOGGED_IN) { - isp_dump_chip_portdb(isp, chan, 0); + isp_dump_chip_portdb(isp, chan); } if (r) { fcp->isp_loopstate = LOOP_LTEST_DONE; - FC_SCRATCH_RELEASE(isp, chan); - goto fail; +fail: + isp_prt(isp, ISP_LOG_SANCFG, + "Chan %d FC fabric scan done (bad)", chan); + return (-1); } /* Get list of port IDs from SNS. */ @@ -3665,42 +3652,36 @@ abort: goto abort; if (r > 0) { fcp->isp_loopstate = LOOP_FSCAN_DONE; - FC_SCRATCH_RELEASE(isp, chan); return (-1); } else if (r < 0) { fcp->isp_loopstate = LOOP_LTEST_DONE; /* try again */ - FC_SCRATCH_RELEASE(isp, chan); return (-1); } - MEMORYBARRIER(isp, SYNC_SFORCPU, IGPOFF, GIDLEN, chan); - rs0 = (sns_gid_ft_rsp_t *) ((uint8_t *)fcp->isp_scratch+IGPOFF); - rs1 = (sns_gid_ft_rsp_t *) ((uint8_t *)fcp->isp_scratch+OGPOFF); - isp_get_gid_ft_response(isp, rs0, rs1, NGENT); + rs = (sns_gid_ft_rsp_t *) fcp->isp_scanscratch; if (fcp->isp_loopstate < LOOP_SCANNING_FABRIC) goto abort; - if (rs1->snscb_cthdr.ct_cmd_resp != LS_ACC) { + if (rs->snscb_cthdr.ct_cmd_resp != LS_ACC) { int level; - if (rs1->snscb_cthdr.ct_reason == 9 && rs1->snscb_cthdr.ct_explanation == 7) { + if (rs->snscb_cthdr.ct_reason == 9 && rs->snscb_cthdr.ct_explanation == 7) { level = ISP_LOG_SANCFG; } else { level = ISP_LOGWARN; } isp_prt(isp, level, "Chan %d Fabric Nameserver rejected GID_FT" " (Reason=0x%x Expl=0x%x)", chan, - rs1->snscb_cthdr.ct_reason, - rs1->snscb_cthdr.ct_explanation); - FC_SCRATCH_RELEASE(isp, chan); + rs->snscb_cthdr.ct_reason, + rs->snscb_cthdr.ct_explanation); fcp->isp_loopstate = LOOP_FSCAN_DONE; return (-1); } /* Check our buffer was big enough to get the full list. */ for (portidx = 0; portidx < NGENT-1; portidx++) { - if (rs1->snscb_ports[portidx].control & 0x80) + if (rs->snscb_ports[portidx].control & 0x80) break; } - if ((rs1->snscb_ports[portidx].control & 0x80) == 0) { + if ((rs->snscb_ports[portidx].control & 0x80) == 0) { isp_prt(isp, ISP_LOGWARN, "fabric too big for scratch area: increase ISP_FC_SCRLEN"); } @@ -3713,24 +3694,24 @@ abort: int npidx; portid = - ((rs1->snscb_ports[portidx].portid[0]) << 16) | - ((rs1->snscb_ports[portidx].portid[1]) << 8) | - ((rs1->snscb_ports[portidx].portid[2])); + ((rs->snscb_ports[portidx].portid[0]) << 16) | + ((rs->snscb_ports[portidx].portid[1]) << 8) | + ((rs->snscb_ports[portidx].portid[2])); for (npidx = portidx + 1; npidx < portlim; npidx++) { uint32_t new_portid = - ((rs1->snscb_ports[npidx].portid[0]) << 16) | - ((rs1->snscb_ports[npidx].portid[1]) << 8) | - ((rs1->snscb_ports[npidx].portid[2])); + ((rs->snscb_ports[npidx].portid[0]) << 16) | + ((rs->snscb_ports[npidx].portid[1]) << 8) | + ((rs->snscb_ports[npidx].portid[2])); if (new_portid == portid) { break; } } if (npidx < portlim) { - rs1->snscb_ports[npidx].portid[0] = 0; - rs1->snscb_ports[npidx].portid[1] = 0; - rs1->snscb_ports[npidx].portid[2] = 0; + rs->snscb_ports[npidx].portid[0] = 0; + rs->snscb_ports[npidx].portid[1] = 0; + rs->snscb_ports[npidx].portid[2] = 0; isp_prt(isp, ISP_LOG_SANCFG, "Chan %d removing duplicate PortID 0x%06x entry from list", chan, portid); } } @@ -3751,9 +3732,9 @@ abort: */ isp_mark_portdb(isp, chan); for (portidx = 0; portidx < portlim; portidx++) { - portid = ((rs1->snscb_ports[portidx].portid[0]) << 16) | - ((rs1->snscb_ports[portidx].portid[1]) << 8) | - ((rs1->snscb_ports[portidx].portid[2])); + portid = ((rs->snscb_ports[portidx].portid[0]) << 16) | + ((rs->snscb_ports[portidx].portid[1]) << 8) | + ((rs->snscb_ports[portidx].portid[2])); isp_prt(isp, ISP_LOG_SANCFG, "Chan %d Checking fabric port 0x%06x", chan, portid); if (portid == 0) { @@ -3775,7 +3756,6 @@ abort: "Chan %d Port 0x%06x@0x%04x [%d] is not probational (0x%x)", chan, lp->portid, lp->handle, FC_PORTDB_TGT(isp, chan, lp), lp->state); - FC_SCRATCH_RELEASE(isp, chan); isp_dump_portdb(isp, chan); goto fail; } @@ -3795,7 +3775,7 @@ abort: * database entry for somebody further along to * decide what to do (policy choice). */ - r = isp_getpdb(isp, chan, lp->handle, &pdb, 0); + r = isp_getpdb(isp, chan, lp->handle, &pdb); if (fcp->isp_loopstate < LOOP_SCANNING_FABRIC) goto abort; if (r != 0) { @@ -3829,7 +3809,6 @@ relogin: if (fcp->isp_loopstate < LOOP_SCANNING_FABRIC) goto abort; - FC_SCRATCH_RELEASE(isp, chan); fcp->isp_loopstate = LOOP_FSCAN_DONE; isp_prt(isp, ISP_LOG_SANCFG, "Chan %d FC fabric scan done", chan); return (0); @@ -3856,7 +3835,7 @@ isp_login_device(ispsoftc_t *isp, int chan, uint32_t portid, isp_pdb_t *p, uint1 return (-1); /* Check if this handle is free. */ - r = isp_getpdb(isp, chan, handle, p, 0); + r = isp_getpdb(isp, chan, handle, p); if (r == 0) { if (p->portid != portid) { /* This handle is busy, try next one. */ @@ -3909,7 +3888,7 @@ isp_login_device(ispsoftc_t *isp, int chan, uint32_t portid, isp_pdb_t *p, uint1 * so we can crosscheck that it is still what we think it * is and that we also have the role it plays */ - r = isp_getpdb(isp, chan, handle, p, 0); + r = isp_getpdb(isp, chan, handle, p); if (r != 0) { isp_prt(isp, ISP_LOGERR, "Chan %d new device 0x%06x@0x%x disappeared", chan, portid, handle); return (-1); @@ -4013,8 +3992,8 @@ isp_register_fc4_type_24xx(ispsoftc_t *isp, int chan) pt->ctp_dataseg[0].ds_base = DMA_LO32(fcp->isp_scdma+XTXOFF); pt->ctp_dataseg[0].ds_basehi = DMA_HI32(fcp->isp_scdma+XTXOFF); pt->ctp_dataseg[0].ds_count = sizeof (rft_id_t); - pt->ctp_dataseg[1].ds_base = DMA_LO32(fcp->isp_scdma+IGPOFF); - pt->ctp_dataseg[1].ds_basehi = DMA_HI32(fcp->isp_scdma+IGPOFF); + pt->ctp_dataseg[1].ds_base = DMA_LO32(fcp->isp_scdma); + pt->ctp_dataseg[1].ds_basehi = DMA_HI32(fcp->isp_scdma); pt->ctp_dataseg[1].ds_count = sizeof (ct_hdr_t); isp_put_ct_pt(isp, pt, (isp_ct_pt_t *) &scp[CTXOFF]); if (isp->isp_dblev & ISP_LOGDEBUG1) { @@ -4072,7 +4051,7 @@ isp_register_fc4_type_24xx(ispsoftc_t *isp, int chan) return (1); } - isp_get_ct_hdr(isp, (ct_hdr_t *) &scp[IGPOFF], ct); + isp_get_ct_hdr(isp, (ct_hdr_t *) scp, ct); FC_SCRATCH_RELEASE(isp, chan); if (ct->ct_cmd_resp == LS_RJT) { @@ -4125,8 +4104,8 @@ isp_register_fc4_features_24xx(ispsoftc_t *isp, int chan) pt->ctp_dataseg[0].ds_base = DMA_LO32(fcp->isp_scdma+XTXOFF); pt->ctp_dataseg[0].ds_basehi = DMA_HI32(fcp->isp_scdma+XTXOFF); pt->ctp_dataseg[0].ds_count = sizeof (rff_id_t); - pt->ctp_dataseg[1].ds_base = DMA_LO32(fcp->isp_scdma+IGPOFF); - pt->ctp_dataseg[1].ds_basehi = DMA_HI32(fcp->isp_scdma+IGPOFF); + pt->ctp_dataseg[1].ds_base = DMA_LO32(fcp->isp_scdma); + pt->ctp_dataseg[1].ds_basehi = DMA_HI32(fcp->isp_scdma); pt->ctp_dataseg[1].ds_count = sizeof (ct_hdr_t); isp_put_ct_pt(isp, pt, (isp_ct_pt_t *) &scp[CTXOFF]); if (isp->isp_dblev & ISP_LOGDEBUG1) { @@ -4189,7 +4168,7 @@ isp_register_fc4_features_24xx(ispsoftc_t *isp, int chan) return (1); } - isp_get_ct_hdr(isp, (ct_hdr_t *) &scp[IGPOFF], ct); + isp_get_ct_hdr(isp, (ct_hdr_t *) scp, ct); FC_SCRATCH_RELEASE(isp, chan); if (ct->ct_cmd_resp == LS_RJT) { @@ -4877,7 +4856,7 @@ isp_control(ispsoftc_t *isp, ispctl_t ctl, ...) tgt = va_arg(ap, int); pdb = va_arg(ap, isp_pdb_t *); va_end(ap); - return (isp_getpdb(isp, chan, tgt, pdb, 1)); + return (isp_getpdb(isp, chan, tgt, pdb)); } break; diff --git a/sys/dev/isp/ispvar.h b/sys/dev/isp/ispvar.h index f752254..a7184e2 100644 --- a/sys/dev/isp/ispvar.h +++ b/sys/dev/isp/ispvar.h @@ -77,7 +77,7 @@ struct ispmdvec { */ #define MAX_TARGETS 16 #ifndef MAX_FC_TARG -#define MAX_FC_TARG 256 +#define MAX_FC_TARG 1024 #endif #define ISP_MAX_TARGETS(isp) (IS_FC(isp)? MAX_FC_TARG : MAX_TARGETS) #define ISP_MAX_LUNS(isp) (isp)->isp_maxluns @@ -472,6 +472,8 @@ typedef struct { */ void * isp_scratch; XS_DMA_ADDR_T isp_scdma; + + uint8_t isp_scanscratch[ISP_FC_SCRLEN]; } fcparam; #define FW_CONFIG_WAIT 0 -- cgit v1.1 From ecf8336fcdf81e2aeb30a7ab82841dd7299ceb98 Mon Sep 17 00:00:00 2001 From: gjb Date: Wed, 30 Dec 2015 13:12:54 +0000 Subject: MFC r278449, r278926: r278449: Enable multi-threaded xz(1) compression for release install media. r278926 (rpaulo): Use xz(1) via pipe when compressing the release distribution tarballs. Tested on: stable/10@r292855 Sponsored by: The FreeBSD Foundation --- Makefile.inc1 | 32 +++++++++++++++++--------------- release/Makefile | 13 +++++++------ release/Makefile.vm | 2 +- share/mk/bsd.own.mk | 9 +++++++++ 4 files changed, 34 insertions(+), 22 deletions(-) diff --git a/Makefile.inc1 b/Makefile.inc1 index a2d015b..1c8ab10 100644 --- a/Makefile.inc1 +++ b/Makefile.inc1 @@ -913,13 +913,13 @@ packageworld: .for dist in base ${EXTRA_DISTRIBUTIONS} .if defined(NO_ROOT) ${_+_}cd ${DESTDIR}/${DISTDIR}/${dist}; \ - tar cvJf ${DESTDIR}/${DISTDIR}/${dist}.txz \ - --exclude usr/lib/debug \ - @${DESTDIR}/${DISTDIR}/${dist}.meta + tar cvf - --exclude usr/lib/debug \ + @${DESTDIR}/${DISTDIR}/${dist}.meta | \ + ${XZ_CMD} > ${DESTDIR}/${DISTDIR}/${dist}.txz .else ${_+_}cd ${DESTDIR}/${DISTDIR}/${dist}; \ - tar cvJf ${DESTDIR}/${DISTDIR}/${dist}.txz \ - --exclude usr/lib/debug . + tar cvf - --exclude usr/lib/debug . | \ + ${XZ_CMD} > ${DESTDIR}/${DISTDIR}/${dist}.txz .endif .endfor @@ -927,12 +927,12 @@ packageworld: . for dist in base ${EXTRA_DISTRIBUTIONS} . if defined(NO_ROOT) ${_+_}cd ${DESTDIR}/${DISTDIR}/${dist}; \ - tar cvJf ${DESTDIR}/${DISTDIR}/${dist}.debug.txz \ - @${DESTDIR}/${DISTDIR}/${dist}.debug.meta + tar cvf - @${DESTDIR}/${DISTDIR}/${dist}.debug.meta | \ + ${XZ_CMD} > ${DESTDIR}/${DISTDIR}/${dist}.debug.txz . else ${_+_}cd ${DESTDIR}/${DISTDIR}/${dist}; \ - tar cvJfL ${DESTDIR}/${DISTDIR}/${dist}.debug.txz \ - usr/lib/debug + tar cvLf - usr/lib/debug | \ + ${XZ_CMD} > ${DESTDIR}/${DISTDIR}/${dist}-debug.txz . endif . endfor .endif @@ -1141,19 +1141,21 @@ distributekernel distributekernel.debug: packagekernel: .if defined(NO_ROOT) cd ${DESTDIR}/${DISTDIR}/kernel; \ - tar cvJf ${DESTDIR}/${DISTDIR}/kernel.txz \ - @${DESTDIR}/${DISTDIR}/kernel.meta + tar cvf - @${DESTDIR}/${DISTDIR}/kernel.meta | \ + ${XZ_CMD} > ${DESTDIR}/${DISTDIR}/kernel.txz .for _kernel in ${BUILDKERNELS:S/${INSTALLKERNEL}//} cd ${DESTDIR}/${DISTDIR}/kernel.${_kernel}; \ - tar cvJf ${DESTDIR}/${DISTDIR}/kernel.${_kernel}.txz \ - @${DESTDIR}/${DISTDIR}/kernel.${_kernel}.meta + tar cvf - @${DESTDIR}/${DISTDIR}/kernel.${_kernel}.meta | \ + ${XZ_CMD} > ${DESTDIR}/${DISTDIR}/kernel.${_kernel}.txz .endfor .else cd ${DESTDIR}/${DISTDIR}/kernel; \ - tar cvJf ${DESTDIR}/${DISTDIR}/kernel.txz . + tar cvf - . | \ + ${XZ_CMD} > ${DESTDIR}/${DISTDIR}/kernel.txz .for _kernel in ${BUILDKERNELS:S/${INSTALLKERNEL}//} cd ${DESTDIR}/${DISTDIR}/kernel.${_kernel}; \ - tar cvJf ${DESTDIR}/${DISTDIR}/kernel.${_kernel}.txz . + tar cvf - . | \ + ${XZ_CMD} > ${DESTDIR}/${DISTDIR}/kernel.${_kernel}.txz .endfor .endif diff --git a/release/Makefile b/release/Makefile index 4cd82c3..976f651 100644 --- a/release/Makefile +++ b/release/Makefile @@ -40,7 +40,6 @@ WORLDDIR?= ${.CURDIR}/.. PORTSDIR?= /usr/ports DOCDIR?= /usr/doc RELNOTES_LANG?= en_US.ISO8859-1 -XZCMD?= /usr/bin/xz .if !defined(TARGET) || empty(TARGET) TARGET= ${MACHINE} @@ -161,16 +160,18 @@ kernel.txz: src.txz: mkdir -p ${DISTDIR}/usr ln -fs ${WORLDDIR} ${DISTDIR}/usr/src - cd ${DISTDIR} && tar cLvJf ${.OBJDIR}/src.txz --exclude .svn --exclude .zfs \ - --exclude .git --exclude @ --exclude usr/src/release/dist usr/src + cd ${DISTDIR} && tar cLvf - --exclude .svn --exclude .zfs \ + --exclude .git --exclude @ --exclude usr/src/release/dist usr/src | \ + ${XZ_CMD} > ${.OBJDIR}/src.txz ports.txz: mkdir -p ${DISTDIR}/usr ln -fs ${PORTSDIR} ${DISTDIR}/usr/ports - cd ${DISTDIR} && tar cLvJf ${.OBJDIR}/ports.txz \ + cd ${DISTDIR} && tar cLvf - \ --exclude .git --exclude .svn \ --exclude usr/ports/distfiles --exclude usr/ports/packages \ - --exclude 'usr/ports/INDEX*' --exclude work usr/ports + --exclude 'usr/ports/INDEX*' --exclude work usr/ports | \ + ${XZ_CMD} > ${.OBJDIR}/ports.txz reldoc: cd ${.CURDIR}/doc && ${MAKE} all install clean 'FORMATS=html txt' \ @@ -333,7 +334,7 @@ release-install: .for I in ${IMAGES} cp -p ${I} ${DESTDIR}/${OSRELEASE}-${I} . if defined(WITH_COMPRESSED_IMAGES) && !empty(WITH_COMPRESSED_IMAGES) - ${XZCMD} -k ${DESTDIR}/${OSRELEASE}-${I} + ${XZ_CMD} -k ${DESTDIR}/${OSRELEASE}-${I} . endif .endfor cd ${DESTDIR} && sha512 ${OSRELEASE}* > ${DESTDIR}/CHECKSUM.SHA512 diff --git a/release/Makefile.vm b/release/Makefile.vm index f4de633..902442f 100644 --- a/release/Makefile.vm +++ b/release/Makefile.vm @@ -137,7 +137,7 @@ vm-install: . if defined(WITH_COMPRESSED_VMIMAGES) && !empty(WITH_COMPRESSED_VMIMAGES) . for FORMAT in ${VMFORMATS} # Don't keep the originals. There is a copy in ${.OBJDIR} if needed. - ${XZCMD} ${DESTDIR}/vmimages/${OSRELEASE}.${FORMAT} + ${XZ_CMD} ${DESTDIR}/vmimages/${OSRELEASE}.${FORMAT} . endfor . endif cd ${DESTDIR}/vmimages && sha512 ${OSRELEASE}* > \ diff --git a/share/mk/bsd.own.mk b/share/mk/bsd.own.mk index 4792bad..ef200d8 100644 --- a/share/mk/bsd.own.mk +++ b/share/mk/bsd.own.mk @@ -213,6 +213,15 @@ STRIP?= -s COMPRESS_CMD?= gzip -cn COMPRESS_EXT?= .gz +# Set XZ_THREADS to 1 to disable multi-threading. +XZ_THREADS?= 0 + +.if !empty(XZ_THREADS) +XZ_CMD?= xz -T ${XZ_THREADS} +.else +XZ_CMD?= xz +.endif + .if !defined(_WITHOUT_SRCCONF) # # Define MK_* variables (which are either "yes" or "no") for users -- cgit v1.1