[6.0] 103ea7c57 finalize task privs when rolling back workspaces

Dridi Boukelmoune dridi.boukelmoune at gmail.com
Thu Aug 16 08:53:10 UTC 2018


commit 103ea7c573d153966db68763ce0b40d2e2c01554
Author: Nils Goroll <nils.goroll at uplex.de>
Date:   Sun Jun 10 10:07:29 2018 +0200

    finalize task privs when rolling back workspaces
    
    ... and introduce request functions for this purpose (for busy
    objects, there is only one use case yet, so we don't).
    
    Before we reset the workspace, we must ensure that there are no active
    references to objects on it. As PRIV_TASK and PRIV_TOP have the same
    lifetime as the respective workspace, they need to be destroyed. vmods
    must not use workspaces for storing information referenced via any of
    the other PRIVs unless the rollback case is considered.
    
    Note that while this bug was exposed by
    beeaa19cced3fe1ab79381b2b1b7b0b5594cbb18, it existed all along for any
    vmod priv state stored on the workspace, so if a vmod happened to
    access a TASK_PRIV stored on the workspace, it would likely have
    triggered a magic check assertion as well.
    
    I got plans for making std.rollback() more useful. While this change
    is required to do so, it only partly covers the planned changes.
    
    Fixes #2706

diff --git a/bin/varnishd/cache/cache_req.c b/bin/varnishd/cache/cache_req.c
index a6b9ee0b1..d741441ca 100644
--- a/bin/varnishd/cache/cache_req.c
+++ b/bin/varnishd/cache/cache_req.c
@@ -181,6 +181,28 @@ Req_Release(struct req *req)
 	MPL_Free(pp->mpl_req, req);
 }
 
+static void
+req_finalize(struct req *req)
+{
+	VRTPRIV_dynamic_kill(req->privs, (uintptr_t)req);
+	VRTPRIV_dynamic_kill(req->privs, (uintptr_t)&req->top);
+	assert(VTAILQ_EMPTY(&req->privs->privs));
+}
+
+/*----------------------------------------------------------------------
+ * TODO:
+ * - check for code duplication with cnt_recv_prep
+ * - re-check if complete
+ */
+
+void
+Req_Rollback(struct req *req)
+{
+	req_finalize(req);
+	HTTP_Copy(req->http, req->http0);
+	WS_Reset(req->ws, req->ws_req);
+}
+
 /*----------------------------------------------------------------------
  * TODO: remove code duplication with cnt_recv_prep
  */
@@ -207,9 +229,7 @@ Req_Cleanup(struct sess *sp, struct worker *wrk, struct req *req)
 		req->vcl = NULL;
 	}
 
-	VRTPRIV_dynamic_kill(req->privs, (uintptr_t)req);
-	VRTPRIV_dynamic_kill(req->privs, (uintptr_t)&req->top);
-	assert(VTAILQ_EMPTY(&req->privs->privs));
+	req_finalize(req);
 
 	/* Charge and log byte counters */
 	if (req->vsl->wid) {
diff --git a/bin/varnishd/cache/cache_req_fsm.c b/bin/varnishd/cache/cache_req_fsm.c
index 00a02491b..b55a0c007 100644
--- a/bin/varnishd/cache/cache_req_fsm.c
+++ b/bin/varnishd/cache/cache_req_fsm.c
@@ -209,8 +209,8 @@ cnt_vclfail(const struct worker *wrk, struct req *req)
 	AZ(req->objcore);
 	AZ(req->stale_oc);
 
-	HTTP_Copy(req->http, req->http0);
-	WS_Reset(req->ws, req->ws_req);
+	Req_Rollback(req);
+
 	req->err_code = 503;
 	req->err_reason = "VCL failed";
 	req->req_step = R_STP_SYNTH;
@@ -857,8 +857,7 @@ cnt_recv(struct worker *wrk, struct req *req)
 
 	VCL_recv_method(req->vcl, wrk, req, NULL, NULL);
 	if (wrk->handling == VCL_RET_VCL && req->restarts == 0) {
-		HTTP_Copy(req->http, req->http0);
-		WS_Reset(req->ws, req->ws_req);
+		Req_Rollback(req);
 		cnt_recv_prep(req, ci);
 		VCL_recv_method(req->vcl, wrk, req, NULL, NULL);
 	}
diff --git a/bin/varnishd/cache/cache_varnishd.h b/bin/varnishd/cache/cache_varnishd.h
index 111c6530f..af122f768 100644
--- a/bin/varnishd/cache/cache_varnishd.h
+++ b/bin/varnishd/cache/cache_varnishd.h
@@ -314,6 +314,7 @@ void VRG_dorange(struct req *req, const char *r);
 /* cache_req.c */
 struct req *Req_New(const struct worker *, struct sess *);
 void Req_Release(struct req *);
+void Req_Rollback(struct req *req);
 void Req_Cleanup(struct sess *sp, struct worker *wrk, struct req *req);
 void Req_Fail(struct req *req, enum sess_close reason);
 void Req_AcctLogCharge(struct VSC_main *, struct req *);
diff --git a/bin/varnishd/cache/cache_vrt.c b/bin/varnishd/cache/cache_vrt.c
index 433ffd02f..8a31ee157 100644
--- a/bin/varnishd/cache/cache_vrt.c
+++ b/bin/varnishd/cache/cache_vrt.c
@@ -519,10 +519,11 @@ VRT_Rollback(VRT_CTX, VCL_HTTP hp)
 	CHECK_OBJ_NOTNULL(hp, HTTP_MAGIC);
 	if (hp == ctx->http_req) {
 		CHECK_OBJ_NOTNULL(ctx->req, REQ_MAGIC);
-		HTTP_Copy(ctx->req->http, ctx->req->http0);
-		WS_Reset(ctx->req->ws, ctx->req->ws_req);
+		Req_Rollback(ctx->req);
 	} else if (hp == ctx->http_bereq) {
 		CHECK_OBJ_NOTNULL(ctx->bo, BUSYOBJ_MAGIC);
+		// -> VBO_Rollback ?
+		VRTPRIV_dynamic_kill(ctx->bo->privs, (uintptr_t)ctx->bo);
 		HTTP_Copy(ctx->bo->bereq, ctx->bo->bereq0);
 		WS_Reset(ctx->bo->bereq->ws, ctx->bo->ws_bo);
 		WS_Reset(ctx->bo->ws, ctx->bo->ws_bo);
diff --git a/bin/varnishtest/tests/m00000.vtc b/bin/varnishtest/tests/m00000.vtc
index 7bdaa02b1..5c0fa7536 100644
--- a/bin/varnishtest/tests/m00000.vtc
+++ b/bin/varnishtest/tests/m00000.vtc
@@ -16,7 +16,15 @@ varnish v1 -vcl+backend {
 		debug.vsc_new();
 	}
 
+	sub vcl_synth {
+		set req.http.overwrite = "the workspace " +
+		    "to ensure we notice any unfinished privs";
+	}
 	sub vcl_recv {
+		if (req.url == "/fail") {
+			debug.test_priv_task("foo");
+			return (fail);
+		}
 		debug.rot52(req);
 		debug.vsc_count();
 	}
@@ -52,6 +60,9 @@ client c1 {
 	expect resp.http.encrypted == "ROT52"
 	expect resp.http.what >= 16
 	expect resp.http.not == -1
+	txreq -url "/fail"
+	rxresp
+	expect resp.status == 503
 } -run
 
 varnish v1 -expect DEBUG.count == 1


More information about the varnish-commit mailing list