From d8c4a69b5b124faa2b1152bf5dcd92a416b03462 Mon Sep 17 00:00:00 2001 From: Phil Shafer Date: Sat, 25 Jan 2020 21:09:12 +0000 Subject: [PATCH 01/27] Import libxo 1.4.0 --- configure.ac | 2 +- doc/api.rst | 59 +++++++++++++++++ doc/encoders.rst | 13 ++-- doc/options.rst | 20 ++++++ encoder/csv/enc_csv.c | 24 ++++--- libxo/libxo.c | 101 +++++++++++++++++++++++------- libxo/xo.h | 9 +++ libxo/xo_encoder.c | 21 ++++++- libxo/xo_encoder.h | 1 + tests/core/Makefile.am | 11 ++-- tests/core/saved/test_02.H.out | 3 + tests/core/saved/test_02.HIPx.out | 15 +++++ tests/core/saved/test_02.HP.out | 15 +++++ tests/core/saved/test_02.J.out | 2 +- tests/core/saved/test_02.JP.out | 12 ++++ tests/core/saved/test_02.T.err | 3 + tests/core/saved/test_02.X.out | 3 + tests/core/saved/test_02.XP.out | 15 +++++ tests/core/test_02.c | 6 ++ tests/core/test_12.c | 2 + 20 files changed, 293 insertions(+), 44 deletions(-) diff --git a/configure.ac b/configure.ac index 62d5a0383f79..e28db9396082 100644 --- a/configure.ac +++ b/configure.ac @@ -12,7 +12,7 @@ # AC_PREREQ(2.2) -AC_INIT([libxo], [1.3.1], [phil@juniper.net]) +AC_INIT([libxo], [1.4.0], [phil@juniper.net]) AM_INIT_AUTOMAKE([-Wall -Werror foreign -Wno-portability]) # Support silent build rules. Requires at least automake-1.11. diff --git a/doc/api.rst b/doc/api.rst index 4ca51306472a..94358489f075 100644 --- a/doc/api.rst +++ b/doc/api.rst @@ -1204,6 +1204,11 @@ message associated with either *errno* or the *code* parameter:: xo_err(1, "cannot open file '%s'", filename); .. index:: xo_error +.. index:: xo_error_h +.. index:: xo_error_hv +.. index:: xo_errorn +.. index:: xo_errorn_h +.. index:: xo_errorn_hv xo_error ~~~~~~~~ @@ -1214,6 +1219,50 @@ xo_error :type fmt: const char * :returns: void +.. c:function:: void xo_error_h (xo_handle_t *xop, const char *fmt, ...) + + :param xop: libxo handle pointer + :type xop: xo_handle_t * + :param fmt: Format string + :type fmt: const char * + :returns: void + +.. c:function:: void xo_error_hv (xo_handle_t *xop, const char *fmt, va_list vap) + + :param xop: libxo handle pointer + :type xop: xo_handle_t * + :param fmt: Format string + :type fmt: const char * + :param vap: variadic arguments + :type xop: va_list + :returns: void + +.. c:function:: void xo_errorn (const char *fmt, ...) + + :param fmt: Format string + :type fmt: const char * + :returns: void + +.. c:function:: void xo_errorn_h (xo_handle_t *xop, const char *fmt, ...) + + :param xop: libxo handle pointer + :type xop: xo_handle_t * + :param fmt: Format string + :type fmt: const char * + :returns: void + +.. c:function:: void xo_errorn_hv (xo_handle_t *xop, int need_newline, const char *fmt, va_list vap) + + :param xop: libxo handle pointer + :type xop: xo_handle_t * + :param need_newline: boolean indicating need for trailing newline + :type need_newline: int + :param fmt: Format string + :type fmt: const char * + :param vap: variadic arguments + :type xop: va_list + :returns: void + The `xo_error` function can be used for generic errors that should be reported over the handle, rather than to stderr. The `xo_error` function behaves like `xo_err` for TEXT and HTML output styles, but @@ -1226,6 +1275,16 @@ xo_error JSON:: "error": { "message": "Does not compute" } + The `xo_error_h` and `xo_error_hv` add a handle object and a + variadic-ized parameter to the signature, respectively. + + The `xo_errorn` function supplies a newline at the end the error + message if the format string does not include one. The + `xo_errorn_h` and `xo_errorn_hv` functions add a handle object and + a variadic-ized parameter to the signature, respectively. The + `xo_errorn_hv` function also adds a boolean to indicate the need for + a trailing newline. + .. index:: xo_no_setlocale .. index:: Locale diff --git a/doc/encoders.rst b/doc/encoders.rst index d06e0e9177c9..dfd0316bfb97 100644 --- a/doc/encoders.rst +++ b/doc/encoders.rst @@ -26,12 +26,13 @@ example uses the "cbor" encoder, saving the output into a file:: df --libxo encoder=cbor > df-output.cbor Encoders can support specific options that can be accessed by -following the encoder name with a colon (':') and one of more options, -separated by a plus sign "+":: +following the encoder name with a colon (':') or a plus sign ('+') and +one of more options, separated by the same character:: - df --libxo encoder=csv:path=filesystem+leaf=name+no-header + df --libxo encoder=csv+path=filesystem+leaf=name+no-header + df --libxo encoder=csv:path=filesystem:leaf=name:no-header -This example instructs libxo to load the "csv" encoder and pass the +These examples instructs libxo to load the "csv" encoder and pass the following options:: path=filesystem @@ -42,6 +43,10 @@ Each of these option is interpreted by the encoder, and all such options names and semantics are specific to the particular encoder. Refer to the intended encoder for documentation on its options. +The string "@" can be used in place of the string "encoder=". + + df --libxo @csv:no-header + .. _csv_encoder: CSV - Comma Separated Values diff --git a/doc/options.rst b/doc/options.rst index bd0fa565e281..79cd360a1f44 100644 --- a/doc/options.rst +++ b/doc/options.rst @@ -162,3 +162,23 @@ foreground and background output to "yellow", give only the fifth mapping, skipping the first four mappings with bare plus signs ("+"):: --libxo colors=++++yellow/yellow + +Encoders +-------- + +In addition to the four "built-in" formats, libxo supports an +extensible mechanism for adding encoders. These are activated +using the "encoder" keyword:: + + --libxo encoder=cbor + +The encoder can include encoder-specific options, separated by either +colons (":") or plus signs ("+"): + + --libxo encoder=csv+path=filesystem+leaf=name+no-header + --libxo encoder=csv:path=filesystem:leaf=name:no-header + +For brevity, the string "@" can be used in place of the string +"encoder=". + + df --libxo @csv:no-header diff --git a/encoder/csv/enc_csv.c b/encoder/csv/enc_csv.c index 88e93f37cc97..10f9110f4939 100644 --- a/encoder/csv/enc_csv.c +++ b/encoder/csv/enc_csv.c @@ -41,10 +41,12 @@ * (double) quote characters. * - Leading and trialing whitespace require fields be quoted. * - * Cheesy, but simple. The RFC also requires MS-DOS end-of-line, which - * we only do with the "dos" option. Strange that we still live in a - * DOS-friendly world, but then again, we make spaceships based on the - * horse butts (http://www.astrodigital.org/space/stshorse.html). + * Cheesy, but simple. The RFC also requires MS-DOS end-of-line, + * which we only do with the "dos" option. Strange that we still live + * in a DOS-friendly world, but then again, we make spaceships based + * on the horse butts (http://www.astrodigital.org/space/stshorse.html + * though the "built by English expatriates” bit is rubbish; better to + * say the first engines used in America were built by Englishmen.) */ #include @@ -655,10 +657,12 @@ csv_record_path (xo_handle_t *xop, csv_private_t *csv, const char *path_raw) /* * Extract the option values. The format is: - * -libxo encoder=csv:kw=val+kw=val+kw=val,pretty,etc + * -libxo encoder=csv:kw=val:kw=val:kw=val,pretty + * -libxo encoder=csv+kw=val+kw=val+kw=val,pretty */ static int -csv_options (xo_handle_t *xop, csv_private_t *csv, const char *raw_opts) +csv_options (xo_handle_t *xop, csv_private_t *csv, + const char *raw_opts, char opts_char) { ssize_t len = strlen(raw_opts); char *options = alloca(len + 1); @@ -667,7 +671,7 @@ csv_options (xo_handle_t *xop, csv_private_t *csv, const char *raw_opts) char *cp, *ep, *np, *vp; for (cp = options, ep = options + len + 1; cp && cp < ep; cp = np) { - np = strchr(cp, '+'); + np = strchr(cp, opts_char); if (np) *np++ = '\0'; @@ -761,7 +765,11 @@ csv_handler (XO_ENCODER_HANDLER_ARGS) break; case XO_OP_OPTIONS: - rc = csv_options(xop, csv, value); + rc = csv_options(xop, csv, value, ':'); + break; + + case XO_OP_OPTIONS_PLUS: + rc = csv_options(xop, csv, value, '+'); break; case XO_OP_OPEN_LIST: diff --git a/libxo/libxo.c b/libxo/libxo.c index 14268d1b250e..ea64feb82747 100644 --- a/libxo/libxo.c +++ b/libxo/libxo.c @@ -2371,6 +2371,25 @@ xo_set_options (xo_handle_t *xop, const char *input) if (np) *np++ = '\0'; + /* + * "@foo" is a shorthand for "encoder=foo". This is driven + * chiefly by a desire to make pluggable encoders not appear + * so distinct from built-in encoders. + */ + if (*cp == '@') { + vp = cp + 1; + + if (*vp == '\0') + xo_failure(xop, "missing value for encoder option"); + else { + rc = xo_encoder_init(xop, vp); + if (rc) + xo_warnx("error initializing encoder: %s", vp); + } + + continue; + } + vp = strchr(cp, '='); if (vp) *vp++ = '\0'; @@ -8007,7 +8026,7 @@ xo_finish_atexit (void) * Generate an error message, such as would be displayed on stderr */ void -xo_error_hv (xo_handle_t *xop, const char *fmt, va_list vap) +xo_errorn_hv (xo_handle_t *xop, int need_newline, const char *fmt, va_list vap) { xop = xo_default(xop); @@ -8015,13 +8034,15 @@ xo_error_hv (xo_handle_t *xop, const char *fmt, va_list vap) * If the format string doesn't end with a newline, we pop * one on ourselves. */ - ssize_t len = strlen(fmt); - if (len > 0 && fmt[len - 1] != '\n') { - char *newfmt = alloca(len + 2); - memcpy(newfmt, fmt, len); - newfmt[len] = '\n'; - newfmt[len + 1] = '\0'; - fmt = newfmt; + if (need_newline) { + ssize_t len = strlen(fmt); + if (len > 0 && fmt[len - 1] != '\n') { + char *newfmt = alloca(len + 2); + memcpy(newfmt, fmt, len); + newfmt[len] = '\n'; + newfmt[len + 1] = '\0'; + fmt = newfmt; + } } switch (xo_style(xop)) { @@ -8069,7 +8090,7 @@ xo_error_h (xo_handle_t *xop, const char *fmt, ...) va_list vap; va_start(vap, fmt); - xo_error_hv(xop, fmt, vap); + xo_errorn_hv(xop, 0, fmt, vap); va_end(vap); } @@ -8082,7 +8103,30 @@ xo_error (const char *fmt, ...) va_list vap; va_start(vap, fmt); - xo_error_hv(NULL, fmt, vap); + xo_errorn_hv(NULL, 0, fmt, vap); + va_end(vap); +} + +void +xo_errorn_h (xo_handle_t *xop, const char *fmt, ...) +{ + va_list vap; + + va_start(vap, fmt); + xo_errorn_hv(xop, 1, fmt, vap); + va_end(vap); +} + +/* + * Generate an error message, such as would be displayed on stderr + */ +void +xo_errorn (const char *fmt, ...) +{ + va_list vap; + + va_start(vap, fmt); + xo_errorn_hv(NULL, 1, fmt, vap); va_end(vap); } @@ -8099,21 +8143,30 @@ xo_parse_args (int argc, char **argv) char *cp; int i, save; - /* Save our program name for xo_err and friends */ - xo_program = argv[0]; - cp = strrchr(xo_program, '/'); - if (cp) - xo_program = ++cp; - else - cp = argv[0]; /* Reset to front of string */ + /* + * If xo_set_program has always been called, we honor that value + */ + if (xo_program == NULL) { + /* Save our program name for xo_err and friends */ + xo_program = argv[0]; + cp = strrchr(xo_program, '/'); + if (cp) + xo_program = ++cp; + else + cp = argv[0]; /* Reset to front of string */ - /* GNU tools add an annoying ".test" as the program extension; remove it */ - size_t len = strlen(xo_program); - static const char gnu_ext[] = ".test"; - if (len >= sizeof(gnu_ext)) { - cp += len + 1 - sizeof(gnu_ext); - if (xo_streq(cp, gnu_ext)) - *cp = '\0'; + /* + * GNU libtool add an annoying ".test" as the program + * extension; we remove it. libtool also adds a "lt-" prefix + * that we cannot remove. + */ + size_t len = strlen(xo_program); + static const char gnu_ext[] = ".test"; + if (len >= sizeof(gnu_ext)) { + cp += len + 1 - sizeof(gnu_ext); + if (xo_streq(cp, gnu_ext)) + *cp = '\0'; + } } xo_handle_t *xop = xo_default(NULL); diff --git a/libxo/xo.h b/libxo/xo.h index 8404c6cb93ae..6a61a16c7cae 100644 --- a/libxo/xo.h +++ b/libxo/xo.h @@ -389,6 +389,15 @@ xo_error_h (xo_handle_t *xop, const char *fmt, ...); void xo_error (const char *fmt, ...); +void +xo_errorn_hv (xo_handle_t *xop, int need_newline, const char *fmt, va_list vap); + +void +xo_errorn_h (xo_handle_t *xop, const char *fmt, ...); + +void +xo_errorn (const char *fmt, ...); + xo_ssize_t xo_flush_h (xo_handle_t *xop); diff --git a/libxo/xo_encoder.c b/libxo/xo_encoder.c index 7e6cc1643374..475b6d70fa9d 100644 --- a/libxo/xo_encoder.c +++ b/libxo/xo_encoder.c @@ -290,8 +290,21 @@ xo_encoder_init (xo_handle_t *xop, const char *name) { xo_encoder_setup(); - const char *opts = strchr(name, ':'); + char opts_char = '\0'; + const char *col_opts = strchr(name, ':'); + const char *plus_opts = strchr(name, '+'); + + /* + * Find the option-separating character (plus or colon) which + * appears first in the options string. + */ + const char *opts = (col_opts == NULL) ? plus_opts + : (plus_opts == NULL) ? col_opts + : (plus_opts < col_opts) ? plus_opts : col_opts; + if (opts) { + opts_char = *opts; + /* Make a writable copy of the name */ size_t len = strlen(name); char *copy = alloca(len + 1); @@ -329,7 +342,11 @@ xo_encoder_init (xo_handle_t *xop, const char *name) int rc = xo_encoder_handle(xop, XO_OP_CREATE, name, NULL, 0); if (rc == 0 && opts != NULL) { - rc = xo_encoder_handle(xop, XO_OP_OPTIONS, name, opts, 0); + xo_encoder_op_t op; + + /* Encoder API is limited, so we're stuck with two different options */ + op = (opts_char == '+') ? XO_OP_OPTIONS_PLUS : XO_OP_OPTIONS; + rc = xo_encoder_handle(xop, op, name, opts, 0); } return rc; diff --git a/libxo/xo_encoder.h b/libxo/xo_encoder.h index 2a940336293c..099248ae13a6 100644 --- a/libxo/xo_encoder.h +++ b/libxo/xo_encoder.h @@ -90,6 +90,7 @@ typedef unsigned xo_encoder_op_t; #define XO_OP_ATTRIBUTE 15 /* Attribute name/value */ #define XO_OP_VERSION 16 /* Version string */ #define XO_OP_OPTIONS 17 /* Additional command line options */ +#define XO_OP_OPTIONS_PLUS 18 /* Additional command line options */ #define XO_ENCODER_HANDLER_ARGS \ xo_handle_t *xop __attribute__ ((__unused__)), \ diff --git a/tests/core/Makefile.am b/tests/core/Makefile.am index 9f7ffc441448..a1dad2cc96a2 100644 --- a/tests/core/Makefile.am +++ b/tests/core/Makefile.am @@ -88,7 +88,7 @@ TEST_JIG = \ TEST_JIG2 = \ echo "... $$test ... $$fmt ..."; \ -xoopts==warn,encoder=csv$$csv ; \ +xoopts==warn,$$csv ; \ ${TEST_JIG}; true; TEST_FORMATS = T XP JP HP X J H HIPx @@ -111,9 +111,12 @@ test tests: ${bin_PROGRAMS} done) \ done) -@ (${TEST_TRACE} test=test_01.c; base=test_01; \ - ( fmt=Ecsv1; csv= ; ${TEST_JIG2} ); \ - ( fmt=Ecsv2; csv=:path=top/data/item+no-header ; ${TEST_JIG2} ); \ - ( fmt=Ecsv3; csv=:path=item+leafs=sku.sold+no-quotes ; ${TEST_JIG2} ); \ + ( fmt=Ecsv1; csv=encoder=csv ; \ + ${TEST_JIG2} ); \ + ( fmt=Ecsv2; csv=encoder=csv:path=top/data/item:no-header ; \ + ${TEST_JIG2} ); \ + ( fmt=Ecsv3; csv=@csv:path=item:leafs=sku.sold:no-quotes ; \ + ${TEST_JIG2} ); \ ) diff --git a/tests/core/saved/test_02.H.out b/tests/core/saved/test_02.H.out index 66a158502766..a3d88030075a 100644 --- a/tests/core/saved/test_02.H.out +++ b/tests/core/saved/test_02.H.out @@ -4,4 +4,7 @@
length
abcdef
close
-1
returned
Bad file descriptor
good
close
-1
returned
Bad fi
good
improper use of profanity; ten yard penalty; first down
20
30
40
file
0
bytes
1
byte
2
bytes
3
bytes
4
bytes
10
/
20
/
30
mbufs <&> in use (current/cache/total)
50
from
Boston
64
left out of
640
64
left out of
640
beforeworkingafter:
string
:
10
11
1010
packets here/there/everywhere
1010
packets here/there/everywhere
(
15
/
20
/
125
)
(
15
/
20
/
125
)
(
15
/
20
/
125
)
(
15
/
20
/
125
)
Humanize:
21
,
57 K
,
96M
,
44M
,
1.2G
one
two
three
(null)
1:
1000
2:
test5000
3:
ten-longx
4:
xtest
this is an error
two more errors
this is an warning
two more warnings
V1/V2 packets
:
10
0004
tries
improper use of profanity; ten yard penalty; first down
Shut 'er down, Clancey! She's a-pumpin' mud! <>!,"!<> +
err message (1)
err message (2) +
err message (1) +
err message (2)
\ No newline at end of file diff --git a/tests/core/saved/test_02.HIPx.out b/tests/core/saved/test_02.HIPx.out index e2b51086d9b6..984caa3297fe 100644 --- a/tests/core/saved/test_02.HIPx.out +++ b/tests/core/saved/test_02.HIPx.out @@ -225,3 +225,18 @@
Shut 'er down, Clancey! She's a-pumpin' mud! <>!,"!<>
+
+
err message (1)
+
+
+
err message (2) +
+
+
+
err message (1) +
+
+
+
err message (2) +
+
diff --git a/tests/core/saved/test_02.HP.out b/tests/core/saved/test_02.HP.out index 2a4b954c94ed..f2634522dbcb 100644 --- a/tests/core/saved/test_02.HP.out +++ b/tests/core/saved/test_02.HP.out @@ -225,3 +225,18 @@
Shut 'er down, Clancey! She's a-pumpin' mud! <>!,"!<>
+
+
err message (1)
+
+
+
err message (2) +
+
+
+
err message (1) +
+
+
+
err message (2) +
+
diff --git a/tests/core/saved/test_02.J.out b/tests/core/saved/test_02.J.out index d6d175339c74..c34e685b4ac5 100644 --- a/tests/core/saved/test_02.J.out +++ b/tests/core/saved/test_02.J.out @@ -1 +1 @@ -{"top": {"data": {"name":"em0","flags":"0x8843","name":"em0","flags":"0x8843","what":"braces","length":"abcdef","fd":-1,"error":"Bad file descriptor","test":"good","fd":-1,"error":"Bad fi","test":"good","lines":20,"words":30,"characters":40, "bytes": [0,1,2,3,4],"mbuf-current":10,"mbuf-cache":20,"mbuf-total":30,"distance":50,"location":"Boston","memory":64,"total":640,"memory":64,"total":640,"ten":10,"eleven":11,"unknown":1010,"unknown":1010,"min":15,"cur":20,"max":125,"min":15,"cur":20,"max":125,"min":15,"cur":20,"max":125,"min":15,"cur":20,"max":125,"val1":21,"val2":58368,"val3":100663296,"val4":44470272,"val5":1342172800, "flag": ["one","two","three"],"works":null,"empty-tag":true,"t1":"1000","t2":"test5000","t3":"ten-longx","t4":"xtest", "__error": {"message":"this is an error"}, "__error": {"message":"two more errors"}, "__warning": {"message":"this is an warning"}, "__warning": {"message":"two more warnings"},"count":10,"test":4, "error": {"message":"Shut 'er down, Clancey! She's a-pumpin' mud! <>!,\"!<>\n"}}}} +{"top": {"data": {"name":"em0","flags":"0x8843","name":"em0","flags":"0x8843","what":"braces","length":"abcdef","fd":-1,"error":"Bad file descriptor","test":"good","fd":-1,"error":"Bad fi","test":"good","lines":20,"words":30,"characters":40, "bytes": [0,1,2,3,4],"mbuf-current":10,"mbuf-cache":20,"mbuf-total":30,"distance":50,"location":"Boston","memory":64,"total":640,"memory":64,"total":640,"ten":10,"eleven":11,"unknown":1010,"unknown":1010,"min":15,"cur":20,"max":125,"min":15,"cur":20,"max":125,"min":15,"cur":20,"max":125,"min":15,"cur":20,"max":125,"val1":21,"val2":58368,"val3":100663296,"val4":44470272,"val5":1342172800, "flag": ["one","two","three"],"works":null,"empty-tag":true,"t1":"1000","t2":"test5000","t3":"ten-longx","t4":"xtest", "__error": {"message":"this is an error"}, "__error": {"message":"two more errors"}, "__warning": {"message":"this is an warning"}, "__warning": {"message":"two more warnings"},"count":10,"test":4, "error": {"message":"Shut 'er down, Clancey! She's a-pumpin' mud! <>!,\"!<>\n"}, "error": {"message":"err message (1)"}, "error": {"message":"err message (2)\n"}, "error": {"message":"err message (1)\n"}, "error": {"message":"err message (2)\n"}}}} diff --git a/tests/core/saved/test_02.JP.out b/tests/core/saved/test_02.JP.out index cf211401be6f..1a3b464231bd 100644 --- a/tests/core/saved/test_02.JP.out +++ b/tests/core/saved/test_02.JP.out @@ -80,6 +80,18 @@ "test": 4, "error": { "message": "Shut 'er down, Clancey! She's a-pumpin' mud! <>!,\"!<>\n" + }, + "error": { + "message": "err message (1)" + }, + "error": { + "message": "err message (2)\n" + }, + "error": { + "message": "err message (1)\n" + }, + "error": { + "message": "err message (2)\n" } } } diff --git a/tests/core/saved/test_02.T.err b/tests/core/saved/test_02.T.err index d0b94597587c..debdac6a5157 100644 --- a/tests/core/saved/test_02.T.err +++ b/tests/core/saved/test_02.T.err @@ -1,2 +1,5 @@ test_02: key field emitted after normal value field: 'name' Shut 'er down, Clancey! She's a-pumpin' mud! <>!,"!<> +err message (1)err message (2) +err message (1) +err message (2) diff --git a/tests/core/saved/test_02.X.out b/tests/core/saved/test_02.X.out index 2eb122d00c8c..598480be9946 100644 --- a/tests/core/saved/test_02.X.out +++ b/tests/core/saved/test_02.X.out @@ -4,4 +4,7 @@ abcdef-1Bad file descriptorgood-1Bad figoodimproper use of profanity; ten yard penalty; first down 2030400123410203050Boston646406464010111010101015201251520125152012515201252158368100663296444702721342172800onetwothreenull1000test5000ten-longxxtest<__error>this is an error<__error>two more errors<__warning>this is an warning<__warning>two more warnings104improper use of profanity; ten yard penalty; first down Shut 'er down, Clancey! She's a-pumpin' mud! <>!,"!<> +err message (1)err message (2) +err message (1) +err message (2) \ No newline at end of file diff --git a/tests/core/saved/test_02.XP.out b/tests/core/saved/test_02.XP.out index 9c18c5edca4f..9a0755e01421 100644 --- a/tests/core/saved/test_02.XP.out +++ b/tests/core/saved/test_02.XP.out @@ -85,6 +85,21 @@ Shut 'er down, Clancey! She's a-pumpin' mud! <>!,"!<> + + + + err message (1) + + + err message (2) + + + + err message (1) + + + + err message (2) diff --git a/tests/core/test_02.c b/tests/core/test_02.c index 7402f04f4b80..4ea8c459047c 100644 --- a/tests/core/test_02.c +++ b/tests/core/test_02.c @@ -21,6 +21,8 @@ int main (int argc, char **argv) { + xo_set_program("test_02"); + argc = xo_parse_args(argc, argv); if (argc < 0) return 1; @@ -144,6 +146,10 @@ main (int argc, char **argv) "ten yard penalty", "first down"); xo_error("Shut 'er down, Clancey! She's a-pumpin' mud! <>!,\"!<>\n"); + xo_error("err message (%d)", 1); + xo_error("err message (%d)\n", 2); + xo_errorn("err message (%d)", 1); + xo_errorn("err message (%d)\n", 2); xo_close_container("data"); diff --git a/tests/core/test_12.c b/tests/core/test_12.c index 90392196629f..32af2d211857 100644 --- a/tests/core/test_12.c +++ b/tests/core/test_12.c @@ -25,6 +25,8 @@ main (int argc, char **argv) xo_emit_flags_t flags = XOEF_RETAIN; int opt_color = 1; + xo_set_program("test_12"); + argc = xo_parse_args(argc, argv); if (argc < 0) return 1; From a0ba604b8070185b7b0a43339b091a56b5bb8a95 Mon Sep 17 00:00:00 2001 From: Li-Wen Hsu Date: Sat, 25 Jan 2020 23:22:08 +0000 Subject: [PATCH 02/27] Specify PACKAGE to install tests files MFC after: 3 weeks MFC with: r356984 Sponsored by: The FreeBSD Foundation --- tests/sys/netinet/Makefile | 2 ++ 1 file changed, 2 insertions(+) diff --git a/tests/sys/netinet/Makefile b/tests/sys/netinet/Makefile index c206e6053cd3..41d7d8abc7da 100644 --- a/tests/sys/netinet/Makefile +++ b/tests/sys/netinet/Makefile @@ -1,5 +1,7 @@ # $FreeBSD$ +PACKAGE= tests + TESTSDIR= ${TESTSBASE}/sys/netinet BINDIR= ${TESTSDIR} From dc9a1cb60be0caad6a80655ed325f300427e2b79 Mon Sep 17 00:00:00 2001 From: Mateusz Guzik Date: Sun, 26 Jan 2020 00:34:57 +0000 Subject: [PATCH 03/27] vfs: predict vn_lock failure as unlikely in vget --- sys/kern/vfs_subr.c | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/sys/kern/vfs_subr.c b/sys/kern/vfs_subr.c index b8278f1cd521..101cdcef636d 100644 --- a/sys/kern/vfs_subr.c +++ b/sys/kern/vfs_subr.c @@ -2911,7 +2911,8 @@ vget_finish(struct vnode *vp, int flags, enum vgetstate vs) __func__)); } - if ((error = vn_lock(vp, flags)) != 0) { + error = vn_lock(vp, flags); + if (__predict_false(error != 0)) { if (vs == VGET_USECOUNT) vrele(vp); else From 6c44a3e019affbf4f22e8b9abedc249c00b28afb Mon Sep 17 00:00:00 2001 From: Mateusz Guzik Date: Sun, 26 Jan 2020 00:38:06 +0000 Subject: [PATCH 04/27] ufs: add vgone calls for unconstructed vnodes in the error path This mostly eliminates the requirement that vput never unlocks the vnode before calling VOP_INACTIVE. Note it may still be present for other filesystems. See r356126 for an example bug. Note vput stopped doing early unlock in r357070 thus this change does not affect correctness as it is. Reviewed by: kib Differential Revision: https://reviews.freebsd.org/D23215 --- sys/ufs/ffs/ffs_vfsops.c | 4 ++++ sys/ufs/ufs/ufs_vnops.c | 7 ++++++- 2 files changed, 10 insertions(+), 1 deletion(-) diff --git a/sys/ufs/ffs/ffs_vfsops.c b/sys/ufs/ffs/ffs_vfsops.c index 458c7360fcc7..d4c730fe20fe 100644 --- a/sys/ufs/ffs/ffs_vfsops.c +++ b/sys/ufs/ffs/ffs_vfsops.c @@ -1787,6 +1787,7 @@ ffs_vgetf(mp, ino, flags, vpp, ffs_flags) * still zero, it will be unlinked and returned to the free * list by vput(). */ + vgone(vp); vput(vp); *vpp = NULL; return (error); @@ -1797,6 +1798,7 @@ ffs_vgetf(mp, ino, flags, vpp, ffs_flags) ip->i_din2 = uma_zalloc(uma_ufs2, M_WAITOK); if ((error = ffs_load_inode(bp, ip, fs, ino)) != 0) { bqrelse(bp); + vgone(vp); vput(vp); *vpp = NULL; return (error); @@ -1814,6 +1816,7 @@ ffs_vgetf(mp, ino, flags, vpp, ffs_flags) error = ufs_vinit(mp, I_IS_UFS1(ip) ? &ffs_fifoops1 : &ffs_fifoops2, &vp); if (error) { + vgone(vp); vput(vp); *vpp = NULL; return (error); @@ -1849,6 +1852,7 @@ ffs_vgetf(mp, ino, flags, vpp, ffs_flags) error = mac_vnode_associate_extattr(mp, vp); if (error) { /* ufs_inactive will release ip->i_devvp ref. */ + vgone(vp); vput(vp); *vpp = NULL; return (error); diff --git a/sys/ufs/ufs/ufs_vnops.c b/sys/ufs/ufs/ufs_vnops.c index 8318844b01de..4ff8206872bf 100644 --- a/sys/ufs/ufs/ufs_vnops.c +++ b/sys/ufs/ufs/ufs_vnops.c @@ -1839,6 +1839,7 @@ ufs_mkdir(ap) if (DOINGSOFTDEP(tvp)) softdep_revert_link(dp, ip); UFS_VFREE(tvp, ip->i_number, dmode); + vgone(tvp); vput(tvp); return (error); } @@ -1853,6 +1854,7 @@ ufs_mkdir(ap) if (DOINGSOFTDEP(tvp)) softdep_revert_link(dp, ip); UFS_VFREE(tvp, ip->i_number, dmode); + vgone(tvp); vput(tvp); return (error); } @@ -1980,7 +1982,7 @@ ufs_mkdir(ap) UFS_INODE_SET_FLAG(ip, IN_CHANGE); if (DOINGSOFTDEP(tvp)) softdep_revert_mkdir(dp, ip); - + vgone(tvp); vput(tvp); } out: @@ -2607,6 +2609,7 @@ ufs_makeinode(mode, dvp, vpp, cnp, callfunc) if (DOINGSOFTDEP(tvp)) softdep_revert_link(pdir, ip); UFS_VFREE(tvp, ip->i_number, mode); + vgone(tvp); vput(tvp); return (error); } @@ -2621,6 +2624,7 @@ ufs_makeinode(mode, dvp, vpp, cnp, callfunc) if (DOINGSOFTDEP(tvp)) softdep_revert_link(pdir, ip); UFS_VFREE(tvp, ip->i_number, mode); + vgone(tvp); vput(tvp); return (error); } @@ -2691,6 +2695,7 @@ ufs_makeinode(mode, dvp, vpp, cnp, callfunc) UFS_INODE_SET_FLAG(ip, IN_CHANGE); if (DOINGSOFTDEP(tvp)) softdep_revert_create(VTOI(dvp), ip); + vgone(tvp); vput(tvp); return (error); } From 6d69e665dd95fbb14e061dcdab97fb55634217e3 Mon Sep 17 00:00:00 2001 From: Mateusz Guzik Date: Sun, 26 Jan 2020 00:40:27 +0000 Subject: [PATCH 05/27] vfs: fix freevnodes count update race against preemption vdbatch_process leaves the critical section too early, openign a time window where another thread can get scheduled and modify vd->freevnodes. Once it the preempted thread gets back it overrides the value with 0. Just move critical_exit to the end of the function. --- sys/kern/vfs_subr.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/sys/kern/vfs_subr.c b/sys/kern/vfs_subr.c index 101cdcef636d..b4c594c2dc8f 100644 --- a/sys/kern/vfs_subr.c +++ b/sys/kern/vfs_subr.c @@ -3324,10 +3324,10 @@ vdbatch_process(struct vdbatch *vd) vp->v_dbatchcpu = NOCPU; } mtx_unlock(&vnode_list_mtx); - critical_exit(); vd->freevnodes = 0; bzero(vd->tab, sizeof(vd->tab)); vd->index = 0; + critical_exit(); } static void From 8a6f5fd50cba25ea51cb0cb39d632895a8827b4a Mon Sep 17 00:00:00 2001 From: Mateusz Guzik Date: Sun, 26 Jan 2020 00:41:38 +0000 Subject: [PATCH 06/27] vfs: stop null checking routines in vop wrappers Calls to vop_bypass pass the same argument, but type casted to something else. Thus by replacing NULL routines with vop_bypass we avoid a runtime check. Reviewed by: kib Differential Revision: https://reviews.freebsd.org/D23357 --- sys/tools/vnode_if.awk | 12 +++++++----- 1 file changed, 7 insertions(+), 5 deletions(-) diff --git a/sys/tools/vnode_if.awk b/sys/tools/vnode_if.awk index df3251090b99..cd138bef75da 100644 --- a/sys/tools/vnode_if.awk +++ b/sys/tools/vnode_if.awk @@ -367,14 +367,11 @@ while ((getline < srcfile) > 0) { add_pre(name); for (i = 0; i < numargs; ++i) add_debug_code(name, args[i], "Entry", "\t"); - printc("\tif (__predict_true(!SDT_PROBES_ENABLED() && vop->"name" != NULL)) {"); + printc("\tif (!SDT_PROBES_ENABLED()) {"); printc("\t\trc = vop->"name"(a);") printc("\t} else {") printc("\t\tSDT_PROBE2(vfs, vop, " name ", entry, a->a_" args[0] ", a);"); - printc("\t\tif (vop->"name" != NULL)") - printc("\t\t\trc = vop->"name"(a);") - printc("\t\telse") - printc("\t\t\trc = vop->vop_bypass(&a->a_gen);") + printc("\t\trc = vop->"name"(a);") printc("\t\tSDT_PROBE3(vfs, vop, " name ", return, a->a_" args[0] ", a, rc);"); printc("\t}") printc("\tif (rc == 0) {"); @@ -450,6 +447,11 @@ if (cfile) { printc("\tif (vop != NULL)"); printc("\t\torig_vop->vop_bypass = vop->vop_bypass;"); printc(""); + for (name in funcarr) { + printc("\tif (orig_vop->"name" == NULL)"); + printc("\t\torig_vop->"name" = (void *)orig_vop->vop_bypass;"); + } + printc(""); printc("\torig_vop->registered = true;"); printc("}") } From cd0e46c66bf8c416114e0c389ec0c70e90dee74a Mon Sep 17 00:00:00 2001 From: Mateusz Guzik Date: Sun, 26 Jan 2020 07:05:06 +0000 Subject: [PATCH 07/27] vfs: remove vop loop from vop_sigdefer All ops are guaranteed to be present since r357131. --- sys/kern/vfs_default.c | 15 +-------------- 1 file changed, 1 insertion(+), 14 deletions(-) diff --git a/sys/kern/vfs_default.c b/sys/kern/vfs_default.c index ac5f60b64e97..14a8c6c04f57 100644 --- a/sys/kern/vfs_default.c +++ b/sys/kern/vfs_default.c @@ -1450,20 +1450,7 @@ vop_sigdefer(struct vop_vector *vop, struct vop_generic_args *a) vop_bypass_t *bp; int prev_stops, rc; - for (; vop != NULL; vop = vop->vop_default) { - bp = bp_by_off(vop, a); - if (bp != NULL) - break; - - /* - * Bypass is not really supported. It is done for - * fallback to unimplemented vops in the default - * vector. - */ - bp = vop->vop_bypass; - if (bp != NULL) - break; - } + bp = bp_by_off(vop, a); MPASS(bp != NULL); prev_stops = sigdeferstop(SIGDEFERSTOP_SILENT); From 1513f80391027532201dd13abe6c0e8c58427482 Mon Sep 17 00:00:00 2001 From: Mateusz Guzik Date: Sun, 26 Jan 2020 07:06:18 +0000 Subject: [PATCH 08/27] vfs: do an unlocked check before iterating the lazy list For most filesystems it is expected to be empty most of the time. --- sys/kern/vfs_subr.c | 3 +++ 1 file changed, 3 insertions(+) diff --git a/sys/kern/vfs_subr.c b/sys/kern/vfs_subr.c index b4c594c2dc8f..289736d54162 100644 --- a/sys/kern/vfs_subr.c +++ b/sys/kern/vfs_subr.c @@ -6368,6 +6368,9 @@ __mnt_vnode_first_lazy(struct vnode **mvp, struct mount *mp, mnt_lazy_cb_t *cb, { struct vnode *vp; + if (TAILQ_EMPTY(&mp->mnt_lazyvnodelist)) + return (NULL); + *mvp = vn_alloc_marker(mp); MNT_ILOCK(mp); MNT_REF(mp); From fba0af0bf897541b88fa66a9fb9225573f49dd9c Mon Sep 17 00:00:00 2001 From: Li-Wen Hsu Date: Sun, 26 Jan 2020 07:24:49 +0000 Subject: [PATCH 09/27] Temporarily skip flakey test case sys.kern.ptrace_test.ptrace__procdesc_reparent_wait_child PR: 243605 Sponsored by: The FreeBSD Foundation --- tests/sys/kern/ptrace_test.c | 3 +++ 1 file changed, 3 insertions(+) diff --git a/tests/sys/kern/ptrace_test.c b/tests/sys/kern/ptrace_test.c index 8cee9749fe3a..cc103bed1995 100644 --- a/tests/sys/kern/ptrace_test.c +++ b/tests/sys/kern/ptrace_test.c @@ -4189,6 +4189,9 @@ ATF_TC_BODY(ptrace__procdesc_reparent_wait_child, tc) pid_t traced, debuger, wpid; int pd, status; + if (atf_tc_get_config_var_as_bool_wd(tc, "ci", false)) + atf_tc_skip("https://bugs.freebsd.org/243605"); + traced = pdfork(&pd, 0); ATF_REQUIRE(traced >= 0); if (traced == 0) { From 532b3f47916726029a5bc2df405089de9c6d7c0d Mon Sep 17 00:00:00 2001 From: Pawel Jakub Dawidek Date: Sun, 26 Jan 2020 10:49:24 +0000 Subject: [PATCH 10/27] - Be consistent with using sysexits(3) codes. - Turn fprintf()+exit() into errx(). Sponsored by: Fudo Security --- bin/pwait/pwait.c | 11 +++++------ 1 file changed, 5 insertions(+), 6 deletions(-) diff --git a/bin/pwait/pwait.c b/bin/pwait/pwait.c index 76989c919371..e31db4dded1f 100644 --- a/bin/pwait/pwait.c +++ b/bin/pwait/pwait.c @@ -53,8 +53,7 @@ static void usage(void) { - fprintf(stderr, "usage: pwait [-t timeout] [-v] pid ...\n"); - exit(EX_USAGE); + errx(EX_USAGE, "usage: pwait [-t timeout] [-v] pid ..."); } /* @@ -120,11 +119,11 @@ main(int argc, char *argv[]) kq = kqueue(); if (kq == -1) - err(1, "kqueue"); + err(EX_OSERR, "kqueue"); e = malloc((argc + tflag) * sizeof(struct kevent)); if (e == NULL) - err(1, "malloc"); + err(EX_OSERR, "malloc"); nleft = 0; for (n = 0; n < argc; n++) { s = argv[n]; @@ -166,12 +165,12 @@ main(int argc, char *argv[]) while (nleft > 0) { n = kevent(kq, NULL, 0, e, nleft + tflag, NULL); if (n == -1) - err(1, "kevent"); + err(EX_OSERR, "kevent"); for (i = 0; i < n; i++) { if (e[i].filter == EVFILT_SIGNAL) { if (verbose) printf("timeout\n"); - return (124); + exit(124); } if (verbose) { status = e[i].data; From 3f50bbaf51f0cc6e9eebae0161f526324e7a9366 Mon Sep 17 00:00:00 2001 From: Pawel Jakub Dawidek Date: Sun, 26 Jan 2020 10:51:57 +0000 Subject: [PATCH 11/27] Check for duplicated PID without using additional variable. Sponsored by: Fudo Security --- bin/pwait/pwait.c | 23 ++++++++++++----------- 1 file changed, 12 insertions(+), 11 deletions(-) diff --git a/bin/pwait/pwait.c b/bin/pwait/pwait.c index e31db4dded1f..4507aad99f27 100644 --- a/bin/pwait/pwait.c +++ b/bin/pwait/pwait.c @@ -66,7 +66,7 @@ main(int argc, char *argv[]) int kq; struct kevent *e; int tflag, verbose; - int opt, nleft, n, i, duplicate, status; + int opt, nleft, n, i, status; long pid; char *s, *end; double timeout; @@ -135,18 +135,19 @@ main(int argc, char *argv[]) warnx("%s: bad process id", s); continue; } - duplicate = 0; - for (i = 0; i < nleft; i++) + for (i = 0; i < nleft; i++) { if (e[i].ident == (uintptr_t)pid) - duplicate = 1; - if (!duplicate) { - EV_SET(e + nleft, pid, EVFILT_PROC, EV_ADD, NOTE_EXIT, - 0, NULL); - if (kevent(kq, e + nleft, 1, NULL, 0, NULL) == -1) - warn("%ld", pid); - else - nleft++; + break; } + if (i < nleft) { + /* Duplicate. */ + continue; + } + EV_SET(e + nleft, pid, EVFILT_PROC, EV_ADD, NOTE_EXIT, 0, NULL); + if (kevent(kq, e + nleft, 1, NULL, 0, NULL) == -1) + warn("%ld", pid); + else + nleft++; } if (tflag) { From 5e2e2222aed13580ec1aa86c68997e15a3b85596 Mon Sep 17 00:00:00 2001 From: Pawel Jakub Dawidek Date: Sun, 26 Jan 2020 10:54:16 +0000 Subject: [PATCH 12/27] Don't setup a timeout if we are exiting. Sponsored by: Fudo Security --- bin/pwait/pwait.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/bin/pwait/pwait.c b/bin/pwait/pwait.c index 4507aad99f27..66cf4a947de6 100644 --- a/bin/pwait/pwait.c +++ b/bin/pwait/pwait.c @@ -150,7 +150,7 @@ main(int argc, char *argv[]) nleft++; } - if (tflag) { + if (nleft > 0 && tflag) { /* * Explicitly detect SIGALRM so that an exit status of 124 * can be returned rather than 142. From 2362bc2cf533639c55165e3d5b870109ec69976f Mon Sep 17 00:00:00 2001 From: Pawel Jakub Dawidek Date: Sun, 26 Jan 2020 11:02:51 +0000 Subject: [PATCH 13/27] Implement -o flag which tells pwait(1) to exit if any of the given processes has terminated. Sponsored by: Fudo Security --- bin/pwait/pwait.1 | 6 ++++-- bin/pwait/pwait.c | 23 +++++++++++++++++------ 2 files changed, 21 insertions(+), 8 deletions(-) diff --git a/bin/pwait/pwait.1 b/bin/pwait/pwait.1 index b31700065aca..05f9392e4aa8 100644 --- a/bin/pwait/pwait.1 +++ b/bin/pwait/pwait.1 @@ -32,7 +32,7 @@ .\" .\" $FreeBSD$ .\" -.Dd March 7, 2017 +.Dd January 26, 2020 .Dt PWAIT 1 .Os .Sh NAME @@ -41,7 +41,7 @@ .Sh SYNOPSIS .Nm .Op Fl t Ar duration -.Op Fl v +.Op Fl ov .Ar pid \&... .Sh DESCRIPTION @@ -51,6 +51,8 @@ utility will wait until each of the given processes has terminated. .Pp The following option is available: .Bl -tag -width indent +.It Fl o +Exit when any of the given processes has terminated. .It Fl t Ar duration If any process is still running after .Ar duration , diff --git a/bin/pwait/pwait.c b/bin/pwait/pwait.c index 66cf4a947de6..ec6428f202e4 100644 --- a/bin/pwait/pwait.c +++ b/bin/pwait/pwait.c @@ -53,7 +53,7 @@ static void usage(void) { - errx(EX_USAGE, "usage: pwait [-t timeout] [-v] pid ..."); + errx(EX_USAGE, "usage: pwait [-t timeout] [-ov] pid ..."); } /* @@ -65,16 +65,22 @@ main(int argc, char *argv[]) struct itimerval itv; int kq; struct kevent *e; - int tflag, verbose; + int oflag, tflag, verbose; int opt, nleft, n, i, status; long pid; char *s, *end; double timeout; - tflag = verbose = 0; + oflag = 0; + tflag = 0; + verbose = 0; memset(&itv, 0, sizeof(itv)); - while ((opt = getopt(argc, argv, "t:v")) != -1) { + + while ((opt = getopt(argc, argv, "t:ov")) != -1) { switch (opt) { + case 'o': + oflag = 1; + break; case 't': tflag = 1; errno = 0; @@ -144,10 +150,13 @@ main(int argc, char *argv[]) continue; } EV_SET(e + nleft, pid, EVFILT_PROC, EV_ADD, NOTE_EXIT, 0, NULL); - if (kevent(kq, e + nleft, 1, NULL, 0, NULL) == -1) + if (kevent(kq, e + nleft, 1, NULL, 0, NULL) == -1) { warn("%ld", pid); - else + if (oflag) + exit(EX_OK); + } else { nleft++; + } } if (nleft > 0 && tflag) { @@ -187,6 +196,8 @@ main(int argc, char *argv[]) printf("%ld: terminated.\n", (long)e[i].ident); } + if (oflag) + exit(EX_OK); --nleft; } } From dee496fc37873c18f33eaf7d12ee0b085179cadd Mon Sep 17 00:00:00 2001 From: Pawel Jakub Dawidek Date: Sun, 26 Jan 2020 11:03:45 +0000 Subject: [PATCH 14/27] Implement tests for the newly added -o flag. Sponsored by: Fudo Security --- bin/pwait/tests/pwait_test.sh | 80 +++++++++++++++++++++++++++++++++++ 1 file changed, 80 insertions(+) diff --git a/bin/pwait/tests/pwait_test.sh b/bin/pwait/tests/pwait_test.sh index 0e22c94114ba..07ed21706fd5 100644 --- a/bin/pwait/tests/pwait_test.sh +++ b/bin/pwait/tests/pwait_test.sh @@ -232,6 +232,85 @@ timeout_many_cleanup() wait $p1 $p5 $p10 >/dev/null 2>&1 } +atf_test_case or_flag +or_flag_head() +{ + atf_set "descr" "Test OR flag" +} + +or_flag_body() +{ + sleep 2 & + p2=$! + + sleep 4 & + p4=$! + + sleep 6 & + p6=$! + + atf_check \ + -o inline:"$p2: exited with status 0.\n" \ + -e empty \ + -s exit:0 \ + timeout --preserve-status 15 pwait -o -v $p2 $p4 $p6 + + atf_check \ + -o empty \ + -e inline:"pwait: $p2: No such process\n" \ + -s exit:0 \ + timeout --preserve-status 15 pwait -o $p2 $p4 $p6 + + atf_check \ + -o empty \ + -e empty \ + -s exit:0 \ + timeout --preserve-status 15 pwait -o $p4 $p6 + + atf_check \ + -o empty \ + -e inline:"pwait: $p4: No such process\n" \ + -s exit:0 \ + timeout --preserve-status 15 pwait -o $p4 $p6 + + atf_check \ + -o inline:"$p6: exited with status 0.\n" \ + -e empty \ + -s exit:0 \ + timeout --preserve-status 15 pwait -o -v $p6 + + atf_check \ + -o empty \ + -e inline:"pwait: $p6: No such process\n" \ + -s exit:0 \ + timeout --preserve-status 15 pwait -o $p6 + + atf_check \ + -o empty \ + -e inline:"kill: $p2: No such process\n" \ + -s exit:1 \ + kill -0 $p2 + + atf_check \ + -o empty \ + -e inline:"kill: $p4: No such process\n" \ + -s exit:1 \ + kill -0 $p4 + + atf_check \ + -o empty \ + -e inline:"kill: $p6: No such process\n" \ + -s exit:1 \ + kill -0 $p6 + +} + +or_flag_cleanup() +{ + kill $p2 $p4 $p6 >/dev/null 2>&1 + wait $p2 $p4 $p6 >/dev/null 2>&1 +} + atf_init_test_cases() { atf_add_test_case basic @@ -239,4 +318,5 @@ atf_init_test_cases() atf_add_test_case timeout_trigger_timeout atf_add_test_case timeout_no_timeout atf_add_test_case timeout_many + atf_add_test_case or_flag } From 967735479078884908dbb9eed0ab40f84371570a Mon Sep 17 00:00:00 2001 From: Pawel Jakub Dawidek Date: Sun, 26 Jan 2020 11:13:34 +0000 Subject: [PATCH 15/27] Style changes, mostly usage of braces around single line statements - it is safer and allowed for some time now by style(9). Sponsored by: Fudo Security --- bin/pwait/pwait.c | 55 +++++++++++++++++++++++++++++------------------ 1 file changed, 34 insertions(+), 21 deletions(-) diff --git a/bin/pwait/pwait.c b/bin/pwait/pwait.c index ec6428f202e4..4c21984de3f9 100644 --- a/bin/pwait/pwait.c +++ b/bin/pwait/pwait.c @@ -63,12 +63,11 @@ int main(int argc, char *argv[]) { struct itimerval itv; - int kq; struct kevent *e; int oflag, tflag, verbose; - int opt, nleft, n, i, status; + int i, kq, n, nleft, opt, status; long pid; - char *s, *end; + char *end, *s; double timeout; oflag = 0; @@ -76,7 +75,7 @@ main(int argc, char *argv[]) verbose = 0; memset(&itv, 0, sizeof(itv)); - while ((opt = getopt(argc, argv, "t:ov")) != -1) { + while ((opt = getopt(argc, argv, "ot:v")) != -1) { switch (opt) { case 'o': oflag = 1; @@ -85,9 +84,9 @@ main(int argc, char *argv[]) tflag = 1; errno = 0; timeout = strtod(optarg, &end); - if (end == optarg || errno == ERANGE || - timeout < 0) + if (end == optarg || errno == ERANGE || timeout < 0) { errx(EX_DATAERR, "timeout value"); + } switch(*end) { case 0: case 's': @@ -101,8 +100,9 @@ main(int argc, char *argv[]) default: errx(EX_DATAERR, "timeout unit"); } - if (timeout > 100000000L) + if (timeout > 100000000L) { errx(EX_DATAERR, "timeout value"); + } itv.it_value.tv_sec = (time_t)timeout; timeout -= (time_t)timeout; itv.it_value.tv_usec = @@ -120,21 +120,26 @@ main(int argc, char *argv[]) argc -= optind; argv += optind; - if (argc == 0) + if (argc == 0) { usage(); + } kq = kqueue(); - if (kq == -1) + if (kq == -1) { err(EX_OSERR, "kqueue"); + } e = malloc((argc + tflag) * sizeof(struct kevent)); - if (e == NULL) + if (e == NULL) { err(EX_OSERR, "malloc"); + } nleft = 0; for (n = 0; n < argc; n++) { s = argv[n]; - if (!strncmp(s, "/proc/", 6)) /* Undocumented Solaris compat */ + /* Undocumented Solaris compat */ + if (!strncmp(s, "/proc/", 6)) { s += 6; + } errno = 0; pid = strtol(s, &end, 10); if (pid < 0 || *end != '\0' || errno != 0) { @@ -142,8 +147,9 @@ main(int argc, char *argv[]) continue; } for (i = 0; i < nleft; i++) { - if (e[i].ident == (uintptr_t)pid) + if (e[i].ident == (uintptr_t)pid) { break; + } } if (i < nleft) { /* Duplicate. */ @@ -152,8 +158,9 @@ main(int argc, char *argv[]) EV_SET(e + nleft, pid, EVFILT_PROC, EV_ADD, NOTE_EXIT, 0, NULL); if (kevent(kq, e + nleft, 1, NULL, 0, NULL) == -1) { warn("%ld", pid); - if (oflag) + if (oflag) { exit(EX_OK); + } } else { nleft++; } @@ -165,39 +172,45 @@ main(int argc, char *argv[]) * can be returned rather than 142. */ EV_SET(e + nleft, SIGALRM, EVFILT_SIGNAL, EV_ADD, 0, 0, NULL); - if (kevent(kq, e + nleft, 1, NULL, 0, NULL) == -1) + if (kevent(kq, e + nleft, 1, NULL, 0, NULL) == -1) { err(EX_OSERR, "kevent"); + } /* Ignore SIGALRM to not interrupt kevent(2). */ signal(SIGALRM, SIG_IGN); - if (setitimer(ITIMER_REAL, &itv, NULL) == -1) + if (setitimer(ITIMER_REAL, &itv, NULL) == -1) { err(EX_OSERR, "setitimer"); + } } while (nleft > 0) { n = kevent(kq, NULL, 0, e, nleft + tflag, NULL); - if (n == -1) + if (n == -1) { err(EX_OSERR, "kevent"); + } for (i = 0; i < n; i++) { if (e[i].filter == EVFILT_SIGNAL) { - if (verbose) + if (verbose) { printf("timeout\n"); + } exit(124); } if (verbose) { status = e[i].data; - if (WIFEXITED(status)) + if (WIFEXITED(status)) { printf("%ld: exited with status %d.\n", (long)e[i].ident, WEXITSTATUS(status)); - else if (WIFSIGNALED(status)) + } else if (WIFSIGNALED(status)) { printf("%ld: killed by signal %d.\n", (long)e[i].ident, WTERMSIG(status)); - else + } else { printf("%ld: terminated.\n", (long)e[i].ident); + } } - if (oflag) + if (oflag) { exit(EX_OK); + } --nleft; } } From 75831a1c95e7bcaab9a70bc321f5e7bdde5b989f Mon Sep 17 00:00:00 2001 From: "Alexander V. Chernikov" Date: Sun, 26 Jan 2020 11:54:21 +0000 Subject: [PATCH 16/27] Fix NOINET6 build after r357038. Reported by: AN --- sys/netinet/ip_divert.c | 2 ++ 1 file changed, 2 insertions(+) diff --git a/sys/netinet/ip_divert.c b/sys/netinet/ip_divert.c index 6ffb8e3e94d8..80bfd86c1951 100644 --- a/sys/netinet/ip_divert.c +++ b/sys/netinet/ip_divert.c @@ -371,9 +371,11 @@ div_output(struct socket *so, struct mbuf *m, struct sockaddr_in *sin, case IPVERSION: family = AF_INET; break; +#ifdef INET6 case IPV6_VERSION >> 4: family = AF_INET6; break; +#endif default: m_freem(m); return (EAFNOSUPPORT); From 1207cda9614c0efa314f5bef902cd12d77cf4d97 Mon Sep 17 00:00:00 2001 From: John Baldwin Date: Sun, 26 Jan 2020 14:19:08 +0000 Subject: [PATCH 17/27] Compile hack.c with normal CFLAGS + -shared -nostdlib. Originally, hack.c was compiled into a shard object with just -shared -nostdlib. This assumed that ${CC} did not require any additional flags for ABIs, cross-building, etc. When kern.post.mk was created in r89509 by reducing duplication in kernel Makefile. files, the -shared flag was moved into a HACK_EXTRA_FLAGS variable so that sparc64 could override it with -Wl,-shared. The sparc64 hack was removed in r111650, but HACK_EXTRA_FLAGS was left in place. Over time, we have started support toolchains that require flags to support alternate ABIs on MIPS and PowerPC and started (ab)using HACK_EXTRA_FLAGS to set only those flags. I need to fix risc-v to pass -mno-relax to the hack.c build for lld in llvm 10, and the patches to support cross-build from non-FreeBSD hosts need to include -target for clang in CFLAGS for hack.c. Rather than adding more hacks into HACK_EXTRA_FLAGS, just use the full set of CFLAGS with hack.c. Reviewed by: kib, arichardson MFC after: 1 month Sponsored by: DARPA Differential Revision: https://reviews.freebsd.org/D23362 --- sys/conf/Makefile.mips | 3 --- sys/conf/Makefile.powerpc | 1 - sys/conf/kern.post.mk | 3 +-- 3 files changed, 1 insertion(+), 6 deletions(-) diff --git a/sys/conf/Makefile.mips b/sys/conf/Makefile.mips index 0d486ed683d7..0060ad7f03d3 100644 --- a/sys/conf/Makefile.mips +++ b/sys/conf/Makefile.mips @@ -50,12 +50,9 @@ ARCH_FLAGS+=-mabi=${MIPS_ABI} EXTRA_FLAGS=-fno-pic -mno-abicalls -G0 -DKERNLOADADDR=${KERNLOADADDR} EXTRA_FLAGS+=-${MIPS_ENDIAN} -HACK_EXTRA_FLAGS=-shared - # We add the -fno-pic flag to kernels because otherwise performance # is extremely poor, as well as -mno-abicalls to force no ABI usage. CFLAGS+=${EXTRA_FLAGS} $(ARCH_FLAGS) -HACK_EXTRA_FLAGS+=${EXTRA_FLAGS} $(ARCH_FLAGS) TRAMP_ARCH_FLAGS?=$(ARCH_FLAGS) TRAMP_EXTRA_FLAGS=${EXTRA_FLAGS} ${TRAMP_ARCH_FLAGS} # Kernel code is always compiled with soft-float on MIPS diff --git a/sys/conf/Makefile.powerpc b/sys/conf/Makefile.powerpc index 907f64dca62e..f8b5bd6b0547 100644 --- a/sys/conf/Makefile.powerpc +++ b/sys/conf/Makefile.powerpc @@ -39,7 +39,6 @@ INCLUDES+= -I$S/contrib/libfdt # Force __SPE__, since the builtin will be removed later with -mno-spe CFLAGS.gcc+= -mabi=spe -D__SPE__ CFLAGS.clang+= -mspe -D__SPE__ -m32 -HACK_EXTRA_FLAGS= -shared -m32 -mspe -D__SPE__ .endif CFLAGS+= -msoft-float CFLAGS.gcc+= -Wa,-many diff --git a/sys/conf/kern.post.mk b/sys/conf/kern.post.mk index 3f6e26429481..acbfc6638fa7 100644 --- a/sys/conf/kern.post.mk +++ b/sys/conf/kern.post.mk @@ -226,10 +226,9 @@ kernel-clean: # This is a hack. BFD "optimizes" away dynamic mode if there are no # dynamic references. We could probably do a '-Bforcedynamic' mode like # in the a.out ld. For now, this works. -HACK_EXTRA_FLAGS?= -shared hack.pico: Makefile :> hack.c - ${CC} ${HACK_EXTRA_FLAGS} -nostdlib hack.c -o hack.pico + ${CC} -shared ${CFLAGS} -nostdlib hack.c -o hack.pico rm -f hack.c offset.inc: $S/kern/genoffset.sh genoffset.o From c73222d0e6db4b4719b92d8622eabc343b609e1a Mon Sep 17 00:00:00 2001 From: John Baldwin Date: Sun, 26 Jan 2020 14:20:57 +0000 Subject: [PATCH 18/27] Fix some misleading indentation warnings reported by recent clang. These should not be any functional change. While the change in emul10kx-pcm.c looks like a real bug fix (as opposed to inconsistent whitespace), the extra statements were not harmful. Reviewed by: kib Sponsored by: DARPA Differential Revision: https://reviews.freebsd.org/D23363 --- sys/dev/mrsas/mrsas_cam.c | 15 ++++++++------- sys/dev/sound/pci/emu10k1.c | 11 ++++++----- sys/dev/sound/pci/emu10kx-pcm.c | 3 ++- sys/kern/subr_stats.c | 4 +--- 4 files changed, 17 insertions(+), 16 deletions(-) diff --git a/sys/dev/mrsas/mrsas_cam.c b/sys/dev/mrsas/mrsas_cam.c index c9290f6a7621..0ff897a01aa8 100644 --- a/sys/dev/mrsas/mrsas_cam.c +++ b/sys/dev/mrsas/mrsas_cam.c @@ -1908,13 +1908,14 @@ mrsas_track_scsiio(struct mrsas_softc *sc, target_id_t tgt_id, u_int32_t bus_id) for (i = 0 ; i < sc->max_fw_cmds; i++) { mpt_cmd = sc->mpt_cmd_list[i]; - /* - * Check if the target_id and bus_id is same as the timeout IO - */ - if (mpt_cmd->ccb_ptr) { - /* bus_id = 1 denotes a VD */ - if (bus_id == 1) - tgt_id = (mpt_cmd->ccb_ptr->ccb_h.target_id - (MRSAS_MAX_PD - 1)); + /* + * Check if the target_id and bus_id is same as the timeout IO + */ + if (mpt_cmd->ccb_ptr) { + /* bus_id = 1 denotes a VD */ + if (bus_id == 1) + tgt_id = + (mpt_cmd->ccb_ptr->ccb_h.target_id - (MRSAS_MAX_PD - 1)); if (mpt_cmd->ccb_ptr->cpi.bus_id == bus_id && mpt_cmd->ccb_ptr->ccb_h.target_id == tgt_id) { diff --git a/sys/dev/sound/pci/emu10k1.c b/sys/dev/sound/pci/emu10k1.c index 028f100c5953..94769b38faf0 100644 --- a/sys/dev/sound/pci/emu10k1.c +++ b/sys/dev/sound/pci/emu10k1.c @@ -1257,11 +1257,12 @@ emu_intr(void *data) #endif } - if (stat & EMU_IPR_MIDIRECVBUFE) - if (sc->mpu_intr) { - (sc->mpu_intr)(sc->mpu); - ack |= EMU_IPR_MIDIRECVBUFE | EMU_IPR_MIDITRANSBUFE; - } + if (stat & EMU_IPR_MIDIRECVBUFE) { + if (sc->mpu_intr) { + (sc->mpu_intr)(sc->mpu); + ack |= EMU_IPR_MIDIRECVBUFE | EMU_IPR_MIDITRANSBUFE; + } + } if (stat & ~ack) device_printf(sc->dev, "dodgy irq: %x (harmless)\n", stat & ~ack); diff --git a/sys/dev/sound/pci/emu10kx-pcm.c b/sys/dev/sound/pci/emu10kx-pcm.c index 0099b0f044d0..58d25d7e68c5 100644 --- a/sys/dev/sound/pci/emu10kx-pcm.c +++ b/sys/dev/sound/pci/emu10kx-pcm.c @@ -263,11 +263,12 @@ emu_dspmixer_uninit(struct snd_mixer *m) /* drop submixer for AC97 codec */ sc = mix_getdevinfo(m); - if (sc->sm != NULL) + if (sc->sm != NULL) { err = mixer_delete(sc->sm); if (err) return (err); sc->sm = NULL; + } return (0); } diff --git a/sys/kern/subr_stats.c b/sys/kern/subr_stats.c index a212f739deca..6181cf7bad74 100644 --- a/sys/kern/subr_stats.c +++ b/sys/kern/subr_stats.c @@ -1583,9 +1583,7 @@ stats_v1_blob_iter(struct statsblobv1 *sb, stats_v1_blob_itercb_t icb, int i, j, firstvoi; ctx.usrctx = usrctx; - ctx.flags |= SB_IT_FIRST_CB; - ctx.flags &= ~(SB_IT_FIRST_VOI | SB_IT_LAST_VOI | SB_IT_FIRST_VOISTAT | - SB_IT_LAST_VOISTAT); + ctx.flags = SB_IT_FIRST_CB; firstvoi = 1; for (i = 0; i < NVOIS(sb); i++) { From 425e5f9dcf2bc9036a5a59dde382fbb4c8ec7986 Mon Sep 17 00:00:00 2001 From: John Baldwin Date: Sun, 26 Jan 2020 14:23:27 +0000 Subject: [PATCH 19/27] Revert accidental change from r357146. --- sys/kern/subr_stats.c | 4 +++- 1 file changed, 3 insertions(+), 1 deletion(-) diff --git a/sys/kern/subr_stats.c b/sys/kern/subr_stats.c index 6181cf7bad74..a212f739deca 100644 --- a/sys/kern/subr_stats.c +++ b/sys/kern/subr_stats.c @@ -1583,7 +1583,9 @@ stats_v1_blob_iter(struct statsblobv1 *sb, stats_v1_blob_itercb_t icb, int i, j, firstvoi; ctx.usrctx = usrctx; - ctx.flags = SB_IT_FIRST_CB; + ctx.flags |= SB_IT_FIRST_CB; + ctx.flags &= ~(SB_IT_FIRST_VOI | SB_IT_LAST_VOI | SB_IT_FIRST_VOISTAT | + SB_IT_LAST_VOISTAT); firstvoi = 1; for (i = 0; i < NVOIS(sb); i++) { From 60a09a94cf15665cccf0ee1238d72399a0e94d51 Mon Sep 17 00:00:00 2001 From: Rick Macklem Date: Sun, 26 Jan 2020 17:59:05 +0000 Subject: [PATCH 20/27] Fix a crash in the NFSv4 server. The PR reported a crash that occurred when a file was removed while client(s) were actively doing lock operations on it. Since nfsvno_getvp() will return NULL when the file does not exist, the bug was obvious and easy to fix via this patch. It is a little surprising that this wasn't found sooner, but I guess the above case rarely occurs. Tested by: iron.udjin@gmail.com PR: 242768 Reported by: iron.udjin@gmail.com MFC after: 2 weeks --- sys/fs/nfsserver/nfs_nfsdstate.c | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/sys/fs/nfsserver/nfs_nfsdstate.c b/sys/fs/nfsserver/nfs_nfsdstate.c index 2a981b630e60..d2351cf4d338 100644 --- a/sys/fs/nfsserver/nfs_nfsdstate.c +++ b/sys/fs/nfsserver/nfs_nfsdstate.c @@ -1554,7 +1554,8 @@ nfsrv_freeallnfslocks(struct nfsstate *stp, vnode_t vp, int cansleep, tvp = NULL; else if (vp == NULL && cansleep != 0) { tvp = nfsvno_getvp(&lfp->lf_fh); - NFSVOPUNLOCK(tvp); + if (tvp != NULL) + NFSVOPUNLOCK(tvp); } else tvp = vp; gottvp = 1; From de27b3034012cb79278eddb18dcece0369542cb9 Mon Sep 17 00:00:00 2001 From: Vincenzo Maffione Date: Sun, 26 Jan 2020 21:34:46 +0000 Subject: [PATCH 21/27] netmap_mem_unmap: fix NULL pointer dereference MFC after: 3 days --- sys/dev/netmap/netmap_mem2.c | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/sys/dev/netmap/netmap_mem2.c b/sys/dev/netmap/netmap_mem2.c index d07c502ab6a8..01ecf6cef186 100644 --- a/sys/dev/netmap/netmap_mem2.c +++ b/sys/dev/netmap/netmap_mem2.c @@ -1523,11 +1523,12 @@ static int netmap_mem_unmap(struct netmap_obj_pool *p, struct netmap_adapter *na) { int i, lim = p->objtotal; - struct netmap_lut *lut = &na->na_lut; + struct netmap_lut *lut; if (na == NULL || na->pdev == NULL) return 0; + lut = &na->na_lut; #if defined(__FreeBSD__) /* On FreeBSD mapping and unmapping is performed by the txsync * and rxsync routine, packet by packet. */ From 8227d65b72ff6df1bacc1560cd21f138cd52bb41 Mon Sep 17 00:00:00 2001 From: Alexander Kabaev Date: Mon, 27 Jan 2020 00:14:51 +0000 Subject: [PATCH 22/27] Enter net epoch in msk_tick. One more instance of if_input being called outside of interrupt, by means of msk_handle_events. Differential Revision: https://reviews.freebsd.org/D23379 --- sys/dev/msk/if_msk.c | 3 +++ 1 file changed, 3 insertions(+) diff --git a/sys/dev/msk/if_msk.c b/sys/dev/msk/if_msk.c index 6f0f88063593..307d9aec35c7 100644 --- a/sys/dev/msk/if_msk.c +++ b/sys/dev/msk/if_msk.c @@ -3374,6 +3374,7 @@ msk_txeof(struct msk_if_softc *sc_if, int idx) static void msk_tick(void *xsc_if) { + struct epoch_tracker et; struct msk_if_softc *sc_if; struct mii_data *mii; @@ -3386,7 +3387,9 @@ msk_tick(void *xsc_if) mii_tick(mii); if ((sc_if->msk_flags & MSK_FLAG_LINK) == 0) msk_miibus_statchg(sc_if->msk_if_dev); + NET_EPOCH_ENTER(et); msk_handle_events(sc_if->msk_softc); + NET_EPOCH_EXIT(et); msk_watchdog(sc_if); callout_reset(&sc_if->msk_tick_ch, hz, msk_tick, sc_if); } From 9ea85092d93a3e993f0bad9718adc9e28fa328f8 Mon Sep 17 00:00:00 2001 From: Conrad Meyer Date: Mon, 27 Jan 2020 06:04:32 +0000 Subject: [PATCH 23/27] hwpstate(4): Log a debug line when throttled If we're going to throttle user requested P-states, we should at least produce a debug log line indicating the surprising behavior. PR: inspired by 234733 --- sys/x86/cpufreq/hwpstate_amd.c | 6 +++++- 1 file changed, 5 insertions(+), 1 deletion(-) diff --git a/sys/x86/cpufreq/hwpstate_amd.c b/sys/x86/cpufreq/hwpstate_amd.c index 71b24edcd3ad..7899370a45ec 100644 --- a/sys/x86/cpufreq/hwpstate_amd.c +++ b/sys/x86/cpufreq/hwpstate_amd.c @@ -173,8 +173,12 @@ hwpstate_goto_pstate(device_t dev, int id) /* get the current pstate limit */ msr = rdmsr(MSR_AMD_10H_11H_LIMIT); limit = AMD_10H_11H_GET_PSTATE_LIMIT(msr); - if (limit > id) + if (limit > id) { + HWPSTATE_DEBUG(dev, + "Restricting requested P%d to P%d due to HW limit\n", id, + limit); id = limit; + } cpu = curcpu; HWPSTATE_DEBUG(dev, "setting P%d-state on cpu%d\n", id, cpu); From 162ae9c834f6d9f9cb443bd62cceb23e0b5fef48 Mon Sep 17 00:00:00 2001 From: Alex Richardson Date: Mon, 27 Jan 2020 12:02:41 +0000 Subject: [PATCH 24/27] Allow bootstrapping makefs on older FreeBSD hosts and Linux/macOS In order to do so we need to install the msdosfs headers to the bootstrap sysroot and avoid includes of kernel headers that may not exist on every host (e.g. sys/lockmgr.h). This change should allow bootstrapping of makefs on FreeBSD 11+ as well as Linux and macOS. We also have to avoid using the IO_SYNC macro since that may not be available. In makefs it is only used to switch between calling bwrite() and bdwrite() which both call the same function. Therefore we can simply always call bwrite(). For our CheriBSD builds we always bootstrap makefs by setting LOCAL_XTOOL_DIRS='lib/libnetbsd usr.sbin/makefs' and use the makefs binary from the build tree to create a bootable disk image. Reviewed By: brooks Differential Revision: https://reviews.freebsd.org/D23201 --- sbin/newfs_msdos/mkfs_msdos.c | 55 ++++++++++++++++++++------ sys/fs/msdosfs/msdosfsmount.h | 4 ++ tools/build/Makefile | 20 +++++++++- usr.sbin/makefs/msdos/msdosfs_denode.c | 4 -- usr.sbin/makefs/msdos/msdosfs_vnops.c | 4 ++ 5 files changed, 71 insertions(+), 16 deletions(-) diff --git a/sbin/newfs_msdos/mkfs_msdos.c b/sbin/newfs_msdos/mkfs_msdos.c index ac95db66cc91..77e8b19d3338 100644 --- a/sbin/newfs_msdos/mkfs_msdos.c +++ b/sbin/newfs_msdos/mkfs_msdos.c @@ -31,10 +31,15 @@ static const char rcsid[] = #endif /* not lint */ #include +#ifdef MAKEFS +/* In the makefs case we only want struct disklabel */ +#include +#else #include #include #include #include +#endif #include #include @@ -285,14 +290,18 @@ mkfs_msdos(const char *fname, const char *dtype, const struct msdos_options *op) if (!S_ISREG(sb.st_mode)) warnx("warning, %s is not a regular file", fname); } else { -#ifndef MAKEFS +#ifdef MAKEFS + errx(1, "o.create_size must be set!"); +#else if (!S_ISCHR(sb.st_mode)) warnx("warning, %s is not a character device", fname); #endif } +#ifndef MAKEFS if (!o.no_create) if (check_mounted(fname, sb.st_mode) == -1) goto done; +#endif if (o.offset && o.offset != lseek(fd, o.offset, SEEK_SET)) { warnx("cannot seek to %jd", (intmax_t)o.offset); goto done; @@ -621,10 +630,12 @@ mkfs_msdos(const char *fname, const char *dtype, const struct msdos_options *op) bpb.bpbBigFATsecs) * bpb.bpbFATs; memset(&si_sa, 0, sizeof(si_sa)); si_sa.sa_handler = infohandler; +#ifdef SIGINFO if (sigaction(SIGINFO, &si_sa, NULL) == -1) { warn("sigaction SIGINFO"); goto done; } +#endif for (lsn = 0; lsn < dir + (fat == 32 ? bpb.bpbSecPerClust : rds); lsn++) { if (got_siginfo) { fprintf(stderr,"%s: writing sector %u of %u (%u%%)\n", @@ -766,6 +777,11 @@ mkfs_msdos(const char *fname, const char *dtype, const struct msdos_options *op) static int check_mounted(const char *fname, mode_t mode) { +/* + * If getmntinfo() is not available (e.g. Linux) don't check. This should + * not be a problem since we will only be using makefs to create images. + */ +#if !defined(MAKEFS) struct statfs *mp; const char *s1, *s2; size_t len; @@ -790,6 +806,7 @@ check_mounted(const char *fname, mode_t mode) return -1; } } +#endif return 0; } @@ -811,6 +828,23 @@ getstdfmt(const char *fmt, struct bpb *bpb) return 0; } +static void +compute_geometry_from_file(int fd, const char *fname, struct disklabel *lp) +{ + struct stat st; + off_t ms; + + if (fstat(fd, &st)) + err(1, "cannot get disk size"); + if (!S_ISREG(st.st_mode)) + errx(1, "%s is not a regular file", fname); + ms = st.st_size; + lp->d_secsize = 512; + lp->d_nsectors = 63; + lp->d_ntracks = 255; + lp->d_secperunit = ms / lp->d_secsize; +} + /* * Get disk slice, partition, and geometry information. */ @@ -819,8 +853,10 @@ getdiskinfo(int fd, const char *fname, const char *dtype, __unused int oflag, struct bpb *bpb) { struct disklabel *lp, dlp; + off_t hs = 0; +#ifndef MAKEFS + off_t ms; struct fd_type type; - off_t ms, hs = 0; lp = NULL; @@ -832,16 +868,8 @@ getdiskinfo(int fd, const char *fname, const char *dtype, __unused int oflag, /* Maybe it's a floppy drive */ if (lp == NULL) { if (ioctl(fd, DIOCGMEDIASIZE, &ms) == -1) { - struct stat st; - - if (fstat(fd, &st)) - err(1, "cannot get disk size"); /* create a fake geometry for a file image */ - ms = st.st_size; - dlp.d_secsize = 512; - dlp.d_nsectors = 63; - dlp.d_ntracks = 255; - dlp.d_secperunit = ms / dlp.d_secsize; + compute_geometry_from_file(fd, fname, &dlp); lp = &dlp; } else if (ioctl(fd, FD_GTYPE, &type) != -1) { dlp.d_secsize = 128 << type.secsize; @@ -881,6 +909,11 @@ getdiskinfo(int fd, const char *fname, const char *dtype, __unused int oflag, hs = (ms / dlp.d_secsize) - dlp.d_secperunit; lp = &dlp; } +#else + /* In the makefs case we only support image files: */ + compute_geometry_from_file(fd, fname, &dlp); + lp = &dlp; +#endif if (bpb->bpbBytesPerSec == 0) { if (ckgeom(fname, lp->d_secsize, "bytes/sector") == -1) diff --git a/sys/fs/msdosfs/msdosfsmount.h b/sys/fs/msdosfs/msdosfsmount.h index f334a0b7908b..6bdcee1ea855 100644 --- a/sys/fs/msdosfs/msdosfsmount.h +++ b/sys/fs/msdosfs/msdosfsmount.h @@ -56,8 +56,10 @@ #if defined (_KERNEL) || defined(MAKEFS) #include +#ifndef MAKEFS #include #include +#endif #include #ifdef MALLOC_DECLARE @@ -110,7 +112,9 @@ struct msdosfsmount { void *pm_w2u; /* Unicode->Local iconv handle */ void *pm_u2d; /* Unicode->DOS iconv handle */ void *pm_d2u; /* DOS->Local iconv handle */ +#ifndef MAKEFS struct lock pm_fatlock; /* lockmgr protecting allocations */ +#endif }; /* diff --git a/tools/build/Makefile b/tools/build/Makefile index 87916eb2c398..b815c77061db 100644 --- a/tools/build/Makefile +++ b/tools/build/Makefile @@ -4,11 +4,16 @@ LIB= egacy SRC= -INCSGROUPS= INCS SYSINCS CASPERINC +INCSGROUPS= INCS SYSINCS CASPERINC UFSINCS FFSINCS MSDOSFSINCS DISKINCS INCS= SYSINCSDIR= ${INCLUDEDIR}/sys CASPERINCDIR= ${INCLUDEDIR}/casper +# Also add ufs/ffs/msdosfs/disk headers to allow building makefs as a bootstrap tool +UFSINCSDIR= ${INCLUDEDIR}/ufs/ufs +FFSINCSDIR= ${INCLUDEDIR}/ufs/ffs +MSDOSFSINCSDIR= ${INCLUDEDIR}/fs/msdosfs +DISKINCSDIR= ${INCLUDEDIR}/sys/disk BOOTSTRAPPING?= 0 @@ -70,6 +75,19 @@ SRCS= dummy.c SUBDIR= cross-build .endif +# To allow bootstrapping makefs on FreeBSD 11 or non-FreeBSD systems: +UFSINCS+= ${SRCTOP}/sys/ufs/ufs/dinode.h +UFSINCS+= ${SRCTOP}/sys/ufs/ufs/dir.h +FFSINCS+= ${SRCTOP}/sys/ufs/ffs/fs.h + +MSDOSFSINCS+= ${SRCTOP}/sys/fs/msdosfs/bootsect.h +MSDOSFSINCS+= ${SRCTOP}/sys/fs/msdosfs/bpb.h +MSDOSFSINCS+= ${SRCTOP}/sys/fs/msdosfs/denode.h +MSDOSFSINCS+= ${SRCTOP}/sys/fs/msdosfs/direntry.h +MSDOSFSINCS+= ${SRCTOP}/sys/fs/msdosfs/fat.h +MSDOSFSINCS+= ${SRCTOP}/sys/fs/msdosfs/msdosfsmount.h +DISKINCS+= ${SRCTOP}/sys/sys/disk/bsd.h + # Needed to build config (since it uses libnv) SYSINCS+= ${SRCTOP}/sys/sys/nv.h ${SRCTOP}/sys/sys/cnv.h \ ${SRCTOP}/sys/sys/dnv.h diff --git a/usr.sbin/makefs/msdos/msdosfs_denode.c b/usr.sbin/makefs/msdos/msdosfs_denode.c index dc6b05f2a42f..96c892caaa7b 100644 --- a/usr.sbin/makefs/msdos/msdosfs_denode.c +++ b/usr.sbin/makefs/msdos/msdosfs_denode.c @@ -54,7 +54,6 @@ __FBSDID("$FreeBSD$"); #include #include -#include #include #include @@ -288,10 +287,7 @@ detrunc(struct denode *dep, u_long length, int flags, struct ucred *cred) return (error); } memset(bp->b_data + boff, 0, pmp->pm_bpcluster - boff); - if (flags & IO_SYNC) bwrite(bp); - else - bdwrite(bp); } } diff --git a/usr.sbin/makefs/msdos/msdosfs_vnops.c b/usr.sbin/makefs/msdos/msdosfs_vnops.c index dcdfc4966f55..703482f75b45 100644 --- a/usr.sbin/makefs/msdos/msdosfs_vnops.c +++ b/usr.sbin/makefs/msdos/msdosfs_vnops.c @@ -103,7 +103,11 @@ msdosfs_times(struct denode *dep, const struct stat *st) if (stampst.st_ino) st = &stampst; +#ifdef HAVE_STRUCT_STAT_BIRTHTIME unix2fattime(&st->st_birthtim, &dep->de_CDate, &dep->de_CTime); +#else + unix2fattime(&st->st_ctim, &dep->de_CDate, &dep->de_CTime); +#endif unix2fattime(&st->st_atim, &dep->de_ADate, NULL); unix2fattime(&st->st_mtim, &dep->de_MDate, &dep->de_MTime); } From d2c32def56f4952cb283ac70fa4be787c6a5eb4b Mon Sep 17 00:00:00 2001 From: Alex Richardson Date: Mon, 27 Jan 2020 12:02:47 +0000 Subject: [PATCH 25/27] Build hard-float lib32 for mips64hf/mips64elhf This should fix linker errors when building with clang+lld. After this change the lib32 compat libraries are now buildt with -mhard-float instead of -msoft-float Reviewed By: brooks, jhb Differential Revision: https://reviews.freebsd.org/D23229 --- share/mk/bsd.compat.mk | 3 +-- 1 file changed, 1 insertion(+), 2 deletions(-) diff --git a/share/mk/bsd.compat.mk b/share/mk/bsd.compat.mk index 0f3a2421b040..47c8ec65c88f 100644 --- a/share/mk/bsd.compat.mk +++ b/share/mk/bsd.compat.mk @@ -79,11 +79,10 @@ LIB32CPUFLAGS= -target mips-unknown-freebsd13.0 .endif LIB32CPUFLAGS+= -mabi=32 LIB32_MACHINE= mips +LIB32_MACHINE_ARCH:= ${COMPAT_ARCH:S/64//} .if ${COMPAT_ARCH:Mmips64el*} != "" -LIB32_MACHINE_ARCH= mipsel _EMULATION= elf32ltsmip_fbsd .else -LIB32_MACHINE_ARCH= mips _EMULATION= elf32btsmip_fbsd .endif LIB32WMAKEFLAGS= LD="${XLD} -m ${_EMULATION}" From fd99699d7ef13a361f452c6c339302f6919ffcb0 Mon Sep 17 00:00:00 2001 From: Konstantin Belousov Date: Mon, 27 Jan 2020 13:15:16 +0000 Subject: [PATCH 26/27] Fix aggregating geoms for BIO_SPEEDUP. If the bio was split into several bios going down, completion computes bio_completed of the original bio as sum of the bio_completes of the splits. For BIO_SETUP, bio_length means something different than the length. it is the requested speedup amount, and is duplicated into the splits, which is in fact reasonable, since we cannot know how the previous activity was distributed among subordinate geoms. Obviously, the sum of n bio_length is greater than bio_length for n > 1, which triggers assert that bio_length >= bio_completed for e.g. geom_stripe and geom_raid3. Fix this by reassigning bio_completed from bio_length for completed BIO_SPEEDED, I do not think it really mattters what we return in bio_completed. Reported and tested by: pho Reviewed by: imp MFC after: 1 week Differential revision: https://reviews.freebsd.org/D23380 --- sys/geom/geom_subr.c | 5 ++++- sys/geom/stripe/g_stripe.c | 2 ++ 2 files changed, 6 insertions(+), 1 deletion(-) diff --git a/sys/geom/geom_subr.c b/sys/geom/geom_subr.c index eba0a0244ce2..f08d049db7c4 100644 --- a/sys/geom/geom_subr.c +++ b/sys/geom/geom_subr.c @@ -1134,8 +1134,11 @@ g_std_done(struct bio *bp) bp2->bio_completed += bp->bio_completed; g_destroy_bio(bp); bp2->bio_inbed++; - if (bp2->bio_children == bp2->bio_inbed) + if (bp2->bio_children == bp2->bio_inbed) { + if (bp2->bio_cmd == BIO_SPEEDUP) + bp2->bio_completed = bp2->bio_length; g_io_deliver(bp2, bp2->bio_error); + } } /* XXX: maybe this is only g_slice_spoiled */ diff --git a/sys/geom/stripe/g_stripe.c b/sys/geom/stripe/g_stripe.c index b5479201818e..df226650de29 100644 --- a/sys/geom/stripe/g_stripe.c +++ b/sys/geom/stripe/g_stripe.c @@ -298,6 +298,8 @@ g_stripe_done(struct bio *bp) mtx_unlock(&sc->sc_lock); if (pbp->bio_driver1 != NULL) uma_zfree(g_stripe_zone, pbp->bio_driver1); + if (bp->bio_cmd == BIO_SPEEDUP) + pbp->bio_completed = pbp->bio_length; g_io_deliver(pbp, pbp->bio_error); } else mtx_unlock(&sc->sc_lock); From f886c4ba71aeb85dc88bec62709884526320338f Mon Sep 17 00:00:00 2001 From: Doug Moore Date: Mon, 27 Jan 2020 15:09:13 +0000 Subject: [PATCH 27/27] Correct the use of RB_AUGMENT in the RB_TREE macros so that is invoked at the root of every subtree that changes in an insert or delete, and only once, and ordered from the bottom of the tree to the top. For intel_gas.c, the only user of RB_AUGMENT I can find, change the augmenting routine so that it does not climb from entry to tree root on every call, and remove a 'tree correcting' function that can be supplanted by proper tree augmentation. Reviewed by: kib Tested by: pho Differential Revision: https://reviews.freebsd.org/D23189 --- sys/sys/tree.h | 88 ++++++-------- sys/x86/iommu/intel_dmar.h | 3 +- sys/x86/iommu/intel_drv.c | 6 +- sys/x86/iommu/intel_gas.c | 237 ++++++++++++++----------------------- 4 files changed, 131 insertions(+), 203 deletions(-) diff --git a/sys/sys/tree.h b/sys/sys/tree.h index 7d09e2236d9b..df85b0587570 100644 --- a/sys/sys/tree.h +++ b/sys/sys/tree.h @@ -335,8 +335,12 @@ struct { \ RB_COLOR(red, field) = RB_RED; \ } while (/*CONSTCOND*/ 0) +/* + * Something to be invoked in a loop at the root of every modified subtree, + * from the bottom up to the root, to update augmented node data. + */ #ifndef RB_AUGMENT -#define RB_AUGMENT(x) do {} while (0) +#define RB_AUGMENT(x) break #endif #define RB_ROTATE_LEFT(head, elm, tmp, field) do { \ @@ -344,7 +348,6 @@ struct { \ if ((RB_RIGHT(elm, field) = RB_LEFT(tmp, field)) != NULL) { \ RB_PARENT(RB_LEFT(tmp, field), field) = (elm); \ } \ - RB_AUGMENT(elm); \ if ((RB_PARENT(tmp, field) = RB_PARENT(elm, field)) != NULL) { \ if ((elm) == RB_LEFT(RB_PARENT(elm, field), field)) \ RB_LEFT(RB_PARENT(elm, field), field) = (tmp); \ @@ -354,9 +357,7 @@ struct { \ (head)->rbh_root = (tmp); \ RB_LEFT(tmp, field) = (elm); \ RB_PARENT(elm, field) = (tmp); \ - RB_AUGMENT(tmp); \ - if ((RB_PARENT(tmp, field))) \ - RB_AUGMENT(RB_PARENT(tmp, field)); \ + RB_AUGMENT(elm); \ } while (/*CONSTCOND*/ 0) #define RB_ROTATE_RIGHT(head, elm, tmp, field) do { \ @@ -364,7 +365,6 @@ struct { \ if ((RB_LEFT(elm, field) = RB_RIGHT(tmp, field)) != NULL) { \ RB_PARENT(RB_RIGHT(tmp, field), field) = (elm); \ } \ - RB_AUGMENT(elm); \ if ((RB_PARENT(tmp, field) = RB_PARENT(elm, field)) != NULL) { \ if ((elm) == RB_LEFT(RB_PARENT(elm, field), field)) \ RB_LEFT(RB_PARENT(elm, field), field) = (tmp); \ @@ -374,9 +374,7 @@ struct { \ (head)->rbh_root = (tmp); \ RB_RIGHT(tmp, field) = (elm); \ RB_PARENT(elm, field) = (tmp); \ - RB_AUGMENT(tmp); \ - if ((RB_PARENT(tmp, field))) \ - RB_AUGMENT(RB_PARENT(tmp, field)); \ + RB_AUGMENT(elm); \ } while (/*CONSTCOND*/ 0) /* Generates prototypes and inline functions */ @@ -571,62 +569,49 @@ name##_RB_REMOVE(struct name *head, struct type *elm) \ else if (RB_RIGHT(elm, field) == NULL) \ child = RB_LEFT(elm, field); \ else { \ - struct type *left; \ - elm = RB_RIGHT(elm, field); \ - while ((left = RB_LEFT(elm, field)) != NULL) \ - elm = left; \ - child = RB_RIGHT(elm, field); \ - parent = RB_PARENT(elm, field); \ - color = RB_COLOR(elm, field); \ - if (child) \ - RB_PARENT(child, field) = parent; \ - if (parent) { \ - if (RB_LEFT(parent, field) == elm) \ - RB_LEFT(parent, field) = child; \ + elm = RB_RIGHT(old, field); \ + if ((child = RB_LEFT(elm, field)) == NULL) { \ + child = RB_RIGHT(elm, field); \ + RB_RIGHT(old, field) = child; \ + RB_PARENT(elm, field) = elm; \ + } else { \ + do \ + elm = child; \ + while ((child = RB_LEFT(elm, field)) != NULL); \ + child = RB_RIGHT(elm, field); \ + RB_PARENT(RB_RIGHT(old, field), field) = elm; \ + } \ + RB_PARENT(RB_LEFT(old, field), field) = elm; \ + parent = RB_PARENT(old, field); \ + if (parent != NULL) { \ + if (RB_LEFT(parent, field) == old) \ + RB_LEFT(parent, field) = elm; \ else \ - RB_RIGHT(parent, field) = child; \ - RB_AUGMENT(parent); \ - } else \ - RB_ROOT(head) = child; \ - if (RB_PARENT(elm, field) == old) \ - parent = elm; \ - (elm)->field = (old)->field; \ - if (RB_PARENT(old, field)) { \ - if (RB_LEFT(RB_PARENT(old, field), field) == old)\ - RB_LEFT(RB_PARENT(old, field), field) = elm;\ - else \ - RB_RIGHT(RB_PARENT(old, field), field) = elm;\ - RB_AUGMENT(RB_PARENT(old, field)); \ + RB_RIGHT(parent, field) = elm; \ } else \ RB_ROOT(head) = elm; \ - RB_PARENT(RB_LEFT(old, field), field) = elm; \ - if (RB_RIGHT(old, field)) \ - RB_PARENT(RB_RIGHT(old, field), field) = elm; \ - if (parent) { \ - left = parent; \ - do { \ - RB_AUGMENT(left); \ - } while ((left = RB_PARENT(left, field)) != NULL); \ - } \ - goto color; \ } \ parent = RB_PARENT(elm, field); \ color = RB_COLOR(elm, field); \ - if (child) \ + if (child != NULL) \ RB_PARENT(child, field) = parent; \ - if (parent) { \ + if (parent != NULL) { \ if (RB_LEFT(parent, field) == elm) \ RB_LEFT(parent, field) = child; \ else \ RB_RIGHT(parent, field) = child; \ - RB_AUGMENT(parent); \ } else \ RB_ROOT(head) = child; \ -color: \ + if (elm != old) \ + (elm)->field = (old)->field; \ if (color == RB_BLACK) \ name##_RB_REMOVE_COLOR(head, parent, child); \ + while (parent != NULL) { \ + RB_AUGMENT(parent); \ + parent = RB_PARENT(parent, field); \ + } \ return (old); \ -} \ +} #define RB_GENERATE_INSERT(name, type, field, cmp, attr) \ /* Inserts a node into the RB tree */ \ @@ -653,10 +638,13 @@ name##_RB_INSERT(struct name *head, struct type *elm) \ RB_LEFT(parent, field) = elm; \ else \ RB_RIGHT(parent, field) = elm; \ - RB_AUGMENT(parent); \ } else \ RB_ROOT(head) = elm; \ name##_RB_INSERT_COLOR(head, elm); \ + while (elm != NULL) { \ + RB_AUGMENT(elm); \ + elm = RB_PARENT(elm, field); \ + } \ return (NULL); \ } diff --git a/sys/x86/iommu/intel_dmar.h b/sys/x86/iommu/intel_dmar.h index 3ed137eae4b4..da610cee89d1 100644 --- a/sys/x86/iommu/intel_dmar.h +++ b/sys/x86/iommu/intel_dmar.h @@ -47,7 +47,8 @@ struct dmar_qi_genseq { struct dmar_map_entry { dmar_gaddr_t start; dmar_gaddr_t end; - dmar_gaddr_t free_after; /* Free space after the entry */ + dmar_gaddr_t first; /* Least start in subtree */ + dmar_gaddr_t last; /* Greatest end in subtree */ dmar_gaddr_t free_down; /* Max free space below the current R/B tree node */ u_int flags; diff --git a/sys/x86/iommu/intel_drv.c b/sys/x86/iommu/intel_drv.c index 0805ca96537a..48815bbe5ae1 100644 --- a/sys/x86/iommu/intel_drv.c +++ b/sys/x86/iommu/intel_drv.c @@ -1112,9 +1112,9 @@ dmar_print_domain_entry(const struct dmar_map_entry *entry) struct dmar_map_entry *l, *r; db_printf( - " start %jx end %jx free_after %jx free_down %jx flags %x ", - entry->start, entry->end, entry->free_after, entry->free_down, - entry->flags); + " start %jx end %jx first %jx last %jx free_down %jx flags %x ", + entry->start, entry->end, entry->first, entry->last, + entry->free_down, entry->flags); db_printf("left "); l = RB_LEFT(entry, rb_entry); if (l == NULL) diff --git a/sys/x86/iommu/intel_gas.c b/sys/x86/iommu/intel_gas.c index b2b388174881..ec92deed98ff 100644 --- a/sys/x86/iommu/intel_gas.c +++ b/sys/x86/iommu/intel_gas.c @@ -139,71 +139,52 @@ dmar_gas_cmp_entries(struct dmar_map_entry *a, struct dmar_map_entry *b) static void dmar_gas_augment_entry(struct dmar_map_entry *entry) { - struct dmar_map_entry *l, *r; + struct dmar_map_entry *child; + dmar_gaddr_t free_down; - for (; entry != NULL; entry = RB_PARENT(entry, rb_entry)) { - l = RB_LEFT(entry, rb_entry); - r = RB_RIGHT(entry, rb_entry); - if (l == NULL && r == NULL) { - entry->free_down = entry->free_after; - } else if (l == NULL && r != NULL) { - entry->free_down = MAX(entry->free_after, r->free_down); - } else if (/*l != NULL && */ r == NULL) { - entry->free_down = MAX(entry->free_after, l->free_down); - } else /* if (l != NULL && r != NULL) */ { - entry->free_down = MAX(entry->free_after, l->free_down); - entry->free_down = MAX(entry->free_down, r->free_down); - } - } + free_down = 0; + if ((child = RB_LEFT(entry, rb_entry)) != NULL) { + free_down = MAX(free_down, child->free_down); + free_down = MAX(free_down, entry->start - child->last); + entry->first = child->first; + } else + entry->first = entry->start; + + if ((child = RB_RIGHT(entry, rb_entry)) != NULL) { + free_down = MAX(free_down, child->free_down); + free_down = MAX(free_down, child->first - entry->end); + entry->last = child->last; + } else + entry->last = entry->end; + entry->free_down = free_down; } RB_GENERATE(dmar_gas_entries_tree, dmar_map_entry, rb_entry, dmar_gas_cmp_entries); -static void -dmar_gas_fix_free(struct dmar_domain *domain, struct dmar_map_entry *entry) -{ - struct dmar_map_entry *next; - - next = RB_NEXT(dmar_gas_entries_tree, &domain->rb_root, entry); - entry->free_after = (next != NULL ? next->start : domain->end) - - entry->end; - dmar_gas_augment_entry(entry); -} - #ifdef INVARIANTS static void dmar_gas_check_free(struct dmar_domain *domain) { - struct dmar_map_entry *entry, *next, *l, *r; + struct dmar_map_entry *entry, *l, *r; dmar_gaddr_t v; RB_FOREACH(entry, dmar_gas_entries_tree, &domain->rb_root) { KASSERT(domain == entry->domain, ("mismatched free domain %p entry %p entry->domain %p", domain, entry, entry->domain)); - next = RB_NEXT(dmar_gas_entries_tree, &domain->rb_root, entry); - if (next == NULL) { - MPASS(entry->free_after == domain->end - entry->end); - } else { - MPASS(entry->free_after = next->start - entry->end); - MPASS(entry->end <= next->start); - } l = RB_LEFT(entry, rb_entry); r = RB_RIGHT(entry, rb_entry); - if (l == NULL && r == NULL) { - MPASS(entry->free_down == entry->free_after); - } else if (l == NULL && r != NULL) { - MPASS(entry->free_down = MAX(entry->free_after, - r->free_down)); - } else if (r == NULL) { - MPASS(entry->free_down = MAX(entry->free_after, - l->free_down)); - } else { - v = MAX(entry->free_after, l->free_down); - v = MAX(v, r->free_down); - MPASS(entry->free_down == v); + v = 0; + if (l != NULL) { + v = MAX(v, l->free_down); + v = MAX(v, entry->start - l->last); } + if (r != NULL) { + v = MAX(v, r->free_down); + v = MAX(v, r->first - entry->end); + } + MPASS(entry->free_down == v); } } #endif @@ -211,25 +192,17 @@ dmar_gas_check_free(struct dmar_domain *domain) static bool dmar_gas_rb_insert(struct dmar_domain *domain, struct dmar_map_entry *entry) { - struct dmar_map_entry *prev, *found; + struct dmar_map_entry *found; found = RB_INSERT(dmar_gas_entries_tree, &domain->rb_root, entry); - dmar_gas_fix_free(domain, entry); - prev = RB_PREV(dmar_gas_entries_tree, &domain->rb_root, entry); - if (prev != NULL) - dmar_gas_fix_free(domain, prev); return (found == NULL); } static void dmar_gas_rb_remove(struct dmar_domain *domain, struct dmar_map_entry *entry) { - struct dmar_map_entry *prev; - prev = RB_PREV(dmar_gas_entries_tree, &domain->rb_root, entry); RB_REMOVE(dmar_gas_entries_tree, &domain->rb_root, entry); - if (prev != NULL) - dmar_gas_fix_free(domain, prev); } void @@ -246,13 +219,11 @@ dmar_gas_init_domain(struct dmar_domain *domain) begin->start = 0; begin->end = DMAR_PAGE_SIZE; - begin->free_after = domain->end - begin->end; begin->flags = DMAR_MAP_ENTRY_PLACE | DMAR_MAP_ENTRY_UNMAPPED; dmar_gas_rb_insert(domain, begin); end->start = domain->end; end->end = domain->end; - end->free_after = 0; end->flags = DMAR_MAP_ENTRY_PLACE | DMAR_MAP_ENTRY_UNMAPPED; dmar_gas_rb_insert(domain, end); @@ -281,7 +252,6 @@ dmar_gas_fini_domain(struct dmar_domain *domain) entry = RB_MAX(dmar_gas_entries_tree, &domain->rb_root); KASSERT(entry->start == domain->end, ("end entry start %p", domain)); KASSERT(entry->end == domain->end, ("end entry end %p", domain)); - KASSERT(entry->free_after == 0, ("end entry free_after %p", domain)); KASSERT(entry->flags == DMAR_MAP_ENTRY_PLACE, ("end entry flags %p", domain)); RB_REMOVE(dmar_gas_entries_tree, &domain->rb_root, entry); @@ -305,19 +275,26 @@ struct dmar_gas_match_args { struct dmar_map_entry *entry; }; +/* + * The interval [beg, end) is a free interval between two dmar_map_entries. + * maxaddr is an upper bound on addresses that can be allocated. Try to + * allocate space in the free interval, subject to the conditions expressed + * by a, and return 'true' if and only if the allocation attempt succeeds. + */ static bool -dmar_gas_match_one(struct dmar_gas_match_args *a, struct dmar_map_entry *prev, - dmar_gaddr_t end) +dmar_gas_match_one(struct dmar_gas_match_args *a, dmar_gaddr_t beg, + dmar_gaddr_t end, dmar_gaddr_t maxaddr) { dmar_gaddr_t bs, start; - if (a->entry->start + a->size > end) + a->entry->start = roundup2(beg + DMAR_PAGE_SIZE, + a->common->alignment); + if (a->entry->start + a->size > maxaddr) return (false); /* DMAR_PAGE_SIZE to create gap after new entry. */ - if (a->entry->start < prev->end + DMAR_PAGE_SIZE || - a->entry->start + a->size + a->offset + DMAR_PAGE_SIZE > - prev->end + prev->free_after) + if (a->entry->start < beg + DMAR_PAGE_SIZE || + a->entry->start + a->size + a->offset + DMAR_PAGE_SIZE > end) return (false); /* No boundary crossing. */ @@ -328,15 +305,14 @@ dmar_gas_match_one(struct dmar_gas_match_args *a, struct dmar_map_entry *prev, /* * The start + offset to start + offset + size region crosses * the boundary. Check if there is enough space after the - * next boundary after the prev->end. + * next boundary after the beg. */ bs = rounddown2(a->entry->start + a->offset + a->common->boundary, a->common->boundary); start = roundup2(bs, a->common->alignment); /* DMAR_PAGE_SIZE to create gap after new entry. */ - if (start + a->offset + a->size + DMAR_PAGE_SIZE <= - prev->end + prev->free_after && - start + a->offset + a->size <= end && + if (start + a->offset + a->size + DMAR_PAGE_SIZE <= end && + start + a->offset + a->size <= maxaddr && dmar_test_boundary(start + a->offset, a->size, a->common->boundary)) { a->entry->start = start; @@ -346,7 +322,7 @@ dmar_gas_match_one(struct dmar_gas_match_args *a, struct dmar_map_entry *prev, /* * Not enough space to align at the requested boundary, or * boundary is smaller than the size, but allowed to split. - * We already checked that start + size does not overlap end. + * We already checked that start + size does not overlap maxaddr. * * XXXKIB. It is possible that bs is exactly at the start of * the next entry, then we do not have gap. Ignore for now. @@ -360,10 +336,8 @@ dmar_gas_match_one(struct dmar_gas_match_args *a, struct dmar_map_entry *prev, } static void -dmar_gas_match_insert(struct dmar_gas_match_args *a, - struct dmar_map_entry *prev) +dmar_gas_match_insert(struct dmar_gas_match_args *a) { - struct dmar_map_entry *next; bool found; /* @@ -376,102 +350,67 @@ dmar_gas_match_insert(struct dmar_gas_match_args *a, */ a->entry->end = a->entry->start + a->size; - next = RB_NEXT(dmar_gas_entries_tree, &a->domain->rb_root, prev); - KASSERT(next->start >= a->entry->end && - next->start - a->entry->start >= a->size && - prev->end <= a->entry->end, - ("dmar_gas_match_insert hole failed %p prev (%jx, %jx) " - "free_after %jx next (%jx, %jx) entry (%jx, %jx)", a->domain, - (uintmax_t)prev->start, (uintmax_t)prev->end, - (uintmax_t)prev->free_after, - (uintmax_t)next->start, (uintmax_t)next->end, - (uintmax_t)a->entry->start, (uintmax_t)a->entry->end)); - - prev->free_after = a->entry->start - prev->end; - a->entry->free_after = next->start - a->entry->end; - found = dmar_gas_rb_insert(a->domain, a->entry); KASSERT(found, ("found dup %p start %jx size %jx", a->domain, (uintmax_t)a->entry->start, (uintmax_t)a->size)); a->entry->flags = DMAR_MAP_ENTRY_MAP; - - KASSERT(RB_PREV(dmar_gas_entries_tree, &a->domain->rb_root, - a->entry) == prev, - ("entry %p prev %p inserted prev %p", a->entry, prev, - RB_PREV(dmar_gas_entries_tree, &a->domain->rb_root, a->entry))); - KASSERT(RB_NEXT(dmar_gas_entries_tree, &a->domain->rb_root, - a->entry) == next, - ("entry %p next %p inserted next %p", a->entry, next, - RB_NEXT(dmar_gas_entries_tree, &a->domain->rb_root, a->entry))); } static int -dmar_gas_lowermatch(struct dmar_gas_match_args *a, struct dmar_map_entry *prev) +dmar_gas_lowermatch(struct dmar_gas_match_args *a, struct dmar_map_entry *entry) { - struct dmar_map_entry *l; - int ret; + struct dmar_map_entry *child; - if (prev->end < a->common->lowaddr) { - a->entry->start = roundup2(prev->end + DMAR_PAGE_SIZE, - a->common->alignment); - if (dmar_gas_match_one(a, prev, a->common->lowaddr)) { - dmar_gas_match_insert(a, prev); - return (0); - } + child = RB_RIGHT(entry, rb_entry); + if (child != NULL && entry->end < a->common->lowaddr && + dmar_gas_match_one(a, entry->end, child->first, + a->common->lowaddr)) { + dmar_gas_match_insert(a); + return (0); } - if (prev->free_down < a->size + a->offset + DMAR_PAGE_SIZE) + if (entry->free_down < a->size + a->offset + DMAR_PAGE_SIZE) return (ENOMEM); - l = RB_LEFT(prev, rb_entry); - if (l != NULL) { - ret = dmar_gas_lowermatch(a, l); - if (ret == 0) - return (0); + child = RB_LEFT(entry, rb_entry); + if (child != NULL && 0 == dmar_gas_lowermatch(a, child)) + return (0); + if (child != NULL && child->last < a->common->lowaddr && + dmar_gas_match_one(a, child->last, entry->start, + a->common->lowaddr)) { + dmar_gas_match_insert(a); + return (0); } - l = RB_RIGHT(prev, rb_entry); - if (l != NULL) - return (dmar_gas_lowermatch(a, l)); + child = RB_RIGHT(entry, rb_entry); + if (child != NULL && 0 == dmar_gas_lowermatch(a, child)) + return (0); return (ENOMEM); } static int -dmar_gas_uppermatch(struct dmar_gas_match_args *a) +dmar_gas_uppermatch(struct dmar_gas_match_args *a, struct dmar_map_entry *entry) { - struct dmar_map_entry *next, *prev, find_entry; + struct dmar_map_entry *child; - find_entry.start = a->common->highaddr; - next = RB_NFIND(dmar_gas_entries_tree, &a->domain->rb_root, - &find_entry); - if (next == NULL) + if (entry->last < a->common->highaddr) return (ENOMEM); - prev = RB_PREV(dmar_gas_entries_tree, &a->domain->rb_root, next); - KASSERT(prev != NULL, ("no prev %p %jx", a->domain, - (uintmax_t)find_entry.start)); - for (;;) { - a->entry->start = prev->start + DMAR_PAGE_SIZE; - if (a->entry->start < a->common->highaddr) - a->entry->start = a->common->highaddr; - a->entry->start = roundup2(a->entry->start, - a->common->alignment); - if (dmar_gas_match_one(a, prev, a->domain->end)) { - dmar_gas_match_insert(a, prev); - return (0); - } - - /* - * XXXKIB. This falls back to linear iteration over - * the free space in the high region. But high - * regions are almost unused, the code should be - * enough to cover the case, although in the - * non-optimal way. - */ - prev = next; - next = RB_NEXT(dmar_gas_entries_tree, &a->domain->rb_root, - prev); - KASSERT(next != NULL, ("no next %p %jx", a->domain, - (uintmax_t)find_entry.start)); - if (next->end >= a->domain->end) - return (ENOMEM); + child = RB_LEFT(entry, rb_entry); + if (child != NULL && 0 == dmar_gas_uppermatch(a, child)) + return (0); + if (child != NULL && child->last >= a->common->highaddr && + dmar_gas_match_one(a, child->last, entry->start, + a->domain->end)) { + dmar_gas_match_insert(a); + return (0); } + child = RB_RIGHT(entry, rb_entry); + if (child != NULL && entry->end >= a->common->highaddr && + dmar_gas_match_one(a, entry->end, child->first, + a->domain->end)) { + dmar_gas_match_insert(a); + return (0); + } + if (child != NULL && 0 == dmar_gas_uppermatch(a, child)) + return (0); + return (ENOMEM); } static int @@ -504,7 +443,7 @@ dmar_gas_find_space(struct dmar_domain *domain, /* Handle upper region. */ if (common->highaddr >= domain->end) return (ENOMEM); - error = dmar_gas_uppermatch(&a); + error = dmar_gas_uppermatch(&a, RB_ROOT(&domain->rb_root)); KASSERT(error == ENOMEM, ("error %d from dmar_gas_uppermatch", error)); return (error);