diff options
author | ngie <ngie@FreeBSD.org> | 2015-12-17 06:55:25 +0000 |
---|---|---|
committer | ngie <ngie@FreeBSD.org> | 2015-12-17 06:55:25 +0000 |
commit | 490921132f201193a73d81699cb455aa2ae87357 (patch) | |
tree | 447ebf673b9e1d362dbcf1b55fd34fa0de86d693 | |
parent | 3fed53d02350ae9cbd7b2786b72b83d2e292b8d1 (diff) | |
parent | a7e4d91c2357d6f2c732cccc35fd4ddda5f2d58e (diff) | |
download | FreeBSD-src-490921132f201193a73d81699cb455aa2ae87357.zip FreeBSD-src-490921132f201193a73d81699cb455aa2ae87357.tar.gz |
MFhead @ r292396
157 files changed, 6768 insertions, 4306 deletions
diff --git a/MAINTAINERS b/MAINTAINERS index 907e376..5ea2483 100644 --- a/MAINTAINERS +++ b/MAINTAINERS @@ -37,9 +37,12 @@ contrib/llvm/tools/lldb emaste Pre-commit review preferred. contrib/netbsd-tests freebsd-testing,ngie Pre-commit review requested. contrib/pjdfstest freebsd-testing,ngie,pjd Pre-commit review requested. dev/usb/wlan adrian Pre-commit review requested, send to freebsd-wireless@freebsd.org +*env(3) secteam Due to the problematic security history of this + code, please have patches reviewed by secteam. etc/mail gshapiro Pre-commit review requested. Keep in sync with -STABLE. etc/sendmail gshapiro Pre-commit review requested. Keep in sync with -STABLE. fetch des Pre-commit review requested. +geli pjd Pre-commit review requested (both sys/geom/eli/ and sbin/geom/class/eli/). isci(4) jimharris Pre-commit review requested. iwm(4) adrian Pre-commit review requested, send to freebsd-wireless@freebsd.org iwn(4) adrian Pre-commit review requested, send to freebsd-wireless@freebsd.org @@ -51,6 +54,7 @@ lpr gad Pre-commit review requested, particularly for lpd/recvjob.c and lpd/printjob.c. nanobsd imp Pre-commit phabricator review requested. net80211 adrian Pre-commit review requested, send to freebsd-wireless@freebsd.org +nfs freebsd-fs@FreeBSD.org, rmacklem is best for reviews. nis(8), yp(8) araujo Pre-commit review requested. nvd(4) jimharris Pre-commit review requested. nvme(4) jimharris Pre-commit review requested. @@ -59,6 +63,7 @@ opencrypto jmg Pre-commit review requested. Documentation Required. openssh des Pre-commit review requested. openssl benl,jkim Pre-commit review requested. otus(4) adrian Pre-commit review requested, send to freebsd-wireless@freebsd.org +pci bus imp,jhb Pre-commit review requested. pmcstudy(8) rrs Pre-commit review requested. procfs des Pre-commit review requested. pseudofs des Pre-commit review requested. @@ -92,7 +97,6 @@ contrib/openbsm rwatson Pre-commit review requested. sys/security/audit rwatson Pre-commit review requested. ahc(4) gibbs Pre-commit review requested. ahd(4) gibbs Pre-commit review requested. -pci bus imp,jhb Pre-commit review requested. cdboot jhb Pre-commit review requested. pxeboot jhb Pre-commit review requested. witness jhb Pre-commit review requested. @@ -122,7 +126,6 @@ file obrien Insists to keep file blocked from other's unapproved contrib/bzip2 obrien Pre-commit review required. geom freebsd-geom@FreeBSD.org geom_concat pjd Pre-commit review preferred. -geom_eli pjd Pre-commit review preferred. geom_gate pjd Pre-commit review preferred. geom_label pjd Pre-commit review preferred. geom_mirror pjd Pre-commit review preferred. @@ -133,7 +136,6 @@ geom_stripe pjd Pre-commit review preferred. geom_zero pjd Pre-commit review preferred. sbin/geom pjd Pre-commit review preferred. zfs freebsd-fs@FreeBSD.org -nfs freebsd-fs@FreeBSD.org, rmacklem is best for reviews. linux emul emulation Please discuss changes here. bs{diff,patch} cperciva Pre-commit review requested. portsnap cperciva Pre-commit review requested. @@ -143,8 +145,6 @@ lib/libbluetooth emax Pre-commit review preferred. lib/libsdp emax Pre-commit review preferred. usr.bin/bluetooth emax Pre-commit review preferred. usr.sbin/bluetooth emax Pre-commit review preferred. -*env(3) secteam Due to the problematic security history of this - code, please have patches reviewed by secteam. share/zoneinfo edwin Heads-up appreciated, since our data is coming from a third party source. usr.sbin/zic edwin Heads-up appreciated, since this code is @@ -31,6 +31,12 @@ NOTE TO PEOPLE WHO THINK THAT FreeBSD 11.x IS SLOW: disable the most expensive debugging functionality run "ln -s 'abort:false,junk:false' /etc/malloc.conf".) +20151216: + The tftp loader (pxeboot) now uses the option root-path directive. As a + consequence it no longer looks for a pxeboot.4th file on the tftp + server. Instead it uses the regular /boot infrastructure as with the + other loaders. + 20151211: The code to start recording plug and play data into the modules has been committed. While the old tools will properly build a new kernel, diff --git a/bin/sh/var.c b/bin/sh/var.c index cfba0ba..c124a5d 100644 --- a/bin/sh/var.c +++ b/bin/sh/var.c @@ -330,7 +330,7 @@ setvareq(char *s, int flags) if (vp->flags & VREADONLY) { if ((flags & (VTEXTFIXED|VSTACK)) == 0) ckfree(s); - error("%.*s: is read only", vp->name_len, s); + error("%.*s: is read only", vp->name_len, vp->text); } if (flags & VNOSET) { if ((flags & (VTEXTFIXED|VSTACK)) == 0) diff --git a/contrib/llvm/tools/lldb/docs/lldb.1 b/contrib/llvm/tools/lldb/docs/lldb.1 index 57b0931..b6084e7 100644 --- a/contrib/llvm/tools/lldb/docs/lldb.1 +++ b/contrib/llvm/tools/lldb/docs/lldb.1 @@ -1,4 +1,4 @@ -.Dd June 7, 2012 \" DATE +.Dd December 16, 2015 \" DATE .Dt LLDB 1 \" Program name and manual section number .Os .Sh NAME \" Section Header - required - don't modify @@ -8,6 +8,7 @@ .Nm lldb .Op Fl hvdexw .Op Fl a Ar arch +.Op Fl c Ar core-file .Op Fl l Ar script-language .Op Fl s Ar lldb-commands .Op Fl n Ar process-name @@ -52,6 +53,8 @@ to it as early in the process-launch as possible. Specifies a currently running process that .Nm should attach to. +.It Fl c, -core Ar core-file +Specifies the core file to examine. .It Fl l, -script-language Ar language Tells the debugger to use the specified scripting language for user-defined scripts, rather than the default. Valid scripting diff --git a/etc/mtree/BSD.tests.dist b/etc/mtree/BSD.tests.dist index 3bfa30c..7887ee4 100644 --- a/etc/mtree/BSD.tests.dist +++ b/etc/mtree/BSD.tests.dist @@ -271,10 +271,14 @@ .. .. .. + nss + .. regex data .. .. + resolv + .. rpc .. ssp diff --git a/etc/periodic/daily/800.scrub-zfs b/etc/periodic/daily/800.scrub-zfs index ee0e52a..359be13 100755 --- a/etc/periodic/daily/800.scrub-zfs +++ b/etc/periodic/daily/800.scrub-zfs @@ -43,6 +43,10 @@ case "$daily_scrub_zfs_enable" in rc=3 echo "Skipping faulted pool: ${pool}" continue ;; + *UNAVAIL*) + rc=4 + echo "Skipping unavailable pool: ${pool}" + continue ;; esac # determine how many days shall be between scrubs diff --git a/lib/libc/tests/Makefile b/lib/libc/tests/Makefile index e6ddc15..a9d8c02 100644 --- a/lib/libc/tests/Makefile +++ b/lib/libc/tests/Makefile @@ -10,7 +10,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 <bsd.test.mk> diff --git a/tools/regression/lib/libc/nss/test-getaddr.c b/lib/libc/tests/nss/getaddrinfo_test.c index f0729ec..0c9704f 100644 --- a/tools/regression/lib/libc/nss/test-getaddr.c +++ b/lib/libc/tests/nss/getaddrinfo_test.c @@ -28,11 +28,10 @@ #include <sys/cdefs.h> __FBSDID("$FreeBSD$"); -#include <arpa/inet.h> -#include <sys/socket.h> #include <sys/types.h> +#include <sys/socket.h> +#include <arpa/inet.h> #include <netinet/in.h> -#include <assert.h> #include <errno.h> #include <netdb.h> #include <resolv.h> @@ -41,6 +40,10 @@ __FBSDID("$FreeBSD$"); #include <string.h> #include <stringlist.h> #include <unistd.h> + +#include <atf-c.h> + +#include "freebsd_test_suite/macros.h" #include "testutil.h" enum test_methods { @@ -48,7 +51,6 @@ enum test_methods { TEST_BUILD_SNAPSHOT }; -static int debug = 0; static struct addrinfo hints; static enum test_methods method = TEST_GETADDRINFO; @@ -59,7 +61,6 @@ 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 free_addrinfo(struct addrinfo *); static void sdump_addrinfo(struct addrinfo *, char *, size_t); @@ -70,23 +71,23 @@ IMPLEMENT_2PASS_TEST(addrinfo) static void clone_addrinfo(struct addrinfo *dest, struct addrinfo const *src) { - assert(dest != NULL); - assert(src != NULL); + + 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 = (struct sockaddr *)malloc(src->ai_addrlen); - assert(dest->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 = (struct addrinfo *)malloc( - sizeof(struct addrinfo)); - assert(dest->ai_next != NULL); + dest->ai_next = malloc(sizeof(struct addrinfo)); + ATF_REQUIRE(dest->ai_next != NULL); clone_addrinfo(dest->ai_next, src->ai_next); } } @@ -94,29 +95,30 @@ clone_addrinfo(struct addrinfo *dest, struct addrinfo const *src) 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))) + 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)) + 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)) + 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)) + if (ai1->ai_next == NULL && ai2->ai_next == NULL) return (0); else return (compare_addrinfo_(ai1->ai_next, ai2->ai_next)); @@ -127,20 +129,16 @@ compare_addrinfo(struct addrinfo *ai1, struct addrinfo *ai2, void *mdata) { int rv; - if (debug) { - printf("testing equality of 2 addrinfo structures\n"); - } + printf("testing equality of 2 addrinfo structures\n"); rv = compare_addrinfo_(ai1, ai2); - if (debug) { - if (rv == 0) - printf("equal\n"); - else { - dump_addrinfo(ai1); - dump_addrinfo(ai2); - printf("not equal\n"); - } + if (rv == 0) + printf("equal\n"); + else { + dump_addrinfo(ai1); + dump_addrinfo(ai2); + printf("not equal\n"); } return (rv); @@ -184,18 +182,18 @@ sdump_addrinfo(struct addrinfo *ai, char *buffer, size_t 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; - } + 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) { @@ -226,7 +224,7 @@ addrinfo_read_snapshot_addr(char *addr, unsigned char *result, size_t len) char *s, *ps, *ts; ps = addr; - while ( (s = strsep(&ps, ".")) != NULL) { + while ((s = strsep(&ps, ".")) != NULL) { if (len == 0) return (-1); @@ -253,55 +251,53 @@ addrinfo_read_snapshot_ai(struct addrinfo *ai, char *line) i = 0; ps = line; memset(ai, 0, sizeof(struct addrinfo)); - while ( (s = strsep(&ps, " ")) != NULL) { + 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); - assert(ai->ai_canonname != NULL); - } - break; - case 6: - if (strcmp(s, "(null)") != 0) { - ai->ai_addr = (struct sockaddr *)malloc( - ai->ai_addrlen); - assert(ai->ai_addr != NULL); - memset(ai->ai_addr, 0, ai->ai_addrlen); - 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; + 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)) { + if (i != 7 || rv != 0) { free_addrinfo(ai); - memset(ai, 0, sizeof(struct addrinfo)); + ai = NULL; return (-1); } @@ -315,8 +311,7 @@ addrinfo_read_snapshot_func(struct addrinfo *ai, char *line) char *s, *ps; int i, rv; - if (debug) - printf("1 line read from snapshot:\n%s\n", line); + printf("1 line read from snapshot:\n%s\n", line); rv = 0; i = 0; @@ -331,15 +326,14 @@ addrinfo_read_snapshot_func(struct addrinfo *ai, char *line) return (-1); ai2 = ai; - while ( (s = strsep(&ps, ":")) != NULL) { - ai2->ai_next = (struct addrinfo *)malloc( - sizeof(struct addrinfo)); - assert(ai2->ai_next != NULL); - memset(ai2->ai_next, 0, sizeof(struct addrinfo)); + 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); } @@ -352,39 +346,36 @@ addrinfo_read_snapshot_func(struct addrinfo *ai, char *line) static int addrinfo_test_correctness(struct addrinfo *ai, void *mdata) { - if (debug) { - printf("testing correctness with the following data:\n"); - dump_addrinfo(ai); - } + + 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))) + 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)) + 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)) + 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)) + if (ai->ai_addrlen != ai->ai_addr->sa_len || + ai->ai_family != ai->ai_addr->sa_family) goto errfin; - if (debug) - printf("correct\n"); + printf("correct\n"); return (0); errfin: - if (debug) - printf("incorrect\n"); + printf("incorrect\n"); return (-1); } @@ -395,93 +386,49 @@ addrinfo_read_hostlist_func(struct addrinfo *ai, char *line) struct addrinfo *result; int rv; - if (debug) - printf("resolving %s: ", line); + printf("resolving %s: ", line); rv = getaddrinfo(line, NULL, &hints, &result); if (rv == 0) { - if (debug) - printf("found\n"); + 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 { - if (debug) - printf("not found\n"); + printf("not found\n"); memset(ai, 0, sizeof(struct addrinfo)); } return (0); } -static void -usage(void) -{ - (void)fprintf(stderr, - "Usage: %s [-d] [-46] [-s <file]> -f <file>\n", - getprogname()); - exit(1); -} - -int -main(int argc, char **argv) +void +run_tests(char *hostlist_file, char *snapshot_file, int ai_family) { struct addrinfo_test_data td, td_snap; - char *snapshot_file, *hostlist_file; int rv; - int c; - if (argc < 2) - usage(); - - snapshot_file = NULL; - hostlist_file = NULL; memset(&hints, 0, sizeof(struct addrinfo)); - hints.ai_family = PF_UNSPEC; + hints.ai_family = ai_family; hints.ai_flags = AI_CANONNAME; - while ((c = getopt(argc, argv, "46dns:f:")) != -1) - switch (c) { - case '4': - hints.ai_family = PF_INET; - break; - case '6': - hints.ai_family = PF_INET6; - break; - case 'd': - debug = 1; - break; - case 's': - snapshot_file = strdup(optarg); - method = TEST_BUILD_SNAPSHOT; - break; - case 'f': - hostlist_file = strdup(optarg); - break; - default: - usage(); - } + + 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); - if (hostlist_file == NULL) - usage(); + ATF_REQUIRE_MSG(access(hostlist_file, R_OK) == 0, + "can't access the hostlist file %s\n", hostlist_file); - if (access(hostlist_file, R_OK) != 0) { - if (debug) - printf("can't access the hostlist file %s\n", - hostlist_file); - - usage(); - } - - if (debug) - printf("building host lists from %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); @@ -493,9 +440,8 @@ main(int argc, char **argv) if (errno == ENOENT) method = TEST_BUILD_SNAPSHOT; else { - if (debug) - printf("can't access the snapshot file %s\n", - snapshot_file); + printf("can't access the snapshot " + "file %s\n", snapshot_file); rv = -1; goto fin; @@ -504,8 +450,8 @@ main(int argc, char **argv) rv = TEST_SNAPSHOT_FILE_READ(addrinfo, snapshot_file, &td_snap, addrinfo_read_snapshot_func); if (rv != 0) { - if (debug) - printf("error reading snapshot file\n"); + printf("error reading snapshot file: %s\n", + strerror(errno)); goto fin; } } @@ -514,26 +460,97 @@ main(int argc, char **argv) switch (method) { case TEST_GETADDRINFO: if (snapshot_file != NULL) - rv = DO_2PASS_TEST(addrinfo, &td, &td_snap, - compare_addrinfo, NULL); + ATF_CHECK(DO_2PASS_TEST(addrinfo, &td, &td_snap, + compare_addrinfo, NULL) == 0); break; case TEST_BUILD_SNAPSHOT: if (snapshot_file != NULL) { - rv = TEST_SNAPSHOT_FILE_WRITE(addrinfo, snapshot_file, &td, - sdump_addrinfo); + ATF_CHECK(TEST_SNAPSHOT_FILE_WRITE(addrinfo, + snapshot_file, &td, sdump_addrinfo) == 0); } break; default: - rv = 0; break; - }; + } fin: TEST_DATA_DESTROY(addrinfo, &td_snap); TEST_DATA_DESTROY(addrinfo, &td); + free(hostlist_file); free(snapshot_file); - return (rv); +} + +#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/tools/regression/lib/libc/nss/test-getgr.c b/lib/libc/tests/nss/getgr_test.c index 0ccebae..d9851ef 100644 --- a/tools/regression/lib/libc/nss/test-getgr.c +++ b/lib/libc/tests/nss/getgr_test.c @@ -29,7 +29,6 @@ __FBSDID("$FreeBSD$"); #include <arpa/inet.h> -#include <assert.h> #include <errno.h> #include <grp.h> #include <stdio.h> @@ -37,17 +36,19 @@ __FBSDID("$FreeBSD$"); #include <string.h> #include <stringlist.h> #include <unistd.h> + +#include <atf-c.h> + #include "testutil.h" enum test_methods { - TEST_GETGRENT, - TEST_GETGRNAM, - TEST_GETGRGID, - TEST_GETGRENT_2PASS, - TEST_BUILD_SNAPSHOT + TEST_GETGRENT = 1, + TEST_GETGRNAM = 2, + TEST_GETGRGID = 4, + TEST_GETGRENT_2PASS = 8, + TEST_BUILD_SNAPSHOT = 16, }; -static int debug = 0; static enum test_methods method = TEST_BUILD_SNAPSHOT; DECLARE_TEST_DATA(group) @@ -71,8 +72,6 @@ static int group_test_getgrnam(struct group *, void *); static int group_test_getgrgid(struct group *, void *); static int group_test_getgrent(struct group *, void *); -static void usage(void) __attribute__((__noreturn__)); - IMPLEMENT_TEST_DATA(group) IMPLEMENT_TEST_FILE_SNAPSHOT(group) IMPLEMENT_1PASS_TEST(group) @@ -81,8 +80,8 @@ IMPLEMENT_2PASS_TEST(group) static void clone_group(struct group *dest, struct group const *src) { - assert(dest != NULL); - assert(src != NULL); + ATF_REQUIRE(dest != NULL); + ATF_REQUIRE(src != NULL); char **cp; int members_num; @@ -91,12 +90,12 @@ clone_group(struct group *dest, struct group const *src) if (src->gr_name != NULL) { dest->gr_name = strdup(src->gr_name); - assert(dest->gr_name != NULL); + ATF_REQUIRE(dest->gr_name != NULL); } if (src->gr_passwd != NULL) { dest->gr_passwd = strdup(src->gr_passwd); - assert(dest->gr_passwd != NULL); + ATF_REQUIRE(dest->gr_passwd != NULL); } dest->gr_gid = src->gr_gid; @@ -105,14 +104,12 @@ clone_group(struct group *dest, struct group const *src) for (cp = src->gr_mem; *cp; ++cp) ++members_num; - dest->gr_mem = (char **)malloc( - (members_num + 1) * (sizeof(char *))); - assert(dest->gr_mem != NULL); - memset(dest->gr_mem, 0, (members_num+1) * (sizeof(char *))); + 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); - assert(dest->gr_mem[cp - src->gr_mem] != NULL); + ATF_REQUIRE(dest->gr_mem[cp - src->gr_mem] != NULL); } } } @@ -122,7 +119,7 @@ free_group(struct group *grp) { char **cp; - assert(grp != NULL); + ATF_REQUIRE(grp != NULL); free(grp->gr_name); free(grp->gr_passwd); @@ -140,31 +137,31 @@ compare_group(struct group *grp1, struct group *grp2, void *mdata) if (grp1 == grp2) return (0); - if ((grp1 == NULL) || (grp2 == NULL)) + 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)) + 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)) + if (grp1->gr_mem == NULL || grp2->gr_mem == NULL) goto errfin; - for (;*c1 && *c2; ++c1, ++c2) + for (; *c1 && *c2; ++c1, ++c2) if (strcmp(*c1, *c2) != 0) goto errfin; - if ((*c1 != '\0') || (*c2 != '\0')) + if (*c1 != '\0' || *c2 != '\0') goto errfin; return 0; errfin: - if ((debug) && (mdata == NULL)) { + if (mdata == NULL) { printf("following structures are not equal:\n"); dump_group(grp1); dump_group(grp2); @@ -211,54 +208,55 @@ group_read_snapshot_func(struct group *grp, char *line) char *s, *ps, *ts; int i; - if (debug) - printf("1 line read from snapshot:\n%s\n", line); + 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) { + while ((s = strsep(&ps, " ")) != NULL) { switch (i) { - case 0: - grp->gr_name = strdup(s); - assert(grp->gr_name != NULL); + case 0: + grp->gr_name = strdup(s); + ATF_REQUIRE(grp->gr_name != NULL); break; - case 1: - grp->gr_passwd = strdup(s); - assert(grp->gr_passwd != NULL); + 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); - return (-1); - } + 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); + default: + if (sl == NULL) { + if (strcmp(s, "(null)") == 0) + return (0); - sl = sl_init(); - assert(sl != NULL); + sl = sl_init(); + ATF_REQUIRE(sl != NULL); - if (strcmp(s, "nomem") != 0) { - ts = strdup(s); - assert(ts != NULL); - sl_add(sl, ts); - } - } else { + if (strcmp(s, "nomem") != 0) { ts = strdup(s); - assert(ts != NULL); + ATF_REQUIRE(ts != NULL); sl_add(sl, ts); } + } else { + ts = strdup(s); + ATF_REQUIRE(ts != NULL); + sl_add(sl, ts); + } break; - }; + } ++i; } @@ -308,10 +306,8 @@ group_fill_test_data(struct group_test_data *td) static int group_test_correctness(struct group *grp, void *mdata) { - if (debug) { - printf("testing correctness with the following data:\n"); - dump_group(grp); - } + printf("testing correctness with the following data:\n"); + dump_group(grp); if (grp == NULL) goto errfin; @@ -325,13 +321,11 @@ group_test_correctness(struct group *grp, void *mdata) if (grp->gr_mem == NULL) goto errfin; - if (debug) - printf("correct\n"); + printf("correct\n"); return (0); errfin: - if (debug) - printf("incorrect\n"); + printf("incorrect\n"); return (-1); } @@ -352,28 +346,20 @@ group_test_getgrnam(struct group *grp_model, void *mdata) { struct group *grp; - if (debug) { - printf("testing getgrnam() with the following data:\n"); - dump_group(grp_model); - } + 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)) + if (compare_group(grp, grp_model, NULL) != 0 && + group_check_ambiguity((struct group_test_data *)mdata, grp) != 0) goto errfin; - if (debug) - printf("ok\n"); return (0); errfin: - if (debug) - printf("not ok\n"); - return (-1); } @@ -382,23 +368,16 @@ group_test_getgrgid(struct group *grp_model, void *mdata) { struct group *grp; - if (debug) { - printf("testing getgrgid() with the following data...\n"); - dump_group(grp_model); - } + 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))) { - if (debug) - printf("not ok\n"); - return (-1); + 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 { - if (debug) - printf("ok\n"); - return (0); + return (0); } } @@ -410,50 +389,11 @@ group_test_getgrent(struct group *grp, void *mdata) return (group_test_correctness(grp, NULL)); } -static void -usage(void) -{ - (void)fprintf(stderr, - "Usage: %s -nge2 [-d] [-s <file>]\n", - getprogname()); - exit(1); -} - -int -main(int argc, char **argv) +static int +run_tests(const char *snapshot_file, enum test_methods method) { struct group_test_data td, td_snap, td_2pass; - char *snapshot_file; int rv; - int c; - - if (argc < 2) - usage(); - - snapshot_file = NULL; - while ((c = getopt(argc, argv, "nge2ds:")) != -1) - switch (c) { - case 'd': - debug++; - break; - case 'n': - method = TEST_GETGRNAM; - break; - case 'g': - method = TEST_GETGRGID; - break; - case 'e': - method = TEST_GETGRENT; - break; - case '2': - method = TEST_GETGRENT_2PASS; - break; - case 's': - snapshot_file = strdup(optarg); - break; - default: - usage(); - } TEST_DATA_INIT(group, &td, clone_group, free_group); TEST_DATA_INIT(group, &td_snap, clone_group, free_group); @@ -462,9 +402,8 @@ main(int argc, char **argv) if (errno == ENOENT) method = TEST_BUILD_SNAPSHOT; else { - if (debug) - printf("can't access the file %s\n", - snapshot_file); + printf("can't access the file %s\n", + snapshot_file); rv = -1; goto fin; @@ -518,17 +457,85 @@ main(int argc, char **argv) break; case TEST_BUILD_SNAPSHOT: if (snapshot_file != NULL) - rv = TEST_SNAPSHOT_FILE_WRITE(group, snapshot_file, &td, - sdump_group); + 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); - free(snapshot_file); + 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 <bushman@freebsd.org> + * 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 <sys/cdefs.h> +__FBSDID("$FreeBSD$"); + +#include <sys/param.h> +#include <sys/socket.h> +#include <arpa/inet.h> +#include <netinet/in.h> +#include <errno.h> +#include <netdb.h> +#include <resolv.h> +#include <stdio.h> +#include <stdlib.h> +#include <string.h> +#include <stringlist.h> +#include <unistd.h> + +#include <atf-c.h> + +#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/tools/regression/lib/libc/nss/test-getproto.c b/lib/libc/tests/nss/getproto_test.c index a3ba271..fdb6804 100644 --- a/tools/regression/lib/libc/nss/test-getproto.c +++ b/lib/libc/tests/nss/getproto_test.c @@ -37,6 +37,9 @@ __FBSDID("$FreeBSD$"); #include <string.h> #include <stringlist.h> #include <unistd.h> + +#include <atf-c.h> + #include "testutil.h" enum test_methods { @@ -47,9 +50,6 @@ enum test_methods { TEST_BUILD_SNAPSHOT }; -static int debug = 0; -static enum test_methods method = TEST_BUILD_SNAPSHOT; - DECLARE_TEST_DATA(protoent) DECLARE_TEST_FILE_SNAPSHOT(protoent) DECLARE_1PASS_TEST(protoent) @@ -71,8 +71,6 @@ static int protoent_test_getprotobyname(struct protoent *, void *); static int protoent_test_getprotobynumber(struct protoent *, void *); static int protoent_test_getprotoent(struct protoent *, void *); -static void usage(void) __attribute__((__noreturn__)); - IMPLEMENT_TEST_DATA(protoent) IMPLEMENT_TEST_FILE_SNAPSHOT(protoent) IMPLEMENT_1PASS_TEST(protoent) @@ -101,9 +99,8 @@ clone_protoent(struct protoent *dest, struct protoent const *src) for (cp = src->p_aliases; *cp; ++cp) ++aliases_num; - dest->p_aliases = (char **)malloc((aliases_num+1) * (sizeof(char *))); + dest->p_aliases = calloc(1, (aliases_num+1) * sizeof(char *)); assert(dest->p_aliases != NULL); - memset(dest->p_aliases, 0, (aliases_num+1) * (sizeof(char *))); for (cp = src->p_aliases; *cp; ++cp) { dest->p_aliases[cp - src->p_aliases] = strdup(*cp); @@ -157,7 +154,7 @@ compare_protoent(struct protoent *pe1, struct protoent *pe2, void *mdata) return 0; errfin: - if ((debug) && (mdata == NULL)) { + if (mdata == NULL) { printf("following structures are not equal:\n"); dump_protoent(pe1); dump_protoent(pe2); @@ -204,8 +201,7 @@ protoent_read_snapshot_func(struct protoent *pe, char *line) char *s, *ps, *ts; int i; - if (debug) - printf("1 line read from snapshot:\n%s\n", line); + printf("1 line read from snapshot:\n%s\n", line); i = 0; sl = NULL; @@ -245,7 +241,7 @@ protoent_read_snapshot_func(struct protoent *pe, char *line) sl_add(sl, ts); } break; - }; + } ++i; } @@ -294,10 +290,8 @@ protoent_fill_test_data(struct protoent_test_data *td) static int protoent_test_correctness(struct protoent *pe, void *mdata) { - if (debug) { - printf("testing correctness with the following data:\n"); - dump_protoent(pe); - } + printf("testing correctness with the following data:\n"); + dump_protoent(pe); if (pe == NULL) goto errfin; @@ -311,13 +305,11 @@ protoent_test_correctness(struct protoent *pe, void *mdata) if (pe->p_aliases == NULL) goto errfin; - if (debug) - printf("correct\n"); + printf("correct\n"); return (0); errfin: - if (debug) - printf("incorrect\n"); + printf("incorrect\n"); return (-1); } @@ -341,10 +333,8 @@ protoent_test_getprotobyname(struct protoent *pe_model, void *mdata) char **alias; struct protoent *pe; - if (debug) { - printf("testing getprotobyname() with the following data:\n"); - dump_protoent(pe_model); - } + 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) @@ -367,13 +357,11 @@ protoent_test_getprotobyname(struct protoent *pe_model, void *mdata) goto errfin; } - if (debug) - printf("ok\n"); + printf("ok\n"); return (0); errfin: - if (debug) - printf("not ok\n"); + printf("not ok\n"); return (-1); } @@ -383,23 +371,19 @@ protoent_test_getprotobynumber(struct protoent *pe_model, void *mdata) { struct protoent *pe; - if (debug) { - printf("testing getprotobyport() with the following data...\n"); - dump_protoent(pe_model); - } + 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))) { - if (debug) printf("not ok\n"); - return (-1); + return (-1); } else { - if (debug) printf("ok\n"); - return (0); + return (0); } } @@ -411,50 +395,11 @@ protoent_test_getprotoent(struct protoent *pe, void *mdata) return (protoent_test_correctness(pe, NULL)); } -static void -usage(void) -{ - (void)fprintf(stderr, - "Usage: %s -nve2 [-d] [-s <file>]\n", - getprogname()); - exit(1); -} - int -main(int argc, char **argv) +run_tests(const char *snapshot_file, enum test_methods method) { struct protoent_test_data td, td_snap, td_2pass; - char *snapshot_file; int rv; - int c; - - if (argc < 2) - usage(); - - snapshot_file = NULL; - while ((c = getopt(argc, argv, "nve2ds:")) != -1) - switch (c) { - case 'd': - debug++; - break; - case 'n': - method = TEST_GETPROTOBYNAME; - break; - case 'v': - method = TEST_GETPROTOBYNUMBER; - break; - case 'e': - method = TEST_GETPROTOENT; - break; - case '2': - method = TEST_GETPROTOENT_2PASS; - break; - case 's': - snapshot_file = strdup(optarg); - break; - default: - usage(); - } TEST_DATA_INIT(protoent, &td, clone_protoent, free_protoent); TEST_DATA_INIT(protoent, &td_snap, clone_protoent, free_protoent); @@ -463,9 +408,8 @@ main(int argc, char **argv) if (errno == ENOENT) method = TEST_BUILD_SNAPSHOT; else { - if (debug) - printf("can't access the file %s\n", - snapshot_file); + printf("can't access the file %s\n", + snapshot_file); rv = -1; goto fin; @@ -510,27 +454,103 @@ main(int argc, char **argv) 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); + 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); + 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); - free(snapshot_file); + 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/tools/regression/lib/libc/nss/test-getpw.c b/lib/libc/tests/nss/getpw_test.c index a0b348d..98f890f 100644 --- a/tools/regression/lib/libc/nss/test-getpw.c +++ b/lib/libc/tests/nss/getpw_test.c @@ -28,13 +28,15 @@ #include <sys/cdefs.h> __FBSDID("$FreeBSD$"); -#include <assert.h> #include <errno.h> #include <pwd.h> #include <stdio.h> #include <stdlib.h> #include <string.h> #include <unistd.h> + +#include <atf-c.h> + #include "testutil.h" enum test_methods { @@ -45,7 +47,6 @@ enum test_methods { TEST_BUILD_SNAPSHOT }; -static int debug = 0; static enum test_methods method = TEST_BUILD_SNAPSHOT; DECLARE_TEST_DATA(passwd) @@ -69,8 +70,6 @@ static int passwd_test_getpwnam(struct passwd *, void *); static int passwd_test_getpwuid(struct passwd *, void *); static int passwd_test_getpwent(struct passwd *, void *); -static void usage(void) __attribute__((__noreturn__)); - IMPLEMENT_TEST_DATA(passwd) IMPLEMENT_TEST_FILE_SNAPSHOT(passwd) IMPLEMENT_1PASS_TEST(passwd) @@ -79,8 +78,8 @@ IMPLEMENT_2PASS_TEST(passwd) static void clone_passwd(struct passwd *dest, struct passwd const *src) { - assert(dest != NULL); - assert(src != NULL); + ATF_REQUIRE(dest != NULL); + ATF_REQUIRE(src != NULL); memcpy(dest, src, sizeof(struct passwd)); if (src->pw_name != NULL) @@ -100,24 +99,23 @@ clone_passwd(struct passwd *dest, struct passwd const *src) static int compare_passwd(struct passwd *pwd1, struct passwd *pwd2, void *mdata) { - assert(pwd1 != NULL); - assert(pwd2 != NULL); + 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) - ) + 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); @@ -137,10 +135,11 @@ free_passwd(struct passwd *pwd) static void sdump_passwd(struct passwd *pwd, char *buffer, size_t buflen) { - snprintf(buffer, buflen, "%s:%s:%d:%d:%d:%s:%s:%s:%s:%d:%d", - pwd->pw_name, pwd->pw_passwd, pwd->pw_uid, pwd->pw_gid, - pwd->pw_change, pwd->pw_class, pwd->pw_gecos, pwd->pw_dir, - pwd->pw_shell, pwd->pw_expire, pwd->pw_fields); + 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 @@ -160,66 +159,67 @@ passwd_read_snapshot_func(struct passwd *pwd, char *line) char *s, *ps, *ts; int i; - if (debug) - printf("1 line read from snapshot:\n%s\n", line); +#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) { + while ((s = strsep(&ps, ":")) != NULL) { switch (i) { - case 0: - pwd->pw_name = strdup(s); - assert(pwd->pw_name != NULL); + case 0: + pwd->pw_name = strdup(s); + ATF_REQUIRE(pwd->pw_name != NULL); break; - case 1: - pwd->pw_passwd = strdup(s); - assert(pwd->pw_passwd != NULL); + 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; + 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; + 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; + case 4: + pwd->pw_change = (time_t)strtol(s, &ts, 10); + if (*ts != '\0') + goto fin; break; - case 5: - pwd->pw_class = strdup(s); - assert(pwd->pw_class != NULL); + case 5: + pwd->pw_class = strdup(s); + ATF_REQUIRE(pwd->pw_class != NULL); break; - case 6: - pwd->pw_gecos = strdup(s); - assert(pwd->pw_gecos != NULL); + case 6: + pwd->pw_gecos = strdup(s); + ATF_REQUIRE(pwd->pw_gecos != NULL); break; - case 7: - pwd->pw_dir = strdup(s); - assert(pwd->pw_dir != NULL); + case 7: + pwd->pw_dir = strdup(s); + ATF_REQUIRE(pwd->pw_dir != NULL); break; - case 8: - pwd->pw_shell = strdup(s); - assert(pwd->pw_shell != NULL); + 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; + 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; + case 10: + pwd->pw_fields = (int)strtol(s, &ts, 10); + if (*ts != '\0') + goto fin; break; - default: + default: break; - }; + } ++i; } @@ -253,10 +253,11 @@ passwd_fill_test_data(struct passwd_test_data *td) static int passwd_test_correctness(struct passwd *pwd, void *mdata) { - if (debug) { - printf("testing correctness with the following data:\n"); - dump_passwd(pwd); - } + +#ifdef DEBUG + printf("testing correctness with the following data:\n"); + dump_passwd(pwd); +#endif if (pwd == NULL) return (-1); @@ -279,13 +280,15 @@ passwd_test_correctness(struct passwd *pwd, void *mdata) if (pwd->pw_shell == NULL) goto errfin; - if (debug) - printf("correct\n"); +#ifdef DEBUG + printf("correct\n"); +#endif return (0); errfin: - if (debug) - printf("incorrect\n"); +#ifdef DEBUG + printf("incorrect\n"); +#endif return (-1); } @@ -306,10 +309,10 @@ passwd_test_getpwnam(struct passwd *pwd_model, void *mdata) { struct passwd *pwd; - if (debug) { - printf("testing getpwnam() with the following data:\n"); - dump_passwd(pwd_model); - } +#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) @@ -320,14 +323,15 @@ passwd_test_getpwnam(struct passwd *pwd_model, void *mdata) !=0)) goto errfin; - if (debug) - printf("ok\n"); +#ifdef DEBUG + printf("ok\n"); +#endif return (0); errfin: - if (debug) - printf("not ok\n"); - +#ifdef DEBUG + printf("not ok\n"); +#endif return (-1); } @@ -336,23 +340,25 @@ passwd_test_getpwuid(struct passwd *pwd_model, void *mdata) { struct passwd *pwd; - if (debug) { - printf("testing getpwuid() with the following data...\n"); - dump_passwd(pwd_model); - } +#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))) { - if (debug) +#ifdef DEBUG printf("not ok\n"); - return (-1); +#endif + return (-1); } else { - if (debug) +#ifdef DEBUG printf("ok\n"); - return (0); +#endif + return (0); } } @@ -364,50 +370,11 @@ passwd_test_getpwent(struct passwd *pwd, void *mdata) return (passwd_test_correctness(pwd, NULL)); } -static void -usage(void) -{ - (void)fprintf(stderr, - "Usage: %s -nue2 [-d] [-s <file>]\n", - getprogname()); - exit(1); -} - -int -main(int argc, char **argv) +static int +run_tests(const char *snapshot_file, enum test_methods method) { struct passwd_test_data td, td_snap, td_2pass; - char *snapshot_file; int rv; - int c; - - if (argc < 2) - usage(); - - snapshot_file = NULL; - while ((c = getopt(argc, argv, "nue2ds:")) != -1) - switch (c) { - case 'd': - debug++; - break; - case 'n': - method = TEST_GETPWNAM; - break; - case 'u': - method = TEST_GETPWUID; - break; - case 'e': - method = TEST_GETPWENT; - break; - case '2': - method = TEST_GETPWENT_2PASS; - break; - case 's': - snapshot_file = strdup(optarg); - break; - default: - usage(); - } TEST_DATA_INIT(passwd, &td, clone_passwd, free_passwd); TEST_DATA_INIT(passwd, &td_snap, clone_passwd, free_passwd); @@ -416,10 +383,8 @@ main(int argc, char **argv) if (errno == ENOENT) method = TEST_BUILD_SNAPSHOT; else { - if (debug) - printf("can't access the file %s\n", - snapshot_file); - + printf("can't access the file %s\n", + snapshot_file); rv = -1; goto fin; } @@ -464,26 +429,102 @@ main(int argc, char **argv) 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); + 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); + 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); - free(snapshot_file); + 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/tools/regression/lib/libc/nss/test-getrpc.c b/lib/libc/tests/nss/getrpc_test.c index 707186e..89de986 100644 --- a/tools/regression/lib/libc/nss/test-getrpc.c +++ b/lib/libc/tests/nss/getrpc_test.c @@ -30,13 +30,15 @@ __FBSDID("$FreeBSD$"); #include <arpa/inet.h> #include <rpc/rpc.h> -#include <assert.h> #include <errno.h> #include <stdio.h> #include <stdlib.h> #include <string.h> #include <stringlist.h> #include <unistd.h> + +#include <atf-c.h> + #include "testutil.h" enum test_methods { @@ -47,9 +49,6 @@ enum test_methods { TEST_BUILD_SNAPSHOT }; -static int debug = 0; -static enum test_methods method = TEST_BUILD_SNAPSHOT; - DECLARE_TEST_DATA(rpcent) DECLARE_TEST_FILE_SNAPSHOT(rpcent) DECLARE_1PASS_TEST(rpcent) @@ -81,8 +80,8 @@ IMPLEMENT_2PASS_TEST(rpcent) static void clone_rpcent(struct rpcent *dest, struct rpcent const *src) { - assert(dest != NULL); - assert(src != NULL); + ATF_REQUIRE(dest != NULL); + ATF_REQUIRE(src != NULL); char **cp; int aliases_num; @@ -91,7 +90,7 @@ clone_rpcent(struct rpcent *dest, struct rpcent const *src) if (src->r_name != NULL) { dest->r_name = strdup(src->r_name); - assert(dest->r_name != NULL); + ATF_REQUIRE(dest->r_name != NULL); } dest->r_number = src->r_number; @@ -101,13 +100,12 @@ clone_rpcent(struct rpcent *dest, struct rpcent const *src) for (cp = src->r_aliases; *cp; ++cp) ++aliases_num; - dest->r_aliases = (char **)malloc((aliases_num+1) * (sizeof(char *))); - assert(dest->r_aliases != NULL); - memset(dest->r_aliases, 0, (aliases_num+1) * (sizeof(char *))); + 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); - assert(dest->r_aliases[cp - src->r_aliases] != NULL); + ATF_REQUIRE(dest->r_aliases[cp - src->r_aliases] != NULL); } } } @@ -117,7 +115,7 @@ free_rpcent(struct rpcent *rpc) { char **cp; - assert(rpc != NULL); + ATF_REQUIRE(rpc != NULL); free(rpc->r_name); @@ -157,7 +155,7 @@ compare_rpcent(struct rpcent *rpc1, struct rpcent *rpc2, void *mdata) return 0; errfin: - if ((debug) && (mdata == NULL)) { + if (mdata == NULL) { printf("following structures are not equal:\n"); dump_rpcent(rpc1); dump_rpcent(rpc2); @@ -204,49 +202,48 @@ rpcent_read_snapshot_func(struct rpcent *rpc, char *line) char *s, *ps, *ts; int i; - if (debug) - printf("1 line read from snapshot:\n%s\n", line); + 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) { + while ((s = strsep(&ps, " ")) != NULL) { switch (i) { - case 0: + case 0: rpc->r_name = strdup(s); - assert(rpc->r_name != NULL); + 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); - } + 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); + default: + if (sl == NULL) { + if (strcmp(s, "(null)") == 0) + return (0); - sl = sl_init(); - assert(sl != NULL); + sl = sl_init(); + ATF_REQUIRE(sl != NULL); - if (strcmp(s, "noaliases") != 0) { - ts = strdup(s); - assert(ts != NULL); - sl_add(sl, ts); - } - } else { + if (strcmp(s, "noaliases") != 0) { ts = strdup(s); - assert(ts != NULL); + ATF_REQUIRE(ts != NULL); sl_add(sl, ts); } + } else { + ts = strdup(s); + ATF_REQUIRE(ts != NULL); + sl_add(sl, ts); + } break; - }; - ++i; + } + i++; } if (i < 3) { @@ -294,10 +291,9 @@ rpcent_fill_test_data(struct rpcent_test_data *td) static int rpcent_test_correctness(struct rpcent *rpc, void *mdata) { - if (debug) { - printf("testing correctness with the following data:\n"); - dump_rpcent(rpc); - } + + printf("testing correctness with the following data:\n"); + dump_rpcent(rpc); if (rpc == NULL) goto errfin; @@ -311,13 +307,11 @@ rpcent_test_correctness(struct rpcent *rpc, void *mdata) if (rpc->r_aliases == NULL) goto errfin; - if (debug) - printf("correct\n"); + printf("correct\n"); return (0); errfin: - if (debug) - printf("incorrect\n"); + printf("incorrect\n"); return (-1); } @@ -341,10 +335,8 @@ rpcent_test_getrpcbyname(struct rpcent *rpc_model, void *mdata) char **alias; struct rpcent *rpc; - if (debug) { - printf("testing getrpcbyname() with the following data:\n"); - dump_rpcent(rpc_model); - } + 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) @@ -367,13 +359,11 @@ rpcent_test_getrpcbyname(struct rpcent *rpc_model, void *mdata) goto errfin; } - if (debug) - printf("ok\n"); + printf("ok\n"); return (0); errfin: - if (debug) - printf("not ok\n"); + printf("not ok\n"); return (-1); } @@ -383,78 +373,38 @@ rpcent_test_getrpcbynumber(struct rpcent *rpc_model, void *mdata) { struct rpcent *rpc; - if (debug) { - printf("testing getrpcbyport() with the following data...\n"); - dump_rpcent(rpc_model); - } + 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))) { - if (debug) + 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); + return (-1); } else { - if (debug) printf("ok\n"); - return (0); + 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)); -} -static void -usage(void) -{ - (void)fprintf(stderr, - "Usage: %s -nve2 [-d] [-s <file>]\n", - getprogname()); - exit(1); + /* + * Only correctness can be checked when doing 1-pass test for + * getrpcent(). + */ + return (rpcent_test_correctness(rpc, NULL)); } int -main(int argc, char **argv) +run_tests(const char *snapshot_file, enum test_methods method) { struct rpcent_test_data td, td_snap, td_2pass; - char *snapshot_file; int rv; - int c; - - if (argc < 2) - usage(); - - snapshot_file = NULL; - while ((c = getopt(argc, argv, "nve2ds:")) != -1) - switch (c) { - case 'd': - debug++; - break; - case 'n': - method = TEST_GETRPCBYNAME; - break; - case 'v': - method = TEST_GETRPCBYNUMBER; - break; - case 'e': - method = TEST_GETRPCENT; - break; - case '2': - method = TEST_GETRPCENT_2PASS; - break; - case 's': - snapshot_file = strdup(optarg); - break; - default: - usage(); - } TEST_DATA_INIT(rpcent, &td, clone_rpcent, free_rpcent); TEST_DATA_INIT(rpcent, &td_snap, clone_rpcent, free_rpcent); @@ -463,9 +413,8 @@ main(int argc, char **argv) if (errno == ENOENT) method = TEST_BUILD_SNAPSHOT; else { - if (debug) - printf("can't access the file %s\n", - snapshot_file); + printf("can't access the file %s\n", + snapshot_file); rv = -1; goto fin; @@ -525,11 +474,87 @@ main(int argc, char **argv) default: rv = 0; break; - }; + } fin: TEST_DATA_DESTROY(rpcent, &td_snap); TEST_DATA_DESTROY(rpcent, &td); - free(snapshot_file); + 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/tools/regression/lib/libc/nss/test-getserv.c b/lib/libc/tests/nss/getserv_test.c index 31e4700..29c1dfa 100644 --- a/tools/regression/lib/libc/nss/test-getserv.c +++ b/lib/libc/tests/nss/getserv_test.c @@ -29,7 +29,6 @@ __FBSDID("$FreeBSD$"); #include <arpa/inet.h> -#include <assert.h> #include <errno.h> #include <netdb.h> #include <stdio.h> @@ -37,6 +36,9 @@ __FBSDID("$FreeBSD$"); #include <string.h> #include <stringlist.h> #include <unistd.h> + +#include <atf-c.h> + #include "testutil.h" enum test_methods { @@ -47,9 +49,6 @@ enum test_methods { TEST_BUILD_SNAPSHOT }; -static int debug = 0; -static enum test_methods method = TEST_BUILD_SNAPSHOT; - DECLARE_TEST_DATA(servent) DECLARE_TEST_FILE_SNAPSHOT(servent) DECLARE_1PASS_TEST(servent) @@ -71,8 +70,6 @@ static int servent_test_getservbyname(struct servent *, void *); static int servent_test_getservbyport(struct servent *, void *); static int servent_test_getservent(struct servent *, void *); -static void usage(void) __attribute__((__noreturn__)); - IMPLEMENT_TEST_DATA(servent) IMPLEMENT_TEST_FILE_SNAPSHOT(servent) IMPLEMENT_1PASS_TEST(servent) @@ -81,8 +78,8 @@ IMPLEMENT_2PASS_TEST(servent) static void clone_servent(struct servent *dest, struct servent const *src) { - assert(dest != NULL); - assert(src != NULL); + ATF_REQUIRE(dest != NULL); + ATF_REQUIRE(src != NULL); char **cp; int aliases_num; @@ -91,12 +88,12 @@ clone_servent(struct servent *dest, struct servent const *src) if (src->s_name != NULL) { dest->s_name = strdup(src->s_name); - assert(dest->s_name != NULL); + ATF_REQUIRE(dest->s_name != NULL); } if (src->s_proto != NULL) { dest->s_proto = strdup(src->s_proto); - assert(dest->s_proto != NULL); + ATF_REQUIRE(dest->s_proto != NULL); } dest->s_port = src->s_port; @@ -105,13 +102,12 @@ clone_servent(struct servent *dest, struct servent const *src) for (cp = src->s_aliases; *cp; ++cp) ++aliases_num; - dest->s_aliases = (char **)malloc((aliases_num+1) * (sizeof(char *))); - assert(dest->s_aliases != NULL); - memset(dest->s_aliases, 0, (aliases_num+1) * (sizeof(char *))); + 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); - assert(dest->s_aliases[cp - src->s_aliases] != NULL); + ATF_REQUIRE(dest->s_aliases[cp - src->s_aliases] != NULL); } } } @@ -121,7 +117,7 @@ free_servent(struct servent *serv) { char **cp; - assert(serv != NULL); + ATF_REQUIRE(serv != NULL); free(serv->s_name); free(serv->s_proto); @@ -163,7 +159,7 @@ compare_servent(struct servent *serv1, struct servent *serv2, void *mdata) return 0; errfin: - if ((debug) && (mdata == NULL)) { + if (mdata == NULL) { printf("following structures are not equal:\n"); dump_servent(serv1); dump_servent(serv2); @@ -210,8 +206,7 @@ servent_read_snapshot_func(struct servent *serv, char *line) char *s, *ps, *ts; int i; - if (debug) - printf("1 line read from snapshot:\n%s\n", line); + printf("1 line read from snapshot:\n%s\n", line); i = 0; sl = NULL; @@ -221,7 +216,7 @@ servent_read_snapshot_func(struct servent *serv, char *line) switch (i) { case 0: serv->s_name = strdup(s); - assert(serv->s_name != NULL); + ATF_REQUIRE(serv->s_name != NULL); break; case 1: @@ -235,7 +230,7 @@ servent_read_snapshot_func(struct servent *serv, char *line) case 2: serv->s_proto = strdup(s); - assert(serv->s_proto != NULL); + ATF_REQUIRE(serv->s_proto != NULL); break; default: @@ -244,20 +239,20 @@ servent_read_snapshot_func(struct servent *serv, char *line) return (0); sl = sl_init(); - assert(sl != NULL); + ATF_REQUIRE(sl != NULL); if (strcmp(s, "noaliases") != 0) { ts = strdup(s); - assert(ts != NULL); + ATF_REQUIRE(ts != NULL); sl_add(sl, ts); } } else { ts = strdup(s); - assert(ts != NULL); + ATF_REQUIRE(ts != NULL); sl_add(sl, ts); } break; - }; + } ++i; } @@ -307,10 +302,8 @@ servent_fill_test_data(struct servent_test_data *td) static int servent_test_correctness(struct servent *serv, void *mdata) { - if (debug) { - printf("testing correctness with the following data:\n"); - dump_servent(serv); - } + printf("testing correctness with the following data:\n"); + dump_servent(serv); if (serv == NULL) goto errfin; @@ -327,13 +320,11 @@ servent_test_correctness(struct servent *serv, void *mdata) if (serv->s_aliases == NULL) goto errfin; - if (debug) - printf("correct\n"); + printf("correct\n"); return (0); errfin: - if (debug) - printf("incorrect\n"); + printf("incorrect\n"); return (-1); } @@ -357,10 +348,8 @@ servent_test_getservbyname(struct servent *serv_model, void *mdata) char **alias; struct servent *serv; - if (debug) { - printf("testing getservbyname() with the following data:\n"); - dump_servent(serv_model); - } + 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) @@ -369,7 +358,7 @@ servent_test_getservbyname(struct servent *serv_model, void *mdata) if ((compare_servent(serv, serv_model, NULL) != 0) && (servent_check_ambiguity((struct servent_test_data *)mdata, serv) !=0)) - goto errfin; + goto errfin; for (alias = serv_model->s_aliases; *alias; ++alias) { serv = getservbyname(*alias, serv_model->s_proto); @@ -383,13 +372,11 @@ servent_test_getservbyname(struct servent *serv_model, void *mdata) goto errfin; } - if (debug) - printf("ok\n"); + printf("ok\n"); return (0); errfin: - if (debug) - printf("not ok\n"); + printf("not ok\n"); return (-1); } @@ -399,23 +386,19 @@ servent_test_getservbyport(struct servent *serv_model, void *mdata) { struct servent *serv; - if (debug) { - printf("testing getservbyport() with the following data...\n"); - dump_servent(serv_model); - } + 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))) { - if (debug) printf("not ok\n"); - return (-1); + return (-1); } else { - if (debug) printf("ok\n"); - return (0); + return (0); } } @@ -427,50 +410,11 @@ servent_test_getservent(struct servent *serv, void *mdata) return (servent_test_correctness(serv, NULL)); } -static void -usage(void) -{ - (void)fprintf(stderr, - "Usage: %s -npe2 [-d] [-s <file>]\n", - getprogname()); - exit(1); -} - int -main(int argc, char **argv) +run_tests(const char *snapshot_file, enum test_methods method) { struct servent_test_data td, td_snap, td_2pass; - char *snapshot_file; int rv; - int c; - - if (argc < 2) - usage(); - - snapshot_file = NULL; - while ((c = getopt(argc, argv, "npe2ds:")) != -1) - switch (c) { - case 'd': - debug++; - break; - case 'n': - method = TEST_GETSERVBYNAME; - break; - case 'p': - method = TEST_GETSERVBYPORT; - break; - case 'e': - method = TEST_GETSERVENT; - break; - case '2': - method = TEST_GETSERVENT_2PASS; - break; - case 's': - snapshot_file = strdup(optarg); - break; - default: - usage(); - } TEST_DATA_INIT(servent, &td, clone_servent, free_servent); TEST_DATA_INIT(servent, &td_snap, clone_servent, free_servent); @@ -479,9 +423,8 @@ main(int argc, char **argv) if (errno == ENOENT) method = TEST_BUILD_SNAPSHOT; else { - if (debug) - printf("can't access the file %s\n", - snapshot_file); + printf("can't access the file %s\n", + snapshot_file); rv = -1; goto fin; @@ -541,11 +484,87 @@ main(int argc, char **argv) default: rv = 0; break; - }; + } fin: TEST_DATA_DESTROY(servent, &td_snap); TEST_DATA_DESTROY(servent, &td); - free(snapshot_file); + 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/tools/regression/lib/libc/nss/test-getusershell.c b/lib/libc/tests/nss/getusershell_test.c index b7b835f..ccd8cf9 100644 --- a/tools/regression/lib/libc/nss/test-getusershell.c +++ b/lib/libc/tests/nss/getusershell_test.c @@ -34,6 +34,9 @@ __FBSDID("$FreeBSD$"); #include <stdlib.h> #include <string.h> #include <unistd.h> + +#include <atf-c.h> + #include "testutil.h" enum test_methods { @@ -45,7 +48,6 @@ struct usershell { char *path; }; -static int debug = 0; static enum test_methods method = TEST_GETUSERSHELL; DECLARE_TEST_DATA(usershell) @@ -59,10 +61,6 @@ static void free_usershell(struct usershell *); static void sdump_usershell(struct usershell *, char *, size_t); static void dump_usershell(struct usershell *); -static int usershell_read_snapshot_func(struct usershell *, char *); - -static void usage(void) __attribute__((__noreturn__)); - IMPLEMENT_TEST_DATA(usershell) IMPLEMENT_TEST_FILE_SNAPSHOT(usershell) IMPLEMENT_2PASS_TEST(usershell) @@ -129,69 +127,39 @@ dump_usershell(struct usershell *us) static int usershell_read_snapshot_func(struct usershell *us, char *line) { + us->path = strdup(line); - assert(us->path != NULL); + ATF_REQUIRE(us->path != NULL); return (0); } -static void -usage(void) -{ - (void)fprintf(stderr, - "Usage: %s [-d] -s <file>\n", - getprogname()); - exit(1); -} - int -main(int argc, char **argv) +run_tests(const char *snapshot_file, enum test_methods method) { struct usershell_test_data td, td_snap; struct usershell ushell; - char *snapshot_file; int rv; - int c; - - if (argc < 2) - usage(); rv = 0; - snapshot_file = NULL; - while ((c = getopt(argc, argv, "ds:")) != -1) { - switch (c) { - case 'd': - debug = 1; - break; - case 's': - snapshot_file = strdup(optarg); - break; - default: - usage(); - } - } 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) { - if (debug) { - printf("usershell found:\n"); - dump_usershell(&ushell); - } + 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 { - if (debug) - printf("can't access the snapshot file %s\n", + printf("can't access the snapshot file %s\n", snapshot_file); rv = -1; @@ -201,8 +169,7 @@ main(int argc, char **argv) rv = TEST_SNAPSHOT_FILE_READ(usershell, snapshot_file, &td_snap, usershell_read_snapshot_func); if (rv != 0) { - if (debug) - printf("error reading snapshot file\n"); + printf("error reading snapshot file\n"); goto fin; } } @@ -210,26 +177,49 @@ main(int argc, char **argv) switch (method) { case TEST_GETUSERSHELL: - if (snapshot_file != NULL) { - rv = DO_2PASS_TEST(usershell, &td, &td_snap, - compare_usershell, NULL); - } + 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); + 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); - free(snapshot_file); + 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/tools/regression/lib/libc/nss/testutil.h b/lib/libc/tests/nss/testutil.h index 711c49f..39c4f41 100644 --- a/tools/regression/lib/libc/nss/testutil.h +++ b/lib/libc/tests/nss/testutil.h @@ -73,9 +73,9 @@ __##ent##_test_data_init(struct ent##_test_data *td, \ void (*clonef)(struct ent *, struct ent const *), \ void (*freef)(struct ent *)) \ { \ - assert(td != NULL); \ - assert(clonef != NULL); \ - assert(freef != NULL); \ + ATF_REQUIRE(td != NULL); \ + ATF_REQUIRE(clonef != NULL); \ + ATF_REQUIRE(freef != NULL); \ \ memset(td, 0, sizeof(*td)); \ td->clone_func = clonef; \ @@ -94,11 +94,11 @@ __##ent##_test_data_append(struct ent##_test_data *td, struct ent *app_data)\ { \ struct ent##_entry *e; \ \ - assert(td != NULL); \ - assert(app_data != NULL); \ + ATF_REQUIRE(td != NULL); \ + ATF_REQUIRE(app_data != NULL); \ \ e = (struct ent##_entry *)malloc(sizeof(struct ent##_entry)); \ - assert(e != NULL); \ + ATF_REQUIRE(e != NULL); \ memset(e, 0, sizeof(struct ent##_entry)); \ \ td->clone_func(&e->data, app_data); \ @@ -112,8 +112,8 @@ __##ent##_test_data_foreach(struct ent##_test_data *td, \ struct ent##_entry *e; \ int rv; \ \ - assert(td != NULL); \ - assert(forf != NULL); \ + ATF_REQUIRE(td != NULL); \ + ATF_REQUIRE(forf != NULL); \ \ rv = 0; \ STAILQ_FOREACH(e, &td->snapshot_data, entries) { \ @@ -132,9 +132,9 @@ __##ent##_test_data_compare(struct ent##_test_data *td1, struct ent##_test_data struct ent##_entry *e1, *e2; \ int rv; \ \ - assert(td1 != NULL); \ - assert(td2 != NULL); \ - assert(cmp_func != NULL); \ + 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); \ @@ -163,8 +163,8 @@ __##ent##_test_data_find(struct ent##_test_data *td, struct ent *data, \ struct ent##_entry *e; \ struct ent *result; \ \ - assert(td != NULL); \ - assert(cmp != NULL); \ + ATF_REQUIRE(td != NULL); \ + ATF_REQUIRE(cmp != NULL); \ \ result = NULL; \ STAILQ_FOREACH(e, &td->snapshot_data, entries) { \ @@ -182,7 +182,7 @@ void \ __##ent##_test_data_clear(struct ent##_test_data *td) \ { \ struct ent##_entry *e; \ - assert(td != NULL); \ + ATF_REQUIRE(td != NULL); \ \ while (!STAILQ_EMPTY(&td->snapshot_data)) { \ e = STAILQ_FIRST(&td->snapshot_data); \ @@ -190,6 +190,7 @@ __##ent##_test_data_clear(struct ent##_test_data *td) \ \ td->free_func(&e->data); \ free(e); \ + e = NULL; \ } \ } @@ -217,7 +218,7 @@ __##ent##_snapshot_write_func(struct ent *data, void *mdata) \ char buffer[1024]; \ struct ent##_snp_param *param; \ \ - assert(data != NULL); \ + ATF_REQUIRE(data != NULL); \ \ param = (struct ent##_snp_param *)mdata; \ param->sdump_func(data, buffer, sizeof(buffer)); \ @@ -233,8 +234,8 @@ __##ent##_snapshot_write(char const *fname, struct ent##_test_data *td, \ { \ struct ent##_snp_param param; \ \ - assert(fname != NULL); \ - assert(td != NULL); \ + ATF_REQUIRE(fname != NULL); \ + ATF_REQUIRE(td != NULL); \ \ param.fp = fopen(fname, "w"); \ if (param.fp == NULL) \ @@ -258,8 +259,8 @@ __##ent##_snapshot_read(char const *fname, struct ent##_test_data *td, \ size_t len; \ int rv; \ \ - assert(fname != NULL); \ - assert(td != NULL); \ + ATF_REQUIRE(fname != NULL); \ + ATF_REQUIRE(td != NULL); \ \ fi = fopen(fname, "r"); \ if (fi == NULL) \ diff --git a/lib/libc/tests/resolv/Makefile b/lib/libc/tests/resolv/Makefile new file mode 100644 index 0000000..4e4e62be --- /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 +#TEST_METADATA.resolv_test= timeout="1800" + +# Note: this test relies on being dynamically linked. You will get a +# spurious PASS for a statically linked test. +LIBADD.resolv_test+= pthread + +.include <bsd.test.mk> 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/tools/regression/lib/libc/resolv/resolv.c b/lib/libc/tests/resolv/resolv_test.c index 2ec3eeb..5c53569 100644 --- a/tools/regression/lib/libc/resolv/resolv.c +++ b/lib/libc/tests/resolv/resolv_test.c @@ -39,10 +39,11 @@ __RCSID("$NetBSD: resolv.c,v 1.6 2004/05/23 16:59:11 christos Exp $"); #include <netdb.h> #include <stdlib.h> #include <unistd.h> -#include <err.h> #include <string.h> #include <stringlist.h> +#include <atf-c.h> + #define NTHREADS 10 #define NHOSTS 100 #define WS " \t\n\r" @@ -54,13 +55,10 @@ enum method { }; static StringList *hosts = NULL; -static int debug = 0; static enum method method = METHOD_GETADDRINFO; -static int reverse = 0; static int *ask = NULL; static int *got = NULL; -static void usage(void) __attribute__((__noreturn__)); static void load(const char *); static void resolvone(int); static void *resolvloop(void *); @@ -69,15 +67,6 @@ static void run(int *); static pthread_mutex_t stats = PTHREAD_MUTEX_INITIALIZER; static void -usage(void) -{ - (void)fprintf(stderr, - "Usage: %s [-AdHIr] [-h <nhosts>] [-n <nthreads>] <file> ...\n", - getprogname()); - exit(1); -} - -static void load(const char *fname) { FILE *fp; @@ -85,7 +74,7 @@ load(const char *fname) char *line; if ((fp = fopen(fname, "r")) == NULL) - err(1, "Cannot open `%s'", fname); + ATF_REQUIRE(fp != NULL); while ((line = fgetln(fp, &len)) != NULL) { char c = line[len]; char *ptr; @@ -114,21 +103,17 @@ resolv_getaddrinfo(pthread_t self, char *host, int port) hints.ai_flags = AI_PASSIVE; hints.ai_socktype = SOCK_STREAM; error = getaddrinfo(host, portstr, &hints, &res); - if (debug) { - 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 && reverse) { + 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); - if (debug) { - len = snprintf(buf, sizeof(buf), - "%p: reverse %s %s\n", self, hbuf, pbuf); - (void)write(STDOUT_FILENO, buf, len); - } + len = snprintf(buf, sizeof(buf), + "%p: reverse %s %s\n", self, hbuf, pbuf); + (void)write(STDOUT_FILENO, buf, len); } if (error == 0) freeaddrinfo(res); @@ -143,15 +128,13 @@ resolv_gethostby(pthread_t self, char *host) int len; hp = gethostbyname(host); - if (debug) { - 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 && reverse) { + 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 && debug) { + if (hp2) { len = snprintf(buf, sizeof(buf), "%p: reverse %s\n", self, hp2->h_name); (void)write(STDOUT_FILENO, buf, len); @@ -168,16 +151,14 @@ resolv_getipnodeby(pthread_t self, char *host) int len, h_error; hp = getipnodebyname(host, AF_INET, 0, &h_error); - if (debug) { - 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 && reverse) { + 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 && debug) { + if (hp2) { len = snprintf(buf, sizeof(buf), "%p: reverse %s\n", self, hp2->h_name); (void)write(STDOUT_FILENO, buf, len); @@ -200,11 +181,9 @@ resolvone(int n) struct addrinfo hints, *res; int error, len; - if (debug) { - len = snprintf(buf, sizeof(buf), "%p: %d resolving %s %d\n", - self, n, host, (int)i); - (void)write(STDOUT_FILENO, buf, 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); @@ -239,13 +218,16 @@ resolvloop(void *p) static void run(int *nhosts) { - pthread_t self = pthread_self(); - if (pthread_create(&self, NULL, resolvloop, nhosts) != 0) - err(1, "pthread_create"); + 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)); } -int -main(int argc, char *argv[]) +static int +run_tests(const char *hostlist_file, enum method method) { int nthreads = NTHREADS; int nhosts = NHOSTS; @@ -254,46 +236,18 @@ main(int argc, char *argv[]) srandom(1234); - while ((c = getopt(argc, argv, "Adh:HIn:r")) != -1) - switch (c) { - case 'A': - method = METHOD_GETADDRINFO; - break; - case 'd': - debug++; - break; - case 'h': - nhosts = atoi(optarg); - break; - case 'H': - method = METHOD_GETHOSTBY; - break; - case 'I': - method = METHOD_GETIPNODEBY; - break; - case 'n': - nthreads = atoi(optarg); - break; - case 'r': - reverse++; - break; - default: - usage(); - } + load(hostlist_file); - for (i = optind; i < argc; i++) - load(argv[i]); + ATF_REQUIRE_MSG(0 < hosts->sl_cur, "0 hosts in %s", hostlist_file); - if (hosts->sl_cur == 0) - usage(); + nleft = malloc(nthreads * sizeof(int)); + ATF_REQUIRE(nleft != NULL); - if ((nleft = malloc(nthreads * sizeof(int))) == NULL) - err(1, "malloc"); - if ((ask = calloc(hosts->sl_cur, sizeof(int))) == NULL) - err(1, "calloc"); - if ((got = calloc(hosts->sl_cur, sizeof(int))) == NULL) - err(1, "calloc"); + 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; @@ -313,7 +267,7 @@ main(int argc, char *argv[]) c = 0; for (i = 0; i < hosts->sl_cur; i++) { if (ask[i] != got[i] && got[i] != 0) { - warnx("Error: host %s ask %d got %d\n", + printf("Error: host %s ask %d got %d\n", hosts->sl_str[i], ask[i], got[i]); c++; } @@ -324,3 +278,44 @@ main(int argc, char *argv[]) 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_WITHOUT_HEAD(getaddrinfo_test); +ATF_TC_BODY(getaddrinfo_test, tc) +{ + + RUN_TESTS(tc, METHOD_GETADDRINFO); +} + +ATF_TC_WITHOUT_HEAD(gethostby_test); +ATF_TC_BODY(gethostby_test, tc) +{ + + RUN_TESTS(tc, METHOD_GETHOSTBY); +} + +ATF_TC_WITHOUT_HEAD(getipnodeby_test); +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()); +} diff --git a/lib/libfetch/http.c b/lib/libfetch/http.c index 51cac70..206648d 100644 --- a/lib/libfetch/http.c +++ b/lib/libfetch/http.c @@ -130,8 +130,8 @@ struct httpio int chunked; /* chunked mode */ char *buf; /* chunk buffer */ size_t bufsize; /* size of chunk buffer */ - ssize_t buflen; /* amount of data currently in buffer */ - int bufpos; /* current read offset in buffer */ + size_t buflen; /* amount of data currently in buffer */ + size_t bufpos; /* current read offset in buffer */ int eof; /* end-of-file flag */ int error; /* error flag */ size_t chunksize; /* remaining size of current chunk */ @@ -215,6 +215,7 @@ http_fillbuf(struct httpio *io, size_t len) if (io->eof) return (0); + /* not chunked: just fetch the requested amount */ if (io->chunked == 0) { if (http_growbuf(io, len) == -1) return (-1); @@ -227,6 +228,7 @@ http_fillbuf(struct httpio *io, size_t len) return (io->buflen); } + /* chunked, but we ran out: get the next chunk header */ if (io->chunksize == 0) { switch (http_new_chunk(io)) { case -1: @@ -238,6 +240,7 @@ http_fillbuf(struct httpio *io, size_t len) } } + /* fetch the requested amount, but no more than the current chunk */ if (len > io->chunksize) len = io->chunksize; if (http_growbuf(io, len) == -1) @@ -246,8 +249,9 @@ http_fillbuf(struct httpio *io, size_t len) io->error = errno; return (-1); } + io->bufpos = 0; io->buflen = nbytes; - io->chunksize -= io->buflen; + io->chunksize -= nbytes; if (io->chunksize == 0) { if (fetch_read(io->conn, &ch, 1) != 1 || ch != '\r' || @@ -255,8 +259,6 @@ http_fillbuf(struct httpio *io, size_t len) return (-1); } - io->bufpos = 0; - return (io->buflen); } diff --git a/lib/libstand/tftp.c b/lib/libstand/tftp.c index 6527c4e..001cbfd 100644 --- a/lib/libstand/tftp.c +++ b/lib/libstand/tftp.c @@ -399,6 +399,8 @@ tftp_open(const char *path, struct open_file *f) struct tftp_handle *tftpfile; struct iodesc *io; int res; + size_t pathsize; + const char *extraslash; if (strcmp(f->f_dev->dv_name, "net") != 0) { #ifdef __i386__ @@ -424,10 +426,22 @@ tftp_open(const char *path, struct open_file *f) io->destip = servip; tftpfile->off = 0; - tftpfile->path = strdup(path); + pathsize = (strlen(rootpath) + 1 + strlen(path) + 1) * sizeof(char); + tftpfile->path = malloc(pathsize); if (tftpfile->path == NULL) { - free(tftpfile); - return(ENOMEM); + free(tftpfile); + return(ENOMEM); + } + if (rootpath[strlen(rootpath) - 1] == '/' || path[0] == '/') + extraslash = ""; + else + extraslash = "/"; + res = snprintf(tftpfile->path, pathsize, "%s%s%s", + rootpath, extraslash, path); + if (res < 0 || res > pathsize) { + free(tftpfile->path); + free(tftpfile); + return(ENOMEM); } res = tftp_makereq(tftpfile); diff --git a/lib/msun/tests/Makefile b/lib/msun/tests/Makefile index 61fd83e..dfac5a2 100644 --- a/lib/msun/tests/Makefile +++ b/lib/msun/tests/Makefile @@ -36,11 +36,34 @@ NETBSD_ATF_TESTS_C+= sqrt_test NETBSD_ATF_TESTS_C+= tan_test NETBSD_ATF_TESTS_C+= tanh_test +TAP_TESTS_C+= cexp_test +TAP_TESTS_C+= conj_test +TAP_TESTS_C+= csqrt_test +TAP_TESTS_C+= fenv_test +TAP_TESTS_C+= fmaxmin_test +TAP_TESTS_C+= ilogb_test +TAP_TESTS_C+= invctrig_test +TAP_TESTS_C+= logarithm_test +TAP_TESTS_C+= lrint_test +TAP_TESTS_C+= nan_test +TAP_TESTS_C+= nearbyint_test +TAP_TESTS_C+= next_test +TAP_TESTS_C+= rem_test +TAP_TESTS_C+= trig_test + +.for t in ${TAP_TESTS_C} +CFLAGS.$t+= -O0 +CFLAGS.$t+= -I${SRCTOP}/tools/regression/lib/msun +.endfor + CSTD= c99 -LIBADD+= m #COPTS+= -Wfloat-equal +IGNORE_PRAGMA= + +LIBADD+= m + # Copied from lib/msun/Makefile .if ${MACHINE_CPUARCH} == "i386" ARCH_SUBDIR= i387 diff --git a/tools/regression/lib/msun/test-cexp.c b/lib/msun/tests/cexp_test.c index 6be71ad..6be71ad 100644 --- a/tools/regression/lib/msun/test-cexp.c +++ b/lib/msun/tests/cexp_test.c diff --git a/tools/regression/lib/msun/test-conj.c b/lib/msun/tests/conj_test.c index 7426f9e..7426f9e 100644 --- a/tools/regression/lib/msun/test-conj.c +++ b/lib/msun/tests/conj_test.c diff --git a/tools/regression/lib/msun/test-csqrt.c b/lib/msun/tests/csqrt_test.c index aa119d1..aa119d1 100644 --- a/tools/regression/lib/msun/test-csqrt.c +++ b/lib/msun/tests/csqrt_test.c diff --git a/tools/regression/lib/msun/test-fenv.c b/lib/msun/tests/fenv_test.c index 0ea6e42..0ea6e42 100644 --- a/tools/regression/lib/msun/test-fenv.c +++ b/lib/msun/tests/fenv_test.c diff --git a/tools/regression/lib/msun/test-fmaxmin.c b/lib/msun/tests/fmaxmin_test.c index 7ddcc87..7ddcc87 100644 --- a/tools/regression/lib/msun/test-fmaxmin.c +++ b/lib/msun/tests/fmaxmin_test.c diff --git a/tools/regression/lib/msun/test-ilogb.c b/lib/msun/tests/ilogb_test.c index a1440c4..a1440c4 100644 --- a/tools/regression/lib/msun/test-ilogb.c +++ b/lib/msun/tests/ilogb_test.c diff --git a/tools/regression/lib/msun/test-invctrig.c b/lib/msun/tests/invctrig_test.c index 78b1119..34e78a1 100644 --- a/tools/regression/lib/msun/test-invctrig.c +++ b/lib/msun/tests/invctrig_test.c @@ -281,21 +281,21 @@ test_axes(void) for (i = 0; i < sizeof(nums) / sizeof(nums[0]); i++) { /* Real axis */ z = CMPLXL(nums[i], 0.0); - if (fabs(nums[i]) <= 1) { + if (fabsl(nums[i]) <= 1) { testall_tol(cacosh, z, CMPLXL(0.0, acos(nums[i])), 1); testall_tol(cacos, z, CMPLXL(acosl(nums[i]), -0.0), 1); testall_tol(casin, z, CMPLXL(asinl(nums[i]), 0.0), 1); testall_tol(catanh, z, CMPLXL(atanh(nums[i]), 0.0), 1); } else { testall_tol(cacosh, z, - CMPLXL(acosh(fabs(nums[i])), + CMPLXL(acosh(fabsl(nums[i])), (nums[i] < 0) ? pi : 0), 1); testall_tol(cacos, z, CMPLXL((nums[i] < 0) ? pi : 0, - -acosh(fabs(nums[i]))), 1); + -acosh(fabsl(nums[i]))), 1); testall_tol(casin, z, CMPLXL(copysign(pi / 2, nums[i]), - acosh(fabs(nums[i]))), 1); + acosh(fabsl(nums[i]))), 1); testall_tol(catanh, z, CMPLXL(atanh(1 / nums[i]), pi / 2), 1); } diff --git a/tools/regression/lib/msun/test-logarithm.c b/lib/msun/tests/logarithm_test.c index 18b9ebe..18b9ebe 100644 --- a/tools/regression/lib/msun/test-logarithm.c +++ b/lib/msun/tests/logarithm_test.c diff --git a/tools/regression/lib/msun/test-lrint.c b/lib/msun/tests/lrint_test.c index ba099aa..ba099aa 100644 --- a/tools/regression/lib/msun/test-lrint.c +++ b/lib/msun/tests/lrint_test.c diff --git a/tools/regression/lib/msun/test-nan.c b/lib/msun/tests/nan_test.c index c12926b..c12926b 100644 --- a/tools/regression/lib/msun/test-nan.c +++ b/lib/msun/tests/nan_test.c diff --git a/tools/regression/lib/msun/test-nearbyint.c b/lib/msun/tests/nearbyint_test.c index 602ea2a..602ea2a 100644 --- a/tools/regression/lib/msun/test-nearbyint.c +++ b/lib/msun/tests/nearbyint_test.c diff --git a/tools/regression/lib/msun/test-next.c b/lib/msun/tests/next_test.c index d16fa77..d16fa77 100644 --- a/tools/regression/lib/msun/test-next.c +++ b/lib/msun/tests/next_test.c diff --git a/tools/regression/lib/msun/test-rem.c b/lib/msun/tests/rem_test.c index 36e3476..36e3476 100644 --- a/tools/regression/lib/msun/test-rem.c +++ b/lib/msun/tests/rem_test.c diff --git a/tools/regression/lib/msun/test-trig.c b/lib/msun/tests/trig_test.c index 1dcce1f..1dcce1f 100644 --- a/tools/regression/lib/msun/test-trig.c +++ b/lib/msun/tests/trig_test.c diff --git a/secure/lib/libcrypto/engines/Makefile b/secure/lib/libcrypto/engines/Makefile index a41dd7b..73ad68c 100644 --- a/secure/lib/libcrypto/engines/Makefile +++ b/secure/lib/libcrypto/engines/Makefile @@ -2,5 +2,5 @@ SUBDIR= lib4758cca libaep libatalla libcapi libchil libcswift libgost \ libnuron libsureware libubsec - +SUBDIR_PARALLEL= .include <bsd.subdir.mk> diff --git a/share/man/man9/VOP_GETPAGES.9 b/share/man/man9/VOP_GETPAGES.9 index 2cc5b7a..4625d9b 100644 --- a/share/man/man9/VOP_GETPAGES.9 +++ b/share/man/man9/VOP_GETPAGES.9 @@ -29,7 +29,7 @@ .\" .\" $FreeBSD$ .\" -.Dd September 12, 2014 +.Dd December 16, 2015 .Dt VOP_GETPAGES 9 .Os .Sh NAME @@ -41,7 +41,7 @@ .In sys/vnode.h .In vm/vm.h .Ft int -.Fn VOP_GETPAGES "struct vnode *vp" "vm_page_t *ma" "int count" "int reqpage" +.Fn VOP_GETPAGES "struct vnode *vp" "vm_page_t *ma" "int count" "int *rbehind" "int *rahead" .Ft int .Fn VOP_PUTPAGES "struct vnode *vp" "vm_page_t *ma" "int count" "int sync" "int *rtvals" .Sh DESCRIPTION @@ -63,7 +63,7 @@ locks are held. Both methods return in the same state on both success and error returns. .Pp The arguments are: -.Bl -tag -width reqpage +.Bl -tag -width rbehind .It Fa vp The file to access. .It Fa ma @@ -78,9 +78,16 @@ if the write should be synchronous. An array of VM system result codes indicating the status of each page written by .Fn VOP_PUTPAGES . -.It Fa reqpage -The index in the page array of the requested page; i.e., the one page which -the implementation of this method must handle. +.It Fa rbehind +Optional pointer to integer specifying number of pages to be read behind, if +possible. +If the filesystem supports that feature, number of actually read pages is +reported back, otherwise zero is returned. +.It Fa rahead +Optional pointer to integer specifying number of pages to be read ahead, if +possible. +If the filesystem supports that feature, number of actually read pages is +reported back, otherwise zero is returned. .El .Pp The status of the diff --git a/share/mk/src.opts.mk b/share/mk/src.opts.mk index f94e63a..65c4348 100644 --- a/share/mk/src.opts.mk +++ b/share/mk/src.opts.mk @@ -180,7 +180,6 @@ __DEFAULT_NO_OPTIONS = \ DTRACE_TESTS \ EISA \ HESIOD \ - LLDB \ NAND \ OFED \ OPENLDAP \ @@ -240,6 +239,11 @@ BROKEN_OPTIONS+=PROFILE # "sorry, unimplemented: profiler support for RISC-V" BROKEN_OPTIONS+=TESTS # "undefined reference to `_Unwind_Resume'" BROKEN_OPTIONS+=CXX # "libcxxrt.so: undefined reference to `_Unwind_Resume_or_Rethrow'" .endif +.if ${__T} == "aarch64" || ${__T} == "amd64" +__DEFAULT_YES_OPTIONS+=LLDB +.else +__DEFAULT_NO_OPTIONS+=LLDB +.endif # LLVM lacks support for FreeBSD 64-bit atomic operations for ARMv4/ARMv5 .if ${__T} == "arm" || ${__T} == "armeb" BROKEN_OPTIONS+=LLDB diff --git a/sys/arm/arm/pmap-v6-new.c b/sys/arm/arm/pmap-v6-new.c index 4e58cf6..8d14ed7 100644 --- a/sys/arm/arm/pmap-v6-new.c +++ b/sys/arm/arm/pmap-v6-new.c @@ -4153,10 +4153,25 @@ pmap_remove_pages(pmap_t pmap) uint32_t inuse, bitmask; boolean_t allfree; - if (pmap != vmspace_pmap(curthread->td_proc->p_vmspace)) { - printf("warning: %s called with non-current pmap\n", __func__); - return; + /* + * Assert that the given pmap is only active on the current + * CPU. Unfortunately, we cannot block another CPU from + * activating the pmap while this function is executing. + */ + KASSERT(pmap == vmspace_pmap(curthread->td_proc->p_vmspace), + ("%s: non-current pmap %p", __func__, pmap)); +#if defined(SMP) && defined(INVARIANTS) + { + cpuset_t other_cpus; + + sched_pin(); + other_cpus = pmap->pm_active; + CPU_CLR(PCPU_GET(cpuid), &other_cpus); + sched_unpin(); + KASSERT(CPU_EMPTY(&other_cpus), + ("%s: pmap %p active on other cpus", __func__, pmap)); } +#endif SLIST_INIT(&free); rw_wlock(&pvh_global_lock); PMAP_LOCK(pmap); diff --git a/sys/boot/efi/loader/arch/amd64/elf64_freebsd.c b/sys/boot/efi/loader/arch/amd64/elf64_freebsd.c index 0c26072..c1dbec2 100644 --- a/sys/boot/efi/loader/arch/amd64/elf64_freebsd.c +++ b/sys/boot/efi/loader/arch/amd64/elf64_freebsd.c @@ -174,13 +174,6 @@ elf64_exec(struct preloaded_file *fp) if (err != 0) return(err); - status = BS->ExitBootServices(IH, efi_mapkey); - if (EFI_ERROR(status)) { - printf("%s: ExitBootServices() returned 0x%lx\n", __func__, - (long)status); - return (EINVAL); - } - dev_cleanup(); trampoline(trampstack, efi_copy_finish, kernend, modulep, PT4, diff --git a/sys/boot/efi/loader/arch/arm/exec.c b/sys/boot/efi/loader/arch/arm/exec.c index 1cbbce5..7c51e6e 100644 --- a/sys/boot/efi/loader/arch/arm/exec.c +++ b/sys/boot/efi/loader/arch/arm/exec.c @@ -82,13 +82,6 @@ __elfN(arm_exec)(struct preloaded_file *fp) printf("modulep: %#x\n", modulep); printf("relocation_offset %llx\n", __elfN(relocation_offset)); - status = BS->ExitBootServices(IH, efi_mapkey); - if (EFI_ERROR(status)) { - printf("%s: ExitBootServices() returned 0x%lx\n", __func__, - (long)status); - return (EINVAL); - } - dev_cleanup(); (*entry)((void *)modulep); diff --git a/sys/boot/efi/loader/arch/arm64/exec.c b/sys/boot/efi/loader/arch/arm64/exec.c index d13e97b..0746c05 100644 --- a/sys/boot/efi/loader/arch/arm64/exec.c +++ b/sys/boot/efi/loader/arch/arm64/exec.c @@ -118,13 +118,6 @@ elf64_exec(struct preloaded_file *fp) if (err != 0) return (err); - status = BS->ExitBootServices(IH, efi_mapkey); - if (EFI_ERROR(status)) { - printf("%s: ExitBootServices() returned 0x%lx\n", __func__, - (long)status); - return (EINVAL); - } - /* Clean D-cache under kernel area and invalidate whole I-cache */ clean_addr = efi_translate(fp->f_addr); clean_size = efi_translate(kernendp) - clean_addr; diff --git a/sys/boot/efi/loader/bootinfo.c b/sys/boot/efi/loader/bootinfo.c index 6ef83a8..c9dbe8d 100644 --- a/sys/boot/efi/loader/bootinfo.c +++ b/sys/boot/efi/loader/bootinfo.c @@ -55,8 +55,6 @@ __FBSDID("$FreeBSD$"); #include <fdt_platform.h> #endif -UINTN efi_mapkey; - static const char howto_switches[] = "aCdrgDmphsv"; static int howto_masks[] = { RB_ASKNAME, RB_CDROM, RB_KDB, RB_DFLTROOT, RB_GDB, RB_MULTIPLE, @@ -234,12 +232,50 @@ bi_copymodules(vm_offset_t addr) } static int +bi_add_efi_data_and_exit(struct preloaded_file *kfp, + struct efi_map_header *efihdr, size_t efisz, EFI_MEMORY_DESCRIPTOR *mm, + UINTN sz) +{ + UINTN efi_mapkey; + UINTN mmsz; + UINT32 mmver; + EFI_STATUS status; + UINTN retry; + + /* + * It is possible that the first call to ExitBootServices may change + * the map key. Fetch a new map key and retry ExitBootServices in that + * case. + */ + for (retry = 2; retry > 0; retry--) { + status = BS->GetMemoryMap(&sz, mm, &efi_mapkey, &mmsz, &mmver); + if (EFI_ERROR(status)) { + printf("%s: GetMemoryMap() returned 0x%lx\n", __func__, + (long)status); + return (EINVAL); + } + status = BS->ExitBootServices(IH, efi_mapkey); + if (EFI_ERROR(status) == 0) { + efihdr->memory_size = sz; + efihdr->descriptor_size = mmsz; + efihdr->descriptor_version = mmver; + file_addmetadata(kfp, MODINFOMD_EFI_MAP, efisz + sz, + efihdr); + return (0); + } + } + printf("ExitBootServices() returned 0x%lx\n", (long)status); + return (EINVAL); +} + +static int bi_load_efi_data(struct preloaded_file *kfp) { EFI_MEMORY_DESCRIPTOR *mm; EFI_PHYSICAL_ADDRESS addr; EFI_STATUS status; size_t efisz; + UINTN efi_mapkey; UINTN mmsz, pages, sz; UINT32 mmver; struct efi_map_header *efihdr; @@ -294,20 +330,8 @@ bi_load_efi_data(struct preloaded_file *kfp) efihdr = (struct efi_map_header *)addr; mm = (void *)((uint8_t *)efihdr + efisz); sz = (EFI_PAGE_SIZE * pages) - efisz; - status = BS->GetMemoryMap(&sz, mm, &efi_mapkey, &mmsz, &mmver); - if (EFI_ERROR(status)) { - printf("%s: GetMemoryMap() returned 0x%lx\n", __func__, - (long)status); - return (EINVAL); - } - - efihdr->memory_size = sz; - efihdr->descriptor_size = mmsz; - efihdr->descriptor_version = mmver; - file_addmetadata(kfp, MODINFOMD_EFI_MAP, efisz + sz, efihdr); - - return (0); + return (bi_add_efi_data_and_exit(kfp, efihdr, efisz, mm, sz)); } /* diff --git a/sys/boot/efi/loader/loader_efi.h b/sys/boot/efi/loader/loader_efi.h index f98f094..5819d78 100644 --- a/sys/boot/efi/loader/loader_efi.h +++ b/sys/boot/efi/loader/loader_efi.h @@ -44,8 +44,6 @@ ssize_t efi_copyout(const vm_offset_t src, void *dest, const size_t len); ssize_t efi_readin(const int fd, vm_offset_t dest, const size_t len); void * efi_translate(vm_offset_t ptr); -extern UINTN efi_mapkey; - void efi_copy_finish(void); #endif /* _LOADER_EFI_COPY_H_ */ diff --git a/sys/boot/i386/libi386/libi386.h b/sys/boot/i386/libi386/libi386.h index ce650dd..839745d 100644 --- a/sys/boot/i386/libi386/libi386.h +++ b/sys/boot/i386/libi386/libi386.h @@ -123,5 +123,4 @@ int bi_load32(char *args, int *howtop, int *bootdevp, vm_offset_t *bip, int bi_load64(char *args, vm_offset_t addr, vm_offset_t *modulep, vm_offset_t *kernend, int add_smap); -char *pxe_default_rc(void); void pxe_enable(void *pxeinfo); diff --git a/sys/boot/i386/libi386/pxe.c b/sys/boot/i386/libi386/pxe.c index 1b255e9..efa04fc 100644 --- a/sys/boot/i386/libi386/pxe.c +++ b/sys/boot/i386/libi386/pxe.c @@ -288,8 +288,10 @@ pxe_open(struct open_file *f, ...) bootp(pxe_sock, BOOTP_PXE); if (rootip.s_addr == 0) rootip.s_addr = bootplayer.sip; +#ifdef LOADER_NFS_SUPPORT if (!rootpath[0]) strcpy(rootpath, PXENFSROOTPATH); +#endif for (i = 0; rootpath[i] != '\0' && i < FNAME_SIZE; i++) if (rootpath[i] == ':') @@ -317,13 +319,13 @@ pxe_open(struct open_file *f, ...) setenv("boot.nfsroot.path", rootpath, 1); #else setenv("boot.netif.server", inet_ntoa(rootip), 1); + setenv("boot.tftproot.path", rootpath, 1); #endif setenv("dhcp.host-name", hostname, 1); - sprintf(temp, "%08X", ntohl(myip.s_addr)); - setenv("pxeboot.ip", temp, 1); + setenv("pxeboot.ip", inet_ntoa(myip), 1); if (bootplayer.Hardware == ETHER_TYPE) { - sprintf(temp, "%6D", bootplayer.CAddr, "-"); + sprintf(temp, "%6D", bootplayer.CAddr, ":"); setenv("pxeboot.hwaddr", temp, 1); } } @@ -705,26 +707,3 @@ readudp(struct iodesc *h, void *pkt, size_t len, time_t timeout) uh->uh_sport = udpread_p->s_port; return udpread_p->buffer_size; } - -char * -pxe_default_rc(void) -{ - char *rc; - size_t count, rcsz; - - /* XXX It may not be a good idea to modify the PXE boot file. */ - rc = (char *)bootplayer.bootfile; - rcsz = sizeof(bootplayer.bootfile); - - /* Ignore how we define rc and rcsz above -- it can change. */ - if (rcsz < 6) - return (NULL); - if (*rc == '\0') { - strncpy(rc, "pxeboot", rcsz); - rc[rcsz - 1] = '\0'; - } - count = strlen(rc); - strncat(rc, ".4th", rcsz - count - 1); - printf("PXE: loading Forth from %s\n", rc); - return (rc); -} diff --git a/sys/boot/i386/loader/main.c b/sys/boot/i386/loader/main.c index 82465a3..0087338 100644 --- a/sys/boot/i386/loader/main.c +++ b/sys/boot/i386/loader/main.c @@ -196,11 +196,6 @@ main(void) bios_getsmap(); -#ifdef LOADER_TFTP_SUPPORT - if (kargs->bootflags & KARGS_FLAGS_PXE) - interact(pxe_default_rc()); - else -#endif interact(NULL); /* if we ever get here, it is an error */ diff --git a/sys/cam/ctl/ctl.c b/sys/cam/ctl/ctl.c index d21bd5a..ac886ca 100644 --- a/sys/cam/ctl/ctl.c +++ b/sys/cam/ctl/ctl.c @@ -6868,6 +6868,8 @@ ctl_log_sense(struct ctl_scsiio *ctsio) header = (struct scsi_log_header *)ctsio->kern_data_ptr; header->page = page_index->page_code; + if (page_index->page_code == SLS_LOGICAL_BLOCK_PROVISIONING) + header->page |= SL_DS; if (page_index->subpage) { header->page |= SL_SPF; header->subpage = page_index->subpage; diff --git a/sys/cam/ctl/ctl_backend_block.c b/sys/cam/ctl/ctl_backend_block.c index df65ffd..7671132 100644 --- a/sys/cam/ctl/ctl_backend_block.c +++ b/sys/cam/ctl/ctl_backend_block.c @@ -610,10 +610,10 @@ ctl_be_block_flush_file(struct ctl_be_block_lun *be_lun, ctl_complete_beio(beio); } -SDT_PROBE_DEFINE1(cbb, kernel, read, file_start, "uint64_t"); -SDT_PROBE_DEFINE1(cbb, kernel, write, file_start, "uint64_t"); -SDT_PROBE_DEFINE1(cbb, kernel, read, file_done,"uint64_t"); -SDT_PROBE_DEFINE1(cbb, kernel, write, file_done, "uint64_t"); +SDT_PROBE_DEFINE1(cbb, , read, file_start, "uint64_t"); +SDT_PROBE_DEFINE1(cbb, , write, file_start, "uint64_t"); +SDT_PROBE_DEFINE1(cbb, , read, file_done,"uint64_t"); +SDT_PROBE_DEFINE1(cbb, , write, file_done, "uint64_t"); static void ctl_be_block_dispatch_file(struct ctl_be_block_lun *be_lun, @@ -638,10 +638,10 @@ ctl_be_block_dispatch_file(struct ctl_be_block_lun *be_lun, bzero(&xuio, sizeof(xuio)); if (beio->bio_cmd == BIO_READ) { - SDT_PROBE(cbb, kernel, read, file_start, 0, 0, 0, 0, 0); + SDT_PROBE0(cbb, , read, file_start); xuio.uio_rw = UIO_READ; } else { - SDT_PROBE(cbb, kernel, write, file_start, 0, 0, 0, 0, 0); + SDT_PROBE0(cbb, , write, file_start); xuio.uio_rw = UIO_WRITE; } xuio.uio_offset = beio->io_offset; @@ -684,7 +684,7 @@ ctl_be_block_dispatch_file(struct ctl_be_block_lun *be_lun, error = VOP_READ(be_lun->vn, &xuio, flags, file_data->cred); VOP_UNLOCK(be_lun->vn, 0); - SDT_PROBE(cbb, kernel, read, file_done, 0, 0, 0, 0, 0); + SDT_PROBE0(cbb, , read, file_done); if (error == 0 && xuio.uio_resid > 0) { /* * If we red less then requested (EOF), then @@ -733,7 +733,7 @@ ctl_be_block_dispatch_file(struct ctl_be_block_lun *be_lun, VOP_UNLOCK(be_lun->vn, 0); vn_finished_write(mountpoint); - SDT_PROBE(cbb, kernel, write, file_done, 0, 0, 0, 0, 0); + SDT_PROBE0(cbb, , write, file_done); } mtx_lock(&be_lun->io_lock); @@ -869,10 +869,10 @@ ctl_be_block_dispatch_zvol(struct ctl_be_block_lun *be_lun, bzero(&xuio, sizeof(xuio)); if (beio->bio_cmd == BIO_READ) { - SDT_PROBE(cbb, kernel, read, file_start, 0, 0, 0, 0, 0); + SDT_PROBE0(cbb, , read, file_start); xuio.uio_rw = UIO_READ; } else { - SDT_PROBE(cbb, kernel, write, file_start, 0, 0, 0, 0, 0); + SDT_PROBE0(cbb, , write, file_start); xuio.uio_rw = UIO_WRITE; } xuio.uio_offset = beio->io_offset; @@ -903,9 +903,9 @@ ctl_be_block_dispatch_zvol(struct ctl_be_block_lun *be_lun, error = ENXIO; if (beio->bio_cmd == BIO_READ) - SDT_PROBE(cbb, kernel, read, file_done, 0, 0, 0, 0, 0); + SDT_PROBE0(cbb, , read, file_done); else - SDT_PROBE(cbb, kernel, write, file_done, 0, 0, 0, 0, 0); + SDT_PROBE0(cbb, , write, file_done); mtx_lock(&be_lun->io_lock); devstat_end_transaction(beio->lun->disk_stats, beio->io_len, @@ -1501,10 +1501,10 @@ ctl_be_block_cw_dispatch(struct ctl_be_block_lun *be_lun, } } -SDT_PROBE_DEFINE1(cbb, kernel, read, start, "uint64_t"); -SDT_PROBE_DEFINE1(cbb, kernel, write, start, "uint64_t"); -SDT_PROBE_DEFINE1(cbb, kernel, read, alloc_done, "uint64_t"); -SDT_PROBE_DEFINE1(cbb, kernel, write, alloc_done, "uint64_t"); +SDT_PROBE_DEFINE1(cbb, , read, start, "uint64_t"); +SDT_PROBE_DEFINE1(cbb, , write, start, "uint64_t"); +SDT_PROBE_DEFINE1(cbb, , read, alloc_done, "uint64_t"); +SDT_PROBE_DEFINE1(cbb, , write, alloc_done, "uint64_t"); static void ctl_be_block_next(struct ctl_be_block_io *beio) @@ -1549,9 +1549,9 @@ ctl_be_block_dispatch(struct ctl_be_block_lun *be_lun, lbalen = ARGS(io); if (lbalen->flags & CTL_LLF_WRITE) { - SDT_PROBE(cbb, kernel, write, start, 0, 0, 0, 0, 0); + SDT_PROBE0(cbb, , write, start); } else { - SDT_PROBE(cbb, kernel, read, start, 0, 0, 0, 0, 0); + SDT_PROBE0(cbb, , read, start); } beio = ctl_alloc_beio(softc); @@ -1638,10 +1638,10 @@ ctl_be_block_dispatch(struct ctl_be_block_lun *be_lun, * need to get the data from the user first. */ if (beio->bio_cmd == BIO_READ) { - SDT_PROBE(cbb, kernel, read, alloc_done, 0, 0, 0, 0, 0); + SDT_PROBE0(cbb, , read, alloc_done); be_lun->dispatch(be_lun, beio); } else { - SDT_PROBE(cbb, kernel, write, alloc_done, 0, 0, 0, 0, 0); + SDT_PROBE0(cbb, , write, alloc_done); #ifdef CTL_TIME_IO getbinuptime(&io->io_hdr.dma_start_bt); #endif diff --git a/sys/cddl/contrib/opensolaris/uts/common/fs/zfs/zfs_vnops.c b/sys/cddl/contrib/opensolaris/uts/common/fs/zfs/zfs_vnops.c index d1ed9da..78f8447 100644 --- a/sys/cddl/contrib/opensolaris/uts/common/fs/zfs/zfs_vnops.c +++ b/sys/cddl/contrib/opensolaris/uts/common/fs/zfs/zfs_vnops.c @@ -5762,96 +5762,54 @@ ioflags(int ioflags) } static int -zfs_getpages(struct vnode *vp, vm_page_t *m, int count, int reqpage) +zfs_getpages(struct vnode *vp, vm_page_t *m, int count, int *rbehind, + int *rahead) { znode_t *zp = VTOZ(vp); zfsvfs_t *zfsvfs = zp->z_zfsvfs; objset_t *os = zp->z_zfsvfs->z_os; - vm_page_t mfirst, mlast, mreq; + vm_page_t mlast; vm_object_t object; caddr_t va; struct sf_buf *sf; off_t startoff, endoff; int i, error; vm_pindex_t reqstart, reqend; - int pcount, lsize, reqsize, size; + int lsize, reqsize, size; - ZFS_ENTER(zfsvfs); - ZFS_VERIFY_ZP(zp); - - pcount = OFF_TO_IDX(round_page(count)); - mreq = m[reqpage]; - object = mreq->object; + object = m[0]->object; error = 0; - if (pcount > 1 && zp->z_blksz > PAGESIZE) { - startoff = rounddown(IDX_TO_OFF(mreq->pindex), zp->z_blksz); - reqstart = OFF_TO_IDX(round_page(startoff)); - if (reqstart < m[0]->pindex) - reqstart = 0; - else - reqstart = reqstart - m[0]->pindex; - endoff = roundup(IDX_TO_OFF(mreq->pindex) + PAGE_SIZE, - zp->z_blksz); - reqend = OFF_TO_IDX(trunc_page(endoff)) - 1; - if (reqend > m[pcount - 1]->pindex) - reqend = m[pcount - 1]->pindex; - reqsize = reqend - m[reqstart]->pindex + 1; - KASSERT(reqstart <= reqpage && reqpage < reqstart + reqsize, - ("reqpage beyond [reqstart, reqstart + reqsize[ bounds")); - } else { - reqstart = reqpage; - reqsize = 1; - } - mfirst = m[reqstart]; - mlast = m[reqstart + reqsize - 1]; + ZFS_ENTER(zfsvfs); + ZFS_VERIFY_ZP(zp); zfs_vmobject_wlock(object); - - for (i = 0; i < reqstart; i++) { - vm_page_lock(m[i]); - vm_page_free(m[i]); - vm_page_unlock(m[i]); - } - for (i = reqstart + reqsize; i < pcount; i++) { - vm_page_lock(m[i]); - vm_page_free(m[i]); - vm_page_unlock(m[i]); - } - - if (mreq->valid && reqsize == 1) { - if (mreq->valid != VM_PAGE_BITS_ALL) - vm_page_zero_invalid(mreq, TRUE); + if (m[count - 1]->valid != 0 && --count == 0) { zfs_vmobject_wunlock(object); - ZFS_EXIT(zfsvfs); - return (zfs_vm_pagerret_ok); + goto out; } - PCPU_INC(cnt.v_vnodein); - PCPU_ADD(cnt.v_vnodepgsin, reqsize); + mlast = m[count - 1]; - if (IDX_TO_OFF(mreq->pindex) >= object->un_pager.vnp.vnp_size) { - for (i = reqstart; i < reqstart + reqsize; i++) { - if (i != reqpage) { - vm_page_lock(m[i]); - vm_page_free(m[i]); - vm_page_unlock(m[i]); - } - } + if (IDX_TO_OFF(mlast->pindex) >= + object->un_pager.vnp.vnp_size) { zfs_vmobject_wunlock(object); ZFS_EXIT(zfsvfs); return (zfs_vm_pagerret_bad); } + PCPU_INC(cnt.v_vnodein); + PCPU_ADD(cnt.v_vnodepgsin, reqsize); + lsize = PAGE_SIZE; if (IDX_TO_OFF(mlast->pindex) + lsize > object->un_pager.vnp.vnp_size) - lsize = object->un_pager.vnp.vnp_size - IDX_TO_OFF(mlast->pindex); - + lsize = object->un_pager.vnp.vnp_size - + IDX_TO_OFF(mlast->pindex); zfs_vmobject_wunlock(object); - for (i = reqstart; i < reqstart + reqsize; i++) { + for (i = 0; i < count; i++) { size = PAGE_SIZE; - if (i == (reqstart + reqsize - 1)) + if (i == count - 1) size = lsize; va = zfs_map_page(m[i], &sf); error = dmu_read(os, zp->z_id, IDX_TO_OFF(m[i]->pindex), @@ -5860,24 +5818,25 @@ zfs_getpages(struct vnode *vp, vm_page_t *m, int count, int reqpage) bzero(va + size, PAGE_SIZE - size); zfs_unmap_page(sf); if (error != 0) - break; + goto out; } zfs_vmobject_wlock(object); - - for (i = reqstart; i < reqstart + reqsize; i++) { - if (!error) - m[i]->valid = VM_PAGE_BITS_ALL; - KASSERT(m[i]->dirty == 0, ("zfs_getpages: page %p is dirty", m[i])); - if (i != reqpage) - vm_page_readahead_finish(m[i]); - } - + for (i = 0; i < count; i++) + m[i]->valid = VM_PAGE_BITS_ALL; zfs_vmobject_wunlock(object); +out: ZFS_ACCESSTIME_STAMP(zfsvfs, zp); ZFS_EXIT(zfsvfs); - return (error ? zfs_vm_pagerret_error : zfs_vm_pagerret_ok); + if (error == 0) { + if (rbehind) + *rbehind = 0; + if (rahead) + *rahead = 0; + return (zfs_vm_pagerret_ok); + } else + return (zfs_vm_pagerret_error); } static int @@ -5886,11 +5845,13 @@ zfs_freebsd_getpages(ap) struct vnode *a_vp; vm_page_t *a_m; int a_count; - int a_reqpage; + int *a_rbehind; + int *a_rahead; } */ *ap; { - return (zfs_getpages(ap->a_vp, ap->a_m, ap->a_count, ap->a_reqpage)); + return (zfs_getpages(ap->a_vp, ap->a_m, ap->a_count, ap->a_rbehind, + ap->a_rahead)); } static int diff --git a/sys/cddl/dev/dtrace/dtrace_cddl.h b/sys/cddl/dev/dtrace/dtrace_cddl.h index eed32a8..b8ea17a 100644 --- a/sys/cddl/dev/dtrace/dtrace_cddl.h +++ b/sys/cddl/dev/dtrace/dtrace_cddl.h @@ -83,8 +83,8 @@ typedef struct kdtrace_thread { uintptr_t td_dtrace_regv; #endif u_int64_t td_hrtime; /* Last time on cpu. */ - int td_errno; /* Syscall return value. */ void *td_dtrace_sscr; /* Saved scratch space location. */ + void *td_systrace_args; /* syscall probe arguments. */ } kdtrace_thread_t; /* @@ -110,6 +110,7 @@ typedef struct kdtrace_thread { #define t_dtrace_astpc td_dtrace->td_dtrace_astpc #define t_dtrace_regv td_dtrace->td_dtrace_regv #define t_dtrace_sscr td_dtrace->td_dtrace_sscr +#define t_dtrace_systrace_args td_dtrace->td_systrace_args #define p_dtrace_helpers p_dtrace->p_dtrace_helpers #define p_dtrace_count p_dtrace->p_dtrace_count #define p_dtrace_probes p_dtrace->p_dtrace_probes diff --git a/sys/cddl/dev/systrace/systrace.c b/sys/cddl/dev/systrace/systrace.c index 1796091..88e680a 100644 --- a/sys/cddl/dev/systrace/systrace.c +++ b/sys/cddl/dev/systrace/systrace.c @@ -19,9 +19,6 @@ * CDDL HEADER END * * Portions Copyright 2006-2008 John Birrell jb@freebsd.org - * - * $FreeBSD$ - * */ /* @@ -30,10 +27,13 @@ */ #include <sys/cdefs.h> +__FBSDID("$FreeBSD$"); + #include <sys/param.h> #include <sys/systm.h> #include <sys/conf.h> #include <sys/cpuvar.h> +#include <sys/dtrace.h> #include <sys/fcntl.h> #include <sys/filio.h> #include <sys/kdb.h> @@ -50,13 +50,14 @@ #include <sys/proc.h> #include <sys/selinfo.h> #include <sys/smp.h> -#include <sys/sysproto.h> #include <sys/sysent.h> +#include <sys/sysproto.h> #include <sys/uio.h> #include <sys/unistd.h> -#include <machine/stdarg.h> -#include <sys/dtrace.h> +#include <cddl/dev/dtrace/dtrace_cddl.h> + +#include <machine/stdarg.h> #ifdef LINUX_SYSTRACE #if defined(__amd64__) @@ -134,26 +135,18 @@ extern const char *freebsd32_syscallnames[]; #error 1 << SYSTRACE_SHIFT must exceed number of system calls #endif -static d_open_t systrace_open; -static int systrace_unload(void); -static void systrace_getargdesc(void *, dtrace_id_t, void *, dtrace_argdesc_t *); +static void systrace_load(void *); +static void systrace_unload(void *); + +static void systrace_getargdesc(void *, dtrace_id_t, void *, + dtrace_argdesc_t *); +static uint64_t systrace_getargval(void *, dtrace_id_t, void *, int, int); static void systrace_provide(void *, dtrace_probedesc_t *); static void systrace_destroy(void *, dtrace_id_t, void *); static void systrace_enable(void *, dtrace_id_t, void *); static void systrace_disable(void *, dtrace_id_t, void *); -static void systrace_load(void *); - -static struct cdevsw systrace_cdevsw = { - .d_version = D_VERSION, - .d_open = systrace_open, -#ifndef NATIVE_ABI - .d_name = "systrace_" MODNAME, -#else - .d_name = "systrace", -#endif -}; -static union { +static union { const char **p_constnames; char **pp_syscallnames; } uglyhack = { SYSCALLNAMES }; @@ -174,17 +167,13 @@ static dtrace_pops_t systrace_pops = { NULL, NULL, systrace_getargdesc, - NULL, + systrace_getargval, NULL, systrace_destroy }; -static struct cdev *systrace_cdev; static dtrace_provider_id_t systrace_id; -typedef void (*systrace_dtrace_probe_t)(dtrace_id_t, uintptr_t, uintptr_t, - uintptr_t, uintptr_t, uintptr_t, uintptr_t, uintptr_t, uintptr_t); - #ifdef NATIVE_ABI /* * Probe callback function. @@ -194,64 +183,80 @@ typedef void (*systrace_dtrace_probe_t)(dtrace_id_t, uintptr_t, uintptr_t, * compat syscall from something like Linux. */ static void -systrace_probe(u_int32_t id, int sysnum, struct sysent *sysent, void *params, - int ret) +systrace_probe(struct syscall_args *sa, enum systrace_probe_t type, int retval) { - systrace_dtrace_probe_t probe; - int n_args = 0; - u_int64_t uargs[8]; + uint64_t uargs[nitems(sa->args)]; + dtrace_id_t id; + int n_args, sysnum; + sysnum = sa->code; memset(uargs, 0, sizeof(uargs)); - /* - * Check if this syscall has an argument conversion function - * registered. - */ - if (params && sysent->sy_systrace_args_func != NULL) { - /* - * Convert the syscall parameters using the registered - * function. - */ - (*sysent->sy_systrace_args_func)(sysnum, params, uargs, &n_args); - } else if (params) { + + if (type == SYSTRACE_ENTRY) { + id = sa->callp->sy_entry; + + if (sa->callp->sy_systrace_args_func != NULL) + /* + * Convert the syscall parameters using the registered + * function. + */ + (*sa->callp->sy_systrace_args_func)(sysnum, sa->args, + uargs, &n_args); + else + /* + * Use the built-in system call argument conversion + * function to translate the syscall structure fields + * into the array of 64-bit values that DTrace expects. + */ + systrace_args(sysnum, sa->args, uargs, &n_args); /* - * Use the built-in system call argument conversion - * function to translate the syscall structure fields - * into the array of 64-bit values that DTrace - * expects. + * Save probe arguments now so that we can retrieve them if + * the getargval method is called from further down the stack. */ - systrace_args(sysnum, params, uargs, &n_args); + curthread->t_dtrace_systrace_args = uargs; } else { - /* - * Since params is NULL, this is a 'return' probe. - * Set arg0 and arg1 as the return value of this syscall. - */ - uargs[0] = uargs[1] = ret; + id = sa->callp->sy_return; + + curthread->t_dtrace_systrace_args = NULL; + /* Set arg0 and arg1 as the return value of this syscall. */ + uargs[0] = uargs[1] = retval; } /* Process the probe using the converted argments. */ - probe = (systrace_dtrace_probe_t)dtrace_probe; - probe(id, uargs[0], uargs[1], uargs[2], uargs[3], uargs[4], uargs[5], - uargs[6], uargs[7]); + dtrace_probe(id, uargs[0], uargs[1], uargs[2], uargs[3], uargs[4]); } - #endif static void -systrace_getargdesc(void *arg, dtrace_id_t id, void *parg, dtrace_argdesc_t *desc) +systrace_getargdesc(void *arg, dtrace_id_t id, void *parg, + dtrace_argdesc_t *desc) { int sysnum = SYSTRACE_SYSNUM((uintptr_t)parg); if (SYSTRACE_ISENTRY((uintptr_t)parg)) - systrace_entry_setargdesc(sysnum, desc->dtargd_ndx, + systrace_entry_setargdesc(sysnum, desc->dtargd_ndx, desc->dtargd_native, sizeof(desc->dtargd_native)); else - systrace_return_setargdesc(sysnum, desc->dtargd_ndx, + systrace_return_setargdesc(sysnum, desc->dtargd_ndx, desc->dtargd_native, sizeof(desc->dtargd_native)); if (desc->dtargd_native[0] == '\0') desc->dtargd_ndx = DTRACE_ARGNONE; +} - return; +static uint64_t +systrace_getargval(void *arg __unused, dtrace_id_t id __unused, + void *parg __unused, int argno, int aframes __unused) +{ + uint64_t *uargs; + + uargs = curthread->t_dtrace_systrace_args; + if (uargs == NULL) + /* This is a return probe. */ + return (0); + if (argno >= nitems(((struct syscall_args *)NULL)->args)) + return (0); + return (uargs[argno]); } static void @@ -267,11 +272,13 @@ systrace_provide(void *arg, dtrace_probedesc_t *desc) uglyhack.pp_syscallnames[i], "entry") != 0) continue; - (void) dtrace_probe_create(systrace_id, MODNAME, uglyhack.pp_syscallnames[i], - "entry", SYSTRACE_ARTIFICIAL_FRAMES, + (void)dtrace_probe_create(systrace_id, MODNAME, + uglyhack.pp_syscallnames[i], "entry", + SYSTRACE_ARTIFICIAL_FRAMES, (void *)((uintptr_t)SYSTRACE_ENTRY(i))); - (void) dtrace_probe_create(systrace_id, MODNAME, uglyhack.pp_syscallnames[i], - "return", SYSTRACE_ARTIFICIAL_FRAMES, + (void)dtrace_probe_create(systrace_id, MODNAME, + uglyhack.pp_syscallnames[i], "return", + SYSTRACE_ARTIFICIAL_FRAMES, (void *)((uintptr_t)SYSTRACE_RETURN(i))); } } @@ -318,14 +325,11 @@ systrace_disable(void *arg, dtrace_id_t id, void *parg) } static void -systrace_load(void *dummy) +systrace_load(void *dummy __unused) { - /* Create the /dev/dtrace/systrace entry. */ - systrace_cdev = make_dev(&systrace_cdevsw, 0, UID_ROOT, GID_WHEEL, 0600, - DEVNAME); - if (dtrace_register(PROVNAME, &systrace_attr, DTRACE_PRIV_USER, - NULL, &systrace_pops, NULL, &systrace_id) != 0) + if (dtrace_register(PROVNAME, &systrace_attr, DTRACE_PRIV_USER, NULL, + &systrace_pops, NULL, &systrace_id) != 0) return; #ifdef NATIVE_ABI @@ -333,29 +337,24 @@ systrace_load(void *dummy) #endif } - -static int -systrace_unload() +static void +systrace_unload(void *dummy __unused) { - int error = 0; - - if ((error = dtrace_unregister(systrace_id)) != 0) - return (error); #ifdef NATIVE_ABI systrace_probe_func = NULL; #endif - destroy_dev(systrace_cdev); - - return (error); + if (dtrace_unregister(systrace_id) != 0) + return; } static int systrace_modevent(module_t mod __unused, int type, void *data __unused) { - int error = 0; + int error; + error = 0; switch (type) { case MOD_LOAD: break; @@ -374,14 +373,10 @@ systrace_modevent(module_t mod __unused, int type, void *data __unused) return (error); } -static int -systrace_open(struct cdev *dev __unused, int oflags __unused, int devtype __unused, struct thread *td __unused) -{ - return (0); -} - -SYSINIT(systrace_load, SI_SUB_DTRACE_PROVIDER, SI_ORDER_ANY, systrace_load, NULL); -SYSUNINIT(systrace_unload, SI_SUB_DTRACE_PROVIDER, SI_ORDER_ANY, systrace_unload, NULL); +SYSINIT(systrace_load, SI_SUB_DTRACE_PROVIDER, SI_ORDER_ANY, + systrace_load, NULL); +SYSUNINIT(systrace_unload, SI_SUB_DTRACE_PROVIDER, SI_ORDER_ANY, + systrace_unload, NULL); #ifdef LINUX_SYSTRACE DEV_MODULE(systrace_linux, systrace_modevent, NULL); diff --git a/sys/compat/linux/linux_dtrace.h b/sys/compat/linux/linux_dtrace.h index c446b3e..6e91327 100644 --- a/sys/compat/linux/linux_dtrace.h +++ b/sys/compat/linux/linux_dtrace.h @@ -72,8 +72,8 @@ #define LIN_SDT_PROBE_DEFINE5(a, b, c, d, e, f, g, h) _LIN_SDT_PROBE_DEFINE5(\ LINUX_DTRACE, a, b, c, d, e, f, g, h) -#define LIN_SDT_PROBE0(a, b, c) SDT_PROBE1(LINUX_DTRACE, a, b, \ - c, 0) +#define LIN_SDT_PROBE0(a, b, c) SDT_PROBE0(LINUX_DTRACE, a, b, \ + c) #define LIN_SDT_PROBE1(a, b, c, d) SDT_PROBE1(LINUX_DTRACE, a, b, \ c, d) #define LIN_SDT_PROBE2(a, b, c, d, e) SDT_PROBE2(LINUX_DTRACE, a, b, \ diff --git a/sys/conf/kmod.mk b/sys/conf/kmod.mk index 203d6d7..50000c5 100644 --- a/sys/conf/kmod.mk +++ b/sys/conf/kmod.mk @@ -225,7 +225,7 @@ ${FULLPROG}: ${OBJS} .else grep -v '^#' < ${EXPORT_SYMS} > export_syms .endif - awk -f ${SYSDIR}/conf/kmod_syms.awk ${.TARGET} \ + ${AWK} -f ${SYSDIR}/conf/kmod_syms.awk ${.TARGET} \ export_syms | xargs -J% ${OBJCOPY} % ${.TARGET} .endif .endif diff --git a/sys/dev/drm2/i915/i915_gem.c b/sys/dev/drm2/i915/i915_gem.c index 07b516c..95edcf9 100644 --- a/sys/dev/drm2/i915/i915_gem.c +++ b/sys/dev/drm2/i915/i915_gem.c @@ -4338,7 +4338,7 @@ i915_gem_wire_page(vm_object_t object, vm_pindex_t pindex, bool *fresh) page = vm_page_grab(object, pindex, VM_ALLOC_NORMAL); if (page->valid != VM_PAGE_BITS_ALL) { if (vm_pager_has_page(object, pindex, NULL, NULL)) { - rv = vm_pager_get_pages(object, &page, 1, 0); + rv = vm_pager_get_pages(object, &page, 1, NULL, NULL); if (rv != VM_PAGER_OK) { vm_page_lock(page); vm_page_free(page); diff --git a/sys/dev/drm2/ttm/ttm_tt.c b/sys/dev/drm2/ttm/ttm_tt.c index 2dd6fb4..1e2db3c 100644 --- a/sys/dev/drm2/ttm/ttm_tt.c +++ b/sys/dev/drm2/ttm/ttm_tt.c @@ -291,7 +291,8 @@ int ttm_tt_swapin(struct ttm_tt *ttm) from_page = vm_page_grab(obj, i, VM_ALLOC_NORMAL); if (from_page->valid != VM_PAGE_BITS_ALL) { if (vm_pager_has_page(obj, i, NULL, NULL)) { - rv = vm_pager_get_pages(obj, &from_page, 1, 0); + rv = vm_pager_get_pages(obj, &from_page, 1, + NULL, NULL); if (rv != VM_PAGER_OK) { vm_page_lock(from_page); vm_page_free(from_page); diff --git a/sys/dev/md/md.c b/sys/dev/md/md.c index 6405ad5..2fa9f46 100644 --- a/sys/dev/md/md.c +++ b/sys/dev/md/md.c @@ -1019,7 +1019,8 @@ mdstart_swap(struct md_s *sc, struct bio *bp) if (m->valid == VM_PAGE_BITS_ALL) rv = VM_PAGER_OK; else - rv = vm_pager_get_pages(sc->object, &m, 1, 0); + rv = vm_pager_get_pages(sc->object, &m, 1, + NULL, NULL); if (rv == VM_PAGER_ERROR) { vm_page_xunbusy(m); break; @@ -1046,7 +1047,8 @@ mdstart_swap(struct md_s *sc, struct bio *bp) } } else if (bp->bio_cmd == BIO_WRITE) { if (len != PAGE_SIZE && m->valid != VM_PAGE_BITS_ALL) - rv = vm_pager_get_pages(sc->object, &m, 1, 0); + rv = vm_pager_get_pages(sc->object, &m, 1, + NULL, NULL); else rv = VM_PAGER_OK; if (rv == VM_PAGER_ERROR) { @@ -1065,7 +1067,8 @@ mdstart_swap(struct md_s *sc, struct bio *bp) m->valid = VM_PAGE_BITS_ALL; } else if (bp->bio_cmd == BIO_DELETE) { if (len != PAGE_SIZE && m->valid != VM_PAGE_BITS_ALL) - rv = vm_pager_get_pages(sc->object, &m, 1, 0); + rv = vm_pager_get_pages(sc->object, &m, 1, + NULL, NULL); else rv = VM_PAGER_OK; if (rv == VM_PAGER_ERROR) { diff --git a/sys/dev/usb/serial/uftdi.c b/sys/dev/usb/serial/uftdi.c index 936d7f0..136cd55 100644 --- a/sys/dev/usb/serial/uftdi.c +++ b/sys/dev/usb/serial/uftdi.c @@ -563,7 +563,7 @@ static const STRUCT_USB_HOST_ID uftdi_devs[] = { UFTDI_DEV(KOBIL, CONV_B1, 0), UFTDI_DEV(KOBIL, CONV_KAAN, 0), UFTDI_DEV(LARSENBRUSGAARD, ALTITRACK, 0), - UFTDI_DEV(MARVELL, SHEEVAPLUG, 0), + UFTDI_DEV(MARVELL, SHEEVAPLUG, UFTDI_JTAG_IFACE(0)), UFTDI_DEV(MATRIXORBITAL, FTDI_RANGE_0100, 0), UFTDI_DEV(MATRIXORBITAL, FTDI_RANGE_0101, 0), UFTDI_DEV(MATRIXORBITAL, FTDI_RANGE_0102, 0), diff --git a/sys/fs/fuse/fuse_vnops.c b/sys/fs/fuse/fuse_vnops.c index 12b9778..74dbcb2 100644 --- a/sys/fs/fuse/fuse_vnops.c +++ b/sys/fs/fuse/fuse_vnops.c @@ -1752,35 +1752,24 @@ fuse_vnop_getpages(struct vop_getpages_args *ap) td = curthread; /* XXX */ cred = curthread->td_ucred; /* XXX */ pages = ap->a_m; - count = ap->a_count; + npages = ap->a_count; if (!fsess_opt_mmap(vnode_mount(vp))) { FS_DEBUG("called on non-cacheable vnode??\n"); return (VM_PAGER_ERROR); } - npages = btoc(count); /* - * If the requested page is partially valid, just return it and - * allow the pager to zero-out the blanks. Partially valid pages - * can only occur at the file EOF. + * If the last page is partially valid, just return it and allow + * the pager to zero-out the blanks. Partially valid pages can + * only occur at the file EOF. + * + * XXXGL: is that true for FUSE, which is a local filesystem, + * but still somewhat disconnected from the kernel? */ - VM_OBJECT_WLOCK(vp->v_object); - fuse_vm_page_lock_queues(); - if (pages[ap->a_reqpage]->valid != 0) { - for (i = 0; i < npages; ++i) { - if (i != ap->a_reqpage) { - fuse_vm_page_lock(pages[i]); - vm_page_free(pages[i]); - fuse_vm_page_unlock(pages[i]); - } - } - fuse_vm_page_unlock_queues(); - VM_OBJECT_WUNLOCK(vp->v_object); - return 0; - } - fuse_vm_page_unlock_queues(); + if (pages[npages - 1]->valid != 0 && --npages == 0) + goto out; VM_OBJECT_WUNLOCK(vp->v_object); /* @@ -1794,6 +1783,7 @@ fuse_vnop_getpages(struct vop_getpages_args *ap) PCPU_INC(cnt.v_vnodein); PCPU_ADD(cnt.v_vnodepgsin, npages); + count = npages << PAGE_SHIFT; iov.iov_base = (caddr_t)kva; iov.iov_len = count; uio.uio_iov = &iov; @@ -1811,17 +1801,6 @@ fuse_vnop_getpages(struct vop_getpages_args *ap) if (error && (uio.uio_resid == count)) { FS_DEBUG("error %d\n", error); - VM_OBJECT_WLOCK(vp->v_object); - fuse_vm_page_lock_queues(); - for (i = 0; i < npages; ++i) { - if (i != ap->a_reqpage) { - fuse_vm_page_lock(pages[i]); - vm_page_free(pages[i]); - fuse_vm_page_unlock(pages[i]); - } - } - fuse_vm_page_unlock_queues(); - VM_OBJECT_WUNLOCK(vp->v_object); return VM_PAGER_ERROR; } /* @@ -1862,12 +1841,15 @@ fuse_vnop_getpages(struct vop_getpages_args *ap) */ ; } - if (i != ap->a_reqpage) - vm_page_readahead_finish(m); } fuse_vm_page_unlock_queues(); +out: VM_OBJECT_WUNLOCK(vp->v_object); - return 0; + if (ap->a_rbehind) + *ap->a_rbehind = 0; + if (ap->a_rahead) + *ap->a_rahead = 0; + return (VM_PAGER_OK); } /* diff --git a/sys/fs/nfsclient/nfs_clbio.c b/sys/fs/nfsclient/nfs_clbio.c index 53ba7ef..3498dc0 100644 --- a/sys/fs/nfsclient/nfs_clbio.c +++ b/sys/fs/nfsclient/nfs_clbio.c @@ -100,7 +100,7 @@ ncl_getpages(struct vop_getpages_args *ap) cred = curthread->td_ucred; /* XXX */ nmp = VFSTONFS(vp->v_mount); pages = ap->a_m; - count = ap->a_count; + npages = ap->a_count; if ((object = vp->v_object) == NULL) { ncl_printf("nfs_getpages: called with non-merged cache vnode??\n"); @@ -126,18 +126,17 @@ ncl_getpages(struct vop_getpages_args *ap) } else mtx_unlock(&nmp->nm_mtx); - npages = btoc(count); - /* * If the requested page is partially valid, just return it and * allow the pager to zero-out the blanks. Partially valid pages * can only occur at the file EOF. + * + * XXXGL: is that true for NFS, where short read can occur??? */ - if (pages[ap->a_reqpage]->valid != 0) { - vm_pager_free_nonreq(object, pages, ap->a_reqpage, npages, - FALSE); - return (VM_PAGER_OK); - } + VM_OBJECT_WLOCK(object); + if (pages[npages - 1]->valid != 0 && --npages == 0) + goto out; + VM_OBJECT_WUNLOCK(object); /* * We use only the kva address for the buffer, but this is extremely @@ -150,6 +149,7 @@ ncl_getpages(struct vop_getpages_args *ap) PCPU_INC(cnt.v_vnodein); PCPU_ADD(cnt.v_vnodepgsin, npages); + count = npages << PAGE_SHIFT; iov.iov_base = (caddr_t) kva; iov.iov_len = count; uio.uio_iov = &iov; @@ -167,8 +167,6 @@ ncl_getpages(struct vop_getpages_args *ap) if (error && (uio.uio_resid == count)) { ncl_printf("nfs_getpages: error %d\n", error); - vm_pager_free_nonreq(object, pages, ap->a_reqpage, npages, - FALSE); return (VM_PAGER_ERROR); } @@ -212,11 +210,14 @@ ncl_getpages(struct vop_getpages_args *ap) */ ; } - if (i != ap->a_reqpage) - vm_page_readahead_finish(m); } +out: VM_OBJECT_WUNLOCK(object); - return (0); + if (ap->a_rbehind) + *ap->a_rbehind = 0; + if (ap->a_rahead) + *ap->a_rahead = 0; + return (VM_PAGER_OK); } /* diff --git a/sys/fs/smbfs/smbfs_io.c b/sys/fs/smbfs/smbfs_io.c index a567ce6..4de3827 100644 --- a/sys/fs/smbfs/smbfs_io.c +++ b/sys/fs/smbfs/smbfs_io.c @@ -424,7 +424,7 @@ smbfs_getpages(ap) #ifdef SMBFS_RWGENERIC return vop_stdgetpages(ap); #else - int i, error, nextoff, size, toff, npages, count, reqpage; + int i, error, nextoff, size, toff, npages, count; struct uio uio; struct iovec iov; vm_offset_t kva; @@ -436,7 +436,7 @@ smbfs_getpages(ap) struct smbnode *np; struct smb_cred *scred; vm_object_t object; - vm_page_t *pages, m; + vm_page_t *pages; vp = ap->a_vp; if ((object = vp->v_object) == NULL) { @@ -449,29 +449,18 @@ smbfs_getpages(ap) np = VTOSMB(vp); smp = VFSTOSMBFS(vp->v_mount); pages = ap->a_m; - count = ap->a_count; - npages = btoc(count); - reqpage = ap->a_reqpage; + npages = ap->a_count; /* * If the requested page is partially valid, just return it and * allow the pager to zero-out the blanks. Partially valid pages * can only occur at the file EOF. + * + * XXXGL: is that true for SMB filesystem? */ - m = pages[reqpage]; - VM_OBJECT_WLOCK(object); - if (m->valid != 0) { - for (i = 0; i < npages; ++i) { - if (i != reqpage) { - vm_page_lock(pages[i]); - vm_page_free(pages[i]); - vm_page_unlock(pages[i]); - } - } - VM_OBJECT_WUNLOCK(object); - return 0; - } + if (pages[npages - 1]->valid != 0 && --npages == 0) + goto out; VM_OBJECT_WUNLOCK(object); scred = smbfs_malloc_scred(); @@ -484,6 +473,7 @@ smbfs_getpages(ap) PCPU_INC(cnt.v_vnodein); PCPU_ADD(cnt.v_vnodepgsin, npages); + count = npages << PAGE_SHIFT; iov.iov_base = (caddr_t) kva; iov.iov_len = count; uio.uio_iov = &iov; @@ -500,22 +490,14 @@ smbfs_getpages(ap) relpbuf(bp, &smbfs_pbuf_freecnt); - VM_OBJECT_WLOCK(object); if (error && (uio.uio_resid == count)) { printf("smbfs_getpages: error %d\n",error); - for (i = 0; i < npages; i++) { - if (reqpage != i) { - vm_page_lock(pages[i]); - vm_page_free(pages[i]); - vm_page_unlock(pages[i]); - } - } - VM_OBJECT_WUNLOCK(object); return VM_PAGER_ERROR; } size = count - uio.uio_resid; + VM_OBJECT_WLOCK(object); for (i = 0, toff = 0; i < npages; i++, toff = nextoff) { vm_page_t m; nextoff = toff + PAGE_SIZE; @@ -544,12 +526,14 @@ smbfs_getpages(ap) */ ; } - - if (i != reqpage) - vm_page_readahead_finish(m); } +out: VM_OBJECT_WUNLOCK(object); - return 0; + if (ap->a_rbehind) + *ap->a_rbehind = 0; + if (ap->a_rahead) + *ap->a_rahead = 0; + return (VM_PAGER_OK); #endif /* SMBFS_RWGENERIC */ } diff --git a/sys/fs/tmpfs/tmpfs_subr.c b/sys/fs/tmpfs/tmpfs_subr.c index fa489b2..fcc8782 100644 --- a/sys/fs/tmpfs/tmpfs_subr.c +++ b/sys/fs/tmpfs/tmpfs_subr.c @@ -1370,7 +1370,8 @@ retry: VM_OBJECT_WLOCK(uobj); goto retry; } else if (m->valid != VM_PAGE_BITS_ALL) - rv = vm_pager_get_pages(uobj, &m, 1, 0); + rv = vm_pager_get_pages(uobj, &m, 1, + NULL, NULL); else /* A cached page was reactivated. */ rv = VM_PAGER_OK; diff --git a/sys/geom/multipath/g_multipath.c b/sys/geom/multipath/g_multipath.c index 0953d18..6644532 100644 --- a/sys/geom/multipath/g_multipath.c +++ b/sys/geom/multipath/g_multipath.c @@ -107,8 +107,9 @@ struct g_class g_multipath_class = { #define MP_NEW 0x00000004 #define MP_POSTED 0x00000008 #define MP_BAD (MP_FAIL | MP_LOST | MP_NEW) -#define MP_IDLE 0x00000010 -#define MP_IDLE_MASK 0xfffffff0 +#define MP_WITHER 0x00000010 +#define MP_IDLE 0x00000020 +#define MP_IDLE_MASK 0xffffffe0 static int g_multipath_good(struct g_geom *gp) @@ -204,6 +205,7 @@ g_mpd(void *arg, int flags __unused) g_access(cp, -cp->acr, -cp->acw, -cp->ace); if (w > 0 && cp->provider != NULL && (cp->provider->geom->flags & G_GEOM_WITHER) == 0) { + cp->index |= MP_WITHER; g_post_event(g_mpd, cp, M_WAITOK, NULL); return; } @@ -467,23 +469,37 @@ g_multipath_access(struct g_provider *pp, int dr, int dw, int de) gp = pp->geom; + /* Error used if we have no valid consumers. */ + error = ENXIO; + LIST_FOREACH(cp, &gp->consumer, consumer) { + if (cp->index & MP_WITHER) + continue; + error = g_access(cp, dr, dw, de); if (error) { badcp = cp; goto fail; } } + + if (error != 0) + return (error); + sc = gp->softc; sc->sc_opened += dr + dw + de; if (sc->sc_stopping && sc->sc_opened == 0) g_multipath_destroy(gp); + return (0); fail: LIST_FOREACH(cp, &gp->consumer, consumer) { if (cp == badcp) break; + if (cp->index & MP_WITHER) + continue; + (void) g_access(cp, -dr, -dw, -de); } return (error); diff --git a/sys/kern/kern_exec.c b/sys/kern/kern_exec.c index a0eb069..741bc3e 100644 --- a/sys/kern/kern_exec.c +++ b/sys/kern/kern_exec.c @@ -94,9 +94,9 @@ dtrace_execexit_func_t dtrace_fasttrap_exec; #endif SDT_PROVIDER_DECLARE(proc); -SDT_PROBE_DEFINE1(proc, kernel, , exec, "char *"); -SDT_PROBE_DEFINE1(proc, kernel, , exec__failure, "int"); -SDT_PROBE_DEFINE1(proc, kernel, , exec__success, "char *"); +SDT_PROBE_DEFINE1(proc, , , exec, "char *"); +SDT_PROBE_DEFINE1(proc, , , exec__failure, "int"); +SDT_PROBE_DEFINE1(proc, , , exec__success, "char *"); MALLOC_DEFINE(M_PARGS, "proc-args", "Process arguments"); @@ -423,7 +423,7 @@ do_execve(td, args, mac_p) | AUDITVNODE1, UIO_SYSSPACE, args->fname, td); } - SDT_PROBE1(proc, kernel, , exec, args->fname); + SDT_PROBE1(proc, , , exec, args->fname); interpret: if (args->fname != NULL) { @@ -851,7 +851,7 @@ interpret: vfs_mark_atime(imgp->vp, td->td_ucred); - SDT_PROBE1(proc, kernel, , exec__success, args->fname); + SDT_PROBE1(proc, , , exec__success, args->fname); VOP_UNLOCK(imgp->vp, 0); done1: @@ -923,7 +923,7 @@ exec_fail: p->p_flag &= ~P_INEXEC; PROC_UNLOCK(p); - SDT_PROBE1(proc, kernel, , exec__failure, error); + SDT_PROBE1(proc, , , exec__failure, error); done2: #ifdef MAC @@ -950,8 +950,7 @@ int exec_map_first_page(imgp) struct image_params *imgp; { - int rv, i; - int initial_pagein; + int rv, i, after, initial_pagein; vm_page_t ma[VM_INITIAL_PAGEIN]; vm_object_t object; @@ -967,9 +966,18 @@ exec_map_first_page(imgp) #endif ma[0] = vm_page_grab(object, 0, VM_ALLOC_NORMAL); if (ma[0]->valid != VM_PAGE_BITS_ALL) { - initial_pagein = VM_INITIAL_PAGEIN; - if (initial_pagein > object->size) - initial_pagein = object->size; + if (!vm_pager_has_page(object, 0, NULL, &after)) { + vm_page_lock(ma[0]); + vm_page_free(ma[0]); + vm_page_unlock(ma[0]); + vm_page_xunbusy(ma[0]); + VM_OBJECT_WUNLOCK(object); + return (EIO); + } + initial_pagein = min(after, VM_INITIAL_PAGEIN); + KASSERT(initial_pagein <= object->size, + ("%s: initial_pagein %d object->size %ju", + __func__, initial_pagein, (uintmax_t )object->size)); for (i = 1; i < initial_pagein; i++) { if ((ma[i] = vm_page_next(ma[i - 1])) != NULL) { if (ma[i]->valid) @@ -984,14 +992,19 @@ exec_map_first_page(imgp) } } initial_pagein = i; - rv = vm_pager_get_pages(object, ma, initial_pagein, 0); + rv = vm_pager_get_pages(object, ma, initial_pagein, NULL, NULL); if (rv != VM_PAGER_OK) { - vm_page_lock(ma[0]); - vm_page_free(ma[0]); - vm_page_unlock(ma[0]); + for (i = 0; i < initial_pagein; i++) { + vm_page_lock(ma[i]); + vm_page_free(ma[i]); + vm_page_unlock(ma[i]); + vm_page_xunbusy(ma[i]); + } VM_OBJECT_WUNLOCK(object); return (EIO); } + for (i = 1; i < initial_pagein; i++) + vm_page_readahead_finish(ma[i]); } vm_page_xunbusy(ma[0]); vm_page_lock(ma[0]); diff --git a/sys/kern/kern_exit.c b/sys/kern/kern_exit.c index 6215ecb..ee87e58 100644 --- a/sys/kern/kern_exit.c +++ b/sys/kern/kern_exit.c @@ -94,7 +94,7 @@ dtrace_execexit_func_t dtrace_fasttrap_exit; #endif SDT_PROVIDER_DECLARE(proc); -SDT_PROBE_DEFINE1(proc, kernel, , exit, "int"); +SDT_PROBE_DEFINE1(proc, , , exit, "int"); /* Hook for NFS teardown procedure. */ void (*nlminfo_release_p)(struct proc *p); @@ -569,7 +569,7 @@ exit1(struct thread *td, int rval, int signo) reason = CLD_DUMPED; else if (WIFSIGNALED(signo)) reason = CLD_KILLED; - SDT_PROBE1(proc, kernel, , exit, reason); + SDT_PROBE1(proc, , , exit, reason); #endif /* diff --git a/sys/kern/kern_fork.c b/sys/kern/kern_fork.c index 1b556be..a395fdd 100644 --- a/sys/kern/kern_fork.c +++ b/sys/kern/kern_fork.c @@ -89,8 +89,7 @@ dtrace_fork_func_t dtrace_fasttrap_fork; #endif SDT_PROVIDER_DECLARE(proc); -SDT_PROBE_DEFINE3(proc, kernel, , create, "struct proc *", - "struct proc *", "int"); +SDT_PROBE_DEFINE3(proc, , , create, "struct proc *", "struct proc *", "int"); #ifndef _SYS_SYSPROTO_H_ struct fork_args { @@ -748,7 +747,7 @@ do_fork(struct thread *td, int flags, struct proc *p2, struct thread *td2, * Tell any interested parties about the new process. */ knote_fork(&p1->p_klist, p2->p_pid); - SDT_PROBE3(proc, kernel, , create, p2, p1, flags); + SDT_PROBE3(proc, , , create, p2, p1, flags); /* * Wait until debugger is attached to child. diff --git a/sys/kern/kern_proc.c b/sys/kern/kern_proc.c index 435a07b..8a3b6ca 100644 --- a/sys/kern/kern_proc.c +++ b/sys/kern/kern_proc.c @@ -92,18 +92,15 @@ __FBSDID("$FreeBSD$"); #endif SDT_PROVIDER_DEFINE(proc); -SDT_PROBE_DEFINE4(proc, kernel, ctor, entry, "struct proc *", "int", - "void *", "int"); -SDT_PROBE_DEFINE4(proc, kernel, ctor, return, "struct proc *", "int", - "void *", "int"); -SDT_PROBE_DEFINE4(proc, kernel, dtor, entry, "struct proc *", "int", - "void *", "struct thread *"); -SDT_PROBE_DEFINE3(proc, kernel, dtor, return, "struct proc *", "int", - "void *"); -SDT_PROBE_DEFINE3(proc, kernel, init, entry, "struct proc *", "int", +SDT_PROBE_DEFINE4(proc, , ctor, entry, "struct proc *", "int", "void *", "int"); -SDT_PROBE_DEFINE3(proc, kernel, init, return, "struct proc *", "int", +SDT_PROBE_DEFINE4(proc, , ctor, return, "struct proc *", "int", "void *", "int"); +SDT_PROBE_DEFINE4(proc, , dtor, entry, "struct proc *", "int", "void *", + "struct thread *"); +SDT_PROBE_DEFINE3(proc, , dtor, return, "struct proc *", "int", "void *"); +SDT_PROBE_DEFINE3(proc, , init, entry, "struct proc *", "int", "int"); +SDT_PROBE_DEFINE3(proc, , init, return, "struct proc *", "int", "int"); MALLOC_DEFINE(M_PGRP, "pgrp", "process group header"); MALLOC_DEFINE(M_SESSION, "session", "session header"); @@ -196,9 +193,9 @@ proc_ctor(void *mem, int size, void *arg, int flags) struct proc *p; p = (struct proc *)mem; - SDT_PROBE4(proc, kernel, ctor , entry, p, size, arg, flags); + SDT_PROBE4(proc, , ctor , entry, p, size, arg, flags); EVENTHANDLER_INVOKE(process_ctor, p); - SDT_PROBE4(proc, kernel, ctor , return, p, size, arg, flags); + SDT_PROBE4(proc, , ctor , return, p, size, arg, flags); return (0); } @@ -214,7 +211,7 @@ proc_dtor(void *mem, int size, void *arg) /* INVARIANTS checks go here */ p = (struct proc *)mem; td = FIRST_THREAD_IN_PROC(p); - SDT_PROBE4(proc, kernel, dtor, entry, p, size, arg, td); + SDT_PROBE4(proc, , dtor, entry, p, size, arg, td); if (td != NULL) { #ifdef INVARIANTS KASSERT((p->p_numthreads == 1), @@ -227,7 +224,7 @@ proc_dtor(void *mem, int size, void *arg) EVENTHANDLER_INVOKE(process_dtor, p); if (p->p_ksi != NULL) KASSERT(! KSI_ONQ(p->p_ksi), ("SIGCHLD queue")); - SDT_PROBE3(proc, kernel, dtor, return, p, size, arg); + SDT_PROBE3(proc, , dtor, return, p, size, arg); } /* @@ -239,7 +236,7 @@ proc_init(void *mem, int size, int flags) struct proc *p; p = (struct proc *)mem; - SDT_PROBE3(proc, kernel, init, entry, p, size, flags); + SDT_PROBE3(proc, , init, entry, p, size, flags); p->p_sched = (struct p_sched *)&p[1]; mtx_init(&p->p_mtx, "process lock", NULL, MTX_DEF | MTX_DUPOK | MTX_NEW); mtx_init(&p->p_slock, "process slock", NULL, MTX_SPIN | MTX_NEW); @@ -251,7 +248,7 @@ proc_init(void *mem, int size, int flags) TAILQ_INIT(&p->p_threads); /* all threads in proc */ EVENTHANDLER_INVOKE(process_init, p); p->p_stats = pstats_alloc(); - SDT_PROBE3(proc, kernel, init, return, p, size, flags); + SDT_PROBE3(proc, , init, return, p, size, flags); return (0); } diff --git a/sys/kern/kern_racct.c b/sys/kern/kern_racct.c index a1ad3c9..0c7c0c4 100644 --- a/sys/kern/kern_racct.c +++ b/sys/kern/kern_racct.c @@ -102,30 +102,32 @@ static void racct_add_cred_locked(struct ucred *cred, int resource, uint64_t amount); SDT_PROVIDER_DEFINE(racct); -SDT_PROBE_DEFINE3(racct, kernel, rusage, add, "struct proc *", "int", - "uint64_t"); -SDT_PROBE_DEFINE3(racct, kernel, rusage, add__failure, +SDT_PROBE_DEFINE3(racct, , rusage, add, "struct proc *", "int", "uint64_t"); -SDT_PROBE_DEFINE3(racct, kernel, rusage, add__cred, "struct ucred *", - "int", "uint64_t"); -SDT_PROBE_DEFINE3(racct, kernel, rusage, add__force, "struct proc *", - "int", "uint64_t"); -SDT_PROBE_DEFINE3(racct, kernel, rusage, set, "struct proc *", "int", - "uint64_t"); -SDT_PROBE_DEFINE3(racct, kernel, rusage, set__failure, +SDT_PROBE_DEFINE3(racct, , rusage, add__failure, "struct proc *", "int", "uint64_t"); -SDT_PROBE_DEFINE3(racct, kernel, rusage, sub, "struct proc *", "int", - "uint64_t"); -SDT_PROBE_DEFINE3(racct, kernel, rusage, sub__cred, "struct ucred *", - "int", "uint64_t"); -SDT_PROBE_DEFINE1(racct, kernel, racct, create, "struct racct *"); -SDT_PROBE_DEFINE1(racct, kernel, racct, destroy, "struct racct *"); -SDT_PROBE_DEFINE2(racct, kernel, racct, join, "struct racct *", +SDT_PROBE_DEFINE3(racct, , rusage, add__cred, + "struct ucred *", "int", "uint64_t"); +SDT_PROBE_DEFINE3(racct, , rusage, add__force, + "struct proc *", "int", "uint64_t"); +SDT_PROBE_DEFINE3(racct, , rusage, set, + "struct proc *", "int", "uint64_t"); +SDT_PROBE_DEFINE3(racct, , rusage, set__failure, + "struct proc *", "int", "uint64_t"); +SDT_PROBE_DEFINE3(racct, , rusage, sub, + "struct proc *", "int", "uint64_t"); +SDT_PROBE_DEFINE3(racct, , rusage, sub__cred, + "struct ucred *", "int", "uint64_t"); +SDT_PROBE_DEFINE1(racct, , racct, create, "struct racct *"); -SDT_PROBE_DEFINE2(racct, kernel, racct, join__failure, - "struct racct *", "struct racct *"); -SDT_PROBE_DEFINE2(racct, kernel, racct, leave, "struct racct *", +SDT_PROBE_DEFINE1(racct, , racct, destroy, "struct racct *"); +SDT_PROBE_DEFINE2(racct, , racct, join, + "struct racct *", "struct racct *"); +SDT_PROBE_DEFINE2(racct, , racct, join__failure, + "struct racct *", "struct racct *"); +SDT_PROBE_DEFINE2(racct, , racct, leave, + "struct racct *", "struct racct *"); int racct_types[] = { [RACCT_CPU] = @@ -445,7 +447,7 @@ racct_create(struct racct **racctp) if (!racct_enable) return; - SDT_PROBE1(racct, kernel, racct, create, racctp); + SDT_PROBE1(racct, , racct, create, racctp); KASSERT(*racctp == NULL, ("racct already allocated")); @@ -460,7 +462,7 @@ racct_destroy_locked(struct racct **racctp) ASSERT_RACCT_ENABLED(); - SDT_PROBE1(racct, kernel, racct, destroy, racctp); + SDT_PROBE1(racct, , racct, destroy, racctp); mtx_assert(&racct_lock, MA_OWNED); KASSERT(racctp != NULL, ("NULL racctp")); @@ -538,7 +540,7 @@ racct_add_locked(struct proc *p, int resource, uint64_t amount) ASSERT_RACCT_ENABLED(); - SDT_PROBE3(racct, kernel, rusage, add, p, resource, amount); + SDT_PROBE3(racct, , rusage, add, p, resource, amount); /* * We need proc lock to dereference p->p_ucred. @@ -548,8 +550,7 @@ racct_add_locked(struct proc *p, int resource, uint64_t amount) #ifdef RCTL error = rctl_enforce(p, resource, amount); if (error && RACCT_IS_DENIABLE(resource)) { - SDT_PROBE3(racct, kernel, rusage, add__failure, p, resource, - amount); + SDT_PROBE3(racct, , rusage, add__failure, p, resource, amount); return (error); } #endif @@ -584,7 +585,7 @@ racct_add_cred_locked(struct ucred *cred, int resource, uint64_t amount) ASSERT_RACCT_ENABLED(); - SDT_PROBE3(racct, kernel, rusage, add__cred, cred, resource, amount); + SDT_PROBE3(racct, , rusage, add__cred, cred, resource, amount); racct_adjust_resource(cred->cr_ruidinfo->ui_racct, resource, amount); for (pr = cred->cr_prison; pr != NULL; pr = pr->pr_parent) @@ -622,7 +623,7 @@ racct_add_force(struct proc *p, int resource, uint64_t amount) if (!racct_enable) return; - SDT_PROBE3(racct, kernel, rusage, add__force, p, resource, amount); + SDT_PROBE3(racct, , rusage, add__force, p, resource, amount); /* * We need proc lock to dereference p->p_ucred. @@ -646,7 +647,7 @@ racct_set_locked(struct proc *p, int resource, uint64_t amount) ASSERT_RACCT_ENABLED(); - SDT_PROBE3(racct, kernel, rusage, set, p, resource, amount); + SDT_PROBE3(racct, , rusage, set, p, resource, amount); /* * We need proc lock to dereference p->p_ucred. @@ -678,8 +679,8 @@ racct_set_locked(struct proc *p, int resource, uint64_t amount) if (diff_proc > 0) { error = rctl_enforce(p, resource, diff_proc); if (error && RACCT_IS_DENIABLE(resource)) { - SDT_PROBE3(racct, kernel, rusage, set__failure, p, - resource, amount); + SDT_PROBE3(racct, , rusage, set__failure, p, resource, + amount); return (error); } } @@ -722,7 +723,7 @@ racct_set_force_locked(struct proc *p, int resource, uint64_t amount) ASSERT_RACCT_ENABLED(); - SDT_PROBE3(racct, kernel, rusage, set, p, resource, amount); + SDT_PROBE3(racct, , rusage, set, p, resource, amount); /* * We need proc lock to dereference p->p_ucred. @@ -833,7 +834,7 @@ racct_sub(struct proc *p, int resource, uint64_t amount) if (!racct_enable) return; - SDT_PROBE3(racct, kernel, rusage, sub, p, resource, amount); + SDT_PROBE3(racct, , rusage, sub, p, resource, amount); /* * We need proc lock to dereference p->p_ucred. @@ -860,7 +861,7 @@ racct_sub_cred_locked(struct ucred *cred, int resource, uint64_t amount) ASSERT_RACCT_ENABLED(); - SDT_PROBE3(racct, kernel, rusage, sub__cred, cred, resource, amount); + SDT_PROBE3(racct, , rusage, sub__cred, cred, resource, amount); #ifdef notyet KASSERT(RACCT_CAN_DROP(resource), diff --git a/sys/kern/kern_sig.c b/sys/kern/kern_sig.c index 767eff0..510b920 100644 --- a/sys/kern/kern_sig.c +++ b/sys/kern/kern_sig.c @@ -94,11 +94,11 @@ __FBSDID("$FreeBSD$"); #define ONSIG 32 /* NSIG for osig* syscalls. XXX. */ SDT_PROVIDER_DECLARE(proc); -SDT_PROBE_DEFINE3(proc, kernel, , signal__send, "struct thread *", - "struct proc *", "int"); -SDT_PROBE_DEFINE2(proc, kernel, , signal__clear, "int", - "ksiginfo_t *"); -SDT_PROBE_DEFINE3(proc, kernel, , signal__discard, +SDT_PROBE_DEFINE3(proc, , , signal__send, + "struct thread *", "struct proc *", "int"); +SDT_PROBE_DEFINE2(proc, , , signal__clear, + "int", "ksiginfo_t *"); +SDT_PROBE_DEFINE3(proc, , , signal__discard, "struct thread *", "struct proc *", "int"); static int coredump(struct thread *); @@ -1308,7 +1308,7 @@ kern_sigtimedwait(struct thread *td, sigset_t waitset, ksiginfo_t *ksi, reschedule_signals(p, new_block, 0); if (error == 0) { - SDT_PROBE2(proc, kernel, , signal__clear, sig, ksi); + SDT_PROBE2(proc, , , signal__clear, sig, ksi); if (ksi->ksi_code == SI_TIMER) itimer_accept(p, ksi->ksi_timerid, ksi); @@ -2121,7 +2121,7 @@ tdsendsignal(struct proc *p, struct thread *td, int sig, ksiginfo_t *ksi) } else sigqueue = &td->td_sigqueue; - SDT_PROBE3(proc, kernel, , signal__send, td, p, sig); + SDT_PROBE3(proc, , , signal__send, td, p, sig); /* * If the signal is being ignored, @@ -2132,7 +2132,7 @@ tdsendsignal(struct proc *p, struct thread *td, int sig, ksiginfo_t *ksi) */ mtx_lock(&ps->ps_mtx); if (SIGISMEMBER(ps->ps_sigignore, sig)) { - SDT_PROBE3(proc, kernel, , signal__discard, td, p, sig); + SDT_PROBE3(proc, , , signal__discard, td, p, sig); mtx_unlock(&ps->ps_mtx); if (ksi && (ksi->ksi_flags & KSI_INS)) diff --git a/sys/kern/kern_timeout.c b/sys/kern/kern_timeout.c index 5bae716..9c9d25f 100644 --- a/sys/kern/kern_timeout.c +++ b/sys/kern/kern_timeout.c @@ -69,10 +69,8 @@ DPCPU_DECLARE(sbintime_t, hardclocktime); #endif SDT_PROVIDER_DEFINE(callout_execute); -SDT_PROBE_DEFINE1(callout_execute, kernel, , callout__start, - "struct callout *"); -SDT_PROBE_DEFINE1(callout_execute, kernel, , callout__end, - "struct callout *"); +SDT_PROBE_DEFINE1(callout_execute, , , callout__start, "struct callout *"); +SDT_PROBE_DEFINE1(callout_execute, , , callout__end, "struct callout *"); #ifdef CALLOUT_PROFILING static int avg_depth; @@ -721,9 +719,9 @@ softclock_call_cc(struct callout *c, struct callout_cpu *cc, sbt1 = sbinuptime(); #endif THREAD_NO_SLEEPING(); - SDT_PROBE1(callout_execute, kernel, , callout__start, c); + SDT_PROBE1(callout_execute, , , callout__start, c); c_func(c_arg); - SDT_PROBE1(callout_execute, kernel, , callout__end, c); + SDT_PROBE1(callout_execute, , , callout__end, c); THREAD_SLEEPING_OK(); #if defined(DIAGNOSTIC) || defined(CALLOUT_PROFILING) sbt2 = sbinuptime(); diff --git a/sys/kern/subr_syscall.c b/sys/kern/subr_syscall.c index c076326..f7bbdfb 100644 --- a/sys/kern/subr_syscall.c +++ b/sys/kern/subr_syscall.c @@ -126,14 +126,9 @@ syscallenter(struct thread *td, struct syscall_args *sa) goto retval; #ifdef KDTRACE_HOOKS - /* - * If the systrace module has registered it's probe - * callback and if there is a probe active for the - * syscall 'entry', process the probe. - */ + /* Give the syscall:::entry DTrace probe a chance to fire. */ if (systrace_probe_func != NULL && sa->callp->sy_entry != 0) - (*systrace_probe_func)(sa->callp->sy_entry, sa->code, - sa->callp, sa->args, 0); + (*systrace_probe_func)(sa, SYSTRACE_ENTRY, 0); #endif AUDIT_SYSCALL_ENTER(sa->code, td); @@ -145,14 +140,10 @@ syscallenter(struct thread *td, struct syscall_args *sa) td->td_errno = error; #ifdef KDTRACE_HOOKS - /* - * If the systrace module has registered it's probe - * callback and if there is a probe active for the - * syscall 'return', process the probe. - */ + /* Give the syscall:::return DTrace probe a chance to fire. */ if (systrace_probe_func != NULL && sa->callp->sy_return != 0) - (*systrace_probe_func)(sa->callp->sy_return, sa->code, - sa->callp, NULL, (error) ? -1 : td->td_retval[0]); + (*systrace_probe_func)(sa, SYSTRACE_RETURN, + error ? -1 : td->td_retval[0]); #endif syscall_thread_exit(td, sa->callp); } diff --git a/sys/kern/uipc_shm.c b/sys/kern/uipc_shm.c index 21cbe49..8df6e43 100644 --- a/sys/kern/uipc_shm.c +++ b/sys/kern/uipc_shm.c @@ -189,7 +189,7 @@ uiomove_object_page(vm_object_t obj, size_t len, struct uio *uio) m = vm_page_grab(obj, idx, VM_ALLOC_NORMAL); if (m->valid != VM_PAGE_BITS_ALL) { if (vm_pager_has_page(obj, idx, NULL, NULL)) { - rv = vm_pager_get_pages(obj, &m, 1, 0); + rv = vm_pager_get_pages(obj, &m, 1, NULL, NULL); if (rv != VM_PAGER_OK) { printf( "uiomove_object: vm_obj %p idx %jd valid %x pager error %d\n", @@ -460,7 +460,7 @@ retry: goto retry; } else if (m->valid != VM_PAGE_BITS_ALL) rv = vm_pager_get_pages(object, &m, 1, - 0); + NULL, NULL); else /* A cached page was reactivated. */ rv = VM_PAGER_OK; diff --git a/sys/kern/uipc_syscalls.c b/sys/kern/uipc_syscalls.c index 54c13024..c33a2cf 100644 --- a/sys/kern/uipc_syscalls.c +++ b/sys/kern/uipc_syscalls.c @@ -2033,7 +2033,7 @@ sendfile_readpage(vm_object_t obj, struct vnode *vp, int nd, VM_OBJECT_WLOCK(obj); } else { if (vm_pager_has_page(obj, pindex, NULL, NULL)) { - rv = vm_pager_get_pages(obj, &m, 1, 0); + rv = vm_pager_get_pages(obj, &m, 1, NULL, NULL); SFSTAT_INC(sf_iocnt); if (rv != VM_PAGER_OK) { vm_page_lock(m); diff --git a/sys/kern/vfs_bio.c b/sys/kern/vfs_bio.c index ccd1b64..6b8f79f 100644 --- a/sys/kern/vfs_bio.c +++ b/sys/kern/vfs_bio.c @@ -2909,7 +2909,7 @@ getnewbuf(struct vnode *vp, int slpflag, int slptimeo, int maxsize, int gbflags) } while(buf_scan(false) == 0); if (reserved) - bufspace_release(maxsize); + atomic_subtract_long(&bufspace, maxsize); if (bp != NULL) { bp->b_flags |= B_INVAL; brelse(bp); diff --git a/sys/kern/vfs_cache.c b/sys/kern/vfs_cache.c index ca9f054..ff3736d 100644 --- a/sys/kern/vfs_cache.c +++ b/sys/kern/vfs_cache.c @@ -417,7 +417,6 @@ cache_zap(ncp) rw_assert(&cache_lock, RA_WLOCKED); CTR2(KTR_VFS, "cache_zap(%p) vp %p", ncp, ncp->nc_vp); -#ifdef KDTRACE_HOOKS if (ncp->nc_vp != NULL) { SDT_PROBE3(vfs, namecache, zap, done, ncp->nc_dvp, nc_get_name(ncp), ncp->nc_vp); @@ -425,7 +424,6 @@ cache_zap(ncp) SDT_PROBE2(vfs, namecache, zap_negative, done, ncp->nc_dvp, nc_get_name(ncp)); } -#endif vp = NULL; LIST_REMOVE(ncp, nc_hash); if (ncp->nc_flag & NCF_ISDOTDOT) { diff --git a/sys/kern/vfs_default.c b/sys/kern/vfs_default.c index 6ee094b..fd83f87 100644 --- a/sys/kern/vfs_default.c +++ b/sys/kern/vfs_default.c @@ -731,12 +731,13 @@ vop_stdgetpages(ap) struct vnode *a_vp; vm_page_t *a_m; int a_count; - int a_reqpage; + int *a_rbehind; + int *a_rahead; } */ *ap; { return vnode_pager_generic_getpages(ap->a_vp, ap->a_m, - ap->a_count, ap->a_reqpage, NULL, NULL); + ap->a_count, ap->a_rbehind, ap->a_rahead, NULL, NULL); } static int @@ -744,8 +745,9 @@ vop_stdgetpages_async(struct vop_getpages_async_args *ap) { int error; - error = VOP_GETPAGES(ap->a_vp, ap->a_m, ap->a_count, ap->a_reqpage); - ap->a_iodone(ap->a_arg, ap->a_m, ap->a_reqpage, error); + error = VOP_GETPAGES(ap->a_vp, ap->a_m, ap->a_count, ap->a_rbehind, + ap->a_rahead); + ap->a_iodone(ap->a_arg, ap->a_m, ap->a_count, error); return (error); } @@ -1034,10 +1036,9 @@ vop_stdallocate(struct vop_allocate_args *ap) int vop_stdadvise(struct vop_advise_args *ap) { - struct buf *bp; - struct buflists *bl; struct vnode *vp; - daddr_t bn, startn, endn; + struct bufobj *bo; + daddr_t startn, endn; off_t start, end; int bsize, error; @@ -1074,36 +1075,21 @@ vop_stdadvise(struct vop_advise_args *ap) VM_OBJECT_WUNLOCK(vp->v_object); } - BO_RLOCK(&vp->v_bufobj); + bo = &vp->v_bufobj; + BO_RLOCK(bo); bsize = vp->v_bufobj.bo_bsize; startn = ap->a_start / bsize; - endn = -1; - bl = &vp->v_bufobj.bo_clean.bv_hd; - if (!TAILQ_EMPTY(bl)) - endn = TAILQ_LAST(bl, buflists)->b_lblkno; - bl = &vp->v_bufobj.bo_dirty.bv_hd; - if (!TAILQ_EMPTY(bl) && - endn < TAILQ_LAST(bl, buflists)->b_lblkno) - endn = TAILQ_LAST(bl, buflists)->b_lblkno; - if (ap->a_end != OFF_MAX && endn != -1) - endn = ap->a_end / bsize; - BO_RUNLOCK(&vp->v_bufobj); - /* - * In the VMIO case, use the B_NOREUSE flag to hint that the - * pages backing each buffer in the range are unlikely to be - * reused. Dirty buffers will have the hint applied once - * they've been written. - */ - for (bn = startn; bn <= endn; bn++) { - bp = getblk(vp, bn, bsize, 0, 0, GB_NOCREAT | - GB_UNMAPPED); - if (bp == NULL) + endn = ap->a_end / bsize; + for (;;) { + error = bnoreuselist(&bo->bo_clean, bo, startn, endn); + if (error == EAGAIN) + continue; + error = bnoreuselist(&bo->bo_dirty, bo, startn, endn); + if (error == EAGAIN) continue; - bp->b_flags |= B_RELBUF; - if (vp->v_object != NULL) - bp->b_flags |= B_NOREUSE; - brelse(bp); + break; } + BO_RUNLOCK(bo); VOP_UNLOCK(vp, 0); break; default: diff --git a/sys/kern/vfs_subr.c b/sys/kern/vfs_subr.c index 2ec5bc1..ace97e8 100644 --- a/sys/kern/vfs_subr.c +++ b/sys/kern/vfs_subr.c @@ -1652,15 +1652,53 @@ flushbuflist(struct bufv *bufv, int flags, struct bufobj *bo, int slpflag, bp->b_flags &= ~B_ASYNC; brelse(bp); BO_LOCK(bo); - if (nbp != NULL && - (nbp->b_bufobj != bo || - nbp->b_lblkno != lblkno || - (nbp->b_xflags & (BX_VNDIRTY | BX_VNCLEAN)) != xflags)) + nbp = gbincore(bo, lblkno); + if (nbp == NULL || (nbp->b_xflags & (BX_VNDIRTY | BX_VNCLEAN)) + != xflags) break; /* nbp invalid */ } return (retval); } +int +bnoreuselist(struct bufv *bufv, struct bufobj *bo, daddr_t startn, daddr_t endn) +{ + struct buf *bp; + int error; + daddr_t lblkno; + + ASSERT_BO_LOCKED(bo); + + for (lblkno = startn;; lblkno++) { + bp = BUF_PCTRIE_LOOKUP_GE(&bufv->bv_root, lblkno); + if (bp == NULL || bp->b_lblkno >= endn) + break; + error = BUF_TIMELOCK(bp, LK_EXCLUSIVE | LK_SLEEPFAIL | + LK_INTERLOCK, BO_LOCKPTR(bo), "brlsfl", 0, 0); + if (error != 0) { + BO_RLOCK(bo); + return (error != ENOLCK ? error : EAGAIN); + } + KASSERT(bp->b_bufobj == bo, + ("bp %p wrong b_bufobj %p should be %p", + bp, bp->b_bufobj, bo)); + if ((bp->b_flags & B_MANAGED) == 0) + bremfree(bp); + bp->b_flags |= B_RELBUF; + /* + * In the VMIO case, use the B_NOREUSE flag to hint that the + * pages backing each buffer in the range are unlikely to be + * reused. Dirty buffers will have the hint applied once + * they've been written. + */ + if (bp->b_vp->v_object != NULL) + bp->b_flags |= B_NOREUSE; + brelse(bp); + BO_RLOCK(bo); + } + return (0); +} + /* * Truncate a file's buffer and pages to a specified length. This * is in lieu of the old vinvalbuf mechanism, which performed unneeded diff --git a/sys/kern/vnode_if.src b/sys/kern/vnode_if.src index 63f8eb9..5586a14 100644 --- a/sys/kern/vnode_if.src +++ b/sys/kern/vnode_if.src @@ -473,7 +473,8 @@ vop_getpages { IN struct vnode *vp; IN vm_page_t *m; IN int count; - IN int reqpage; + IN int *rbehind; + IN int *rahead; }; @@ -483,7 +484,8 @@ vop_getpages_async { IN struct vnode *vp; IN vm_page_t *m; IN int count; - IN int reqpage; + IN int *rbehind; + IN int *rahead; IN vop_getpages_iodone_t *iodone; IN void *arg; }; diff --git a/sys/modules/Makefile b/sys/modules/Makefile index 85c3553..dc95750 100644 --- a/sys/modules/Makefile +++ b/sys/modules/Makefile @@ -346,6 +346,7 @@ SUBDIR= \ ${_syscons} \ sysvipc \ ${_ti} \ + tcp/fastpath \ tests/framework \ tests/callout_test \ tl \ diff --git a/sys/modules/tcp/fastpath/Makefile b/sys/modules/tcp/fastpath/Makefile new file mode 100644 index 0000000..526b39a --- /dev/null +++ b/sys/modules/tcp/fastpath/Makefile @@ -0,0 +1,15 @@ +# +# $FreeBSD$ +# + +.PATH: ${.CURDIR}/../../../netinet/tcp_stacks + +KMOD= fastpath +SRCS= fastpath.c + +# +# Enable full debugging +# +#CFLAGS += -g + +.include <bsd.kmod.mk> diff --git a/sys/net/if_stf.c b/sys/net/if_stf.c index cbcee14..5209bc8 100644 --- a/sys/net/if_stf.c +++ b/sys/net/if_stf.c @@ -101,6 +101,7 @@ #include <net/vnet.h> #include <netinet/in.h> +#include <netinet/in_fib.h> #include <netinet/in_systm.h> #include <netinet/ip.h> #include <netinet/ip_var.h> @@ -557,26 +558,13 @@ stf_checkaddr4(struct stf_softc *sc, struct in_addr *in, struct ifnet *inifp) * perform ingress filter */ if (sc && (STF2IFP(sc)->if_flags & IFF_LINK2) == 0 && inifp) { - struct sockaddr_in sin; - struct rtentry *rt; - - bzero(&sin, sizeof(sin)); - sin.sin_family = AF_INET; - sin.sin_len = sizeof(struct sockaddr_in); - sin.sin_addr = *in; - rt = rtalloc1_fib((struct sockaddr *)&sin, 0, - 0UL, sc->sc_fibnum); - if (!rt || rt->rt_ifp != inifp) { -#if 0 - log(LOG_WARNING, "%s: packet from 0x%x dropped " - "due to ingress filter\n", if_name(STF2IFP(sc)), - (u_int32_t)ntohl(sin.sin_addr.s_addr)); -#endif - if (rt) - RTFREE_LOCKED(rt); - return -1; - } - RTFREE_LOCKED(rt); + struct nhop4_basic nh4; + + if (fib4_lookup_nh_basic(sc->sc_fibnum, *in, 0, 0, &nh4) != 0) + return (-1); + + if (nh4.nh_ifp != inifp) + return (-1); } return 0; diff --git a/sys/net/route.h b/sys/net/route.h index c1d0997..66f4d77 100644 --- a/sys/net/route.h +++ b/sys/net/route.h @@ -83,6 +83,9 @@ struct rt_metrics { #define RTM_RTTUNIT 1000000 /* units for rtt, rttvar, as units per sec */ #define RTTTOPRHZ(r) ((r) / (RTM_RTTUNIT / PR_SLOWHZ)) +/* lle state is exported in rmx_state rt_metrics field */ +#define rmx_state rmx_weight + #define RT_DEFAULT_FIB 0 /* Explicitly mark fib=0 restricted cases */ #define RT_ALL_FIBS -1 /* Announce event for every fib */ #ifdef _KERNEL diff --git a/sys/netinet/if_ether.c b/sys/netinet/if_ether.c index 2214542..6ca4844 100644 --- a/sys/netinet/if_ether.c +++ b/sys/netinet/if_ether.c @@ -855,12 +855,20 @@ match: arp_check_update_lle(ah, isaddr, ifp, bridged, la); else if (itaddr.s_addr == myaddr.s_addr) { /* - * Reply to our address, but no lle exists yet. - * do we really have to create an entry? + * Request/reply to our address, but no lle exists yet. + * Try to create new llentry. */ la = lltable_alloc_entry(LLTABLE(ifp), 0, dst); - if (la == NULL) - goto drop; + if (la == NULL) { + + /* + * lle creation may fail if source address belongs + * to non-directly connected subnet. However, we + * will try to answer the request instead of dropping + * frame. + */ + goto reply; + } lltable_set_entry_addr(ifp, la, ar_sha(ah)); IF_AFDATA_WLOCK(ifp); @@ -1209,7 +1217,8 @@ arp_announce(struct ifnet *ifp) struct ifaddr *ifa; struct in_addr *addr, *head; - if (!(ifp->if_flags & IFF_UP) || (ifp->if_flags & IFF_NOARP)) + if (!(ifp->if_flags & IFF_UP) || (ifp->if_flags & IFF_NOARP) || + ifp->if_addr == NULL) return; entries = 8; @@ -1246,9 +1255,11 @@ arp_announce(struct ifnet *ifp) } IF_ADDR_RUNLOCK(ifp); - lladdr = IF_LLADDR(ifp); - for (i = 0; i < cnt; i++) { - arp_announce_addr(ifp, head + i, lladdr); + if (cnt > 0) { + lladdr = IF_LLADDR(ifp); + for (i = 0; i < cnt; i++) { + arp_announce_addr(ifp, head + i, lladdr); + } } free(head, M_TEMP); } diff --git a/sys/netinet/in_kdtrace.c b/sys/netinet/in_kdtrace.c index f39f0e8..0efe403 100644 --- a/sys/netinet/in_kdtrace.c +++ b/sys/netinet/in_kdtrace.c @@ -122,7 +122,7 @@ SDT_PROBE_DEFINE2_XLATE(tcp, , , debug__user, SDT_PROBE_DEFINE3_XLATE(tcp, , , debug__drop, "struct tcpcb *", "tcpsinfo_t *" , "struct tcphdr *", "tcpinfo_t *", - "uint8_t *", "ipinfo_t *") + "uint8_t *", "ipinfo_t *"); SDT_PROBE_DEFINE6_XLATE(tcp, , , state__change, "void *", "void *", diff --git a/sys/netinet/in_kdtrace.h b/sys/netinet/in_kdtrace.h index ba8355a..a36991e 100644 --- a/sys/netinet/in_kdtrace.h +++ b/sys/netinet/in_kdtrace.h @@ -32,13 +32,13 @@ SDT_PROBE6(ip, , , probe, arg0, arg1, arg2, arg3, arg4, arg5) #define UDP_PROBE(probe, arg0, arg1, arg2, arg3, arg4) \ SDT_PROBE5(udp, , , probe, arg0, arg1, arg2, arg3, arg4) -#define TCP_PROBE1(probe, arg0) \ +#define TCP_PROBE1(probe, arg0) \ SDT_PROBE1(tcp, , , probe, arg0) -#define TCP_PROBE2(probe, arg0, arg1) \ +#define TCP_PROBE2(probe, arg0, arg1) \ SDT_PROBE2(tcp, , , probe, arg0, arg1) -#define TCP_PROBE3(probe, arg0, arg1, arg2) \ +#define TCP_PROBE3(probe, arg0, arg1, arg2) \ SDT_PROBE3(tcp, , , probe, arg0, arg1, arg2) -#define TCP_PROBE4(probe, arg0, arg1, arg2, arg3) \ +#define TCP_PROBE4(probe, arg0, arg1, arg2, arg3) \ SDT_PROBE4(tcp, , , probe, arg0, arg1, arg2, arg3) #define TCP_PROBE5(probe, arg0, arg1, arg2, arg3, arg4) \ SDT_PROBE5(tcp, , , probe, arg0, arg1, arg2, arg3, arg4) diff --git a/sys/netinet/ip_carp.c b/sys/netinet/ip_carp.c index 6989da2..da0ceab 100644 --- a/sys/netinet/ip_carp.c +++ b/sys/netinet/ip_carp.c @@ -1045,7 +1045,7 @@ carp_send_na(struct carp_softc *sc) nd6_na_output_unsolicited_addr(sc->sc_carpdev, IFA_IN6(ifa), IFA_ND6_NA_BASE_FLAGS(sc->sc_carpdev, ifa)); - nd6_na_unsolicited_addr_delay(ifa); + DELAY(nd6_na_unsolicited_addr_delay(ifa)); } } diff --git a/sys/netinet/sctp_cc_functions.c b/sys/netinet/sctp_cc_functions.c index d616d19..0bddcfd 100644 --- a/sys/netinet/sctp_cc_functions.c +++ b/sys/netinet/sctp_cc_functions.c @@ -95,7 +95,7 @@ sctp_set_initial_cc_param(struct sctp_tcb *stcb, struct sctp_nets *net) } sctp_enforce_cwnd_limit(assoc, net); net->ssthresh = assoc->peers_rwnd; - SDT_PROBE(sctp, cwnd, net, init, + SDT_PROBE5(sctp, cwnd, net, init, stcb->asoc.my_vtag, ((stcb->sctp_ep->sctp_lport << 16) | (stcb->rport)), net, 0, net->cwnd); if (SCTP_BASE_SYSCTL(sctp_logging_level) & @@ -193,7 +193,7 @@ sctp_cwnd_update_after_fr(struct sctp_tcb *stcb, } net->cwnd = net->ssthresh; sctp_enforce_cwnd_limit(asoc, net); - SDT_PROBE(sctp, cwnd, net, fr, + SDT_PROBE5(sctp, cwnd, net, fr, stcb->asoc.my_vtag, ((stcb->sctp_ep->sctp_lport << 16) | (stcb->rport)), net, old_cwnd, net->cwnd); if (SCTP_BASE_SYSCTL(sctp_logging_level) & SCTP_CWND_MONITOR_ENABLE) { @@ -261,7 +261,7 @@ cc_bw_same(struct sctp_tcb *stcb, struct sctp_nets *net, uint64_t nbw, */ /* Probe point 5 */ probepoint |= ((5 << 16) | 1); - SDT_PROBE(sctp, cwnd, net, rttvar, + SDT_PROBE5(sctp, cwnd, net, rttvar, vtag, ((net->cc_mod.rtcc.lbw << 32) | nbw), ((net->cc_mod.rtcc.lbw_rtt << 32) | net->rtt), @@ -282,7 +282,7 @@ cc_bw_same(struct sctp_tcb *stcb, struct sctp_nets *net, uint64_t nbw, oth |= net->cc_mod.rtcc.step_cnt; oth <<= 16; oth |= net->cc_mod.rtcc.last_step_state; - SDT_PROBE(sctp, cwnd, net, rttstep, + SDT_PROBE5(sctp, cwnd, net, rttstep, vtag, ((net->cc_mod.rtcc.lbw << 32) | nbw), ((net->cc_mod.rtcc.lbw_rtt << 32) | net->rtt), @@ -306,7 +306,7 @@ cc_bw_same(struct sctp_tcb *stcb, struct sctp_nets *net, uint64_t nbw, */ /* Probe point 6 */ probepoint |= ((6 << 16) | 0); - SDT_PROBE(sctp, cwnd, net, rttvar, + SDT_PROBE5(sctp, cwnd, net, rttvar, vtag, ((net->cc_mod.rtcc.lbw << 32) | nbw), ((net->cc_mod.rtcc.lbw_rtt << 32) | net->rtt), @@ -318,7 +318,7 @@ cc_bw_same(struct sctp_tcb *stcb, struct sctp_nets *net, uint64_t nbw, oth |= net->cc_mod.rtcc.step_cnt; oth <<= 16; oth |= net->cc_mod.rtcc.last_step_state; - SDT_PROBE(sctp, cwnd, net, rttstep, + SDT_PROBE5(sctp, cwnd, net, rttstep, vtag, ((net->cc_mod.rtcc.lbw << 32) | nbw), ((net->cc_mod.rtcc.lbw_rtt << 32) | net->rtt), @@ -349,7 +349,7 @@ cc_bw_same(struct sctp_tcb *stcb, struct sctp_nets *net, uint64_t nbw, */ /* Probe point 7 */ probepoint |= ((7 << 16) | net->cc_mod.rtcc.ret_from_eq); - SDT_PROBE(sctp, cwnd, net, rttvar, + SDT_PROBE5(sctp, cwnd, net, rttvar, vtag, ((net->cc_mod.rtcc.lbw << 32) | nbw), ((net->cc_mod.rtcc.lbw_rtt << 32) | net->rtt), @@ -398,7 +398,7 @@ cc_bw_decrease(struct sctp_tcb *stcb, struct sctp_nets *net, uint64_t nbw, uint6 /* We caused it maybe.. back off? */ /* PROBE POINT 1 */ probepoint |= ((1 << 16) | 1); - SDT_PROBE(sctp, cwnd, net, rttvar, + SDT_PROBE5(sctp, cwnd, net, rttvar, vtag, ((net->cc_mod.rtcc.lbw << 32) | nbw), ((net->cc_mod.rtcc.lbw_rtt << 32) | net->rtt), @@ -416,7 +416,7 @@ cc_bw_decrease(struct sctp_tcb *stcb, struct sctp_nets *net, uint64_t nbw, uint6 } /* Probe point 2 */ probepoint |= ((2 << 16) | 0); - SDT_PROBE(sctp, cwnd, net, rttvar, + SDT_PROBE5(sctp, cwnd, net, rttvar, vtag, ((net->cc_mod.rtcc.lbw << 32) | nbw), ((net->cc_mod.rtcc.lbw_rtt << 32) | net->rtt), @@ -429,7 +429,7 @@ cc_bw_decrease(struct sctp_tcb *stcb, struct sctp_nets *net, uint64_t nbw, uint6 oth |= net->cc_mod.rtcc.step_cnt; oth <<= 16; oth |= net->cc_mod.rtcc.last_step_state; - SDT_PROBE(sctp, cwnd, net, rttstep, + SDT_PROBE5(sctp, cwnd, net, rttstep, vtag, ((net->cc_mod.rtcc.lbw << 32) | nbw), ((net->cc_mod.rtcc.lbw_rtt << 32) | net->rtt), @@ -453,7 +453,7 @@ cc_bw_decrease(struct sctp_tcb *stcb, struct sctp_nets *net, uint64_t nbw, uint6 /* bw & rtt decreased */ /* Probe point 3 */ probepoint |= ((3 << 16) | 0); - SDT_PROBE(sctp, cwnd, net, rttvar, + SDT_PROBE5(sctp, cwnd, net, rttvar, vtag, ((net->cc_mod.rtcc.lbw << 32) | nbw), ((net->cc_mod.rtcc.lbw_rtt << 32) | net->rtt), @@ -465,7 +465,7 @@ cc_bw_decrease(struct sctp_tcb *stcb, struct sctp_nets *net, uint64_t nbw, uint6 oth |= net->cc_mod.rtcc.step_cnt; oth <<= 16; oth |= net->cc_mod.rtcc.last_step_state; - SDT_PROBE(sctp, cwnd, net, rttstep, + SDT_PROBE5(sctp, cwnd, net, rttstep, vtag, ((net->cc_mod.rtcc.lbw << 32) | nbw), ((net->cc_mod.rtcc.lbw_rtt << 32) | net->rtt), @@ -485,7 +485,7 @@ cc_bw_decrease(struct sctp_tcb *stcb, struct sctp_nets *net, uint64_t nbw, uint6 /* The bw decreased but rtt stayed the same */ /* Probe point 4 */ probepoint |= ((4 << 16) | 0); - SDT_PROBE(sctp, cwnd, net, rttvar, + SDT_PROBE5(sctp, cwnd, net, rttvar, vtag, ((net->cc_mod.rtcc.lbw << 32) | nbw), ((net->cc_mod.rtcc.lbw_rtt << 32) | net->rtt), @@ -497,7 +497,7 @@ cc_bw_decrease(struct sctp_tcb *stcb, struct sctp_nets *net, uint64_t nbw, uint6 oth |= net->cc_mod.rtcc.step_cnt; oth <<= 16; oth |= net->cc_mod.rtcc.last_step_state; - SDT_PROBE(sctp, cwnd, net, rttstep, + SDT_PROBE5(sctp, cwnd, net, rttstep, vtag, ((net->cc_mod.rtcc.lbw << 32) | nbw), ((net->cc_mod.rtcc.lbw_rtt << 32) | net->rtt), @@ -535,7 +535,7 @@ cc_bw_increase(struct sctp_tcb *stcb, struct sctp_nets *net, uint64_t nbw, uint6 */ /* PROBE POINT 0 */ probepoint = (((uint64_t) net->cwnd) << 32); - SDT_PROBE(sctp, cwnd, net, rttvar, + SDT_PROBE5(sctp, cwnd, net, rttvar, vtag, ((net->cc_mod.rtcc.lbw << 32) | nbw), ((net->cc_mod.rtcc.lbw_rtt << 32) | net->rtt), @@ -547,7 +547,7 @@ cc_bw_increase(struct sctp_tcb *stcb, struct sctp_nets *net, uint64_t nbw, uint6 oth |= net->cc_mod.rtcc.step_cnt; oth <<= 16; oth |= net->cc_mod.rtcc.last_step_state; - SDT_PROBE(sctp, cwnd, net, rttstep, + SDT_PROBE5(sctp, cwnd, net, rttstep, vtag, ((net->cc_mod.rtcc.lbw << 32) | nbw), ((net->cc_mod.rtcc.lbw_rtt << 32) | net->rtt), @@ -647,7 +647,7 @@ cc_bw_limit(struct sctp_tcb *stcb, struct sctp_nets *net, uint64_t nbw) /* Can't determine do not change */ probepoint |= ((0xd << 16) | inst_ind); } - SDT_PROBE(sctp, cwnd, net, rttvar, + SDT_PROBE5(sctp, cwnd, net, rttvar, vtag, ((nbw << 32) | inst_bw), ((net->cc_mod.rtcc.lbw_rtt << 32) | rtt), @@ -807,7 +807,7 @@ sctp_cwnd_update_after_sack_common(struct sctp_tcb *stcb, (((uint32_t) (stcb->sctp_ep->sctp_lport)) << 16) | (stcb->rport); - SDT_PROBE(sctp, cwnd, net, rttvar, + SDT_PROBE5(sctp, cwnd, net, rttvar, vtag, nbw, ((net->cc_mod.rtcc.lbw_rtt << 32) | net->rtt), @@ -906,7 +906,7 @@ sctp_cwnd_update_after_sack_common(struct sctp_tcb *stcb, sctp_log_cwnd(stcb, net, incr, SCTP_CWND_LOG_FROM_SS); } - SDT_PROBE(sctp, cwnd, net, ack, + SDT_PROBE5(sctp, cwnd, net, ack, stcb->asoc.my_vtag, ((stcb->sctp_ep->sctp_lport << 16) | (stcb->rport)), net, @@ -969,7 +969,7 @@ sctp_cwnd_update_after_sack_common(struct sctp_tcb *stcb, } net->cwnd += incr; sctp_enforce_cwnd_limit(asoc, net); - SDT_PROBE(sctp, cwnd, net, ack, + SDT_PROBE5(sctp, cwnd, net, ack, stcb->asoc.my_vtag, ((stcb->sctp_ep->sctp_lport << 16) | (stcb->rport)), net, @@ -1001,7 +1001,7 @@ sctp_cwnd_update_exit_pf_common(struct sctp_tcb *stcb, struct sctp_nets *net) old_cwnd = net->cwnd; net->cwnd = net->mtu; - SDT_PROBE(sctp, cwnd, net, ack, + SDT_PROBE5(sctp, cwnd, net, ack, stcb->asoc.my_vtag, ((stcb->sctp_ep->sctp_lport << 16) | (stcb->rport)), net, old_cwnd, net->cwnd); SCTPDBG(SCTP_DEBUG_INDATA1, "Destination %p moved from PF to reachable with cwnd %d.\n", @@ -1072,7 +1072,7 @@ sctp_cwnd_update_after_timeout(struct sctp_tcb *stcb, struct sctp_nets *net) } net->cwnd = net->mtu; net->partial_bytes_acked = 0; - SDT_PROBE(sctp, cwnd, net, to, + SDT_PROBE5(sctp, cwnd, net, to, stcb->asoc.my_vtag, ((stcb->sctp_ep->sctp_lport << 16) | (stcb->rport)), net, @@ -1132,7 +1132,7 @@ sctp_cwnd_update_after_ecn_echo_common(struct sctp_tcb *stcb, struct sctp_nets * net->RTO <<= 1; } net->cwnd = net->ssthresh; - SDT_PROBE(sctp, cwnd, net, ecn, + SDT_PROBE5(sctp, cwnd, net, ecn, stcb->asoc.my_vtag, ((stcb->sctp_ep->sctp_lport << 16) | (stcb->rport)), net, @@ -1251,7 +1251,7 @@ sctp_cwnd_update_after_packet_dropped(struct sctp_tcb *stcb, sctp_enforce_cwnd_limit(&stcb->asoc, net); if (net->cwnd - old_cwnd != 0) { /* log only changes */ - SDT_PROBE(sctp, cwnd, net, pd, + SDT_PROBE5(sctp, cwnd, net, pd, stcb->asoc.my_vtag, ((stcb->sctp_ep->sctp_lport << 16) | (stcb->rport)), net, @@ -1274,7 +1274,7 @@ sctp_cwnd_update_after_output(struct sctp_tcb *stcb, if (burst_limit) { net->cwnd = (net->flight_size + (burst_limit * net->mtu)); sctp_enforce_cwnd_limit(&stcb->asoc, net); - SDT_PROBE(sctp, cwnd, net, bl, + SDT_PROBE5(sctp, cwnd, net, bl, stcb->asoc.my_vtag, ((stcb->sctp_ep->sctp_lport << 16) | (stcb->rport)), net, @@ -1350,7 +1350,7 @@ sctp_cwnd_new_rtcc_transmission_begins(struct sctp_tcb *stcb, probepoint = (((uint64_t) net->cwnd) << 32); /* Probe point 8 */ probepoint |= ((8 << 16) | 0); - SDT_PROBE(sctp, cwnd, net, rttvar, + SDT_PROBE5(sctp, cwnd, net, rttvar, vtag, ((net->cc_mod.rtcc.lbw << 32) | 0), ((net->cc_mod.rtcc.lbw_rtt << 32) | net->rtt), @@ -1413,7 +1413,7 @@ sctp_set_rtcc_initial_cc_param(struct sctp_tcb *stcb, vtag = (net->rtt << 32) | (((uint32_t) (stcb->sctp_ep->sctp_lport)) << 16) | (stcb->rport); - SDT_PROBE(sctp, cwnd, net, rttvar, + SDT_PROBE5(sctp, cwnd, net, rttvar, vtag, 0, 0, diff --git a/sys/netinet/tcp.h b/sys/netinet/tcp.h index 3760860..294e994 100644 --- a/sys/netinet/tcp.h +++ b/sys/netinet/tcp.h @@ -167,7 +167,7 @@ struct tcphdr { #define TCP_KEEPCNT 1024 /* L,N number of keepalives before close */ #define TCP_PCAP_OUT 2048 /* number of output packets to keep */ #define TCP_PCAP_IN 4096 /* number of input packets to keep */ - +#define TCP_FUNCTION_BLK 8192 /* Set the tcp function pointers to the specified stack */ /* Start of reserved space for third-party user-settable options. */ #define TCP_VENDOR SO_VENDOR @@ -245,5 +245,11 @@ struct tcp_info { u_int32_t __tcpi_pad[26]; /* Padding. */ }; #endif +#define TCP_FUNCTION_NAME_LEN_MAX 32 + +struct tcp_function_set { + char function_set_name[TCP_FUNCTION_NAME_LEN_MAX]; + uint32_t pcbcnt; +}; #endif /* !_NETINET_TCP_H_ */ diff --git a/sys/netinet/tcp_input.c b/sys/netinet/tcp_input.c index f73c397..140cee7 100644 --- a/sys/netinet/tcp_input.c +++ b/sys/netinet/tcp_input.c @@ -230,23 +230,6 @@ VNET_DEFINE(struct inpcbhead, tcb); #define tcb6 tcb /* for KAME src sync over BSD*'s */ VNET_DEFINE(struct inpcbinfo, tcbinfo); -static void tcp_dooptions(struct tcpopt *, u_char *, int, int); -static void tcp_do_segment(struct mbuf *, struct tcphdr *, - struct socket *, struct tcpcb *, int, int, uint8_t, - int); -static void tcp_dropwithreset(struct mbuf *, struct tcphdr *, - struct tcpcb *, int, int); -static void tcp_pulloutofband(struct socket *, - struct tcphdr *, struct mbuf *, int); -static void tcp_xmit_timer(struct tcpcb *, int); -static void tcp_newreno_partial_ack(struct tcpcb *, struct tcphdr *); -static void inline cc_ack_received(struct tcpcb *tp, struct tcphdr *th, - uint16_t type); -static void inline cc_conn_init(struct tcpcb *tp); -static void inline cc_post_recovery(struct tcpcb *tp, struct tcphdr *th); -static void inline hhook_run_tcp_est_in(struct tcpcb *tp, - struct tcphdr *th, struct tcpopt *to); - /* * TCP statistics are stored in an "array" of counter(9)s. */ @@ -272,7 +255,7 @@ kmod_tcpstat_inc(int statnum) /* * Wrapper for the TCP established input helper hook. */ -static void inline +void hhook_run_tcp_est_in(struct tcpcb *tp, struct tcphdr *th, struct tcpopt *to) { struct tcp_hhook_data hhook_data; @@ -290,7 +273,7 @@ hhook_run_tcp_est_in(struct tcpcb *tp, struct tcphdr *th, struct tcpopt *to) /* * CC wrapper hook functions */ -static void inline +void cc_ack_received(struct tcpcb *tp, struct tcphdr *th, uint16_t type) { INP_WLOCK_ASSERT(tp->t_inpcb); @@ -322,7 +305,7 @@ cc_ack_received(struct tcpcb *tp, struct tcphdr *th, uint16_t type) } } -static void inline +void cc_conn_init(struct tcpcb *tp) { struct hc_metrics_lite metrics; @@ -446,7 +429,7 @@ cc_cong_signal(struct tcpcb *tp, struct tcphdr *th, uint32_t type) } } -static void inline +void inline cc_post_recovery(struct tcpcb *tp, struct tcphdr *th) { INP_WLOCK_ASSERT(tp->t_inpcb); @@ -601,9 +584,6 @@ tcp_input(struct mbuf **mp, int *offp, int proto) struct tcpopt to; /* options in this segment */ char *s = NULL; /* address and port logging */ int ti_locked; -#define TI_UNLOCKED 1 -#define TI_RLOCKED 2 - #ifdef TCPDEBUG /* * The size of tcp_saveipgen must be the size of the max ip header, @@ -1175,7 +1155,7 @@ relocked: * contains. tcp_do_segment() consumes * the mbuf chain and unlocks the inpcb. */ - tcp_do_segment(m, th, so, tp, drop_hdrlen, tlen, + tp->t_fb->tfb_tcp_do_segment(m, th, so, tp, drop_hdrlen, tlen, iptos, ti_locked); INP_INFO_UNLOCK_ASSERT(&V_tcbinfo); return (IPPROTO_DONE); @@ -1421,7 +1401,7 @@ relocked: * state. tcp_do_segment() always consumes the mbuf chain, unlocks * the inpcb, and unlocks pcbinfo. */ - tcp_do_segment(m, th, so, tp, drop_hdrlen, tlen, iptos, ti_locked); + tp->t_fb->tfb_tcp_do_segment(m, th, so, tp, drop_hdrlen, tlen, iptos, ti_locked); INP_INFO_UNLOCK_ASSERT(&V_tcbinfo); return (IPPROTO_DONE); @@ -1476,7 +1456,7 @@ drop: return (IPPROTO_DONE); } -static void +void tcp_do_segment(struct mbuf *m, struct tcphdr *th, struct socket *so, struct tcpcb *tp, int drop_hdrlen, int tlen, uint8_t iptos, int ti_locked) @@ -1788,7 +1768,7 @@ tcp_do_segment(struct mbuf *m, struct tcphdr *th, struct socket *so, tp->t_rxtcur); sowwakeup(so); if (sbavail(&so->so_snd)) - (void) tcp_output(tp); + (void) tp->t_fb->tfb_tcp_output(tp); goto check_delack; } } else if (th->th_ack == tp->snd_una && @@ -1907,7 +1887,7 @@ tcp_do_segment(struct mbuf *m, struct tcphdr *th, struct socket *so, tp->t_flags |= TF_DELACK; } else { tp->t_flags |= TF_ACKNOW; - tcp_output(tp); + tp->t_fb->tfb_tcp_output(tp); } goto check_delack; } @@ -2522,7 +2502,7 @@ tcp_do_segment(struct mbuf *m, struct tcphdr *th, struct socket *so, } } else tp->snd_cwnd += tp->t_maxseg; - (void) tcp_output(tp); + (void) tp->t_fb->tfb_tcp_output(tp); goto drop; } else if (tp->t_dupacks == tcprexmtthresh) { tcp_seq onxt = tp->snd_nxt; @@ -2556,12 +2536,12 @@ tcp_do_segment(struct mbuf *m, struct tcphdr *th, struct socket *so, tcps_sack_recovery_episode); tp->sack_newdata = tp->snd_nxt; tp->snd_cwnd = tp->t_maxseg; - (void) tcp_output(tp); + (void) tp->t_fb->tfb_tcp_output(tp); goto drop; } tp->snd_nxt = th->th_ack; tp->snd_cwnd = tp->t_maxseg; - (void) tcp_output(tp); + (void) tp->t_fb->tfb_tcp_output(tp); KASSERT(tp->snd_limited <= 2, ("%s: tp->snd_limited too big", __func__)); @@ -2608,7 +2588,7 @@ tcp_do_segment(struct mbuf *m, struct tcphdr *th, struct socket *so, (tp->snd_nxt - tp->snd_una); SOCKBUF_UNLOCK(&so->so_snd); if (avail > 0) - (void) tcp_output(tp); + (void) tp->t_fb->tfb_tcp_output(tp); sent = tp->snd_max - oldsndmax; if (sent > tp->t_maxseg) { KASSERT((tp->t_dupacks == 2 && @@ -3074,7 +3054,7 @@ dodata: /* XXX */ * Return any desired output. */ if (needoutput || (tp->t_flags & TF_ACKNOW)) - (void) tcp_output(tp); + (void) tp->t_fb->tfb_tcp_output(tp); check_delack: KASSERT(ti_locked == TI_UNLOCKED, ("%s: check_delack ti_locked %d", @@ -3122,7 +3102,7 @@ dropafterack: ti_locked = TI_UNLOCKED; tp->t_flags |= TF_ACKNOW; - (void) tcp_output(tp); + (void) tp->t_fb->tfb_tcp_output(tp); INP_WUNLOCK(tp->t_inpcb); m_freem(m); return; @@ -3168,7 +3148,7 @@ drop: * The mbuf must still include the original packet header. * tp may be NULL. */ -static void +void tcp_dropwithreset(struct mbuf *m, struct tcphdr *th, struct tcpcb *tp, int tlen, int rstreason) { @@ -3231,7 +3211,7 @@ drop: /* * Parse TCP options and place in tcpopt. */ -static void +void tcp_dooptions(struct tcpopt *to, u_char *cp, int cnt, int flags) { int opt, optlen; @@ -3325,7 +3305,7 @@ tcp_dooptions(struct tcpopt *to, u_char *cp, int cnt, int flags) * It is still reflected in the segment length for * sequencing purposes. */ -static void +void tcp_pulloutofband(struct socket *so, struct tcphdr *th, struct mbuf *m, int off) { @@ -3358,7 +3338,7 @@ tcp_pulloutofband(struct socket *so, struct tcphdr *th, struct mbuf *m, * Collect new round-trip time estimate * and update averages and current timeout. */ -static void +void tcp_xmit_timer(struct tcpcb *tp, int rtt) { int delta; @@ -3738,7 +3718,7 @@ tcp_mssopt(struct in_conninfo *inc) * By setting snd_nxt to ti_ack, this forces retransmission timer to * be started again. */ -static void +void tcp_newreno_partial_ack(struct tcpcb *tp, struct tcphdr *th) { tcp_seq onxt = tp->snd_nxt; @@ -3755,7 +3735,7 @@ tcp_newreno_partial_ack(struct tcpcb *tp, struct tcphdr *th) */ tp->snd_cwnd = tp->t_maxseg + BYTES_THIS_ACK(tp, th); tp->t_flags |= TF_ACKNOW; - (void) tcp_output(tp); + (void) tp->t_fb->tfb_tcp_output(tp); tp->snd_cwnd = ocwnd; if (SEQ_GT(onxt, tp->snd_nxt)) tp->snd_nxt = onxt; diff --git a/sys/netinet/tcp_sack.c b/sys/netinet/tcp_sack.c index 82e2251..1e31871 100644 --- a/sys/netinet/tcp_sack.c +++ b/sys/netinet/tcp_sack.c @@ -599,7 +599,7 @@ tcp_sack_partialack(struct tcpcb *tp, struct tcphdr *th) if (tp->snd_cwnd > tp->snd_ssthresh) tp->snd_cwnd = tp->snd_ssthresh; tp->t_flags |= TF_ACKNOW; - (void) tcp_output(tp); + (void) tp->t_fb->tfb_tcp_output(tp); } #if 0 diff --git a/sys/netinet/tcp_stacks/fastpath.c b/sys/netinet/tcp_stacks/fastpath.c new file mode 100644 index 0000000..85b24f6 --- /dev/null +++ b/sys/netinet/tcp_stacks/fastpath.c @@ -0,0 +1,2461 @@ +/*- + * Copyright (c) 1982, 1986, 1988, 1990, 1993, 1994, 1995 + * The Regents of the University of California. All rights reserved. + * Copyright (c) 2007-2008,2010 + * Swinburne University of Technology, Melbourne, Australia. + * Copyright (c) 2009-2010 Lawrence Stewart <lstewart@freebsd.org> + * Copyright (c) 2010 The FreeBSD Foundation + * Copyright (c) 2010-2011 Juniper Networks, Inc. + * Copyright (c) 2015 Netflix Inc. + * All rights reserved. + * + * Portions of this software were developed at the Centre for Advanced Internet + * Architectures, Swinburne University of Technology, by Lawrence Stewart, + * James Healy and David Hayes, made possible in part by a grant from the Cisco + * University Research Program Fund at Community Foundation Silicon Valley. + * + * Portions of this software were developed at the Centre for Advanced + * Internet Architectures, Swinburne University of Technology, Melbourne, + * Australia by David Hayes under sponsorship from the FreeBSD Foundation. + * + * Portions of this software were developed by Robert N. M. Watson under + * contract to Juniper Networks, Inc. + * + * Portions of this software were developed by Randall R. Stewart while + * working for Netflix Inc. + * + * 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. + * 4. Neither the name of the University nor the names of its contributors + * may be used to endorse or promote products derived from this software + * without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE REGENTS 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 REGENTS 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. + * + * @(#)tcp_input.c 8.12 (Berkeley) 5/24/95 + */ + +#include <sys/cdefs.h> +__FBSDID("$FreeBSD$"); + +#include "opt_ipfw.h" /* for ipfw_fwd */ +#include "opt_inet.h" +#include "opt_inet6.h" +#include "opt_ipsec.h" +#include "opt_kdtrace.h" +#include "opt_tcpdebug.h" + +#include <sys/param.h> +#include <sys/module.h> +#include <sys/kernel.h> +#include <sys/hhook.h> +#include <sys/malloc.h> +#include <sys/mbuf.h> +#include <sys/proc.h> /* for proc0 declaration */ +#include <sys/protosw.h> +#include <sys/sdt.h> +#include <sys/signalvar.h> +#include <sys/socket.h> +#include <sys/socketvar.h> +#include <sys/sysctl.h> +#include <sys/syslog.h> +#include <sys/systm.h> + +#include <machine/cpu.h> /* before tcp_seq.h, for tcp_random18() */ + +#include <vm/uma.h> + +#include <net/if.h> +#include <net/if_var.h> +#include <net/route.h> +#include <net/vnet.h> + +#define TCPSTATES /* for logging */ + +#include <netinet/cc.h> +#include <netinet/in.h> +#include <netinet/in_kdtrace.h> +#include <netinet/in_pcb.h> +#include <netinet/in_systm.h> +#include <netinet/in_var.h> +#include <netinet/ip.h> +#include <netinet/ip_icmp.h> /* required for icmp_var.h */ +#include <netinet/icmp_var.h> /* for ICMP_BANDLIM */ +#include <netinet/ip_var.h> +#include <netinet/ip_options.h> +#include <netinet/ip6.h> +#include <netinet/icmp6.h> +#include <netinet6/in6_pcb.h> +#include <netinet6/ip6_var.h> +#include <netinet6/nd6.h> +#include <netinet/tcp_fsm.h> +#include <netinet/tcp_seq.h> +#include <netinet/tcp_timer.h> +#include <netinet/tcp_var.h> +#include <netinet6/tcp6_var.h> +#include <netinet/tcpip.h> +#include <netinet/tcp_syncache.h> +#ifdef TCPDEBUG +#include <netinet/tcp_debug.h> +#endif /* TCPDEBUG */ +#ifdef TCP_OFFLOAD +#include <netinet/tcp_offload.h> +#endif + +#ifdef IPSEC +#include <netipsec/ipsec.h> +#include <netipsec/ipsec6.h> +#endif /*IPSEC*/ + +#include <machine/in_cksum.h> + +#include <security/mac/mac_framework.h> + +const int tcprexmtthresh; + +VNET_DECLARE(int, tcp_autorcvbuf_inc); +#define V_tcp_autorcvbuf_inc VNET(tcp_autorcvbuf_inc) +VNET_DECLARE(int, tcp_autorcvbuf_max); +#define V_tcp_autorcvbuf_max VNET(tcp_autorcvbuf_max) +VNET_DECLARE(int, tcp_do_rfc3042); +#define V_tcp_do_rfc3042 VNET(tcp_do_rfc3042) +VNET_DECLARE(int, tcp_do_autorcvbuf); +#define V_tcp_do_autorcvbuf VNET(tcp_do_autorcvbuf) +VNET_DECLARE(int, tcp_insecure_rst); +#define V_tcp_insecure_rst VNET(tcp_insecure_rst) +VNET_DECLARE(int, tcp_insecure_syn); +#define V_tcp_insecure_syn VNET(tcp_insecure_syn) + +static void tcp_do_segment_fastslow(struct mbuf *, struct tcphdr *, + struct socket *, struct tcpcb *, int, int, uint8_t, + int); + +static void tcp_do_segment_fastack(struct mbuf *, struct tcphdr *, + struct socket *, struct tcpcb *, int, int, uint8_t, + int); + +/* + * Indicate whether this ack should be delayed. We can delay the ack if + * following conditions are met: + * - There is no delayed ack timer in progress. + * - Our last ack wasn't a 0-sized window. We never want to delay + * the ack that opens up a 0-sized window. + * - LRO wasn't used for this segment. We make sure by checking that the + * segment size is not larger than the MSS. + * - Delayed acks are enabled or this is a half-synchronized T/TCP + * connection. + */ +#define DELAY_ACK(tp, tlen) \ + ((!tcp_timer_active(tp, TT_DELACK) && \ + (tp->t_flags & TF_RXWIN0SENT) == 0) && \ + (tlen <= tp->t_maxopd) && \ + (V_tcp_delack_enabled || (tp->t_flags & TF_NEEDSYN))) + +/* + * So how is this faster than the normal fast ack? + * It basically allows us to also stay in the fastpath + * when a window-update ack also arrives. In testing + * we saw only 25-30% of connections doing fastpath + * due to the fact that along with moving forward + * in sequence the window was also updated. + */ +static void +tcp_do_fastack(struct mbuf *m, struct tcphdr *th, struct socket *so, + struct tcpcb *tp, struct tcpopt *to, int drop_hdrlen, int tlen, + int ti_locked, u_long tiwin) +{ + int acked; + int winup_only=0; +#ifdef TCPDEBUG + /* + * The size of tcp_saveipgen must be the size of the max ip header, + * now IPv6. + */ + u_char tcp_saveipgen[IP6_HDR_LEN]; + struct tcphdr tcp_savetcp; + short ostate = 0; +#endif + /* + * The following if statment will be true if + * we are doing the win_up_in_fp <and> + * - We have more new data (SEQ_LT(tp->snd_wl1, th->th_seq)) <or> + * - No more new data, but we have an ack for new data + * (tp->snd_wl1 == th->th_seq && SEQ_LT(tp->snd_wl2, th->th_ack)) + * - No more new data, the same ack point but the window grew + * (tp->snd_wl1 == th->th_seq && tp->snd_wl2 == th->th_ack && twin > tp->snd_wnd) + */ + if ((SEQ_LT(tp->snd_wl1, th->th_seq) || + (tp->snd_wl1 == th->th_seq && (SEQ_LT(tp->snd_wl2, th->th_ack) || + (tp->snd_wl2 == th->th_ack && tiwin > tp->snd_wnd))))) { + /* keep track of pure window updates */ + if (tp->snd_wl2 == th->th_ack && tiwin > tp->snd_wnd) { + winup_only = 1; + TCPSTAT_INC(tcps_rcvwinupd); + } + tp->snd_wnd = tiwin; + tp->snd_wl1 = th->th_seq; + tp->snd_wl2 = th->th_ack; + if (tp->snd_wnd > tp->max_sndwnd) + tp->max_sndwnd = tp->snd_wnd; + } + /* + * If last ACK falls within this segment's sequence numbers, + * record the timestamp. + * NOTE that the test is modified according to the latest + * proposal of the tcplw@cray.com list (Braden 1993/04/26). + */ + if ((to->to_flags & TOF_TS) != 0 && + SEQ_LEQ(th->th_seq, tp->last_ack_sent)) { + tp->ts_recent_age = tcp_ts_getticks(); + tp->ts_recent = to->to_tsval; + } + /* + * This is a pure ack for outstanding data. + */ + if (ti_locked == TI_RLOCKED) { + INP_INFO_RUNLOCK(&V_tcbinfo); + } + ti_locked = TI_UNLOCKED; + + TCPSTAT_INC(tcps_predack); + + /* + * "bad retransmit" recovery. + */ + if (tp->t_rxtshift == 1 && + tp->t_flags & TF_PREVVALID && + (int)(ticks - tp->t_badrxtwin) < 0) { + cc_cong_signal(tp, th, CC_RTO_ERR); + } + + /* + * Recalculate the transmit timer / rtt. + * + * Some boxes send broken timestamp replies + * during the SYN+ACK phase, ignore + * timestamps of 0 or we could calculate a + * huge RTT and blow up the retransmit timer. + */ + if ((to->to_flags & TOF_TS) != 0 && + to->to_tsecr) { + u_int t; + + t = tcp_ts_getticks() - to->to_tsecr; + if (!tp->t_rttlow || tp->t_rttlow > t) + tp->t_rttlow = t; + tcp_xmit_timer(tp, + TCP_TS_TO_TICKS(t) + 1); + } else if (tp->t_rtttime && + SEQ_GT(th->th_ack, tp->t_rtseq)) { + if (!tp->t_rttlow || + tp->t_rttlow > ticks - tp->t_rtttime) + tp->t_rttlow = ticks - tp->t_rtttime; + tcp_xmit_timer(tp, + ticks - tp->t_rtttime); + } + if (winup_only == 0) { + acked = BYTES_THIS_ACK(tp, th); + + /* Run HHOOK_TCP_ESTABLISHED_IN helper hooks. */ + hhook_run_tcp_est_in(tp, th, to); + + TCPSTAT_ADD(tcps_rcvackbyte, acked); + sbdrop(&so->so_snd, acked); + if (SEQ_GT(tp->snd_una, tp->snd_recover) && + SEQ_LEQ(th->th_ack, tp->snd_recover)) + tp->snd_recover = th->th_ack - 1; + + /* + * Let the congestion control algorithm update + * congestion control related information. This + * typically means increasing the congestion + * window. + */ + cc_ack_received(tp, th, CC_ACK); + + tp->snd_una = th->th_ack; + /* + * Pull snd_wl2 up to prevent seq wrap relative + * to th_ack. + */ + tp->snd_wl2 = th->th_ack; + tp->t_dupacks = 0; + m_freem(m); + + /* + * If all outstanding data are acked, stop + * retransmit timer, otherwise restart timer + * using current (possibly backed-off) value. + * If process is waiting for space, + * wakeup/selwakeup/signal. If data + * are ready to send, let tcp_output + * decide between more output or persist. + */ +#ifdef TCPDEBUG + if (so->so_options & SO_DEBUG) + tcp_trace(TA_INPUT, ostate, tp, + (void *)tcp_saveipgen, + &tcp_savetcp, 0); +#endif + if (tp->snd_una == tp->snd_max) + tcp_timer_activate(tp, TT_REXMT, 0); + else if (!tcp_timer_active(tp, TT_PERSIST)) + tcp_timer_activate(tp, TT_REXMT, + tp->t_rxtcur); + } else { + /* + * Window update only, just free the mbufs and + * send out whatever we can. + */ + m_freem(m); + } + sowwakeup(so); + if (sbavail(&so->so_snd)) + (void) tcp_output(tp); + KASSERT(ti_locked == TI_UNLOCKED, ("%s: check_delack ti_locked %d", + __func__, ti_locked)); + INP_INFO_UNLOCK_ASSERT(&V_tcbinfo); + INP_WLOCK_ASSERT(tp->t_inpcb); + + if (tp->t_flags & TF_DELACK) { + tp->t_flags &= ~TF_DELACK; + tcp_timer_activate(tp, TT_DELACK, tcp_delacktime); + } + INP_WUNLOCK(tp->t_inpcb); +} + +/* + * Here nothing is really faster, its just that we + * have broken out the fast-data path also just like + * the fast-ack. + */ +static void +tcp_do_fastnewdata(struct mbuf *m, struct tcphdr *th, struct socket *so, + struct tcpcb *tp, struct tcpopt *to, int drop_hdrlen, int tlen, + int ti_locked, u_long tiwin) +{ + int newsize = 0; /* automatic sockbuf scaling */ +#ifdef TCPDEBUG + /* + * The size of tcp_saveipgen must be the size of the max ip header, + * now IPv6. + */ + u_char tcp_saveipgen[IP6_HDR_LEN]; + struct tcphdr tcp_savetcp; + short ostate = 0; +#endif + /* + * If last ACK falls within this segment's sequence numbers, + * record the timestamp. + * NOTE that the test is modified according to the latest + * proposal of the tcplw@cray.com list (Braden 1993/04/26). + */ + if ((to->to_flags & TOF_TS) != 0 && + SEQ_LEQ(th->th_seq, tp->last_ack_sent)) { + tp->ts_recent_age = tcp_ts_getticks(); + tp->ts_recent = to->to_tsval; + } + + /* + * This is a pure, in-sequence data packet with + * nothing on the reassembly queue and we have enough + * buffer space to take it. + */ + if (ti_locked == TI_RLOCKED) { + INP_INFO_RUNLOCK(&V_tcbinfo); + } + ti_locked = TI_UNLOCKED; + + /* Clean receiver SACK report if present */ + if ((tp->t_flags & TF_SACK_PERMIT) && tp->rcv_numsacks) + tcp_clean_sackreport(tp); + TCPSTAT_INC(tcps_preddat); + tp->rcv_nxt += tlen; + /* + * Pull snd_wl1 up to prevent seq wrap relative to + * th_seq. + */ + tp->snd_wl1 = th->th_seq; + /* + * Pull rcv_up up to prevent seq wrap relative to + * rcv_nxt. + */ + tp->rcv_up = tp->rcv_nxt; + TCPSTAT_ADD(tcps_rcvbyte, tlen); +#ifdef TCPDEBUG + if (so->so_options & SO_DEBUG) + tcp_trace(TA_INPUT, ostate, tp, + (void *)tcp_saveipgen, &tcp_savetcp, 0); +#endif + /* + * Automatic sizing of receive socket buffer. Often the send + * buffer size is not optimally adjusted to the actual network + * conditions at hand (delay bandwidth product). Setting the + * buffer size too small limits throughput on links with high + * bandwidth and high delay (eg. trans-continental/oceanic links). + * + * On the receive side the socket buffer memory is only rarely + * used to any significant extent. This allows us to be much + * more aggressive in scaling the receive socket buffer. For + * the case that the buffer space is actually used to a large + * extent and we run out of kernel memory we can simply drop + * the new segments; TCP on the sender will just retransmit it + * later. Setting the buffer size too big may only consume too + * much kernel memory if the application doesn't read() from + * the socket or packet loss or reordering makes use of the + * reassembly queue. + * + * The criteria to step up the receive buffer one notch are: + * 1. Application has not set receive buffer size with + * SO_RCVBUF. Setting SO_RCVBUF clears SB_AUTOSIZE. + * 2. the number of bytes received during the time it takes + * one timestamp to be reflected back to us (the RTT); + * 3. received bytes per RTT is within seven eighth of the + * current socket buffer size; + * 4. receive buffer size has not hit maximal automatic size; + * + * This algorithm does one step per RTT at most and only if + * we receive a bulk stream w/o packet losses or reorderings. + * Shrinking the buffer during idle times is not necessary as + * it doesn't consume any memory when idle. + * + * TODO: Only step up if the application is actually serving + * the buffer to better manage the socket buffer resources. + */ + if (V_tcp_do_autorcvbuf && + (to->to_flags & TOF_TS) && + to->to_tsecr && + (so->so_rcv.sb_flags & SB_AUTOSIZE)) { + if (TSTMP_GT(to->to_tsecr, tp->rfbuf_ts) && + to->to_tsecr - tp->rfbuf_ts < hz) { + if (tp->rfbuf_cnt > + (so->so_rcv.sb_hiwat / 8 * 7) && + so->so_rcv.sb_hiwat < + V_tcp_autorcvbuf_max) { + newsize = + min(so->so_rcv.sb_hiwat + + V_tcp_autorcvbuf_inc, + V_tcp_autorcvbuf_max); + } + /* Start over with next RTT. */ + tp->rfbuf_ts = 0; + tp->rfbuf_cnt = 0; + } else + tp->rfbuf_cnt += tlen; /* add up */ + } + + /* Add data to socket buffer. */ + SOCKBUF_LOCK(&so->so_rcv); + if (so->so_rcv.sb_state & SBS_CANTRCVMORE) { + m_freem(m); + } else { + /* + * Set new socket buffer size. + * Give up when limit is reached. + */ + if (newsize) + if (!sbreserve_locked(&so->so_rcv, + newsize, so, NULL)) + so->so_rcv.sb_flags &= ~SB_AUTOSIZE; + m_adj(m, drop_hdrlen); /* delayed header drop */ + sbappendstream_locked(&so->so_rcv, m, 0); + } + /* NB: sorwakeup_locked() does an implicit unlock. */ + sorwakeup_locked(so); + if (DELAY_ACK(tp, tlen)) { + tp->t_flags |= TF_DELACK; + } else { + tp->t_flags |= TF_ACKNOW; + tcp_output(tp); + } + KASSERT(ti_locked == TI_UNLOCKED, ("%s: check_delack ti_locked %d", + __func__, ti_locked)); + INP_INFO_UNLOCK_ASSERT(&V_tcbinfo); + INP_WLOCK_ASSERT(tp->t_inpcb); + + if (tp->t_flags & TF_DELACK) { + tp->t_flags &= ~TF_DELACK; + tcp_timer_activate(tp, TT_DELACK, tcp_delacktime); + } + INP_WUNLOCK(tp->t_inpcb); +} + +/* + * The slow-path is the clone of the long long part + * of tcp_do_segment past all the fast-path stuff. We + * use it here by two different callers, the fast/slow and + * the fastack only. + */ +static void +tcp_do_slowpath(struct mbuf *m, struct tcphdr *th, struct socket *so, + struct tcpcb *tp, struct tcpopt *to, int drop_hdrlen, int tlen, + int ti_locked, u_long tiwin, int thflags) +{ + int acked, ourfinisacked, needoutput = 0; + int rstreason, todrop, win; + char *s; + struct in_conninfo *inc; + struct mbuf *mfree = NULL; +#ifdef TCPDEBUG + /* + * The size of tcp_saveipgen must be the size of the max ip header, + * now IPv6. + */ + u_char tcp_saveipgen[IP6_HDR_LEN]; + struct tcphdr tcp_savetcp; + short ostate = 0; +#endif + /* + * Calculate amount of space in receive window, + * and then do TCP input processing. + * Receive window is amount of space in rcv queue, + * but not less than advertised window. + */ + inc = &tp->t_inpcb->inp_inc; + win = sbspace(&so->so_rcv); + if (win < 0) + win = 0; + tp->rcv_wnd = imax(win, (int)(tp->rcv_adv - tp->rcv_nxt)); + + /* Reset receive buffer auto scaling when not in bulk receive mode. */ + tp->rfbuf_ts = 0; + tp->rfbuf_cnt = 0; + + switch (tp->t_state) { + + /* + * If the state is SYN_RECEIVED: + * if seg contains an ACK, but not for our SYN/ACK, send a RST. + */ + case TCPS_SYN_RECEIVED: + if ((thflags & TH_ACK) && + (SEQ_LEQ(th->th_ack, tp->snd_una) || + SEQ_GT(th->th_ack, tp->snd_max))) { + rstreason = BANDLIM_RST_OPENPORT; + goto dropwithreset; + } + break; + + /* + * If the state is SYN_SENT: + * if seg contains an ACK, but not for our SYN, drop the input. + * if seg contains a RST, then drop the connection. + * if seg does not contain SYN, then drop it. + * Otherwise this is an acceptable SYN segment + * initialize tp->rcv_nxt and tp->irs + * if seg contains ack then advance tp->snd_una + * if seg contains an ECE and ECN support is enabled, the stream + * is ECN capable. + * if SYN has been acked change to ESTABLISHED else SYN_RCVD state + * arrange for segment to be acked (eventually) + * continue processing rest of data/controls, beginning with URG + */ + case TCPS_SYN_SENT: + if ((thflags & TH_ACK) && + (SEQ_LEQ(th->th_ack, tp->iss) || + SEQ_GT(th->th_ack, tp->snd_max))) { + rstreason = BANDLIM_UNLIMITED; + goto dropwithreset; + } + if ((thflags & (TH_ACK|TH_RST)) == (TH_ACK|TH_RST)) { + TCP_PROBE5(connect__refused, NULL, tp, + mtod(m, const char *), tp, th); + tp = tcp_drop(tp, ECONNREFUSED); + } + if (thflags & TH_RST) + goto drop; + if (!(thflags & TH_SYN)) + goto drop; + + tp->irs = th->th_seq; + tcp_rcvseqinit(tp); + if (thflags & TH_ACK) { + TCPSTAT_INC(tcps_connects); + soisconnected(so); +#ifdef MAC + mac_socketpeer_set_from_mbuf(m, so); +#endif + /* Do window scaling on this connection? */ + if ((tp->t_flags & (TF_RCVD_SCALE|TF_REQ_SCALE)) == + (TF_RCVD_SCALE|TF_REQ_SCALE)) { + tp->rcv_scale = tp->request_r_scale; + } + tp->rcv_adv += imin(tp->rcv_wnd, + TCP_MAXWIN << tp->rcv_scale); + tp->snd_una++; /* SYN is acked */ + /* + * If there's data, delay ACK; if there's also a FIN + * ACKNOW will be turned on later. + */ + if (DELAY_ACK(tp, tlen) && tlen != 0) + tcp_timer_activate(tp, TT_DELACK, + tcp_delacktime); + else + tp->t_flags |= TF_ACKNOW; + + if ((thflags & TH_ECE) && V_tcp_do_ecn) { + tp->t_flags |= TF_ECN_PERMIT; + TCPSTAT_INC(tcps_ecn_shs); + } + + /* + * Received <SYN,ACK> in SYN_SENT[*] state. + * Transitions: + * SYN_SENT --> ESTABLISHED + * SYN_SENT* --> FIN_WAIT_1 + */ + tp->t_starttime = ticks; + if (tp->t_flags & TF_NEEDFIN) { + tcp_state_change(tp, TCPS_FIN_WAIT_1); + tp->t_flags &= ~TF_NEEDFIN; + thflags &= ~TH_SYN; + } else { + tcp_state_change(tp, TCPS_ESTABLISHED); + TCP_PROBE5(connect__established, NULL, tp, + mtod(m, const char *), tp, th); + cc_conn_init(tp); + tcp_timer_activate(tp, TT_KEEP, + TP_KEEPIDLE(tp)); + } + } else { + /* + * Received initial SYN in SYN-SENT[*] state => + * simultaneous open. + * If it succeeds, connection is * half-synchronized. + * Otherwise, do 3-way handshake: + * SYN-SENT -> SYN-RECEIVED + * SYN-SENT* -> SYN-RECEIVED* + */ + tp->t_flags |= (TF_ACKNOW | TF_NEEDSYN); + tcp_timer_activate(tp, TT_REXMT, 0); + tcp_state_change(tp, TCPS_SYN_RECEIVED); + } + + KASSERT(ti_locked == TI_RLOCKED, ("%s: trimthenstep6: " + "ti_locked %d", __func__, ti_locked)); + INP_INFO_RLOCK_ASSERT(&V_tcbinfo); + INP_WLOCK_ASSERT(tp->t_inpcb); + + /* + * Advance th->th_seq to correspond to first data byte. + * If data, trim to stay within window, + * dropping FIN if necessary. + */ + th->th_seq++; + if (tlen > tp->rcv_wnd) { + todrop = tlen - tp->rcv_wnd; + m_adj(m, -todrop); + tlen = tp->rcv_wnd; + thflags &= ~TH_FIN; + TCPSTAT_INC(tcps_rcvpackafterwin); + TCPSTAT_ADD(tcps_rcvbyteafterwin, todrop); + } + tp->snd_wl1 = th->th_seq - 1; + tp->rcv_up = th->th_seq; + /* + * Client side of transaction: already sent SYN and data. + * If the remote host used T/TCP to validate the SYN, + * our data will be ACK'd; if so, enter normal data segment + * processing in the middle of step 5, ack processing. + * Otherwise, goto step 6. + */ + if (thflags & TH_ACK) + goto process_ACK; + + goto step6; + + /* + * If the state is LAST_ACK or CLOSING or TIME_WAIT: + * do normal processing. + * + * NB: Leftover from RFC1644 T/TCP. Cases to be reused later. + */ + case TCPS_LAST_ACK: + case TCPS_CLOSING: + break; /* continue normal processing */ + } + + /* + * States other than LISTEN or SYN_SENT. + * First check the RST flag and sequence number since reset segments + * are exempt from the timestamp and connection count tests. This + * fixes a bug introduced by the Stevens, vol. 2, p. 960 bugfix + * below which allowed reset segments in half the sequence space + * to fall though and be processed (which gives forged reset + * segments with a random sequence number a 50 percent chance of + * killing a connection). + * Then check timestamp, if present. + * Then check the connection count, if present. + * Then check that at least some bytes of segment are within + * receive window. If segment begins before rcv_nxt, + * drop leading data (and SYN); if nothing left, just ack. + */ + if (thflags & TH_RST) { + /* + * RFC5961 Section 3.2 + * + * - RST drops connection only if SEG.SEQ == RCV.NXT. + * - If RST is in window, we send challenge ACK. + * + * Note: to take into account delayed ACKs, we should + * test against last_ack_sent instead of rcv_nxt. + * Note 2: we handle special case of closed window, not + * covered by the RFC. + */ + if ((SEQ_GEQ(th->th_seq, tp->last_ack_sent) && + SEQ_LT(th->th_seq, tp->last_ack_sent + tp->rcv_wnd)) || + (tp->rcv_wnd == 0 && tp->last_ack_sent == th->th_seq)) { + INP_INFO_RLOCK_ASSERT(&V_tcbinfo); + KASSERT(ti_locked == TI_RLOCKED, + ("%s: TH_RST ti_locked %d, th %p tp %p", + __func__, ti_locked, th, tp)); + KASSERT(tp->t_state != TCPS_SYN_SENT, + ("%s: TH_RST for TCPS_SYN_SENT th %p tp %p", + __func__, th, tp)); + + if (V_tcp_insecure_rst || + tp->last_ack_sent == th->th_seq) { + TCPSTAT_INC(tcps_drops); + /* Drop the connection. */ + switch (tp->t_state) { + case TCPS_SYN_RECEIVED: + so->so_error = ECONNREFUSED; + goto close; + case TCPS_ESTABLISHED: + case TCPS_FIN_WAIT_1: + case TCPS_FIN_WAIT_2: + case TCPS_CLOSE_WAIT: + so->so_error = ECONNRESET; + close: + tcp_state_change(tp, TCPS_CLOSED); + /* FALLTHROUGH */ + default: + tp = tcp_close(tp); + } + } else { + TCPSTAT_INC(tcps_badrst); + /* Send challenge ACK. */ + tcp_respond(tp, mtod(m, void *), th, m, + tp->rcv_nxt, tp->snd_nxt, TH_ACK); + tp->last_ack_sent = tp->rcv_nxt; + m = NULL; + } + } + goto drop; + } + + /* + * RFC5961 Section 4.2 + * Send challenge ACK for any SYN in synchronized state. + */ + if ((thflags & TH_SYN) && tp->t_state != TCPS_SYN_SENT) { + KASSERT(ti_locked == TI_RLOCKED, + ("tcp_do_segment: TH_SYN ti_locked %d", ti_locked)); + INP_INFO_RLOCK_ASSERT(&V_tcbinfo); + + TCPSTAT_INC(tcps_badsyn); + if (V_tcp_insecure_syn && + SEQ_GEQ(th->th_seq, tp->last_ack_sent) && + SEQ_LT(th->th_seq, tp->last_ack_sent + tp->rcv_wnd)) { + tp = tcp_drop(tp, ECONNRESET); + rstreason = BANDLIM_UNLIMITED; + } else { + /* Send challenge ACK. */ + tcp_respond(tp, mtod(m, void *), th, m, tp->rcv_nxt, + tp->snd_nxt, TH_ACK); + tp->last_ack_sent = tp->rcv_nxt; + m = NULL; + } + goto drop; + } + + /* + * RFC 1323 PAWS: If we have a timestamp reply on this segment + * and it's less than ts_recent, drop it. + */ + if ((to->to_flags & TOF_TS) != 0 && tp->ts_recent && + TSTMP_LT(to->to_tsval, tp->ts_recent)) { + + /* Check to see if ts_recent is over 24 days old. */ + if (tcp_ts_getticks() - tp->ts_recent_age > TCP_PAWS_IDLE) { + /* + * Invalidate ts_recent. If this segment updates + * ts_recent, the age will be reset later and ts_recent + * will get a valid value. If it does not, setting + * ts_recent to zero will at least satisfy the + * requirement that zero be placed in the timestamp + * echo reply when ts_recent isn't valid. The + * age isn't reset until we get a valid ts_recent + * because we don't want out-of-order segments to be + * dropped when ts_recent is old. + */ + tp->ts_recent = 0; + } else { + TCPSTAT_INC(tcps_rcvduppack); + TCPSTAT_ADD(tcps_rcvdupbyte, tlen); + TCPSTAT_INC(tcps_pawsdrop); + if (tlen) + goto dropafterack; + goto drop; + } + } + + /* + * In the SYN-RECEIVED state, validate that the packet belongs to + * this connection before trimming the data to fit the receive + * window. Check the sequence number versus IRS since we know + * the sequence numbers haven't wrapped. This is a partial fix + * for the "LAND" DoS attack. + */ + if (tp->t_state == TCPS_SYN_RECEIVED && SEQ_LT(th->th_seq, tp->irs)) { + rstreason = BANDLIM_RST_OPENPORT; + goto dropwithreset; + } + + todrop = tp->rcv_nxt - th->th_seq; + if (todrop > 0) { + if (thflags & TH_SYN) { + thflags &= ~TH_SYN; + th->th_seq++; + if (th->th_urp > 1) + th->th_urp--; + else + thflags &= ~TH_URG; + todrop--; + } + /* + * Following if statement from Stevens, vol. 2, p. 960. + */ + if (todrop > tlen + || (todrop == tlen && (thflags & TH_FIN) == 0)) { + /* + * Any valid FIN must be to the left of the window. + * At this point the FIN must be a duplicate or out + * of sequence; drop it. + */ + thflags &= ~TH_FIN; + + /* + * Send an ACK to resynchronize and drop any data. + * But keep on processing for RST or ACK. + */ + tp->t_flags |= TF_ACKNOW; + todrop = tlen; + TCPSTAT_INC(tcps_rcvduppack); + TCPSTAT_ADD(tcps_rcvdupbyte, todrop); + } else { + TCPSTAT_INC(tcps_rcvpartduppack); + TCPSTAT_ADD(tcps_rcvpartdupbyte, todrop); + } + drop_hdrlen += todrop; /* drop from the top afterwards */ + th->th_seq += todrop; + tlen -= todrop; + if (th->th_urp > todrop) + th->th_urp -= todrop; + else { + thflags &= ~TH_URG; + th->th_urp = 0; + } + } + + /* + * If new data are received on a connection after the + * user processes are gone, then RST the other end. + */ + if ((so->so_state & SS_NOFDREF) && + tp->t_state > TCPS_CLOSE_WAIT && tlen) { + KASSERT(ti_locked == TI_RLOCKED, ("%s: SS_NOFDEREF && " + "CLOSE_WAIT && tlen ti_locked %d", __func__, ti_locked)); + INP_INFO_RLOCK_ASSERT(&V_tcbinfo); + + if ((s = tcp_log_addrs(inc, th, NULL, NULL))) { + log(LOG_DEBUG, "%s; %s: %s: Received %d bytes of data " + "after socket was closed, " + "sending RST and removing tcpcb\n", + s, __func__, tcpstates[tp->t_state], tlen); + free(s, M_TCPLOG); + } + tp = tcp_close(tp); + TCPSTAT_INC(tcps_rcvafterclose); + rstreason = BANDLIM_UNLIMITED; + goto dropwithreset; + } + + /* + * If segment ends after window, drop trailing data + * (and PUSH and FIN); if nothing left, just ACK. + */ + todrop = (th->th_seq + tlen) - (tp->rcv_nxt + tp->rcv_wnd); + if (todrop > 0) { + TCPSTAT_INC(tcps_rcvpackafterwin); + if (todrop >= tlen) { + TCPSTAT_ADD(tcps_rcvbyteafterwin, tlen); + /* + * If window is closed can only take segments at + * window edge, and have to drop data and PUSH from + * incoming segments. Continue processing, but + * remember to ack. Otherwise, drop segment + * and ack. + */ + if (tp->rcv_wnd == 0 && th->th_seq == tp->rcv_nxt) { + tp->t_flags |= TF_ACKNOW; + TCPSTAT_INC(tcps_rcvwinprobe); + } else + goto dropafterack; + } else + TCPSTAT_ADD(tcps_rcvbyteafterwin, todrop); + m_adj(m, -todrop); + tlen -= todrop; + thflags &= ~(TH_PUSH|TH_FIN); + } + + /* + * If last ACK falls within this segment's sequence numbers, + * record its timestamp. + * NOTE: + * 1) That the test incorporates suggestions from the latest + * proposal of the tcplw@cray.com list (Braden 1993/04/26). + * 2) That updating only on newer timestamps interferes with + * our earlier PAWS tests, so this check should be solely + * predicated on the sequence space of this segment. + * 3) That we modify the segment boundary check to be + * Last.ACK.Sent <= SEG.SEQ + SEG.Len + * instead of RFC1323's + * Last.ACK.Sent < SEG.SEQ + SEG.Len, + * This modified check allows us to overcome RFC1323's + * limitations as described in Stevens TCP/IP Illustrated + * Vol. 2 p.869. In such cases, we can still calculate the + * RTT correctly when RCV.NXT == Last.ACK.Sent. + */ + if ((to->to_flags & TOF_TS) != 0 && + SEQ_LEQ(th->th_seq, tp->last_ack_sent) && + SEQ_LEQ(tp->last_ack_sent, th->th_seq + tlen + + ((thflags & (TH_SYN|TH_FIN)) != 0))) { + tp->ts_recent_age = tcp_ts_getticks(); + tp->ts_recent = to->to_tsval; + } + + /* + * If the ACK bit is off: if in SYN-RECEIVED state or SENDSYN + * flag is on (half-synchronized state), then queue data for + * later processing; else drop segment and return. + */ + if ((thflags & TH_ACK) == 0) { + if (tp->t_state == TCPS_SYN_RECEIVED || + (tp->t_flags & TF_NEEDSYN)) + goto step6; + else if (tp->t_flags & TF_ACKNOW) + goto dropafterack; + else + goto drop; + } + + /* + * Ack processing. + */ + switch (tp->t_state) { + + /* + * In SYN_RECEIVED state, the ack ACKs our SYN, so enter + * ESTABLISHED state and continue processing. + * The ACK was checked above. + */ + case TCPS_SYN_RECEIVED: + + TCPSTAT_INC(tcps_connects); + soisconnected(so); + /* Do window scaling? */ + if ((tp->t_flags & (TF_RCVD_SCALE|TF_REQ_SCALE)) == + (TF_RCVD_SCALE|TF_REQ_SCALE)) { + tp->rcv_scale = tp->request_r_scale; + tp->snd_wnd = tiwin; + } + /* + * Make transitions: + * SYN-RECEIVED -> ESTABLISHED + * SYN-RECEIVED* -> FIN-WAIT-1 + */ + tp->t_starttime = ticks; + if (tp->t_flags & TF_NEEDFIN) { + tcp_state_change(tp, TCPS_FIN_WAIT_1); + tp->t_flags &= ~TF_NEEDFIN; + } else { + tcp_state_change(tp, TCPS_ESTABLISHED); + TCP_PROBE5(accept__established, NULL, tp, + mtod(m, const char *), tp, th); + cc_conn_init(tp); + tcp_timer_activate(tp, TT_KEEP, TP_KEEPIDLE(tp)); + } + /* + * If segment contains data or ACK, will call tcp_reass() + * later; if not, do so now to pass queued data to user. + */ + if (tlen == 0 && (thflags & TH_FIN) == 0) + (void) tcp_reass(tp, (struct tcphdr *)0, 0, + (struct mbuf *)0); + tp->snd_wl1 = th->th_seq - 1; + /* FALLTHROUGH */ + + /* + * In ESTABLISHED state: drop duplicate ACKs; ACK out of range + * ACKs. If the ack is in the range + * tp->snd_una < th->th_ack <= tp->snd_max + * then advance tp->snd_una to th->th_ack and drop + * data from the retransmission queue. If this ACK reflects + * more up to date window information we update our window information. + */ + case TCPS_ESTABLISHED: + case TCPS_FIN_WAIT_1: + case TCPS_FIN_WAIT_2: + case TCPS_CLOSE_WAIT: + case TCPS_CLOSING: + case TCPS_LAST_ACK: + if (SEQ_GT(th->th_ack, tp->snd_max)) { + TCPSTAT_INC(tcps_rcvacktoomuch); + goto dropafterack; + } + if ((tp->t_flags & TF_SACK_PERMIT) && + ((to->to_flags & TOF_SACK) || + !TAILQ_EMPTY(&tp->snd_holes))) + tcp_sack_doack(tp, to, th->th_ack); + else + /* + * Reset the value so that previous (valid) value + * from the last ack with SACK doesn't get used. + */ + tp->sackhint.sacked_bytes = 0; + + /* Run HHOOK_TCP_ESTABLISHED_IN helper hooks. */ + hhook_run_tcp_est_in(tp, th, to); + + if (SEQ_LEQ(th->th_ack, tp->snd_una)) { + if (tlen == 0 && tiwin == tp->snd_wnd) { + /* + * If this is the first time we've seen a + * FIN from the remote, this is not a + * duplicate and it needs to be processed + * normally. This happens during a + * simultaneous close. + */ + if ((thflags & TH_FIN) && + (TCPS_HAVERCVDFIN(tp->t_state) == 0)) { + tp->t_dupacks = 0; + break; + } + TCPSTAT_INC(tcps_rcvdupack); + /* + * If we have outstanding data (other than + * a window probe), this is a completely + * duplicate ack (ie, window info didn't + * change and FIN isn't set), + * the ack is the biggest we've + * seen and we've seen exactly our rexmt + * threshhold of them, assume a packet + * has been dropped and retransmit it. + * Kludge snd_nxt & the congestion + * window so we send only this one + * packet. + * + * We know we're losing at the current + * window size so do congestion avoidance + * (set ssthresh to half the current window + * and pull our congestion window back to + * the new ssthresh). + * + * Dup acks mean that packets have left the + * network (they're now cached at the receiver) + * so bump cwnd by the amount in the receiver + * to keep a constant cwnd packets in the + * network. + * + * When using TCP ECN, notify the peer that + * we reduced the cwnd. + */ + if (!tcp_timer_active(tp, TT_REXMT) || + th->th_ack != tp->snd_una) + tp->t_dupacks = 0; + else if (++tp->t_dupacks > tcprexmtthresh || + IN_FASTRECOVERY(tp->t_flags)) { + cc_ack_received(tp, th, CC_DUPACK); + if ((tp->t_flags & TF_SACK_PERMIT) && + IN_FASTRECOVERY(tp->t_flags)) { + int awnd; + + /* + * Compute the amount of data in flight first. + * We can inject new data into the pipe iff + * we have less than 1/2 the original window's + * worth of data in flight. + */ + if (V_tcp_do_rfc6675_pipe) + awnd = tcp_compute_pipe(tp); + else + awnd = (tp->snd_nxt - tp->snd_fack) + + tp->sackhint.sack_bytes_rexmit; + + if (awnd < tp->snd_ssthresh) { + tp->snd_cwnd += tp->t_maxseg; + if (tp->snd_cwnd > tp->snd_ssthresh) + tp->snd_cwnd = tp->snd_ssthresh; + } + } else + tp->snd_cwnd += tp->t_maxseg; + (void) tp->t_fb->tfb_tcp_output(tp); + goto drop; + } else if (tp->t_dupacks == tcprexmtthresh) { + tcp_seq onxt = tp->snd_nxt; + + /* + * If we're doing sack, check to + * see if we're already in sack + * recovery. If we're not doing sack, + * check to see if we're in newreno + * recovery. + */ + if (tp->t_flags & TF_SACK_PERMIT) { + if (IN_FASTRECOVERY(tp->t_flags)) { + tp->t_dupacks = 0; + break; + } + } else { + if (SEQ_LEQ(th->th_ack, + tp->snd_recover)) { + tp->t_dupacks = 0; + break; + } + } + /* Congestion signal before ack. */ + cc_cong_signal(tp, th, CC_NDUPACK); + cc_ack_received(tp, th, CC_DUPACK); + tcp_timer_activate(tp, TT_REXMT, 0); + tp->t_rtttime = 0; + if (tp->t_flags & TF_SACK_PERMIT) { + TCPSTAT_INC( + tcps_sack_recovery_episode); + tp->sack_newdata = tp->snd_nxt; + tp->snd_cwnd = tp->t_maxseg; + (void) tp->t_fb->tfb_tcp_output(tp); + goto drop; + } + tp->snd_nxt = th->th_ack; + tp->snd_cwnd = tp->t_maxseg; + (void) tp->t_fb->tfb_tcp_output(tp); + KASSERT(tp->snd_limited <= 2, + ("%s: tp->snd_limited too big", + __func__)); + tp->snd_cwnd = tp->snd_ssthresh + + tp->t_maxseg * + (tp->t_dupacks - tp->snd_limited); + if (SEQ_GT(onxt, tp->snd_nxt)) + tp->snd_nxt = onxt; + goto drop; + } else if (V_tcp_do_rfc3042) { + /* + * Process first and second duplicate + * ACKs. Each indicates a segment + * leaving the network, creating room + * for more. Make sure we can send a + * packet on reception of each duplicate + * ACK by increasing snd_cwnd by one + * segment. Restore the original + * snd_cwnd after packet transmission. + */ + cc_ack_received(tp, th, CC_DUPACK); + u_long oldcwnd = tp->snd_cwnd; + tcp_seq oldsndmax = tp->snd_max; + u_int sent; + int avail; + + KASSERT(tp->t_dupacks == 1 || + tp->t_dupacks == 2, + ("%s: dupacks not 1 or 2", + __func__)); + if (tp->t_dupacks == 1) + tp->snd_limited = 0; + tp->snd_cwnd = + (tp->snd_nxt - tp->snd_una) + + (tp->t_dupacks - tp->snd_limited) * + tp->t_maxseg; + /* + * Only call tcp_output when there + * is new data available to be sent. + * Otherwise we would send pure ACKs. + */ + SOCKBUF_LOCK(&so->so_snd); + avail = sbavail(&so->so_snd) - + (tp->snd_nxt - tp->snd_una); + SOCKBUF_UNLOCK(&so->so_snd); + if (avail > 0) + (void) tp->t_fb->tfb_tcp_output(tp); + sent = tp->snd_max - oldsndmax; + if (sent > tp->t_maxseg) { + KASSERT((tp->t_dupacks == 2 && + tp->snd_limited == 0) || + (sent == tp->t_maxseg + 1 && + tp->t_flags & TF_SENTFIN), + ("%s: sent too much", + __func__)); + tp->snd_limited = 2; + } else if (sent > 0) + ++tp->snd_limited; + tp->snd_cwnd = oldcwnd; + goto drop; + } + } else + tp->t_dupacks = 0; + break; + } + + KASSERT(SEQ_GT(th->th_ack, tp->snd_una), + ("%s: th_ack <= snd_una", __func__)); + + /* + * If the congestion window was inflated to account + * for the other side's cached packets, retract it. + */ + if (IN_FASTRECOVERY(tp->t_flags)) { + if (SEQ_LT(th->th_ack, tp->snd_recover)) { + if (tp->t_flags & TF_SACK_PERMIT) + tcp_sack_partialack(tp, th); + else + tcp_newreno_partial_ack(tp, th); + } else + cc_post_recovery(tp, th); + } + tp->t_dupacks = 0; + /* + * If we reach this point, ACK is not a duplicate, + * i.e., it ACKs something we sent. + */ + if (tp->t_flags & TF_NEEDSYN) { + /* + * T/TCP: Connection was half-synchronized, and our + * SYN has been ACK'd (so connection is now fully + * synchronized). Go to non-starred state, + * increment snd_una for ACK of SYN, and check if + * we can do window scaling. + */ + tp->t_flags &= ~TF_NEEDSYN; + tp->snd_una++; + /* Do window scaling? */ + if ((tp->t_flags & (TF_RCVD_SCALE|TF_REQ_SCALE)) == + (TF_RCVD_SCALE|TF_REQ_SCALE)) { + tp->rcv_scale = tp->request_r_scale; + /* Send window already scaled. */ + } + } + +process_ACK: + INP_WLOCK_ASSERT(tp->t_inpcb); + + acked = BYTES_THIS_ACK(tp, th); + TCPSTAT_INC(tcps_rcvackpack); + TCPSTAT_ADD(tcps_rcvackbyte, acked); + + /* + * If we just performed our first retransmit, and the ACK + * arrives within our recovery window, then it was a mistake + * to do the retransmit in the first place. Recover our + * original cwnd and ssthresh, and proceed to transmit where + * we left off. + */ + if (tp->t_rxtshift == 1 && tp->t_flags & TF_PREVVALID && + (int)(ticks - tp->t_badrxtwin) < 0) + cc_cong_signal(tp, th, CC_RTO_ERR); + + /* + * If we have a timestamp reply, update smoothed + * round trip time. If no timestamp is present but + * transmit timer is running and timed sequence + * number was acked, update smoothed round trip time. + * Since we now have an rtt measurement, cancel the + * timer backoff (cf., Phil Karn's retransmit alg.). + * Recompute the initial retransmit timer. + * + * Some boxes send broken timestamp replies + * during the SYN+ACK phase, ignore + * timestamps of 0 or we could calculate a + * huge RTT and blow up the retransmit timer. + */ + if ((to->to_flags & TOF_TS) != 0 && to->to_tsecr) { + u_int t; + + t = tcp_ts_getticks() - to->to_tsecr; + if (!tp->t_rttlow || tp->t_rttlow > t) + tp->t_rttlow = t; + tcp_xmit_timer(tp, TCP_TS_TO_TICKS(t) + 1); + } else if (tp->t_rtttime && SEQ_GT(th->th_ack, tp->t_rtseq)) { + if (!tp->t_rttlow || tp->t_rttlow > ticks - tp->t_rtttime) + tp->t_rttlow = ticks - tp->t_rtttime; + tcp_xmit_timer(tp, ticks - tp->t_rtttime); + } + + /* + * If all outstanding data is acked, stop retransmit + * timer and remember to restart (more output or persist). + * If there is more data to be acked, restart retransmit + * timer, using current (possibly backed-off) value. + */ + if (th->th_ack == tp->snd_max) { + tcp_timer_activate(tp, TT_REXMT, 0); + needoutput = 1; + } else if (!tcp_timer_active(tp, TT_PERSIST)) + tcp_timer_activate(tp, TT_REXMT, tp->t_rxtcur); + + /* + * If no data (only SYN) was ACK'd, + * skip rest of ACK processing. + */ + if (acked == 0) + goto step6; + + /* + * Let the congestion control algorithm update congestion + * control related information. This typically means increasing + * the congestion window. + */ + cc_ack_received(tp, th, CC_ACK); + + SOCKBUF_LOCK(&so->so_snd); + if (acked > sbavail(&so->so_snd)) { + tp->snd_wnd -= sbavail(&so->so_snd); + mfree = sbcut_locked(&so->so_snd, + (int)sbavail(&so->so_snd)); + ourfinisacked = 1; + } else { + mfree = sbcut_locked(&so->so_snd, acked); + tp->snd_wnd -= acked; + ourfinisacked = 0; + } + /* NB: sowwakeup_locked() does an implicit unlock. */ + sowwakeup_locked(so); + m_freem(mfree); + /* Detect una wraparound. */ + if (!IN_RECOVERY(tp->t_flags) && + SEQ_GT(tp->snd_una, tp->snd_recover) && + SEQ_LEQ(th->th_ack, tp->snd_recover)) + tp->snd_recover = th->th_ack - 1; + /* XXXLAS: Can this be moved up into cc_post_recovery? */ + if (IN_RECOVERY(tp->t_flags) && + SEQ_GEQ(th->th_ack, tp->snd_recover)) { + EXIT_RECOVERY(tp->t_flags); + } + tp->snd_una = th->th_ack; + if (tp->t_flags & TF_SACK_PERMIT) { + if (SEQ_GT(tp->snd_una, tp->snd_recover)) + tp->snd_recover = tp->snd_una; + } + if (SEQ_LT(tp->snd_nxt, tp->snd_una)) + tp->snd_nxt = tp->snd_una; + + switch (tp->t_state) { + + /* + * In FIN_WAIT_1 STATE in addition to the processing + * for the ESTABLISHED state if our FIN is now acknowledged + * then enter FIN_WAIT_2. + */ + case TCPS_FIN_WAIT_1: + if (ourfinisacked) { + /* + * If we can't receive any more + * data, then closing user can proceed. + * Starting the timer is contrary to the + * specification, but if we don't get a FIN + * we'll hang forever. + * + * XXXjl: + * we should release the tp also, and use a + * compressed state. + */ + if (so->so_rcv.sb_state & SBS_CANTRCVMORE) { + soisdisconnected(so); + tcp_timer_activate(tp, TT_2MSL, + (tcp_fast_finwait2_recycle ? + tcp_finwait2_timeout : + TP_MAXIDLE(tp))); + } + tcp_state_change(tp, TCPS_FIN_WAIT_2); + } + break; + + /* + * In CLOSING STATE in addition to the processing for + * the ESTABLISHED state if the ACK acknowledges our FIN + * then enter the TIME-WAIT state, otherwise ignore + * the segment. + */ + case TCPS_CLOSING: + if (ourfinisacked) { + INP_INFO_RLOCK_ASSERT(&V_tcbinfo); + tcp_twstart(tp); + INP_INFO_RUNLOCK(&V_tcbinfo); + m_freem(m); + return; + } + break; + + /* + * In LAST_ACK, we may still be waiting for data to drain + * and/or to be acked, as well as for the ack of our FIN. + * If our FIN is now acknowledged, delete the TCB, + * enter the closed state and return. + */ + case TCPS_LAST_ACK: + if (ourfinisacked) { + INP_INFO_RLOCK_ASSERT(&V_tcbinfo); + tp = tcp_close(tp); + goto drop; + } + break; + } + } + +step6: + INP_WLOCK_ASSERT(tp->t_inpcb); + + /* + * Update window information. + * Don't look at window if no ACK: TAC's send garbage on first SYN. + */ + if ((thflags & TH_ACK) && + (SEQ_LT(tp->snd_wl1, th->th_seq) || + (tp->snd_wl1 == th->th_seq && (SEQ_LT(tp->snd_wl2, th->th_ack) || + (tp->snd_wl2 == th->th_ack && tiwin > tp->snd_wnd))))) { + /* keep track of pure window updates */ + if (tlen == 0 && + tp->snd_wl2 == th->th_ack && tiwin > tp->snd_wnd) + TCPSTAT_INC(tcps_rcvwinupd); + tp->snd_wnd = tiwin; + tp->snd_wl1 = th->th_seq; + tp->snd_wl2 = th->th_ack; + if (tp->snd_wnd > tp->max_sndwnd) + tp->max_sndwnd = tp->snd_wnd; + needoutput = 1; + } + + /* + * Process segments with URG. + */ + if ((thflags & TH_URG) && th->th_urp && + TCPS_HAVERCVDFIN(tp->t_state) == 0) { + /* + * This is a kludge, but if we receive and accept + * random urgent pointers, we'll crash in + * soreceive. It's hard to imagine someone + * actually wanting to send this much urgent data. + */ + SOCKBUF_LOCK(&so->so_rcv); + if (th->th_urp + sbavail(&so->so_rcv) > sb_max) { + th->th_urp = 0; /* XXX */ + thflags &= ~TH_URG; /* XXX */ + SOCKBUF_UNLOCK(&so->so_rcv); /* XXX */ + goto dodata; /* XXX */ + } + /* + * If this segment advances the known urgent pointer, + * then mark the data stream. This should not happen + * in CLOSE_WAIT, CLOSING, LAST_ACK or TIME_WAIT STATES since + * a FIN has been received from the remote side. + * In these states we ignore the URG. + * + * According to RFC961 (Assigned Protocols), + * the urgent pointer points to the last octet + * of urgent data. We continue, however, + * to consider it to indicate the first octet + * of data past the urgent section as the original + * spec states (in one of two places). + */ + if (SEQ_GT(th->th_seq+th->th_urp, tp->rcv_up)) { + tp->rcv_up = th->th_seq + th->th_urp; + so->so_oobmark = sbavail(&so->so_rcv) + + (tp->rcv_up - tp->rcv_nxt) - 1; + if (so->so_oobmark == 0) + so->so_rcv.sb_state |= SBS_RCVATMARK; + sohasoutofband(so); + tp->t_oobflags &= ~(TCPOOB_HAVEDATA | TCPOOB_HADDATA); + } + SOCKBUF_UNLOCK(&so->so_rcv); + /* + * Remove out of band data so doesn't get presented to user. + * This can happen independent of advancing the URG pointer, + * but if two URG's are pending at once, some out-of-band + * data may creep in... ick. + */ + if (th->th_urp <= (u_long)tlen && + !(so->so_options & SO_OOBINLINE)) { + /* hdr drop is delayed */ + tcp_pulloutofband(so, th, m, drop_hdrlen); + } + } else { + /* + * If no out of band data is expected, + * pull receive urgent pointer along + * with the receive window. + */ + if (SEQ_GT(tp->rcv_nxt, tp->rcv_up)) + tp->rcv_up = tp->rcv_nxt; + } +dodata: /* XXX */ + INP_WLOCK_ASSERT(tp->t_inpcb); + + /* + * Process the segment text, merging it into the TCP sequencing queue, + * and arranging for acknowledgment of receipt if necessary. + * This process logically involves adjusting tp->rcv_wnd as data + * is presented to the user (this happens in tcp_usrreq.c, + * case PRU_RCVD). If a FIN has already been received on this + * connection then we just ignore the text. + */ + if ((tlen || (thflags & TH_FIN)) && + TCPS_HAVERCVDFIN(tp->t_state) == 0) { + tcp_seq save_start = th->th_seq; + m_adj(m, drop_hdrlen); /* delayed header drop */ + /* + * Insert segment which includes th into TCP reassembly queue + * with control block tp. Set thflags to whether reassembly now + * includes a segment with FIN. This handles the common case + * inline (segment is the next to be received on an established + * connection, and the queue is empty), avoiding linkage into + * and removal from the queue and repetition of various + * conversions. + * Set DELACK for segments received in order, but ack + * immediately when segments are out of order (so + * fast retransmit can work). + */ + if (th->th_seq == tp->rcv_nxt && + LIST_EMPTY(&tp->t_segq) && + TCPS_HAVEESTABLISHED(tp->t_state)) { + if (DELAY_ACK(tp, tlen)) + tp->t_flags |= TF_DELACK; + else + tp->t_flags |= TF_ACKNOW; + tp->rcv_nxt += tlen; + thflags = th->th_flags & TH_FIN; + TCPSTAT_INC(tcps_rcvpack); + TCPSTAT_ADD(tcps_rcvbyte, tlen); + SOCKBUF_LOCK(&so->so_rcv); + if (so->so_rcv.sb_state & SBS_CANTRCVMORE) + m_freem(m); + else + sbappendstream_locked(&so->so_rcv, m, 0); + /* NB: sorwakeup_locked() does an implicit unlock. */ + sorwakeup_locked(so); + } else { + /* + * XXX: Due to the header drop above "th" is + * theoretically invalid by now. Fortunately + * m_adj() doesn't actually frees any mbufs + * when trimming from the head. + */ + thflags = tcp_reass(tp, th, &tlen, m); + tp->t_flags |= TF_ACKNOW; + } + if (tlen > 0 && (tp->t_flags & TF_SACK_PERMIT)) + tcp_update_sack_list(tp, save_start, save_start + tlen); +#if 0 + /* + * Note the amount of data that peer has sent into + * our window, in order to estimate the sender's + * buffer size. + * XXX: Unused. + */ + if (SEQ_GT(tp->rcv_adv, tp->rcv_nxt)) + len = so->so_rcv.sb_hiwat - (tp->rcv_adv - tp->rcv_nxt); + else + len = so->so_rcv.sb_hiwat; +#endif + } else { + m_freem(m); + thflags &= ~TH_FIN; + } + + /* + * If FIN is received ACK the FIN and let the user know + * that the connection is closing. + */ + if (thflags & TH_FIN) { + if (TCPS_HAVERCVDFIN(tp->t_state) == 0) { + socantrcvmore(so); + /* + * If connection is half-synchronized + * (ie NEEDSYN flag on) then delay ACK, + * so it may be piggybacked when SYN is sent. + * Otherwise, since we received a FIN then no + * more input can be expected, send ACK now. + */ + if (tp->t_flags & TF_NEEDSYN) + tp->t_flags |= TF_DELACK; + else + tp->t_flags |= TF_ACKNOW; + tp->rcv_nxt++; + } + switch (tp->t_state) { + + /* + * In SYN_RECEIVED and ESTABLISHED STATES + * enter the CLOSE_WAIT state. + */ + case TCPS_SYN_RECEIVED: + tp->t_starttime = ticks; + /* FALLTHROUGH */ + case TCPS_ESTABLISHED: + tcp_state_change(tp, TCPS_CLOSE_WAIT); + break; + + /* + * If still in FIN_WAIT_1 STATE FIN has not been acked so + * enter the CLOSING state. + */ + case TCPS_FIN_WAIT_1: + tcp_state_change(tp, TCPS_CLOSING); + break; + + /* + * In FIN_WAIT_2 state enter the TIME_WAIT state, + * starting the time-wait timer, turning off the other + * standard timers. + */ + case TCPS_FIN_WAIT_2: + INP_INFO_RLOCK_ASSERT(&V_tcbinfo); + KASSERT(ti_locked == TI_RLOCKED, ("%s: dodata " + "TCP_FIN_WAIT_2 ti_locked: %d", __func__, + ti_locked)); + + tcp_twstart(tp); + INP_INFO_RUNLOCK(&V_tcbinfo); + return; + } + } + if (ti_locked == TI_RLOCKED) { + INP_INFO_RUNLOCK(&V_tcbinfo); + } + ti_locked = TI_UNLOCKED; + +#ifdef TCPDEBUG + if (so->so_options & SO_DEBUG) + tcp_trace(TA_INPUT, ostate, tp, (void *)tcp_saveipgen, + &tcp_savetcp, 0); +#endif + TCP_PROBE3(debug__input, tp, th, mtod(m, const char *)); + + /* + * Return any desired output. + */ + if (needoutput || (tp->t_flags & TF_ACKNOW)) + (void) tp->t_fb->tfb_tcp_output(tp); + + KASSERT(ti_locked == TI_UNLOCKED, ("%s: check_delack ti_locked %d", + __func__, ti_locked)); + INP_INFO_UNLOCK_ASSERT(&V_tcbinfo); + INP_WLOCK_ASSERT(tp->t_inpcb); + + if (tp->t_flags & TF_DELACK) { + tp->t_flags &= ~TF_DELACK; + tcp_timer_activate(tp, TT_DELACK, tcp_delacktime); + } + INP_WUNLOCK(tp->t_inpcb); + return; + +dropafterack: + /* + * Generate an ACK dropping incoming segment if it occupies + * sequence space, where the ACK reflects our state. + * + * We can now skip the test for the RST flag since all + * paths to this code happen after packets containing + * RST have been dropped. + * + * In the SYN-RECEIVED state, don't send an ACK unless the + * segment we received passes the SYN-RECEIVED ACK test. + * If it fails send a RST. This breaks the loop in the + * "LAND" DoS attack, and also prevents an ACK storm + * between two listening ports that have been sent forged + * SYN segments, each with the source address of the other. + */ + if (tp->t_state == TCPS_SYN_RECEIVED && (thflags & TH_ACK) && + (SEQ_GT(tp->snd_una, th->th_ack) || + SEQ_GT(th->th_ack, tp->snd_max)) ) { + rstreason = BANDLIM_RST_OPENPORT; + goto dropwithreset; + } +#ifdef TCPDEBUG + if (so->so_options & SO_DEBUG) + tcp_trace(TA_DROP, ostate, tp, (void *)tcp_saveipgen, + &tcp_savetcp, 0); +#endif + TCP_PROBE3(debug__input, tp, th, mtod(m, const char *)); + if (ti_locked == TI_RLOCKED) { + INP_INFO_RUNLOCK(&V_tcbinfo); + } + ti_locked = TI_UNLOCKED; + + tp->t_flags |= TF_ACKNOW; + (void) tp->t_fb->tfb_tcp_output(tp); + INP_WUNLOCK(tp->t_inpcb); + m_freem(m); + return; + +dropwithreset: + if (ti_locked == TI_RLOCKED) { + INP_INFO_RUNLOCK(&V_tcbinfo); + } + ti_locked = TI_UNLOCKED; + + if (tp != NULL) { + tcp_dropwithreset(m, th, tp, tlen, rstreason); + INP_WUNLOCK(tp->t_inpcb); + } else + tcp_dropwithreset(m, th, NULL, tlen, rstreason); + return; + +drop: + if (ti_locked == TI_RLOCKED) { + INP_INFO_RUNLOCK(&V_tcbinfo); + ti_locked = TI_UNLOCKED; + } +#ifdef INVARIANTS + else + INP_INFO_UNLOCK_ASSERT(&V_tcbinfo); +#endif + + /* + * Drop space held by incoming segment and return. + */ +#ifdef TCPDEBUG + if (tp == NULL || (tp->t_inpcb->inp_socket->so_options & SO_DEBUG)) + tcp_trace(TA_DROP, ostate, tp, (void *)tcp_saveipgen, + &tcp_savetcp, 0); +#endif + TCP_PROBE3(debug__input, tp, th, mtod(m, const char *)); + if (tp != NULL) + INP_WUNLOCK(tp->t_inpcb); + m_freem(m); +} + + +/* + * Do fast slow is a combination of the original + * tcp_dosegment and a split fastpath, one function + * for the fast-ack which also includes allowing fastpath + * for window advanced in sequence acks. And also a + * sub-function that handles the insequence data. + */ +void +tcp_do_segment_fastslow(struct mbuf *m, struct tcphdr *th, struct socket *so, + struct tcpcb *tp, int drop_hdrlen, int tlen, uint8_t iptos, + int ti_locked) +{ + int thflags; + u_long tiwin; + char *s; + int can_enter; + struct in_conninfo *inc; + struct tcpopt to; + + thflags = th->th_flags; + tp->sackhint.last_sack_ack = 0; + inc = &tp->t_inpcb->inp_inc; + /* + * If this is either a state-changing packet or current state isn't + * established, we require a write lock on tcbinfo. Otherwise, we + * allow the tcbinfo to be in either alocked or unlocked, as the + * caller may have unnecessarily acquired a write lock due to a race. + */ + if ((thflags & (TH_SYN | TH_FIN | TH_RST)) != 0 || + tp->t_state != TCPS_ESTABLISHED) { + KASSERT(ti_locked == TI_RLOCKED, ("%s ti_locked %d for " + "SYN/FIN/RST/!EST", __func__, ti_locked)); + INP_INFO_RLOCK_ASSERT(&V_tcbinfo); + } else { +#ifdef INVARIANTS + if (ti_locked == TI_RLOCKED) { + INP_INFO_RLOCK_ASSERT(&V_tcbinfo); + } else { + KASSERT(ti_locked == TI_UNLOCKED, ("%s: EST " + "ti_locked: %d", __func__, ti_locked)); + INP_INFO_UNLOCK_ASSERT(&V_tcbinfo); + } +#endif + } + INP_WLOCK_ASSERT(tp->t_inpcb); + KASSERT(tp->t_state > TCPS_LISTEN, ("%s: TCPS_LISTEN", + __func__)); + KASSERT(tp->t_state != TCPS_TIME_WAIT, ("%s: TCPS_TIME_WAIT", + __func__)); + + /* + * Segment received on connection. + * Reset idle time and keep-alive timer. + * XXX: This should be done after segment + * validation to ignore broken/spoofed segs. + */ + tp->t_rcvtime = ticks; + if (TCPS_HAVEESTABLISHED(tp->t_state)) + tcp_timer_activate(tp, TT_KEEP, TP_KEEPIDLE(tp)); + + /* + * Unscale the window into a 32-bit value. + * For the SYN_SENT state the scale is zero. + */ + tiwin = th->th_win << tp->snd_scale; + + /* + * TCP ECN processing. + */ + if (tp->t_flags & TF_ECN_PERMIT) { + if (thflags & TH_CWR) + tp->t_flags &= ~TF_ECN_SND_ECE; + switch (iptos & IPTOS_ECN_MASK) { + case IPTOS_ECN_CE: + tp->t_flags |= TF_ECN_SND_ECE; + TCPSTAT_INC(tcps_ecn_ce); + break; + case IPTOS_ECN_ECT0: + TCPSTAT_INC(tcps_ecn_ect0); + break; + case IPTOS_ECN_ECT1: + TCPSTAT_INC(tcps_ecn_ect1); + break; + } + /* Congestion experienced. */ + if (thflags & TH_ECE) { + cc_cong_signal(tp, th, CC_ECN); + } + } + + /* + * Parse options on any incoming segment. + */ + tcp_dooptions(&to, (u_char *)(th + 1), + (th->th_off << 2) - sizeof(struct tcphdr), + (thflags & TH_SYN) ? TO_SYN : 0); + + /* + * If echoed timestamp is later than the current time, + * fall back to non RFC1323 RTT calculation. Normalize + * timestamp if syncookies were used when this connection + * was established. + */ + if ((to.to_flags & TOF_TS) && (to.to_tsecr != 0)) { + to.to_tsecr -= tp->ts_offset; + if (TSTMP_GT(to.to_tsecr, tcp_ts_getticks())) + to.to_tsecr = 0; + } + /* + * If timestamps were negotiated during SYN/ACK they should + * appear on every segment during this session and vice versa. + */ + if ((tp->t_flags & TF_RCVD_TSTMP) && !(to.to_flags & TOF_TS)) { + if ((s = tcp_log_addrs(inc, th, NULL, NULL))) { + log(LOG_DEBUG, "%s; %s: Timestamp missing, " + "no action\n", s, __func__); + free(s, M_TCPLOG); + } + } + if (!(tp->t_flags & TF_RCVD_TSTMP) && (to.to_flags & TOF_TS)) { + if ((s = tcp_log_addrs(inc, th, NULL, NULL))) { + log(LOG_DEBUG, "%s; %s: Timestamp not expected, " + "no action\n", s, __func__); + free(s, M_TCPLOG); + } + } + + /* + * Process options only when we get SYN/ACK back. The SYN case + * for incoming connections is handled in tcp_syncache. + * According to RFC1323 the window field in a SYN (i.e., a <SYN> + * or <SYN,ACK>) segment itself is never scaled. + * XXX this is traditional behavior, may need to be cleaned up. + */ + if (tp->t_state == TCPS_SYN_SENT && (thflags & TH_SYN)) { + if ((to.to_flags & TOF_SCALE) && + (tp->t_flags & TF_REQ_SCALE)) { + tp->t_flags |= TF_RCVD_SCALE; + tp->snd_scale = to.to_wscale; + } + /* + * Initial send window. It will be updated with + * the next incoming segment to the scaled value. + */ + tp->snd_wnd = th->th_win; + if (to.to_flags & TOF_TS) { + tp->t_flags |= TF_RCVD_TSTMP; + tp->ts_recent = to.to_tsval; + tp->ts_recent_age = tcp_ts_getticks(); + } + if (to.to_flags & TOF_MSS) + tcp_mss(tp, to.to_mss); + if ((tp->t_flags & TF_SACK_PERMIT) && + (to.to_flags & TOF_SACKPERM) == 0) + tp->t_flags &= ~TF_SACK_PERMIT; + } + can_enter = 0; + if (__predict_true((tlen == 0))) { + /* + * The ack moved forward and we have a window (non-zero) + * <or> + * The ack did not move forward, but the window increased. + */ + if (__predict_true((SEQ_GT(th->th_ack, tp->snd_una) && tiwin) || + ((th->th_ack == tp->snd_una) && tiwin && (tiwin > tp->snd_wnd)))) { + can_enter = 1; + } + } else { + /* + * Data incoming, use the old entry criteria + * for fast-path with data. + */ + if ((tiwin && tiwin == tp->snd_wnd)) { + can_enter = 1; + } + } + /* + * Header prediction: check for the two common cases + * of a uni-directional data xfer. If the packet has + * no control flags, is in-sequence, the window didn't + * change and we're not retransmitting, it's a + * candidate. If the length is zero and the ack moved + * forward, we're the sender side of the xfer. Just + * free the data acked & wake any higher level process + * that was blocked waiting for space. If the length + * is non-zero and the ack didn't move, we're the + * receiver side. If we're getting packets in-order + * (the reassembly queue is empty), add the data to + * the socket buffer and note that we need a delayed ack. + * Make sure that the hidden state-flags are also off. + * Since we check for TCPS_ESTABLISHED first, it can only + * be TH_NEEDSYN. + */ + if (__predict_true(tp->t_state == TCPS_ESTABLISHED && + th->th_seq == tp->rcv_nxt && + (thflags & (TH_SYN|TH_FIN|TH_RST|TH_URG|TH_ACK)) == TH_ACK && + tp->snd_nxt == tp->snd_max && + can_enter && + ((tp->t_flags & (TF_NEEDSYN|TF_NEEDFIN)) == 0) && + LIST_EMPTY(&tp->t_segq) && + ((to.to_flags & TOF_TS) == 0 || + TSTMP_GEQ(to.to_tsval, tp->ts_recent)))) { + if (__predict_true((tlen == 0) && + (SEQ_LEQ(th->th_ack, tp->snd_max) && + !IN_RECOVERY(tp->t_flags) && + (to.to_flags & TOF_SACK) == 0 && + TAILQ_EMPTY(&tp->snd_holes)))) { + /* We are done */ + tcp_do_fastack(m, th, so, tp, &to, drop_hdrlen, tlen, + ti_locked, tiwin); + return; + } else if ((tlen) && + (th->th_ack == tp->snd_una && + tlen <= sbspace(&so->so_rcv))) { + tcp_do_fastnewdata(m, th, so, tp, &to, drop_hdrlen, tlen, + ti_locked, tiwin); + /* We are done */ + return; + } + } + tcp_do_slowpath(m, th, so, tp, &to, drop_hdrlen, tlen, + ti_locked, tiwin, thflags); +} + + +/* + * This subfunction is used to try to highly optimize the + * fast path. We again allow window updates that are + * in sequence to remain in the fast-path. We also add + * in the __predict's to attempt to help the compiler. + * Note that if we return a 0, then we can *not* process + * it and the caller should push the packet into the + * slow-path. + */ +static int +tcp_fastack(struct mbuf *m, struct tcphdr *th, struct socket *so, + struct tcpcb *tp, struct tcpopt *to, int drop_hdrlen, int tlen, + int ti_locked, u_long tiwin) +{ + int acked; + int winup_only=0; +#ifdef TCPDEBUG + /* + * The size of tcp_saveipgen must be the size of the max ip header, + * now IPv6. + */ + u_char tcp_saveipgen[IP6_HDR_LEN]; + struct tcphdr tcp_savetcp; + short ostate = 0; +#endif + + + if (__predict_false(SEQ_LEQ(th->th_ack, tp->snd_una))) { + /* Old ack, behind (or duplicate to) the last one rcv'd */ + return (0); + } + if (__predict_false(th->th_ack == tp->snd_una) && + __predict_false(tiwin <= tp->snd_wnd)) { + /* duplicate ack <or> a shrinking dup ack with shrinking window */ + return (0); + } + if (__predict_false(tiwin == 0)) { + /* zero window */ + return (0); + } + if (__predict_false(SEQ_GT(th->th_ack, tp->snd_max))) { + /* Above what we have sent? */ + return (0); + } + if (__predict_false(tp->snd_nxt != tp->snd_max)) { + /* We are retransmitting */ + return (0); + } + if (__predict_false(tp->t_flags & (TF_NEEDSYN|TF_NEEDFIN))) { + /* We need a SYN or a FIN, unlikely.. */ + return (0); + } + if((to->to_flags & TOF_TS) && __predict_false(TSTMP_LT(to->to_tsval, tp->ts_recent))) { + /* Timestamp is behind .. old ack with seq wrap? */ + return (0); + } + if (__predict_false(IN_RECOVERY(tp->t_flags))) { + /* Still recovering */ + return (0); + } + if (__predict_false(to->to_flags & TOF_SACK)) { + /* Sack included in the ack.. */ + return (0); + } + if (!TAILQ_EMPTY(&tp->snd_holes)) { + /* We have sack holes on our scoreboard */ + return (0); + } + /* Ok if we reach here, we can process a fast-ack */ + + /* Did the window get updated? */ + if (tiwin != tp->snd_wnd) { + /* keep track of pure window updates */ + if (tp->snd_wl2 == th->th_ack && tiwin > tp->snd_wnd) { + winup_only = 1; + TCPSTAT_INC(tcps_rcvwinupd); + } + tp->snd_wnd = tiwin; + tp->snd_wl1 = th->th_seq; + if (tp->snd_wnd > tp->max_sndwnd) + tp->max_sndwnd = tp->snd_wnd; + } + /* + * Pull snd_wl2 up to prevent seq wrap relative + * to th_ack. + */ + tp->snd_wl2 = th->th_ack; + /* + * If last ACK falls within this segment's sequence numbers, + * record the timestamp. + * NOTE that the test is modified according to the latest + * proposal of the tcplw@cray.com list (Braden 1993/04/26). + */ + if ((to->to_flags & TOF_TS) != 0 && + SEQ_LEQ(th->th_seq, tp->last_ack_sent)) { + tp->ts_recent_age = tcp_ts_getticks(); + tp->ts_recent = to->to_tsval; + } + /* + * This is a pure ack for outstanding data. + */ + if (ti_locked == TI_RLOCKED) { + INP_INFO_RUNLOCK(&V_tcbinfo); + } + ti_locked = TI_UNLOCKED; + + TCPSTAT_INC(tcps_predack); + + /* + * "bad retransmit" recovery. + */ + if (tp->t_rxtshift == 1 && + tp->t_flags & TF_PREVVALID && + (int)(ticks - tp->t_badrxtwin) < 0) { + cc_cong_signal(tp, th, CC_RTO_ERR); + } + + /* + * Recalculate the transmit timer / rtt. + * + * Some boxes send broken timestamp replies + * during the SYN+ACK phase, ignore + * timestamps of 0 or we could calculate a + * huge RTT and blow up the retransmit timer. + */ + if ((to->to_flags & TOF_TS) != 0 && + to->to_tsecr) { + u_int t; + + t = tcp_ts_getticks() - to->to_tsecr; + if (!tp->t_rttlow || tp->t_rttlow > t) + tp->t_rttlow = t; + tcp_xmit_timer(tp, + TCP_TS_TO_TICKS(t) + 1); + } else if (tp->t_rtttime && + SEQ_GT(th->th_ack, tp->t_rtseq)) { + if (!tp->t_rttlow || + tp->t_rttlow > ticks - tp->t_rtttime) + tp->t_rttlow = ticks - tp->t_rtttime; + tcp_xmit_timer(tp, + ticks - tp->t_rtttime); + } + if (winup_only == 0) { + acked = BYTES_THIS_ACK(tp, th); + + /* Run HHOOK_TCP_ESTABLISHED_IN helper hooks. */ + hhook_run_tcp_est_in(tp, th, to); + + TCPSTAT_ADD(tcps_rcvackbyte, acked); + sbdrop(&so->so_snd, acked); + if (SEQ_GT(tp->snd_una, tp->snd_recover) && + SEQ_LEQ(th->th_ack, tp->snd_recover)) + tp->snd_recover = th->th_ack - 1; + + /* + * Let the congestion control algorithm update + * congestion control related information. This + * typically means increasing the congestion + * window. + */ + cc_ack_received(tp, th, CC_ACK); + + tp->snd_una = th->th_ack; + tp->t_dupacks = 0; + m_freem(m); + + /* + * If all outstanding data are acked, stop + * retransmit timer, otherwise restart timer + * using current (possibly backed-off) value. + * If process is waiting for space, + * wakeup/selwakeup/signal. If data + * are ready to send, let tcp_output + * decide between more output or persist. + */ +#ifdef TCPDEBUG + if (so->so_options & SO_DEBUG) + tcp_trace(TA_INPUT, ostate, tp, + (void *)tcp_saveipgen, + &tcp_savetcp, 0); +#endif + if (tp->snd_una == tp->snd_max) + tcp_timer_activate(tp, TT_REXMT, 0); + else if (!tcp_timer_active(tp, TT_PERSIST)) + tcp_timer_activate(tp, TT_REXMT, + tp->t_rxtcur); + /* Wake up the socket if we have room to write more */ + sowwakeup(so); + } else { + /* + * Window update only, just free the mbufs and + * send out whatever we can. + */ + m_freem(m); + } + if (sbavail(&so->so_snd)) + (void) tcp_output(tp); + KASSERT(ti_locked == TI_UNLOCKED, ("%s: check_delack ti_locked %d", + __func__, ti_locked)); + INP_INFO_UNLOCK_ASSERT(&V_tcbinfo); + INP_WLOCK_ASSERT(tp->t_inpcb); + + if (tp->t_flags & TF_DELACK) { + tp->t_flags &= ~TF_DELACK; + tcp_timer_activate(tp, TT_DELACK, tcp_delacktime); + } + INP_WUNLOCK(tp->t_inpcb); + return (1); +} + +/* + * This tcp-do-segment concentrates on making the fastest + * ack processing path. It does not have a fast-path for + * data (it possibly could which would then eliminate the + * need for fast-slow above). For a content distributor having + * large outgoing elephants and very very little coming in + * having no fastpath for data does not really help (since you + * don't get much data in). The most important thing is + * processing ack's quickly and getting the rest of the data + * output to the peer as quickly as possible. This routine + * seems to be about an overall 3% faster then the old + * tcp_do_segment and keeps us in the fast-path for packets + * much more (by allowing window updates to also stay in the fastpath). + */ +void +tcp_do_segment_fastack(struct mbuf *m, struct tcphdr *th, struct socket *so, + struct tcpcb *tp, int drop_hdrlen, int tlen, uint8_t iptos, + int ti_locked) +{ + int thflags; + u_long tiwin; + char *s; + struct in_conninfo *inc; + struct tcpopt to; + + thflags = th->th_flags; + tp->sackhint.last_sack_ack = 0; + inc = &tp->t_inpcb->inp_inc; + /* + * If this is either a state-changing packet or current state isn't + * established, we require a write lock on tcbinfo. Otherwise, we + * allow the tcbinfo to be in either alocked or unlocked, as the + * caller may have unnecessarily acquired a write lock due to a race. + */ + if ((thflags & (TH_SYN | TH_FIN | TH_RST)) != 0 || + tp->t_state != TCPS_ESTABLISHED) { + KASSERT(ti_locked == TI_RLOCKED, ("%s ti_locked %d for " + "SYN/FIN/RST/!EST", __func__, ti_locked)); + INP_INFO_RLOCK_ASSERT(&V_tcbinfo); + } else { +#ifdef INVARIANTS + if (ti_locked == TI_RLOCKED) { + INP_INFO_RLOCK_ASSERT(&V_tcbinfo); + } else { + KASSERT(ti_locked == TI_UNLOCKED, ("%s: EST " + "ti_locked: %d", __func__, ti_locked)); + INP_INFO_UNLOCK_ASSERT(&V_tcbinfo); + } +#endif + } + INP_WLOCK_ASSERT(tp->t_inpcb); + KASSERT(tp->t_state > TCPS_LISTEN, ("%s: TCPS_LISTEN", + __func__)); + KASSERT(tp->t_state != TCPS_TIME_WAIT, ("%s: TCPS_TIME_WAIT", + __func__)); + + /* + * Segment received on connection. + * Reset idle time and keep-alive timer. + * XXX: This should be done after segment + * validation to ignore broken/spoofed segs. + */ + tp->t_rcvtime = ticks; + if (TCPS_HAVEESTABLISHED(tp->t_state)) + tcp_timer_activate(tp, TT_KEEP, TP_KEEPIDLE(tp)); + + /* + * Unscale the window into a 32-bit value. + * For the SYN_SENT state the scale is zero. + */ + tiwin = th->th_win << tp->snd_scale; + + /* + * TCP ECN processing. + */ + if (tp->t_flags & TF_ECN_PERMIT) { + if (thflags & TH_CWR) + tp->t_flags &= ~TF_ECN_SND_ECE; + switch (iptos & IPTOS_ECN_MASK) { + case IPTOS_ECN_CE: + tp->t_flags |= TF_ECN_SND_ECE; + TCPSTAT_INC(tcps_ecn_ce); + break; + case IPTOS_ECN_ECT0: + TCPSTAT_INC(tcps_ecn_ect0); + break; + case IPTOS_ECN_ECT1: + TCPSTAT_INC(tcps_ecn_ect1); + break; + } + /* Congestion experienced. */ + if (thflags & TH_ECE) { + cc_cong_signal(tp, th, CC_ECN); + } + } + + /* + * Parse options on any incoming segment. + */ + tcp_dooptions(&to, (u_char *)(th + 1), + (th->th_off << 2) - sizeof(struct tcphdr), + (thflags & TH_SYN) ? TO_SYN : 0); + + /* + * If echoed timestamp is later than the current time, + * fall back to non RFC1323 RTT calculation. Normalize + * timestamp if syncookies were used when this connection + * was established. + */ + if ((to.to_flags & TOF_TS) && (to.to_tsecr != 0)) { + to.to_tsecr -= tp->ts_offset; + if (TSTMP_GT(to.to_tsecr, tcp_ts_getticks())) + to.to_tsecr = 0; + } + /* + * If timestamps were negotiated during SYN/ACK they should + * appear on every segment during this session and vice versa. + */ + if ((tp->t_flags & TF_RCVD_TSTMP) && !(to.to_flags & TOF_TS)) { + if ((s = tcp_log_addrs(inc, th, NULL, NULL))) { + log(LOG_DEBUG, "%s; %s: Timestamp missing, " + "no action\n", s, __func__); + free(s, M_TCPLOG); + } + } + if (!(tp->t_flags & TF_RCVD_TSTMP) && (to.to_flags & TOF_TS)) { + if ((s = tcp_log_addrs(inc, th, NULL, NULL))) { + log(LOG_DEBUG, "%s; %s: Timestamp not expected, " + "no action\n", s, __func__); + free(s, M_TCPLOG); + } + } + + /* + * Process options only when we get SYN/ACK back. The SYN case + * for incoming connections is handled in tcp_syncache. + * According to RFC1323 the window field in a SYN (i.e., a <SYN> + * or <SYN,ACK>) segment itself is never scaled. + * XXX this is traditional behavior, may need to be cleaned up. + */ + if (tp->t_state == TCPS_SYN_SENT && (thflags & TH_SYN)) { + if ((to.to_flags & TOF_SCALE) && + (tp->t_flags & TF_REQ_SCALE)) { + tp->t_flags |= TF_RCVD_SCALE; + tp->snd_scale = to.to_wscale; + } + /* + * Initial send window. It will be updated with + * the next incoming segment to the scaled value. + */ + tp->snd_wnd = th->th_win; + if (to.to_flags & TOF_TS) { + tp->t_flags |= TF_RCVD_TSTMP; + tp->ts_recent = to.to_tsval; + tp->ts_recent_age = tcp_ts_getticks(); + } + if (to.to_flags & TOF_MSS) + tcp_mss(tp, to.to_mss); + if ((tp->t_flags & TF_SACK_PERMIT) && + (to.to_flags & TOF_SACKPERM) == 0) + tp->t_flags &= ~TF_SACK_PERMIT; + } + /* + * Header prediction: check for the two common cases + * of a uni-directional data xfer. If the packet has + * no control flags, is in-sequence, the window didn't + * change and we're not retransmitting, it's a + * candidate. If the length is zero and the ack moved + * forward, we're the sender side of the xfer. Just + * free the data acked & wake any higher level process + * that was blocked waiting for space. If the length + * is non-zero and the ack didn't move, we're the + * receiver side. If we're getting packets in-order + * (the reassembly queue is empty), add the data to + * the socket buffer and note that we need a delayed ack. + * Make sure that the hidden state-flags are also off. + * Since we check for TCPS_ESTABLISHED first, it can only + * be TH_NEEDSYN. + */ + if (__predict_true(tp->t_state == TCPS_ESTABLISHED) && + __predict_true(((to.to_flags & TOF_SACK) == 0)) && + __predict_true(tlen == 0) && + __predict_true((thflags & (TH_SYN|TH_FIN|TH_RST|TH_URG|TH_ACK)) == TH_ACK) && + __predict_true(LIST_EMPTY(&tp->t_segq)) && + __predict_true(th->th_seq == tp->rcv_nxt)) { + if (tcp_fastack(m, th, so, tp, &to, drop_hdrlen, tlen, + ti_locked, tiwin)) { + return; + } + } + tcp_do_slowpath(m, th, so, tp, &to, drop_hdrlen, tlen, + ti_locked, tiwin, thflags); +} + +struct tcp_function_block __tcp_fastslow = { + "fastslow", + tcp_output, + tcp_do_segment_fastslow, + tcp_default_ctloutput, + NULL, + NULL, + NULL, + NULL, + NULL, + NULL, + NULL, + 0, + 0 + +}; + +struct tcp_function_block __tcp_fastack = { + "fastack", + tcp_output, + tcp_do_segment_fastack, + tcp_default_ctloutput, + NULL, + NULL, + NULL, + NULL, + NULL, + NULL, + NULL, + 0, + 0 +}; + +static int +tcp_addfastpaths(module_t mod, int type, void *data) +{ + int err=0; + + switch (type) { + case MOD_LOAD: + err = register_tcp_functions(&__tcp_fastack, M_WAITOK); + if (err) { + printf("Failed to register fastack module -- err:%d\n", err); + return(err); + } + err = register_tcp_functions(&__tcp_fastslow, M_WAITOK); + if (err) { + printf("Failed to register fastslow module -- err:%d\n", err); + deregister_tcp_functions(&__tcp_fastack); + return(err); + } + break; + case MOD_QUIESCE: + if ((__tcp_fastslow.tfb_refcnt) ||( __tcp_fastack.tfb_refcnt)) { + return(EBUSY); + } + break; + case MOD_UNLOAD: + err = deregister_tcp_functions(&__tcp_fastack); + if (err == EBUSY) + break; + err = deregister_tcp_functions(&__tcp_fastslow); + if (err == EBUSY) + break; + err = 0; + break; + default: + return (EOPNOTSUPP); + } + return (err); +} + +static moduledata_t new_tcp_fastpaths = { + .name = "tcp_fastpaths", + .evhand = tcp_addfastpaths, + .priv = 0 +}; + +MODULE_VERSION(kern_tcpfastpaths, 1); +DECLARE_MODULE(kern_tcpfastpaths, new_tcp_fastpaths, SI_SUB_PSEUDO, SI_ORDER_ANY); diff --git a/sys/netinet/tcp_subr.c b/sys/netinet/tcp_subr.c index 29af766..00869a6 100644 --- a/sys/netinet/tcp_subr.c +++ b/sys/netinet/tcp_subr.c @@ -47,6 +47,7 @@ __FBSDID("$FreeBSD$"); #include <sys/sysctl.h> #include <sys/jail.h> #include <sys/malloc.h> +#include <sys/refcount.h> #include <sys/mbuf.h> #ifdef INET6 #include <sys/domain.h> @@ -125,6 +126,8 @@ VNET_DEFINE(int, tcp_mssdflt) = TCP_MSS; VNET_DEFINE(int, tcp_v6mssdflt) = TCP6_MSS; #endif +struct rwlock tcp_function_lock; + static int sysctl_net_inet_tcp_mss_check(SYSCTL_HANDLER_ARGS) { @@ -236,6 +239,179 @@ static char * tcp_log_addr(struct in_conninfo *inc, struct tcphdr *th, void *ip4hdr, const void *ip6hdr); static void tcp_timer_discard(struct tcpcb *, uint32_t); + +static struct tcp_function_block tcp_def_funcblk = { + "default", + tcp_output, + tcp_do_segment, + tcp_default_ctloutput, + NULL, + NULL, + NULL, + NULL, + NULL, + NULL, + NULL, + 0, + 0 +}; + +struct tcp_funchead t_functions; +static struct tcp_function_block *tcp_func_set_ptr = &tcp_def_funcblk; + +static struct tcp_function_block * +find_tcp_functions_locked(struct tcp_function_set *fs) +{ + struct tcp_function *f; + struct tcp_function_block *blk=NULL; + + TAILQ_FOREACH(f, &t_functions, tf_next) { + if (strcmp(f->tf_fb->tfb_tcp_block_name, fs->function_set_name) == 0) { + blk = f->tf_fb; + break; + } + } + return(blk); +} + +static struct tcp_function_block * +find_tcp_fb_locked(struct tcp_function_block *blk, struct tcp_function **s) +{ + struct tcp_function_block *rblk=NULL; + struct tcp_function *f; + + TAILQ_FOREACH(f, &t_functions, tf_next) { + if (f->tf_fb == blk) { + rblk = blk; + if (s) { + *s = f; + } + break; + } + } + return (rblk); +} + +struct tcp_function_block * +find_and_ref_tcp_functions(struct tcp_function_set *fs) +{ + struct tcp_function_block *blk; + + rw_rlock(&tcp_function_lock); + blk = find_tcp_functions_locked(fs); + if (blk) + refcount_acquire(&blk->tfb_refcnt); + rw_runlock(&tcp_function_lock); + return(blk); +} + +struct tcp_function_block * +find_and_ref_tcp_fb(struct tcp_function_block *blk) +{ + struct tcp_function_block *rblk; + + rw_rlock(&tcp_function_lock); + rblk = find_tcp_fb_locked(blk, NULL); + if (rblk) + refcount_acquire(&rblk->tfb_refcnt); + rw_runlock(&tcp_function_lock); + return(rblk); +} + + +static int +sysctl_net_inet_default_tcp_functions(SYSCTL_HANDLER_ARGS) +{ + int error=ENOENT; + struct tcp_function_set fs; + struct tcp_function_block *blk; + + memset(&fs, 0, sizeof(fs)); + rw_rlock(&tcp_function_lock); + blk = find_tcp_fb_locked(tcp_func_set_ptr, NULL); + if (blk) { + /* Found him */ + strcpy(fs.function_set_name, blk->tfb_tcp_block_name); + fs.pcbcnt = blk->tfb_refcnt; + } + rw_runlock(&tcp_function_lock); + error = sysctl_handle_string(oidp, fs.function_set_name, + sizeof(fs.function_set_name), req); + + /* Check for error or no change */ + if (error != 0 || req->newptr == NULL) + return(error); + + rw_wlock(&tcp_function_lock); + blk = find_tcp_functions_locked(&fs); + if ((blk == NULL) || + (blk->tfb_flags & TCP_FUNC_BEING_REMOVED)) { + error = ENOENT; + goto done; + } + tcp_func_set_ptr = blk; +done: + rw_wunlock(&tcp_function_lock); + return (error); +} + +SYSCTL_PROC(_net_inet_tcp, OID_AUTO, functions_default, + CTLTYPE_STRING | CTLFLAG_RW, + NULL, 0, sysctl_net_inet_default_tcp_functions, "A", + "Set/get the default TCP functions"); + +static int +sysctl_net_inet_list_available(SYSCTL_HANDLER_ARGS) +{ + int error, cnt, linesz; + struct tcp_function *f; + char *buffer, *cp; + size_t bufsz, outsz; + + cnt = 0; + rw_rlock(&tcp_function_lock); + TAILQ_FOREACH(f, &t_functions, tf_next) { + cnt++; + } + rw_runlock(&tcp_function_lock); + + bufsz = (cnt+2) * (TCP_FUNCTION_NAME_LEN_MAX + 12) + 1; + buffer = malloc(bufsz, M_TEMP, M_WAITOK); + + error = 0; + cp = buffer; + + linesz = snprintf(cp, bufsz, "\n%-32s%c %s\n", "Stack", 'D', "PCB count"); + cp += linesz; + bufsz -= linesz; + outsz = linesz; + + rw_rlock(&tcp_function_lock); + TAILQ_FOREACH(f, &t_functions, tf_next) { + linesz = snprintf(cp, bufsz, "%-32s%c %u\n", + f->tf_fb->tfb_tcp_block_name, + (f->tf_fb == tcp_func_set_ptr) ? '*' : ' ', + f->tf_fb->tfb_refcnt); + if (linesz >= bufsz) { + error = EOVERFLOW; + break; + } + cp += linesz; + bufsz -= linesz; + outsz += linesz; + } + rw_runlock(&tcp_function_lock); + if (error == 0) + error = sysctl_handle_string(oidp, buffer, outsz + 1, req); + free(buffer, M_TEMP); + return (error); +} + +SYSCTL_PROC(_net_inet_tcp, OID_AUTO, functions_available, + CTLTYPE_STRING|CTLFLAG_RD, + NULL, 0, sysctl_net_inet_list_available, "A", + "list available TCP Function sets"); + /* * Target size of TCP PCB hash tables. Must be a power of two. * @@ -263,6 +439,8 @@ static VNET_DEFINE(uma_zone_t, tcpcb_zone); #define V_tcpcb_zone VNET(tcpcb_zone) MALLOC_DEFINE(M_TCPLOG, "tcplog", "TCP address and flags print buffers"); +MALLOC_DEFINE(M_TCPFUNCTIONS, "tcpfunc", "TCP function set memory"); + static struct mtx isn_mtx; #define ISN_LOCK_INIT() mtx_init(&isn_mtx, "isn_mtx", NULL, MTX_DEF) @@ -311,6 +489,96 @@ maketcp_hashsize(int size) return (hashsize); } +int +register_tcp_functions(struct tcp_function_block *blk, int wait) +{ + struct tcp_function_block *lblk; + struct tcp_function *n; + struct tcp_function_set fs; + + if ((blk->tfb_tcp_output == NULL) || + (blk->tfb_tcp_do_segment == NULL) || + (blk->tfb_tcp_ctloutput == NULL) || + (strlen(blk->tfb_tcp_block_name) == 0)) { + /* + * These functions are required and you + * need a name. + */ + return (EINVAL); + } + if (blk->tfb_tcp_timer_stop_all || + blk->tfb_tcp_timers_left || + blk->tfb_tcp_timer_activate || + blk->tfb_tcp_timer_active || + blk->tfb_tcp_timer_stop) { + /* + * If you define one timer function you + * must have them all. + */ + if ((blk->tfb_tcp_timer_stop_all == NULL) || + (blk->tfb_tcp_timers_left == NULL) || + (blk->tfb_tcp_timer_activate == NULL) || + (blk->tfb_tcp_timer_active == NULL) || + (blk->tfb_tcp_timer_stop == NULL)) { + return (EINVAL); + } + } + n = malloc(sizeof(struct tcp_function), M_TCPFUNCTIONS, wait); + if (n == NULL) { + return (ENOMEM); + } + n->tf_fb = blk; + strcpy(fs.function_set_name, blk->tfb_tcp_block_name); + rw_wlock(&tcp_function_lock); + lblk = find_tcp_functions_locked(&fs); + if (lblk) { + /* Duplicate name space not allowed */ + rw_wunlock(&tcp_function_lock); + free(n, M_TCPFUNCTIONS); + return (EALREADY); + } + refcount_init(&blk->tfb_refcnt, 0); + blk->tfb_flags = 0; + TAILQ_INSERT_TAIL(&t_functions, n, tf_next); + rw_wunlock(&tcp_function_lock); + return(0); +} + +int +deregister_tcp_functions(struct tcp_function_block *blk) +{ + struct tcp_function_block *lblk; + struct tcp_function *f; + int error=ENOENT; + + if (strcmp(blk->tfb_tcp_block_name, "default") == 0) { + /* You can't un-register the default */ + return (EPERM); + } + rw_wlock(&tcp_function_lock); + if (blk == tcp_func_set_ptr) { + /* You can't free the current default */ + rw_wunlock(&tcp_function_lock); + return (EBUSY); + } + if (blk->tfb_refcnt) { + /* Still tcb attached, mark it. */ + blk->tfb_flags |= TCP_FUNC_BEING_REMOVED; + rw_wunlock(&tcp_function_lock); + return (EBUSY); + } + lblk = find_tcp_fb_locked(blk, &f); + if (lblk) { + /* Found */ + TAILQ_REMOVE(&t_functions, f, tf_next); + f->tf_fb = NULL; + free(f, M_TCPFUNCTIONS); + error = 0; + } + rw_wunlock(&tcp_function_lock); + return (error); +} + void tcp_init(void) { @@ -325,7 +593,10 @@ tcp_init(void) if (hhook_head_register(HHOOK_TYPE_TCP, HHOOK_TCP_EST_OUT, &V_tcp_hhh[HHOOK_TCP_EST_OUT], HHOOK_NOWAIT|HHOOK_HEADISINVNET) != 0) printf("%s: WARNING: unable to register helper hook\n", __func__); - + /* Setup the tcp function block list */ + TAILQ_INIT(&t_functions); + rw_init_flags(&tcp_function_lock, "tcp_func_lock" , 0); + register_tcp_functions(&tcp_def_funcblk, M_WAITOK); hashsize = TCBHASHSIZE; TUNABLE_INT_FETCH(tcbhash_tuneable, &hashsize); if (hashsize == 0) { @@ -768,7 +1039,13 @@ tcp_newtcpcb(struct inpcb *inp) tp->ccv = &tm->ccv; tp->ccv->type = IPPROTO_TCP; tp->ccv->ccvc.tcp = tp; - + rw_rlock(&tcp_function_lock); + tp->t_fb = tcp_func_set_ptr; + refcount_acquire(&tp->t_fb->tfb_refcnt); + rw_runlock(&tcp_function_lock); + if (tp->t_fb->tfb_tcp_fb_init) { + (*tp->t_fb->tfb_tcp_fb_init)(tp); + } /* * Use the current system default CC algorithm. */ @@ -779,12 +1056,18 @@ tcp_newtcpcb(struct inpcb *inp) if (CC_ALGO(tp)->cb_init != NULL) if (CC_ALGO(tp)->cb_init(tp->ccv) > 0) { + if (tp->t_fb->tfb_tcp_fb_fini) + (*tp->t_fb->tfb_tcp_fb_fini)(tp); + refcount_release(&tp->t_fb->tfb_refcnt); uma_zfree(V_tcpcb_zone, tm); return (NULL); } tp->osd = &tm->osd; if (khelp_init_osd(HELPER_CLASS_TCP, tp->osd)) { + if (tp->t_fb->tfb_tcp_fb_fini) + (*tp->t_fb->tfb_tcp_fb_fini)(tp); + refcount_release(&tp->t_fb->tfb_refcnt); uma_zfree(V_tcpcb_zone, tm); return (NULL); } @@ -925,7 +1208,7 @@ tcp_drop(struct tcpcb *tp, int errno) if (TCPS_HAVERCVDSYN(tp->t_state)) { tcp_state_change(tp, TCPS_CLOSED); - (void) tcp_output(tp); + (void) tp->t_fb->tfb_tcp_output(tp); TCPSTAT_INC(tcps_drops); } else TCPSTAT_INC(tcps_conndrops); @@ -960,6 +1243,10 @@ tcp_discardcb(struct tcpcb *tp) tcp_timer_stop(tp, TT_KEEP); tcp_timer_stop(tp, TT_2MSL); tcp_timer_stop(tp, TT_DELACK); + if (tp->t_fb->tfb_tcp_timer_stop_all) { + /* Call the stop-all function of the methods */ + tp->t_fb->tfb_tcp_timer_stop_all(tp); + } /* * If we got enough samples through the srtt filter, @@ -1044,6 +1331,14 @@ tcp_discardcb(struct tcpcb *tp) inp->inp_ppcb = NULL; if ((tp->t_timers->tt_flags & TT_MASK) == 0) { /* We own the last reference on tcpcb, let's free it. */ + if ((tp->t_fb->tfb_tcp_timers_left) && + (tp->t_fb->tfb_tcp_timers_left(tp))) { + /* Some fb timers left running! */ + return; + } + if (tp->t_fb->tfb_tcp_fb_fini) + (*tp->t_fb->tfb_tcp_fb_fini)(tp); + refcount_release(&tp->t_fb->tfb_refcnt); tp->t_inpcb = NULL; uma_zfree(V_tcpcb_zone, tp); released = in_pcbrele_wlocked(inp); @@ -1105,6 +1400,14 @@ tcp_timer_discard(struct tcpcb *tp, uint32_t timer_type) tp->t_timers->tt_flags &= ~timer_type; if ((tp->t_timers->tt_flags & TT_MASK) == 0) { /* We own the last reference on this tcpcb, let's free it. */ + if ((tp->t_fb->tfb_tcp_timers_left) && + (tp->t_fb->tfb_tcp_timers_left(tp))) { + /* Some fb timers left running! */ + goto leave; + } + if (tp->t_fb->tfb_tcp_fb_fini) + (*tp->t_fb->tfb_tcp_fb_fini)(tp); + refcount_release(&tp->t_fb->tfb_refcnt); tp->t_inpcb = NULL; uma_zfree(V_tcpcb_zone, tp); if (in_pcbrele_wlocked(inp)) { @@ -1113,6 +1416,7 @@ tcp_timer_discard(struct tcpcb *tp, uint32_t timer_type) return; } } +leave: INP_WUNLOCK(inp); INP_INFO_RUNLOCK(&V_tcbinfo); CURVNET_RESTORE(); @@ -1865,7 +2169,7 @@ tcp_mtudisc(struct inpcb *inp, int mtuoffer) tp->snd_recover = tp->snd_max; if (tp->t_flags & TF_SACK_PERMIT) EXIT_FASTRECOVERY(tp->t_flags); - tcp_output(tp); + tp->t_fb->tfb_tcp_output(tp); } #ifdef INET diff --git a/sys/netinet/tcp_syncache.c b/sys/netinet/tcp_syncache.c index e5a38d5..8ad1b22 100644 --- a/sys/netinet/tcp_syncache.c +++ b/sys/netinet/tcp_syncache.c @@ -41,6 +41,7 @@ __FBSDID("$FreeBSD$"); #include <sys/param.h> #include <sys/systm.h> #include <sys/hash.h> +#include <sys/refcount.h> #include <sys/kernel.h> #include <sys/sysctl.h> #include <sys/limits.h> @@ -626,6 +627,7 @@ done: static struct socket * syncache_socket(struct syncache *sc, struct socket *lso, struct mbuf *m) { + struct tcp_function_block *blk; struct inpcb *inp = NULL; struct socket *so; struct tcpcb *tp; @@ -817,6 +819,26 @@ syncache_socket(struct syncache *sc, struct socket *lso, struct mbuf *m) tp->irs = sc->sc_irs; tcp_rcvseqinit(tp); tcp_sendseqinit(tp); + blk = sototcpcb(lso)->t_fb; + if (blk != tp->t_fb) { + /* + * Our parents t_fb was not the default, + * we need to release our ref on tp->t_fb and + * pickup one on the new entry. + */ + struct tcp_function_block *rblk; + + rblk = find_and_ref_tcp_fb(blk); + KASSERT(rblk != NULL, + ("cannot find blk %p out of syncache?", blk)); + if (tp->t_fb->tfb_tcp_fb_fini) + (*tp->t_fb->tfb_tcp_fb_fini)(tp); + refcount_release(&tp->t_fb->tfb_refcnt); + tp->t_fb = rblk; + if (tp->t_fb->tfb_tcp_fb_init) { + (*tp->t_fb->tfb_tcp_fb_init)(tp); + } + } tp->snd_wl1 = sc->sc_irs; tp->snd_max = tp->iss + 1; tp->snd_nxt = tp->iss + 1; diff --git a/sys/netinet/tcp_timer.c b/sys/netinet/tcp_timer.c index d129586..6a24ce7 100644 --- a/sys/netinet/tcp_timer.c +++ b/sys/netinet/tcp_timer.c @@ -292,7 +292,7 @@ tcp_timer_delack(void *xtp) tp->t_flags |= TF_ACKNOW; TCPSTAT_INC(tcps_delack); - (void) tcp_output(tp); + (void) tp->t_fb->tfb_tcp_output(tp); INP_WUNLOCK(inp); CURVNET_RESTORE(); } @@ -543,7 +543,7 @@ tcp_timer_persist(void *xtp) } tcp_setpersist(tp); tp->t_flags |= TF_FORCEDATA; - (void) tcp_output(tp); + (void) tp->t_fb->tfb_tcp_output(tp); tp->t_flags &= ~TF_FORCEDATA; out: @@ -798,7 +798,7 @@ tcp_timer_rexmt(void * xtp) cc_cong_signal(tp, NULL, CC_RTO); - (void) tcp_output(tp); + (void) tp->t_fb->tfb_tcp_output(tp); out: #ifdef TCPDEBUG @@ -858,6 +858,10 @@ tcp_timer_activate(struct tcpcb *tp, uint32_t timer_type, u_int delta) f_reset = TT_2MSL_RST; break; default: + if (tp->t_fb->tfb_tcp_timer_activate) { + tp->t_fb->tfb_tcp_timer_activate(tp, timer_type, delta); + return; + } panic("tp %p bad timer_type %#x", tp, timer_type); } if (delta == 0) { @@ -904,6 +908,9 @@ tcp_timer_active(struct tcpcb *tp, uint32_t timer_type) t_callout = &tp->t_timers->tt_2msl; break; default: + if (tp->t_fb->tfb_tcp_timer_active) { + return(tp->t_fb->tfb_tcp_timer_active(tp, timer_type)); + } panic("tp %p bad timer_type %#x", tp, timer_type); } return callout_active(t_callout); @@ -945,6 +952,14 @@ tcp_timer_stop(struct tcpcb *tp, uint32_t timer_type) f_reset = TT_2MSL_RST; break; default: + if (tp->t_fb->tfb_tcp_timer_stop) { + /* + * XXXrrs we need to look at this with the + * stop case below (flags). + */ + tp->t_fb->tfb_tcp_timer_stop(tp, timer_type); + return; + } panic("tp %p bad timer_type %#x", tp, timer_type); } diff --git a/sys/netinet/tcp_usrreq.c b/sys/netinet/tcp_usrreq.c index a1f8a0c..42e2ea7 100644 --- a/sys/netinet/tcp_usrreq.c +++ b/sys/netinet/tcp_usrreq.c @@ -47,6 +47,7 @@ __FBSDID("$FreeBSD$"); #include <sys/systm.h> #include <sys/limits.h> #include <sys/malloc.h> +#include <sys/refcount.h> #include <sys/kernel.h> #include <sys/sysctl.h> #include <sys/mbuf.h> @@ -509,7 +510,7 @@ tcp_usr_connect(struct socket *so, struct sockaddr *nam, struct thread *td) goto out; #endif tcp_timer_activate(tp, TT_KEEP, TP_KEEPINIT(tp)); - error = tcp_output(tp); + error = tp->t_fb->tfb_tcp_output(tp); out: TCPDEBUG2(PRU_CONNECT); INP_WUNLOCK(inp); @@ -579,7 +580,7 @@ tcp6_usr_connect(struct socket *so, struct sockaddr *nam, struct thread *td) (error = tcp_offload_connect(so, nam)) == 0) goto out; #endif - error = tcp_output(tp); + error = tp->t_fb->tfb_tcp_output(tp); goto out; } #endif @@ -597,7 +598,7 @@ tcp6_usr_connect(struct socket *so, struct sockaddr *nam, struct thread *td) goto out; #endif tcp_timer_activate(tp, TT_KEEP, TP_KEEPINIT(tp)); - error = tcp_output(tp); + error = tp->t_fb->tfb_tcp_output(tp); out: TCPDEBUG2(PRU_CONNECT); @@ -773,7 +774,7 @@ tcp_usr_shutdown(struct socket *so) socantsendmore(so); tcp_usrclosed(tp); if (!(inp->inp_flags & INP_DROPPED)) - error = tcp_output(tp); + error = tp->t_fb->tfb_tcp_output(tp); out: TCPDEBUG2(PRU_SHUTDOWN); @@ -809,7 +810,7 @@ tcp_usr_rcvd(struct socket *so, int flags) tcp_offload_rcvd(tp); else #endif - tcp_output(tp); + tp->t_fb->tfb_tcp_output(tp); out: TCPDEBUG2(PRU_RCVD); @@ -911,7 +912,7 @@ tcp_usr_send(struct socket *so, int flags, struct mbuf *m, !(flags & PRUS_NOTREADY)) { if (flags & PRUS_MORETOCOME) tp->t_flags |= TF_MORETOCOME; - error = tcp_output(tp); + error = tp->t_fb->tfb_tcp_output(tp); if (flags & PRUS_MORETOCOME) tp->t_flags &= ~TF_MORETOCOME; } @@ -961,7 +962,7 @@ tcp_usr_send(struct socket *so, int flags, struct mbuf *m, tp->snd_up = tp->snd_una + sbavail(&so->so_snd); if (!(flags & PRUS_NOTREADY)) { tp->t_flags |= TF_FORCEDATA; - error = tcp_output(tp); + error = tp->t_fb->tfb_tcp_output(tp); tp->t_flags &= ~TF_FORCEDATA; } } @@ -997,7 +998,7 @@ tcp_usr_ready(struct socket *so, struct mbuf *m, int count) error = sbready(&so->so_snd, m, count); SOCKBUF_UNLOCK(&so->so_snd); if (error == 0) - error = tcp_output(tp); + error = tp->t_fb->tfb_tcp_output(tp); INP_WUNLOCK(inp); return (error); @@ -1349,13 +1350,11 @@ tcp_fill_info(struct tcpcb *tp, struct tcp_info *ti) int tcp_ctloutput(struct socket *so, struct sockopt *sopt) { - int error, opt, optval; - u_int ui; + int error; struct inpcb *inp; struct tcpcb *tp; - struct tcp_info ti; - char buf[TCP_CA_NAME_MAX]; - struct cc_algo *algo; + struct tcp_function_block *blk; + struct tcp_function_set fsn; error = 0; inp = sotoinpcb(so); @@ -1383,7 +1382,83 @@ tcp_ctloutput(struct socket *so, struct sockopt *sopt) INP_WUNLOCK(inp); return (ECONNRESET); } + tp = intotcpcb(inp); + /* + * Protect the TCP option TCP_FUNCTION_BLK so + * that a sub-function can *never* overwrite this. + */ + if ((sopt->sopt_dir == SOPT_SET) && + (sopt->sopt_name == TCP_FUNCTION_BLK)) { + INP_WUNLOCK(inp); + error = sooptcopyin(sopt, &fsn, sizeof fsn, + sizeof fsn); + if (error) + return (error); + INP_WLOCK_RECHECK(inp); + if (tp->t_state != TCPS_CLOSED) { + /* + * The user has advanced the state + * past the initial point, we can't + * switch since we are down the road + * and a new set of functions may + * not be compatibile. + */ + INP_WUNLOCK(inp); + return(EINVAL); + } + blk = find_and_ref_tcp_functions(&fsn); + if (blk == NULL) { + INP_WUNLOCK(inp); + return (ENOENT); + } + if (tp->t_fb != blk) { + if (blk->tfb_flags & TCP_FUNC_BEING_REMOVED) { + refcount_release(&blk->tfb_refcnt); + INP_WUNLOCK(inp); + return (ENOENT); + } + /* + * Release the old refcnt, the + * lookup acquires a ref on the + * new one. + */ + if (tp->t_fb->tfb_tcp_fb_fini) + (*tp->t_fb->tfb_tcp_fb_fini)(tp); + refcount_release(&tp->t_fb->tfb_refcnt); + tp->t_fb = blk; + if (tp->t_fb->tfb_tcp_fb_init) { + (*tp->t_fb->tfb_tcp_fb_init)(tp); + } + } +#ifdef TCP_OFFLOAD + if (tp->t_flags & TF_TOE) { + tcp_offload_ctloutput(tp, sopt->sopt_dir, + sopt->sopt_name); + } +#endif + INP_WUNLOCK(inp); + return (error); + } else if ((sopt->sopt_dir == SOPT_GET) && + (sopt->sopt_name == TCP_FUNCTION_BLK)) { + strcpy(fsn.function_set_name, tp->t_fb->tfb_tcp_block_name); + fsn.pcbcnt = tp->t_fb->tfb_refcnt; + INP_WUNLOCK(inp); + error = sooptcopyout(sopt, &fsn, sizeof fsn); + return (error); + } + /* Pass in the INP locked, called must unlock it */ + return (tp->t_fb->tfb_tcp_ctloutput(so, sopt, inp, tp)); +} +int +tcp_default_ctloutput(struct socket *so, struct sockopt *sopt, struct inpcb *inp, struct tcpcb *tp) +{ + int error, opt, optval; + u_int ui; + struct tcp_info ti; + struct cc_algo *algo; + char buf[TCP_CA_NAME_MAX]; + switch (sopt->sopt_dir) { case SOPT_SET: switch (sopt->sopt_name) { @@ -1451,7 +1526,7 @@ unlock_and_done: else if (tp->t_flags & TF_NOPUSH) { tp->t_flags &= ~TF_NOPUSH; if (TCPS_HAVEESTABLISHED(tp->t_state)) - error = tcp_output(tp); + error = tp->t_fb->tfb_tcp_output(tp); } goto unlock_and_done; @@ -1770,7 +1845,7 @@ tcp_disconnect(struct tcpcb *tp) sbflush(&so->so_rcv); tcp_usrclosed(tp); if (!(inp->inp_flags & INP_DROPPED)) - tcp_output(tp); + tp->t_fb->tfb_tcp_output(tp); } } diff --git a/sys/netinet/tcp_var.h b/sys/netinet/tcp_var.h index bf8347a..2b3954a 100644 --- a/sys/netinet/tcp_var.h +++ b/sys/netinet/tcp_var.h @@ -89,6 +89,52 @@ struct tcptemp { #define tcp6cb tcpcb /* for KAME src sync over BSD*'s */ +/* + * TODO: We yet need to brave plowing in + * to tcp_input() and the pru_usrreq() block. + * Right now these go to the old standards which + * are somewhat ok, but in the long term may + * need to be changed. If we do tackle tcp_input() + * then we need to get rid of the tcp_do_segment() + * function below. + */ +/* Flags for tcp functions */ +#define TCP_FUNC_BEING_REMOVED 0x01 /* Can no longer be referenced */ +struct tcpcb; +struct inpcb; +struct sockopt; +struct socket; + +struct tcp_function_block { + char tfb_tcp_block_name[TCP_FUNCTION_NAME_LEN_MAX]; + int (*tfb_tcp_output)(struct tcpcb *); + void (*tfb_tcp_do_segment)(struct mbuf *, struct tcphdr *, + struct socket *, struct tcpcb *, + int, int, uint8_t, + int); + int (*tfb_tcp_ctloutput)(struct socket *so, struct sockopt *sopt, + struct inpcb *inp, struct tcpcb *tp); + /* Optional memory allocation/free routine */ + void (*tfb_tcp_fb_init)(struct tcpcb *); + void (*tfb_tcp_fb_fini)(struct tcpcb *); + /* Optional timers, must define all if you define one */ + int (*tfb_tcp_timer_stop_all)(struct tcpcb *); + int (*tfb_tcp_timers_left)(struct tcpcb *); + void (*tfb_tcp_timer_activate)(struct tcpcb *, + uint32_t, u_int); + int (*tfb_tcp_timer_active)(struct tcpcb *, uint32_t); + void (*tfb_tcp_timer_stop)(struct tcpcb *, uint32_t); + volatile uint32_t tfb_refcnt; + uint32_t tfb_flags; +}; + +struct tcp_function { + TAILQ_ENTRY(tcp_function) tf_next; + struct tcp_function_block *tf_fb; +}; + +TAILQ_HEAD(tcp_funchead, tcp_function); + /* * Tcp control block, one per tcp; fields: * Organized for 16 byte cacheline efficiency. @@ -207,9 +253,10 @@ struct tcpcb { u_int t_tsomaxsegsize; /* TSO maximum segment size in bytes */ u_int t_pmtud_saved_maxopd; /* pre-blackhole MSS */ u_int t_flags2; /* More tcpcb flags storage */ - uint32_t t_ispare[8]; /* 5 UTO, 3 TBD */ - void *t_pspare2[4]; /* 1 TCP_SIGNATURE, 3 TBD */ + struct tcp_function_block *t_fb;/* TCP function call block */ + void *t_fb_ptr; /* Pointer to t_fb specific data */ + void *t_pspare2[2]; /* 1 TCP_SIGNATURE, 1 TBD */ #if defined(_KERNEL) && defined(TCPPCAP) struct mbufq t_inpkts; /* List of saved input packets. */ struct mbufq t_outpkts; /* List of saved output packets. */ @@ -534,6 +581,8 @@ struct tcpstat { #define tcps_rcvmemdrop tcps_rcvreassfull /* compat */ #ifdef _KERNEL +#define TI_UNLOCKED 1 +#define TI_RLOCKED 2 #include <sys/counter.h> VNET_PCPUSTAT_DECLARE(struct tcpstat, tcpstat); /* tcp statistics */ @@ -684,7 +733,32 @@ char *tcp_log_vain(struct in_conninfo *, struct tcphdr *, void *, int tcp_reass(struct tcpcb *, struct tcphdr *, int *, struct mbuf *); void tcp_reass_global_init(void); void tcp_reass_flush(struct tcpcb *); +void tcp_dooptions(struct tcpopt *, u_char *, int, int); +void tcp_dropwithreset(struct mbuf *, struct tcphdr *, + struct tcpcb *, int, int); +void tcp_pulloutofband(struct socket *, + struct tcphdr *, struct mbuf *, int); +void tcp_xmit_timer(struct tcpcb *, int); +void tcp_newreno_partial_ack(struct tcpcb *, struct tcphdr *); +void cc_ack_received(struct tcpcb *tp, struct tcphdr *th, + uint16_t type); +void cc_conn_init(struct tcpcb *tp); +void cc_post_recovery(struct tcpcb *tp, struct tcphdr *th); +void cc_cong_signal(struct tcpcb *tp, struct tcphdr *th, uint32_t type); +void hhook_run_tcp_est_in(struct tcpcb *tp, + struct tcphdr *th, struct tcpopt *to); + int tcp_input(struct mbuf **, int *, int); +void tcp_do_segment(struct mbuf *, struct tcphdr *, + struct socket *, struct tcpcb *, int, int, uint8_t, + int); + +int register_tcp_functions(struct tcp_function_block *blk, int wait); +int deregister_tcp_functions(struct tcp_function_block *blk); +struct tcp_function_block *find_and_ref_tcp_functions(struct tcp_function_set *fs); +struct tcp_function_block *find_and_ref_tcp_fb(struct tcp_function_block *blk); +int tcp_default_ctloutput(struct socket *so, struct sockopt *sopt, struct inpcb *inp, struct tcpcb *tp); + u_long tcp_maxmtu(struct in_conninfo *, struct tcp_ifcap *); u_long tcp_maxmtu6(struct in_conninfo *, struct tcp_ifcap *); void tcp_mss_update(struct tcpcb *, int, int, struct hc_metrics_lite *, @@ -752,8 +826,6 @@ int tcp_newreno(struct tcpcb *, struct tcphdr *); u_long tcp_seq_subtract(u_long, u_long ); int tcp_compute_pipe(struct tcpcb *); -void cc_cong_signal(struct tcpcb *tp, struct tcphdr *th, uint32_t type); - static inline void tcp_fields_to_host(struct tcphdr *th) { diff --git a/sys/netinet/toecore.c b/sys/netinet/toecore.c index 87d8856..ef82f8a 100644 --- a/sys/netinet/toecore.c +++ b/sys/netinet/toecore.c @@ -509,7 +509,7 @@ toe_connect_failed(struct toedev *tod, struct inpcb *inp, int err) KASSERT(!(tp->t_flags & TF_TOE), ("%s: tp %p still offloaded.", __func__, tp)); tcp_timer_activate(tp, TT_KEEP, TP_KEEPINIT(tp)); - (void) tcp_output(tp); + (void) tp->t_fb->tfb_tcp_output(tp); } else { INP_INFO_RLOCK_ASSERT(&V_tcbinfo); diff --git a/sys/netinet6/in6.c b/sys/netinet6/in6.c index e815a96..c2f4397 100644 --- a/sys/netinet6/in6.c +++ b/sys/netinet6/in6.c @@ -2359,13 +2359,20 @@ in6_lltable_dump_entry(struct lltable *llt, struct llentry *lle, sdl->sdl_index = ifp->if_index; sdl->sdl_type = ifp->if_type; bcopy(&lle->ll_addr, LLADDR(sdl), ifp->if_addrlen); - ndpc.rtm.rtm_rmx.rmx_expire = lle->la_expire + - lle->lle_remtime / hz; + if (lle->la_expire != 0) + ndpc.rtm.rtm_rmx.rmx_expire = lle->la_expire + + lle->lle_remtime / hz + + time_second - time_uptime; ndpc.rtm.rtm_flags |= (RTF_HOST | RTF_LLDATA); if (lle->la_flags & LLE_STATIC) ndpc.rtm.rtm_flags |= RTF_STATIC; if (lle->la_flags & LLE_IFADDR) ndpc.rtm.rtm_flags |= RTF_PINNED; + if (lle->ln_router != 0) + ndpc.rtm.rtm_flags |= RTF_GATEWAY; + ndpc.rtm.rtm_rmx.rmx_pksent = lle->la_asked; + /* Store state in rmx_weight value */ + ndpc.rtm.rtm_rmx.rmx_state = lle->ln_state; ndpc.rtm.rtm_index = ifp->if_index; error = SYSCTL_OUT(wr, &ndpc, sizeof(ndpc)); diff --git a/sys/netinet6/nd6.c b/sys/netinet6/nd6.c index d0bcc9d..d2a457d 100644 --- a/sys/netinet6/nd6.c +++ b/sys/netinet6/nd6.c @@ -209,6 +209,7 @@ nd6_ifnet_link_event(void *arg __unused, struct ifnet *ifp, int linkstate) if (linkstate == LINK_STATE_UP && V_nd6_on_link) nd6_na_output_unsolicited(ifp); } + void nd6_init(void) { @@ -1748,7 +1749,7 @@ nd6_ioctl(u_long cmd, caddr_t data, struct ifnet *ifp) if (ln->la_expire == 0) nbi->expire = 0; else - nbi->expire = ln->la_expire + + nbi->expire = ln->la_expire + ln->lle_remtime / hz + (time_second - time_uptime); LLE_RUNLOCK(ln); break; diff --git a/sys/netinet6/nd6_nbr.c b/sys/netinet6/nd6_nbr.c index 0717e11..07ad0cc 100644 --- a/sys/netinet6/nd6_nbr.c +++ b/sys/netinet6/nd6_nbr.c @@ -1646,7 +1646,8 @@ nd6_na_output_unsolicited(struct ifnet *ifp) i++; if (i == cnt) break; - DELAY(ann1->delay); + /* XXX DELAY needs to be done in taskqueue to avoid stalling. */ + //DELAY(ann1->delay); } free(head, M_TEMP); } diff --git a/sys/security/mac/mac_framework.c b/sys/security/mac/mac_framework.c index 0f0a2ff..d76b280 100644 --- a/sys/security/mac/mac_framework.c +++ b/sys/security/mac/mac_framework.c @@ -93,11 +93,11 @@ __FBSDID("$FreeBSD$"); SDT_PROVIDER_DEFINE(mac); SDT_PROVIDER_DEFINE(mac_framework); -SDT_PROBE_DEFINE2(mac, kernel, policy, modevent, "int", +SDT_PROBE_DEFINE2(mac, , policy, modevent, "int", "struct mac_policy_conf *"); -SDT_PROBE_DEFINE1(mac, kernel, policy, register, +SDT_PROBE_DEFINE1(mac, , policy, register, "struct mac_policy_conf *"); -SDT_PROBE_DEFINE1(mac, kernel, policy, unregister, +SDT_PROBE_DEFINE1(mac, , policy, unregister, "struct mac_policy_conf *"); /* @@ -444,7 +444,7 @@ mac_policy_register(struct mac_policy_conf *mpc) (*(mpc->mpc_ops->mpo_init))(mpc); mac_policy_update(); - SDT_PROBE(mac, kernel, policy, register, mpc, 0, 0, 0, 0); + SDT_PROBE1(mac, , policy, register, mpc); printf("Security policy loaded: %s (%s)\n", mpc->mpc_fullname, mpc->mpc_name); @@ -491,7 +491,7 @@ mac_policy_unregister(struct mac_policy_conf *mpc) mac_policy_update(); mac_policy_xunlock(); - SDT_PROBE(mac, kernel, policy, unregister, mpc, 0, 0, 0, 0); + SDT_PROBE1(mac, , policy, unregister, mpc); printf("Security policy unload: %s (%s)\n", mpc->mpc_fullname, mpc->mpc_name); @@ -517,7 +517,7 @@ mac_policy_modevent(module_t mod, int type, void *data) } #endif - SDT_PROBE(mac, kernel, policy, modevent, type, mpc, 0, 0, 0); + SDT_PROBE2(mac, , policy, modevent, type, mpc); switch (type) { case MOD_LOAD: if (mpc->mpc_loadtime_flags & MPC_LOADTIME_FLAG_NOTLATE && diff --git a/sys/security/mac/mac_internal.h b/sys/security/mac/mac_internal.h index ceb1e87..2ecffc6 100644 --- a/sys/security/mac/mac_internal.h +++ b/sys/security/mac/mac_internal.h @@ -74,35 +74,35 @@ SDT_PROVIDER_DECLARE(mac); /* MAC Framework-level events. */ SDT_PROVIDER_DECLARE(mac_framework); /* Entry points to MAC. */ #define MAC_CHECK_PROBE_DEFINE4(name, arg0, arg1, arg2, arg3) \ - SDT_PROBE_DEFINE5(mac_framework, kernel, name, mac__check__err, \ + SDT_PROBE_DEFINE5(mac_framework, , name, mac__check__err, \ "int", arg0, arg1, arg2, arg3); \ - SDT_PROBE_DEFINE5(mac_framework, kernel, name, mac__check__ok, \ + SDT_PROBE_DEFINE5(mac_framework, , name, mac__check__ok, \ "int", arg0, arg1, arg2, arg3); #define MAC_CHECK_PROBE_DEFINE3(name, arg0, arg1, arg2) \ - SDT_PROBE_DEFINE4(mac_framework, kernel, name, mac__check__err, \ + SDT_PROBE_DEFINE4(mac_framework, , name, mac__check__err, \ "int", arg0, arg1, arg2); \ - SDT_PROBE_DEFINE4(mac_framework, kernel, name, mac__check__ok, \ + SDT_PROBE_DEFINE4(mac_framework, , name, mac__check__ok, \ "int", arg0, arg1, arg2); #define MAC_CHECK_PROBE_DEFINE2(name, arg0, arg1) \ - SDT_PROBE_DEFINE3(mac_framework, kernel, name, mac__check__err, \ + SDT_PROBE_DEFINE3(mac_framework, , name, mac__check__err, \ "int", arg0, arg1); \ - SDT_PROBE_DEFINE3(mac_framework, kernel, name, mac__check__ok, \ + SDT_PROBE_DEFINE3(mac_framework, , name, mac__check__ok, \ "int", arg0, arg1); #define MAC_CHECK_PROBE_DEFINE1(name, arg0) \ - SDT_PROBE_DEFINE2(mac_framework, kernel, name, mac__check__err, \ + SDT_PROBE_DEFINE2(mac_framework, , name, mac__check__err, \ "int", arg0); \ - SDT_PROBE_DEFINE2(mac_framework, kernel, name, mac__check__ok, \ + SDT_PROBE_DEFINE2(mac_framework, , name, mac__check__ok, \ "int", arg0); #define MAC_CHECK_PROBE4(name, error, arg0, arg1, arg2, arg3) do { \ if (error) { \ - SDT_PROBE(mac_framework, kernel, name, mac__check__err, \ + SDT_PROBE5(mac_framework, , name, mac__check__err, \ error, arg0, arg1, arg2, arg3); \ } else { \ - SDT_PROBE(mac_framework, kernel, name, mac__check__ok, \ + SDT_PROBE5(mac_framework, , name, mac__check__ok, \ 0, arg0, arg1, arg2, arg3); \ } \ } while (0) @@ -116,18 +116,18 @@ SDT_PROVIDER_DECLARE(mac_framework); /* Entry points to MAC. */ #endif #define MAC_GRANT_PROBE_DEFINE2(name, arg0, arg1) \ - SDT_PROBE_DEFINE3(mac_framework, kernel, name, mac__grant__err, \ + SDT_PROBE_DEFINE3(mac_framework, , name, mac__grant__err, \ "int", arg0, arg1); \ - SDT_PROBE_DEFINE3(mac_framework, kernel, name, mac__grant__ok, \ + SDT_PROBE_DEFINE3(mac_framework, , name, mac__grant__ok, \ "int", arg0, arg1); #define MAC_GRANT_PROBE2(name, error, arg0, arg1) do { \ if (error) { \ - SDT_PROBE(mac_framework, kernel, name, mac__grant__err, \ - error, arg0, arg1, 0, 0); \ + SDT_PROBE3(mac_framework, , name, mac__grant__err, \ + error, arg0, arg1); \ } else { \ - SDT_PROBE(mac_framework, kernel, name, mac__grant__ok, \ - error, arg0, arg1, 0, 0); \ + SDT_PROBE3(mac_framework, , name, mac__grant__ok, \ + error, arg0, arg1); \ } \ } while (0) diff --git a/sys/sys/buf.h b/sys/sys/buf.h index 75b41f3..c85b88f 100644 --- a/sys/sys/buf.h +++ b/sys/sys/buf.h @@ -122,14 +122,13 @@ struct buf { struct ucred *b_rcred; /* Read credentials reference. */ struct ucred *b_wcred; /* Write credentials reference. */ union { - TAILQ_ENTRY(buf) bu_freelist; /* (Q) */ + TAILQ_ENTRY(buf) b_freelist; /* (Q) */ struct { - void (*pg_iodone)(void *, vm_page_t *, int, int); - int pg_reqpage; - } bu_pager; - } b_union; -#define b_freelist b_union.bu_freelist -#define b_pager b_union.bu_pager + void (*b_pgiodone)(void *, vm_page_t *, int, int); + int b_pgbefore; + int b_pgafter; + }; + }; union cluster_info { TAILQ_HEAD(cluster_list_head, buf) cluster_head; TAILQ_ENTRY(buf) cluster_entry; diff --git a/sys/sys/sysent.h b/sys/sys/sysent.h index fe78fb4..d5b88eb 100644 --- a/sys/sys/sysent.h +++ b/sys/sys/sysent.h @@ -38,18 +38,18 @@ struct rlimit; struct sysent; struct thread; struct ksiginfo; +struct syscall_args; + +enum systrace_probe_t { + SYSTRACE_ENTRY, + SYSTRACE_RETURN, +}; typedef int sy_call_t(struct thread *, void *); -/* Used by the machine dependent syscall() code. */ -typedef void (*systrace_probe_func_t)(u_int32_t, int, struct sysent *, void *, - int); - -/* - * Used by loaded syscalls to convert arguments to a DTrace array - * of 64-bit arguments. - */ -typedef void (*systrace_args_func_t)(int, void *, u_int64_t *, int *); +typedef void (*systrace_probe_func_t)(struct syscall_args *, + enum systrace_probe_t, int); +typedef void (*systrace_args_func_t)(int, void *, uint64_t *, int *); extern systrace_probe_func_t systrace_probe_func; @@ -84,7 +84,6 @@ struct sysent { /* system call table */ struct image_params; struct __sigset; -struct syscall_args; struct trapframe; struct vnode; diff --git a/sys/sys/vnode.h b/sys/sys/vnode.h index 2ee63f2..7706b25 100644 --- a/sys/sys/vnode.h +++ b/sys/sys/vnode.h @@ -605,6 +605,8 @@ struct vnode; typedef int (*vn_get_ino_t)(struct mount *, void *, int, struct vnode **); +int bnoreuselist(struct bufv *bufv, struct bufobj *bo, daddr_t startn, + daddr_t endn); /* cache_* may belong in namei.h. */ void cache_changesize(int newhashsize); #define cache_enter(dvp, vp, cnp) \ diff --git a/sys/vm/default_pager.c b/sys/vm/default_pager.c index 98dee45..f334cd7 100644 --- a/sys/vm/default_pager.c +++ b/sys/vm/default_pager.c @@ -56,7 +56,7 @@ __FBSDID("$FreeBSD$"); static vm_object_t default_pager_alloc(void *, vm_ooffset_t, vm_prot_t, vm_ooffset_t, struct ucred *); static void default_pager_dealloc(vm_object_t); -static int default_pager_getpages(vm_object_t, vm_page_t *, int, int); +static int default_pager_getpages(vm_object_t, vm_page_t *, int, int *, int *); static void default_pager_putpages(vm_object_t, vm_page_t *, int, boolean_t, int *); static boolean_t default_pager_haspage(vm_object_t, vm_pindex_t, int *, @@ -122,13 +122,11 @@ default_pager_dealloc(object) * see a vm_page with assigned swap here. */ static int -default_pager_getpages(object, m, count, reqpage) - vm_object_t object; - vm_page_t *m; - int count; - int reqpage; +default_pager_getpages(vm_object_t object, vm_page_t *m, int count, + int *rbehind, int *rahead) { - return VM_PAGER_FAIL; + + return (VM_PAGER_FAIL); } /* diff --git a/sys/vm/device_pager.c b/sys/vm/device_pager.c index a0446be..5473081 100644 --- a/sys/vm/device_pager.c +++ b/sys/vm/device_pager.c @@ -59,7 +59,7 @@ static void dev_pager_init(void); static vm_object_t dev_pager_alloc(void *, vm_ooffset_t, vm_prot_t, vm_ooffset_t, struct ucred *); static void dev_pager_dealloc(vm_object_t); -static int dev_pager_getpages(vm_object_t, vm_page_t *, int, int); +static int dev_pager_getpages(vm_object_t, vm_page_t *, int, int *, int *); static void dev_pager_putpages(vm_object_t, vm_page_t *, int, int, int *); static boolean_t dev_pager_haspage(vm_object_t, vm_pindex_t, int *, int *); static void dev_pager_free_page(vm_object_t object, vm_page_t m); @@ -257,28 +257,33 @@ dev_pager_dealloc(vm_object_t object) } static int -dev_pager_getpages(vm_object_t object, vm_page_t *ma, int count, int reqpage) +dev_pager_getpages(vm_object_t object, vm_page_t *ma, int count, int *rbehind, + int *rahead) { int error; + /* Since our haspage reports zero after/before, the count is 1. */ + KASSERT(count == 1, ("%s: count %d", __func__, count)); VM_OBJECT_ASSERT_WLOCKED(object); error = object->un_pager.devp.ops->cdev_pg_fault(object, - IDX_TO_OFF(ma[reqpage]->pindex), PROT_READ, &ma[reqpage]); + IDX_TO_OFF(ma[0]->pindex), PROT_READ, &ma[0]); VM_OBJECT_ASSERT_WLOCKED(object); - vm_pager_free_nonreq(object, ma, reqpage, count, TRUE); - if (error == VM_PAGER_OK) { KASSERT((object->type == OBJT_DEVICE && - (ma[reqpage]->oflags & VPO_UNMANAGED) != 0) || + (ma[0]->oflags & VPO_UNMANAGED) != 0) || (object->type == OBJT_MGTDEVICE && - (ma[reqpage]->oflags & VPO_UNMANAGED) == 0), - ("Wrong page type %p %p", ma[reqpage], object)); + (ma[0]->oflags & VPO_UNMANAGED) == 0), + ("Wrong page type %p %p", ma[0], object)); if (object->type == OBJT_DEVICE) { TAILQ_INSERT_TAIL(&object->un_pager.devp.devp_pglist, - ma[reqpage], plinks.q); + ma[0], plinks.q); } + if (rbehind) + *rbehind = 0; + if (rahead) + *rahead = 0; } return (error); diff --git a/sys/vm/phys_pager.c b/sys/vm/phys_pager.c index 885a451..02e819e 100644 --- a/sys/vm/phys_pager.c +++ b/sys/vm/phys_pager.c @@ -139,7 +139,8 @@ phys_pager_dealloc(vm_object_t object) * Fill as many pages as vm_fault has allocated for us. */ static int -phys_pager_getpages(vm_object_t object, vm_page_t *m, int count, int reqpage) +phys_pager_getpages(vm_object_t object, vm_page_t *m, int count, int *rbehind, + int *rahead) { int i; @@ -154,14 +155,11 @@ phys_pager_getpages(vm_object_t object, vm_page_t *m, int count, int reqpage) ("phys_pager_getpages: partially valid page %p", m[i])); KASSERT(m[i]->dirty == 0, ("phys_pager_getpages: dirty page %p", m[i])); - /* The requested page must remain busy, the others not. */ - if (i == reqpage) { - vm_page_lock(m[i]); - vm_page_flash(m[i]); - vm_page_unlock(m[i]); - } else - vm_page_xunbusy(m[i]); } + if (rbehind) + *rbehind = 0; + if (rahead) + *rahead = 0; return (VM_PAGER_OK); } diff --git a/sys/vm/sg_pager.c b/sys/vm/sg_pager.c index 23ebd3a..26aa1d3 100644 --- a/sys/vm/sg_pager.c +++ b/sys/vm/sg_pager.c @@ -49,7 +49,7 @@ __FBSDID("$FreeBSD$"); static vm_object_t sg_pager_alloc(void *, vm_ooffset_t, vm_prot_t, vm_ooffset_t, struct ucred *); static void sg_pager_dealloc(vm_object_t); -static int sg_pager_getpages(vm_object_t, vm_page_t *, int, int); +static int sg_pager_getpages(vm_object_t, vm_page_t *, int, int *, int *); static void sg_pager_putpages(vm_object_t, vm_page_t *, int, boolean_t, int *); static boolean_t sg_pager_haspage(vm_object_t, vm_pindex_t, int *, @@ -135,7 +135,8 @@ sg_pager_dealloc(vm_object_t object) } static int -sg_pager_getpages(vm_object_t object, vm_page_t *m, int count, int reqpage) +sg_pager_getpages(vm_object_t object, vm_page_t *m, int count, int *rbehind, + int *rahead) { struct sglist *sg; vm_page_t m_paddr, page; @@ -145,11 +146,13 @@ sg_pager_getpages(vm_object_t object, vm_page_t *m, int count, int reqpage) size_t space; int i; + /* Since our haspage reports zero after/before, the count is 1. */ + KASSERT(count == 1, ("%s: count %d", __func__, count)); VM_OBJECT_ASSERT_WLOCKED(object); sg = object->handle; memattr = object->memattr; VM_OBJECT_WUNLOCK(object); - offset = m[reqpage]->pindex; + offset = m[0]->pindex; /* * Lookup the physical address of the requested page. An initial @@ -178,26 +181,23 @@ sg_pager_getpages(vm_object_t object, vm_page_t *m, int count, int reqpage) } /* Return a fake page for the requested page. */ - KASSERT(!(m[reqpage]->flags & PG_FICTITIOUS), + KASSERT(!(m[0]->flags & PG_FICTITIOUS), ("backing page for SG is fake")); /* Construct a new fake page. */ page = vm_page_getfake(paddr, memattr); VM_OBJECT_WLOCK(object); TAILQ_INSERT_TAIL(&object->un_pager.sgp.sgp_pglist, page, plinks.q); - - /* Free the original pages and insert this fake page into the object. */ - for (i = 0; i < count; i++) { - if (i == reqpage && - vm_page_replace(page, object, offset) != m[i]) - panic("sg_pager_getpages: invalid place replacement"); - vm_page_lock(m[i]); - vm_page_free(m[i]); - vm_page_unlock(m[i]); - } - m[reqpage] = page; + if (vm_page_replace(page, object, offset) != m[0]) + panic("sg_pager_getpages: invalid place replacement"); + m[0] = page; page->valid = VM_PAGE_BITS_ALL; + if (rbehind) + *rbehind = 0; + if (rahead) + *rahead = 0; + return (VM_PAGER_OK); } diff --git a/sys/vm/swap_pager.c b/sys/vm/swap_pager.c index 0bd4883..f243eca 100644 --- a/sys/vm/swap_pager.c +++ b/sys/vm/swap_pager.c @@ -357,9 +357,10 @@ static vm_object_t swap_pager_alloc(void *handle, vm_ooffset_t size, vm_prot_t prot, vm_ooffset_t offset, struct ucred *); static void swap_pager_dealloc(vm_object_t object); -static int swap_pager_getpages(vm_object_t, vm_page_t *, int, int); -static int swap_pager_getpages_async(vm_object_t, vm_page_t *, int, int, - pgo_getpages_iodone_t, void *); +static int swap_pager_getpages(vm_object_t, vm_page_t *, int, int *, + int *); +static int swap_pager_getpages_async(vm_object_t, vm_page_t *, int, int *, + int *, pgo_getpages_iodone_t, void *); static void swap_pager_putpages(vm_object_t, vm_page_t *, int, boolean_t, int *); static boolean_t swap_pager_haspage(vm_object_t object, vm_pindex_t pindex, int *before, int *after); @@ -413,16 +414,6 @@ static void swp_pager_meta_free(vm_object_t, vm_pindex_t, daddr_t); static void swp_pager_meta_free_all(vm_object_t); static daddr_t swp_pager_meta_ctl(vm_object_t, vm_pindex_t, int); -static void -swp_pager_free_nrpage(vm_page_t m) -{ - - vm_page_lock(m); - if (m->wire_count == 0) - vm_page_free(m); - vm_page_unlock(m); -} - /* * SWP_SIZECHECK() - update swap_pager_full indication * @@ -1103,16 +1094,12 @@ swap_pager_unswapped(vm_page_t m) * left busy, but the others adjusted. */ static int -swap_pager_getpages(vm_object_t object, vm_page_t *m, int count, int reqpage) +swap_pager_getpages(vm_object_t object, vm_page_t *m, int count, int *rbehind, + int *rahead) { struct buf *bp; - vm_page_t mreq; - int i; - int j; daddr_t blk; - mreq = m[reqpage]; - /* * Calculate range to retrieve. The pages have already been assigned * their swapblks. We require a *contiguous* range but we know it to @@ -1122,45 +1109,18 @@ swap_pager_getpages(vm_object_t object, vm_page_t *m, int count, int reqpage) * * The swp_*() calls must be made with the object locked. */ - blk = swp_pager_meta_ctl(mreq->object, mreq->pindex, 0); + blk = swp_pager_meta_ctl(m[0]->object, m[0]->pindex, 0); - for (i = reqpage - 1; i >= 0; --i) { - daddr_t iblk; - - iblk = swp_pager_meta_ctl(m[i]->object, m[i]->pindex, 0); - if (blk != iblk + (reqpage - i)) - break; - } - ++i; - - for (j = reqpage + 1; j < count; ++j) { - daddr_t jblk; - - jblk = swp_pager_meta_ctl(m[j]->object, m[j]->pindex, 0); - if (blk != jblk - (j - reqpage)) - break; - } - - /* - * free pages outside our collection range. Note: we never free - * mreq, it must remain busy throughout. - */ - if (0 < i || j < count) { - int k; - - for (k = 0; k < i; ++k) - swp_pager_free_nrpage(m[k]); - for (k = j; k < count; ++k) - swp_pager_free_nrpage(m[k]); - } - - /* - * Return VM_PAGER_FAIL if we have nothing to do. Return mreq - * still busy, but the others unbusied. - */ if (blk == SWAPBLK_NONE) return (VM_PAGER_FAIL); +#ifdef INVARIANTS + for (int i = 0; i < count; i++) + KASSERT(blk + i == + swp_pager_meta_ctl(m[i]->object, m[i]->pindex, 0), + ("%s: range is not contiguous", __func__)); +#endif + /* * Getpbuf() can sleep. */ @@ -1175,21 +1135,16 @@ swap_pager_getpages(vm_object_t object, vm_page_t *m, int count, int reqpage) bp->b_iodone = swp_pager_async_iodone; bp->b_rcred = crhold(thread0.td_ucred); bp->b_wcred = crhold(thread0.td_ucred); - bp->b_blkno = blk - (reqpage - i); - bp->b_bcount = PAGE_SIZE * (j - i); - bp->b_bufsize = PAGE_SIZE * (j - i); - bp->b_pager.pg_reqpage = reqpage - i; + bp->b_blkno = blk; + bp->b_bcount = PAGE_SIZE * count; + bp->b_bufsize = PAGE_SIZE * count; + bp->b_npages = count; VM_OBJECT_WLOCK(object); - { - int k; - - for (k = i; k < j; ++k) { - bp->b_pages[k - i] = m[k]; - m[k]->oflags |= VPO_SWAPINPROG; - } + for (int i = 0; i < count; i++) { + bp->b_pages[i] = m[i]; + m[i]->oflags |= VPO_SWAPINPROG; } - bp->b_npages = j - i; PCPU_INC(cnt.v_swapin); PCPU_ADD(cnt.v_swappgsin, bp->b_npages); @@ -1221,8 +1176,8 @@ swap_pager_getpages(vm_object_t object, vm_page_t *m, int count, int reqpage) * is set in the meta-data. */ VM_OBJECT_WLOCK(object); - while ((mreq->oflags & VPO_SWAPINPROG) != 0) { - mreq->oflags |= VPO_SWAPSLEEP; + while ((m[0]->oflags & VPO_SWAPINPROG) != 0) { + m[0]->oflags |= VPO_SWAPSLEEP; PCPU_INC(cnt.v_intrans); if (VM_OBJECT_SLEEP(object, &object->paging_in_progress, PSWP, "swread", hz * 20)) { @@ -1233,15 +1188,18 @@ swap_pager_getpages(vm_object_t object, vm_page_t *m, int count, int reqpage) } /* - * mreq is left busied after completion, but all the other pages - * are freed. If we had an unrecoverable read error the page will - * not be valid. + * If we had an unrecoverable read error pages will not be valid. */ - if (mreq->valid != VM_PAGE_BITS_ALL) { - return (VM_PAGER_ERROR); - } else { - return (VM_PAGER_OK); - } + for (int i = 0; i < count; i++) + if (m[i]->valid != VM_PAGE_BITS_ALL) + return (VM_PAGER_ERROR); + + if (rbehind) + *rbehind = 0; + if (rahead) + *rahead = 0; + + return (VM_PAGER_OK); /* * A final note: in a low swap situation, we cannot deallocate swap @@ -1259,11 +1217,11 @@ swap_pager_getpages(vm_object_t object, vm_page_t *m, int count, int reqpage) */ static int swap_pager_getpages_async(vm_object_t object, vm_page_t *m, int count, - int reqpage, pgo_getpages_iodone_t iodone, void *arg) + int *rbehind, int *rahead, pgo_getpages_iodone_t iodone, void *arg) { int r, error; - r = swap_pager_getpages(object, m, count, reqpage); + r = swap_pager_getpages(object, m, count, rbehind, rahead); VM_OBJECT_WUNLOCK(object); switch (r) { case VM_PAGER_OK: @@ -1527,33 +1485,11 @@ swp_pager_async_iodone(struct buf *bp) */ if (bp->b_iocmd == BIO_READ) { /* - * When reading, reqpage needs to stay - * locked for the parent, but all other - * pages can be freed. We still want to - * wakeup the parent waiting on the page, - * though. ( also: pg_reqpage can be -1 and - * not match anything ). - * - * We have to wake specifically requested pages - * up too because we cleared VPO_SWAPINPROG and - * someone may be waiting for that. - * * NOTE: for reads, m->dirty will probably * be overridden by the original caller of * getpages so don't play cute tricks here. */ m->valid = 0; - if (i != bp->b_pager.pg_reqpage) - swp_pager_free_nrpage(m); - else { - vm_page_lock(m); - vm_page_flash(m); - vm_page_unlock(m); - } - /* - * If i == bp->b_pager.pg_reqpage, do not wake - * the page up. The caller needs to. - */ } else { /* * If a write error occurs, reactivate page @@ -1575,38 +1511,12 @@ swp_pager_async_iodone(struct buf *bp) * want to do that anyway, but it was an optimization * that existed in the old swapper for a time before * it got ripped out due to precisely this problem. - * - * If not the requested page then deactivate it. - * - * Note that the requested page, reqpage, is left - * busied, but we still have to wake it up. The - * other pages are released (unbusied) by - * vm_page_xunbusy(). */ KASSERT(!pmap_page_is_mapped(m), ("swp_pager_async_iodone: page %p is mapped", m)); - m->valid = VM_PAGE_BITS_ALL; KASSERT(m->dirty == 0, ("swp_pager_async_iodone: page %p is dirty", m)); - - /* - * We have to wake specifically requested pages - * up too because we cleared VPO_SWAPINPROG and - * could be waiting for it in getpages. However, - * be sure to not unbusy getpages specifically - * requested page - getpages expects it to be - * left busy. - */ - if (i != bp->b_pager.pg_reqpage) { - vm_page_lock(m); - vm_page_deactivate(m); - vm_page_unlock(m); - vm_page_xunbusy(m); - } else { - vm_page_lock(m); - vm_page_flash(m); - vm_page_unlock(m); - } + m->valid = VM_PAGE_BITS_ALL; } else { /* * For write success, clear the dirty @@ -1727,7 +1637,7 @@ swp_pager_force_pagein(vm_object_t object, vm_pindex_t pindex) return; } - if (swap_pager_getpages(object, &m, 1, 0) != VM_PAGER_OK) + if (swap_pager_getpages(object, &m, 1, NULL, NULL) != VM_PAGER_OK) panic("swap_pager_force_pagein: read from swap failed");/*XXX*/ vm_object_pip_wakeup(object); vm_page_dirty(m); diff --git a/sys/vm/vm_fault.c b/sys/vm/vm_fault.c index 6990d12..a7e3d37 100644 --- a/sys/vm/vm_fault.c +++ b/sys/vm/vm_fault.c @@ -107,13 +107,8 @@ __FBSDID("$FreeBSD$"); #define PFBAK 4 #define PFFOR 4 -static int vm_fault_additional_pages(vm_page_t, int, int, vm_page_t *, int *); - -#define VM_FAULT_READ_BEHIND 8 #define VM_FAULT_READ_DEFAULT (1 + VM_FAULT_READ_AHEAD_INIT) #define VM_FAULT_READ_MAX (1 + VM_FAULT_READ_AHEAD_MAX) -#define VM_FAULT_NINCR (VM_FAULT_READ_MAX / VM_FAULT_READ_BEHIND) -#define VM_FAULT_SUM (VM_FAULT_NINCR * (VM_FAULT_NINCR + 1) / 2) #define VM_FAULT_DONTNEED_MIN 1048576 @@ -133,7 +128,7 @@ struct faultstate { static void vm_fault_dontneed(const struct faultstate *fs, vm_offset_t vaddr, int ahead); static void vm_fault_prefault(const struct faultstate *fs, vm_offset_t addra, - int faultcount, int reqpage); + int backward, int forward); static inline void release_page(struct faultstate *fs) @@ -288,11 +283,10 @@ vm_fault_hold(vm_map_t map, vm_offset_t vaddr, vm_prot_t fault_type, int fault_flags, vm_page_t *m_hold) { vm_prot_t prot; - int alloc_req, era, faultcount, nera, reqpage, result; + int alloc_req, era, faultcount, nera, result; boolean_t growstack, is_first_object_locked, wired; int map_generation; vm_object_t next_object; - vm_page_t marray[VM_FAULT_READ_MAX]; int hardfault; struct faultstate fs; struct vnode *vp; @@ -303,7 +297,7 @@ vm_fault_hold(vm_map_t map, vm_offset_t vaddr, vm_prot_t fault_type, growstack = TRUE; PCPU_INC(cnt.v_vm_faults); fs.vp = NULL; - faultcount = reqpage = 0; + faultcount = 0; RetryFault:; @@ -389,7 +383,7 @@ RetryFault:; FALSE); VM_OBJECT_RUNLOCK(fs.first_object); if (!wired) - vm_fault_prefault(&fs, vaddr, 0, 0); + vm_fault_prefault(&fs, vaddr, PFBAK, PFFOR); vm_map_lookup_done(fs.map, fs.entry); curthread->td_ru.ru_minflt++; return (KERN_SUCCESS); @@ -652,36 +646,13 @@ vnode_locked: ("vm_fault: vnode-backed object mapped by system map")); /* - * now we find out if any other pages should be paged - * in at this time this routine checks to see if the - * pages surrounding this fault reside in the same - * object as the page for this fault. If they do, - * then they are faulted in also into the object. The - * array "marray" returned contains an array of - * vm_page_t structs where one of them is the - * vm_page_t passed to the routine. The reqpage - * return value is the index into the marray for the - * vm_page_t passed to the routine. - * - * fs.m plus the additional pages are exclusive busied. + * Page in the requested page and hint the pager, + * that it may bring up surrounding pages. */ - faultcount = vm_fault_additional_pages( - fs.m, behind, ahead, marray, &reqpage); - - rv = faultcount ? - vm_pager_get_pages(fs.object, marray, faultcount, - reqpage) : VM_PAGER_FAIL; - + rv = vm_pager_get_pages(fs.object, &fs.m, 1, + &behind, &ahead); if (rv == VM_PAGER_OK) { - /* - * Found the page. Leave it busy while we play - * with it. - * - * Pager could have changed the page. Pager - * is responsible for disposition of old page - * if moved. - */ - fs.m = marray[reqpage]; + faultcount = behind + 1 + ahead; hardfault++; break; /* break to PAGE HAS BEEN FOUND */ } @@ -965,16 +936,13 @@ vnode_locked: } /* * If the page was filled by a pager, update the map entry's - * last read offset. Since the pager does not return the - * actual set of pages that it read, this update is based on - * the requested set. Typically, the requested and actual - * sets are the same. + * last read offset. * * XXX The following assignment modifies the map * without holding a write lock on it. */ if (hardfault) - fs.entry->next_read = fs.pindex + faultcount - reqpage; + fs.entry->next_read = fs.pindex + ahead + 1; vm_fault_dirty(fs.entry, fs.m, prot, fault_type, fault_flags, TRUE); vm_page_assert_xbusied(fs.m); @@ -997,7 +965,9 @@ vnode_locked: fault_type | (wired ? PMAP_ENTER_WIRED : 0), 0); if (faultcount != 1 && (fault_flags & VM_FAULT_WIRE) == 0 && wired == 0) - vm_fault_prefault(&fs, vaddr, faultcount, reqpage); + vm_fault_prefault(&fs, vaddr, + faultcount > 0 ? behind : PFBAK, + faultcount > 0 ? ahead : PFFOR); VM_OBJECT_WLOCK(fs.object); vm_page_lock(fs.m); @@ -1114,7 +1084,7 @@ vm_fault_dontneed(const struct faultstate *fs, vm_offset_t vaddr, int ahead) */ static void vm_fault_prefault(const struct faultstate *fs, vm_offset_t addra, - int faultcount, int reqpage) + int backward, int forward) { pmap_t pmap; vm_map_entry_t entry; @@ -1122,19 +1092,12 @@ vm_fault_prefault(const struct faultstate *fs, vm_offset_t addra, vm_offset_t addr, starta; vm_pindex_t pindex; vm_page_t m; - int backward, forward, i; + int i; pmap = fs->map->pmap; if (pmap != vmspace_pmap(curthread->td_proc->p_vmspace)) return; - if (faultcount > 0) { - backward = reqpage; - forward = faultcount - reqpage - 1; - } else { - backward = PFBAK; - forward = PFFOR; - } entry = fs->entry; starta = addra - backward * PAGE_SIZE; @@ -1465,133 +1428,6 @@ again: } } - -/* - * This routine checks around the requested page for other pages that - * might be able to be faulted in. This routine brackets the viable - * pages for the pages to be paged in. - * - * Inputs: - * m, rbehind, rahead - * - * Outputs: - * marray (array of vm_page_t), reqpage (index of requested page) - * - * Return value: - * number of pages in marray - */ -static int -vm_fault_additional_pages(m, rbehind, rahead, marray, reqpage) - vm_page_t m; - int rbehind; - int rahead; - vm_page_t *marray; - int *reqpage; -{ - int i,j; - vm_object_t object; - vm_pindex_t pindex, startpindex, endpindex, tpindex; - vm_page_t rtm; - int cbehind, cahead; - - VM_OBJECT_ASSERT_WLOCKED(m->object); - - object = m->object; - pindex = m->pindex; - cbehind = cahead = 0; - - /* - * if the requested page is not available, then give up now - */ - if (!vm_pager_has_page(object, pindex, &cbehind, &cahead)) { - return 0; - } - - if ((cbehind == 0) && (cahead == 0)) { - *reqpage = 0; - marray[0] = m; - return 1; - } - - if (rahead > cahead) { - rahead = cahead; - } - - if (rbehind > cbehind) { - rbehind = cbehind; - } - - /* - * scan backward for the read behind pages -- in memory - */ - if (pindex > 0) { - if (rbehind > pindex) { - rbehind = pindex; - startpindex = 0; - } else { - startpindex = pindex - rbehind; - } - - if ((rtm = TAILQ_PREV(m, pglist, listq)) != NULL && - rtm->pindex >= startpindex) - startpindex = rtm->pindex + 1; - - /* tpindex is unsigned; beware of numeric underflow. */ - for (i = 0, tpindex = pindex - 1; tpindex >= startpindex && - tpindex < pindex; i++, tpindex--) { - - rtm = vm_page_alloc(object, tpindex, VM_ALLOC_NORMAL | - VM_ALLOC_IFNOTCACHED); - if (rtm == NULL) { - /* - * Shift the allocated pages to the - * beginning of the array. - */ - for (j = 0; j < i; j++) { - marray[j] = marray[j + tpindex + 1 - - startpindex]; - } - break; - } - - marray[tpindex - startpindex] = rtm; - } - } else { - startpindex = 0; - i = 0; - } - - marray[i] = m; - /* page offset of the required page */ - *reqpage = i; - - tpindex = pindex + 1; - i++; - - /* - * scan forward for the read ahead pages - */ - endpindex = tpindex + rahead; - if ((rtm = TAILQ_NEXT(m, listq)) != NULL && rtm->pindex < endpindex) - endpindex = rtm->pindex; - if (endpindex > object->size) - endpindex = object->size; - - for (; tpindex < endpindex; i++, tpindex++) { - - rtm = vm_page_alloc(object, tpindex, VM_ALLOC_NORMAL | - VM_ALLOC_IFNOTCACHED); - if (rtm == NULL) { - break; - } - - marray[i] = rtm; - } - - /* return number of pages */ - return i; -} - /* * Block entry into the machine-independent layer's page fault handler by * the calling thread. Subsequent calls to vm_fault() by that thread will diff --git a/sys/vm/vm_glue.c b/sys/vm/vm_glue.c index f00dce1..e1538db 100644 --- a/sys/vm/vm_glue.c +++ b/sys/vm/vm_glue.c @@ -238,7 +238,7 @@ vm_imgact_hold_page(vm_object_t object, vm_ooffset_t offset) pindex = OFF_TO_IDX(offset); m = vm_page_grab(object, pindex, VM_ALLOC_NORMAL); if (m->valid != VM_PAGE_BITS_ALL) { - rv = vm_pager_get_pages(object, &m, 1, 0); + rv = vm_pager_get_pages(object, &m, 1, NULL, NULL); if (rv != VM_PAGER_OK) { vm_page_lock(m); vm_page_free(m); @@ -567,37 +567,37 @@ vm_thread_swapin(struct thread *td) { vm_object_t ksobj; vm_page_t ma[KSTACK_MAX_PAGES]; - int i, j, pages, rv; + int pages; pages = td->td_kstack_pages; ksobj = td->td_kstack_obj; VM_OBJECT_WLOCK(ksobj); - for (i = 0; i < pages; i++) + for (int i = 0; i < pages; i++) ma[i] = vm_page_grab(ksobj, i, VM_ALLOC_NORMAL | VM_ALLOC_WIRED); - for (i = 0; i < pages; i++) { - if (ma[i]->valid != VM_PAGE_BITS_ALL) { - vm_page_assert_xbusied(ma[i]); - vm_object_pip_add(ksobj, 1); - for (j = i + 1; j < pages; j++) { - if (ma[j]->valid != VM_PAGE_BITS_ALL) - vm_page_assert_xbusied(ma[j]); - if (ma[j]->valid == VM_PAGE_BITS_ALL) - break; - } - rv = vm_pager_get_pages(ksobj, ma + i, j - i, 0); - if (rv != VM_PAGER_OK) - panic("vm_thread_swapin: cannot get kstack for proc: %d", - td->td_proc->p_pid); - /* - * All pages in the array are in place, due to the - * pager is always the swap pager, which doesn't - * free or remove wired non-req pages from object. - */ - vm_object_pip_wakeup(ksobj); - vm_page_xunbusy(ma[i]); - } else if (vm_page_xbusied(ma[i])) + for (int i = 0; i < pages;) { + int j, a, count, rv; + + vm_page_assert_xbusied(ma[i]); + if (ma[i]->valid == VM_PAGE_BITS_ALL) { vm_page_xunbusy(ma[i]); + i++; + continue; + } + vm_object_pip_add(ksobj, 1); + for (j = i + 1; j < pages; j++) + if (ma[j]->valid == VM_PAGE_BITS_ALL) + break; + rv = vm_pager_has_page(ksobj, ma[i]->pindex, NULL, &a); + KASSERT(rv == 1, ("%s: missing page %p", __func__, ma[i])); + count = min(a + 1, j - i); + rv = vm_pager_get_pages(ksobj, ma + i, count, NULL, NULL); + KASSERT(rv == VM_PAGER_OK, ("%s: cannot get kstack for proc %d", + __func__, td->td_proc->p_pid)); + vm_object_pip_wakeup(ksobj); + for (j = i; j < i + count; j++) + vm_page_xunbusy(ma[j]); + i += count; } VM_OBJECT_WUNLOCK(ksobj); pmap_qenter(td->td_kstack, ma, pages); diff --git a/sys/vm/vm_object.c b/sys/vm/vm_object.c index 9c5c83a..bc0e4c0 100644 --- a/sys/vm/vm_object.c +++ b/sys/vm/vm_object.c @@ -2014,7 +2014,7 @@ vm_object_populate(vm_object_t object, vm_pindex_t start, vm_pindex_t end) for (pindex = start; pindex < end; pindex++) { m = vm_page_grab(object, pindex, VM_ALLOC_NORMAL); if (m->valid != VM_PAGE_BITS_ALL) { - rv = vm_pager_get_pages(object, &m, 1, 0); + rv = vm_pager_get_pages(object, &m, 1, NULL, NULL); if (rv != VM_PAGER_OK) { vm_page_lock(m); vm_page_free(m); diff --git a/sys/vm/vm_object.h b/sys/vm/vm_object.h index 894a8d5..ca2d73a 100644 --- a/sys/vm/vm_object.h +++ b/sys/vm/vm_object.h @@ -243,6 +243,8 @@ extern struct vm_object kmem_object_store; rw_try_upgrade(&(object)->lock) #define VM_OBJECT_WLOCK(object) \ rw_wlock(&(object)->lock) +#define VM_OBJECT_WOWNED(object) \ + rw_wowned(&(object)->lock) #define VM_OBJECT_WUNLOCK(object) \ rw_wunlock(&(object)->lock) diff --git a/sys/vm/vm_page.c b/sys/vm/vm_page.c index e5edf77..2e6b56a 100644 --- a/sys/vm/vm_page.c +++ b/sys/vm/vm_page.c @@ -979,38 +979,28 @@ vm_page_free_zero(vm_page_t m) /* * Unbusy and handle the page queueing for a page from the VOP_GETPAGES() - * array which is not the request page. + * array which was optionally read ahead or behind. */ void vm_page_readahead_finish(vm_page_t m) { - if (m->valid != 0) { - /* - * Since the page is not the requested page, whether - * it should be activated or deactivated is not - * obvious. Empirical results have shown that - * deactivating the page is usually the best choice, - * unless the page is wanted by another thread. - */ - vm_page_lock(m); - if ((m->busy_lock & VPB_BIT_WAITERS) != 0) - vm_page_activate(m); - else - vm_page_deactivate(m); - vm_page_unlock(m); - vm_page_xunbusy(m); - } else { - /* - * Free the completely invalid page. Such page state - * occurs due to the short read operation which did - * not covered our page at all, or in case when a read - * error happens. - */ - vm_page_lock(m); - vm_page_free(m); - vm_page_unlock(m); - } + /* We shouldn't put invalid pages on queues. */ + KASSERT(m->valid != 0, ("%s: %p is invalid", __func__, m)); + + /* + * Since the page is not the actually needed one, whether it should + * be activated or deactivated is not obvious. Empirical results + * have shown that deactivating the page is usually the best choice, + * unless the page is wanted by another thread. + */ + vm_page_lock(m); + if ((m->busy_lock & VPB_BIT_WAITERS) != 0) + vm_page_activate(m); + else + vm_page_deactivate(m); + vm_page_unlock(m); + vm_page_xunbusy(m); } /* diff --git a/sys/vm/vm_page.h b/sys/vm/vm_page.h index 1fa61eb..9abd31c 100644 --- a/sys/vm/vm_page.h +++ b/sys/vm/vm_page.h @@ -514,37 +514,38 @@ void vm_page_lock_assert_KBI(vm_page_t m, int a, const char *file, int line); #define vm_page_assert_sbusied(m) \ KASSERT(vm_page_sbusied(m), \ ("vm_page_assert_sbusied: page %p not shared busy @ %s:%d", \ - (void *)m, __FILE__, __LINE__)); + (m), __FILE__, __LINE__)) #define vm_page_assert_unbusied(m) \ KASSERT(!vm_page_busied(m), \ ("vm_page_assert_unbusied: page %p busy @ %s:%d", \ - (void *)m, __FILE__, __LINE__)); + (m), __FILE__, __LINE__)) #define vm_page_assert_xbusied(m) \ KASSERT(vm_page_xbusied(m), \ ("vm_page_assert_xbusied: page %p not exclusive busy @ %s:%d", \ - (void *)m, __FILE__, __LINE__)); + (m), __FILE__, __LINE__)) #define vm_page_busied(m) \ ((m)->busy_lock != VPB_UNBUSIED) #define vm_page_sbusy(m) do { \ if (!vm_page_trysbusy(m)) \ - panic("%s: page %p failed shared busing", __func__, m); \ + panic("%s: page %p failed shared busying", __func__, \ + (m)); \ } while (0) #define vm_page_tryxbusy(m) \ - (atomic_cmpset_acq_int(&m->busy_lock, VPB_UNBUSIED, \ + (atomic_cmpset_acq_int(&(m)->busy_lock, VPB_UNBUSIED, \ VPB_SINGLE_EXCLUSIVER)) #define vm_page_xbusied(m) \ - ((m->busy_lock & VPB_SINGLE_EXCLUSIVER) != 0) + (((m)->busy_lock & VPB_SINGLE_EXCLUSIVER) != 0) #define vm_page_xbusy(m) do { \ if (!vm_page_tryxbusy(m)) \ - panic("%s: page %p failed exclusive busing", __func__, \ - m); \ + panic("%s: page %p failed exclusive busying", __func__, \ + (m)); \ } while (0) #define vm_page_xunbusy(m) do { \ diff --git a/sys/vm/vm_pager.c b/sys/vm/vm_pager.c index 40d7d4e..7a1e6ae 100644 --- a/sys/vm/vm_pager.c +++ b/sys/vm/vm_pager.c @@ -88,7 +88,7 @@ int cluster_pbuf_freecnt = -1; /* unlimited to begin with */ struct buf *swbuf; -static int dead_pager_getpages(vm_object_t, vm_page_t *, int, int); +static int dead_pager_getpages(vm_object_t, vm_page_t *, int, int *, int *); static vm_object_t dead_pager_alloc(void *, vm_ooffset_t, vm_prot_t, vm_ooffset_t, struct ucred *); static void dead_pager_putpages(vm_object_t, vm_page_t *, int, int, int *); @@ -96,13 +96,11 @@ static boolean_t dead_pager_haspage(vm_object_t, vm_pindex_t, int *, int *); static void dead_pager_dealloc(vm_object_t); static int -dead_pager_getpages(obj, ma, count, req) - vm_object_t obj; - vm_page_t *ma; - int count; - int req; +dead_pager_getpages(vm_object_t obj, vm_page_t *ma, int count, int *rbehind, + int *rahead) { - return VM_PAGER_FAIL; + + return (VM_PAGER_FAIL); } static vm_object_t @@ -282,45 +280,47 @@ vm_pager_assert_in(vm_object_t object, vm_page_t *m, int count) * The requested page must be fully valid on successful return. */ int -vm_pager_get_pages(vm_object_t object, vm_page_t *m, int count, int reqpage) +vm_pager_get_pages(vm_object_t object, vm_page_t *m, int count, int *rbehind, + int *rahead) { +#ifdef INVARIANTS + vm_pindex_t pindex = m[0]->pindex; +#endif int r; vm_pager_assert_in(object, m, count); - r = (*pagertab[object->type]->pgo_getpages)(object, m, count, reqpage); + r = (*pagertab[object->type]->pgo_getpages)(object, m, count, rbehind, + rahead); if (r != VM_PAGER_OK) return (r); - /* - * If pager has replaced the page, assert that it had - * updated the array. Also assert that page is still - * busied. - */ - KASSERT(m[reqpage] == vm_page_lookup(object, m[reqpage]->pindex), - ("%s: mismatch page %p pindex %ju", __func__, - m[reqpage], (uintmax_t )m[reqpage]->pindex)); - vm_page_assert_xbusied(m[reqpage]); - - /* - * Pager didn't fill up entire page. Zero out - * partially filled data. - */ - if (m[reqpage]->valid != VM_PAGE_BITS_ALL) - vm_page_zero_invalid(m[reqpage], TRUE); - + for (int i = 0; i < count; i++) { + /* + * If pager has replaced a page, assert that it had + * updated the array. + */ + KASSERT(m[i] == vm_page_lookup(object, pindex++), + ("%s: mismatch page %p pindex %ju", __func__, + m[i], (uintmax_t )pindex - 1)); + /* + * Zero out partially filled data. + */ + if (m[i]->valid != VM_PAGE_BITS_ALL) + vm_page_zero_invalid(m[i], TRUE); + } return (VM_PAGER_OK); } int vm_pager_get_pages_async(vm_object_t object, vm_page_t *m, int count, - int reqpage, pgo_getpages_iodone_t iodone, void *arg) + int *rbehind, int *rahead, pgo_getpages_iodone_t iodone, void *arg) { vm_pager_assert_in(object, m, count); return ((*pagertab[object->type]->pgo_getpages_async)(object, m, - count, reqpage, iodone, arg)); + count, rbehind, rahead, iodone, arg)); } /* @@ -355,39 +355,6 @@ vm_pager_object_lookup(struct pagerlst *pg_list, void *handle) } /* - * Free the non-requested pages from the given array. To remove all pages, - * caller should provide out of range reqpage number. - */ -void -vm_pager_free_nonreq(vm_object_t object, vm_page_t ma[], int reqpage, - int npages, boolean_t object_locked) -{ - enum { UNLOCKED, CALLER_LOCKED, INTERNALLY_LOCKED } locked; - int i; - - if (object_locked) { - VM_OBJECT_ASSERT_WLOCKED(object); - locked = CALLER_LOCKED; - } else { - VM_OBJECT_ASSERT_UNLOCKED(object); - locked = UNLOCKED; - } - for (i = 0; i < npages; ++i) { - if (i != reqpage) { - if (locked == UNLOCKED) { - VM_OBJECT_WLOCK(object); - locked = INTERNALLY_LOCKED; - } - vm_page_lock(ma[i]); - vm_page_free(ma[i]); - vm_page_unlock(ma[i]); - } - } - if (locked == INTERNALLY_LOCKED) - VM_OBJECT_WUNLOCK(object); -} - -/* * initialize a physical buffer */ diff --git a/sys/vm/vm_pager.h b/sys/vm/vm_pager.h index 6884729..4b7d100 100644 --- a/sys/vm/vm_pager.h +++ b/sys/vm/vm_pager.h @@ -50,9 +50,9 @@ typedef void pgo_init_t(void); typedef vm_object_t pgo_alloc_t(void *, vm_ooffset_t, vm_prot_t, vm_ooffset_t, struct ucred *); typedef void pgo_dealloc_t(vm_object_t); -typedef int pgo_getpages_t(vm_object_t, vm_page_t *, int, int); +typedef int pgo_getpages_t(vm_object_t, vm_page_t *, int, int *, int *); typedef void pgo_getpages_iodone_t(void *, vm_page_t *, int, int); -typedef int pgo_getpages_async_t(vm_object_t, vm_page_t *, int, int, +typedef int pgo_getpages_async_t(vm_object_t, vm_page_t *, int, int *, int *, pgo_getpages_iodone_t, void *); typedef void pgo_putpages_t(vm_object_t, vm_page_t *, int, int, int *); typedef boolean_t pgo_haspage_t(vm_object_t, vm_pindex_t, int *, int *); @@ -106,14 +106,12 @@ vm_object_t vm_pager_allocate(objtype_t, void *, vm_ooffset_t, vm_prot_t, vm_ooffset_t, struct ucred *); void vm_pager_bufferinit(void); void vm_pager_deallocate(vm_object_t); -int vm_pager_get_pages(vm_object_t, vm_page_t *, int, int); -int vm_pager_get_pages_async(vm_object_t, vm_page_t *, int, int, +int vm_pager_get_pages(vm_object_t, vm_page_t *, int, int *, int *); +int vm_pager_get_pages_async(vm_object_t, vm_page_t *, int, int *, int *, pgo_getpages_iodone_t, void *); static __inline boolean_t vm_pager_has_page(vm_object_t, vm_pindex_t, int *, int *); void vm_pager_init(void); vm_object_t vm_pager_object_lookup(struct pagerlst *, void *); -void vm_pager_free_nonreq(vm_object_t object, vm_page_t ma[], int reqpage, - int npages, boolean_t object_locked); static __inline void vm_pager_put_pages( diff --git a/sys/vm/vnode_pager.c b/sys/vm/vnode_pager.c index 96510ac..ff30f4d 100644 --- a/sys/vm/vnode_pager.c +++ b/sys/vm/vnode_pager.c @@ -84,11 +84,9 @@ static int vnode_pager_addr(struct vnode *vp, vm_ooffset_t address, static int vnode_pager_input_smlfs(vm_object_t object, vm_page_t m); static int vnode_pager_input_old(vm_object_t object, vm_page_t m); static void vnode_pager_dealloc(vm_object_t); -static int vnode_pager_local_getpages0(struct vnode *, vm_page_t *, int, int, - vop_getpages_iodone_t, void *); -static int vnode_pager_getpages(vm_object_t, vm_page_t *, int, int); -static int vnode_pager_getpages_async(vm_object_t, vm_page_t *, int, int, - vop_getpages_iodone_t, void *); +static int vnode_pager_getpages(vm_object_t, vm_page_t *, int, int *, int *); +static int vnode_pager_getpages_async(vm_object_t, vm_page_t *, int, int *, + int *, vop_getpages_iodone_t, void *); static void vnode_pager_putpages(vm_object_t, vm_page_t *, int, int, int *); static boolean_t vnode_pager_haspage(vm_object_t, vm_pindex_t, int *, int *); static vm_object_t vnode_pager_alloc(void *, vm_ooffset_t, vm_prot_t, @@ -673,15 +671,15 @@ vnode_pager_input_old(vm_object_t object, vm_page_t m) * backing vp's VOP_GETPAGES. */ static int -vnode_pager_getpages(vm_object_t object, vm_page_t *m, int count, int reqpage) +vnode_pager_getpages(vm_object_t object, vm_page_t *m, int count, int *rbehind, + int *rahead) { - int rtval; struct vnode *vp; - int bytes = count * PAGE_SIZE; + int rtval; vp = object->handle; VM_OBJECT_WUNLOCK(object); - rtval = VOP_GETPAGES(vp, m, bytes, reqpage); + rtval = VOP_GETPAGES(vp, m, count, rbehind, rahead); KASSERT(rtval != EOPNOTSUPP, ("vnode_pager: FS getpages not implemented\n")); VM_OBJECT_WLOCK(object); @@ -690,15 +688,14 @@ vnode_pager_getpages(vm_object_t object, vm_page_t *m, int count, int reqpage) static int vnode_pager_getpages_async(vm_object_t object, vm_page_t *m, int count, - int reqpage, vop_getpages_iodone_t iodone, void *arg) + int *rbehind, int *rahead, vop_getpages_iodone_t iodone, void *arg) { struct vnode *vp; int rtval; vp = object->handle; VM_OBJECT_WUNLOCK(object); - rtval = VOP_GETPAGES_ASYNC(vp, m, count * PAGE_SIZE, reqpage, - iodone, arg); + rtval = VOP_GETPAGES_ASYNC(vp, m, count, rbehind, rahead, iodone, arg); KASSERT(rtval != EOPNOTSUPP, ("vnode_pager: FS getpages_async not implemented\n")); VM_OBJECT_WLOCK(object); @@ -714,48 +711,16 @@ int vnode_pager_local_getpages(struct vop_getpages_args *ap) { - return (vnode_pager_local_getpages0(ap->a_vp, ap->a_m, ap->a_count, - ap->a_reqpage, NULL, NULL)); + return (vnode_pager_generic_getpages(ap->a_vp, ap->a_m, ap->a_count, + ap->a_rbehind, ap->a_rahead, NULL, NULL)); } int vnode_pager_local_getpages_async(struct vop_getpages_async_args *ap) { - return (vnode_pager_local_getpages0(ap->a_vp, ap->a_m, ap->a_count, - ap->a_reqpage, ap->a_iodone, ap->a_arg)); -} - -static int -vnode_pager_local_getpages0(struct vnode *vp, vm_page_t *m, int bytecount, - int reqpage, vop_getpages_iodone_t iodone, void *arg) -{ - vm_page_t mreq; - - mreq = m[reqpage]; - - /* - * Since the caller has busied the requested page, that page's valid - * field will not be changed by other threads. - */ - vm_page_assert_xbusied(mreq); - - /* - * The requested page has valid blocks. Invalid part can only - * exist at the end of file, and the page is made fully valid - * by zeroing in vm_pager_get_pages(). Free non-requested - * pages, since no i/o is done to read its content. - */ - if (mreq->valid != 0) { - vm_pager_free_nonreq(mreq->object, m, reqpage, - round_page(bytecount) / PAGE_SIZE, FALSE); - if (iodone != NULL) - iodone(arg, m, reqpage, 0); - return (VM_PAGER_OK); - } - - return (vnode_pager_generic_getpages(vp, m, bytecount, reqpage, - iodone, arg)); + return (vnode_pager_generic_getpages(ap->a_vp, ap->a_m, ap->a_count, + ap->a_rbehind, ap->a_rahead, ap->a_iodone, ap->a_arg)); } /* @@ -763,25 +728,43 @@ vnode_pager_local_getpages0(struct vnode *vp, vm_page_t *m, int bytecount, * own vnodes if they fail to implement VOP_GETPAGES. */ int -vnode_pager_generic_getpages(struct vnode *vp, vm_page_t *m, int bytecount, - int reqpage, vop_getpages_iodone_t iodone, void *arg) +vnode_pager_generic_getpages(struct vnode *vp, vm_page_t *m, int count, + int *a_rbehind, int *a_rahead, vop_getpages_iodone_t iodone, void *arg) { vm_object_t object; struct bufobj *bo; struct buf *bp; - daddr_t firstaddr, reqblock; - off_t foff, pib; - int pbefore, pafter, i, size, bsize, first, last, *freecnt; - int count, error, before, after, secmask; + off_t foff; + int bsize, pagesperblock, *freecnt; + int error, before, after, rbehind, rahead, poff, i; + int bytecount, secmask; KASSERT(vp->v_type != VCHR && vp->v_type != VBLK, - ("vnode_pager_generic_getpages does not support devices")); + ("%s does not support devices", __func__)); + if (vp->v_iflag & VI_DOOMED) return (VM_PAGER_BAD); object = vp->v_object; - count = bytecount / PAGE_SIZE; + foff = IDX_TO_OFF(m[0]->pindex); bsize = vp->v_mount->mnt_stat.f_iosize; + pagesperblock = bsize / PAGE_SIZE; + + KASSERT(foff < object->un_pager.vnp.vnp_size, + ("%s: page %p offset beyond vp %p size", __func__, m[0], vp)); + KASSERT(count <= sizeof(bp->b_pages), + ("%s: requested %d pages", __func__, count)); + + /* + * The last page has valid blocks. Invalid part can only + * exist at the end of file, and the page is made fully valid + * by zeroing in vm_pager_get_pages(). + */ + if (m[count - 1]->valid != 0 && --count == 0) { + if (iodone != NULL) + iodone(arg, m, 1, 0); + return (VM_PAGER_OK); + } /* * Synchronous and asynchronous paging operations use different @@ -800,130 +783,182 @@ vnode_pager_generic_getpages(struct vnode *vp, vm_page_t *m, int bytecount, * If the file system doesn't support VOP_BMAP, use old way of * getting pages via VOP_READ. */ - error = VOP_BMAP(vp, IDX_TO_OFF(m[reqpage]->pindex) / bsize, &bo, - &reqblock, &after, &before); + error = VOP_BMAP(vp, foff / bsize, &bo, &bp->b_blkno, &after, &before); if (error == EOPNOTSUPP) { relpbuf(bp, freecnt); VM_OBJECT_WLOCK(object); - for (i = 0; i < count; i++) - if (i != reqpage) { - vm_page_lock(m[i]); - vm_page_free(m[i]); - vm_page_unlock(m[i]); - } - PCPU_INC(cnt.v_vnodein); - PCPU_INC(cnt.v_vnodepgsin); - error = vnode_pager_input_old(object, m[reqpage]); + for (i = 0; i < count; i++) { + PCPU_INC(cnt.v_vnodein); + PCPU_INC(cnt.v_vnodepgsin); + error = vnode_pager_input_old(object, m[i]); + if (error) + break; + } VM_OBJECT_WUNLOCK(object); return (error); } else if (error != 0) { relpbuf(bp, freecnt); - vm_pager_free_nonreq(object, m, reqpage, count, FALSE); return (VM_PAGER_ERROR); - - /* - * If the blocksize is smaller than a page size, then use - * special small filesystem code. - */ - } else if ((PAGE_SIZE / bsize) > 1) { - relpbuf(bp, freecnt); - vm_pager_free_nonreq(object, m, reqpage, count, FALSE); - PCPU_INC(cnt.v_vnodein); - PCPU_INC(cnt.v_vnodepgsin); - return (vnode_pager_input_smlfs(object, m[reqpage])); } /* - * Since the caller has busied the requested page, that page's valid - * field will not be changed by other threads. + * If the file system supports BMAP, but blocksize is smaller + * than a page size, then use special small filesystem code. */ - vm_page_assert_xbusied(m[reqpage]); + if (pagesperblock == 0) { + for (i = 0; i < count; i++) { + PCPU_INC(cnt.v_vnodein); + PCPU_INC(cnt.v_vnodepgsin); + error = vnode_pager_input_smlfs(object, m[i]); + if (error) + break; + } + return (error); + } /* - * If we have a completely valid page available to us, we can - * clean up and return. Otherwise we have to re-read the - * media. + * A sparse file can be encountered only for a single page request, + * which may not be preceeded by call to vm_pager_haspage(). */ - if (m[reqpage]->valid == VM_PAGE_BITS_ALL) { - relpbuf(bp, freecnt); - vm_pager_free_nonreq(object, m, reqpage, count, FALSE); - return (VM_PAGER_OK); - } else if (reqblock == -1) { + if (bp->b_blkno == -1) { + KASSERT(count == 1, + ("%s: array[%d] request to a sparse file %p", __func__, + count, vp)); relpbuf(bp, freecnt); - pmap_zero_page(m[reqpage]); - KASSERT(m[reqpage]->dirty == 0, - ("vnode_pager_generic_getpages: page %p is dirty", m)); + pmap_zero_page(m[0]); + KASSERT(m[0]->dirty == 0, ("%s: page %p is dirty", + __func__, m[0])); VM_OBJECT_WLOCK(object); - m[reqpage]->valid = VM_PAGE_BITS_ALL; - vm_pager_free_nonreq(object, m, reqpage, count, TRUE); + m[0]->valid = VM_PAGE_BITS_ALL; VM_OBJECT_WUNLOCK(object); return (VM_PAGER_OK); - } else if (m[reqpage]->valid != 0) { - VM_OBJECT_WLOCK(object); - m[reqpage]->valid = 0; - VM_OBJECT_WUNLOCK(object); } - pib = IDX_TO_OFF(m[reqpage]->pindex) % bsize; - pbefore = ((daddr_t)before * bsize + pib) / PAGE_SIZE; - pafter = ((daddr_t)(after + 1) * bsize - pib) / PAGE_SIZE - 1; - first = reqpage < pbefore ? 0 : reqpage - pbefore; - last = reqpage + pafter >= count ? count - 1 : reqpage + pafter; - if (first > 0 || last + 1 < count) { + bp->b_blkno += (foff % bsize) / DEV_BSIZE; + + /* Recalculate blocks available after/before to pages. */ + poff = (foff % bsize) / PAGE_SIZE; + before *= pagesperblock; + before += poff; + after *= pagesperblock; + after += pagesperblock - (poff + 1); + if (m[0]->pindex + after >= object->size) + after = object->size - 1 - m[0]->pindex; + KASSERT(count <= after + 1, ("%s: %d pages asked, can do only %d", + __func__, count, after + 1)); + after -= count - 1; + + /* Trim requested rbehind/rahead to possible values. */ + rbehind = a_rbehind ? *a_rbehind : 0; + rahead = a_rahead ? *a_rahead : 0; + rbehind = min(rbehind, before); + rbehind = min(rbehind, m[0]->pindex); + rahead = min(rahead, after); + rahead = min(rahead, object->size - m[count - 1]->pindex); + KASSERT(rbehind + rahead + count <= sizeof(bp->b_pages), + ("%s: behind %d ahead %d count %d", __func__, + rbehind, rahead, count)); + + /* + * Fill in the bp->b_pages[] array with requested and optional + * read behind or read ahead pages. Read behind pages are looked + * up in a backward direction, down to a first cached page. Same + * for read ahead pages, but there is no need to shift the array + * in case of encountering a cached page. + */ + i = bp->b_npages = 0; + if (rbehind) { + vm_pindex_t startpindex, tpindex; + vm_page_t p; + VM_OBJECT_WLOCK(object); - for (i = 0; i < first; i++) { - vm_page_lock(m[i]); - vm_page_free(m[i]); - vm_page_unlock(m[i]); + startpindex = m[0]->pindex - rbehind; + if ((p = TAILQ_PREV(m[0], pglist, listq)) != NULL && + p->pindex >= startpindex) + startpindex = p->pindex + 1; + + /* tpindex is unsigned; beware of numeric underflow. */ + for (tpindex = m[0]->pindex - 1; + tpindex >= startpindex && tpindex < m[0]->pindex; + tpindex--, i++) { + p = vm_page_alloc(object, tpindex, VM_ALLOC_NORMAL | + VM_ALLOC_IFNOTCACHED); + if (p == NULL) { + /* Shift the array. */ + for (int j = 0; j < i; j++) + bp->b_pages[j] = bp->b_pages[j + + tpindex + 1 - startpindex]; + break; + } + bp->b_pages[tpindex - startpindex] = p; } - for (i = last + 1; i < count; i++) { - vm_page_lock(m[i]); - vm_page_free(m[i]); - vm_page_unlock(m[i]); + + bp->b_pgbefore = i; + bp->b_npages += i; + bp->b_blkno -= IDX_TO_OFF(i) / DEV_BSIZE; + } else + bp->b_pgbefore = 0; + + /* Requested pages. */ + for (int j = 0; j < count; j++, i++) + bp->b_pages[i] = m[j]; + bp->b_npages += count; + + if (rahead) { + vm_pindex_t endpindex, tpindex; + vm_page_t p; + + if (!VM_OBJECT_WOWNED(object)) + VM_OBJECT_WLOCK(object); + endpindex = m[count - 1]->pindex + rahead + 1; + if ((p = TAILQ_NEXT(m[count - 1], listq)) != NULL && + p->pindex < endpindex) + endpindex = p->pindex; + if (endpindex > object->size) + endpindex = object->size; + + for (tpindex = m[count - 1]->pindex + 1; + tpindex < endpindex; i++, tpindex++) { + p = vm_page_alloc(object, tpindex, VM_ALLOC_NORMAL | + VM_ALLOC_IFNOTCACHED); + if (p == NULL) + break; + bp->b_pages[i] = p; } - VM_OBJECT_WUNLOCK(object); - } - /* - * here on direct device I/O - */ - firstaddr = reqblock; - firstaddr += pib / DEV_BSIZE; - firstaddr -= IDX_TO_OFF(reqpage - first) / DEV_BSIZE; + bp->b_pgafter = i - bp->b_npages; + bp->b_npages = i; + } else + bp->b_pgafter = 0; - /* - * The first and last page have been calculated now, move - * input pages to be zero based, and adjust the count. - */ - m += first; - reqpage -= first; - count = last - first + 1; + if (VM_OBJECT_WOWNED(object)) + VM_OBJECT_WUNLOCK(object); - /* - * calculate the file virtual address for the transfer - */ - foff = IDX_TO_OFF(m[0]->pindex); + /* Report back actual behind/ahead read. */ + if (a_rbehind) + *a_rbehind = bp->b_pgbefore; + if (a_rahead) + *a_rahead = bp->b_pgafter; - /* - * calculate the size of the transfer - */ - size = count * PAGE_SIZE; - KASSERT(count > 0, ("zero count")); - if ((foff + size) > object->un_pager.vnp.vnp_size) - size = object->un_pager.vnp.vnp_size - foff; - KASSERT(size > 0, ("zero size")); + KASSERT(bp->b_npages <= sizeof(bp->b_pages), + ("%s: buf %p overflowed", __func__, bp)); /* - * round up physical size for real devices. + * Recalculate first offset and bytecount with regards to read behind. + * Truncate bytecount to vnode real size and round up physical size + * for real devices. */ + foff = IDX_TO_OFF(bp->b_pages[0]->pindex); + bytecount = bp->b_npages << PAGE_SHIFT; + if ((foff + bytecount) > object->un_pager.vnp.vnp_size) + bytecount = object->un_pager.vnp.vnp_size - foff; secmask = bo->bo_bsize - 1; KASSERT(secmask < PAGE_SIZE && secmask > 0, - ("vnode_pager_generic_getpages: sector size %d too large", - secmask + 1)); - size = (size + secmask) & ~secmask; + ("%s: sector size %d too large", __func__, secmask + 1)); + bytecount = (bytecount + secmask) & ~secmask; /* - * and map the pages to be read into the kva, if the filesystem + * And map the pages to be read into the kva, if the filesystem * requires mapped buffers. */ if ((vp->v_mount->mnt_kern_flag & MNTK_UNMAPPED_BUFS) != 0 && @@ -932,41 +967,32 @@ vnode_pager_generic_getpages(struct vnode *vp, vm_page_t *m, int bytecount, bp->b_offset = 0; } else { bp->b_data = bp->b_kvabase; - pmap_qenter((vm_offset_t)bp->b_data, m, count); + pmap_qenter((vm_offset_t)bp->b_data, bp->b_pages, bp->b_npages); } - /* build a minimal buffer header */ + /* Build a minimal buffer header. */ bp->b_iocmd = BIO_READ; KASSERT(bp->b_rcred == NOCRED, ("leaking read ucred")); KASSERT(bp->b_wcred == NOCRED, ("leaking write ucred")); bp->b_rcred = crhold(curthread->td_ucred); bp->b_wcred = crhold(curthread->td_ucred); - bp->b_blkno = firstaddr; pbgetbo(bo, bp); bp->b_vp = vp; - bp->b_bcount = size; - bp->b_bufsize = size; - bp->b_runningbufspace = bp->b_bufsize; - for (i = 0; i < count; i++) - bp->b_pages[i] = m[i]; - bp->b_npages = count; - bp->b_pager.pg_reqpage = reqpage; - atomic_add_long(&runningbufspace, bp->b_runningbufspace); + bp->b_bcount = bp->b_bufsize = bp->b_runningbufspace = bytecount; + bp->b_iooffset = dbtob(bp->b_blkno); + atomic_add_long(&runningbufspace, bp->b_runningbufspace); PCPU_INC(cnt.v_vnodein); - PCPU_ADD(cnt.v_vnodepgsin, count); - - /* do the input */ - bp->b_iooffset = dbtob(bp->b_blkno); + PCPU_ADD(cnt.v_vnodepgsin, bp->b_npages); if (iodone != NULL) { /* async */ - bp->b_pager.pg_iodone = iodone; + bp->b_pgiodone = iodone; bp->b_caller1 = arg; bp->b_iodone = vnode_pager_generic_getpages_done_async; bp->b_flags |= B_ASYNC; BUF_KERNPROC(bp); bstrategy(bp); - /* Good bye! */ + return (VM_PAGER_OK); } else { bp->b_iodone = bdone; bstrategy(bp); @@ -977,9 +1003,8 @@ vnode_pager_generic_getpages(struct vnode *vp, vm_page_t *m, int bytecount, bp->b_vp = NULL; pbrelbo(bp); relpbuf(bp, &vnode_pbuf_freecnt); + return (error != 0 ? VM_PAGER_ERROR : VM_PAGER_OK); } - - return (error != 0 ? VM_PAGER_ERROR : VM_PAGER_OK); } static void @@ -988,8 +1013,9 @@ vnode_pager_generic_getpages_done_async(struct buf *bp) int error; error = vnode_pager_generic_getpages_done(bp); - bp->b_pager.pg_iodone(bp->b_caller1, bp->b_pages, - bp->b_pager.pg_reqpage, error); + /* Run the iodone upon the requested range. */ + bp->b_pgiodone(bp->b_caller1, bp->b_pages + bp->b_pgbefore, + bp->b_npages - bp->b_pgbefore - bp->b_pgafter, error); for (int i = 0; i < bp->b_npages; i++) bp->b_pages[i] = NULL; bp->b_vp = NULL; @@ -1052,8 +1078,8 @@ vnode_pager_generic_getpages_done(struct buf *bp) object->un_pager.vnp.vnp_size - tfoff)) == 0, ("%s: page %p is dirty", __func__, mt)); } - - if (i != bp->b_pager.pg_reqpage) + + if (i < bp->b_pgbefore || i >= bp->b_npages - bp->b_pgafter) vm_page_readahead_finish(mt); } VM_OBJECT_WUNLOCK(object); diff --git a/sys/vm/vnode_pager.h b/sys/vm/vnode_pager.h index 1ff16eb..a94b09b 100644 --- a/sys/vm/vnode_pager.h +++ b/sys/vm/vnode_pager.h @@ -41,7 +41,8 @@ #ifdef _KERNEL int vnode_pager_generic_getpages(struct vnode *vp, vm_page_t *m, - int count, int reqpage, vop_getpages_iodone_t iodone, void *arg); + int count, int *rbehind, int *rahead, vop_getpages_iodone_t iodone, + void *arg); int vnode_pager_generic_putpages(struct vnode *vp, vm_page_t *m, int count, boolean_t sync, int *rtvals); diff --git a/tests/freebsd_test_suite/macros.h b/tests/freebsd_test_suite/macros.h index 8d95f05..98da0ed 100644 --- a/tests/freebsd_test_suite/macros.h +++ b/tests/freebsd_test_suite/macros.h @@ -38,6 +38,13 @@ #include <atf-c.h> +#define ATF_REQUIRE_FEATURE(_feature_name) do { \ + if (feature_present(_feature_name) == 0) { \ + atf_tc_skip("kernel feature (%s) not present", \ + _feature_name); \ + } \ +} while(0) + #define ATF_REQUIRE_KERNEL_MODULE(_mod_name) do { \ if (modfind(_mod_name) == -1) { \ atf_tc_skip("module %s could not be resolved: %s", \ @@ -45,6 +52,14 @@ } \ } while(0) +#define PLAIN_REQUIRE_FEATURE(_feature_name, _exit_code) do { \ + if (feature_present(_feature_name) == 0) { \ + printf("kernel feature (%s) not present\n", \ + _feature_name); \ + _exit(_exit_code); \ + } \ +} while(0) + #define PLAIN_REQUIRE_KERNEL_MODULE(_mod_name, _exit_code) do { \ if (modfind(_mod_name) == -1) { \ printf("module %s could not be resolved: %s\n", \ diff --git a/tools/build/mk/OptionalObsoleteFiles.inc b/tools/build/mk/OptionalObsoleteFiles.inc index 0e9c955..779f596 100644 --- a/tools/build/mk/OptionalObsoleteFiles.inc +++ b/tools/build/mk/OptionalObsoleteFiles.inc @@ -4254,6 +4254,11 @@ OLD_DIRS+=usr/include/c++/v1 # to be filled in #.endif +.if ${MK_LLDB} == no +OLD_FILES+=usr/bin/lldb +OLD_FILES+=usr/share/man/man1/lldb.1.gz +.endif + .if ${MK_LOCALES} == no OLD_FILES+=usr/share/locale/af_ZA.ISO8859-1/LC_COLLATE OLD_FILES+=usr/share/locale/af_ZA.ISO8859-1/LC_CTYPE diff --git a/tools/regression/lib/libc/nss/Makefile b/tools/regression/lib/libc/nss/Makefile deleted file mode 100644 index 8c8a514..0000000 --- a/tools/regression/lib/libc/nss/Makefile +++ /dev/null @@ -1,12 +0,0 @@ -# $FreeBSD$ - -TESTS= test-getaddr test-getgr test-gethostby test-getpw test-getproto\ - test-getrpc test-getserv test-getusershell -CFLAGS+= -g -Wall - -.PHONY: tests -tests: ${TESTS} - -.PHONY: clean -clean: - -rm -f ${TESTS} diff --git a/tools/regression/lib/libc/nss/README b/tools/regression/lib/libc/nss/README deleted file mode 100644 index bf32913..0000000 --- a/tools/regression/lib/libc/nss/README +++ /dev/null @@ -1,203 +0,0 @@ -$FreeBSD$ - -A brief how-to --------------- - -Each nsswitch regression test does 2 kinds of actions: -1. It runs a series of queries and tests the correctness of results. - There are 2 basic criteria which are used for that: - - numbers must be in the correct range - - certain pointers should not be NULL - -2. It makes a snapshot of the results of all queries that were made. - The idea of snapshots is to test that nsswitch-related function - calls behave equally (i.e. return same results for the same queries) - between system upgrades. When the test is executed and the snapshot is - already created, the test will compare the result of each query with - the appropriate result from the snapshot and will signal if they - differ. - -In order for nsswitch tests to be as useful as possible you should use -them in the following way: - -Step 1 (before upgrading your system). -Build the tests with "make" command and execute them with "prove -v" -command. If there are errors during the execution, then appropriate -nsswitch functions should be checked. Note, that errors on this state -can happen only if the particular function return incorrect data. - -After the stage 1 a number of "snapshot_[test name]" files will appear -in your test folder. - -Step 2 (after upgrading you system). -Rebuild the tests with "make clean; make" command and execute them -again with "prove -v" (check that "snapshot_[test name]" files -are in the same folder with tests). On this stage regression tests -will catch not only the correctness errors, but will also determine -the changes in nsswitch functions behaviour. - -In case of the test failure you will get the following message: - -To get more details about the error you should do the following: -Step 1. Run the test alone with debug output enabled. -Step 2. Mail the snapshot file and the debug test output to the -freebsd-current@ mailing list. - -Example testing session for getpwXXX() family of functions ----------------------------------------------------------- -1. make - -2. prove -v ./test-getpw.t - - test-getpw....1..8 - ok 1 - getpwnam() - ok 2 - getpwuid() - ok 3 - getpwent() - ok 4 - getpwent() 2-pass - ok 5 - building snapshot, if needed - ok 6 - getpwnam() snapshot - ok 7 - getpwuid() snapshot - ok 8 - getpwent() snapshot - ok - All tests successful. - Files=1, Tests=8, 1 wallclock secs ( 0.00 cusr + 0.20 csys = 0.20 CPU) - - -3. Upgrading the system. - -4. make clean; make - -5. prove -v ./test-getpw.t (suppose that something has gone wrong) - - test-getpw....1..8 - ok 1 - getpwnam() - ok 2 - getpwuid() - ok 3 - getpwent() - ok 4 - getpwent() 2-pass - ok 5 - building snapshot, if needed - not ok 6 - getpwnam() snapshot - ok 7 - getpwuid() snapshot - not ok 8 - getpwent() snapshot - FAILED tests 6, 8 - Failed 2/8 tests, 75.00% okay - Failed 1/1 test scripts, 0.00% okay. 2/8 subtests failed, 75.00% okay. - -6. We see that test number 6 failed. According to get-getpw.t, this test - is executed like this: - do_test 6 'getpwnam() snapshot' '-n -s snapshot_pwd' - - To determine why the test has failed, we need to run it in debug mode - - it means adding "-d" to the options list. - -7. ./test-getpw -dn -s snapshot_pwd - ... - testing getpwnam() with the following data: - toor:*:0:0:0::ne-again Superuser:/root::0:4831 - testing correctness with the following data: - toor:*:0:0:0::Bourne-again Superuser:/root::0:4831 - correct - not ok - -8. Here we can see that the data from snapshot (first "toor" line) and - the data received from the getpwnam() call (second "toor" line) are - different. It is the reason why the test has failed. If you can't - (or don't want) to investigate the problem by yourself, mail - the test debug output and the snapshot file to the developers list. - -Notes on using standalone nsswitch tests ----------------------------------------- - -All nsswitch tests have [-d] optional command line argument which enables -debug output. The debug output can be extremely helpful to determine the -cause of test failure. - -In all nsswitch tests -s <file> command line argument specifies the -snapshot file. If this file doesn't exist, it would be built during -test execution. If it already exists then it will be used to check -the results of particular function calls. This argument is mostly -optional, but some tests (test-getaddr and test-getusershell) force -it to be specified. - -test-gethostby and test-getaddr require the list of hostnames, that should -be queried during the test. This list must be specified via -f <file> -command line argument. Each hostname should occupy exactly one line -in the file. - -Detailed tests description --------------------------- - -./test-getaddr - tests the getaddrinfo() function. - Usage: test-getaddr [-d] [-46] [-s <file>] -f <file> - -d - enable debug output - -4 - force IPv4 usage - -6 - force IPv6 usage - -s - build/use specified snapshot file - -f - use specified hostnames list for testing - -./test-getgr - Usage: test-getgr -nge2 [-d] [-s <file>] - -d - enable debug output - -n - test getgrnam(3) - -g - test getgrgid(3) - -e - test getgrent(3) - -2 - test getgrent(3) in 2-pass mode - -s - build/use specified snapshot file - -./test-gethostby - Usage: test-gethostby -na2i [-o] [-d] [-m46] [-s <file>] -f <file> - -n - test gethostbyname2(3) - -a - test gethostbyaddr(3) - -2 - test gethostbyname2(3) results to be equal with getaddrinfo(3) - results for the similar query - -i - test gethostbyaddr(3) results to be equal with getnameinfo(3) - results for the similar query - -o - use getipnodebyname(3)/getipnodebyaddr(3) for testing instead of - gethostbyname2(3)/gethostbyaddr(3) - -d - enable debug output - -m - force IPv4-to-IPv6 mapping - -4 - force IPv4 usage - -6 - force IPv6 usage - -s - build/use specified snapshot file - -f - use specified hostnames list for testing - -./test-getproto - Usage: test-getproto -nve2 [-d] [-s <file>] - -d - enable debug output - -n - test getprotobyname(3) - -v - test getprotobynumber(3) - -e - test getprotoent(3) - -2 - test getprotoent(3) in 2-pass mode - -s - build/use specified snapshot file - -./test-getpw - Usage: test-getpw -nue2 [-d] [-s <file>] - -d - enable debug output - -n - test getpwnam(3) - -u - test getpwuid(3) - -e - test getpwent(3) - -2 - test getpwent(3) in 2-pass mode - -s - build/use snapshot file - -./test-getrpc - Usage: test-getrpc -nve2 [-d] [-s <file>] - -d - enable debug output - -n - test getrpcbyname(3) - -v - test getrpcbynumber(3) - -e - test getrpcent(3) - -2 - test getrpcent(3) in 2-pass mode - -s - build/use specified snapshot file - -./test-getserv - Usage: test-getserv -npe2 [-d] [-s <file>] - -d - enable debug output - -n - test getservbyname(3) - -p - test getservbyport(3) - -e - test getservent(3) - -2 - test getservent(3) in 2-pass mode - -s - build/use specified snapshot file - -./test-getusershell - Usage: test-getusershell [-d] -s <file> - -d - enable debug output - -s - build/use specified snapshot file - diff --git a/tools/regression/lib/libc/nss/mach b/tools/regression/lib/libc/nss/mach deleted file mode 100644 index ab7ce24..0000000 --- a/tools/regression/lib/libc/nss/mach +++ /dev/null @@ -1,93 +0,0 @@ -# $FreeBSD$ -localhost -above.warped.net -anoncvs.cirr.com -anoncvs.isc.netbsd.org -anoncvs.leo.org -anoncvs.netbsd.lt -anoncvs.netbsd.ro -anoncvs.netbsd.se -antioche.antioche.eu.org -boulder.tele.dk -centaurus.4web.cz -chur.math.ntnu.no -console.netbsd.org -cvs.fi.netbsd.org -cvs.mikrolahti.fi -cvs.netbsd.org -cvsup-netbsd.leo.org -cvsup.netbsd.se -cvsup.pasta.cs.uit.no -ftp.bitcon.no -ftp.chg.ru -ftp.duth.gr -ftp.estpak.ee -ftp.fsn.hu -ftp.funet.fi -ftp.grondar.za -ftp.leo.org -ftp.netbsd.lt -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 -grappa.unix-ag.uni-kl.de -info.wins.uva.nl -irc.warped.net -knug.youn.co.kr -lala.iri.co.jp -mail.jp.netbsd.org -mail.kr.netbsd.org -mail.netbsd.org -melanoma.cs.rmit.edu.au -mirror.aarnet.edu.au -mirror.netbsd.com.br -mirror03.inet.tele.dk -moon.vub.ac.be -nbwww.sergei.cc -net.bsd.cz -netbsd.3miasto.net -netbsd.4ka.mipt.ru -netbsd.apk.od.ua -netbsd.csie.nctu.edu.tw -netbsd.enderunix.org -netbsd.ftp.fu-berlin.de -netbsd.netlead.com.au -netbsd.nsysu.edu.tw -netbsd.pair.com -netbsd.stevens-tech.edu -netbsd.triada.bg -netbsd.unix.net.nz -netbsd.unixtech.be -netbsd.vejas.lt -netbsd.wagener-consulting.lu -netbsd.zarco.org -netbsdiso.interoute.net.uk -netbsdwww.bitcon.no -netbsdwww.cordef.com.pl -netbsdwww.cs.rmit.edu.au -netbsdwww.interoute.net.uk -news.gw.com -ns.netbsd.org -pigu.iri.co.jp -pluto.cdpa.nsysu.edu.tw -projects.slowass.net -server6.pasta.cs.uit.no -skeleton.phys.spbu.ru -snoopy.allbsd.org -spike.allbsd.org -sundry.netbsd.org -tanya.sergei.cc -web-a.fi.gw.com -web-a.us.gw.com -web.netbsd.mirror.arhea.net -www.en.netbsd.de -www.netbsd.cl -www.netbsd.nl -www.netbsd.org -www.netbsd.ro -zathras.netbsd.org -zeppo.rediris.es diff --git a/tools/regression/lib/libc/nss/test-getaddr.t b/tools/regression/lib/libc/nss/test-getaddr.t deleted file mode 100644 index b3020f0..0000000 --- a/tools/regression/lib/libc/nss/test-getaddr.t +++ /dev/null @@ -1,33 +0,0 @@ -#!/bin/sh -# $FreeBSD$ - -do_test() { - number=$1 - comment=$2 - opt=$3 - if ./$executable $opt; then - echo "ok $number - $comment" - else - echo "not ok $number - $comment" - fi -} - -cd `dirname $0` - -executable=`basename $0 .t` - -make $executable 2>&1 > /dev/null - -echo 1..6 -#Tests with hints.ai_family is set to PF_UNSPEC -do_test 1 'getaddrinfo() (PF_UNSPEC)' '-f mach' -do_test 2 'getaddrinfo() snapshot (PF_UNSPEC)' '-f mach -s snapshot_ai' - -#Tests with hints.ai_family is set to PF_INET -do_test 3 'getaddrinfo() (PF_INET)' '-f mach' -do_test 4 'getaddrinfo() snapshot (PF_INET)' '-4 -f mach -s snapshot_ai4' - -#Tests with hints.ai_family is set to PF_INET6 -do_test 5 'getaddrinfo() (PF_INET6)' '-f mach' -do_test 6 'getaddrinfo() snapshot (PF_INET6)' '-6 -f mach -s snapshot_ai6' - diff --git a/tools/regression/lib/libc/nss/test-getgr.t b/tools/regression/lib/libc/nss/test-getgr.t deleted file mode 100644 index e2cf8e5..0000000 --- a/tools/regression/lib/libc/nss/test-getgr.t +++ /dev/null @@ -1,29 +0,0 @@ -#!/bin/sh -# $FreeBSD$ - -do_test() { - number=$1 - comment=$2 - opt=$3 - if ./$executable $opt; then - echo "ok $number - $comment" - else - echo "not ok $number - $comment" - fi -} - -cd `dirname $0` - -executable=`basename $0 .t` - -make $executable 2>&1 > /dev/null - -echo 1..8 -do_test 1 'getgrnam()' '-n' -do_test 2 'getgrgid()' '-g' -do_test 3 'getgrent()' '-e' -do_test 4 'getgrent() 2-pass' '-2' -do_test 5 'building snapshot, if needed' '-s snapshot_grp' -do_test 6 'getgrnam() snapshot' '-n -s snapshot_grp' -do_test 7 'getgrgid() snapshot' '-g -s snapshot_grp' -do_test 8 'getgrent() snapshot' '-e -s snapshot_grp' diff --git a/tools/regression/lib/libc/nss/test-gethostby.c b/tools/regression/lib/libc/nss/test-gethostby.c deleted file mode 100644 index 9e7bdf5..0000000 --- a/tools/regression/lib/libc/nss/test-gethostby.c +++ /dev/null @@ -1,1105 +0,0 @@ -/*- - * Copyright (c) 2006 Michael Bushkov <bushman@freebsd.org> - * 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 <sys/cdefs.h> -__FBSDID("$FreeBSD$"); - -#include <arpa/inet.h> -#include <sys/socket.h> -#include <sys/types.h> -#include <netinet/in.h> -#include <assert.h> -#include <errno.h> -#include <netdb.h> -#include <resolv.h> -#include <stdio.h> -#include <stdlib.h> -#include <string.h> -#include <stringlist.h> -#include <unistd.h> -#include "testutil.h" - -#ifndef min -#define min(a,b) (((a)<(b))?(a):(b)) -#endif - -enum test_methods { - TEST_GETHOSTBYNAME2, - TEST_GETHOSTBYADDR, - TEST_GETHOSTBYNAME2_GETADDRINFO, - TEST_GETHOSTBYADDR_GETNAMEINFO, - TEST_BUILD_SNAPSHOT, - TEST_BUILD_ADDR_SNAPSHOT -}; - -static int use_ipnode_functions = 0; -static int use_ipv6_mapping = 0; -static int ipnode_flags = 0; -static int debug = 0; -static int af_type = AF_INET; -static enum test_methods method = TEST_BUILD_SNAPSHOT; - -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 == 0) - he = gethostbyname2(name, af); - else { - error = 0; - he = getipnodebyname(name, af, ipnode_flags, &error); - if (he == NULL) - errno = error; - } - - return (he); -} - -static struct hostent * -__gethostbyaddr(const void *addr, socklen_t len, int af) -{ - struct hostent *he; - int error; - - if (use_ipnode_functions == 0) - he = gethostbyaddr(addr, len, af); - else { - error = 0; - he = getipnodebyaddr(addr, len, af, &error); - if (he == NULL) - errno = error; - } - - return (he); -} - -static void -__freehostent(struct hostent *he) -{ - /* NOTE: checking for he != NULL - just in case */ - if ((use_ipnode_functions != 0) && (he != NULL)) - freehostent(he); -} - -static void -clone_hostent(struct hostent *dest, struct hostent const *src) -{ - assert(dest != NULL); - assert(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); - assert(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 = (char **)malloc((aliases_num + 1) * - (sizeof(char *))); - assert(dest->h_aliases != NULL); - memset(dest->h_aliases, 0, (aliases_num + 1) * - (sizeof(char *))); - - for (cp = src->h_aliases; *cp; ++cp) { - dest->h_aliases[cp - src->h_aliases] = strdup(*cp); - assert(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 = (char **)malloc((addrs_num + 1) * - (sizeof(char *))); - assert(dest->h_addr_list != NULL); - memset(dest->h_addr_list, 0, (addrs_num + 1) * - (sizeof(char *))); - - for (cp = src->h_addr_list; *cp; ++cp) { - offset = cp - src->h_addr_list; - dest->h_addr_list[offset] = - (char *)malloc(src->h_length); - assert(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; - - assert(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) { - if (debug) - 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) { - if (debug) - 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) { - if (debug) - 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) { - if (debug) - printf("h2 addresses item can't be "\ - "found in h1 addresses\n"); - goto errfin; - } - } - } - - return 0; - -errfin: - if ((debug) && (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; - - if (debug) - printf("checking equality of he and ai\n"); - - rv = check_addrinfo_for_name(ai, he->h_name); - if (rv != 0) { - if (debug) - 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) { - if (debug) - printf("not equal - one of he->h_addr_list couldn't be found\n"); - - return (rv); - } - } - - if (debug) - printf("equal\n"); - - 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; - - if (debug) - printf("resolving %s: ", line); - result = __gethostbyname2(line, af_type); - if (result != NULL) { - if (debug) - printf("found\n"); - - rv = hostent_test_correctness(result, NULL); - if (rv != 0) { - __freehostent(result); - return (rv); - } - - clone_hostent(he, result); - __freehostent(result); - } else { - if (debug) - printf("not found\n"); - - memset(he, 0, sizeof(struct hostent)); - he->h_name = strdup(line); - assert(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; - - if (debug) - printf("1 line read from snapshot:\n%s\n", line); - - 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); - assert(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(); - assert(sl1 != NULL); - - if (strcmp(s, "noaliases") != 0) { - ts = strdup(s); - assert(ts != NULL); - sl_add(sl1, ts); - } - } else { - if (strcmp(s, ":") == 0) - ++i; - else { - ts = strdup(s); - assert(ts != NULL); - sl_add(sl1, ts); - } - } - break; - - case 4: - if (sl2 == NULL) { - if (strcmp(s, "(null)") == 0) - return (0); - - sl2 = sl_init(); - assert(sl2 != NULL); - - if (strcmp(s, "noaddrs") != 0) { - ts = (char *)malloc(ht->h_length); - assert(ts != NULL); - memset(ts, 0, ht->h_length); - rv = hostent_read_snapshot_addr(s,\ - (unsigned char *)ts, ht->h_length); - sl_add(sl2, ts); - if (rv != 0) - goto fin; - } - } else { - ts = (char *)malloc(ht->h_length); - assert(ts != NULL); - memset(ts, 0, ht->h_length); - 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) -{ - if (debug) { - printf("testing correctness with the following data:\n"); - dump_hostent(ht); - } - - 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; - - if (debug) - printf("correct\n"); - - return (0); -errfin: - if (debug) - 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) { - if (debug) - printf("doing reverse lookup for %s\n", he->h_name); - - result = __gethostbyaddr(*cp, he->h_length, - he->h_addrtype); - if (result == NULL) { - if (debug) - printf("warning: reverse lookup failed\n"); - - 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; - - if (debug) - 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) { - if (debug) - printf("not ok - shouldn't have been resolved\n"); - return (-1); - } - } else { - rv = getaddrinfo(he->h_name, NULL, &hints, &ai); - if (rv != 0) { - if (debug) - printf("not ok - should have beed resolved\n"); - return (-1); - } - - rv = is_hostent_equal(he, ai); - if (rv != 0) { - if (debug) - 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 buffer[NI_MAXHOST]; - struct sockaddr_in sin; - struct sockaddr_in6 sin6; - struct sockaddr *saddr; - struct hostent *result; - int rv; - - if (he->h_addr_list != NULL) { - char **cp; - for (cp = he->h_addr_list; *cp; ++cp) { - if (debug) - printf("doing reverse lookup for %s\n", he->h_name); - - 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 { - if (debug) - printf("reverse lookup failed\n"); - } - - 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: - if (debug) - printf("warning: %d family is unsupported\n", - he->h_addrtype); - continue; - } - - assert(saddr != NULL); - rv = getnameinfo(saddr, saddr->sa_len, buffer, - sizeof(buffer), NULL, 0, NI_NAMEREQD); - - if ((rv != 0) && (result != NULL)) { - if (debug) - printf("not ok - getnameinfo() didn't make the reverse lookup, when it should have (%s)\n", - gai_strerror(rv)); - return (rv); - } - - if ((rv == 0) && (result == NULL)) { - if (debug) - printf("not ok - getnameinfo() made the reverse lookup, when it shouldn't have\n"); - return (rv); - } - - if ((rv != 0) && (result == NULL)) { - if (debug) - printf("ok - both getnameinfo() and ***byaddr() failed\n"); - - continue; - } - - if (debug) - printf("comparing %s with %s\n", result->h_name, - buffer); - - rv = strcmp(result->h_name, buffer); - __freehostent(result); - - if (rv != 0) { - if (debug) - printf("not ok - getnameinfo() and ***byaddr() results are not equal\n"); - return (rv); - } else { - if (debug) - printf("ok - getnameinfo() and ***byaddr() results are equal\n"); - } - } - } - - return (0); -} - -static void -usage(void) -{ - (void)fprintf(stderr, - "Usage: %s -na2i [-o] [-d] [-46] [-mAcM] [-C] [-s <file>] -f <file>\n", - getprogname()); - exit(1); -} - -int -main(int argc, char **argv) -{ - struct hostent_test_data td, td_addr, td_snap; - char *snapshot_file, *hostlist_file; - res_state statp; - int rv; - int c; - - if (argc < 2) - usage(); - - snapshot_file = NULL; - hostlist_file = NULL; - while ((c = getopt(argc, argv, "nad2iod46mAcMs:f:")) != -1) - switch (c) { - case '4': - af_type = AF_INET; - break; - case '6': - af_type = AF_INET6; - break; - case 'M': - af_type = AF_INET6; - use_ipv6_mapping = 1; - ipnode_flags |= AI_V4MAPPED_CFG; - break; - case 'm': - af_type = AF_INET6; - use_ipv6_mapping = 1; - ipnode_flags |= AI_V4MAPPED; - break; - case 'c': - ipnode_flags |= AI_ADDRCONFIG; - break; - case 'A': - ipnode_flags |= AI_ALL; - break; - case 'o': - use_ipnode_functions = 1; - break; - case 'd': - debug = 1; - break; - case 'n': - method = TEST_GETHOSTBYNAME2; - break; - case 'a': - method = TEST_GETHOSTBYADDR; - break; - case '2': - method = TEST_GETHOSTBYNAME2_GETADDRINFO; - break; - case 'i': - method = TEST_GETHOSTBYADDR_GETNAMEINFO; - break; - case 's': - snapshot_file = strdup(optarg); - break; - case 'f': - hostlist_file = strdup(optarg); - break; - default: - usage(); - } - - if (use_ipnode_functions == 0) { - statp = __res_state(); - if ((statp == NULL) || ((statp->options & RES_INIT) == 0 && - res_ninit(statp) == -1)) { - if (debug) - printf("error: can't init res_state\n"); - - free(snapshot_file); - free(hostlist_file); - return (-1); - } - - if (use_ipv6_mapping == 0) - 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 (hostlist_file == NULL) - usage(); - - if (access(hostlist_file, R_OK) != 0) { - if (debug) - printf("can't access the hostlist file %s\n", - hostlist_file); - - usage(); - } - - if (debug) - printf("building host lists from %s\n", hostlist_file); - - rv = TEST_SNAPSHOT_FILE_READ(hostent, hostlist_file, &td, - hostent_read_hostlist_func); - if (rv != 0) - 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 { - if (debug) - 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) { - if (debug) - 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 (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); - - 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); - free(hostlist_file); - free(snapshot_file); - - return (rv); -} - diff --git a/tools/regression/lib/libc/nss/test-gethostby.t b/tools/regression/lib/libc/nss/test-gethostby.t deleted file mode 100644 index 42bed00..0000000 --- a/tools/regression/lib/libc/nss/test-gethostby.t +++ /dev/null @@ -1,113 +0,0 @@ -#!/bin/sh -# $FreeBSD$ - -do_test() { - number=$1 - comment=$2 - opt=$3 - if ./$executable $opt; then - echo "ok $number - $comment" - else - echo "not ok $number - $comment" - fi -} - -cd `dirname $0` - -executable=`basename $0 .t` - -make $executable 2>&1 > /dev/null - -echo 1..46 -#Tests for gethostby***() functions -#IPv4-driven testing -do_test 1 'gethostbyname2() (IPv4)' '-4 -n -f mach' -do_test 2 'gethostbyaddr() (IPv4)' '-4 -a -f mach' -do_test 3 'gethostbyname2()-getaddrinfo() (IPv4)' '-4 -2 -f mach' -do_test 4 'gethostbyaddr()-getnameinfo() (IPv4)' '-4 -i -f mach' -do_test 5 'gethostbyname2() snapshot (IPv4)'\ - '-4 -n -s snapshot_htname4 -f mach' -do_test 6 'gethostbyaddr() snapshot (IPv4)'\ - '-4 -a -s snapshot_htaddr4 -f mach' - -#IPv6-driven testing -do_test 7 'gethostbyname2() (IPv6)' '-6 -n -f mach' -do_test 8 'gethostbyaddr() (IPv6)' '-6 -a -f mach' -do_test 9 'gethostbyname2()-getaddrinfo() (IPv6)' '-6 -2 -f mach' -do_test 10 'gethostbyaddr()-getnameinfo() (IPv6)' '-6 -i -f mach' -do_test 11 'gethostbyname2() snapshot (IPv6)'\ - '-6 -n -s snapshot_htname6 -f mach' -do_test 12 'gethostbyaddr() snapshot (IPv6)'\ - '-6 -a -s snapshot_htaddr6 -f mach' - -#Mapped IPv6-driven testing (getaddrinfo() equality test is useless here) -do_test 13 'gethostbyname2() (IPv6 mapped)' '-m -n -f mach' -do_test 14 'gethostbyaddr() (IPv6 mapped)' '-m -a -f mach' -do_test 15 'gethostbyname2() snapshot (IPv6 mapped)'\ - '-m -n -s snapshot_htname6map -f mach' -do_test 16 'gethostbyaddr() snapshot (IPv6 mapped)'\ - '-m -a -s snapshot_htaddr6map -f mach' - -#Tests for getipnodeby***() functions -#IPv4-driven testing, flags are 0 -do_test 17 'getipnodebyname() (IPv4)' '-o -4 -n -f mach' -do_test 18 'getipnodebyaddr() (IPv4)' '-o -4 -a -f mach' -do_test 19 'getipnodebyname()-getaddrinfo() (IPv4)' '-o -4 -2 -f mach' -do_test 20 'getipnodebyaddr()-getnameinfo() (IPv4)' '-o -4 -i -f mach' -do_test 21 'getipnodebyname() snapshot (IPv4)'\ - '-o -4 -n -s snapshot_ipnodename4 -f mach' -do_test 22 'getipnodebyname() snapshot (IPv4)'\ - '-o -4 -a -s snapshot_ipnodeaddr4 -f mach' - -#IPv6-driven testing, flags are 0 -do_test 23 'getipnodebyname() (IPv6)' '-o -6 -n -f mach' -do_test 24 'getipnodebyaddr() (IPv6)' '-o -6 -a -f mach' -do_test 25 'getipnodebyname()-getaddrinfo() (IPv6)' '-o -6 -2 -f mach' -do_test 26 'getipnodebyaddr()-getnameinfo() (IPv6)' '-o -6 -i -f mach' -do_test 27 'getipnodebyname() snapshot (IPv6)'\ - '-o -6 -n -s snapshot_ipnodename6 -f mach' -do_test 28 'getipnodebyaddr() snapshot (IPv6)'\ - '-o -6 -a -s snapshot_ipnodeaddr6 -f mach' - -#Mapped IPv6-driven testing, flags are AI_V4MAPPED -do_test 29 'getipnodebyname() (IPv6, AI_V4MAPPED)' '-o -m -n -f mach' -do_test 30 'getipnodebyaddr() (IPv6, AI_V4MAPPED)' '-o -m -a -f mach' -do_test 31 'getipnodebyname() snapshot (IPv6, AI_V4MAPPED)'\ - '-o -m -n -s snapshot_ipnodename6_AI_V4MAPPED -f mach' -do_test 32 'getipnodebyaddr() snapshot (IPv6, AI_V4MAPPED)'\ - '-o -m -a -s snapshot_ipnodeaddr6_AI_V4MAPPED -f mach' - -#Mapped IPv6-driven testing, flags are AI_V4MAPPED_CFG -do_test 33 'getipnodebyname() (IPv6, AI_V4MAPPED_CFG)' '-o -M -n -f mach' -do_test 34 'getipnodebyaddr() (IPv6, AI_V4MAPPED_CFG)' '-o -M -a -f mach' -do_test 35 'getipnodebyname() snapshot (IPv6, AI_V4MAPPED_CFG)'\ - '-o -M -n -s snapshot_ipnodename6_AI_V4MAPPED_CFG -f mach' -do_test 36 'getipnodebyaddr() snapshot (IPv6, AI_V4MAPPED_CFG)'\ - '-o -M -a -s snapshot_ipnodeaddr6_AI_V4MAPPED_CFG -f mach' - -#Mapped IPv6-driven testing, flags are AI_V4MAPPED_CFG | AI_ALL -do_test 37 'getipnodebyname() (IPv6, AI_V4MAPPED_CFG | AI_ALL)'\ - '-o -MA -n -f mach' -do_test 38 'getipnodebyaddr() (IPv6, AI_V4MAPPED_CFG | AI_ALL)'\ - '-o -MA -a -f mach' -do_test 39 'getipnodebyname() snapshot (IPv6, AI_V4MAPPED_CFG | AI_ALL)'\ - '-o -MA -n -s snapshot_ipnodename6_AI_V4MAPPED_CFG_AI_ALL -f mach' -do_test 40 'getipnodebyaddr() snapshot (IPv6, AI_V4MAPPED_CFG | AI_ALL)'\ - '-o -MA -a -s snapshot_ipnodeaddr6_AI_V4MAPPED_CFG_AI_ALL -f mach' - -#Mapped IPv6-driven testing, flags are AI_V4MAPPED_CFG | AI_ADDRCONFIG -do_test 41 'getipnodebyname() (IPv6, AI_V4MAPPED_CFG | AI_ADDRCONFIG)'\ - '-o -Mc -n -f mach' -do_test 42 'getipnodebyname() snapshot (IPv6, AI_V4MAPPED_CFG | AI_ADDRCONFIG)'\ - '-o -Mc -n -s snapshot_ipnodename6_AI_V4MAPPED_CFG_AI_ADDRCONFIG -f mach' - -#IPv4-driven testing, flags are AI_ADDRCONFIG -do_test 43 'getipnodebyname() (IPv4, AI_ADDRCONFIG)' '-o -4c -n -f mach' -do_test 44 'getipnodebyname() snapshot (IPv4, AI_ADDRCONFIG)'\ - '-o -4c -n -s snapshot_ipnodename4_AI_ADDRCONFIG -f mach' - -#IPv6-driven testing, flags are AI_ADDRCONFIG -do_test 45 'getipnodebyname() (IPv6, AI_ADDRCONFIG)' '-o -6c -n -f mach' -do_test 46 'getipnodebyname() snapshot (IPv6, AI_ADDRCONFIG)'\ - '-o -6c -n -s snapshot_ipnodename6_AI_ADDRCONFIG -f mach' - diff --git a/tools/regression/lib/libc/nss/test-getproto.t b/tools/regression/lib/libc/nss/test-getproto.t deleted file mode 100644 index f582d31..0000000 --- a/tools/regression/lib/libc/nss/test-getproto.t +++ /dev/null @@ -1,29 +0,0 @@ -#!/bin/sh -# $FreeBSD$ - -do_test() { - number=$1 - comment=$2 - opt=$3 - if ./$executable $opt; then - echo "ok $number - $comment" - else - echo "not ok $number - $comment" - fi -} - -cd `dirname $0` - -executable=`basename $0 .t` - -make $executable 2>&1 > /dev/null - -echo 1..8 -do_test 1 'getprotobyname()' '-n' -do_test 2 'getprotobynumber()' '-v' -do_test 3 'getprotoent()' '-e' -do_test 4 'getprotoent() 2-pass' '-2' -do_test 5 'building snapshot, if needed' '-s snapshot_proto' -do_test 6 'getprotobyname() snapshot' '-n -s snapshot_proto' -do_test 7 'getprotobynumber() snapshot' '-v -s snapshot_proto' -do_test 8 'getprotoent() snapshot' '-e -s snapshot_proto' diff --git a/tools/regression/lib/libc/nss/test-getpw.t b/tools/regression/lib/libc/nss/test-getpw.t deleted file mode 100644 index 5172177..0000000 --- a/tools/regression/lib/libc/nss/test-getpw.t +++ /dev/null @@ -1,29 +0,0 @@ -#!/bin/sh -# $FreeBSD$ - -do_test() { - number=$1 - comment=$2 - opt=$3 - if ./$executable $opt; then - echo "ok $number - $comment" - else - echo "not ok $number - $comment" - fi -} - -cd `dirname $0` - -executable=`basename $0 .t` - -make $executable 2>&1 > /dev/null - -echo 1..8 -do_test 1 'getpwnam()' '-n' -do_test 2 'getpwuid()' '-u' -do_test 3 'getpwent()' '-e' -do_test 4 'getpwent() 2-pass' '-2' -do_test 5 'building snapshot, if needed' '-s snapshot_pwd' -do_test 6 'getpwnam() snapshot' '-n -s snapshot_pwd' -do_test 7 'getpwuid() snapshot' '-u -s snapshot_pwd' -do_test 8 'getpwent() snapshot' '-e -s snapshot_pwd' diff --git a/tools/regression/lib/libc/nss/test-getrpc.t b/tools/regression/lib/libc/nss/test-getrpc.t deleted file mode 100644 index 831a086..0000000 --- a/tools/regression/lib/libc/nss/test-getrpc.t +++ /dev/null @@ -1,29 +0,0 @@ -#!/bin/sh -# $FreeBSD$ - -do_test() { - number=$1 - comment=$2 - opt=$3 - if ./$executable $opt; then - echo "ok $number - $comment" - else - echo "not ok $number - $comment" - fi -} - -cd `dirname $0` - -executable=`basename $0 .t` - -make $executable 2>&1 > /dev/null - -echo 1..8 -do_test 1 'getrpcbyname()' '-n' -do_test 2 'getrpcbynumber()' '-v' -do_test 3 'getrpcent()' '-e' -do_test 4 'getrpcent() 2-pass' '-2' -do_test 5 'building snapshot, if needed' '-s snapshot_rpc' -do_test 6 'getrpcbyname() snapshot' '-n -s snapshot_rpc' -do_test 7 'getrpcbynumber() snapshot' '-v -s snapshot_rpc' -do_test 8 'getrpcent() snapshot' '-e -s snapshot_rpc' diff --git a/tools/regression/lib/libc/nss/test-getserv.t b/tools/regression/lib/libc/nss/test-getserv.t deleted file mode 100644 index 60a6c50..0000000 --- a/tools/regression/lib/libc/nss/test-getserv.t +++ /dev/null @@ -1,29 +0,0 @@ -#!/bin/sh -# $FreeBSD$ - -do_test() { - number=$1 - comment=$2 - opt=$3 - if ./$executable $opt; then - echo "ok $number - $comment" - else - echo "not ok $number - $comment" - fi -} - -cd `dirname $0` - -executable=`basename $0 .t` - -make $executable 2>&1 > /dev/null - -echo 1..8 -do_test 1 'getservbyname()' '-n' -do_test 2 'getservbyport()' '-p' -do_test 3 'getservent()' '-e' -do_test 4 'getservent() 2-pass' '-2' -do_test 5 'building snapshot, if needed' '-s snapshot_serv' -do_test 6 'getservbyname() snapshot' '-n -s snapshot_serv' -do_test 7 'getservbyport() snapshot' '-p -s snapshot_serv' -do_test 8 'getservent() snapshot' '-e -s snapshot_serv' diff --git a/tools/regression/lib/libc/nss/test-getusershell.t b/tools/regression/lib/libc/nss/test-getusershell.t deleted file mode 100644 index 16a392a..0000000 --- a/tools/regression/lib/libc/nss/test-getusershell.t +++ /dev/null @@ -1,22 +0,0 @@ -#!/bin/sh -# $FreeBSD$ - -do_test() { - number=$1 - comment=$2 - opt=$3 - if ./$executable $opt; then - echo "ok $number - $comment" - else - echo "not ok $number - $comment" - fi -} - -cd `dirname $0` - -executable=`basename $0 .t` - -make $executable 2>&1 > /dev/null - -echo 1..1 -do_test 1 'getusershell() snapshot' '-s snapshot_usershell' diff --git a/tools/regression/lib/libc/resolv/Makefile b/tools/regression/lib/libc/resolv/Makefile deleted file mode 100644 index 18a71bc..0000000 --- a/tools/regression/lib/libc/resolv/Makefile +++ /dev/null @@ -1,14 +0,0 @@ -# $NetBSD: Makefile,v 1.1 2004/05/13 19:17:12 christos Exp $ -# $FreeBSD$ - -PROG= resolv -MAN= - -# Note: this test relies on being dynamically linked. You will get a -# spurious PASS for a statically linked test. -LIBADD+= pthread - -regress: ${PROG} - ./${PROG} -r ${.CURDIR}/mach - -.include <bsd.prog.mk> diff --git a/tools/regression/lib/libc/resolv/mach b/tools/regression/lib/libc/resolv/mach deleted file mode 100644 index ab7ce24..0000000 --- a/tools/regression/lib/libc/resolv/mach +++ /dev/null @@ -1,93 +0,0 @@ -# $FreeBSD$ -localhost -above.warped.net -anoncvs.cirr.com -anoncvs.isc.netbsd.org -anoncvs.leo.org -anoncvs.netbsd.lt -anoncvs.netbsd.ro -anoncvs.netbsd.se -antioche.antioche.eu.org -boulder.tele.dk -centaurus.4web.cz -chur.math.ntnu.no -console.netbsd.org -cvs.fi.netbsd.org -cvs.mikrolahti.fi -cvs.netbsd.org -cvsup-netbsd.leo.org -cvsup.netbsd.se -cvsup.pasta.cs.uit.no -ftp.bitcon.no -ftp.chg.ru -ftp.duth.gr -ftp.estpak.ee -ftp.fsn.hu -ftp.funet.fi -ftp.grondar.za -ftp.leo.org -ftp.netbsd.lt -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 -grappa.unix-ag.uni-kl.de -info.wins.uva.nl -irc.warped.net -knug.youn.co.kr -lala.iri.co.jp -mail.jp.netbsd.org -mail.kr.netbsd.org -mail.netbsd.org -melanoma.cs.rmit.edu.au -mirror.aarnet.edu.au -mirror.netbsd.com.br -mirror03.inet.tele.dk -moon.vub.ac.be -nbwww.sergei.cc -net.bsd.cz -netbsd.3miasto.net -netbsd.4ka.mipt.ru -netbsd.apk.od.ua -netbsd.csie.nctu.edu.tw -netbsd.enderunix.org -netbsd.ftp.fu-berlin.de -netbsd.netlead.com.au -netbsd.nsysu.edu.tw -netbsd.pair.com -netbsd.stevens-tech.edu -netbsd.triada.bg -netbsd.unix.net.nz -netbsd.unixtech.be -netbsd.vejas.lt -netbsd.wagener-consulting.lu -netbsd.zarco.org -netbsdiso.interoute.net.uk -netbsdwww.bitcon.no -netbsdwww.cordef.com.pl -netbsdwww.cs.rmit.edu.au -netbsdwww.interoute.net.uk -news.gw.com -ns.netbsd.org -pigu.iri.co.jp -pluto.cdpa.nsysu.edu.tw -projects.slowass.net -server6.pasta.cs.uit.no -skeleton.phys.spbu.ru -snoopy.allbsd.org -spike.allbsd.org -sundry.netbsd.org -tanya.sergei.cc -web-a.fi.gw.com -web-a.us.gw.com -web.netbsd.mirror.arhea.net -www.en.netbsd.de -www.netbsd.cl -www.netbsd.nl -www.netbsd.org -www.netbsd.ro -zathras.netbsd.org -zeppo.rediris.es diff --git a/tools/regression/lib/libc/resolv/resolv.t b/tools/regression/lib/libc/resolv/resolv.t deleted file mode 100644 index 278ba06..0000000 --- a/tools/regression/lib/libc/resolv/resolv.t +++ /dev/null @@ -1,24 +0,0 @@ -#!/bin/sh -# $FreeBSD$ - -do_test() { - number=$1 - comment=$2 - opt=$3 - if ./$executable $opt; then - echo "ok $number - $comment" - else - echo "not ok $number - $comment" - fi -} - -cd `dirname $0` - -executable=`basename $0 .t` - -make $executable 2>&1 > /dev/null - -echo 1..3 -do_test 1 'getaddrinfo()' '-r mach' -do_test 2 'gethostbyname()' '-rH mach' -do_test 3 'getipnodebyname()' '-rI mach' diff --git a/tools/regression/lib/msun/Makefile b/tools/regression/lib/msun/Makefile index dbf582f..8b301cb 100644 --- a/tools/regression/lib/msun/Makefile +++ b/tools/regression/lib/msun/Makefile @@ -1,10 +1,8 @@ # $FreeBSD$ -TESTS= test-cexp test-conj test-csqrt test-ctrig \ - test-exponential test-fenv test-fma \ - test-fmaxmin test-ilogb test-invtrig test-invctrig \ - test-logarithm test-lrint \ - test-lround test-nan test-nearbyint test-next test-rem test-trig +TESTS= test-ctrig \ + test-exponential test-fma \ + test-lround test-nearbyint test-next test-rem test-trig CFLAGS+= -O0 -lm -Wno-unknown-pragmas .PHONY: tests diff --git a/tools/regression/lib/msun/test-cexp.t b/tools/regression/lib/msun/test-cexp.t deleted file mode 100644 index 8bdfd03..0000000 --- a/tools/regression/lib/msun/test-cexp.t +++ /dev/null @@ -1,10 +0,0 @@ -#!/bin/sh -# $FreeBSD$ - -cd `dirname $0` - -executable=`basename $0 .t` - -make $executable 2>&1 > /dev/null - -exec ./$executable diff --git a/tools/regression/lib/msun/test-conj.t b/tools/regression/lib/msun/test-conj.t deleted file mode 100644 index 8bdfd03..0000000 --- a/tools/regression/lib/msun/test-conj.t +++ /dev/null @@ -1,10 +0,0 @@ -#!/bin/sh -# $FreeBSD$ - -cd `dirname $0` - -executable=`basename $0 .t` - -make $executable 2>&1 > /dev/null - -exec ./$executable diff --git a/tools/regression/lib/msun/test-csqrt.t b/tools/regression/lib/msun/test-csqrt.t deleted file mode 100644 index 8bdfd03..0000000 --- a/tools/regression/lib/msun/test-csqrt.t +++ /dev/null @@ -1,10 +0,0 @@ -#!/bin/sh -# $FreeBSD$ - -cd `dirname $0` - -executable=`basename $0 .t` - -make $executable 2>&1 > /dev/null - -exec ./$executable diff --git a/tools/regression/lib/msun/test-fenv.t b/tools/regression/lib/msun/test-fenv.t deleted file mode 100644 index 8bdfd03..0000000 --- a/tools/regression/lib/msun/test-fenv.t +++ /dev/null @@ -1,10 +0,0 @@ -#!/bin/sh -# $FreeBSD$ - -cd `dirname $0` - -executable=`basename $0 .t` - -make $executable 2>&1 > /dev/null - -exec ./$executable diff --git a/tools/regression/lib/msun/test-fmaxmin.t b/tools/regression/lib/msun/test-fmaxmin.t deleted file mode 100644 index 8bdfd03..0000000 --- a/tools/regression/lib/msun/test-fmaxmin.t +++ /dev/null @@ -1,10 +0,0 @@ -#!/bin/sh -# $FreeBSD$ - -cd `dirname $0` - -executable=`basename $0 .t` - -make $executable 2>&1 > /dev/null - -exec ./$executable diff --git a/tools/regression/lib/msun/test-ilogb.t b/tools/regression/lib/msun/test-ilogb.t deleted file mode 100644 index 8bdfd03..0000000 --- a/tools/regression/lib/msun/test-ilogb.t +++ /dev/null @@ -1,10 +0,0 @@ -#!/bin/sh -# $FreeBSD$ - -cd `dirname $0` - -executable=`basename $0 .t` - -make $executable 2>&1 > /dev/null - -exec ./$executable diff --git a/tools/regression/lib/msun/test-logarithm.t b/tools/regression/lib/msun/test-logarithm.t deleted file mode 100644 index 8bdfd03..0000000 --- a/tools/regression/lib/msun/test-logarithm.t +++ /dev/null @@ -1,10 +0,0 @@ -#!/bin/sh -# $FreeBSD$ - -cd `dirname $0` - -executable=`basename $0 .t` - -make $executable 2>&1 > /dev/null - -exec ./$executable diff --git a/tools/regression/lib/msun/test-lrint.t b/tools/regression/lib/msun/test-lrint.t deleted file mode 100644 index 8bdfd03..0000000 --- a/tools/regression/lib/msun/test-lrint.t +++ /dev/null @@ -1,10 +0,0 @@ -#!/bin/sh -# $FreeBSD$ - -cd `dirname $0` - -executable=`basename $0 .t` - -make $executable 2>&1 > /dev/null - -exec ./$executable diff --git a/tools/regression/lib/msun/test-nan.t b/tools/regression/lib/msun/test-nan.t deleted file mode 100644 index 8bdfd03..0000000 --- a/tools/regression/lib/msun/test-nan.t +++ /dev/null @@ -1,10 +0,0 @@ -#!/bin/sh -# $FreeBSD$ - -cd `dirname $0` - -executable=`basename $0 .t` - -make $executable 2>&1 > /dev/null - -exec ./$executable diff --git a/tools/regression/lib/msun/test-nearbyint.t b/tools/regression/lib/msun/test-nearbyint.t deleted file mode 100644 index 8bdfd03..0000000 --- a/tools/regression/lib/msun/test-nearbyint.t +++ /dev/null @@ -1,10 +0,0 @@ -#!/bin/sh -# $FreeBSD$ - -cd `dirname $0` - -executable=`basename $0 .t` - -make $executable 2>&1 > /dev/null - -exec ./$executable diff --git a/tools/regression/lib/msun/test-next.t b/tools/regression/lib/msun/test-next.t deleted file mode 100644 index 8bdfd03..0000000 --- a/tools/regression/lib/msun/test-next.t +++ /dev/null @@ -1,10 +0,0 @@ -#!/bin/sh -# $FreeBSD$ - -cd `dirname $0` - -executable=`basename $0 .t` - -make $executable 2>&1 > /dev/null - -exec ./$executable diff --git a/tools/regression/lib/msun/test-rem.t b/tools/regression/lib/msun/test-rem.t deleted file mode 100644 index 8bdfd03..0000000 --- a/tools/regression/lib/msun/test-rem.t +++ /dev/null @@ -1,10 +0,0 @@ -#!/bin/sh -# $FreeBSD$ - -cd `dirname $0` - -executable=`basename $0 .t` - -make $executable 2>&1 > /dev/null - -exec ./$executable diff --git a/tools/regression/lib/msun/test-trig.t b/tools/regression/lib/msun/test-trig.t deleted file mode 100644 index 8bdfd03..0000000 --- a/tools/regression/lib/msun/test-trig.t +++ /dev/null @@ -1,10 +0,0 @@ -#!/bin/sh -# $FreeBSD$ - -cd `dirname $0` - -executable=`basename $0 .t` - -make $executable 2>&1 > /dev/null - -exec ./$executable diff --git a/usr.bin/netstat/ipsec.c b/usr.bin/netstat/ipsec.c index f3309ff..1347a93 100644 --- a/usr.bin/netstat/ipsec.c +++ b/usr.bin/netstat/ipsec.c @@ -216,10 +216,17 @@ ipsec_stats(u_long off, const char *name, int af1 __unused, int proto __unused) { struct ipsecstat ipsecstat; - if (off == 0) - return; + if (strcmp(name, "ipsec6") == 0) { + if (fetch_stats("net.inet6.ipsec6.ipsecstats", off,&ipsecstat, + sizeof(ipsecstat), kread_counters) != 0) + return; + } else { + if (fetch_stats("net.inet.ipsec.ipsecstats", off, &ipsecstat, + sizeof(ipsecstat), kread_counters) != 0) + return; + } + xo_emit("{T:/%s}:\n", name); - kread_counters(off, (char *)&ipsecstat, sizeof(ipsecstat)); print_ipsecstats(&ipsecstat); } @@ -318,10 +325,11 @@ ah_stats(u_long off, const char *name, int family __unused, int proto __unused) { struct ahstat ahstat; - if (off == 0) + if (fetch_stats("net.inet.ah.stats", off, &ahstat, + sizeof(ahstat), kread_counters) != 0) return; + xo_emit("{T:/%s}:\n", name); - kread_counters(off, (char *)&ahstat, sizeof(ahstat)); print_ahstats(&ahstat); } @@ -377,10 +385,11 @@ esp_stats(u_long off, const char *name, int family __unused, int proto __unused) { struct espstat espstat; - if (off == 0) + if (fetch_stats("net.inet.esp.stats", off, &espstat, + sizeof(espstat), kread_counters) != 0) return; + xo_emit("{T:/%s}:\n", name); - kread_counters(off, (char *)&espstat, sizeof(espstat)); print_espstats(&espstat); } @@ -434,10 +443,11 @@ ipcomp_stats(u_long off, const char *name, int family __unused, { struct ipcompstat ipcompstat; - if (off == 0) + if (fetch_stats("net.inet.ipcomp.stats", off, &ipcompstat, + sizeof(ipcompstat), kread_counters) != 0) return; + xo_emit("{T:/%s}:\n", name); - kread_counters(off, (char *)&ipcompstat, sizeof(ipcompstat)); print_ipcompstats(&ipcompstat); } diff --git a/usr.bin/netstat/main.c b/usr.bin/netstat/main.c index ce9e81a..e8cf914 100644 --- a/usr.bin/netstat/main.c +++ b/usr.bin/netstat/main.c @@ -108,13 +108,13 @@ static struct protox { igmp_stats, NULL, "igmp", 1, IPPROTO_IGMP }, #ifdef IPSEC { -1, N_IPSEC4STAT, 1, NULL, /* keep as compat */ - ipsec_stats, NULL, "ipsec", 0, 0}, + ipsec_stats, NULL, "ipsec", 1, 0}, { -1, N_AHSTAT, 1, NULL, - ah_stats, NULL, "ah", 0, 0}, + ah_stats, NULL, "ah", 1, 0}, { -1, N_ESPSTAT, 1, NULL, - esp_stats, NULL, "esp", 0, 0}, + esp_stats, NULL, "esp", 1, 0}, { -1, N_IPCOMPSTAT, 1, NULL, - ipcomp_stats, NULL, "ipcomp", 0, 0}, + ipcomp_stats, NULL, "ipcomp", 1, 0}, #endif { N_RIPCBINFO, N_PIMSTAT, 1, protopr, pim_stats, NULL, "pim", 1, IPPROTO_PIM }, @@ -146,7 +146,7 @@ static struct protox ip6protox[] = { #endif #ifdef IPSEC { -1, N_IPSEC6STAT, 1, NULL, - ipsec_stats, NULL, "ipsec6", 0, 0 }, + ipsec_stats, NULL, "ipsec6", 1, 0 }, #endif #ifdef notyet { -1, N_PIM6STAT, 1, NULL, diff --git a/usr.sbin/Makefile.arm b/usr.sbin/Makefile.arm index b21bc52..590b8cd 100644 --- a/usr.sbin/Makefile.arm +++ b/usr.sbin/Makefile.arm @@ -1,4 +1,5 @@ # $FreeBSD$ -SUBDIR+= ofwdump SUBDIR+= kgmon +SUBDIR+= mount_smbfs +SUBDIR+= ofwdump diff --git a/usr.sbin/ndp/ndp.c b/usr.sbin/ndp/ndp.c index 85cb67c..8c498ec 100644 --- a/usr.sbin/ndp/ndp.c +++ b/usr.sbin/ndp/ndp.c @@ -563,8 +563,8 @@ dump(struct sockaddr_in6 *addr, int cflag) struct sockaddr_in6 *sin; struct sockaddr_dl *sdl; extern int h_errno; - struct in6_nbrinfo *nbi; struct timeval now; + u_long expire; int addrwidth; int llwidth; int ifwidth; @@ -676,52 +676,46 @@ again:; llwidth, llwidth, ether_str(sdl), ifwidth, ifwidth, ifname); /* Print neighbor discovery specific information */ - nbi = getnbrinfo(&sin->sin6_addr, sdl->sdl_index, 1); - if (nbi) { - if (nbi->expire > now.tv_sec) { - printf(" %-9.9s", - sec2str(nbi->expire - now.tv_sec)); - } else if (nbi->expire == 0) - printf(" %-9.9s", "permanent"); - else - printf(" %-9.9s", "expired"); + expire = rtm->rtm_rmx.rmx_expire; + if (expire > now.tv_sec) + printf(" %-9.9s", sec2str(expire - now.tv_sec)); + else if (expire == 0) + printf(" %-9.9s", "permanent"); + else + printf(" %-9.9s", "expired"); - switch (nbi->state) { - case ND6_LLINFO_NOSTATE: - printf(" N"); - break; + switch (rtm->rtm_rmx.rmx_state) { + case ND6_LLINFO_NOSTATE: + printf(" N"); + break; #ifdef ND6_LLINFO_WAITDELETE - case ND6_LLINFO_WAITDELETE: - printf(" W"); - break; + case ND6_LLINFO_WAITDELETE: + printf(" W"); + break; #endif - case ND6_LLINFO_INCOMPLETE: - printf(" I"); - break; - case ND6_LLINFO_REACHABLE: - printf(" R"); - break; - case ND6_LLINFO_STALE: - printf(" S"); - break; - case ND6_LLINFO_DELAY: - printf(" D"); - break; - case ND6_LLINFO_PROBE: - printf(" P"); - break; - default: - printf(" ?"); - break; - } - - isrouter = nbi->isrouter; - prbs = nbi->asked; - } else { - warnx("failed to get neighbor information"); - printf(" "); + case ND6_LLINFO_INCOMPLETE: + printf(" I"); + break; + case ND6_LLINFO_REACHABLE: + printf(" R"); + break; + case ND6_LLINFO_STALE: + printf(" S"); + break; + case ND6_LLINFO_DELAY: + printf(" D"); + break; + case ND6_LLINFO_PROBE: + printf(" P"); + break; + default: + printf(" ?"); + break; } + isrouter = rtm->rtm_flags & RTF_GATEWAY; + prbs = rtm->rtm_rmx.rmx_pksent; + /* * other flags. R: router, P: proxy, W: ?? */ |