/*--------------------------------------------------------------------*/
+struct smf {
+ struct storage s;
+ struct smf_sc *sc;
+
+ int alloc;
+ time_t age;
+
+ off_t size;
+ off_t offset;
+ unsigned char *ptr;
+
+ TAILQ_ENTRY(smf) order;
+ TAILQ_ENTRY(smf) status;
+};
+
+TAILQ_HEAD(smfhead, smf);
+
struct smf_sc {
char *filename;
int fd;
+ int pagesize;
uintmax_t filesize;
-};
-
-struct smf {
- struct storage s;
+ struct smfhead order;
+ struct smfhead free;
+ struct smfhead used;
};
/*--------------------------------------------------------------------*/
AZ(fstatfs(sc->fd, &fsst));
/* We use units of the larger of filesystem blocksize and pagesize */
- bs = getpagesize();
+ bs = sc->pagesize;
if (bs < fsst.f_bsize)
bs = fsst.f_bsize;
/* round down to of filesystem blocksize or pagesize */
l -= (l % bs);
- if (l < MINPAGES * getpagesize()) {
+ if (l < MINPAGES * sc->pagesize) {
fprintf(stderr,
"Error: size too small, at least %ju needed\n",
- (uintmax_t)MINPAGES * getpagesize());
+ (uintmax_t)MINPAGES * sc->pagesize);
exit (2);
}
printf("file %s size %ju bytes (%ju fs-blocks, %ju pages)\n",
- sc->filename, l, l / fsst.f_bsize, l / getpagesize());
+ sc->filename, l, l / fsst.f_bsize, l / sc->pagesize);
sc->filesize = l;
}
sc = calloc(sizeof *sc, 1);
assert(sc != NULL);
+ TAILQ_INIT(&sc->order);
+ TAILQ_INIT(&sc->free);
+ TAILQ_INIT(&sc->used);
+ sc->pagesize = getpagesize();
+
parent->priv = sc;
/* If no size specified, use 50% of filesystem free space */
smf_initfile(sc, size, 1);
}
+/*--------------------------------------------------------------------
+ * Allocate a range from the first free range that is large enough.
+ */
+
+static struct smf *
+alloc_smf(struct smf_sc *sc, size_t bytes)
+{
+ struct smf *sp, *sp2;
+
+ bytes += (sc->pagesize - 1);
+ bytes &= ~(sc->pagesize - 1);
+ TAILQ_FOREACH(sp, &sc->free, status) {
+ if (sp->size >= bytes)
+ break;
+ }
+ if (sp == NULL)
+ return (sp);
+
+ if (sp->size == bytes) {
+ TAILQ_REMOVE(&sc->free, sp, status);
+ sp->alloc = 1;
+ TAILQ_INSERT_TAIL(&sc->used, sp, status);
+ printf("ALLOC %12p %12p %12jx %12jx\n", (void*)sp, (void*)sp->ptr, (uintmax_t)sp->offset, (uintmax_t)sp->size);
+ return (sp);
+ }
+
+ /* Split from front */
+ sp2 = malloc(sizeof *sp2);
+ assert(sp2 != NULL);
+ *sp2 = *sp;
+
+ sp->offset += bytes;
+ sp->ptr += bytes;
+ sp->size -= bytes;
+
+ sp2->size = bytes;
+ sp2->alloc = 1;
+ TAILQ_INSERT_BEFORE(sp, sp2, order);
+ TAILQ_INSERT_TAIL(&sc->used, sp2, status);
+ printf("SPLIT %12p %12p %12jx %12jx\n", (void*)sp, (void*)sp->ptr, (uintmax_t)sp->offset, (uintmax_t)sp->size);
+ printf("ALLOC %12p %12p %12jx %12jx\n", (void*)sp2, (void*)sp2->ptr, (uintmax_t)sp2->offset, (uintmax_t)sp2->size);
+ return (sp2);
+}
+
+/*--------------------------------------------------------------------
+ * Free a range. Attemt merge forward and backward, then sort into
+ * free list according to age.
+ */
+
+static void
+free_smf(struct smf *sp)
+{
+ struct smf *sp2;
+ struct smf_sc *sc = sp->sc;
+
+ printf("FREE %12p %12p %12jx %12jx\n", (void*)sp, (void*)sp->ptr, (uintmax_t)sp->offset, (uintmax_t)sp->size);
+ TAILQ_REMOVE(&sc->used, sp, status);
+ sp->alloc = 0;
+
+ sp2 = TAILQ_NEXT(sp, order);
+ if (sp2 != NULL &&
+ sp2->alloc == 0 &&
+ (sp2->ptr == sp->ptr + sp->size) &&
+ (sp2->offset == sp->offset + sp->size)) {
+ sp->size += sp2->size;
+ TAILQ_REMOVE(&sc->order, sp2, order);
+ TAILQ_REMOVE(&sc->free, sp2, status);
+ free(sp2);
+ printf("MERGEN %12p %12p %12jx %12jx\n", (void*)sp, (void*)sp->ptr, (uintmax_t)sp->offset, (uintmax_t)sp->size);
+ }
+
+ sp2 = TAILQ_PREV(sp, smfhead, order);
+ if (sp2 != NULL &&
+ sp2->alloc == 0 &&
+ (sp->ptr == sp2->ptr + sp2->size) &&
+ (sp->offset == sp2->offset + sp2->size)) {
+ sp2->size += sp->size;
+ sp2->age = sp->age;
+ TAILQ_REMOVE(&sc->order, sp, order);
+ free(sp);
+ TAILQ_REMOVE(&sc->free, sp2, status);
+ sp = sp2;
+ printf("MERGEP %12p %12p %12jx %12jx\n", (void*)sp, (void*)sp->ptr, (uintmax_t)sp->offset, (uintmax_t)sp->size);
+ }
+
+ TAILQ_FOREACH(sp2, &sc->free, status) {
+ if (sp->age > sp2->age ||
+ (sp->age == sp2->age && sp->offset < sp2->offset)) {
+ TAILQ_INSERT_BEFORE(sp2, sp, order);
+ break;
+ }
+ }
+ if (sp2 == NULL)
+ TAILQ_INSERT_TAIL(&sc->free, sp, status);
+}
+
+/*--------------------------------------------------------------------
+ * Insert a newly created range as busy, then free it to do any collapses
+ */
+
+static void
+new_smf(struct smf_sc *sc, unsigned char *ptr, off_t off, size_t len)
+{
+ struct smf *sp, *sp2;
+
+ sp = calloc(sizeof *sp, 1);
+ assert(sp != NULL);
+ printf("NEW %12p %12p %12jx %12jx\n", (void*)sp, (void*)ptr, (uintmax_t)off, (uintmax_t)len);
+
+ sp->sc = sc;
+
+ sp->size = len;
+ sp->ptr = ptr;
+ sp->offset = off;
+
+ sp->alloc = 1;
+
+ TAILQ_FOREACH(sp2, &sc->order, order) {
+ if (sp->ptr < sp2->ptr) {
+ TAILQ_INSERT_BEFORE(sp2, sp, order);
+ break;
+ }
+ }
+ if (sp2 == NULL)
+ TAILQ_INSERT_TAIL(&sc->order, sp, order);
+
+ TAILQ_INSERT_HEAD(&sc->used, sp, status);
+
+ free_smf(sp);
+}
+
/*--------------------------------------------------------------------*/
/*
void *p;
off_t h;
- if (*fail < getpagesize() * MINPAGES)
+ if (*fail < sc->pagesize * MINPAGES)
return;
if (sz < *fail && sz < SIZE_T_MAX) {
p = mmap(NULL, sz, PROT_READ|PROT_WRITE,
MAP_NOCORE | MAP_NOSYNC | MAP_PRIVATE, sc->fd, off);
if (p != MAP_FAILED) {
- printf("%12p...%12p %12jx...%12jx %12jx\n",
- p, (u_char *)p + sz,
- off, off + sz, sz);
(*sum) += sz;
+ new_smf(sc, p, off, sz);
return;
}
}
h = sz / 2;
if (h > SIZE_T_MAX)
h = SIZE_T_MAX;
- h -= (h % getpagesize());
+ h -= (h % sc->pagesize);
smf_open_chunk(sc, h, off, fail, sum);
smf_open_chunk(sc, sz - h, off + h, fail, sum);
/*--------------------------------------------------------------------*/
static struct storage *
-smf_alloc(struct stevedore *st __unused, unsigned size)
+smf_alloc(struct stevedore *st, unsigned size)
{
struct smf *smf;
- smf = calloc(sizeof *smf, 1);
+ smf = alloc_smf(st->priv, size);
assert(smf != NULL);
smf->s.priv = smf;
- smf->s.ptr = malloc(size);
- assert(smf->s.ptr != NULL);
+ smf->s.ptr = smf->ptr;
smf->s.len = size;
return (&smf->s);
}
struct smf *smf;
smf = s->priv;
- free(smf->s.ptr);
- free(smf);
+ free_smf(smf);
}
struct stevedore smf_stevedore = {