[master] b2b6e32 Fix a race spotted by Nils: We have to hold a ref to the busyobj if we want to examine it in any detail.
Poul-Henning Kamp
phk at FreeBSD.org
Mon Jun 30 21:37:13 CEST 2014
commit b2b6e329da78e465720bec9a26a905e8a77cab92
Author: Poul-Henning Kamp <phk at FreeBSD.org>
Date: Mon Jun 30 19:34:47 2014 +0000
Fix a race spotted by Nils: We have to hold a ref to the
busyobj if we want to examine it in any detail.
Hold that ref over all of V1D_Deliver() (different from Nils
patch) to make sure we have a consistent view on streaming
vs. no streaming throughout.
Also use the bo to clean up a hack related to ESI includes.
Diagnosed by: Nils Goroll
diff --git a/bin/varnishd/cache/cache.h b/bin/varnishd/cache/cache.h
index ad4c3ab..038510d 100644
--- a/bin/varnishd/cache/cache.h
+++ b/bin/varnishd/cache/cache.h
@@ -818,7 +818,7 @@ HTTP1_Chunked(struct http_conn *htc, intptr_t *priv, const char **error,
/* cache_http1_deliver.c */
unsigned V1D_FlushReleaseAcct(struct req *req);
-void V1D_Deliver(struct req *);
+void V1D_Deliver(struct req *, struct busyobj *);
void V1D_Deliver_Synth(struct req *req);
diff --git a/bin/varnishd/cache/cache_http1_deliver.c b/bin/varnishd/cache/cache_http1_deliver.c
index 1bdcef7..73aea69 100644
--- a/bin/varnishd/cache/cache_http1_deliver.c
+++ b/bin/varnishd/cache/cache_http1_deliver.c
@@ -87,7 +87,7 @@ v1d_range_bytes(struct req *req, enum vdp_action act, const void *ptr,
/*--------------------------------------------------------------------*/
static void
-v1d_dorange(struct req *req, const char *r)
+v1d_dorange(struct req *req, struct busyobj *bo, const char *r)
{
ssize_t len, low, high, has_low;
@@ -96,8 +96,8 @@ v1d_dorange(struct req *req, const char *r)
assert(http_GetStatus(req->obj->http) == 200);
/* We must snapshot the length if we're streaming from the backend */
- if (req->obj->objcore->busyobj != NULL)
- len = VBO_waitlen(req->obj->objcore->busyobj, -1);
+ if (bo != NULL)
+ len = VBO_waitlen(bo, -1);
else
len = req->obj->len;
@@ -228,10 +228,11 @@ V1D_FlushReleaseAcct(struct req *req)
}
void
-V1D_Deliver(struct req *req)
+V1D_Deliver(struct req *req, struct busyobj *bo)
{
char *r;
enum objiter_status ois;
+ ssize_t l;
CHECK_OBJ_NOTNULL(req, REQ_MAGIC);
CHECK_OBJ_NOTNULL(req->obj, OBJECT_MAGIC);
@@ -247,7 +248,7 @@ V1D_Deliver(struct req *req)
req->res_mode &= ~RES_LEN;
http_Unset(req->resp, H_Content_Length);
req->wantbody = 0;
- } else if (req->obj->objcore->busyobj == NULL) {
+ } else if (bo == NULL) {
/* XXX: Not happy with this convoluted test */
req->res_mode |= RES_LEN;
if (!(req->obj->objcore->flags & OC_F_PASS) ||
@@ -310,7 +311,7 @@ V1D_Deliver(struct req *req)
http_GetStatus(req->resp) == 200) {
http_SetHeader(req->resp, "Accept-Ranges: bytes");
if (http_GetHdr(req->http, H_Range, &r))
- v1d_dorange(req, r);
+ v1d_dorange(req, bo, r);
}
if (req->res_mode & RES_ESI)
@@ -334,8 +335,11 @@ V1D_Deliver(struct req *req)
} else if (req->res_mode & RES_ESI) {
ESI_Deliver(req);
} else if (req->res_mode & RES_ESI_CHILD && req->gzip_resp) {
- while (req->obj->objcore->busyobj)
- (void)usleep(10000);
+ l = -1;
+ while (req->obj->objcore->busyobj) {
+ assert(bo != NULL);
+ l = VBO_waitlen(bo, l);
+ }
ESI_DeliverChild(req);
} else if (req->res_mode & RES_GUNZIP ||
(req->res_mode & RES_ESI_CHILD &&
@@ -421,7 +425,7 @@ V1D_Deliver_Synth(struct req *req)
http_GetStatus(req->resp) == 200) {
http_SetHeader(req->resp, "Accept-Ranges: bytes");
if (http_GetHdr(req->http, H_Range, &r))
- v1d_dorange(req, r);
+ v1d_dorange(req, NULL, r);
}
WRW_Reserve(req->wrk, &req->sp->fd, req->vsl, req->t_prev);
@@ -441,8 +445,6 @@ V1D_Deliver_Synth(struct req *req)
#if 0
XXX: Missing pretend GZIP for esi-children
} else if (req->res_mode & RES_ESI_CHILD && req->gzip_resp) {
- while (req->obj->objcore->busyobj)
- (void)usleep(10000);
ESI_DeliverChild(req);
#endif
} else {
diff --git a/bin/varnishd/cache/cache_req_fsm.c b/bin/varnishd/cache/cache_req_fsm.c
index f987568..161c5e8 100644
--- a/bin/varnishd/cache/cache_req_fsm.c
+++ b/bin/varnishd/cache/cache_req_fsm.c
@@ -87,6 +87,7 @@ DOT deliver:deliver:s -> DONE [style=bold,color=blue]
static enum req_fsm_nxt
cnt_deliver(struct worker *wrk, struct req *req)
{
+ struct busyobj *bo;
CHECK_OBJ_NOTNULL(wrk, WORKER_MAGIC);
CHECK_OBJ_NOTNULL(req, REQ_MAGIC);
@@ -154,7 +155,12 @@ cnt_deliver(struct worker *wrk, struct req *req)
req->wantbody = 0;
}
- V1D_Deliver(req);
+ /* Grab a ref to the bo if there is one, and hand it down */
+ bo = HSH_RefBusy(req->obj->objcore);
+ V1D_Deliver(req, bo);
+ if (bo != NULL)
+ VBO_DerefBusyObj(req->wrk, &bo);
+
VSLb_ts_req(req, "Resp", W_TIM_real(wrk));
if (http_HdrIs(req->resp, H_Connection, "close"))
More information about the varnish-commit
mailing list