# HG changeset patch # User Igor Sysoev # Date 1220626127 0 # Node ID 8564129d49b6e6ee2b6622103d37a333b000fc79 # Parent 25cf039c40bd7c30b7c51570caef2a5cf5e95ebf *) handle unaligned file part for directio *) disable sendfile in directio mode diff --git a/src/core/ngx_buf.h b/src/core/ngx_buf.h --- a/src/core/ngx_buf.h +++ b/src/core/ngx_buf.h @@ -78,6 +78,7 @@ typedef struct { ngx_chain_t *busy; unsigned sendfile; + unsigned directio; unsigned need_in_memory; unsigned need_in_temp; diff --git a/src/core/ngx_file.h b/src/core/ngx_file.h --- a/src/core/ngx_file.h +++ b/src/core/ngx_file.h @@ -26,7 +26,8 @@ struct ngx_file_s { ngx_log_t *log; - ngx_uint_t valid_info; /* unsigned valid_info:1; */ + unsigned valid_info:1; + unsigned directio:1; }; #define NGX_MAX_PATH_LEVEL 3 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 @@ -502,6 +502,9 @@ ngx_open_and_stat_file(u_char *name, ngx if (ngx_directio(fd) == -1) { ngx_log_error(NGX_LOG_ALERT, log, ngx_errno, ngx_directio_n " \"%s\" failed", name); + + } else { + of->is_directio = 1; } } } 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 @@ -33,6 +33,7 @@ typedef struct { unsigned is_file:1; unsigned is_link:1; unsigned is_exec:1; + unsigned is_directio:1; } ngx_open_file_info_t; 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 @@ -18,13 +18,14 @@ static ngx_inline ngx_int_t - ngx_output_chain_need_to_copy(ngx_output_chain_ctx_t *ctx, ngx_buf_t *buf); + ngx_output_chain_as_is(ngx_output_chain_ctx_t *ctx, ngx_buf_t *buf); static ngx_int_t ngx_output_chain_add_copy(ngx_pool_t *pool, ngx_chain_t **chain, ngx_chain_t *in); +static ngx_int_t ngx_output_chain_align_file_buf(ngx_output_chain_ctx_t *ctx, + off_t bsize); static ngx_int_t ngx_output_chain_get_buf(ngx_output_chain_ctx_t *ctx, off_t bsize); -static ngx_int_t ngx_output_chain_copy_buf(ngx_buf_t *dst, ngx_buf_t *src, - ngx_uint_t sendfile); +static ngx_int_t ngx_output_chain_copy_buf(ngx_output_chain_ctx_t *ctx); ngx_int_t @@ -50,7 +51,7 @@ ngx_output_chain(ngx_output_chain_ctx_t #if (NGX_SENDFILE_LIMIT) && !(in->buf->in_file && in->buf->file_last > NGX_SENDFILE_LIMIT) #endif - && !ngx_output_chain_need_to_copy(ctx, in->buf)) + && ngx_output_chain_as_is(ctx, in->buf)) { return ctx->output_filter(ctx->filter_ctx, in); } @@ -74,7 +75,7 @@ ngx_output_chain(ngx_output_chain_ctx_t /* * cycle while there are the ctx->in bufs - * or there are the free output bufs to copy in + * and there are the free output bufs to copy in */ bsize = ngx_buf_size(ctx->in->buf); @@ -101,7 +102,7 @@ ngx_output_chain(ngx_output_chain_ctx_t continue; } - if (!ngx_output_chain_need_to_copy(ctx, ctx->in->buf)) { + if (ngx_output_chain_as_is(ctx, ctx->in->buf)) { /* move the chain link to the output chain */ @@ -117,25 +118,35 @@ ngx_output_chain(ngx_output_chain_ctx_t if (ctx->buf == NULL) { - /* get the free buf */ + rc = ngx_output_chain_align_file_buf(ctx, bsize); + + if (rc == NGX_ERROR) { + return NGX_ERROR; + } + + if (rc != NGX_OK) { + + if (ctx->free) { + + /* get the free buf */ - if (ctx->free) { - cl = ctx->free; - ctx->buf = cl->buf; - ctx->free = cl->next; - ngx_free_chain(ctx->pool, cl); + cl = ctx->free; + ctx->buf = cl->buf; + ctx->free = cl->next; + + ngx_free_chain(ctx->pool, cl); - } else if (out || ctx->allocated == ctx->bufs.num) { + } else if (out || ctx->allocated == ctx->bufs.num) { + + break; - break; - - } else if (ngx_output_chain_get_buf(ctx, bsize) != NGX_OK) { - return NGX_ERROR; + } else if (ngx_output_chain_get_buf(ctx, bsize) != NGX_OK) { + return NGX_ERROR; + } } } - rc = ngx_output_chain_copy_buf(ctx->buf, ctx->in->buf, - ctx->sendfile); + rc = ngx_output_chain_copy_buf(ctx); if (rc == NGX_ERROR) { return rc; @@ -189,11 +200,15 @@ ngx_output_chain(ngx_output_chain_ctx_t static ngx_inline ngx_int_t -ngx_output_chain_need_to_copy(ngx_output_chain_ctx_t *ctx, ngx_buf_t *buf) +ngx_output_chain_as_is(ngx_output_chain_ctx_t *ctx, ngx_buf_t *buf) { ngx_uint_t sendfile; if (ngx_buf_special(buf)) { + return 1; + } + + if (buf->in_file && buf->file->directio) { return 0; } @@ -210,21 +225,21 @@ ngx_output_chain_need_to_copy(ngx_output if (!sendfile) { if (!ngx_buf_in_memory(buf)) { - return 1; + return 0; } buf->in_file = 0; } if (ctx->need_in_memory && !ngx_buf_in_memory(buf)) { - return 1; + return 0; } if (ctx->need_in_temp && (buf->memory || buf->mmap)) { - return 1; + return 0; } - return 0; + return 1; } @@ -258,6 +273,8 @@ ngx_output_chain_add_copy(ngx_pool_t *po && buf->file_pos < NGX_SENDFILE_LIMIT && buf->file_last > NGX_SENDFILE_LIMIT) { + /* split a file buf on two bufs by the sendfile limit */ + b = ngx_calloc_buf(pool); if (b == NULL) { return NGX_ERROR; @@ -297,32 +314,82 @@ ngx_output_chain_add_copy(ngx_pool_t *po static ngx_int_t +ngx_output_chain_align_file_buf(ngx_output_chain_ctx_t *ctx, off_t bsize) +{ + size_t size; + ngx_buf_t *in; + + in = ctx->in->buf; + + if (in->file == NULL || !in->file->directio) { + return NGX_DECLINED; + } + + ctx->directio = 1; + + size = (size_t) (in->file_pos - (in->file_pos & ~511)); + + if (size == 0) { + + if (bsize >= ctx->bufs.size) { + return NGX_DECLINED; + } + + size = (size_t) bsize; + + } else { + size = 512 - size; + + if (size > bsize) { + size = (size_t) bsize; + } + } + + ctx->buf = ngx_create_temp_buf(ctx->pool, size); + if (ctx->buf == NULL) { + return NGX_ERROR; + } + + /* + * we do not set ctx->buf->tag, because we do not want + * to reuse the buf via ctx->free list + */ + + return NGX_OK; +} + + +static ngx_int_t ngx_output_chain_get_buf(ngx_output_chain_ctx_t *ctx, off_t bsize) { size_t size; - ngx_buf_t *b; + ngx_buf_t *b, *in; ngx_uint_t recycled; + in = ctx->in->buf; size = ctx->bufs.size; recycled = 1; - if (ctx->in->buf->last_in_chain) { + if (in->last_in_chain) { if (bsize < (off_t) size) { - /* - * allocate a small temp buf for a small last buf - * or its small last part - */ + /* + * allocate a small temp buf for a small last buf + * or its small last part + */ size = (size_t) bsize; recycled = 0; - } else if (ctx->bufs.num == 1 && (bsize < (off_t) (size + size / 4))) { - + } else if (!ctx->directio + && ctx->bufs.num == 1 + && (bsize < (off_t) (size + size / 4))) + { /* - * allocate a temp buf that equals to a last buf, if the last buf - * size is lesser than 1.25 of bufs.size and the temp buf is single + * allocate a temp buf that equals to a last buf, + * if there is no directio, the last buf size is lesser + * than 1.25 of bufs.size and the temp buf is single */ size = (size_t) bsize; @@ -335,11 +402,23 @@ ngx_output_chain_get_buf(ngx_output_chai return NGX_ERROR; } - /* allocate block aligned to a disk sector size to enable O_DIRECT */ + if (ctx->directio) { + + /* + * allocate block aligned to a disk sector size to enable + * userland buffer direct usage conjunctly with directio + */ - b->start = ngx_pmemalign(ctx->pool, size, 512); - if (b->start == NULL) { - return NGX_ERROR; + b->start = ngx_pmemalign(ctx->pool, size, 512); + if (b->start == NULL) { + return NGX_ERROR; + } + + } else { + b->start = ngx_palloc(ctx->pool, size); + if (b->start == NULL) { + return NGX_ERROR; + } } b->pos = b->start; @@ -357,10 +436,15 @@ ngx_output_chain_get_buf(ngx_output_chai static ngx_int_t -ngx_output_chain_copy_buf(ngx_buf_t *dst, ngx_buf_t *src, ngx_uint_t sendfile) +ngx_output_chain_copy_buf(ngx_output_chain_ctx_t *ctx) { - off_t size; - ssize_t n; + off_t size; + ssize_t n; + ngx_buf_t *src, *dst; + ngx_uint_t sendfile; + + src = ctx->in->buf; + dst = ctx->buf; size = ngx_buf_size(src); @@ -368,6 +452,8 @@ ngx_output_chain_copy_buf(ngx_buf_t *dst size = dst->end - dst->pos; } + sendfile = ctx->sendfile & !ctx->directio; + #if (NGX_SENDFILE_LIMIT) if (src->in_file && src->file_pos >= NGX_SENDFILE_LIMIT) { @@ -418,7 +504,7 @@ ngx_output_chain_copy_buf(ngx_buf_t *dst #endif if (n != size) { - ngx_log_error(NGX_LOG_ALERT, src->file->log, 0, + ngx_log_error(NGX_LOG_ALERT, ctx->pool->log, 0, ngx_read_file_n " read only %z of %O from file", n, size); if (n == 0) { diff --git a/src/http/modules/ngx_http_flv_module.c b/src/http/modules/ngx_http_flv_module.c --- a/src/http/modules/ngx_http_flv_module.c +++ b/src/http/modules/ngx_http_flv_module.c @@ -244,6 +244,7 @@ ngx_http_flv_handler(ngx_http_request_t b->file->fd = of.fd; b->file->name = path; b->file->log = log; + b->file->directio = of.is_directio; out[1].buf = b; out[1].next = NULL; diff --git a/src/http/modules/ngx_http_gzip_static_module.c b/src/http/modules/ngx_http_gzip_static_module.c --- a/src/http/modules/ngx_http_gzip_static_module.c +++ b/src/http/modules/ngx_http_gzip_static_module.c @@ -235,6 +235,7 @@ ngx_http_gzip_static_handler(ngx_http_re b->file->fd = of.fd; b->file->name = path; b->file->log = log; + b->file->directio = of.is_directio; out.buf = b; out.next = NULL; diff --git a/src/http/modules/ngx_http_static_module.c b/src/http/modules/ngx_http_static_module.c --- a/src/http/modules/ngx_http_static_module.c +++ b/src/http/modules/ngx_http_static_module.c @@ -251,6 +251,7 @@ ngx_http_static_handler(ngx_http_request b->file->fd = of.fd; b->file->name = path; b->file->log = log; + b->file->directio = of.is_directio; out.buf = b; out.next = NULL; diff --git a/src/http/modules/perl/nginx.xs b/src/http/modules/perl/nginx.xs --- a/src/http/modules/perl/nginx.xs +++ b/src/http/modules/perl/nginx.xs @@ -681,6 +681,7 @@ sendfile(r, filename, offset = -1, bytes b->file->fd = of.fd; b->file->log = r->connection->log; + b->file->directio = of.is_directio; (void) ngx_http_perl_output(r, b);