Fix double allocations of busyobj in some cases

Make VBO_DerefBusyObj return refcount after decrementation

Make VBO_RefBusyObj return a pointer to the ref'ed busyobj

Make objcore's have a refcount on the busyobj

Drop const from VBO_RefBusyObj arg

BusyObj lock-less mode
---
 bin/varnishd/cache/cache.h         |    5 +++--
 bin/varnishd/cache/cache_busyobj.c |   22 +++++++++++++++-------
 bin/varnishd/cache/cache_center.c  |   36 +++++++++++++++++++-----------------
 bin/varnishd/cache/cache_hash.c    |   10 ++++++++--
 4 files changed, 45 insertions(+), 28 deletions(-)

diff --git a/bin/varnishd/cache/cache.h b/bin/varnishd/cache/cache.h
index 7fcd41e..4f260e9 100644
--- a/bin/varnishd/cache/cache.h
+++ b/bin/varnishd/cache/cache.h
@@ -501,6 +501,7 @@ struct busyobj {
        unsigned                magic;
 #define BUSYOBJ_MAGIC          0x23b95567
        struct vbo              *vbo;
+       unsigned                use_locks;
 
        uint8_t                 *vary;
        unsigned                is_gzip;
@@ -733,8 +734,8 @@ double BAN_Time(const struct ban *ban);
 /* cache_busyobj.c */
 void VBO_Init(void);
 struct busyobj *VBO_GetBusyObj(struct worker *wrk);
-void VBO_RefBusyObj(const struct busyobj *busyobj);
-void VBO_DerefBusyObj(struct worker *wrk, struct busyobj **busyobj);
+struct busyobj *VBO_RefBusyObj(struct busyobj *busyobj);
+unsigned VBO_DerefBusyObj(struct worker *wrk, struct busyobj **busyobj);
 void VBO_Free(struct vbo **vbo);
 
 /* cache_center.c [CNT] */
diff --git a/bin/varnishd/cache/cache_busyobj.c 
b/bin/varnishd/cache/cache_busyobj.c
index ab4db76..b8b6fd7 100644
--- a/bin/varnishd/cache/cache_busyobj.c
+++ b/bin/varnishd/cache/cache_busyobj.c
@@ -144,21 +144,25 @@ VBO_GetBusyObj(struct worker *wrk)
        return (&vbo->bo);
 }
 
-void
-VBO_RefBusyObj(const struct busyobj *busyobj)
+struct busyobj *
+VBO_RefBusyObj(struct busyobj *busyobj)
 {
        struct vbo *vbo;
 
        CHECK_OBJ_NOTNULL(busyobj, BUSYOBJ_MAGIC);
        vbo = busyobj->vbo;
        CHECK_OBJ_NOTNULL(vbo, VBO_MAGIC);
-       Lck_Lock(&vbo->mtx);
+       if (busyobj->use_locks)
+               Lck_Lock(&vbo->mtx);
        assert(vbo->refcount > 0);
        vbo->refcount++;
-       Lck_Unlock(&vbo->mtx);
+       if (busyobj->use_locks)
+               Lck_Unlock(&vbo->mtx);
+
+       return (busyobj);
 }
 
-void
+unsigned
 VBO_DerefBusyObj(struct worker *wrk, struct busyobj **pbo)
 {
        struct busyobj *bo;
@@ -172,10 +176,12 @@ VBO_DerefBusyObj(struct worker *wrk, struct busyobj **pbo)
        CHECK_OBJ_NOTNULL(bo, BUSYOBJ_MAGIC);
        vbo = bo->vbo;
        CHECK_OBJ_NOTNULL(vbo, VBO_MAGIC);
-       Lck_Lock(&vbo->mtx);
+       if (bo->use_locks)
+               Lck_Lock(&vbo->mtx);
        assert(vbo->refcount > 0);
        r = --vbo->refcount;
-       Lck_Unlock(&vbo->mtx);
+       if (bo->use_locks)
+               Lck_Unlock(&vbo->mtx);
 
        if (r == 0) {
                /* XXX: Sanity checks & cleanup */
@@ -196,4 +202,6 @@ VBO_DerefBusyObj(struct worker *wrk, struct busyobj **pbo)
                                VBO_Free(&vbo);
                }
        }
+
+       return (r);
 }
diff --git a/bin/varnishd/cache/cache_center.c 
b/bin/varnishd/cache/cache_center.c
index f9908b3..2909212 100644
--- a/bin/varnishd/cache/cache_center.c
+++ b/bin/varnishd/cache/cache_center.c
@@ -119,6 +119,7 @@ cnt_wait(struct sess *sp, struct worker *wrk, struct req 
*req)
        AZ(req->esi_level);
        assert(req->xid == 0);
        req->t_resp = NAN;
+       AZ(wrk->busyobj);
 
        assert(!isnan(sp->t_req));
        tmo = (int)(1e3 * cache_param->timeout_linger);
@@ -381,12 +382,11 @@ cnt_done(struct sess *sp, struct worker *wrk, struct req 
*req)
        CHECK_OBJ_ORNULL(req->vcl, VCL_CONF_MAGIC);
 
        AZ(req->obj);
+       AZ(req->objcore);
        AZ(wrk->busyobj);
        req->director = NULL;
        req->restarts = 0;
 
-       wrk->busyobj = NULL;
-
        SES_Charge(sp);
 
        /* If we did an ESI include, don't mess up our state */
@@ -535,7 +535,7 @@ cnt_error(struct sess *sp, struct worker *wrk, struct req 
*req)
        if (req->handling == VCL_RET_RESTART &&
            req->restarts <  cache_param->max_restarts) {
                HSH_Drop(wrk);
-               VBO_DerefBusyObj(wrk, &wrk->busyobj);
+               (void)VBO_DerefBusyObj(wrk, &wrk->busyobj);
                req->director = NULL;
                req->restarts++;
                sp->step = STP_RECV;
@@ -552,7 +552,7 @@ cnt_error(struct sess *sp, struct worker *wrk, struct req 
*req)
        req->err_code = 0;
        req->err_reason = NULL;
        http_Setup(wrk->busyobj->bereq, NULL);
-       VBO_DerefBusyObj(wrk, &wrk->busyobj);
+       (void)VBO_DerefBusyObj(wrk, &wrk->busyobj);
        sp->step = STP_PREPRESP;
        return (0);
 }
@@ -680,7 +680,7 @@ cnt_fetch(struct sess *sp, struct worker *wrk, struct req 
*req)
                AZ(HSH_Deref(wrk, req->objcore, NULL));
                req->objcore = NULL;
        }
-       VBO_DerefBusyObj(wrk, &wrk->busyobj);
+       (void)VBO_DerefBusyObj(wrk, &wrk->busyobj);
        req->director = NULL;
        req->storage_hint = NULL;
 
@@ -852,7 +852,7 @@ cnt_fetchbody(struct sess *sp, struct worker *wrk, struct 
req *req)
                req->err_code = 503;
                sp->step = STP_ERROR;
                VDI_CloseFd(wrk, &wrk->busyobj->vbc);
-               VBO_DerefBusyObj(wrk, &wrk->busyobj);
+               (void)VBO_DerefBusyObj(wrk, &wrk->busyobj);
                return (0);
        }
        CHECK_OBJ_NOTNULL(req->obj, OBJECT_MAGIC);
@@ -922,7 +922,7 @@ cnt_fetchbody(struct sess *sp, struct worker *wrk, struct 
req *req)
 
        if (i) {
                HSH_Drop(wrk);
-               VBO_DerefBusyObj(wrk, &wrk->busyobj);
+               (void)VBO_DerefBusyObj(wrk, &wrk->busyobj);
                AZ(req->obj);
                req->err_code = 503;
                sp->step = STP_ERROR;
@@ -935,7 +935,7 @@ cnt_fetchbody(struct sess *sp, struct worker *wrk, struct 
req *req)
                AN(req->obj->objcore->ban);
                HSH_Unbusy(wrk);
        }
-       VBO_DerefBusyObj(wrk, &wrk->busyobj);
+       (void)VBO_DerefBusyObj(wrk, &wrk->busyobj);
        wrk->acct_tmp.fetch++;
        sp->step = STP_PREPRESP;
        return (0);
@@ -1011,7 +1011,7 @@ cnt_streambody(struct sess *sp, struct worker *wrk, 
struct req *req)
        assert(WRW_IsReleased(wrk));
        assert(wrk->wrw.ciov == wrk->wrw.siov);
        (void)HSH_Deref(wrk, NULL, &req->obj);
-       VBO_DerefBusyObj(wrk, &wrk->busyobj);
+       (void)VBO_DerefBusyObj(wrk, &wrk->busyobj);
        http_Setup(req->resp, NULL);
        sp->step = STP_DONE;
        return (0);
@@ -1103,6 +1103,10 @@ cnt_hit(struct sess *sp, struct worker *wrk, struct req 
*req)
        /* Drop our object, we won't need it */
        (void)HSH_Deref(wrk, NULL, &req->obj);
        req->objcore = NULL;
+       if (wrk->busyobj != NULL) {
+               CHECK_OBJ_NOTNULL(wrk->busyobj, BUSYOBJ_MAGIC);
+               (void)VBO_DerefBusyObj(wrk, &wrk->busyobj);
+       }
 
        switch(req->handling) {
        case VCL_RET_PASS:
@@ -1274,7 +1278,6 @@ cnt_miss(struct sess *sp, struct worker *wrk, struct req 
*req)
        AN(req->objcore);
        CHECK_OBJ_NOTNULL(wrk->busyobj, BUSYOBJ_MAGIC);
        WS_Reset(wrk->ws, NULL);
-       wrk->busyobj = VBO_GetBusyObj(wrk);
        http_Setup(wrk->busyobj->bereq, wrk->ws);
        http_FilterReq(sp, HTTPH_R_FETCH);
        http_ForceGet(wrk->busyobj->bereq);
@@ -1299,13 +1302,13 @@ cnt_miss(struct sess *sp, struct worker *wrk, struct 
req *req)
                AZ(HSH_Deref(wrk, req->objcore, NULL));
                req->objcore = NULL;
                http_Setup(wrk->busyobj->bereq, NULL);
-               VBO_DerefBusyObj(wrk, &wrk->busyobj);
+               (void)VBO_DerefBusyObj(wrk, &wrk->busyobj);
                sp->step = STP_ERROR;
                return (0);
        case VCL_RET_PASS:
                AZ(HSH_Deref(wrk, req->objcore, NULL));
                req->objcore = NULL;
-               VBO_DerefBusyObj(wrk, &wrk->busyobj);
+               (void)VBO_DerefBusyObj(wrk, &wrk->busyobj);
                sp->step = STP_PASS;
                return (0);
        case VCL_RET_FETCH:
@@ -1315,7 +1318,7 @@ cnt_miss(struct sess *sp, struct worker *wrk, struct req 
*req)
        case VCL_RET_RESTART:
                AZ(HSH_Deref(wrk, req->objcore, NULL));
                req->objcore = NULL;
-               VBO_DerefBusyObj(wrk, &wrk->busyobj);
+               (void)VBO_DerefBusyObj(wrk, &wrk->busyobj);
                INCOMPL();
        default:
                WRONG("Illegal action in vcl_miss{}");
@@ -1364,7 +1367,6 @@ cnt_pass(struct sess *sp, struct worker *wrk, struct req 
*req)
        AZ(req->obj);
        AZ(wrk->busyobj);
 
-       wrk->busyobj = VBO_GetBusyObj(wrk);
        WS_Reset(wrk->ws, NULL);
        wrk->busyobj = VBO_GetBusyObj(wrk);
        http_Setup(wrk->busyobj->bereq, wrk->ws);
@@ -1376,7 +1378,7 @@ cnt_pass(struct sess *sp, struct worker *wrk, struct req 
*req)
        VCL_pass_method(sp);
        if (req->handling == VCL_RET_ERROR) {
                http_Setup(wrk->busyobj->bereq, NULL);
-               VBO_DerefBusyObj(wrk, &wrk->busyobj);
+               (void)VBO_DerefBusyObj(wrk, &wrk->busyobj);
                sp->step = STP_ERROR;
                return (0);
        }
@@ -1423,7 +1425,6 @@ cnt_pipe(struct sess *sp, struct worker *wrk, const 
struct req *req)
        AZ(wrk->busyobj);
 
        wrk->acct_tmp.pipe++;
-       wrk->busyobj = VBO_GetBusyObj(wrk);
        WS_Reset(wrk->ws, NULL);
        wrk->busyobj = VBO_GetBusyObj(wrk);
        http_Setup(wrk->busyobj->bereq, wrk->ws);
@@ -1438,7 +1439,7 @@ cnt_pipe(struct sess *sp, struct worker *wrk, const 
struct req *req)
        PipeSession(sp);
        assert(WRW_IsReleased(wrk));
        http_Setup(wrk->busyobj->bereq, NULL);
-       VBO_DerefBusyObj(wrk, &wrk->busyobj);
+       (void)VBO_DerefBusyObj(wrk, &wrk->busyobj);
        sp->step = STP_DONE;
        return (0);
 }
@@ -1577,6 +1578,7 @@ cnt_start(struct sess *sp, struct worker *wrk, struct req 
*req)
        AZ(req->vcl);
        EXP_Clr(&req->exp);
        AZ(req->esi_level);
+       AZ(wrk->busyobj);
 
        /* Update stats of various sorts */
        wrk->stats.client_req++;
diff --git a/bin/varnishd/cache/cache_hash.c b/bin/varnishd/cache/cache_hash.c
index d967291..e78eb60 100644
--- a/bin/varnishd/cache/cache_hash.c
+++ b/bin/varnishd/cache/cache_hash.c
@@ -306,6 +306,7 @@ HSH_Lookup(struct sess *sp, struct objhead **poh)
        AN(sp->req->director);
        AN(hash);
        wrk = sp->wrk;
+       AZ(wrk->busyobj);
 
        HSH_Prealloc(sp);
        memcpy(sp->wrk->nobjhead->digest, sp->req->digest,
@@ -459,7 +460,7 @@ HSH_Lookup(struct sess *sp, struct objhead **poh)
                wrk->busyobj->vary = sp->req->vary_b;
        else
                wrk->busyobj->vary = NULL;
-       oc->busyobj = wrk->busyobj;
+       oc->busyobj = VBO_RefBusyObj(wrk->busyobj);
 
        /*
         * Busy objects go on the tail, so they will not trip up searches.
@@ -622,7 +623,8 @@ HSH_Unbusy(struct worker *wrk)
        VTAILQ_REMOVE(&oh->objcs, oc, list);
        VTAILQ_INSERT_HEAD(&oh->objcs, oc, list);
        oc->flags &= ~OC_F_BUSY;
-       oc->busyobj = NULL;
+       if (oc->busyobj != NULL)
+               (void)VBO_DerefBusyObj(wrk, &oc->busyobj);
        if (oh->waitinglist != NULL)
                hsh_rush(oh);
        AN(oc->ban);
@@ -710,6 +712,10 @@ HSH_Deref(struct worker *wrk, struct objcore *oc, struct 
object **oo)
        BAN_DestroyObj(oc);
        AZ(oc->ban);
 
+       if (oc->busyobj != NULL)
+               (void)VBO_DerefBusyObj(wrk, &oc->busyobj);
+       AZ(oc->busyobj);
+
        if (oc->methods != NULL) {
                oc_freeobj(oc);
                wrk->stats.n_object--;
-- 
1.7.4.1


_______________________________________________
varnish-dev mailing list
[email protected]
https://www.varnish-cache.org/lists/mailman/listinfo/varnish-dev

Reply via email to