comparison src/http/ngx_http_upstream.c @ 7975:a7a77549265e

HTTP/2: fixed sendfile() aio handling. With sendfile() in threads ("aio threads; sendfile on;"), client connection can block on writing, waiting for sendfile() to complete. In HTTP/2 this might result in the request hang, since an attempt to continue processing in thread event handler will call request's write event handler, which is usually stopped by ngx_http_v2_send_chain(): it does nothing if there are no additional data and stream->queued is set. Further, HTTP/2 resets stream's c->write->ready to 0 if writing blocks, so just fixing ngx_http_v2_send_chain() is not enough. Can be reproduced with test suite on Linux with: TEST_NGINX_GLOBALS_HTTP="aio threads; sendfile on;" prove h2*.t The following tests currently fail: h2_keepalive.t, h2_priority.t, h2_proxy_max_temp_file_size.t, h2.t, h2_trailers.t. Similarly, sendfile() with AIO preloading on FreeBSD can block as well, with similar results. This is, however, harder to reproduce, especially on modern FreeBSD systems, since sendfile() usually does not return EBUSY. Fix is to modify ngx_http_v2_send_chain() so it actually tries to send data to the main connection when called, and to make sure that c->write->ready is set by the relevant event handlers.
author Maxim Dounin <mdounin@mdounin.ru>
date Thu, 25 Nov 2021 22:02:10 +0300
parents 555533169506
children 08b3ea81ff5f 5c86189a1c1b
comparison
equal deleted inserted replaced
7974:555533169506 7975:a7a77549265e
3925 "http upstream thread: \"%V?%V\"", &r->uri, &r->args); 3925 "http upstream thread: \"%V?%V\"", &r->uri, &r->args);
3926 3926
3927 r->main->blocked--; 3927 r->main->blocked--;
3928 r->aio = 0; 3928 r->aio = 0;
3929 3929
3930 #if (NGX_HTTP_V2)
3931
3932 if (r->stream) {
3933 /*
3934 * for HTTP/2, update write event to make sure processing will
3935 * reach the main connection to handle sendfile() in threads
3936 */
3937
3938 c->write->ready = 1;
3939 c->write->active = 0;
3940 }
3941
3942 #endif
3943
3930 if (r->done) { 3944 if (r->done) {
3931 /* 3945 /*
3932 * trigger connection event handler if the subrequest was 3946 * trigger connection event handler if the subrequest was
3933 * already finalized; this can happen if the handler is used 3947 * already finalized; this can happen if the handler is used
3934 * for sendfile() in threads 3948 * for sendfile() in threads