From mdounin at mdounin.ru Thu May 8 14:33:56 2025 From: mdounin at mdounin.ru (=?iso-8859-1?q?Maxim_Dounin?=) Date: Thu, 08 May 2025 17:33:56 +0300 Subject: [nginx] Version bump. Message-ID: details: http://freenginx.org/hg/nginx/rev/e207e1565eca branches: changeset: 9350:e207e1565eca user: Maxim Dounin date: Thu May 08 17:28:23 2025 +0300 description: Version bump. diffstat: src/core/nginx.h | 4 ++-- 1 files changed, 2 insertions(+), 2 deletions(-) diffs (14 lines): diff --git a/src/core/nginx.h b/src/core/nginx.h --- a/src/core/nginx.h +++ b/src/core/nginx.h @@ -9,8 +9,8 @@ #define _NGINX_H_INCLUDED_ -#define nginx_version 1027006 -#define NGINX_VERSION "1.27.6" +#define nginx_version 1029000 +#define NGINX_VERSION "1.29.0" #define NGINX_NAME "freenginx" #define NGINX_VER NGINX_NAME "/" NGINX_VERSION From mdounin at mdounin.ru Thu May 8 14:33:56 2025 From: mdounin at mdounin.ru (=?iso-8859-1?q?Maxim_Dounin?=) Date: Thu, 08 May 2025 17:33:56 +0300 Subject: [nginx] Compatibility with -Wunterminated-string-initialization ... Message-ID: details: http://freenginx.org/hg/nginx/rev/a287b197e342 branches: changeset: 9351:a287b197e342 user: Maxim Dounin date: Thu May 08 17:29:06 2025 +0300 description: Compatibility with -Wunterminated-string-initialization in GCC 15. Builds with recently released GCC 15 currently fail due to -Wunterminated-string-initialization (introduced in -Wextra), which warns about attempts to initialize a character array with a string literal if the trailing NUL character doesn't fit (perfectly valid in C, but might be unintentional). Fix is to use arrays for initialization instead of string literals, or switch to using character arrays of unknown size where appropriate. diffstat: src/event/quic/ngx_event_quic_protection.c | 19 ++++++++++++------- src/http/v2/ngx_http_v2_filter_module.c | 6 +++--- 2 files changed, 15 insertions(+), 10 deletions(-) diffs (66 lines): diff --git a/src/event/quic/ngx_event_quic_protection.c b/src/event/quic/ngx_event_quic_protection.c --- a/src/event/quic/ngx_event_quic_protection.c +++ b/src/event/quic/ngx_event_quic_protection.c @@ -122,9 +122,10 @@ ngx_quic_keys_set_initial_secret(ngx_qui ngx_quic_secret_t *client, *server; ngx_quic_ciphers_t ciphers; - static const uint8_t salt[20] = - "\x38\x76\x2c\xf7\xf5\x59\x34\xb3\x4d\x17" - "\x9a\xe6\xa4\xc8\x0c\xad\xcc\xbb\x7f\x0a"; + static const uint8_t salt[20] = { + 0x38, 0x76, 0x2c, 0xf7, 0xf5, 0x59, 0x34, 0xb3, 0x4d, 0x17, + 0x9a, 0xe6, 0xa4, 0xc8, 0x0c, 0xad, 0xcc, 0xbb, 0x7f, 0x0a + }; client = &keys->secrets[ssl_encryption_initial].client; server = &keys->secrets[ssl_encryption_initial].server; @@ -936,10 +937,14 @@ ngx_quic_create_retry_packet(ngx_quic_he ngx_quic_ciphers_t ciphers; /* 5.8. Retry Packet Integrity */ - static u_char key_data[16] = - "\xbe\x0c\x69\x0b\x9f\x66\x57\x5a\x1d\x76\x6b\x54\xe3\x68\xc8\x4e"; - static u_char nonce[NGX_QUIC_IV_LEN] = - "\x46\x15\x99\xd3\x5d\x63\x2b\xf2\x23\x98\x25\xbb"; + static u_char key_data[16] = { + 0xbe, 0x0c, 0x69, 0x0b, 0x9f, 0x66, 0x57, 0x5a, 0x1d, 0x76, + 0x6b, 0x54, 0xe3, 0x68, 0xc8, 0x4e + }; + static u_char nonce[NGX_QUIC_IV_LEN] = { + 0x46, 0x15, 0x99, 0xd3, 0x5d, 0x63, 0x2b, 0xf2, 0x23, 0x98, + 0x25, 0xbb + }; static ngx_str_t in = ngx_string(""); ad.data = res->data; diff --git a/src/http/v2/ngx_http_v2_filter_module.c b/src/http/v2/ngx_http_v2_filter_module.c --- a/src/http/v2/ngx_http_v2_filter_module.c +++ b/src/http/v2/ngx_http_v2_filter_module.c @@ -116,7 +116,7 @@ ngx_http_v2_header_filter(ngx_http_reque u_char addr[NGX_SOCKADDR_STRLEN]; #if (NGX_HTTP_GZIP) - static const u_char accept_encoding[12] = + static const u_char accept_encoding[] = "\x8b\x84\x84\x2d\x69\x5b\x05\x44\x3c\x86\xaa\x6f"; #endif @@ -341,7 +341,7 @@ ngx_http_v2_header_filter(ngx_http_reque #if (NGX_HTTP_GZIP) if (r->gzip_vary) { if (clcf->gzip_vary) { - len += 1 + sizeof(accept_encoding); + len += 1 + sizeof(accept_encoding) - 1; } else { r->gzip_vary = 0; @@ -568,7 +568,7 @@ ngx_http_v2_header_filter(ngx_http_reque "http2 output header: \"vary: Accept-Encoding\""); *pos++ = ngx_http_v2_inc_indexed(NGX_HTTP_V2_VARY_INDEX); - pos = ngx_cpymem(pos, accept_encoding, sizeof(accept_encoding)); + pos = ngx_cpymem(pos, accept_encoding, sizeof(accept_encoding) - 1); } #endif From mdounin at mdounin.ru Thu May 8 14:44:03 2025 From: mdounin at mdounin.ru (Maxim Dounin) Date: Thu, 8 May 2025 17:44:03 +0300 Subject: [PATCH 0 of 6] conditional rearm of write timeouts In-Reply-To: References: Message-ID: Hello! On Fri, May 02, 2025 at 03:43:03AM +0300, Maxim Dounin wrote: > Hello! > > The following patch series introduces conditional rearm of write > timeouts (and also does some related cleanup). > > Notably, this might be beneficial on Linux under memory pressure, when > requested send buffers cannot be allocated and writev() returns EAGAIN > without any progress, yet write events are reported by kernel, resulting > in a busy loop. And, more importantly, making existing write timeout > handling ineffective. > > Suggested change is to only rearm write timeouts if some progress was > made, in most cases detected by comparing c->sent with the original > value as saved at the start of the event handler. > > Comments are welcome. It looks like I've accidentally posted this patch series and a couple of previous patches into the nginx@ mailing list instead of nginx-devel at freenginx.org, sorry. -- Maxim Dounin http://mdounin.ru/ From mdounin at mdounin.ru Thu May 8 14:46:13 2025 From: mdounin at mdounin.ru (=?iso-8859-1?q?Maxim_Dounin?=) Date: Thu, 08 May 2025 17:46:13 +0300 Subject: [nginx] Stream: fixed passwords usage for certificates with vari... Message-ID: details: http://freenginx.org/hg/nginx/rev/9e3487fd18c8 branches: changeset: 9352:9e3487fd18c8 user: Maxim Dounin date: Thu May 08 17:44:47 2025 +0300 description: Stream: fixed passwords usage for certificates with variables. Missed in 9343:4f20c52c5f1b. Passwords not preserved for run time could happen to be used at run time if there are multiple server{} blocks all using the same SSL configuration inherited from the stream{} block. diffstat: src/stream/ngx_stream_proxy_module.c | 13 +++++++++++++ 1 files changed, 13 insertions(+), 0 deletions(-) diffs (23 lines): diff --git a/src/stream/ngx_stream_proxy_module.c b/src/stream/ngx_stream_proxy_module.c --- a/src/stream/ngx_stream_proxy_module.c +++ b/src/stream/ngx_stream_proxy_module.c @@ -2261,6 +2261,19 @@ ngx_stream_proxy_set_ssl(ngx_conf_t *cf, ngx_pool_cleanup_t *cln; if (pscf->ssl->ctx) { + + if (pscf->ssl_certificate + && pscf->ssl_certificate->value.len + && (pscf->ssl_certificate->lengths + || pscf->ssl_certificate_key->lengths)) + { + pscf->ssl_passwords = + ngx_ssl_preserve_passwords(cf, pscf->ssl_passwords); + if (pscf->ssl_passwords == NULL) { + return NGX_ERROR; + } + } + return NGX_OK; } From mdounin at mdounin.ru Wed May 14 03:07:45 2025 From: mdounin at mdounin.ru (=?iso-8859-1?q?Maxim_Dounin?=) Date: Wed, 14 May 2025 06:07:45 +0300 Subject: [nginx] Stream: style. Message-ID: details: http://freenginx.org/hg/nginx/rev/54c96bb0bbfa branches: changeset: 9353:54c96bb0bbfa user: Maxim Dounin date: Wed May 14 01:15:05 2025 +0300 description: Stream: style. Moved SSL configuration parsing functions to the end of the file, where configuration parsing should be. diffstat: src/stream/ngx_stream_proxy_module.c | 82 ++++++++++++++++++----------------- 1 files changed, 43 insertions(+), 39 deletions(-) diffs (110 lines): diff --git a/src/stream/ngx_stream_proxy_module.c b/src/stream/ngx_stream_proxy_module.c --- a/src/stream/ngx_stream_proxy_module.c +++ b/src/stream/ngx_stream_proxy_module.c @@ -94,10 +94,6 @@ static char *ngx_stream_proxy_bind(ngx_c #if (NGX_STREAM_SSL) static ngx_int_t ngx_stream_proxy_send_proxy_protocol(ngx_stream_session_t *s); -static char *ngx_stream_proxy_ssl_password_file(ngx_conf_t *cf, - ngx_command_t *cmd, void *conf); -static char *ngx_stream_proxy_ssl_conf_command_check(ngx_conf_t *cf, void *post, - void *data); static void ngx_stream_proxy_ssl_init_connection(ngx_stream_session_t *s); static void ngx_stream_proxy_ssl_handshake(ngx_connection_t *pc); static void ngx_stream_proxy_ssl_save_session(ngx_connection_t *c); @@ -107,6 +103,10 @@ static ngx_int_t ngx_stream_proxy_merge_ ngx_stream_proxy_srv_conf_t *conf, ngx_stream_proxy_srv_conf_t *prev); static ngx_int_t ngx_stream_proxy_set_ssl(ngx_conf_t *cf, ngx_stream_proxy_srv_conf_t *pscf); +static char *ngx_stream_proxy_ssl_password_file(ngx_conf_t *cf, + ngx_command_t *cmd, void *conf); +static char *ngx_stream_proxy_ssl_conf_command_check(ngx_conf_t *cf, void *post, + void *data); static ngx_conf_bitmask_t ngx_stream_proxy_ssl_protocols[] = { @@ -1010,41 +1010,6 @@ ngx_stream_proxy_send_proxy_protocol(ngx } -static char * -ngx_stream_proxy_ssl_password_file(ngx_conf_t *cf, ngx_command_t *cmd, - void *conf) -{ - ngx_stream_proxy_srv_conf_t *pscf = conf; - - ngx_str_t *value; - - if (pscf->ssl_passwords != NGX_CONF_UNSET_PTR) { - return "is duplicate"; - } - - value = cf->args->elts; - - pscf->ssl_passwords = ngx_ssl_read_password_file(cf, &value[1]); - - if (pscf->ssl_passwords == NULL) { - return NGX_CONF_ERROR; - } - - return NGX_CONF_OK; -} - - -static char * -ngx_stream_proxy_ssl_conf_command_check(ngx_conf_t *cf, void *post, void *data) -{ -#ifndef SSL_CONF_FLAG_FILE - return "is not supported on this platform"; -#else - return NGX_CONF_OK; -#endif -} - - static void ngx_stream_proxy_ssl_init_connection(ngx_stream_session_t *s) { @@ -2518,3 +2483,42 @@ ngx_stream_proxy_bind(ngx_conf_t *cf, ng return NGX_CONF_OK; } + + +#if (NGX_STREAM_SSL) + +static char * +ngx_stream_proxy_ssl_password_file(ngx_conf_t *cf, ngx_command_t *cmd, + void *conf) +{ + ngx_stream_proxy_srv_conf_t *pscf = conf; + + ngx_str_t *value; + + if (pscf->ssl_passwords != NGX_CONF_UNSET_PTR) { + return "is duplicate"; + } + + value = cf->args->elts; + + pscf->ssl_passwords = ngx_ssl_read_password_file(cf, &value[1]); + + if (pscf->ssl_passwords == NULL) { + return NGX_CONF_ERROR; + } + + return NGX_CONF_OK; +} + + +static char * +ngx_stream_proxy_ssl_conf_command_check(ngx_conf_t *cf, void *post, void *data) +{ +#ifndef SSL_CONF_FLAG_FILE + return "is not supported on this platform"; +#else + return NGX_CONF_OK; +#endif +} + +#endif From mdounin at mdounin.ru Wed May 14 03:07:45 2025 From: mdounin at mdounin.ru (=?iso-8859-1?q?Maxim_Dounin?=) Date: Wed, 14 May 2025 06:07:45 +0300 Subject: [nginx] Stream: style. Message-ID: details: http://freenginx.org/hg/nginx/rev/85a9b0bb5b3c branches: changeset: 9354:85a9b0bb5b3c user: Maxim Dounin date: Wed May 14 01:15:13 2025 +0300 description: Stream: style. Unless actually required for some reason, line continuation should be in column 79, not 80. diffstat: src/stream/ngx_stream.h | 16 ++++++++-------- 1 files changed, 8 insertions(+), 8 deletions(-) diffs (32 lines): diff --git a/src/stream/ngx_stream.h b/src/stream/ngx_stream.h --- a/src/stream/ngx_stream.h +++ b/src/stream/ngx_stream.h @@ -264,20 +264,20 @@ typedef struct { #define ngx_stream_delete_ctx(s, module) s->ctx[module.ctx_index] = NULL; -#define ngx_stream_get_module_main_conf(s, module) \ +#define ngx_stream_get_module_main_conf(s, module) \ (s)->main_conf[module.ctx_index] -#define ngx_stream_get_module_srv_conf(s, module) \ +#define ngx_stream_get_module_srv_conf(s, module) \ (s)->srv_conf[module.ctx_index] -#define ngx_stream_conf_get_module_main_conf(cf, module) \ +#define ngx_stream_conf_get_module_main_conf(cf, module) \ ((ngx_stream_conf_ctx_t *) cf->ctx)->main_conf[module.ctx_index] -#define ngx_stream_conf_get_module_srv_conf(cf, module) \ +#define ngx_stream_conf_get_module_srv_conf(cf, module) \ ((ngx_stream_conf_ctx_t *) cf->ctx)->srv_conf[module.ctx_index] -#define ngx_stream_cycle_get_module_main_conf(cycle, module) \ - (cycle->conf_ctx[ngx_stream_module.index] ? \ - ((ngx_stream_conf_ctx_t *) cycle->conf_ctx[ngx_stream_module.index]) \ - ->main_conf[module.ctx_index]: \ +#define ngx_stream_cycle_get_module_main_conf(cycle, module) \ + (cycle->conf_ctx[ngx_stream_module.index] ? \ + ((ngx_stream_conf_ctx_t *) cycle->conf_ctx[ngx_stream_module.index]) \ + ->main_conf[module.ctx_index]: \ NULL) From mdounin at mdounin.ru Wed May 14 03:07:45 2025 From: mdounin at mdounin.ru (=?iso-8859-1?q?Maxim_Dounin?=) Date: Wed, 14 May 2025 06:07:45 +0300 Subject: [nginx] Stream: fixed timeout usage for proxy_protocol with SSL ... Message-ID: details: http://freenginx.org/hg/nginx/rev/196e9f3db2b0 branches: changeset: 9355:196e9f3db2b0 user: Maxim Dounin date: Wed May 14 01:15:24 2025 +0300 description: Stream: fixed timeout usage for proxy_protocol with SSL proxying. Connection establishment with a proxied server includes SSL handshake, and the relevant timeout is set with the proxy_connect_timeout directive. Since proxy_protocol sending happens before SSL handshake, it should use proxy_connect_timeout as well. Further, the timeout should not be rearmed if it's already set. Additionally, read handler should be set as long as we are waiting for events, since it can be triggered. diffstat: src/stream/ngx_stream_proxy_module.c | 7 +++++-- 1 files changed, 5 insertions(+), 2 deletions(-) diffs (17 lines): diff --git a/src/stream/ngx_stream_proxy_module.c b/src/stream/ngx_stream_proxy_module.c --- a/src/stream/ngx_stream_proxy_module.c +++ b/src/stream/ngx_stream_proxy_module.c @@ -977,8 +977,11 @@ ngx_stream_proxy_send_proxy_protocol(ngx pscf = ngx_stream_get_module_srv_conf(s, ngx_stream_proxy_module); - ngx_add_timer(pc->write, pscf->timeout); - + if (!pc->write->timer_set) { + ngx_add_timer(pc->write, pscf->connect_timeout); + } + + pc->read->handler = ngx_stream_proxy_connect_handler; pc->write->handler = ngx_stream_proxy_connect_handler; return NGX_AGAIN; From mdounin at mdounin.ru Wed May 14 03:07:46 2025 From: mdounin at mdounin.ru (=?iso-8859-1?q?Maxim_Dounin?=) Date: Wed, 14 May 2025 06:07:46 +0300 Subject: [nginx] Stream: fixed proxy_connect_timeout with SSL proxying. Message-ID: details: http://freenginx.org/hg/nginx/rev/b29b2f2ffdc3 branches: changeset: 9356:b29b2f2ffdc3 user: Maxim Dounin date: Wed May 14 01:15:42 2025 +0300 description: Stream: fixed proxy_connect_timeout with SSL proxying. Connection establishment, including SSL handshake, is expected to complete within the time set with the proxy_connect_timeout directive. However, previously corresponding timer was removed after TCP connect, and then again added for SSL handshaking, resulting in 2x longer time allowed in the worst case. Fix is to remove the timer in ngx_stream_proxy_init_upstream() instead of doing this in ngx_stream_proxy_connect_handler(). diffstat: src/stream/ngx_stream_proxy_module.c | 10 ++++------ 1 files changed, 4 insertions(+), 6 deletions(-) diffs (34 lines): diff --git a/src/stream/ngx_stream_proxy_module.c b/src/stream/ngx_stream_proxy_module.c --- a/src/stream/ngx_stream_proxy_module.c +++ b/src/stream/ngx_stream_proxy_module.c @@ -929,6 +929,10 @@ ngx_stream_proxy_init_upstream(ngx_strea pc->read->handler = ngx_stream_proxy_upstream_handler; pc->write->handler = ngx_stream_proxy_upstream_handler; + if (pc->write->timer_set) { + ngx_del_timer(pc->write); + } + if (pc->read->ready) { ngx_post_event(pc->read, &ngx_posted_events); } @@ -1113,10 +1117,6 @@ ngx_stream_proxy_ssl_handshake(ngx_conne } } - if (pc->write->timer_set) { - ngx_del_timer(pc->write); - } - ngx_stream_proxy_init_upstream(s); return; @@ -1494,8 +1494,6 @@ ngx_stream_proxy_connect_handler(ngx_eve return; } - ngx_del_timer(c->write); - ngx_log_debug0(NGX_LOG_DEBUG_STREAM, c->log, 0, "stream proxy connect upstream"); From mdounin at mdounin.ru Wed May 14 03:07:46 2025 From: mdounin at mdounin.ru (=?iso-8859-1?q?Maxim_Dounin?=) Date: Wed, 14 May 2025 06:07:46 +0300 Subject: [nginx] Mail: style. Message-ID: details: http://freenginx.org/hg/nginx/rev/1e66d7bd556e branches: changeset: 9357:1e66d7bd556e user: Maxim Dounin date: Wed May 14 01:15:59 2025 +0300 description: Mail: style. There is no reason to use c->write as we already have wev, and it is used elsewhere in ngx_mail_send(). diffstat: src/mail/ngx_mail_handler.c | 6 +++--- 1 files changed, 3 insertions(+), 3 deletions(-) diffs (24 lines): diff --git a/src/mail/ngx_mail_handler.c b/src/mail/ngx_mail_handler.c --- a/src/mail/ngx_mail_handler.c +++ b/src/mail/ngx_mail_handler.c @@ -1042,7 +1042,7 @@ ngx_mail_send(ngx_event_t *wev) } if (s->out.len == 0) { - if (ngx_handle_write_event(c->write, 0) != NGX_OK) { + if (ngx_handle_write_event(wev, 0) != NGX_OK) { ngx_mail_close_connection(c); } @@ -1086,9 +1086,9 @@ again: cscf = ngx_mail_get_module_srv_conf(s, ngx_mail_core_module); - ngx_add_timer(c->write, cscf->timeout); + ngx_add_timer(wev, cscf->timeout); - if (ngx_handle_write_event(c->write, 0) != NGX_OK) { + if (ngx_handle_write_event(wev, 0) != NGX_OK) { ngx_mail_close_connection(c); return; } From mdounin at mdounin.ru Wed May 14 03:07:46 2025 From: mdounin at mdounin.ru (=?iso-8859-1?q?Maxim_Dounin?=) Date: Wed, 14 May 2025 06:07:46 +0300 Subject: [nginx] Conditional rearm of write timeouts. Message-ID: details: http://freenginx.org/hg/nginx/rev/4c872940b19b branches: changeset: 9358:4c872940b19b user: Maxim Dounin date: Wed May 14 01:16:05 2025 +0300 description: Conditional rearm of write timeouts. When the network memory limit is hit on Linux, it is possible that connections are reported as writable, yet writev() / sendfile() returns no progress and EAGAIN. This results in write timeouts being ineffective, since they are rearmed on each write event. In particular, such behaviour can be easily reproduced with SO_SNDBUF explicitly set (via "listen ... sndbuf=...") and with poll or select event methods. Before kernel 6.0 and 5.19.2, this also can be easily reproduced with epoll (849b425cd091e "tcp: fix possible freeze in tx path under memory pressure"). With this change, write timeouts are only rearmed if some progress is made, ensuring that timeouts work properly in such situations. diffstat: src/event/ngx_event_pipe.c | 7 ++++++- src/http/ngx_http_request.c | 5 ++++- src/http/ngx_http_upstream.c | 30 ++++++++++++++++++++++++++---- src/http/v2/ngx_http_v2.c | 8 +++++++- src/mail/ngx_mail_handler.c | 7 ++++--- src/mail/ngx_mail_proxy_module.c | 4 +++- src/stream/ngx_stream_proxy_module.c | 14 ++++++++++++-- src/stream/ngx_stream_return_module.c | 7 ++++++- 8 files changed, 68 insertions(+), 14 deletions(-) diffs (306 lines): diff --git a/src/event/ngx_event_pipe.c b/src/event/ngx_event_pipe.c --- a/src/event/ngx_event_pipe.c +++ b/src/event/ngx_event_pipe.c @@ -22,10 +22,13 @@ static ngx_int_t ngx_event_pipe_drain_ch ngx_int_t ngx_event_pipe(ngx_event_pipe_t *p, ngx_int_t do_write) { + off_t sent; ngx_int_t rc; ngx_uint_t flags; ngx_event_t *rev, *wev; + sent = p->downstream->sent; + for ( ;; ) { if (do_write) { p->log->action = "sending to client"; @@ -88,7 +91,9 @@ ngx_event_pipe(ngx_event_pipe_t *p, ngx_ if (!wev->delayed) { if (wev->active && !wev->ready) { - ngx_add_timer(wev, p->send_timeout); + if (p->downstream->sent != sent || !wev->timer_set) { + ngx_add_timer(wev, p->send_timeout); + } } else if (wev->timer_set) { ngx_del_timer(wev); diff --git a/src/http/ngx_http_request.c b/src/http/ngx_http_request.c --- a/src/http/ngx_http_request.c +++ b/src/http/ngx_http_request.c @@ -2855,6 +2855,7 @@ ngx_http_set_write_handler(ngx_http_requ static void ngx_http_writer(ngx_http_request_t *r) { + off_t sent; ngx_int_t rc; ngx_event_t *wev; ngx_connection_t *c; @@ -2892,6 +2893,8 @@ ngx_http_writer(ngx_http_request_t *r) return; } + sent = c->sent; + rc = ngx_http_output_filter(r, NULL); ngx_log_debug3(NGX_LOG_DEBUG_HTTP, c->log, 0, @@ -2905,7 +2908,7 @@ ngx_http_writer(ngx_http_request_t *r) if (r->buffered || r->postponed || (r == r->main && c->buffered)) { - if (!wev->delayed) { + if (!wev->delayed && (c->sent != sent || !wev->timer_set)) { ngx_add_timer(wev, clcf->send_timeout); } diff --git a/src/http/ngx_http_upstream.c b/src/http/ngx_http_upstream.c --- a/src/http/ngx_http_upstream.c +++ b/src/http/ngx_http_upstream.c @@ -2103,6 +2103,7 @@ static void ngx_http_upstream_send_request(ngx_http_request_t *r, ngx_http_upstream_t *u, ngx_uint_t do_write) { + off_t sent; ngx_int_t rc; ngx_connection_t *c; @@ -2120,6 +2121,12 @@ ngx_http_upstream_send_request(ngx_http_ return; } + sent = c->sent; + + if (!u->request_sent) { + sent = -1; + } + c->log->action = "sending request to upstream"; rc = ngx_http_upstream_send_request_body(r, u, do_write); @@ -2136,7 +2143,9 @@ ngx_http_upstream_send_request(ngx_http_ if (rc == NGX_AGAIN) { if (!c->write->ready || u->request_body_blocked) { - ngx_add_timer(c->write, u->conf->send_timeout); + if (c->sent != sent || !c->write->timer_set) { + ngx_add_timer(c->write, u->conf->send_timeout); + } } else if (c->write->timer_set) { ngx_del_timer(c->write); @@ -3512,6 +3521,7 @@ static void ngx_http_upstream_process_upgraded(ngx_http_request_t *r, ngx_uint_t from_upstream, ngx_uint_t do_write) { + off_t dsent, usent; size_t size; ssize_t n; ngx_buf_t *b; @@ -3529,6 +3539,9 @@ ngx_http_upstream_process_upgraded(ngx_h downstream = c; upstream = u->peer.connection; + dsent = downstream->sent; + usent = upstream->sent; + if (downstream->write->timedout) { c->timedout = 1; ngx_connection_error(c, NGX_ETIMEDOUT, "client timed out"); @@ -3648,7 +3661,9 @@ ngx_http_upstream_process_upgraded(ngx_h } if (upstream->write->active && !upstream->write->ready) { - ngx_add_timer(upstream->write, u->conf->send_timeout); + if (upstream->sent != usent || !upstream->write->timer_set) { + ngx_add_timer(upstream->write, u->conf->send_timeout); + } } else if (upstream->write->timer_set) { ngx_del_timer(upstream->write); @@ -3693,7 +3708,9 @@ ngx_http_upstream_process_upgraded(ngx_h } if (downstream->write->active && !downstream->write->ready) { - ngx_add_timer(downstream->write, clcf->send_timeout); + if (downstream->sent != dsent || !downstream->write->timer_set) { + ngx_add_timer(downstream->write, clcf->send_timeout); + } } else if (downstream->write->timer_set) { ngx_del_timer(downstream->write); @@ -3755,6 +3772,7 @@ static void ngx_http_upstream_process_non_buffered_request(ngx_http_request_t *r, ngx_uint_t do_write) { + off_t sent; size_t size; ssize_t n; ngx_buf_t *b; @@ -3768,6 +3786,8 @@ ngx_http_upstream_process_non_buffered_r downstream = r->connection; upstream = u->peer.connection; + sent = downstream->sent; + b = &u->buffer; do_write = do_write || u->length == 0; @@ -3857,7 +3877,9 @@ ngx_http_upstream_process_non_buffered_r } if (downstream->write->active && !downstream->write->ready) { - ngx_add_timer(downstream->write, clcf->send_timeout); + if (downstream->sent != sent || !downstream->write->timer_set) { + ngx_add_timer(downstream->write, clcf->send_timeout); + } } else if (downstream->write->timer_set) { ngx_del_timer(downstream->write); diff --git a/src/http/v2/ngx_http_v2.c b/src/http/v2/ngx_http_v2.c --- a/src/http/v2/ngx_http_v2.c +++ b/src/http/v2/ngx_http_v2.c @@ -503,6 +503,7 @@ ngx_int_t ngx_http_v2_send_output_queue(ngx_http_v2_connection_t *h2c) { int tcp_nodelay; + off_t sent; ngx_chain_t *cl; ngx_event_t *wev; ngx_connection_t *c; @@ -537,6 +538,8 @@ ngx_http_v2_send_output_queue(ngx_http_v out->blocked, out->length); } + sent = c->sent; + cl = c->send_chain(c, cl, 0); if (cl == NGX_CHAIN_ERROR) { @@ -592,7 +595,10 @@ ngx_http_v2_send_output_queue(ngx_http_v h2c->last_out = frame; if (!wev->ready) { - ngx_add_timer(wev, clcf->send_timeout); + if (c->sent != sent || !wev->timer_set) { + ngx_add_timer(wev, clcf->send_timeout); + } + return NGX_AGAIN; } diff --git a/src/mail/ngx_mail_handler.c b/src/mail/ngx_mail_handler.c --- a/src/mail/ngx_mail_handler.c +++ b/src/mail/ngx_mail_handler.c @@ -1084,9 +1084,10 @@ ngx_mail_send(ngx_event_t *wev) again: - cscf = ngx_mail_get_module_srv_conf(s, ngx_mail_core_module); - - ngx_add_timer(wev, cscf->timeout); + if (n > 0 || !wev->timer_set) { + cscf = ngx_mail_get_module_srv_conf(s, ngx_mail_core_module); + ngx_add_timer(wev, cscf->timeout); + } if (ngx_handle_write_event(wev, 0) != NGX_OK) { ngx_mail_close_connection(c); diff --git a/src/mail/ngx_mail_proxy_module.c b/src/mail/ngx_mail_proxy_module.c --- a/src/mail/ngx_mail_proxy_module.c +++ b/src/mail/ngx_mail_proxy_module.c @@ -1116,6 +1116,7 @@ static void ngx_mail_proxy_handler(ngx_event_t *ev) { char *action, *recv_action, *send_action; + off_t sent; size_t size; ssize_t n; ngx_buf_t *b; @@ -1181,6 +1182,7 @@ ngx_mail_proxy_handler(ngx_event_t *ev) } do_write = ev->write ? 1 : 0; + sent = dst->sent; ngx_log_debug3(NGX_LOG_DEBUG_MAIL, ev->log, 0, "mail proxy handler: %ui, #%d > #%d", @@ -1276,7 +1278,7 @@ ngx_mail_proxy_handler(ngx_event_t *ev) return; } - if (c == s->connection) { + if (c == s->connection && (dst->sent != sent || !ev->write)) { pcf = ngx_mail_get_module_srv_conf(s, ngx_mail_proxy_module); ngx_add_timer(c->read, pcf->timeout); } diff --git a/src/stream/ngx_stream_proxy_module.c b/src/stream/ngx_stream_proxy_module.c --- a/src/stream/ngx_stream_proxy_module.c +++ b/src/stream/ngx_stream_proxy_module.c @@ -1555,7 +1555,7 @@ ngx_stream_proxy_process(ngx_stream_sess ngx_uint_t do_write) { char *recv_action, *send_action; - off_t *received, limit; + off_t *received, limit, sent; size_t size, limit_rate; ssize_t n; ngx_buf_t *b; @@ -1615,6 +1615,14 @@ ngx_stream_proxy_process(ngx_stream_sess send_action = "proxying and sending to upstream"; } +#if (NGX_SUPPRESS_WARN) + sent = 0; +#endif + + if (dst) { + sent = dst->sent; + } + for ( ;; ) { if (do_write && dst) { @@ -1758,7 +1766,9 @@ ngx_stream_proxy_process(ngx_stream_sess } if (!c->read->delayed && !pc->read->delayed) { - ngx_add_timer(c->write, pscf->timeout); + if (dst->sent != sent || !c->write->timer_set) { + ngx_add_timer(c->write, pscf->timeout); + } } else if (c->write->timer_set) { ngx_del_timer(c->write); diff --git a/src/stream/ngx_stream_return_module.c b/src/stream/ngx_stream_return_module.c --- a/src/stream/ngx_stream_return_module.c +++ b/src/stream/ngx_stream_return_module.c @@ -133,6 +133,7 @@ ngx_stream_return_handler(ngx_stream_ses static void ngx_stream_return_write_handler(ngx_event_t *ev) { + off_t sent; ngx_connection_t *c; ngx_stream_session_t *s; ngx_stream_return_ctx_t *ctx; @@ -146,6 +147,8 @@ ngx_stream_return_write_handler(ngx_even return; } + sent = c->sent; + ctx = ngx_stream_get_module_ctx(s, ngx_stream_return_module); if (ngx_stream_top_filter(s, ctx->out, 1) == NGX_ERROR) { @@ -167,7 +170,9 @@ ngx_stream_return_write_handler(ngx_even return; } - ngx_add_timer(ev, 5000); + if (c->sent != sent || !ev->timer_set) { + ngx_add_timer(ev, 5000); + } } From mdounin at mdounin.ru Thu May 15 02:46:42 2025 From: mdounin at mdounin.ru (=?utf-8?q?Maxim_Dounin?=) Date: Thu, 15 May 2025 05:46:42 +0300 Subject: [PATCH 1 of 2] Mp4: fixed directio usage with open_file_cache Message-ID: <6f0485388f31ead0177f.1747277202@vm-bsd.mdounin.ru> # HG changeset patch # User Maxim Dounin # Date 1747276031 -10800 # Thu May 15 05:27:11 2025 +0300 # Node ID 6f0485388f31ead0177fd294f4883b59dfb1dea7 # Parent 4c872940b19b8181d791eb80c17110364150af9d Mp4: fixed directio usage with open_file_cache. With open_file_cache, if directio is enabled on a file descriptor after opening the file, other consumers won't know about directio being enabled and will use unaligned reads, leading to EINVAL errors from pread() on Linux. Further, if a file descriptor with directio enabled will be returned to the mp4 module itself, during mp4 file processing it will be used in assumption that directio is not enabled. Fix is to use of.directio and ngx_open_cached_file() to enable directio, and switch it off during mp4 file processing. While this does some unneeded syscalls if the file is actually just opened and we have to parse the file, this shouldn't be significant compared to other mp4 file processing costs. Note well that even with this fix using directio with open_file_cache might be problematic on Linux if combined with file AIO or threaded IO, as directio might be re-enabled after an unaligned read when a thread tries to do an unaligned read for another request. diff --git a/src/http/modules/ngx_http_mp4_module.c b/src/http/modules/ngx_http_mp4_module.c --- a/src/http/modules/ngx_http_mp4_module.c +++ b/src/http/modules/ngx_http_mp4_module.c @@ -479,7 +479,7 @@ ngx_http_mp4_handler(ngx_http_request_t u_char *last; size_t root; ngx_int_t rc, start, end; - ngx_uint_t level, length; + ngx_uint_t level, length, directio; ngx_str_t path, value; ngx_log_t *log; ngx_buf_t *b; @@ -519,7 +519,7 @@ ngx_http_mp4_handler(ngx_http_request_t ngx_memzero(&of, sizeof(ngx_open_file_info_t)); of.read_ahead = clcf->read_ahead; - of.directio = NGX_MAX_OFF_T_VALUE; + of.directio = clcf->directio; of.valid = clcf->open_file_cache_valid; of.min_uses = clcf->open_file_cache_min_uses; of.errors = clcf->open_file_cache_errors; @@ -579,6 +579,7 @@ ngx_http_mp4_handler(ngx_http_request_t start = -1; length = 0; + directio = 0; r->headers_out.content_length_n = of.size; mp4 = NULL; b = NULL; @@ -614,6 +615,21 @@ ngx_http_mp4_handler(ngx_http_request_t if (start >= 0) { r->single_range = 1; + if (of.is_directio) { + + /* + * DIRECTIO is set on transfer only + * to allow kernel to cache "moov" atom + */ + + if (ngx_directio_off(of.fd) == NGX_FILE_ERROR) { + ngx_log_error(NGX_LOG_ALERT, log, ngx_errno, + ngx_directio_off_n " \"%s\" failed", path.data); + } + + directio = 1; + } + mp4 = ngx_pcalloc(r->pool, sizeof(ngx_http_mp4_file_t)); if (mp4 == NULL) { return NGX_HTTP_INTERNAL_SERVER_ERROR; @@ -622,6 +638,7 @@ ngx_http_mp4_handler(ngx_http_request_t mp4->file.fd = of.fd; mp4->file.name = path; mp4->file.log = r->connection->log; + mp4->file.directio = of.is_directio; mp4->end = of.size; mp4->start = (ngx_uint_t) start; mp4->length = length; @@ -656,23 +673,14 @@ ngx_http_mp4_handler(ngx_http_request_t log->action = "sending mp4 to client"; - if (clcf->directio <= of.size) { - - /* - * DIRECTIO is set on transfer only - * to allow kernel to cache "moov" atom - */ + if (directio) { + + /* DIRECTIO was switched off, restore it */ if (ngx_directio_on(of.fd) == NGX_FILE_ERROR) { ngx_log_error(NGX_LOG_ALERT, log, ngx_errno, ngx_directio_on_n " \"%s\" failed", path.data); } - - of.is_directio = 1; - - if (mp4) { - mp4->file.directio = 1; - } } r->headers_out.status = NGX_HTTP_OK; From mdounin at mdounin.ru Thu May 15 02:46:43 2025 From: mdounin at mdounin.ru (=?utf-8?q?Maxim_Dounin?=) Date: Thu, 15 May 2025 05:46:43 +0300 Subject: [PATCH 2 of 2] Mp4: of.directio_off flag to avoid unneeded syscalls In-Reply-To: <6f0485388f31ead0177f.1747277202@vm-bsd.mdounin.ru> References: <6f0485388f31ead0177f.1747277202@vm-bsd.mdounin.ru> Message-ID: # HG changeset patch # User Maxim Dounin # Date 1747276516 -10800 # Thu May 15 05:35:16 2025 +0300 # Node ID abc30f01c381567949fcb62c8e3ce04f47cf7198 # Parent 6f0485388f31ead0177fd294f4883b59dfb1dea7 Mp4: of.directio_off flag to avoid unneeded syscalls. When set, ngx_open_cached_file() won't try to enable directio on the file, allowing the caller to do it itself, but will set is_directio flag in ngx_open_file_info_t and in open file cache. The fact that directio needs to be enabled by the caller is signalled in the of.is_directio_off output flag. This approach makes it possible to avoid unneeded syscalls when directio is enabled, yet the caller needs it disabled for some initial file processing, such as in the mp4 module. diff --git a/src/core/ngx_open_file_cache.c b/src/core/ngx_open_file_cache.c --- a/src/core/ngx_open_file_cache.c +++ b/src/core/ngx_open_file_cache.c @@ -249,6 +249,7 @@ ngx_open_cached_file(ngx_open_file_cache of->is_link = file->is_link; of->is_exec = file->is_exec; of->is_directio = file->is_directio; + of->is_directio_off = 0; if (!file->is_dir) { file->count++; @@ -313,6 +314,7 @@ ngx_open_cached_file(ngx_open_file_cache } of->is_directio = file->is_directio; + of->is_directio_off = 0; goto update; } @@ -920,7 +922,11 @@ ngx_open_and_stat_file(ngx_str_t *name, } if (of->directio <= ngx_file_size(&fi)) { - if (ngx_directio_on(fd) == NGX_FILE_ERROR) { + if (of->directio_off) { + of->is_directio = 1; + of->is_directio_off = 1; + + } else if (ngx_directio_on(fd) == NGX_FILE_ERROR) { ngx_log_error(NGX_LOG_ALERT, log, ngx_errno, ngx_directio_on_n " \"%V\" failed", name); diff --git a/src/core/ngx_open_file_cache.h b/src/core/ngx_open_file_cache.h --- a/src/core/ngx_open_file_cache.h +++ b/src/core/ngx_open_file_cache.h @@ -42,12 +42,14 @@ typedef struct { unsigned log:1; unsigned errors:1; unsigned events:1; + unsigned directio_off:1; unsigned is_dir:1; unsigned is_file:1; unsigned is_link:1; unsigned is_exec:1; unsigned is_directio:1; + unsigned is_directio_off:1; } ngx_open_file_info_t; diff --git a/src/http/modules/ngx_http_mp4_module.c b/src/http/modules/ngx_http_mp4_module.c --- a/src/http/modules/ngx_http_mp4_module.c +++ b/src/http/modules/ngx_http_mp4_module.c @@ -479,7 +479,7 @@ ngx_http_mp4_handler(ngx_http_request_t u_char *last; size_t root; ngx_int_t rc, start, end; - ngx_uint_t level, length, directio; + ngx_uint_t level, length; ngx_str_t path, value; ngx_log_t *log; ngx_buf_t *b; @@ -520,6 +520,7 @@ ngx_http_mp4_handler(ngx_http_request_t of.read_ahead = clcf->read_ahead; of.directio = clcf->directio; + of.directio_off = 1; of.valid = clcf->open_file_cache_valid; of.min_uses = clcf->open_file_cache_min_uses; of.errors = clcf->open_file_cache_errors; @@ -579,7 +580,6 @@ ngx_http_mp4_handler(ngx_http_request_t start = -1; length = 0; - directio = 0; r->headers_out.content_length_n = of.size; mp4 = NULL; b = NULL; @@ -615,7 +615,7 @@ ngx_http_mp4_handler(ngx_http_request_t if (start >= 0) { r->single_range = 1; - if (of.is_directio) { + if (of.is_directio && !of.is_directio_off) { /* * DIRECTIO is set on transfer only @@ -627,7 +627,7 @@ ngx_http_mp4_handler(ngx_http_request_t ngx_directio_off_n " \"%s\" failed", path.data); } - directio = 1; + of.is_directio_off = 1; } mp4 = ngx_pcalloc(r->pool, sizeof(ngx_http_mp4_file_t)); @@ -673,7 +673,7 @@ ngx_http_mp4_handler(ngx_http_request_t log->action = "sending mp4 to client"; - if (directio) { + if (of.is_directio_off) { /* DIRECTIO was switched off, restore it */ From mdounin at mdounin.ru Thu May 15 02:49:33 2025 From: mdounin at mdounin.ru (=?utf-8?q?Maxim_Dounin?=) Date: Thu, 15 May 2025 05:49:33 +0300 Subject: [PATCH] Cache: directio support when reading cache files Message-ID: <579fd22909a485c48d07.1747277373@vm-bsd.mdounin.ru> # HG changeset patch # User Maxim Dounin # Date 1747277255 -10800 # Thu May 15 05:47:35 2025 +0300 # Node ID 579fd22909a485c48d0780e764c02af0c44c3666 # Parent abc30f01c381567949fcb62c8e3ce04f47cf7198 Cache: directio support when reading cache files. diff --git a/src/http/ngx_http_file_cache.c b/src/http/ngx_http_file_cache.c --- a/src/http/ngx_http_file_cache.c +++ b/src/http/ngx_http_file_cache.c @@ -353,7 +353,7 @@ ngx_http_file_cache_open(ngx_http_reques of.valid = clcf->open_file_cache_valid; of.min_uses = clcf->open_file_cache_min_uses; of.events = clcf->open_file_cache_events; - of.directio = NGX_OPEN_FILE_DIRECTIO_OFF; + of.directio = clcf->directio; of.read_ahead = clcf->read_ahead; if (ngx_open_cached_file(clcf->open_file_cache, &c->file.name, &of, r->pool) @@ -380,13 +380,36 @@ ngx_http_file_cache_open(ngx_http_reques c->file.fd = of.fd; c->file.log = r->connection->log; + c->file.directio = of.is_directio; c->uniq = of.uniq; c->length = of.size; c->fs_size = (of.fs_size + cache->bsize - 1) / cache->bsize; - c->buf = ngx_create_temp_buf(r->pool, c->body_start); - if (c->buf == NULL) { - return NGX_ERROR; + if (of.is_directio) { + + c->body_start = ngx_align(c->body_start, clcf->directio_alignment); + + c->buf = ngx_calloc_buf(r->pool); + if (c->buf == NULL) { + return NGX_ERROR; + } + + c->buf->start = ngx_pmemalign(r->pool, c->body_start, + clcf->directio_alignment); + if (c->buf->start == NULL) { + return NGX_ERROR; + } + + c->buf->pos = c->buf->start; + c->buf->last = c->buf->start; + c->buf->end = c->buf->start + c->body_start; + c->buf->temporary = 1; + + } else { + c->buf = ngx_create_temp_buf(r->pool, c->body_start); + if (c->buf == NULL) { + return NGX_ERROR; + } } return ngx_http_file_cache_read(r, c); @@ -1663,6 +1686,7 @@ ngx_http_cache_send(ngx_http_request_t * b->file->fd = c->file.fd; b->file->name = c->file.name; b->file->log = r->connection->log; + b->file->directio = c->file.directio; out.buf = b; out.next = NULL; From mdounin at mdounin.ru Thu May 15 02:52:51 2025 From: mdounin at mdounin.ru (=?utf-8?q?Maxim_Dounin?=) Date: Thu, 15 May 2025 05:52:51 +0300 Subject: [PATCH] Tests: mp4 tests with directio and open_file_cache In-Reply-To: <6f0485388f31ead0177f.1747277202@vm-bsd.mdounin.ru> References: <6f0485388f31ead0177f.1747277202@vm-bsd.mdounin.ru> Message-ID: # HG changeset patch # User Maxim Dounin # Date 1747275653 -10800 # Thu May 15 05:20:53 2025 +0300 # Node ID c5566713e4bed939c0f2bc4de443fbe49ae212c4 # Parent 0a913a10945b996bcdac073467bf7bc957ef716e Tests: mp4 tests with directio and open_file_cache. diff --git a/mp4_directio.t b/mp4_directio.t new file mode 100644 --- /dev/null +++ b/mp4_directio.t @@ -0,0 +1,78 @@ +#!/usr/bin/perl + +# (C) Maxim Dounin + +# Test for directio support in mp4 module. + +############################################################################### + +use warnings; +use strict; + +use Test::More; + +BEGIN { use FindBin; chdir($FindBin::Bin); } + +use lib 'lib'; +use Test::Nginx; + +############################################################################### + +select STDERR; $| = 1; +select STDOUT; $| = 1; + +my $t = Test::Nginx->new()->has(qw/http mp4/)->has_daemon('ffmpeg') + ->write_file_expand('nginx.conf', <<'EOF'); + +%%TEST_GLOBALS%% + +daemon off; + +events { +} + +http { + %%TEST_GLOBALS_HTTP%% + + server { + listen 127.0.0.1:8080; + server_name localhost; + + location / { + mp4; + open_file_cache max=10; + directio 0; + } + } +} + +EOF + +plan(skip_all => 'no lavfi') + unless grep /lavfi/, `ffmpeg -loglevel quiet -formats`; +plan(skip_all => 'no libx264 or libopenh264') + unless grep /libx264|libopenh264/, `ffmpeg -loglevel quiet -encoders`; +system('ffmpeg -nostdin -loglevel quiet -y ' + . '-f lavfi -i testsrc=duration=10:size=320x200:rate=15 ' + . '-g 15 -c:v h264 ' + . "${\($t->testdir())}/test.mp4") == 0 + or die "Can't create mp4 file: $!"; + +$t->run()->plan(2); + +############################################################################### + +# mp4 module uses unaligned reads while parsing mp4 file, though +# failed to disable directio if a file with directio enabled was +# returned from open file cache + +like(http_get('/test.mp4?start=1.0'), qr/ 200 /, 'mp4 directio first'); + +TODO: { +local $TODO = 'not yet' unless $t->has_version('1.29.0') or $^O ne 'linux'; + +like(http_get('/test.mp4?start=1.0'), qr/ 200 /, 'mp4 directio cached'); + +} + +############################################################################### From mdounin at mdounin.ru Sun May 25 20:59:02 2025 From: mdounin at mdounin.ru (=?iso-8859-1?q?Maxim_Dounin?=) Date: Sun, 25 May 2025 23:59:02 +0300 Subject: [nginx] Mp4: fixed directio usage with open_file_cache. Message-ID: details: http://freenginx.org/hg/nginx/rev/314192d67a91 branches: changeset: 9359:314192d67a91 user: Maxim Dounin date: Sun May 25 23:57:28 2025 +0300 description: Mp4: fixed directio usage with open_file_cache. With open_file_cache, if directio is enabled on a file descriptor after opening the file, other consumers won't know about directio being enabled and will use unaligned reads, leading to EINVAL errors from pread() on Linux. Further, if a file descriptor with directio enabled will be returned to the mp4 module itself, during mp4 file processing it will be used in assumption that directio is not enabled. Fix is to use of.directio and ngx_open_cached_file() to enable directio, and switch it off during mp4 file processing. While this does some unneeded syscalls if the file is actually just opened and we have to parse the file, this shouldn't be significant compared to other mp4 file processing costs. diffstat: src/http/modules/ngx_http_mp4_module.c | 36 ++++++++++++++++++++------------- 1 files changed, 22 insertions(+), 14 deletions(-) diffs (86 lines): diff --git a/src/http/modules/ngx_http_mp4_module.c b/src/http/modules/ngx_http_mp4_module.c --- a/src/http/modules/ngx_http_mp4_module.c +++ b/src/http/modules/ngx_http_mp4_module.c @@ -479,7 +479,7 @@ ngx_http_mp4_handler(ngx_http_request_t u_char *last; size_t root; ngx_int_t rc, start, end; - ngx_uint_t level, length; + ngx_uint_t level, length, directio; ngx_str_t path, value; ngx_log_t *log; ngx_buf_t *b; @@ -519,7 +519,7 @@ ngx_http_mp4_handler(ngx_http_request_t ngx_memzero(&of, sizeof(ngx_open_file_info_t)); of.read_ahead = clcf->read_ahead; - of.directio = NGX_MAX_OFF_T_VALUE; + of.directio = clcf->directio; of.valid = clcf->open_file_cache_valid; of.min_uses = clcf->open_file_cache_min_uses; of.errors = clcf->open_file_cache_errors; @@ -579,6 +579,7 @@ ngx_http_mp4_handler(ngx_http_request_t start = -1; length = 0; + directio = 0; r->headers_out.content_length_n = of.size; mp4 = NULL; b = NULL; @@ -614,6 +615,21 @@ ngx_http_mp4_handler(ngx_http_request_t if (start >= 0) { r->single_range = 1; + if (of.is_directio) { + + /* + * DIRECTIO is set on transfer only + * to allow kernel to cache "moov" atom + */ + + if (ngx_directio_off(of.fd) == NGX_FILE_ERROR) { + ngx_log_error(NGX_LOG_ALERT, log, ngx_errno, + ngx_directio_off_n " \"%s\" failed", path.data); + } + + directio = 1; + } + mp4 = ngx_pcalloc(r->pool, sizeof(ngx_http_mp4_file_t)); if (mp4 == NULL) { return NGX_HTTP_INTERNAL_SERVER_ERROR; @@ -622,6 +638,7 @@ ngx_http_mp4_handler(ngx_http_request_t mp4->file.fd = of.fd; mp4->file.name = path; mp4->file.log = r->connection->log; + mp4->file.directio = of.is_directio; mp4->end = of.size; mp4->start = (ngx_uint_t) start; mp4->length = length; @@ -656,23 +673,14 @@ ngx_http_mp4_handler(ngx_http_request_t log->action = "sending mp4 to client"; - if (clcf->directio <= of.size) { - - /* - * DIRECTIO is set on transfer only - * to allow kernel to cache "moov" atom - */ + if (directio) { + + /* DIRECTIO was switched off, restore it */ if (ngx_directio_on(of.fd) == NGX_FILE_ERROR) { ngx_log_error(NGX_LOG_ALERT, log, ngx_errno, ngx_directio_on_n " \"%s\" failed", path.data); } - - of.is_directio = 1; - - if (mp4) { - mp4->file.directio = 1; - } } r->headers_out.status = NGX_HTTP_OK; From mdounin at mdounin.ru Sun May 25 20:59:02 2025 From: mdounin at mdounin.ru (=?iso-8859-1?q?Maxim_Dounin?=) Date: Sun, 25 May 2025 23:59:02 +0300 Subject: [nginx] Mp4: of.directio_off flag to avoid unneeded syscalls. Message-ID: details: http://freenginx.org/hg/nginx/rev/268e0fb3a16c branches: changeset: 9360:268e0fb3a16c user: Maxim Dounin date: Sun May 25 23:57:39 2025 +0300 description: Mp4: of.directio_off flag to avoid unneeded syscalls. When set, ngx_open_cached_file() won't try to enable directio on the file, allowing the caller to do it itself, but will set is_directio flag in ngx_open_file_info_t and in open file cache. The fact that directio needs to be enabled by the caller is signalled in the of.is_directio_off output flag. This approach makes it possible to avoid unneeded syscalls when directio is enabled, yet the caller needs it disabled for some initial file processing, such as in the mp4 module. diffstat: src/core/ngx_open_file_cache.c | 8 +++++++- src/core/ngx_open_file_cache.h | 2 ++ src/http/modules/ngx_http_mp4_module.c | 10 +++++----- 3 files changed, 14 insertions(+), 6 deletions(-) diffs (105 lines): diff --git a/src/core/ngx_open_file_cache.c b/src/core/ngx_open_file_cache.c --- a/src/core/ngx_open_file_cache.c +++ b/src/core/ngx_open_file_cache.c @@ -249,6 +249,7 @@ ngx_open_cached_file(ngx_open_file_cache of->is_link = file->is_link; of->is_exec = file->is_exec; of->is_directio = file->is_directio; + of->is_directio_off = 0; if (!file->is_dir) { file->count++; @@ -313,6 +314,7 @@ ngx_open_cached_file(ngx_open_file_cache } of->is_directio = file->is_directio; + of->is_directio_off = 0; goto update; } @@ -920,7 +922,11 @@ ngx_open_and_stat_file(ngx_str_t *name, } if (of->directio <= ngx_file_size(&fi)) { - if (ngx_directio_on(fd) == NGX_FILE_ERROR) { + if (of->directio_off) { + of->is_directio = 1; + of->is_directio_off = 1; + + } else if (ngx_directio_on(fd) == NGX_FILE_ERROR) { ngx_log_error(NGX_LOG_ALERT, log, ngx_errno, ngx_directio_on_n " \"%V\" failed", name); diff --git a/src/core/ngx_open_file_cache.h b/src/core/ngx_open_file_cache.h --- a/src/core/ngx_open_file_cache.h +++ b/src/core/ngx_open_file_cache.h @@ -42,12 +42,14 @@ typedef struct { unsigned log:1; unsigned errors:1; unsigned events:1; + unsigned directio_off:1; unsigned is_dir:1; unsigned is_file:1; unsigned is_link:1; unsigned is_exec:1; unsigned is_directio:1; + unsigned is_directio_off:1; } ngx_open_file_info_t; diff --git a/src/http/modules/ngx_http_mp4_module.c b/src/http/modules/ngx_http_mp4_module.c --- a/src/http/modules/ngx_http_mp4_module.c +++ b/src/http/modules/ngx_http_mp4_module.c @@ -479,7 +479,7 @@ ngx_http_mp4_handler(ngx_http_request_t u_char *last; size_t root; ngx_int_t rc, start, end; - ngx_uint_t level, length, directio; + ngx_uint_t level, length; ngx_str_t path, value; ngx_log_t *log; ngx_buf_t *b; @@ -520,6 +520,7 @@ ngx_http_mp4_handler(ngx_http_request_t of.read_ahead = clcf->read_ahead; of.directio = clcf->directio; + of.directio_off = 1; of.valid = clcf->open_file_cache_valid; of.min_uses = clcf->open_file_cache_min_uses; of.errors = clcf->open_file_cache_errors; @@ -579,7 +580,6 @@ ngx_http_mp4_handler(ngx_http_request_t start = -1; length = 0; - directio = 0; r->headers_out.content_length_n = of.size; mp4 = NULL; b = NULL; @@ -615,7 +615,7 @@ ngx_http_mp4_handler(ngx_http_request_t if (start >= 0) { r->single_range = 1; - if (of.is_directio) { + if (of.is_directio && !of.is_directio_off) { /* * DIRECTIO is set on transfer only @@ -627,7 +627,7 @@ ngx_http_mp4_handler(ngx_http_request_t ngx_directio_off_n " \"%s\" failed", path.data); } - directio = 1; + of.is_directio_off = 1; } mp4 = ngx_pcalloc(r->pool, sizeof(ngx_http_mp4_file_t)); @@ -673,7 +673,7 @@ ngx_http_mp4_handler(ngx_http_request_t log->action = "sending mp4 to client"; - if (directio) { + if (of.is_directio_off) { /* DIRECTIO was switched off, restore it */ From mdounin at mdounin.ru Sun May 25 21:03:16 2025 From: mdounin at mdounin.ru (=?iso-8859-1?q?Maxim_Dounin?=) Date: Mon, 26 May 2025 00:03:16 +0300 Subject: [nginx-tests] Tests: mp4 tests with directio and open_file_cache. Message-ID: details: http://freenginx.org/hg/nginx-tests/rev/ba4f76b3b823 branches: changeset: 2008:ba4f76b3b823 user: Maxim Dounin date: Mon May 26 00:02:51 2025 +0300 description: Tests: mp4 tests with directio and open_file_cache. diffstat: mp4_directio.t | 78 ++++++++++++++++++++++++++++++++++++++++++++++++++++++++++ 1 files changed, 78 insertions(+), 0 deletions(-) diffs (83 lines): diff --git a/mp4_directio.t b/mp4_directio.t new file mode 100644 --- /dev/null +++ b/mp4_directio.t @@ -0,0 +1,78 @@ +#!/usr/bin/perl + +# (C) Maxim Dounin + +# Test for directio support in mp4 module. + +############################################################################### + +use warnings; +use strict; + +use Test::More; + +BEGIN { use FindBin; chdir($FindBin::Bin); } + +use lib 'lib'; +use Test::Nginx; + +############################################################################### + +select STDERR; $| = 1; +select STDOUT; $| = 1; + +my $t = Test::Nginx->new()->has(qw/http mp4/)->has_daemon('ffmpeg') + ->write_file_expand('nginx.conf', <<'EOF'); + +%%TEST_GLOBALS%% + +daemon off; + +events { +} + +http { + %%TEST_GLOBALS_HTTP%% + + server { + listen 127.0.0.1:8080; + server_name localhost; + + location / { + mp4; + open_file_cache max=10; + directio 0; + } + } +} + +EOF + +plan(skip_all => 'no lavfi') + unless grep /lavfi/, `ffmpeg -loglevel quiet -formats`; +plan(skip_all => 'no libx264 or libopenh264') + unless grep /libx264|libopenh264/, `ffmpeg -loglevel quiet -encoders`; +system('ffmpeg -nostdin -loglevel quiet -y ' + . '-f lavfi -i testsrc=duration=10:size=320x200:rate=15 ' + . '-g 15 -c:v h264 ' + . "${\($t->testdir())}/test.mp4") == 0 + or die "Can't create mp4 file: $!"; + +$t->run()->plan(2); + +############################################################################### + +# mp4 module uses unaligned reads while parsing mp4 file, though +# failed to disable directio if a file with directio enabled was +# returned from open file cache + +like(http_get('/test.mp4?start=1.0'), qr/ 200 /, 'mp4 directio first'); + +TODO: { +local $TODO = 'not yet' unless $t->has_version('1.29.0') or $^O ne 'linux'; + +like(http_get('/test.mp4?start=1.0'), qr/ 200 /, 'mp4 directio cached'); + +} + +############################################################################### From mdounin at mdounin.ru Sun May 25 21:05:26 2025 From: mdounin at mdounin.ru (=?iso-8859-1?q?Maxim_Dounin?=) Date: Mon, 26 May 2025 00:05:26 +0300 Subject: [nginx] Cache: directio support when reading cache files. Message-ID: details: http://freenginx.org/hg/nginx/rev/e2a6fefd81db branches: changeset: 9361:e2a6fefd81db user: Maxim Dounin date: Mon May 26 00:04:45 2025 +0300 description: Cache: directio support when reading cache files. diffstat: src/http/ngx_http_file_cache.c | 32 ++++++++++++++++++++++++++++---- 1 files changed, 28 insertions(+), 4 deletions(-) diffs (60 lines): diff --git a/src/http/ngx_http_file_cache.c b/src/http/ngx_http_file_cache.c --- a/src/http/ngx_http_file_cache.c +++ b/src/http/ngx_http_file_cache.c @@ -353,7 +353,7 @@ ngx_http_file_cache_open(ngx_http_reques of.valid = clcf->open_file_cache_valid; of.min_uses = clcf->open_file_cache_min_uses; of.events = clcf->open_file_cache_events; - of.directio = NGX_OPEN_FILE_DIRECTIO_OFF; + of.directio = clcf->directio; of.read_ahead = clcf->read_ahead; if (ngx_open_cached_file(clcf->open_file_cache, &c->file.name, &of, r->pool) @@ -380,13 +380,36 @@ ngx_http_file_cache_open(ngx_http_reques c->file.fd = of.fd; c->file.log = r->connection->log; + c->file.directio = of.is_directio; c->uniq = of.uniq; c->length = of.size; c->fs_size = (of.fs_size + cache->bsize - 1) / cache->bsize; - c->buf = ngx_create_temp_buf(r->pool, c->body_start); - if (c->buf == NULL) { - return NGX_ERROR; + if (of.is_directio) { + + c->body_start = ngx_align(c->body_start, clcf->directio_alignment); + + c->buf = ngx_calloc_buf(r->pool); + if (c->buf == NULL) { + return NGX_ERROR; + } + + c->buf->start = ngx_pmemalign(r->pool, c->body_start, + clcf->directio_alignment); + if (c->buf->start == NULL) { + return NGX_ERROR; + } + + c->buf->pos = c->buf->start; + c->buf->last = c->buf->start; + c->buf->end = c->buf->start + c->body_start; + c->buf->temporary = 1; + + } else { + c->buf = ngx_create_temp_buf(r->pool, c->body_start); + if (c->buf == NULL) { + return NGX_ERROR; + } } return ngx_http_file_cache_read(r, c); @@ -1663,6 +1686,7 @@ ngx_http_cache_send(ngx_http_request_t * b->file->fd = c->file.fd; b->file->name = c->file.name; b->file->log = r->connection->log; + b->file->directio = c->file.directio; out.buf = b; out.next = NULL; From mdounin at mdounin.ru Sun May 25 21:29:14 2025 From: mdounin at mdounin.ru (=?utf-8?q?Maxim_Dounin?=) Date: Mon, 26 May 2025 00:29:14 +0300 Subject: [PATCH 0 of 5] open file cache fixes Message-ID: Hello! The following patch series implements some open file cache fixes. Notably, directio handling is fixed to be compatible with threaded IO. -- Maxim Dounin From mdounin at mdounin.ru Sun May 25 21:29:15 2025 From: mdounin at mdounin.ru (=?utf-8?q?Maxim_Dounin?=) Date: Mon, 26 May 2025 00:29:15 +0300 Subject: [PATCH 1 of 5] Disabled open_file_cache on platforms without pread() In-Reply-To: References: Message-ID: <811bf7dc0d46e5e6d69e.1748208555@vm-bsd.mdounin.ru> # HG changeset patch # User Maxim Dounin # Date 1748208420 -10800 # Mon May 26 00:27:00 2025 +0300 # Node ID 811bf7dc0d46e5e6d69e700a1a5a3852d4ba0381 # Parent e2a6fefd81dbe201a88876a95f34620df87259a2 Disabled open_file_cache on platforms without pread(). Current open file cache code cannot properly work on platforms without pread(), since file->sys_offset is not shared across files. Further, it is not set on file initialization after ngx_open_cached_file(), leading to incorrect value 0 instead of non-zero current offset for cached file descriptors. Since platforms without pread() are rather exotic nowadays, fix is to disable open_file_cache for them. diff --git a/src/http/ngx_http_core_module.c b/src/http/ngx_http_core_module.c --- a/src/http/ngx_http_core_module.c +++ b/src/http/ngx_http_core_module.c @@ -4981,6 +4981,8 @@ ngx_http_core_error_page(ngx_conf_t *cf, static char * ngx_http_core_open_file_cache(ngx_conf_t *cf, ngx_command_t *cmd, void *conf) { +#if (NGX_HAVE_PREAD || NGX_WIN32) + ngx_http_core_loc_conf_t *clcf = conf; time_t inactive; @@ -5048,11 +5050,17 @@ ngx_http_core_open_file_cache(ngx_conf_t } clcf->open_file_cache = ngx_open_file_cache_init(cf->pool, max, inactive); - if (clcf->open_file_cache) { - return NGX_CONF_OK; - } - - return NGX_CONF_ERROR; + if (clcf->open_file_cache == NULL) { + return NGX_CONF_ERROR; + } + +#else + ngx_conf_log_error(NGX_LOG_WARN, cf, 0, + "\"open_file_cache\" is not supported " + "on this platform, ignored"); +#endif + + return NGX_CONF_OK; } From mdounin at mdounin.ru Sun May 25 21:29:16 2025 From: mdounin at mdounin.ru (=?utf-8?q?Maxim_Dounin?=) Date: Mon, 26 May 2025 00:29:16 +0300 Subject: [PATCH 2 of 5] Open file cache: style In-Reply-To: References: Message-ID: <8cc90a3e3e74d31a92b2.1748208556@vm-bsd.mdounin.ru> # HG changeset patch # User Maxim Dounin # Date 1748208424 -10800 # Mon May 26 00:27:04 2025 +0300 # Node ID 8cc90a3e3e74d31a92b2732f6f4003684a011fcd # Parent 811bf7dc0d46e5e6d69e700a1a5a3852d4ba0381 Open file cache: style. diff --git a/src/core/ngx_open_file_cache.c b/src/core/ngx_open_file_cache.c --- a/src/core/ngx_open_file_cache.c +++ b/src/core/ngx_open_file_cache.c @@ -974,7 +974,7 @@ ngx_open_file_add_event(ngx_open_file_ca file->use_event = 0; file->event = ngx_calloc(sizeof(ngx_event_t), log); - if (file->event== NULL) { + if (file->event == NULL) { return; } diff --git a/src/core/ngx_open_file_cache.h b/src/core/ngx_open_file_cache.h --- a/src/core/ngx_open_file_cache.h +++ b/src/core/ngx_open_file_cache.h @@ -53,9 +53,7 @@ typedef struct { } ngx_open_file_info_t; -typedef struct ngx_cached_open_file_s ngx_cached_open_file_t; - -struct ngx_cached_open_file_s { +typedef struct { ngx_rbtree_node_t node; ngx_queue_t queue; @@ -87,7 +85,7 @@ struct ngx_cached_open_file_s { unsigned is_directio:1; ngx_event_t *event; -}; +} ngx_cached_open_file_t; typedef struct { From mdounin at mdounin.ru Sun May 25 21:29:17 2025 From: mdounin at mdounin.ru (=?utf-8?q?Maxim_Dounin?=) Date: Mon, 26 May 2025 00:29:17 +0300 Subject: [PATCH 3 of 5] Open file cache: disable_symlinks with open_file_cache_events In-Reply-To: References: Message-ID: # HG changeset patch # User Maxim Dounin # Date 1748208427 -10800 # Mon May 26 00:27:07 2025 +0300 # Node ID f84080a83901176c0dd95681b19290f070de045c # Parent 8cc90a3e3e74d31a92b2732f6f4003684a011fcd Open file cache: disable_symlinks with open_file_cache_events. Previously, different disable_symlinks settings were respected when retrieving a file from open file cache when using periodic retest, but were ignored with using open_file_cache_events. Fix is to test disable_symlinks settings in all cases, and retest the file if requested settings are different from what we already have in the cache. diff --git a/src/core/ngx_open_file_cache.c b/src/core/ngx_open_file_cache.c --- a/src/core/ngx_open_file_cache.c +++ b/src/core/ngx_open_file_cache.c @@ -227,15 +227,15 @@ ngx_open_cached_file(ngx_open_file_cache goto add_event; } - if (file->use_event - || (file->event == NULL - && (of->uniq == 0 || of->uniq == file->uniq) - && now - file->created < of->valid + if ((file->use_event + || (file->event == NULL + && (of->uniq == 0 || of->uniq == file->uniq) + && now - file->created < of->valid)) #if (NGX_HAVE_OPENAT) - && of->disable_symlinks == file->disable_symlinks - && of->disable_symlinks_from == file->disable_symlinks_from + && of->disable_symlinks == file->disable_symlinks + && of->disable_symlinks_from == file->disable_symlinks_from #endif - )) + ) { if (file->err == 0) { From mdounin at mdounin.ru Sun May 25 21:29:18 2025 From: mdounin at mdounin.ru (=?utf-8?q?Maxim_Dounin?=) Date: Mon, 26 May 2025 00:29:18 +0300 Subject: [PATCH 4 of 5] Open file cache: fixed file->uses loss on retest In-Reply-To: References: Message-ID: <6032949667f1e5fda9ce.1748208558@vm-bsd.mdounin.ru> # HG changeset patch # User Maxim Dounin # Date 1748208430 -10800 # Mon May 26 00:27:10 2025 +0300 # Node ID 6032949667f1e5fda9ce364d6eb1668074274c56 # Parent f84080a83901176c0dd95681b19290f070de045c Open file cache: fixed file->uses loss on retest. If an open file was reopened during a retest, but was in use by another request, the cache entry was re-created with file->uses set to 1. Fix is to preserve existing file->uses. diff --git a/src/core/ngx_open_file_cache.c b/src/core/ngx_open_file_cache.c --- a/src/core/ngx_open_file_cache.c +++ b/src/core/ngx_open_file_cache.c @@ -147,6 +147,7 @@ ngx_open_cached_file(ngx_open_file_cache time_t now; uint32_t hash; ngx_int_t rc; + ngx_uint_t uses; ngx_file_info_t fi; ngx_pool_cleanup_t *cln; ngx_cached_open_file_t *file; @@ -348,6 +349,8 @@ ngx_open_cached_file(ngx_open_file_cache file->close = 1; + uses = file->uses; + goto create; } @@ -359,6 +362,8 @@ ngx_open_cached_file(ngx_open_file_cache goto failed; } + uses = 1; + create: if (cache->current >= cache->max) { @@ -387,7 +392,7 @@ create: cache->current++; - file->uses = 1; + file->uses = uses; file->count = 0; file->use_event = 0; file->event = NULL; From mdounin at mdounin.ru Sun May 25 21:29:19 2025 From: mdounin at mdounin.ru (=?utf-8?q?Maxim_Dounin?=) Date: Mon, 26 May 2025 00:29:19 +0300 Subject: [PATCH 5 of 5] Open file cached: correct directio handling with threads In-Reply-To: References: Message-ID: # HG changeset patch # User Maxim Dounin # Date 1748208437 -10800 # Mon May 26 00:27:17 2025 +0300 # Node ID e3e07705481df3c60a3bac8af9101323ee7ceb83 # Parent 6032949667f1e5fda9ce364d6eb1668074274c56 Open file cached: correct directio handling with threads. On Linux with open_file_cache and directio enabled along with threaded IO, if a file descriptor is shared among multiple requests, one request might unexpectedly switch directio on while another request does an unaligned read in a thread, leading to EINVAL from pread(). To fix this, now all directio changes are done with reference counting when open file cache is used, and directio is only re-enabled on a file descriptor when there are no outstanding requests to switch it off. diff --git a/src/core/ngx_open_file_cache.c b/src/core/ngx_open_file_cache.c --- a/src/core/ngx_open_file_cache.c +++ b/src/core/ngx_open_file_cache.c @@ -41,7 +41,8 @@ static void ngx_open_file_add_event(ngx_ ngx_cached_open_file_t *file, ngx_open_file_info_t *of, ngx_log_t *log); static void ngx_open_file_cleanup(void *data); static void ngx_close_cached_file(ngx_open_file_cache_t *cache, - ngx_cached_open_file_t *file, ngx_uint_t min_uses, ngx_log_t *log); + ngx_cached_open_file_t *file, ngx_uint_t min_uses, ngx_uint_t directio_off, + ngx_log_t *log); static void ngx_open_file_del_event(ngx_cached_open_file_t *file); static void ngx_expire_old_cached_files(ngx_open_file_cache_t *cache, ngx_uint_t n, ngx_log_t *log); @@ -51,6 +52,8 @@ static ngx_cached_open_file_t * ngx_open_file_lookup(ngx_open_file_cache_t *cache, ngx_str_t *name, uint32_t hash); static void ngx_open_file_cache_remove(ngx_event_t *ev); +static ngx_open_file_cache_cleanup_t * + ngx_open_file_cache_get_cleanup(ngx_pool_t *p, ngx_fd_t fd); ngx_open_file_cache_t * @@ -118,7 +121,7 @@ ngx_open_file_cache_cleanup(void *data) if (!file->err && !file->is_dir) { file->close = 1; file->count = 0; - ngx_close_cached_file(cache, file, 0, ngx_cycle->log); + ngx_close_cached_file(cache, file, 0, 0, ngx_cycle->log); } else { ngx_free(file->name); @@ -396,6 +399,7 @@ create: file->count = 0; file->use_event = 0; file->event = NULL; + file->directio_off = of->is_directio_off; add_event: @@ -449,6 +453,7 @@ found: ofcln->cache = cache; ofcln->file = file; ofcln->min_uses = of->min_uses; + ofcln->directio_off = of->is_directio_off; ofcln->log = pool->log; } @@ -1032,7 +1037,8 @@ ngx_open_file_cleanup(void *data) c->file->count--; - ngx_close_cached_file(c->cache, c->file, c->min_uses, c->log); + ngx_close_cached_file(c->cache, c->file, c->min_uses, c->directio_off, + c->log); /* drop one or two expired open files */ ngx_expire_old_cached_files(c->cache, 1, c->log); @@ -1041,12 +1047,25 @@ ngx_open_file_cleanup(void *data) static void ngx_close_cached_file(ngx_open_file_cache_t *cache, - ngx_cached_open_file_t *file, ngx_uint_t min_uses, ngx_log_t *log) + ngx_cached_open_file_t *file, ngx_uint_t min_uses, ngx_uint_t directio_off, + ngx_log_t *log) { ngx_log_debug5(NGX_LOG_DEBUG_CORE, log, 0, "close cached open file: %s, fd:%d, c:%d, u:%d, %d", file->name, file->fd, file->count, file->uses, file->close); + if (directio_off) { + file->directio_off--; + + if (file->directio_off == 0) { + if (ngx_directio_on(file->fd) == NGX_FILE_ERROR) { + ngx_log_error(NGX_LOG_ALERT, log, ngx_errno, + ngx_directio_on_n " \"%s\" failed", + file->name); + } + } + } + if (!file->close) { file->accessed = ngx_time(); @@ -1143,7 +1162,7 @@ ngx_expire_old_cached_files(ngx_open_fil if (!file->err && !file->is_dir) { file->close = 1; - ngx_close_cached_file(cache, file, 0, log); + ngx_close_cached_file(cache, file, 0, 0, log); } else { ngx_free(file->name); @@ -1255,10 +1274,92 @@ ngx_open_file_cache_remove(ngx_event_t * file->close = 1; - ngx_close_cached_file(fev->cache, file, 0, ev->log); + ngx_close_cached_file(fev->cache, file, 0, 0, ev->log); /* free memory only when fev->cache and fev->file are already not needed */ ngx_free(ev->data); ngx_free(ev); } + + +ngx_int_t +ngx_open_file_directio_on(ngx_fd_t fd, ngx_pool_t *pool) +{ + ngx_open_file_cache_cleanup_t *c; + + /* + * DIRECTIO is only re-enabled on a file descriptor + * when there are no outstanding requests to switch it off + */ + + c = ngx_open_file_cache_get_cleanup(pool, fd); + + if (c) { + if (!c->directio_off) { + return NGX_OK; + } + + c->directio_off = 0; + c->file->directio_off--; + + if (c->file->directio_off > 0) { + return NGX_OK; + } + } + + if (ngx_directio_on(fd) == NGX_FILE_ERROR) { + return NGX_ERROR; + } + + return NGX_OK; +} + + +ngx_int_t +ngx_open_file_directio_off(ngx_fd_t fd, ngx_pool_t *pool) +{ + ngx_open_file_cache_cleanup_t *c; + + c = ngx_open_file_cache_get_cleanup(pool, fd); + + if (c) { + if (c->directio_off) { + return NGX_OK; + } + + c->directio_off = 1; + c->file->directio_off++; + + if (c->file->directio_off > 1) { + return NGX_OK; + } + } + + if (ngx_directio_off(fd) == NGX_FILE_ERROR) { + return NGX_ERROR; + } + + return NGX_OK; +} + + +static ngx_open_file_cache_cleanup_t * +ngx_open_file_cache_get_cleanup(ngx_pool_t *p, ngx_fd_t fd) +{ + ngx_pool_cleanup_t *cln; + ngx_open_file_cache_cleanup_t *c; + + for (cln = p->cleanup; cln; cln = cln->next) { + if (cln->handler == ngx_open_file_cleanup) { + + c = cln->data; + + if (c->file->fd == fd) { + return c; + } + } + } + + return NULL; +} diff --git a/src/core/ngx_open_file_cache.h b/src/core/ngx_open_file_cache.h --- a/src/core/ngx_open_file_cache.h +++ b/src/core/ngx_open_file_cache.h @@ -67,6 +67,8 @@ typedef struct { off_t size; ngx_err_t err; + ngx_uint_t directio_off; + uint32_t uses; #if (NGX_HAVE_OPENAT) @@ -103,6 +105,7 @@ typedef struct { ngx_open_file_cache_t *cache; ngx_cached_open_file_t *file; ngx_uint_t min_uses; + ngx_uint_t directio_off; ngx_log_t *log; } ngx_open_file_cache_cleanup_t; @@ -125,5 +128,8 @@ ngx_open_file_cache_t *ngx_open_file_cac ngx_int_t ngx_open_cached_file(ngx_open_file_cache_t *cache, ngx_str_t *name, ngx_open_file_info_t *of, ngx_pool_t *pool); +ngx_int_t ngx_open_file_directio_on(ngx_fd_t fd, ngx_pool_t *pool); +ngx_int_t ngx_open_file_directio_off(ngx_fd_t fd, ngx_pool_t *pool); + #endif /* _NGX_OPEN_FILE_CACHE_H_INCLUDED_ */ diff --git a/src/core/ngx_output_chain.c b/src/core/ngx_output_chain.c --- a/src/core/ngx_output_chain.c +++ b/src/core/ngx_output_chain.c @@ -553,7 +553,9 @@ ngx_output_chain_copy_buf(ngx_output_cha #if (NGX_HAVE_ALIGNED_DIRECTIO) if (ctx->unaligned) { - if (ngx_directio_off(src->file->fd) == NGX_FILE_ERROR) { + if (ngx_open_file_directio_off(src->file->fd, ctx->pool) + != NGX_OK) + { ngx_log_error(NGX_LOG_ALERT, ctx->pool->log, ngx_errno, ngx_directio_off_n " \"%s\" failed", src->file->name.data); @@ -600,7 +602,9 @@ ngx_output_chain_copy_buf(ngx_output_cha err = ngx_errno; - if (ngx_directio_on(src->file->fd) == NGX_FILE_ERROR) { + if (ngx_open_file_directio_on(src->file->fd, ctx->pool) + != NGX_OK) + { ngx_log_error(NGX_LOG_ALERT, ctx->pool->log, ngx_errno, ngx_directio_on_n " \"%s\" failed", src->file->name.data); diff --git a/src/http/modules/ngx_http_mp4_module.c b/src/http/modules/ngx_http_mp4_module.c --- a/src/http/modules/ngx_http_mp4_module.c +++ b/src/http/modules/ngx_http_mp4_module.c @@ -622,7 +622,7 @@ ngx_http_mp4_handler(ngx_http_request_t * to allow kernel to cache "moov" atom */ - if (ngx_directio_off(of.fd) == NGX_FILE_ERROR) { + if (ngx_open_file_directio_off(of.fd, r->pool) != NGX_OK) { ngx_log_error(NGX_LOG_ALERT, log, ngx_errno, ngx_directio_off_n " \"%s\" failed", path.data); } @@ -677,7 +677,7 @@ ngx_http_mp4_handler(ngx_http_request_t /* DIRECTIO was switched off, restore it */ - if (ngx_directio_on(of.fd) == NGX_FILE_ERROR) { + if (ngx_open_file_directio_on(of.fd, r->pool) != NGX_OK) { ngx_log_error(NGX_LOG_ALERT, log, ngx_errno, ngx_directio_on_n " \"%s\" failed", path.data); } From mdounin at mdounin.ru Sun May 25 21:46:35 2025 From: mdounin at mdounin.ru (=?utf-8?q?Maxim_Dounin?=) Date: Mon, 26 May 2025 00:46:35 +0300 Subject: [PATCH 0 of 6] various compatibility fixes Message-ID: Hello! The following patch series fixes some compilation issues as observed on various exotic platforms, notably seen on MINIX, Cygwin, and FreeBSD 2.2.9. -- Maxim Dounin From mdounin at mdounin.ru Sun May 25 21:46:36 2025 From: mdounin at mdounin.ru (=?utf-8?q?Maxim_Dounin?=) Date: Mon, 26 May 2025 00:46:36 +0300 Subject: [PATCH 1 of 6] Configure: fixed nobody/nogroup detection stderr redirection In-Reply-To: References: Message-ID: <03f5c84e7e8c05ce16f6.1748209596@vm-bsd.mdounin.ru> # HG changeset patch # User Maxim Dounin # Date 1748209461 -10800 # Mon May 26 00:44:21 2025 +0300 # Node ID 03f5c84e7e8c05ce16f6f36452e4cb818c85dde6 # Parent e2a6fefd81dbe201a88876a95f34620df87259a2 Configure: fixed nobody/nogroup detection stderr redirection. Previously, "grep: /etc/group: No such file or directory" errors were printed on systems without the /etc/group file along with the configure output. Fix is to use correct stderr redirection. diff --git a/auto/unix b/auto/unix --- a/auto/unix +++ b/auto/unix @@ -7,13 +7,13 @@ NGX_USER=${NGX_USER:-nobody} if [ -z "$NGX_GROUP" ]; then if [ $NGX_USER = nobody ]; then - if grep nobody /etc/group 2>&1 >/dev/null; then + if grep nobody /etc/group >/dev/null 2>&1; then echo "checking for nobody group ... found" NGX_GROUP=nobody else echo "checking for nobody group ... not found" - if grep nogroup /etc/group 2>&1 >/dev/null; then + if grep nogroup /etc/group >/dev/null 2>&1; then echo "checking for nogroup group ... found" NGX_GROUP=nogroup else From mdounin at mdounin.ru Sun May 25 21:46:37 2025 From: mdounin at mdounin.ru (=?utf-8?q?Maxim_Dounin?=) Date: Mon, 26 May 2025 00:46:37 +0300 Subject: [PATCH 2 of 6] Configure: added uint8_t and uint16_t detection In-Reply-To: References: Message-ID: <38f1f374523ff2630e59.1748209597@vm-bsd.mdounin.ru> # HG changeset patch # User Maxim Dounin # Date 1748209464 -10800 # Mon May 26 00:44:24 2025 +0300 # Node ID 38f1f374523ff2630e59f6a722fd6f9d7f70ac01 # Parent 03f5c84e7e8c05ce16f6f36452e4cb818c85dde6 Configure: added uint8_t and uint16_t detection. This fixes compilation on some old systems (though mostly for consistency with uint32_t and uint64_t). diff --git a/auto/unix b/auto/unix --- a/auto/unix +++ b/auto/unix @@ -645,6 +645,8 @@ ngx_param=NGX_PTR_SIZE; ngx_value=$ngx_s NGX_INCLUDE_AUTO_CONFIG_H="#include \"ngx_auto_config.h\"" +ngx_type="uint8_t"; ngx_types="u_int8_t"; . auto/types/typedef +ngx_type="uint16_t"; ngx_types="u_int16_t"; . auto/types/typedef ngx_type="uint32_t"; ngx_types="u_int32_t"; . auto/types/typedef ngx_type="uint64_t"; ngx_types="u_int64_t"; . auto/types/typedef From mdounin at mdounin.ru Sun May 25 21:46:38 2025 From: mdounin at mdounin.ru (=?utf-8?q?Maxim_Dounin?=) Date: Mon, 26 May 2025 00:46:38 +0300 Subject: [PATCH 3 of 6] Cleaned up iov_base, msg_name, msg_control type casts In-Reply-To: References: Message-ID: <4eed7851024b4ca5d771.1748209598@vm-bsd.mdounin.ru> # HG changeset patch # User Maxim Dounin # Date 1748209475 -10800 # Mon May 26 00:44:35 2025 +0300 # Node ID 4eed7851024b4ca5d77107676025e84324e23c74 # Parent 38f1f374523ff2630e59f6a722fd6f9d7f70ac01 Cleaned up iov_base, msg_name, msg_control type casts. In old OSes iov_base, msg_name, and msg_control fields were caddr_t ("char *" in case of iov_base), though later were changed to "void *". In particular, in FreeBSD this change happened around FreeBSD 4.0. With newer "void *" type no type casts are needed, but with caddr_t type casts were required in most cases. Previously, casts were used inconsistently across the code: to caddr_t, to "void *", or no casts at all in some recent code. With this change, casts to "void *" are consistently used in all relevant places. diff --git a/src/event/ngx_event_udp.c b/src/event/ngx_event_udp.c --- a/src/event/ngx_event_udp.c +++ b/src/event/ngx_event_udp.c @@ -70,14 +70,14 @@ ngx_event_recvmsg(ngx_event_t *ev) iov[0].iov_base = (void *) buffer; iov[0].iov_len = sizeof(buffer); - msg.msg_name = &sa; + msg.msg_name = (void *) &sa; msg.msg_namelen = sizeof(ngx_sockaddr_t); msg.msg_iov = iov; msg.msg_iovlen = 1; #if (NGX_HAVE_ADDRINFO_CMSG) if (ls->wildcard) { - msg.msg_control = &msg_control; + msg.msg_control = (void *) &msg_control; msg.msg_controllen = sizeof(msg_control); ngx_memzero(&msg_control, sizeof(msg_control)); @@ -108,7 +108,7 @@ ngx_event_recvmsg(ngx_event_t *ev) } #endif - sockaddr = msg.msg_name; + sockaddr = (void *) msg.msg_name; socklen = msg.msg_namelen; if (socklen > (socklen_t) sizeof(ngx_sockaddr_t)) { diff --git a/src/event/quic/ngx_event_quic_output.c b/src/event/quic/ngx_event_quic_output.c --- a/src/event/quic/ngx_event_quic_output.c +++ b/src/event/quic/ngx_event_quic_output.c @@ -410,16 +410,16 @@ ngx_quic_send_segments(ngx_connection_t ngx_memzero(&msg, sizeof(struct msghdr)); ngx_memzero(msg_control, sizeof(msg_control)); + iov.iov_base = (void *) buf; iov.iov_len = len; - iov.iov_base = buf; msg.msg_iov = &iov; msg.msg_iovlen = 1; - msg.msg_name = sockaddr; + msg.msg_name = (void *) sockaddr; msg.msg_namelen = socklen; - msg.msg_control = msg_control; + msg.msg_control = (void *) msg_control; msg.msg_controllen = sizeof(msg_control); cmsg = CMSG_FIRSTHDR(&msg); @@ -698,19 +698,19 @@ ngx_quic_send(ngx_connection_t *c, u_cha ngx_memzero(&msg, sizeof(struct msghdr)); + iov.iov_base = (void *) buf; iov.iov_len = len; - iov.iov_base = buf; msg.msg_iov = &iov; msg.msg_iovlen = 1; - msg.msg_name = sockaddr; + msg.msg_name = (void *) sockaddr; msg.msg_namelen = socklen; #if (NGX_HAVE_ADDRINFO_CMSG) if (c->listening && c->listening->wildcard && c->local_sockaddr) { - msg.msg_control = msg_control; + msg.msg_control = (void *) msg_control; msg.msg_controllen = sizeof(msg_control); ngx_memzero(msg_control, sizeof(msg_control)); diff --git a/src/event/quic/ngx_event_quic_udp.c b/src/event/quic/ngx_event_quic_udp.c --- a/src/event/quic/ngx_event_quic_udp.c +++ b/src/event/quic/ngx_event_quic_udp.c @@ -68,14 +68,14 @@ ngx_quic_recvmsg(ngx_event_t *ev) iov[0].iov_base = (void *) buffer; iov[0].iov_len = sizeof(buffer); - msg.msg_name = &sa; + msg.msg_name = (void *) &sa; msg.msg_namelen = sizeof(ngx_sockaddr_t); msg.msg_iov = iov; msg.msg_iovlen = 1; #if (NGX_HAVE_ADDRINFO_CMSG) if (ls->wildcard) { - msg.msg_control = &msg_control; + msg.msg_control = (void *) &msg_control; msg.msg_controllen = sizeof(msg_control); ngx_memzero(&msg_control, sizeof(msg_control)); @@ -106,7 +106,7 @@ ngx_quic_recvmsg(ngx_event_t *ev) } #endif - sockaddr = msg.msg_name; + sockaddr = (void *) msg.msg_name; socklen = msg.msg_namelen; if (socklen > (socklen_t) sizeof(ngx_sockaddr_t)) { diff --git a/src/os/unix/ngx_channel.c b/src/os/unix/ngx_channel.c --- a/src/os/unix/ngx_channel.c +++ b/src/os/unix/ngx_channel.c @@ -31,7 +31,7 @@ ngx_write_channel(ngx_socket_t s, ngx_ch msg.msg_controllen = 0; } else { - msg.msg_control = (caddr_t) &cmsg; + msg.msg_control = (void *) &cmsg; msg.msg_controllen = sizeof(cmsg); ngx_memzero(&cmsg, sizeof(cmsg)); @@ -68,7 +68,7 @@ ngx_write_channel(ngx_socket_t s, ngx_ch #endif - iov[0].iov_base = (char *) ch; + iov[0].iov_base = (void *) ch; iov[0].iov_len = size; msg.msg_name = NULL; @@ -109,7 +109,7 @@ ngx_read_channel(ngx_socket_t s, ngx_cha int fd; #endif - iov[0].iov_base = (char *) ch; + iov[0].iov_base = (void *) ch; iov[0].iov_len = size; msg.msg_name = NULL; @@ -118,7 +118,7 @@ ngx_read_channel(ngx_socket_t s, ngx_cha msg.msg_iovlen = 1; #if (NGX_HAVE_MSGHDR_MSG_CONTROL) - msg.msg_control = (caddr_t) &cmsg; + msg.msg_control = (void *) &cmsg; msg.msg_controllen = sizeof(cmsg); #else msg.msg_accrights = (caddr_t) &fd; diff --git a/src/os/unix/ngx_udp_sendmsg_chain.c b/src/os/unix/ngx_udp_sendmsg_chain.c --- a/src/os/unix/ngx_udp_sendmsg_chain.c +++ b/src/os/unix/ngx_udp_sendmsg_chain.c @@ -216,7 +216,7 @@ ngx_sendmsg_vec(ngx_connection_t *c, ngx ngx_memzero(&msg, sizeof(struct msghdr)); if (c->socklen) { - msg.msg_name = c->sockaddr; + msg.msg_name = (void *) c->sockaddr; msg.msg_namelen = c->socklen; } @@ -226,7 +226,7 @@ ngx_sendmsg_vec(ngx_connection_t *c, ngx #if (NGX_HAVE_ADDRINFO_CMSG) if (c->listening && c->listening->wildcard && c->local_sockaddr) { - msg.msg_control = msg_control; + msg.msg_control = (void *) msg_control; msg.msg_controllen = sizeof(msg_control); ngx_memzero(msg_control, sizeof(msg_control)); From mdounin at mdounin.ru Sun May 25 21:46:39 2025 From: mdounin at mdounin.ru (=?utf-8?q?Maxim_Dounin?=) Date: Mon, 26 May 2025 00:46:39 +0300 Subject: [PATCH 4 of 6] Adjusted mmap() type casts In-Reply-To: References: Message-ID: <3e11162ed39312387fc7.1748209599@vm-bsd.mdounin.ru> # HG changeset patch # User Maxim Dounin # Date 1748209484 -10800 # Mon May 26 00:44:44 2025 +0300 # Node ID 3e11162ed39312387fc79a731071b0a50aa15acc # Parent 4eed7851024b4ca5d77107676025e84324e23c74 Adjusted mmap() type casts. Type casting mmap() result explicitly to (u_char *) is only needed on systems where mmap() returns caddr_t, but on these systems MAP_FAILED also needs to be casted. Added appropriate type casts. diff --git a/src/os/unix/ngx_shmem.c b/src/os/unix/ngx_shmem.c --- a/src/os/unix/ngx_shmem.c +++ b/src/os/unix/ngx_shmem.c @@ -18,7 +18,7 @@ ngx_shm_alloc(ngx_shm_t *shm) PROT_READ|PROT_WRITE, MAP_ANON|MAP_SHARED, -1, 0); - if (shm->addr == MAP_FAILED) { + if (shm->addr == (u_char *) MAP_FAILED) { ngx_log_error(NGX_LOG_ALERT, shm->log, ngx_errno, "mmap(MAP_ANON|MAP_SHARED, %uz) failed", shm->size); return NGX_ERROR; @@ -55,7 +55,7 @@ ngx_shm_alloc(ngx_shm_t *shm) shm->addr = (u_char *) mmap(NULL, shm->size, PROT_READ|PROT_WRITE, MAP_SHARED, fd, 0); - if (shm->addr == MAP_FAILED) { + if (shm->addr == (u_char *) MAP_FAILED) { ngx_log_error(NGX_LOG_ALERT, shm->log, ngx_errno, "mmap(/dev/zero, MAP_SHARED, %uz) failed", shm->size); } @@ -65,7 +65,7 @@ ngx_shm_alloc(ngx_shm_t *shm) "close(\"/dev/zero\") failed"); } - return (shm->addr == MAP_FAILED) ? NGX_ERROR : NGX_OK; + return (shm->addr == (u_char *) MAP_FAILED) ? NGX_ERROR : NGX_OK; } From mdounin at mdounin.ru Sun May 25 21:46:40 2025 From: mdounin at mdounin.ru (=?utf-8?q?Maxim_Dounin?=) Date: Mon, 26 May 2025 00:46:40 +0300 Subject: [PATCH 5 of 6] Fixed unused variable in ngx_set_srcaddr_cmsg() on MINIX In-Reply-To: References: Message-ID: <7a595fa6ade10f801f6e.1748209600@vm-bsd.mdounin.ru> # HG changeset patch # User Maxim Dounin # Date 1748209507 -10800 # Mon May 26 00:45:07 2025 +0300 # Node ID 7a595fa6ade10f801f6e9bc84a7fd8fc1f9cca21 # Parent 3e11162ed39312387fc79a731071b0a50aa15acc Fixed unused variable in ngx_set_srcaddr_cmsg() on MINIX. diff --git a/src/os/unix/ngx_udp_sendmsg_chain.c b/src/os/unix/ngx_udp_sendmsg_chain.c --- a/src/os/unix/ngx_udp_sendmsg_chain.c +++ b/src/os/unix/ngx_udp_sendmsg_chain.c @@ -245,7 +245,10 @@ ngx_sendmsg_vec(ngx_connection_t *c, ngx size_t ngx_set_srcaddr_cmsg(struct cmsghdr *cmsg, struct sockaddr *local_sockaddr) { +#if (NGX_HAVE_IP_SENDSRCADDR || NGX_HAVE_IP_PKTINFO \ + || (NGX_HAVE_INET6 && NGX_HAVE_IPV6_RECVPKTINFO)) size_t len; +#endif #if (NGX_HAVE_IP_SENDSRCADDR) struct in_addr *addr; struct sockaddr_in *sin; From mdounin at mdounin.ru Sun May 25 21:46:41 2025 From: mdounin at mdounin.ru (=?utf-8?q?Maxim_Dounin?=) Date: Mon, 26 May 2025 00:46:41 +0300 Subject: [PATCH 6 of 6] Compatibility with systems without SA_SIGINFO in sigaction() In-Reply-To: References: Message-ID: <95e5cc6c73d1b94a59c4.1748209601@vm-bsd.mdounin.ru> # HG changeset patch # User Maxim Dounin # Date 1748209526 -10800 # Mon May 26 00:45:26 2025 +0300 # Node ID 95e5cc6c73d1b94a59c4eea26bd2956a1cdc2f3d # Parent 7a595fa6ade10f801f6e9bc84a7fd8fc1f9cca21 Compatibility with systems without SA_SIGINFO in sigaction(). This change restores compatibility with some older systems without SA_SIGINFO support, broken by 6985:23ecffd5bcfe. Notably, this fixes compilation on MINIX. diff --git a/auto/unix b/auto/unix --- a/auto/unix +++ b/auto/unix @@ -1043,3 +1043,16 @@ ngx_feature_test='struct addrinfo *res; if (getaddrinfo("localhost", NULL, NULL, &res) != 0) return 1; freeaddrinfo(res)' . auto/feature + + +ngx_feature="sigaction(SA_SIGINFO)" +ngx_feature_name="NGX_HAVE_SIGINFO" +ngx_feature_run=no +ngx_feature_incs="#include " +ngx_feature_path= +ngx_feature_libs= +ngx_feature_test="struct sigaction sa; + sa.sa_flags = SA_SIGINFO; + sa.sa_sigaction = NULL; + if (sigaction(0, &sa, NULL) == -1) return 1;" +. auto/feature diff --git a/src/os/unix/ngx_process.c b/src/os/unix/ngx_process.c --- a/src/os/unix/ngx_process.c +++ b/src/os/unix/ngx_process.c @@ -15,13 +15,21 @@ typedef struct { int signo; char *signame; char *name; +#if (NGX_HAVE_SIGINFO) void (*handler)(int signo, siginfo_t *siginfo, void *ucontext); +#else + void (*handler)(int signo); +#endif } ngx_signal_t; static void ngx_execute_proc(ngx_cycle_t *cycle, void *data); +#if (NGX_HAVE_SIGINFO) static void ngx_signal_handler(int signo, siginfo_t *siginfo, void *ucontext); +#else +static void ngx_signal_handler(int signo); +#endif static void ngx_process_get_status(void); static void ngx_unlock_mutexes(ngx_pid_t pid); @@ -291,8 +299,12 @@ ngx_init_signals(ngx_log_t *log) ngx_memzero(&sa, sizeof(struct sigaction)); if (sig->handler) { +#if (NGX_HAVE_SIGINFO) sa.sa_sigaction = sig->handler; sa.sa_flags = SA_SIGINFO; +#else + sa.sa_handler = sig->handler; +#endif } else { sa.sa_handler = SIG_IGN; @@ -315,8 +327,13 @@ ngx_init_signals(ngx_log_t *log) } +#if (NGX_HAVE_SIGINFO) static void ngx_signal_handler(int signo, siginfo_t *siginfo, void *ucontext) +#else +static void +ngx_signal_handler(int signo) +#endif { char *action; ngx_int_t ignore; @@ -441,12 +458,15 @@ ngx_signal_handler(int signo, siginfo_t break; } +#if (NGX_HAVE_SIGINFO) if (siginfo && siginfo->si_pid) { ngx_log_error(NGX_LOG_NOTICE, ngx_cycle->log, 0, "signal %d (%s) received from %P%s", signo, sig->signame, siginfo->si_pid, action); - } else { + } else +#endif + { ngx_log_error(NGX_LOG_NOTICE, ngx_cycle->log, 0, "signal %d (%s) received%s", signo, sig->signame, action); From mdounin at mdounin.ru Mon May 26 19:52:29 2025 From: mdounin at mdounin.ru (=?iso-8859-1?q?Maxim_Dounin?=) Date: Mon, 26 May 2025 22:52:29 +0300 Subject: [nginx] Fixed compilation without O_DIRECT, broken by 9359:31419... Message-ID: details: http://freenginx.org/hg/nginx/rev/d1edde45c5f1 branches: changeset: 9362:d1edde45c5f1 user: Maxim Dounin date: Mon May 26 22:49:07 2025 +0300 description: Fixed compilation without O_DIRECT, broken by 9359:314192d67a91. diffstat: src/os/unix/ngx_files.h | 9 +++++++++ 1 files changed, 9 insertions(+), 0 deletions(-) diffs (29 lines): diff --git a/src/os/unix/ngx_files.h b/src/os/unix/ngx_files.h --- a/src/os/unix/ngx_files.h +++ b/src/os/unix/ngx_files.h @@ -336,16 +336,25 @@ ngx_int_t ngx_directio_off(ngx_fd_t fd); #define ngx_directio_on(fd) fcntl(fd, F_NOCACHE, 1) #define ngx_directio_on_n "fcntl(F_NOCACHE, 1)" +#define ngx_directio_off(fd) fcntl(fd, F_NOCACHE, 0) +#define ngx_directio_off_n "fcntl(F_NOCACHE, 0)" + #elif (NGX_HAVE_DIRECTIO) #define ngx_directio_on(fd) directio(fd, DIRECTIO_ON) #define ngx_directio_on_n "directio(DIRECTIO_ON)" +#define ngx_directio_off(fd) directio(fd, DIRECTIO_OFF) +#define ngx_directio_off_n "directio(DIRECTIO_OFF)" + #else #define ngx_directio_on(fd) 0 #define ngx_directio_on_n "ngx_directio_on_n" +#define ngx_directio_off(fd) 0 +#define ngx_directio_off_n "ngx_directio_off_n" + #endif size_t ngx_fs_bsize(u_char *name); From mdounin at mdounin.ru Sat May 31 20:23:15 2025 From: mdounin at mdounin.ru (=?utf-8?q?Maxim_Dounin?=) Date: Sat, 31 May 2025 23:23:15 +0300 Subject: [PATCH 1 of 4] Win32: fixed 64-bit compilation with MSVC after 9333:1996ea0bc55d Message-ID: <9228d497cb38bd5fda21.1748722995@vm-bsd.mdounin.ru> # HG changeset patch # User Maxim Dounin # Date 1748666354 -10800 # Sat May 31 07:39:14 2025 +0300 # Node ID 9228d497cb38bd5fda2177380c3eee372a3ddbfd # Parent d1edde45c5f14fbe5e820a6f3a861c086f3626c5 Win32: fixed 64-bit compilation with MSVC after 9333:1996ea0bc55d. Compatibility with zlib in LIT_MEM mode added in 9333:1996ea0bc55d triggered MSVC warning C4334 (result of 32-bit shift implicitly converted to 64 bits), fixed by adding explicit conversion. diff --git a/src/http/modules/ngx_http_gzip_filter_module.c b/src/http/modules/ngx_http_gzip_filter_module.c --- a/src/http/modules/ngx_http_gzip_filter_module.c +++ b/src/http/modules/ngx_http_gzip_filter_module.c @@ -520,7 +520,7 @@ ngx_http_gzip_filter_memory(ngx_http_req * buffer for literals/lengths. */ - ctx->allocated += (1 << (memlevel + 6)); + ctx->allocated += ((ngx_uint_t) 1 << (memlevel + 6)); ctx->zlib_lit_mem = 1; } From mdounin at mdounin.ru Sat May 31 20:23:16 2025 From: mdounin at mdounin.ru (=?utf-8?q?Maxim_Dounin?=) Date: Sat, 31 May 2025 23:23:16 +0300 Subject: [PATCH 2 of 4] Win32: cleaned up most of C4244 warnings with 32-bit compilation In-Reply-To: <9228d497cb38bd5fda21.1748722995@vm-bsd.mdounin.ru> References: <9228d497cb38bd5fda21.1748722995@vm-bsd.mdounin.ru> Message-ID: <1ce7a2381e6a88063677.1748722996@vm-bsd.mdounin.ru> # HG changeset patch # User Maxim Dounin # Date 1748666368 -10800 # Sat May 31 07:39:28 2025 +0300 # Node ID 1ce7a2381e6a880636779800499a0bf99ca7bd6e # Parent 9228d497cb38bd5fda2177380c3eee372a3ddbfd Win32: cleaned up most of C4244 warnings with 32-bit compilation. C4244 warnings (conversion from 'type1' to 'type2', possible loss of data) were disabled in 6861:e4590dfd97ff as part of introducing support for 64-bit compilation with MSVC. Still, these warnings remain useful in some cases. Additionally, they explain multiple otherwise unneeded type casts in the code. This change resolves most of the warnings as observed during 32-bit compilation with C4244 warnings enabled by introducing additional type casts, in most cases already used in other parts of the code in similar constructs. diff --git a/src/core/ngx_inet.c b/src/core/ngx_inet.c --- a/src/core/ngx_inet.c +++ b/src/core/ngx_inet.c @@ -1286,7 +1286,7 @@ ngx_inet_add_addr(ngx_pool_t *pool, ngx_ ngx_memcpy(sa, sockaddr, socklen); - ngx_inet_set_port(sa, u->port + i); + ngx_inet_set_port(sa, u->port + (in_port_t) i); switch (sa->sa_family) { diff --git a/src/core/ngx_times.c b/src/core/ngx_times.c --- a/src/core/ngx_times.c +++ b/src/core/ngx_times.c @@ -332,7 +332,7 @@ ngx_gmtime(time_t t, ngx_tm_t *tp) t = 0; } - days = t / 86400; + days = (ngx_uint_t) t / 86400; sec = t % 86400; /* diff --git a/src/http/ngx_http_file_cache.c b/src/http/ngx_http_file_cache.c --- a/src/http/ngx_http_file_cache.c +++ b/src/http/ngx_http_file_cache.c @@ -387,7 +387,8 @@ ngx_http_file_cache_open(ngx_http_reques if (of.is_directio) { - c->body_start = ngx_align(c->body_start, clcf->directio_alignment); + c->body_start = ngx_align(c->body_start, + (size_t) clcf->directio_alignment); c->buf = ngx_calloc_buf(r->pool); if (c->buf == NULL) { @@ -395,7 +396,7 @@ ngx_http_file_cache_open(ngx_http_reques } c->buf->start = ngx_pmemalign(r->pool, c->body_start, - clcf->directio_alignment); + (size_t) clcf->directio_alignment); if (c->buf->start == NULL) { return NGX_ERROR; } diff --git a/src/http/ngx_http_request_body.c b/src/http/ngx_http_request_body.c --- a/src/http/ngx_http_request_body.c +++ b/src/http/ngx_http_request_body.c @@ -1220,7 +1220,8 @@ ngx_http_request_body_chunked_filter(ngx } } else { - ngx_memmove(b->last, cl->buf->pos, rb->chunked->size); + ngx_memmove(b->last, cl->buf->pos, + (size_t) rb->chunked->size); b->last += rb->chunked->size; cl->buf->pos += rb->chunked->size; rb->chunked->size = 0; From mdounin at mdounin.ru Sat May 31 20:23:17 2025 From: mdounin at mdounin.ru (=?utf-8?q?Maxim_Dounin?=) Date: Sat, 31 May 2025 23:23:17 +0300 Subject: [PATCH 3 of 4] Postpone filter: fixed incorrect content length check In-Reply-To: <9228d497cb38bd5fda21.1748722995@vm-bsd.mdounin.ru> References: <9228d497cb38bd5fda21.1748722995@vm-bsd.mdounin.ru> Message-ID: <41e7de4b8d3918a501dc.1748722997@vm-bsd.mdounin.ru> # HG changeset patch # User Maxim Dounin # Date 1748666373 -10800 # Sat May 31 07:39:33 2025 +0300 # Node ID 41e7de4b8d3918a501dc95c8b0e706703675fc92 # Parent 1ce7a2381e6a880636779800499a0bf99ca7bd6e Postpone filter: fixed incorrect content length check. The code in ngx_http_postpone_filter_in_memory() used to assign r->headers_out.content_length_n to a size_t variable before comparison, which can lead to incorrect results on 32-bit platforms. Fix is to compare r->headers_out.content_length_n before conversion to size_t. Found with MSVC with C4244 warnings (conversion from 'type1' to 'type2', possible loss of data) enabled. diff --git a/src/http/ngx_http_postpone_filter_module.c b/src/http/ngx_http_postpone_filter_module.c --- a/src/http/ngx_http_postpone_filter_module.c +++ b/src/http/ngx_http_postpone_filter_module.c @@ -194,14 +194,18 @@ ngx_http_postpone_filter_in_memory(ngx_h clcf = ngx_http_get_module_loc_conf(r, ngx_http_core_module); if (r->headers_out.content_length_n != -1) { - len = r->headers_out.content_length_n; - if (len > clcf->subrequest_output_buffer_size) { + if (r->headers_out.content_length_n + > (off_t) clcf->subrequest_output_buffer_size) + { ngx_log_error(NGX_LOG_ERR, c->log, 0, - "too big subrequest response: %uz", len); + "too big subrequest response: %O", + r->headers_out.content_length_n); return NGX_ERROR; } + len = (size_t) r->headers_out.content_length_n; + } else { len = clcf->subrequest_output_buffer_size; } From mdounin at mdounin.ru Sat May 31 20:23:18 2025 From: mdounin at mdounin.ru (=?utf-8?q?Maxim_Dounin?=) Date: Sat, 31 May 2025 23:23:18 +0300 Subject: [PATCH 4 of 4] SSL: usage of SSL_SESSION_get_time_ex() with OpenSSL 3.3+ In-Reply-To: <9228d497cb38bd5fda21.1748722995@vm-bsd.mdounin.ru> References: <9228d497cb38bd5fda21.1748722995@vm-bsd.mdounin.ru> Message-ID: # HG changeset patch # User Maxim Dounin # Date 1748666384 -10800 # Sat May 31 07:39:44 2025 +0300 # Node ID b56f2f0dd036938a6734c577c7fd1871d44cbee2 # Parent 41e7de4b8d3918a501dc95c8b0e706703675fc92 SSL: usage of SSL_SESSION_get_time_ex() with OpenSSL 3.3+. In OpenSSL, SSL_SESSION_get_time() and SSL_SESSION_set_time() functions use "long" to store seconds since the Epoch, which makes these functions problematic after Y2038 on 32-bit platforms, and, more importantly, on 64-bit platforms with 32-bit long (notably Windows). Note that there is no such problem in BoringSSL, which uses uint64_t instead of "long". LibreSSL also uses "long", but it does not support TLSv1.3 session resumption anyway, hence this is not an issue. Fix is to use SSL_SESSION_get_time_ex() and SSL_SESSION_set_time_ex() functions introduced in OpenSSL 3.3 when these are available. Prodded by MSVC with C4244 warnings (conversion from 'type1' to 'type2', possible loss of data) enabled. diff --git a/src/event/ngx_event_openssl.c b/src/event/ngx_event_openssl.c --- a/src/event/ngx_event_openssl.c +++ b/src/event/ngx_event_openssl.c @@ -1190,7 +1190,7 @@ ngx_ssl_info_callback(const ngx_ssl_conn } else { SSL_SESSION_set_time(sess, now); - SSL_SESSION_set_timeout(sess, timeout - (now - time)); + SSL_SESSION_set_timeout(sess, (long) (timeout - (now - time))); } } } diff --git a/src/event/ngx_event_openssl.h b/src/event/ngx_event_openssl.h --- a/src/event/ngx_event_openssl.h +++ b/src/event/ngx_event_openssl.h @@ -83,6 +83,12 @@ #endif +#if (OPENSSL_VERSION_NUMBER > 0x30300000L) +#define SSL_SESSION_get_time(s) SSL_SESSION_get_time_ex(s) +#define SSL_SESSION_set_time(s, t) SSL_SESSION_set_time_ex(s, t) +#endif + + typedef struct ngx_ssl_ocsp_s ngx_ssl_ocsp_t; From mdounin at mdounin.ru Sat May 31 22:20:31 2025 From: mdounin at mdounin.ru (=?utf-8?q?Maxim_Dounin?=) Date: Sun, 01 Jun 2025 01:20:31 +0300 Subject: [PATCH] Tests: fixed Valgrind errors filtering Message-ID: <7bfe91f27c949eac6152.1748730031@vm-bsd.mdounin.ru> # HG changeset patch # User Maxim Dounin # Date 1748729541 -10800 # Sun Jun 01 01:12:21 2025 +0300 # Node ID 7bfe91f27c949eac6152ac9954129b6338bbb815 # Parent ba4f76b3b823c59b5a56343b6110b3524ed008b2 Tests: fixed Valgrind errors filtering. Broken in 1995:d329b05e20fa during $t->grep_file() introduction and resulted in warnings in output (and no filtering) when testing with TEST_NGINX_VALGRIND set. diff --git a/lib/Test/Nginx.pm b/lib/Test/Nginx.pm --- a/lib/Test/Nginx.pm +++ b/lib/Test/Nginx.pm @@ -89,7 +89,7 @@ sub DESTROY { } if (Test::More->builder->expected_tests && $ENV{TEST_NGINX_VALGRIND}) { - my $errors = $self->grep_file('valgrind.log', /^==\d+== .+/m); + my $errors = $self->grep_file('valgrind.log', qr/^==\d+== .+/m); Test::More::is($errors, '', 'no valgrind errors'); }