changeset 154:eac26585476e

nginx-0.0.1-2003-10-22-11:05:29 import
author Igor Sysoev <igor@sysoev.ru>
date Wed, 22 Oct 2003 07:05:29 +0000
parents c71aeb75c071
children 46eb23d9471d
files src/core/ngx_hunk.c src/core/ngx_hunk.h src/event/ngx_event_pipe.c src/event/ngx_event_pipe.h src/http/modules/ngx_http_gzip_filter.c src/http/modules/proxy/ngx_http_proxy_handler.c src/http/modules/proxy/ngx_http_proxy_handler.h src/http/ngx_http_core_module.c src/http/ngx_http_core_module.h src/http/ngx_http_filter.h src/http/ngx_http_output_filter.c src/http/ngx_http_request.h src/http/ngx_http_write_filter.c src/os/unix/ngx_files.c src/os/unix/ngx_freebsd_sendfile_chain.c
diffstat 15 files changed, 153 insertions(+), 82 deletions(-) [+]
line wrap: on
line diff
--- a/src/core/ngx_hunk.c
+++ b/src/core/ngx_hunk.c
@@ -125,7 +125,7 @@ int ngx_chain_add_copy(ngx_pool_t *pool,
 
 
 void ngx_chain_update_chains(ngx_chain_t **free, ngx_chain_t **busy,
-                             ngx_chain_t **out)
+                             ngx_chain_t **out, ngx_hunk_tag_t tag)
 {
     ngx_chain_t  *te;
 
@@ -154,9 +154,7 @@ void ngx_chain_update_chains(ngx_chain_t
         }
 #endif
 
-        /* TODO: change to hunk->tag */
-
-        if (!((*busy)->hunk->type & NGX_HUNK_TEMP)) {
+        if ((*busy)->hunk->tag != tag) {
             *busy = (*busy)->next;
             continue;
         }
--- a/src/core/ngx_hunk.h
+++ b/src/core/ngx_hunk.h
@@ -34,25 +34,28 @@
 /* last hunk */
 #define NGX_HUNK_LAST         0x2000
 #define NGX_HUNK_LAST_SHADOW  0x4000
+#define NGX_HUNK_TEMP_FILE    0x8000
 
 
+typedef void *                   ngx_hunk_tag_t;
 
 typedef struct ngx_hunk_s        ngx_hunk_t;
 
 struct ngx_hunk_s {
-    char        *pos;
-    char        *last;
-    off_t        file_pos;
-    off_t        file_last;
+    char            *pos;
+    char            *last;
+    off_t            file_pos;
+    off_t            file_last;
 
-    int          type;
-    char        *start;         /* start of hunk */
-    char        *end;           /* end of hunk */
-    char        *pre_start;     /* start of pre-allocated hunk */
-    char        *post_end;      /* end of post-allocated hunk */
-    int          tag;
-    ngx_file_t  *file;
-    ngx_hunk_t  *shadow;
+    int              type;
+    char            *start;         /* start of hunk */
+    char            *end;           /* end of hunk */
+    char            *pre_start;     /* start of pre-allocated hunk */
+    char            *post_end;      /* end of post-allocated hunk */
+    ngx_hunk_tag_t   tag;
+    ngx_file_t      *file;
+    ngx_hunk_t      *shadow;
+    /* STUB */ int   num;
 };
 
 
@@ -119,7 +122,7 @@ ngx_hunk_t *ngx_create_temp_hunk(ngx_poo
 
 int ngx_chain_add_copy(ngx_pool_t *pool, ngx_chain_t **ch, ngx_chain_t *in);
 void ngx_chain_update_chains(ngx_chain_t **free, ngx_chain_t **busy,
-                             ngx_chain_t **out);
+                             ngx_chain_t **out, ngx_hunk_tag_t tag);
 
 
 
--- a/src/event/ngx_event_pipe.c
+++ b/src/event/ngx_event_pipe.c
@@ -27,12 +27,13 @@ int ngx_event_pipe(ngx_event_pipe_t *p, 
         }
 
         p->read = 0;
+        p->upstream_blocked = 0;
 
         if (ngx_event_pipe_read_upstream(p) == NGX_ABORT) {
             return NGX_ABORT;
         }
 
-        if (!p->read) {
+        if (!p->read && !p->upstream_blocked) {
             break;
         }
 
@@ -140,6 +141,8 @@ int ngx_event_pipe_read_upstream(ngx_eve
                  * a downstream is ready then write the hunks to a downstream
                  */
 
+                p->upstream_blocked = 1;
+
                 ngx_log_debug(p->log, "downstream ready");
 
                 break;
@@ -184,6 +187,8 @@ int ngx_event_pipe_read_upstream(ngx_eve
                 break;
             }
 
+            ngx_log_debug(p->log, "HUNK_FREE: %d" _ chain->hunk->num);
+
             n = ngx_recv_chain(p->upstream, chain);
 
             ngx_log_debug(p->log, "recv_chain: %d" _ n);
@@ -218,6 +223,8 @@ int ngx_event_pipe_read_upstream(ngx_eve
             if (n >= size) {
                 ce->hunk->last = ce->hunk->end;
 
+    /* STUB */ ce->hunk->num = p->num++;
+
                 if (p->input_filter(p, ce->hunk) == NGX_ERROR) {
                     return NGX_ABORT;
                 }
@@ -235,6 +242,7 @@ int ngx_event_pipe_read_upstream(ngx_eve
     }
 
     if ((p->upstream_eof || p->upstream_error) && p->free_raw_hunks) {
+    /* STUB */ p->free_raw_hunks->hunk->num = p->num++;
         if (p->input_filter(p, p->free_raw_hunks->hunk) == NGX_ERROR) {
             return NGX_ABORT;
         }
@@ -302,6 +310,8 @@ int ngx_event_pipe_write_to_downstream(n
                 p->out = p->out->next;
                 ngx_remove_shadow_free_raw_hunk(&p->free_raw_hunks, ce->hunk);
 
+ngx_log_debug(p->log, "HUNK OUT: %d %x" _ ce->hunk->num _ ce->hunk->type);
+
             } else if (!p->cachable && p->in) {
                 ce = p->in;
 
@@ -313,6 +323,8 @@ int ngx_event_pipe_write_to_downstream(n
 
                 p->in = p->in->next;
 
+ngx_log_debug(p->log, "HUNK IN: %d" _ ce->hunk->num);
+
             } else {
                 break;
             }
@@ -323,22 +335,32 @@ int ngx_event_pipe_write_to_downstream(n
         }
 
         if (out == NULL) {
-            break;
+            ngx_log_debug(p->log, "no hunks to write BUSY: %d" _ busy_len);
+
+            if (!p->upstream_blocked || busy_len == 0) {
+                break;
+            }
+
+            /* if the upstream is blocked then write the busy hunks */
         }
 
         if (p->output_filter(p->output_ctx, out) == NGX_ERROR) {
             p->downstream_error = 1;
+
+            /* handle the downstream error at the begin of the cycle.  */
+
             continue;
         }
 
-        ngx_chain_update_chains(&p->free, &p->busy, &out);
-
-        /* add the free shadow raw hunks to p->free_raw_hunks */
+        ngx_chain_update_chains(&p->free, &p->busy, &out, p->tag);
 
         for (ce = p->free; ce; ce = ce->next) {
+
+            /* add the free shadow raw hunk to p->free_raw_hunks */
+
             if (ce->hunk->type & NGX_HUNK_LAST_SHADOW) {
                 h = ce->hunk->shadow;
-                /* THINK NEEDED ??? */ h->pos = h->last = h->start;
+                h->pos = h->last = h->start;
                 h->shadow = NULL;
                 ngx_alloc_ce_and_set_hunk(te, h, p->pool, NGX_ABORT);
                 ngx_add_after_partially_filled_hunk(&p->free_raw_hunks, te);
@@ -346,6 +368,15 @@ int ngx_event_pipe_write_to_downstream(n
                 ce->hunk->type &= ~NGX_HUNK_LAST_SHADOW;
             }
             ce->hunk->shadow = NULL;
+
+            if (p->cyclic_temp_file && (ce->hunk->type & NGX_HUNK_TEMP_FILE)) {
+
+                /* reset p->temp_offset if all hunks had been sent */
+
+                if (ce->hunk->file_last == p->temp_offset) {
+                    p->temp_offset = 0;
+                }
+            }
         }
     }
 
@@ -355,7 +386,7 @@ int ngx_event_pipe_write_to_downstream(n
 
 static int ngx_event_pipe_write_chain_to_temp_file(ngx_event_pipe_t *p)
 {
-    int           rc, size, hunk_size;
+    int           rc, size, hsize;
     ngx_hunk_t   *h;
     ngx_chain_t  *ce, *te, *next, *out, **le, **last_free;
 
@@ -389,17 +420,17 @@ static int ngx_event_pipe_write_chain_to
 ngx_log_debug(p->log, "offset: %d" _ p->temp_offset);
 
         do {
-            hunk_size = ce->hunk->last - ce->hunk->pos;
+            hsize = ce->hunk->last - ce->hunk->pos;
 
-ngx_log_debug(p->log, "hunk size: %d" _ hunk_size);
+ngx_log_debug(p->log, "hunk size: %d" _ hsize);
 
-            if ((size + hunk_size > p->temp_file_write_size)
-                || (p->temp_offset + hunk_size > p->max_temp_file_size))
+            if ((size + hsize > p->temp_file_write_size)
+                || (p->temp_offset + size + hsize > p->max_temp_file_size))
             {
                 break;
             }
 
-            size += hunk_size;
+            size += hsize;
             le = &ce->next;
             ce = ce->next;
 
@@ -438,12 +469,17 @@ ngx_log_debug(p->log, "size: %d" _ size)
         ce->next = NULL;
 
         h = ce->hunk;
-        h->type |= NGX_HUNK_FILE;
         h->file = p->temp_file;
         h->file_pos = p->temp_offset;
         p->temp_offset += h->last - h->pos;
         h->file_last = p->temp_offset;
 
+        if (p->cachable) {
+            h->type |= NGX_HUNK_FILE;
+        } else {
+            h->type |= NGX_HUNK_FILE|NGX_HUNK_TEMP_FILE;
+        }
+
         ngx_chain_add_ce(p->out, p->last_out, ce);
 
         if (h->type & NGX_HUNK_LAST_SHADOW) {
@@ -479,10 +515,12 @@ int ngx_event_pipe_copy_input_filter(ngx
 
     ngx_memcpy(h, hunk, sizeof(ngx_hunk_t));
     h->shadow = hunk;
+    h->tag = p->tag;
     h->type |= NGX_HUNK_LAST_SHADOW|NGX_HUNK_RECYCLED;
     hunk->shadow = h;
 
     ngx_alloc_ce_and_set_hunk(ce, h, p->pool, NGX_ERROR);
+ngx_log_debug(p->log, "HUNK %d" _ h->num);
     ngx_chain_add_ce(p->in, p->last_in, ce);
 
     return NGX_OK;
--- a/src/event/ngx_event_pipe.h
+++ b/src/event/ngx_event_pipe.h
@@ -39,13 +39,16 @@ struct ngx_event_pipe_s {
     unsigned           read:1;
     unsigned           cachable:1;
     unsigned           upstream_done:1;
+    unsigned           upstream_error:1;
     unsigned           upstream_eof:1;
-    unsigned           upstream_error:1;
+    unsigned           upstream_blocked:1;
     unsigned           downstream_done:1;
     unsigned           downstream_error:1;
+    unsigned           cyclic_temp_file:1;
 
     int                hunks;
     ngx_bufs_t         bufs;
+    ngx_hunk_tag_t     tag;
 
     size_t             max_busy_len;
 
@@ -65,6 +68,7 @@ struct ngx_event_pipe_s {
     ngx_file_t        *temp_file;
     ngx_path_t        *temp_path;
     char              *temp_file_warn;
+    /* STUB */ int     num;
 };
 
 
--- a/src/http/modules/ngx_http_gzip_filter.c
+++ b/src/http/modules/ngx_http_gzip_filter.c
@@ -287,6 +287,8 @@ static int ngx_http_gzip_body_filter(ngx
                                   ngx_create_temp_hunk(r->pool, conf->bufs.size,
                                                        0, 0),
                                   ngx_http_gzip_error(ctx));
+                    ctx->out_hunk->tag = (ngx_hunk_tag_t)
+                                                  &ngx_http_gzip_filter_module;
                     ctx->out_hunk->type |= NGX_HUNK_RECYCLED;
                     ctx->hunks++;
 
@@ -417,7 +419,8 @@ ngx_log_debug(r->connection->log, "DEFLA
             return ngx_http_gzip_error(ctx);
         }
 
-        ngx_chain_update_chains(&ctx->free, &ctx->busy, &ctx->out);
+        ngx_chain_update_chains(&ctx->free, &ctx->busy, &ctx->out,
+                                (ngx_hunk_tag_t) &ngx_http_gzip_filter_module);
         ctx->last_out = &ctx->out;
     }
 }
--- a/src/http/modules/proxy/ngx_http_proxy_handler.c
+++ b/src/http/modules/proxy/ngx_http_proxy_handler.c
@@ -410,6 +410,7 @@ static void ngx_http_proxy_process_upstr
             ngx_http_proxy_finalize_request(p, NGX_HTTP_INTERNAL_SERVER_ERROR);
             return;
         }
+        p->header_in->tag = (ngx_hunk_tag_t) &ngx_http_proxy_module;
     }
 
     n = ngx_http_proxy_read_upstream_header(p);
@@ -712,6 +713,7 @@ static void ngx_http_proxy_send_response
     ep->output_filter = (ngx_event_pipe_output_filter_pt)
                                                         ngx_http_output_filter;
     ep->output_ctx = r;
+    ep->tag = (ngx_hunk_tag_t) &ngx_http_proxy_module;
     ep->bufs = p->lcf->bufs;
     ep->max_busy_len = p->lcf->max_busy_len;
     ep->upstream = p->upstream.connection;
@@ -720,7 +722,7 @@ static void ngx_http_proxy_send_response
     ep->log = r->connection->log;
     ep->temp_path = p->lcf->temp_path;
 
-    ep->temp_file = ngx_palloc(r->pool, sizeof(ngx_file_t));
+    ep->temp_file = ngx_pcalloc(r->pool, sizeof(ngx_file_t));
     if (ep->temp_file == NULL) {
         ngx_http_proxy_finalize_request(p, 0);
         return;
@@ -750,10 +752,23 @@ static void ngx_http_proxy_send_response
      */
     p->header_in->last = p->header_in->pos;
 
-    /* STUB */ ep->cachable = 1;
-#if 0
-    ep->max_temp_file_size = 1000000000;
-#endif
+    /* STUB */ ep->cachable = 0;
+
+    if (p->lcf->cyclic_temp_file) {
+
+        /*
+         * we need to disable the use of sendfile() if we use cyclic temp file
+         * because the writing a new data can interfere with sendfile
+         * that uses the same kernel file pages
+         */
+
+        ep->cyclic_temp_file = 1;
+        r->sendfile = 0;
+
+    } else {
+        ep->cyclic_temp_file = 0;
+        r->sendfile = 1;
+    }
 
     p->event_pipe = ep;
 
@@ -1162,16 +1177,17 @@ static void *ngx_http_proxy_create_loc_c
     conf->header_size = 4096;
     conf->read_timeout = 30000;
 
-    conf->bufs.num = 10;
+    conf->bufs.num = 5;
     conf->bufs.size = 4096;
     conf->max_busy_len = 8192;
 
 
     /* CHECK in _init conf->max_temp_size >= conf->bufs.size !!! */
-    conf->max_temp_file_size = 4096 * 6;
+    conf->max_temp_file_size = 4096 * 3;
 
 
-    conf->temp_file_write_size = 4096 * 1;
+    conf->temp_file_write_size = 4096 * 2;
+    conf->cyclic_temp_file= 1;
 
     ngx_test_null(conf->temp_path, ngx_pcalloc(cf->pool, sizeof(ngx_path_t)),
                   NULL);
--- a/src/http/modules/proxy/ngx_http_proxy_handler.h
+++ b/src/http/modules/proxy/ngx_http_proxy_handler.h
@@ -26,10 +26,11 @@ typedef struct {
 
     ngx_bufs_t                  bufs;
 
-    /* STUB */
+    /* STUB names */
     int                         max_busy_len;
     int                         max_temp_file_size;
     int                         temp_file_write_size;
+    int                         cyclic_temp_file;
     /* */
 
     ngx_path_t                 *temp_path;
--- a/src/http/ngx_http_core_module.c
+++ b/src/http/ngx_http_core_module.c
@@ -130,6 +130,13 @@ static ngx_command_t  ngx_http_core_comm
      offsetof(ngx_http_core_loc_conf_t, doc_root),
      NULL},
 
+    {ngx_string("sendfile"),
+     NGX_HTTP_MAIN_CONF|NGX_HTTP_SRV_CONF|NGX_HTTP_LOC_CONF|NGX_CONF_TAKE1,
+     ngx_conf_set_flag_slot,
+     NGX_HTTP_LOC_CONF_OFFSET,
+     offsetof(ngx_http_core_loc_conf_t, sendfile),
+     NULL},
+
     {ngx_string("send_timeout"),
      NGX_HTTP_MAIN_CONF|NGX_HTTP_SRV_CONF|NGX_HTTP_LOC_CONF|NGX_CONF_TAKE1,
      ngx_conf_set_msec_slot,
@@ -334,7 +341,6 @@ int ngx_http_find_location_config(ngx_ht
     int                            i, rc;
     ngx_http_core_loc_conf_t      *clcf, **clcfp;
     ngx_http_core_srv_conf_t      *cscf;
-    ngx_http_write_filter_conf_t  *wcf;
 
     cscf = ngx_http_get_module_srv_conf(r, ngx_http_core_module);
 
@@ -364,14 +370,15 @@ ngx_log_debug(r->connection->log, "rc: %
         }
     }
 
-    wcf = ngx_http_get_module_loc_conf(r, ngx_http_write_filter_module);
+    clcf = ngx_http_get_module_loc_conf(r, ngx_http_core_module);
 
-    if (!(ngx_io.flags & NGX_IO_SENDFILE) || !wcf->sendfile) {
-        r->filter = NGX_HTTP_FILTER_NEED_IN_MEMORY;
+    if (!(ngx_io.flags & NGX_IO_SENDFILE) || !clcf->sendfile) {
+        r->sendfile = 0;
+
+    } else {
+        r->sendfile = 1;
     }
 
-    clcf = ngx_http_get_module_loc_conf(r, ngx_http_core_module);
-
     if (clcf->handler) {
         /*
          * if the location already has content handler then skip
@@ -828,6 +835,7 @@ static void *ngx_http_core_create_loc_co
 
     */
 
+    lcf->sendfile = NGX_CONF_UNSET;
     lcf->send_timeout = NGX_CONF_UNSET;
     lcf->discarded_buffer_size = NGX_CONF_UNSET;
     lcf->keepalive_timeout = NGX_CONF_UNSET;
@@ -896,6 +904,7 @@ static char *ngx_http_core_merge_loc_con
     ngx_conf_merge_str_value(conf->default_type,
                              prev->default_type, "text/plain");
 
+    ngx_conf_merge_value(conf->sendfile, prev->sendfile, 0);
     ngx_conf_merge_msec_value(conf->send_timeout, prev->send_timeout, 10000);
     ngx_conf_merge_size_value(conf->discarded_buffer_size,
                               prev->discarded_buffer_size, 1500);
--- a/src/http/ngx_http_core_module.h
+++ b/src/http/ngx_http_core_module.h
@@ -110,6 +110,7 @@ typedef struct {
     ngx_array_t  *types;
     ngx_str_t     default_type;
 
+    int           sendfile;                /* sendfile */
     ngx_msec_t    send_timeout;            /* send_timeout */
     ssize_t       send_lowat;              /* send_lowat */
     ssize_t       discarded_buffer_size;   /* discarded_buffer_size */
--- a/src/http/ngx_http_filter.h
+++ b/src/http/ngx_http_filter.h
@@ -7,12 +7,6 @@
 #define NGX_HTTP_FILTER_NEED_TEMP           4
 
 
-typedef struct {
-    ssize_t  buffer_output;
-    int      sendfile;
-} ngx_http_write_filter_conf_t;
-
-
 int ngx_http_output_filter(ngx_http_request_t *r, ngx_chain_t *in);
 int ngx_http_write_filter(ngx_http_request_t *r, ngx_chain_t *in);
 
@@ -20,7 +14,5 @@ int ngx_http_write_filter(ngx_http_reque
 extern int (*ngx_http_top_header_filter) (ngx_http_request_t *r);
 extern int (*ngx_http_top_body_filter) (ngx_http_request_t *r, ngx_chain_t *ch);
 
-extern ngx_module_t  ngx_http_write_filter_module;
-
 
 #endif /* _NGX_HTTP_FILTER_H_INCLUDED_ */
--- a/src/http/ngx_http_output_filter.c
+++ b/src/http/ngx_http_output_filter.c
@@ -32,7 +32,8 @@ typedef struct {
 } ngx_http_output_filter_ctx_t;
 
 
-static int ngx_http_output_filter_copy_hunk(ngx_hunk_t *dst, ngx_hunk_t *src);
+static int ngx_http_output_filter_copy_hunk(ngx_hunk_t *dst, ngx_hunk_t *src,
+                                            int sendfile);
 static void *ngx_http_output_filter_create_conf(ngx_conf_t *cf);
 static char *ngx_http_output_filter_merge_conf(ngx_conf_t *cf,
                                                void *parent, void *child);
@@ -77,7 +78,8 @@ ngx_module_t  ngx_http_output_filter_mod
 
 #define need_to_copy(r, hunk)                                             \
             (!ngx_hunk_special(hunk)                                      \
-             && (((r->filter & NGX_HTTP_FILTER_NEED_IN_MEMORY)            \
+             && (!r->sendfile                                             \
+                 || ((r->filter & NGX_HTTP_FILTER_NEED_IN_MEMORY)         \
                    && (hunk->type & NGX_HUNK_IN_MEMORY) == 0)             \
                  || ((r->filter & NGX_HTTP_FILTER_NEED_TEMP)              \
                   && (hunk->type & (NGX_HUNK_MEMORY|NGX_HUNK_MMAP)))))
@@ -162,6 +164,8 @@ int ngx_http_output_filter(ngx_http_requ
                                   ngx_create_temp_hunk(r->pool, conf->bufs.size,
                                                        0, 0),
                                   NGX_ERROR);
+                    ctx->hunk->tag = (ngx_hunk_tag_t)
+                                                &ngx_http_output_filter_module;
                     ctx->hunk->type |= NGX_HUNK_RECYCLED;
                     ctx->hunks++;
 
@@ -170,7 +174,8 @@ int ngx_http_output_filter(ngx_http_requ
                 }
             }
 
-            rc = ngx_http_output_filter_copy_hunk(ctx->hunk, ctx->in->hunk);
+            rc = ngx_http_output_filter_copy_hunk(ctx->hunk, ctx->in->hunk,
+                                                  r->sendfile);
 
             if (rc == NGX_ERROR) {
                 return rc;
@@ -215,13 +220,15 @@ int ngx_http_output_filter(ngx_http_requ
 
         last = ngx_next_filter(r, ctx->out);
 
-        ngx_chain_update_chains(&ctx->free, &ctx->busy, &ctx->out);
+        ngx_chain_update_chains(&ctx->free, &ctx->busy, &ctx->out,
+                               (ngx_hunk_tag_t) &ngx_http_output_filter_module);
         ctx->last_out = &ctx->out;
     }
 }
 
 
-static int ngx_http_output_filter_copy_hunk(ngx_hunk_t *dst, ngx_hunk_t *src)
+static int ngx_http_output_filter_copy_hunk(ngx_hunk_t *dst, ngx_hunk_t *src,
+                                            int sendfile)
 {
     ssize_t  n, size;
 
@@ -279,6 +286,10 @@ ngx_log_debug(src->file->log, "READ: %qd
         src->file_pos += n;
         dst->last += n;
 
+        if (!sendfile) {
+            dst->type &= ~NGX_HUNK_FILE;
+        }
+
         if ((src->type & NGX_HUNK_LAST) && src->file_pos == src->file_last) {
             dst->type |= NGX_HUNK_LAST;
         }
--- a/src/http/ngx_http_request.h
+++ b/src/http/ngx_http_request.h
@@ -190,6 +190,9 @@ struct ngx_http_request_s {
 #endif
     unsigned             pipeline:1;
 
+    /* can we use sendfile ? */
+    unsigned             sendfile:1;
+
     unsigned             chunked:1;
     unsigned             header_only:1;
     unsigned             keepalive:1;
--- a/src/http/ngx_http_write_filter.c
+++ b/src/http/ngx_http_write_filter.c
@@ -6,6 +6,11 @@
 
 
 typedef struct {
+    ssize_t  buffer_output;
+} ngx_http_write_filter_conf_t;
+
+
+typedef struct {
     ngx_chain_t  *out;
 } ngx_http_write_filter_ctx_t;
 
@@ -18,13 +23,6 @@ static int ngx_http_write_filter_init(ng
 
 static ngx_command_t ngx_http_write_filter_commands[] = {
 
-    {ngx_string("sendfile"),
-     NGX_HTTP_MAIN_CONF|NGX_HTTP_SRV_CONF|NGX_HTTP_LOC_CONF|NGX_CONF_TAKE1,
-     ngx_conf_set_flag_slot,
-     NGX_HTTP_LOC_CONF_OFFSET,
-     offsetof(ngx_http_write_filter_conf_t, sendfile),
-     NULL},
-
     {ngx_string("buffer_output"),
      NGX_HTTP_LOC_CONF|NGX_CONF_TAKE1,
      ngx_conf_set_size_slot,
@@ -94,9 +92,6 @@ int ngx_http_write_filter(ngx_http_reque
         }
     }
 
-    conf = ngx_http_get_module_loc_conf(r->main ? r->main : r,
-                                        ngx_http_write_filter_module);
-
     /* add the new chain to the existent one */
 
     for (/* void */; in; in = in->next) {
@@ -107,10 +102,6 @@ int ngx_http_write_filter(ngx_http_reque
         *le = ce;
         le = &ce->next;
 
-        if (!(ngx_io.flags & NGX_IO_SENDFILE) || !conf->sendfile) {
-            ce->hunk->type &= ~NGX_HUNK_FILE;
-        }
-
         size += ngx_hunk_size(ce->hunk);
 
         if (ce->hunk->type & (NGX_HUNK_FLUSH|NGX_HUNK_RECYCLED)) {
@@ -128,6 +119,9 @@ int ngx_http_write_filter(ngx_http_reque
                   last _ flush _ size);
 #endif
 
+    conf = ngx_http_get_module_loc_conf(r->main ? r->main : r,
+                                        ngx_http_write_filter_module);
+
     /*
      * avoid the output if there is no last hunk, no flush point and
      * size of the hunks is smaller then "buffer_output"
@@ -174,7 +168,6 @@ static void *ngx_http_write_filter_creat
                   NULL);
 
     conf->buffer_output = NGX_CONF_UNSET;
-    conf->sendfile = NGX_CONF_UNSET;
 
     return conf;
 }
@@ -187,7 +180,6 @@ static char *ngx_http_write_filter_merge
     ngx_http_write_filter_conf_t *conf = child;
 
     ngx_conf_merge_size_value(conf->buffer_output, prev->buffer_output, 1460);
-    ngx_conf_merge_value(conf->sendfile, prev->sendfile, 0);
 
     return NULL;
 }
--- a/src/os/unix/ngx_files.c
+++ b/src/os/unix/ngx_files.c
@@ -77,15 +77,15 @@ ssize_t ngx_write_chain_to_file(ngx_file
         ce = ce->next;
     }
 
-    if (lseek(file->fd, offset, SEEK_SET) == -1) {
-        ngx_log_error(NGX_LOG_CRIT, file->log, ngx_errno, "lseek() failed");
-        return NGX_ERROR;
+    if (file->offset != offset) {
+        if (lseek(file->fd, offset, SEEK_SET) == -1) {
+            ngx_log_error(NGX_LOG_CRIT, file->log, ngx_errno, "lseek() failed");
+            return NGX_ERROR;
+        }
     }
 
     n = writev(file->fd, (struct iovec *) io.elts, io.nelts);
 
-    ngx_destroy_array(&io);
-
     if (n == -1) {
         ngx_log_error(NGX_LOG_CRIT, file->log, ngx_errno, "writev() failed");
         return NGX_ERROR;
--- a/src/os/unix/ngx_freebsd_sendfile_chain.c
+++ b/src/os/unix/ngx_freebsd_sendfile_chain.c
@@ -83,9 +83,9 @@ ngx_chain_t *ngx_freebsd_sendfile_chain(
 
         if (ce && (ce->hunk->type & NGX_HUNK_FILE)) {
             file = ce->hunk;
-            ce = ce->next;
             fsize = (size_t) (file->file_last - file->file_pos);
             fprev = file->file_last;
+            ce = ce->next;
 
             /* coalesce the neighbouring file hunks */