3 * Copyright (C) Igor Sysoev
4 * Copyright (C) Nginx, Inc.
8 #include <ngx_config.h>
10 #include <ngx_event.h>
14 #define NGX_SENDFILE_LIMIT 4096
18 * When DIRECTIO is enabled FreeBSD, Solaris, and MacOSX read directly
19 * to an application memory from a device if parameters are aligned
20 * to device sector boundary (512 bytes). They fallback to usual read
21 * operation if the parameters are not aligned.
22 * Linux allows DIRECTIO only if the parameters are aligned to a filesystem
23 * sector boundary, otherwise it returns EINVAL. The sector size is
24 * usually 512 bytes, however, on XFS it may be 4096 bytes.
30 static ngx_inline ngx_int_t
31 ngx_output_chain_as_is(ngx_output_chain_ctx_t
*ctx
, ngx_buf_t
*buf
);
32 static ngx_int_t
ngx_output_chain_add_copy(ngx_pool_t
*pool
,
33 ngx_chain_t
**chain
, ngx_chain_t
*in
);
34 static ngx_int_t
ngx_output_chain_align_file_buf(ngx_output_chain_ctx_t
*ctx
,
36 static ngx_int_t
ngx_output_chain_get_buf(ngx_output_chain_ctx_t
*ctx
,
38 static ngx_int_t
ngx_output_chain_copy_buf(ngx_output_chain_ctx_t
*ctx
);
42 ngx_output_chain(ngx_output_chain_ctx_t
*ctx
, ngx_chain_t
*in
)
46 ngx_chain_t
*cl
, *out
, **last_out
;
48 if (ctx
->in
== NULL
&& ctx
->busy
== NULL
) {
51 * the short path for the case when the ctx->in and ctx->busy chains
52 * are empty, the incoming chain is empty too or has the single buf
53 * that does not require the copy
57 return ctx
->output_filter(ctx
->filter_ctx
, in
);
61 #if (NGX_SENDFILE_LIMIT)
62 && !(in
->buf
->in_file
&& in
->buf
->file_last
> NGX_SENDFILE_LIMIT
)
64 && ngx_output_chain_as_is(ctx
, in
->buf
))
66 return ctx
->output_filter(ctx
->filter_ctx
, in
);
70 /* add the incoming buf to the chain ctx->in */
73 if (ngx_output_chain_add_copy(ctx
->pool
, &ctx
->in
, in
) == NGX_ERROR
) {
84 #if (NGX_HAVE_FILE_AIO)
93 * cycle while there are the ctx->in bufs
94 * and there are the free output bufs to copy in
97 bsize
= ngx_buf_size(ctx
->in
->buf
);
99 if (bsize
== 0 && !ngx_buf_special(ctx
->in
->buf
)) {
101 ngx_log_error(NGX_LOG_ALERT
, ctx
->pool
->log
, 0,
102 "zero size buf in output "
103 "t:%d r:%d f:%d %p %p-%p %p %O-%O",
104 ctx
->in
->buf
->temporary
,
105 ctx
->in
->buf
->recycled
,
106 ctx
->in
->buf
->in_file
,
111 ctx
->in
->buf
->file_pos
,
112 ctx
->in
->buf
->file_last
);
116 ctx
->in
= ctx
->in
->next
;
121 if (ngx_output_chain_as_is(ctx
, ctx
->in
->buf
)) {
123 /* move the chain link to the output chain */
129 last_out
= &cl
->next
;
135 if (ctx
->buf
== NULL
) {
137 rc
= ngx_output_chain_align_file_buf(ctx
, bsize
);
139 if (rc
== NGX_ERROR
) {
147 /* get the free buf */
151 ctx
->free
= cl
->next
;
153 ngx_free_chain(ctx
->pool
, cl
);
155 } else if (out
|| ctx
->allocated
== ctx
->bufs
.num
) {
159 } else if (ngx_output_chain_get_buf(ctx
, bsize
) != NGX_OK
) {
165 rc
= ngx_output_chain_copy_buf(ctx
);
167 if (rc
== NGX_ERROR
) {
171 if (rc
== NGX_AGAIN
) {
179 /* delete the completed buf from the ctx->in chain */
181 if (ngx_buf_size(ctx
->in
->buf
) == 0) {
182 ctx
->in
= ctx
->in
->next
;
185 cl
= ngx_alloc_chain_link(ctx
->pool
);
193 last_out
= &cl
->next
;
197 if (out
== NULL
&& last
!= NGX_NONE
) {
206 last
= ctx
->output_filter(ctx
->filter_ctx
, out
);
208 if (last
== NGX_ERROR
|| last
== NGX_DONE
) {
212 ngx_chain_update_chains(ctx
->pool
, &ctx
->free
, &ctx
->busy
, &out
,
219 static ngx_inline ngx_int_t
220 ngx_output_chain_as_is(ngx_output_chain_ctx_t
*ctx
, ngx_buf_t
*buf
)
224 if (ngx_buf_special(buf
)) {
228 if (buf
->in_file
&& buf
->file
->directio
) {
232 sendfile
= ctx
->sendfile
;
234 #if (NGX_SENDFILE_LIMIT)
236 if (buf
->in_file
&& buf
->file_pos
>= NGX_SENDFILE_LIMIT
) {
244 if (!ngx_buf_in_memory(buf
)) {
251 if (ctx
->need_in_memory
&& !ngx_buf_in_memory(buf
)) {
255 if (ctx
->need_in_temp
&& (buf
->memory
|| buf
->mmap
)) {
264 ngx_output_chain_add_copy(ngx_pool_t
*pool
, ngx_chain_t
**chain
,
267 ngx_chain_t
*cl
, **ll
;
268 #if (NGX_SENDFILE_LIMIT)
274 for (cl
= *chain
; cl
; cl
= cl
->next
) {
280 cl
= ngx_alloc_chain_link(pool
);
285 #if (NGX_SENDFILE_LIMIT)
290 && buf
->file_pos
< NGX_SENDFILE_LIMIT
291 && buf
->file_last
> NGX_SENDFILE_LIMIT
)
293 /* split a file buf on two bufs by the sendfile limit */
295 b
= ngx_calloc_buf(pool
);
300 ngx_memcpy(b
, buf
, sizeof(ngx_buf_t
));
302 if (ngx_buf_in_memory(buf
)) {
303 buf
->pos
+= (ssize_t
) (NGX_SENDFILE_LIMIT
- buf
->file_pos
);
307 buf
->file_pos
= NGX_SENDFILE_LIMIT
;
308 b
->file_last
= NGX_SENDFILE_LIMIT
;
333 ngx_output_chain_align_file_buf(ngx_output_chain_ctx_t
*ctx
, off_t bsize
)
340 if (in
->file
== NULL
|| !in
->file
->directio
) {
346 size
= (size_t) (in
->file_pos
- (in
->file_pos
& ~(ctx
->alignment
- 1)));
350 if (bsize
>= (off_t
) ctx
->bufs
.size
) {
354 size
= (size_t) bsize
;
357 size
= (size_t) ctx
->alignment
- size
;
359 if ((off_t
) size
> bsize
) {
360 size
= (size_t) bsize
;
364 ctx
->buf
= ngx_create_temp_buf(ctx
->pool
, size
);
365 if (ctx
->buf
== NULL
) {
370 * we do not set ctx->buf->tag, because we do not want
371 * to reuse the buf via ctx->free list
374 #if (NGX_HAVE_ALIGNED_DIRECTIO)
383 ngx_output_chain_get_buf(ngx_output_chain_ctx_t
*ctx
, off_t bsize
)
390 size
= ctx
->bufs
.size
;
393 if (in
->last_in_chain
) {
395 if (bsize
< (off_t
) size
) {
398 * allocate a small temp buf for a small last buf
399 * or its small last part
402 size
= (size_t) bsize
;
405 } else if (!ctx
->directio
406 && ctx
->bufs
.num
== 1
407 && (bsize
< (off_t
) (size
+ size
/ 4)))
410 * allocate a temp buf that equals to a last buf,
411 * if there is no directio, the last buf size is lesser
412 * than 1.25 of bufs.size and the temp buf is single
415 size
= (size_t) bsize
;
420 b
= ngx_calloc_buf(ctx
->pool
);
428 * allocate block aligned to a disk sector size to enable
429 * userland buffer direct usage conjunctly with directio
432 b
->start
= ngx_pmemalign(ctx
->pool
, size
, (size_t) ctx
->alignment
);
433 if (b
->start
== NULL
) {
438 b
->start
= ngx_palloc(ctx
->pool
, size
);
439 if (b
->start
== NULL
) {
446 b
->end
= b
->last
+ size
;
449 b
->recycled
= recycled
;
459 ngx_output_chain_copy_buf(ngx_output_chain_ctx_t
*ctx
)
463 ngx_buf_t
*src
, *dst
;
469 size
= ngx_buf_size(src
);
470 size
= ngx_min(size
, dst
->end
- dst
->pos
);
472 sendfile
= ctx
->sendfile
& !ctx
->directio
;
474 #if (NGX_SENDFILE_LIMIT)
476 if (src
->in_file
&& src
->file_pos
>= NGX_SENDFILE_LIMIT
) {
482 if (ngx_buf_in_memory(src
)) {
483 ngx_memcpy(dst
->pos
, src
->pos
, (size_t) size
);
484 src
->pos
+= (size_t) size
;
485 dst
->last
+= (size_t) size
;
491 dst
->file
= src
->file
;
492 dst
->file_pos
= src
->file_pos
;
493 dst
->file_last
= src
->file_pos
+ size
;
499 src
->file_pos
+= size
;
505 if (src
->pos
== src
->last
) {
506 dst
->flush
= src
->flush
;
507 dst
->last_buf
= src
->last_buf
;
508 dst
->last_in_chain
= src
->last_in_chain
;
513 #if (NGX_HAVE_ALIGNED_DIRECTIO)
515 if (ctx
->unaligned
) {
516 if (ngx_directio_off(src
->file
->fd
) == NGX_FILE_ERROR
) {
517 ngx_log_error(NGX_LOG_ALERT
, ctx
->pool
->log
, ngx_errno
,
518 ngx_directio_off_n
" \"%s\" failed",
519 src
->file
->name
.data
);
525 #if (NGX_HAVE_FILE_AIO)
527 if (ctx
->aio_handler
) {
528 n
= ngx_file_aio_read(src
->file
, dst
->pos
, (size_t) size
,
529 src
->file_pos
, ctx
->pool
);
530 if (n
== NGX_AGAIN
) {
531 ctx
->aio_handler(ctx
, src
->file
);
536 n
= ngx_read_file(src
->file
, dst
->pos
, (size_t) size
,
541 n
= ngx_read_file(src
->file
, dst
->pos
, (size_t) size
, src
->file_pos
);
545 #if (NGX_HAVE_ALIGNED_DIRECTIO)
547 if (ctx
->unaligned
) {
552 if (ngx_directio_on(src
->file
->fd
) == NGX_FILE_ERROR
) {
553 ngx_log_error(NGX_LOG_ALERT
, ctx
->pool
->log
, ngx_errno
,
554 ngx_directio_on_n
" \"%s\" failed",
555 src
->file
->name
.data
);
565 if (n
== NGX_ERROR
) {
566 return (ngx_int_t
) n
;
570 ngx_log_error(NGX_LOG_ALERT
, ctx
->pool
->log
, 0,
571 ngx_read_file_n
" read only %z of %O from \"%s\"",
572 n
, size
, src
->file
->name
.data
);
580 dst
->file
= src
->file
;
581 dst
->file_pos
= src
->file_pos
;
582 dst
->file_last
= src
->file_pos
+ n
;
590 if (src
->file_pos
== src
->file_last
) {
591 dst
->flush
= src
->flush
;
592 dst
->last_buf
= src
->last_buf
;
593 dst
->last_in_chain
= src
->last_in_chain
;
602 ngx_chain_writer(void *data
, ngx_chain_t
*in
)
604 ngx_chain_writer_ctx_t
*ctx
= data
;
612 for (size
= 0; in
; in
= in
->next
) {
615 if (ngx_buf_size(in
->buf
) == 0 && !ngx_buf_special(in
->buf
)) {
620 size
+= ngx_buf_size(in
->buf
);
622 ngx_log_debug2(NGX_LOG_DEBUG_CORE
, c
->log
, 0,
623 "chain writer buf fl:%d s:%uO",
624 in
->buf
->flush
, ngx_buf_size(in
->buf
));
626 cl
= ngx_alloc_chain_link(ctx
->pool
);
634 ctx
->last
= &cl
->next
;
637 ngx_log_debug1(NGX_LOG_DEBUG_CORE
, c
->log
, 0,
638 "chain writer in: %p", ctx
->out
);
640 for (cl
= ctx
->out
; cl
; cl
= cl
->next
) {
643 if (ngx_buf_size(cl
->buf
) == 0 && !ngx_buf_special(cl
->buf
)) {
649 size
+= ngx_buf_size(cl
->buf
);
652 if (size
== 0 && !c
->buffered
) {
656 ctx
->out
= c
->send_chain(c
, ctx
->out
, ctx
->limit
);
658 ngx_log_debug1(NGX_LOG_DEBUG_CORE
, c
->log
, 0,
659 "chain writer out: %p", ctx
->out
);
661 if (ctx
->out
== NGX_CHAIN_ERROR
) {
665 if (ctx
->out
== NULL
) {
666 ctx
->last
= &ctx
->out
;