varnish-cache/bin/varnishd/storage/storage_simple.c
0
/*-
1
 * Copyright (c) 2007-2015 Varnish Software AS
2
 * All rights reserved.
3
 *
4
 * Author: Poul-Henning Kamp <phk@phk.freebsd.dk>
5
 *
6
 * SPDX-License-Identifier: BSD-2-Clause
7
 *
8
 * Redistribution and use in source and binary forms, with or without
9
 * modification, are permitted provided that the following conditions
10
 * are met:
11
 * 1. Redistributions of source code must retain the above copyright
12
 *    notice, this list of conditions and the following disclaimer.
13
 * 2. Redistributions in binary form must reproduce the above copyright
14
 *    notice, this list of conditions and the following disclaimer in the
15
 *    documentation and/or other materials provided with the distribution.
16
 *
17
 * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND
18
 * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
19
 * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
20
 * ARE DISCLAIMED.  IN NO EVENT SHALL AUTHOR OR CONTRIBUTORS BE LIABLE
21
 * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
22
 * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
23
 * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
24
 * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
25
 * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
26
 * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
27
 * SUCH DAMAGE.
28
 *
29
 */
30
31
#include "config.h"
32
33
#include "cache/cache_varnishd.h"
34
35 108318
#include "cache/cache_obj.h"
36 88277
#include "cache/cache_objhead.h"
37 20555
38 14249
#include "storage/storage.h"
39 88279
#include "storage/storage_simple.h"
40
41
#include "vtim.h"
42
43
/* Flags for allocating memory in sml_stv_alloc */
44
#define LESS_MEM_ALLOCED_IS_OK  1
45 120105
46 228282
// marker pointer for sml_trimstore
47
static void *trim_once = &trim_once;
48
49
/*-------------------------------------------------------------------*/
50
51
static struct storage *
52 157808
objallocwithnuke(struct worker *, const struct stevedore *, ssize_t size,
53
    int flags);
54
55
static struct storage *
56 124775
sml_stv_alloc(const struct stevedore *stv, ssize_t size, int flags)
57
{
58
        struct storage *st;
59
60 124775
        CHECK_OBJ_NOTNULL(stv, STEVEDORE_MAGIC);
61 124775
        AN(stv->sml_alloc);
62
63 124775
        if (!(flags & LESS_MEM_ALLOCED_IS_OK)) {
64 13404
                if (size > cache_param->fetch_maxchunksize)
65 0
                        return (NULL);
66
                else
67 13404
                        return (stv->sml_alloc(stv, size));
68
        }
69
70 111371
        if (size > cache_param->fetch_maxchunksize)
71 0
                size = cache_param->fetch_maxchunksize;
72
73 111371
        assert(size <= UINT_MAX);       /* field limit in struct storage */
74
75 116771
        for (;;) {
76
                /* try to allocate from it */
77 116771
                assert(size > 0);
78 116771
                st = stv->sml_alloc(stv, size);
79 116771
                if (st != NULL)
80 110931
                        break;
81
82 5840
                if (size <= cache_param->fetch_chunksize)
83 440
                        break;
84
85 5400
                size /= 2;
86
        }
87 111371
        CHECK_OBJ_ORNULL(st, STORAGE_MAGIC);
88 111371
        return (st);
89 124775
}
90
91
static void
92 163538
sml_stv_free(const struct stevedore *stv, struct storage *st)
93
{
94
95 163538
        CHECK_OBJ_NOTNULL(stv, STEVEDORE_MAGIC);
96 163538
        CHECK_OBJ_NOTNULL(st, STORAGE_MAGIC);
97 163538
        if (stv->sml_free != NULL)
98 163537
                stv->sml_free(st);
99 163538
}
100
101
/*--------------------------------------------------------------------
102
 * This function is called by stevedores ->allocobj() method, which
103
 * very often will be SML_allocobj() below, to convert a slab
104
 * of storage into object which the stevedore can then register in its
105
 * internal state, before returning it to STV_NewObject().
106
 * As you probably guessed: All this for persistence.
107
 */
108
109
struct object *
110 112919
SML_MkObject(const struct stevedore *stv, struct objcore *oc, void *ptr)
111
{
112
        struct object *o;
113
114 112919
        CHECK_OBJ_NOTNULL(stv, STEVEDORE_MAGIC);
115 112919
        AN(stv->methods);
116 112919
        CHECK_OBJ_NOTNULL(oc, OBJCORE_MAGIC);
117
118 112919
        assert(PAOK(ptr));
119
120 112919
        o = ptr;
121 112919
        INIT_OBJ(o, OBJECT_MAGIC);
122
123 112919
        VTAILQ_INIT(&o->list);
124
125 112919
        oc->stobj->stevedore = stv;
126 112919
        oc->stobj->priv = o;
127 112919
        oc->stobj->priv2 = 0;
128 112919
        return (o);
129
}
130
131
/*--------------------------------------------------------------------
132
 * This is the default ->allocobj() which all stevedores who do not
133
 * implement persistent storage can rely on.
134
 */
135
136
int v_matchproto_(storage_allocobj_f)
137 112479
SML_allocobj(struct worker *wrk, const struct stevedore *stv,
138
    struct objcore *oc, unsigned wsl)
139
{
140
        struct object *o;
141 112479
        struct storage *st = NULL;
142
        unsigned ltot;
143
144 112479
        CHECK_OBJ_NOTNULL(wrk, WORKER_MAGIC);
145 112479
        CHECK_OBJ_NOTNULL(stv, STEVEDORE_MAGIC);
146 112479
        CHECK_OBJ_NOTNULL(oc, OBJCORE_MAGIC);
147
148 112479
        AN(stv->sml_alloc);
149
150 112479
        ltot = sizeof(*o) + PRNDUP(wsl);
151
152 112479
        do {
153 112600
                st = stv->sml_alloc(stv, ltot);
154 112600
                if (st != NULL && st->space < ltot) {
155 0
                        stv->sml_free(st);
156 0
                        st = NULL;
157 0
                }
158 112600
        } while (st == NULL && LRU_NukeOne(wrk, stv->lru));
159 112479
        if (st == NULL)
160 440
                return (0);
161
162 112039
        CHECK_OBJ_NOTNULL(st, STORAGE_MAGIC);
163 112039
        o = SML_MkObject(stv, oc, st->ptr);
164 112039
        CHECK_OBJ_NOTNULL(o, OBJECT_MAGIC);
165 112039
        st->len = sizeof(*o);
166 112039
        o->objstore = st;
167 112039
        return (1);
168 112479
}
169
170
void * v_matchproto_(storage_allocbuf_t)
171 880
SML_AllocBuf(struct worker *wrk, const struct stevedore *stv, size_t size,
172
    uintptr_t *ppriv)
173
{
174
        struct storage *st;
175
176 880
        CHECK_OBJ_NOTNULL(wrk, WORKER_MAGIC);
177 880
        CHECK_OBJ_NOTNULL(stv, STEVEDORE_MAGIC);
178 880
        AN(ppriv);
179
180 880
        if (size > UINT_MAX)
181 0
                return (NULL);
182 880
        st = objallocwithnuke(wrk, stv, size, 0);
183 880
        if (st == NULL)
184 0
                return (NULL);
185 880
        assert(st->space >= size);
186 880
        st->flags = STORAGE_F_BUFFER;
187 880
        st->len = size;
188 880
        *ppriv = (uintptr_t)st;
189 880
        return (st->ptr);
190 880
}
191
192
void v_matchproto_(storage_freebuf_t)
193 880
SML_FreeBuf(struct worker *wrk, const struct stevedore *stv, uintptr_t priv)
194
{
195
        struct storage *st;
196
197 880
        CHECK_OBJ_NOTNULL(wrk, WORKER_MAGIC);
198 880
        CHECK_OBJ_NOTNULL(stv, STEVEDORE_MAGIC);
199
200 880
        CAST_OBJ_NOTNULL(st, (void *)priv, STORAGE_MAGIC);
201 880
        assert(st->flags == STORAGE_F_BUFFER);
202 880
        sml_stv_free(stv, st);
203 880
}
204
205
/*---------------------------------------------------------------------
206
 */
207
208
static struct object *
209 6177387
sml_getobj(struct worker *wrk, struct objcore *oc)
210
{
211
        const struct stevedore *stv;
212
        struct object *o;
213
214 6177387
        CHECK_OBJ_NOTNULL(wrk, WORKER_MAGIC);
215 6177387
        CHECK_OBJ_NOTNULL(oc, OBJCORE_MAGIC);
216 6177387
        stv = oc->stobj->stevedore;
217 6177387
        CHECK_OBJ_NOTNULL(stv, STEVEDORE_MAGIC);
218 6177387
        if (stv->sml_getobj != NULL)
219 11600
                return (stv->sml_getobj(wrk, oc));
220 6165787
        if (oc->stobj->priv == NULL)
221 0
                return (NULL);
222 6165787
        CAST_OBJ_NOTNULL(o, oc->stobj->priv, OBJECT_MAGIC);
223 6165787
        return (o);
224 6177387
}
225
226
static void v_matchproto_(objslim_f)
227 126728
sml_slim(struct worker *wrk, struct objcore *oc)
228
{
229
        const struct stevedore *stv;
230
        struct object *o;
231
        struct storage *st, *stn;
232
233 126728
        CHECK_OBJ_NOTNULL(wrk, WORKER_MAGIC);
234
235 126728
        stv = oc->stobj->stevedore;
236 126728
        CHECK_OBJ_NOTNULL(stv, STEVEDORE_MAGIC);
237 126728
        o = sml_getobj(wrk, oc);
238 126728
        CHECK_OBJ_NOTNULL(o, OBJECT_MAGIC);
239
240
#define OBJ_AUXATTR(U, l)                                       \
241
        do {                                                    \
242
                if (o->aa_##l != NULL) {                        \
243
                        sml_stv_free(stv, o->aa_##l);           \
244
                        o->aa_##l = NULL;                       \
245
                }                                               \
246
        } while (0);
247
#include "tbl/obj_attr.h"
248
249 159768
        VTAILQ_FOREACH_SAFE(st, &o->list, list, stn) {
250 33040
                CHECK_OBJ_NOTNULL(st, STORAGE_MAGIC);
251 33040
                VTAILQ_REMOVE(&o->list, st, list);
252 33040
                sml_stv_free(stv, st);
253 33040
        }
254
}
255
256
static void
257 113597
sml_bocfini(const struct stevedore *stv, struct boc *boc)
258
{
259
        struct storage *st;
260
261 113597
        CHECK_OBJ_NOTNULL(stv, STEVEDORE_MAGIC);
262 113597
        CHECK_OBJ_NOTNULL(boc, BOC_MAGIC);
263
264 113597
        if (boc->stevedore_priv == NULL ||
265 74801
            boc->stevedore_priv == trim_once)
266 105513
                return;
267
268
        /* Free any leftovers from Trim */
269 8084
        TAKE_OBJ_NOTNULL(st, &boc->stevedore_priv, STORAGE_MAGIC);
270 8084
        sml_stv_free(stv, st);
271 113597
}
272
273
/*
274
 * called in two cases:
275
 * - oc->boc == NULL: cache object on LRU freed
276
 * - oc->boc != NULL: cache object replaced for backend error
277
 */
278
static void v_matchproto_(objfree_f)
279 70888
sml_objfree(struct worker *wrk, struct objcore *oc)
280
{
281
        const struct stevedore *stv;
282
        struct storage *st;
283
        struct object *o;
284
285 70888
        CHECK_OBJ_NOTNULL(wrk, WORKER_MAGIC);
286 70888
        CHECK_OBJ_NOTNULL(oc, OBJCORE_MAGIC);
287 70888
        stv = oc->stobj->stevedore;
288 70888
        CHECK_OBJ_NOTNULL(stv, STEVEDORE_MAGIC);
289 70888
        CAST_OBJ_NOTNULL(o, oc->stobj->priv, OBJECT_MAGIC);
290
291 70888
        sml_slim(wrk, oc);
292 70888
        st = o->objstore;
293 70888
        CHECK_OBJ_NOTNULL(st, STORAGE_MAGIC);
294 70888
        FINI_OBJ(o);
295
296 70888
        if (oc->boc != NULL)
297 840
                sml_bocfini(stv, oc->boc);
298 70048
        else if (stv->lru != NULL)
299 70045
                LRU_Remove(oc);
300
301 70888
        sml_stv_free(stv, st);
302
303 70888
        memset(oc->stobj, 0, sizeof oc->stobj);
304
305 70888
        wrk->stats->n_object--;
306 70888
}
307
308
static int v_matchproto_(objiterator_f)
309 95753
sml_iterator(struct worker *wrk, struct objcore *oc,
310
    void *priv, objiterate_f *func, int final)
311
{
312
        struct boc *boc;
313
        enum boc_state_e state;
314
        struct object *obj;
315
        struct storage *st;
316 95753
        struct storage *checkpoint = NULL;
317
        const struct stevedore *stv;
318 95753
        ssize_t checkpoint_len = 0;
319 95753
        ssize_t len = 0;
320 95753
        int ret = 0, ret2;
321
        ssize_t ol;
322
        ssize_t nl;
323
        ssize_t sl;
324
        void *p;
325
        ssize_t l;
326
        unsigned u;
327
328 95753
        obj = sml_getobj(wrk, oc);
329 95753
        CHECK_OBJ_NOTNULL(obj, OBJECT_MAGIC);
330 95753
        stv = oc->stobj->stevedore;
331 95753
        CHECK_OBJ_NOTNULL(stv, STEVEDORE_MAGIC);
332
333 95753
        boc = HSH_RefBoc(oc);
334
335 95753
        if (boc == NULL) {
336 137157
                VTAILQ_FOREACH_REVERSE_SAFE(
337
                    st, &obj->list, storagehead, list, checkpoint) {
338
339 72680
                        u = 0;
340 72680
                        if (VTAILQ_PREV(st, storagehead, list) == NULL)
341 65677
                                u |= OBJ_ITER_END;
342 72680
                        if (final)
343 30360
                                u |= OBJ_ITER_FLUSH;
344 72680
                        if (ret == 0 && st->len > 0)
345 72675
                                ret = func(priv, u, st->ptr, st->len);
346 72682
                        if (final) {
347 30360
                                VTAILQ_REMOVE(&obj->list, st, list);
348 30360
                                sml_stv_free(stv, st);
349 72678
                        } else if (ret)
350 1241
                                break;
351 71437
                }
352 65718
                return (ret);
353
        }
354
355 30033
        p = NULL;
356 30033
        l = 0;
357
358 30033
        u = 0;
359 30033
        if (boc->fetched_so_far == 0) {
360 3336
                ret = func(priv, OBJ_ITER_FLUSH, NULL, 0);
361 3336
                if (ret)
362 0
                        return (ret);
363 3336
        }
364 87130
        while (1) {
365 87130
                ol = len;
366 87130
                nl = ObjWaitExtend(wrk, oc, ol, &state);
367 87130
                if (state == BOS_FAILED) {
368 560
                        ret = -1;
369 560
                        break;
370
                }
371 86570
                if (nl == ol) {
372 28763
                        assert(state == BOS_FINISHED);
373 28763
                        break;
374
                }
375 57807
                assert(nl > ol);
376 57807
                Lck_Lock(&boc->mtx);
377 57807
                AZ(VTAILQ_EMPTY(&obj->list));
378 57807
                if (checkpoint == NULL) {
379 35551
                        st = VTAILQ_LAST(&obj->list, storagehead);
380 35551
                        sl = 0;
381 35551
                } else {
382 22256
                        st = checkpoint;
383 22256
                        sl = checkpoint_len;
384 22256
                        ol -= checkpoint_len;
385
                }
386 79518
                while (st != NULL) {
387 79517
                        if (st->len > ol) {
388 57806
                                p = st->ptr + ol;
389 57806
                                l = st->len - ol;
390 57806
                                len += l;
391 57806
                                break;
392
                        }
393 21711
                        ol -= st->len;
394 21711
                        assert(ol >= 0);
395 21711
                        nl -= st->len;
396 21711
                        assert(nl > 0);
397 21711
                        sl += st->len;
398 21711
                        st = VTAILQ_PREV(st, storagehead, list);
399 21711
                        if (final && checkpoint != NULL) {
400 19811
                                if (checkpoint == boc->stevedore_priv)
401 0
                                        boc->stevedore_priv = trim_once;
402
                                else
403 19811
                                        VTAILQ_REMOVE(&obj->list, checkpoint, list);
404 19811
                                sml_stv_free(stv, checkpoint);
405 19811
                        }
406 21711
                        checkpoint = st;
407 21711
                        checkpoint_len = sl;
408
                }
409 57813
                CHECK_OBJ_NOTNULL(obj, OBJECT_MAGIC);
410 57813
                CHECK_OBJ_NOTNULL(st, STORAGE_MAGIC);
411 57813
                st = VTAILQ_PREV(st, storagehead, list);
412 57813
                if (st != NULL && st->len == 0)
413 9437
                        st = NULL;
414 57813
                Lck_Unlock(&boc->mtx);
415 57813
                assert(l > 0 || state == BOS_FINISHED);
416 57813
                u = 0;
417 57813
                if (st == NULL || final)
418 57077
                        u |= OBJ_ITER_FLUSH;
419 57813
                if (st == NULL && state == BOS_FINISHED)
420 287
                        u |= OBJ_ITER_END;
421 57813
                ret = func(priv, u, p, l);
422 57813
                if (ret)
423 716
                        break;
424
        }
425 30039
        HSH_DerefBoc(wrk, oc);
426 30039
        if ((u & OBJ_ITER_END) == 0) {
427 29753
                ret2 = func(priv, OBJ_ITER_END, NULL, 0);
428 29753
                if (ret == 0)
429 28477
                        ret = ret2;
430 29753
        }
431 30039
        return (ret);
432 95757
}
433
434
/*--------------------------------------------------------------------
435
 */
436
437
static struct storage *
438 116691
objallocwithnuke(struct worker *wrk, const struct stevedore *stv, ssize_t size,
439
    int flags)
440
{
441 116691
        struct storage *st = NULL;
442
443 116691
        CHECK_OBJ_NOTNULL(wrk, WORKER_MAGIC);
444 116691
        CHECK_OBJ_NOTNULL(stv, STEVEDORE_MAGIC);
445
446 116691
        if (size > cache_param->fetch_maxchunksize) {
447 80
                if (!(flags & LESS_MEM_ALLOCED_IS_OK))
448 0
                        return (NULL);
449 80
                size = cache_param->fetch_maxchunksize;
450 80
        }
451
452 116691
        assert(size <= UINT_MAX);       /* field limit in struct storage */
453
454 116691
        do {
455
                /* try to allocate from it */
456 117011
                st = sml_stv_alloc(stv, size, flags);
457 117011
                if (st != NULL)
458 116491
                        break;
459
460
                /* no luck; try to free some space and keep trying */
461 520
                if (stv->lru == NULL)
462 0
                        break;
463 520
        } while (LRU_NukeOne(wrk, stv->lru));
464
465 116691
        CHECK_OBJ_ORNULL(st, STORAGE_MAGIC);
466 116691
        return (st);
467 116691
}
468
469
static int v_matchproto_(objgetspace_f)
470 2319959
sml_getspace(struct worker *wrk, struct objcore *oc, ssize_t *sz,
471
    uint8_t **ptr)
472
{
473
        struct object *o;
474
        struct storage *st;
475
476 2319959
        CHECK_OBJ_NOTNULL(wrk, WORKER_MAGIC);
477 2319959
        CHECK_OBJ_NOTNULL(oc, OBJCORE_MAGIC);
478 2319959
        CHECK_OBJ_NOTNULL(oc->boc, BOC_MAGIC);
479 2319959
        AN(sz);
480 2319959
        AN(ptr);
481 2319959
        if (*sz == 0)
482 2176901
                *sz = cache_param->fetch_chunksize;
483 2319959
        assert(*sz > 0);
484 2319959
        if (oc->boc->transit_buffer > 0)
485 19211
                *sz = vmin_t(ssize_t, *sz, oc->boc->transit_buffer);
486
487 2319959
        o = sml_getobj(wrk, oc);
488 2319959
        CHECK_OBJ_NOTNULL(o, OBJECT_MAGIC);
489 2319959
        CHECK_OBJ_NOTNULL(oc->boc, BOC_MAGIC);
490
491 2319959
        st = VTAILQ_FIRST(&o->list);
492 2319959
        if (st != NULL && st->len < st->space) {
493 2208832
                *sz = st->space - st->len;
494 2208832
                *ptr = st->ptr + st->len;
495 2208832
                assert (*sz > 0);
496 2208832
                return (1);
497
        }
498
499 111127
        st = objallocwithnuke(wrk, oc->stobj->stevedore, *sz,
500
            LESS_MEM_ALLOCED_IS_OK);
501 111127
        if (st == NULL)
502 200
                return (0);
503
504 110927
        CHECK_OBJ_NOTNULL(oc->boc, BOC_MAGIC);
505 110927
        Lck_Lock(&oc->boc->mtx);
506 110927
        VTAILQ_INSERT_HEAD(&o->list, st, list);
507 110927
        Lck_Unlock(&oc->boc->mtx);
508
509 110927
        *sz = st->space - st->len;
510 110927
        assert (*sz > 0);
511 110927
        *ptr = st->ptr + st->len;
512 110927
        return (1);
513 2319959
}
514
515
static void v_matchproto_(objextend_f)
516 2261908
sml_extend(struct worker *wrk, struct objcore *oc, ssize_t l)
517
{
518
        struct object *o;
519
        struct storage *st;
520
521 2261908
        CHECK_OBJ_NOTNULL(wrk, WORKER_MAGIC);
522 2261908
        assert(l > 0);
523
524 2261908
        o = sml_getobj(wrk, oc);
525 2261908
        CHECK_OBJ_NOTNULL(o, OBJECT_MAGIC);
526 2261908
        st = VTAILQ_FIRST(&o->list);
527 2261908
        CHECK_OBJ_NOTNULL(st, STORAGE_MAGIC);
528 2261908
        assert(st->len + l <= st->space);
529 2261908
        st->len += l;
530 2261908
}
531
532
static void v_matchproto_(objtrimstore_f)
533 74801
sml_trimstore(struct worker *wrk, struct objcore *oc)
534
{
535
        const struct stevedore *stv;
536
        struct storage *st, *st1;
537
        struct object *o;
538
539 74801
        CHECK_OBJ_NOTNULL(wrk, WORKER_MAGIC);
540 74801
        CHECK_OBJ_NOTNULL(oc, OBJCORE_MAGIC);
541 74801
        CHECK_OBJ_NOTNULL(oc->boc, BOC_MAGIC);
542
543 74801
        stv = oc->stobj->stevedore;
544 74801
        CHECK_OBJ_NOTNULL(stv, STEVEDORE_MAGIC);
545
546 74801
        if (oc->boc->stevedore_priv != NULL)
547 0
                WRONG("sml_trimstore already called");
548 74801
        oc->boc->stevedore_priv = trim_once;
549
550 74801
        if (stv->sml_free == NULL)
551 0
                return;
552
553 74801
        o = sml_getobj(wrk, oc);
554 74801
        CHECK_OBJ_NOTNULL(o, OBJECT_MAGIC);
555 74801
        st = VTAILQ_FIRST(&o->list);
556
557 74801
        if (st == NULL)
558 0
                return;
559
560 74801
        if (st->len == 0) {
561 320
                Lck_Lock(&oc->boc->mtx);
562 320
                VTAILQ_REMOVE(&o->list, st, list);
563 320
                Lck_Unlock(&oc->boc->mtx);
564
                /* sml_bocdone frees this */
565 320
                oc->boc->stevedore_priv = st;
566 320
                return;
567
        }
568
569 74481
        if (st->space - st->len < 512)
570 66717
                return;
571
572 7764
        st1 = sml_stv_alloc(stv, st->len, 0);
573 7764
        if (st1 == NULL)
574 0
                return;
575 7764
        assert(st1->space >= st->len);
576
577 7764
        memcpy(st1->ptr, st->ptr, st->len);
578 7764
        st1->len = st->len;
579 7764
        Lck_Lock(&oc->boc->mtx);
580 7764
        VTAILQ_REMOVE(&o->list, st, list);
581 7764
        VTAILQ_INSERT_HEAD(&o->list, st1, list);
582 7764
        Lck_Unlock(&oc->boc->mtx);
583
        /* sml_bocdone frees this */
584 7764
        oc->boc->stevedore_priv = st;
585 74801
}
586
587
static void v_matchproto_(objbocdone_f)
588 112758
sml_bocdone(struct worker *wrk, struct objcore *oc, struct boc *boc)
589
{
590
        const struct stevedore *stv;
591
592 112758
        CHECK_OBJ_NOTNULL(wrk, WORKER_MAGIC);
593 112758
        CHECK_OBJ_NOTNULL(oc, OBJCORE_MAGIC);
594 112758
        CHECK_OBJ_NOTNULL(boc, BOC_MAGIC);
595 112758
        stv = oc->stobj->stevedore;
596 112758
        CHECK_OBJ_NOTNULL(stv, STEVEDORE_MAGIC);
597
598 112758
        sml_bocfini(stv, boc);
599
600 112758
        if (stv->lru != NULL) {
601 111198
                if (isnan(wrk->lastused))
602 0
                        wrk->lastused = VTIM_real();
603 111198
                LRU_Add(oc, wrk->lastused);     // approx timestamp is OK
604 111198
        }
605 112758
}
606
607
static const void * v_matchproto_(objgetattr_f)
608 877863
sml_getattr(struct worker *wrk, struct objcore *oc, enum obj_attr attr,
609
   ssize_t *len)
610
{
611
        struct object *o;
612
        ssize_t dummy;
613
614 877863
        CHECK_OBJ_NOTNULL(wrk, WORKER_MAGIC);
615
616 877863
        if (len == NULL)
617 538288
                len = &dummy;
618 877863
        o = sml_getobj(wrk, oc);
619 877863
        CHECK_OBJ_NOTNULL(o, OBJECT_MAGIC);
620
621 877863
        switch (attr) {
622
                /* Fixed size attributes */
623
#define OBJ_FIXATTR(U, l, s)                                            \
624
        case OA_##U:                                                    \
625
                *len = sizeof o->fa_##l;                                \
626
                return (o->fa_##l);
627
#include "tbl/obj_attr.h"
628
629
                /* Variable size attributes */
630
#define OBJ_VARATTR(U, l)                                               \
631
        case OA_##U:                                                    \
632
                if (o->va_##l == NULL)                                  \
633
                        return (NULL);                                  \
634
                *len = o->va_##l##_len;                                 \
635
                return (o->va_##l);
636
#include "tbl/obj_attr.h"
637
638
                /* Auxiliary attributes */
639
#define OBJ_AUXATTR(U, l)                                               \
640
        case OA_##U:                                                    \
641
                if (o->aa_##l == NULL)                                  \
642
                        return (NULL);                                  \
643
                CHECK_OBJ_NOTNULL(o->aa_##l, STORAGE_MAGIC);            \
644
                *len = o->aa_##l->len;                                  \
645
                return (o->aa_##l->ptr);
646
#include "tbl/obj_attr.h"
647
648
        default:
649
                break;
650
        }
651 0
        WRONG("Unsupported OBJ_ATTR");
652 877863
}
653
654
static void * v_matchproto_(objsetattr_f)
655 421077
sml_setattr(struct worker *wrk, struct objcore *oc, enum obj_attr attr,
656
    ssize_t len, const void *ptr)
657
{
658
        struct object *o;
659 421077
        void *retval = NULL;
660
        struct storage *st;
661
662 421077
        CHECK_OBJ_NOTNULL(wrk, WORKER_MAGIC);
663
664 421077
        o = sml_getobj(wrk, oc);
665 421077
        CHECK_OBJ_NOTNULL(o, OBJECT_MAGIC);
666 421077
        st = o->objstore;
667
668 421077
        switch (attr) {
669
                /* Fixed size attributes */
670
#define OBJ_FIXATTR(U, l, s)                                            \
671
        case OA_##U:                                                    \
672
                assert(len == sizeof o->fa_##l);                        \
673
                retval = o->fa_##l;                                     \
674
                break;
675
#include "tbl/obj_attr.h"
676
677
                /* Variable size attributes */
678
#define OBJ_VARATTR(U, l)                                               \
679
        case OA_##U:                                                    \
680
                if (o->va_##l##_len > 0) {                              \
681
                        AN(o->va_##l);                                  \
682
                        assert(len == o->va_##l##_len);                 \
683
                        retval = o->va_##l;                             \
684
                } else if (len > 0) {                                   \
685
                        assert(len <= UINT_MAX);                        \
686
                        assert(st->len + len <= st->space);             \
687
                        o->va_##l = st->ptr + st->len;                  \
688
                        st->len += len;                                 \
689
                        o->va_##l##_len = len;                          \
690
                        retval = o->va_##l;                             \
691
                }                                                       \
692
                break;
693
#include "tbl/obj_attr.h"
694
695
                /* Auxiliary attributes */
696
#define OBJ_AUXATTR(U, l)                                               \
697
        case OA_##U:                                                    \
698
                if (o->aa_##l != NULL) {                                \
699
                        CHECK_OBJ_NOTNULL(o->aa_##l, STORAGE_MAGIC);    \
700
                        assert(len == o->aa_##l->len);                  \
701
                        retval = o->aa_##l->ptr;                        \
702
                        break;                                          \
703
                }                                                       \
704
                if (len == 0)                                           \
705
                        break;                                          \
706
                o->aa_##l = objallocwithnuke(wrk, oc->stobj->stevedore, \
707
                    len, 0);                                            \
708
                if (o->aa_##l == NULL)                                  \
709
                        break;                                          \
710
                CHECK_OBJ_NOTNULL(o->aa_##l, STORAGE_MAGIC);            \
711
                assert(len <= o->aa_##l->space);                        \
712
                o->aa_##l->len = len;                                   \
713
                retval = o->aa_##l->ptr;                                \
714
                break;
715
#include "tbl/obj_attr.h"
716
717
        default:
718 0
                WRONG("Unsupported OBJ_ATTR");
719
                break;
720
        }
721
722 421077
        if (retval != NULL && ptr != NULL)
723 15040
                memcpy(retval, ptr, len);
724 421077
        return (retval);
725
}
726
727
const struct obj_methods SML_methods = {
728
        .objfree        = sml_objfree,
729
        .objiterator    = sml_iterator,
730
        .objgetspace    = sml_getspace,
731
        .objextend      = sml_extend,
732
        .objtrimstore   = sml_trimstore,
733
        .objbocdone     = sml_bocdone,
734
        .objslim        = sml_slim,
735
        .objgetattr     = sml_getattr,
736
        .objsetattr     = sml_setattr,
737
        .objtouch       = LRU_Touch,
738
};
739
740
static void
741 120
sml_panic_st(struct vsb *vsb, const char *hd, const struct storage *st)
742
{
743 240
        VSB_printf(vsb, "%s = %p {priv=%p, ptr=%p, len=%u, space=%u},\n",
744 120
            hd, st, st->priv, st->ptr, st->len, st->space);
745 120
}
746
747
void
748 80
SML_panic(struct vsb *vsb, const struct objcore *oc)
749
{
750
        struct object *o;
751
        struct storage *st;
752
753 80
        VSB_printf(vsb, "Simple = %p,\n", oc->stobj->priv);
754 80
        if (oc->stobj->priv == NULL)
755 0
                return;
756 80
        o = oc->stobj->priv;
757 80
        PAN_CheckMagic(vsb, o, OBJECT_MAGIC);
758 80
        sml_panic_st(vsb, "Obj", o->objstore);
759
760
#define OBJ_FIXATTR(U, l, sz) \
761
        VSB_printf(vsb, "%s = ", #U); \
762
        VSB_quote(vsb, (const void*)o->fa_##l, sz, VSB_QUOTE_HEX); \
763
        VSB_printf(vsb, ",\n");
764
765
#define OBJ_VARATTR(U, l) \
766
        VSB_printf(vsb, "%s = {len=%u, ptr=%p},\n", \
767
            #U, o->va_##l##_len, o->va_##l);
768
769
#define OBJ_AUXATTR(U, l)                                               \
770
        do {                                                            \
771
                if (o->aa_##l != NULL) sml_panic_st(vsb, #U, o->aa_##l);\
772
        } while(0);
773
774
#include "tbl/obj_attr.h"
775
776 120
        VTAILQ_FOREACH(st, &o->list, list) {
777 40
                sml_panic_st(vsb, "Body", st);
778 40
        }
779
}