Mercurial > hg > nginx
comparison src/core/ngx_buf.c @ 7969:84c60a3cd12a stable-1.20
Changed ngx_chain_update_chains() to test tag first (ticket #2248).
Without this change, aio used with HTTP/2 can result in connection hang,
as observed with "aio threads; aio_write on;" and proxying (ticket #2248).
The problem is that HTTP/2 updates buffers outside of the output filters
(notably, marks them as sent), and then posts a write event to call
output filters. If a filter does not call the next one for some reason
(for example, because of an AIO operation in progress), this might
result in a state when the owner of a buffer already called
ngx_chain_update_chains() and can reuse the buffer, while the same buffer
is still sitting in the busy chain of some other filter.
In the particular case a buffer was sitting in output chain's ctx->busy,
and was reused by event pipe. Output chain's ctx->busy was permanently
blocked by it, and this resulted in connection hang.
Fix is to change ngx_chain_update_chains() to skip buffers from other
modules unconditionally, without trying to wait for these buffers to
become empty.
author | Maxim Dounin <mdounin@mdounin.ru> |
---|---|
date | Sat, 30 Oct 2021 02:39:19 +0300 |
parents | da9941c9b01b |
children |
comparison
equal
deleted
inserted
replaced
7968:5354bf552520 | 7969:84c60a3cd12a |
---|---|
201 } | 201 } |
202 | 202 |
203 while (*busy) { | 203 while (*busy) { |
204 cl = *busy; | 204 cl = *busy; |
205 | 205 |
206 if (ngx_buf_size(cl->buf) != 0) { | |
207 break; | |
208 } | |
209 | |
210 if (cl->buf->tag != tag) { | 206 if (cl->buf->tag != tag) { |
211 *busy = cl->next; | 207 *busy = cl->next; |
212 ngx_free_chain(p, cl); | 208 ngx_free_chain(p, cl); |
213 continue; | 209 continue; |
210 } | |
211 | |
212 if (ngx_buf_size(cl->buf) != 0) { | |
213 break; | |
214 } | 214 } |
215 | 215 |
216 cl->buf->pos = cl->buf->start; | 216 cl->buf->pos = cl->buf->start; |
217 cl->buf->last = cl->buf->start; | 217 cl->buf->last = cl->buf->start; |
218 | 218 |