Commit e4d1d360 authored by Poul-Henning Kamp's avatar Poul-Henning Kamp

Polish round over varnishd part of VSM

parent 356d46a8
...@@ -37,9 +37,7 @@ ...@@ -37,9 +37,7 @@
#include "cache_backend.h" // For w->vbc #include "cache_backend.h" // For w->vbc
#include "vapi/vsm_int.h"
#include "vmb.h" #include "vmb.h"
#include "vtim.h"
/* These cannot be struct lock, which depends on vsm/vsl working */ /* These cannot be struct lock, which depends on vsm/vsl working */
static pthread_mutex_t vsl_mtx; static pthread_mutex_t vsl_mtx;
......
...@@ -75,30 +75,11 @@ void mgt_child_inherit(int fd, const char *what); ...@@ -75,30 +75,11 @@ void mgt_child_inherit(int fd, const char *what);
/* vsm.c */ /* vsm.c */
struct vsm_sc; struct vsm_sc;
struct vsm_sc *VSM_common_new(void *ptr, unsigned len); struct vsm_sc *VSM_common_new(void *ptr, ssize_t len);
void *VSM_common_alloc(struct vsm_sc *sc, unsigned size, void *VSM_common_alloc(struct vsm_sc *sc, ssize_t size,
const char *class, const char *type, const char *ident); const char *class, const char *type, const char *ident);
void VSM_common_free(struct vsm_sc *sc, void *ptr); void VSM_common_free(struct vsm_sc *sc, void *ptr);
void VSM_common_delete(struct vsm_sc *sc); void VSM_common_delete(struct vsm_sc **sc);
// extern struct VSM_head *VSM_head;
// extern const struct VSM_chunk *vsm_end;
/*
* These three should not be called directly, but only through
* proper vectors in mgt.h/cache.h, hence the __
*/
void *VSM__Alloc(unsigned size, const char *class, const char *type,
const char *ident);
void VSM__Free(const void *ptr);
void VSM__Clean(void);
/* These classes are opaque to other programs, so we define the here */
#define VSM_CLASS_FREE "Free"
#define VSM_CLASS_COOL "Cool"
#define VSM_CLASS_PARAM "Params"
#define VSM_CLASS_MARK "MgrCld"
#define VSM_COOL_TIME 5
/*--------------------------------------------------------------------- /*---------------------------------------------------------------------
* Generic power-2 rounding macros * Generic power-2 rounding macros
......
...@@ -27,27 +27,8 @@ ...@@ -27,27 +27,8 @@
* *
* VSM stuff common to manager and child. * VSM stuff common to manager and child.
* *
* We have three potential conflicts we need to deal with: * Please see comments in <vapi/vsm_int.h> for details of protocols and
* * data consistency.
* VSM-studying programs (varnishstat...) vs. everybody else
* The VSM studying programs only have read-only access to the VSM
* so everybody else must use memory barriers, stable storage and
* similar tricks to keep the VSM image in sync (long enough) for
* the studying programs.
* It can not be prevented, and may indeed in some cases be
* desirable for such programs to write to VSM, for instance to
* zero counters.
* Varnishd should never trust the integrity of VSM content.
*
* Manager process vs child process.
* The manager will create a fresh VSM for each child process launch
* and not muck about with VSM while the child runs. If the child
* crashes, the panicstring will be evacuated and the VSM possibly
* saved for debugging, and a new VSM created before the child is
* started again.
*
* Child process threads
* Pthread locking necessary.
* *
*/ */
...@@ -71,8 +52,8 @@ struct vsm_range { ...@@ -71,8 +52,8 @@ struct vsm_range {
unsigned magic; unsigned magic;
#define VSM_RANGE_MAGIC 0x8d30f14 #define VSM_RANGE_MAGIC 0x8d30f14
VTAILQ_ENTRY(vsm_range) list; VTAILQ_ENTRY(vsm_range) list;
unsigned off; ssize_t off;
unsigned len; ssize_t len;
double cool; double cool;
struct VSM_chunk *chunk; struct VSM_chunk *chunk;
void *ptr; void *ptr;
...@@ -82,7 +63,7 @@ struct vsm_sc { ...@@ -82,7 +63,7 @@ struct vsm_sc {
unsigned magic; unsigned magic;
#define VSM_SC_MAGIC 0x8b83270d #define VSM_SC_MAGIC 0x8b83270d
char *b; char *b;
unsigned len; ssize_t len;
struct VSM_head *head; struct VSM_head *head;
VTAILQ_HEAD(,vsm_range) r_used; VTAILQ_HEAD(,vsm_range) r_used;
VTAILQ_HEAD(,vsm_range) r_cooling; VTAILQ_HEAD(,vsm_range) r_cooling;
...@@ -137,7 +118,7 @@ vsm_common_insert_free(struct vsm_sc *sc, struct vsm_range *vr) ...@@ -137,7 +118,7 @@ vsm_common_insert_free(struct vsm_sc *sc, struct vsm_range *vr)
*/ */
struct vsm_sc * struct vsm_sc *
VSM_common_new(void *p, unsigned l) VSM_common_new(void *p, ssize_t l)
{ {
struct vsm_sc *sc; struct vsm_sc *sc;
struct vsm_range *vr; struct vsm_range *vr;
...@@ -154,10 +135,13 @@ VSM_common_new(void *p, unsigned l) ...@@ -154,10 +135,13 @@ VSM_common_new(void *p, unsigned l)
sc->len = l; sc->len = l;
sc->head = (void *)sc->b; sc->head = (void *)sc->b;
memset(TRUST_ME(sc->head), 0, sizeof *sc->head); /* This should not be necessary, but just in case...*/
memset(sc->head, 0, sizeof *sc->head);
sc->head->magic = VSM_HEAD_MAGIC; sc->head->magic = VSM_HEAD_MAGIC;
sc->head->hdrsize = sizeof *sc->head; sc->head->hdrsize = sizeof *sc->head;
sc->head->shm_size = l; sc->head->shm_size = l;
sc->head->alloc_seq = random() | 1;
VWMB();
ALLOC_OBJ(vr, VSM_RANGE_MAGIC); ALLOC_OBJ(vr, VSM_RANGE_MAGIC);
AN(vr); AN(vr);
...@@ -172,7 +156,7 @@ VSM_common_new(void *p, unsigned l) ...@@ -172,7 +156,7 @@ VSM_common_new(void *p, unsigned l)
*/ */
void * void *
VSM_common_alloc(struct vsm_sc *sc, unsigned size, VSM_common_alloc(struct vsm_sc *sc, ssize_t size,
const char *class, const char *type, const char *ident) const char *class, const char *type, const char *ident)
{ {
struct vsm_range *vr, *vr2, *vr3; struct vsm_range *vr, *vr2, *vr3;
...@@ -238,15 +222,15 @@ VSM_common_alloc(struct vsm_sc *sc, unsigned size, ...@@ -238,15 +222,15 @@ VSM_common_alloc(struct vsm_sc *sc, unsigned size,
/* XXX: stats ? */ /* XXX: stats ? */
/* Zero the entire allocation, to avoid garbage confusing readers */ /* Zero the entire allocation, to avoid garbage confusing readers */
memset(TRUST_ME(sc->b + vr->off), 0, vr->len); memset(sc->b + vr->off, 0, vr->len);
vr->chunk = (void *)(sc->b + vr->off); vr->chunk = (void *)(sc->b + vr->off);
vr->ptr = (vr->chunk + 1); vr->ptr = (vr->chunk + 1);
vr->chunk->magic = VSM_CHUNK_MAGIC; vr->chunk->magic = VSM_CHUNK_MAGIC;
strcpy(TRUST_ME(vr->chunk->class), class); strcpy(vr->chunk->class, class);
strcpy(TRUST_ME(vr->chunk->type), type); strcpy(vr->chunk->type, type);
strcpy(TRUST_ME(vr->chunk->ident), ident); strcpy(vr->chunk->ident, ident);
VWMB(); VWMB();
vr3 = VTAILQ_FIRST(&sc->r_used); vr3 = VTAILQ_FIRST(&sc->r_used);
...@@ -258,6 +242,7 @@ VSM_common_alloc(struct vsm_sc *sc, unsigned size, ...@@ -258,6 +242,7 @@ VSM_common_alloc(struct vsm_sc *sc, unsigned size,
} else { } else {
sc->head->first = vr->off; sc->head->first = vr->off;
} }
sc->head->alloc_seq += 2;
VWMB(); VWMB();
return (vr->ptr); return (vr->ptr);
} }
...@@ -289,6 +274,7 @@ VSM_common_free(struct vsm_sc *sc, void *ptr) ...@@ -289,6 +274,7 @@ VSM_common_free(struct vsm_sc *sc, void *ptr)
sc->head->first = vr->chunk->next; sc->head->first = vr->chunk->next;
VWMB(); VWMB();
vr->chunk->len = 0; vr->chunk->len = 0;
sc->head->alloc_seq += 2;
VWMB(); VWMB();
return; return;
} }
...@@ -298,7 +284,7 @@ VSM_common_free(struct vsm_sc *sc, void *ptr) ...@@ -298,7 +284,7 @@ VSM_common_free(struct vsm_sc *sc, void *ptr)
VTAILQ_REMOVE(&sc->r_bogus, vr, list); VTAILQ_REMOVE(&sc->r_bogus, vr, list);
FREE_OBJ(vr); FREE_OBJ(vr);
/* XXX: stats ? */ /* XXX: stats ? */
free(TRUST_ME(ptr)); free(ptr);
return; return;
} }
} }
...@@ -311,9 +297,14 @@ VSM_common_free(struct vsm_sc *sc, void *ptr) ...@@ -311,9 +297,14 @@ VSM_common_free(struct vsm_sc *sc, void *ptr)
*/ */
void void
VSM_common_delete(struct vsm_sc *sc) VSM_common_delete(struct vsm_sc **scp)
{ {
struct vsm_range *vr, *vr2; struct vsm_range *vr, *vr2;
struct vsm_sc *sc;
AN(scp);
sc =*scp;
*scp = NULL;
CHECK_OBJ_NOTNULL(sc, VSM_SC_MAGIC); CHECK_OBJ_NOTNULL(sc, VSM_SC_MAGIC);
VTAILQ_FOREACH_SAFE(vr, &sc->r_free, list, vr2) VTAILQ_FOREACH_SAFE(vr, &sc->r_free, list, vr2)
...@@ -323,9 +314,10 @@ VSM_common_delete(struct vsm_sc *sc) ...@@ -323,9 +314,10 @@ VSM_common_delete(struct vsm_sc *sc)
VTAILQ_FOREACH_SAFE(vr, &sc->r_cooling, list, vr2) VTAILQ_FOREACH_SAFE(vr, &sc->r_cooling, list, vr2)
FREE_OBJ(vr); FREE_OBJ(vr);
VTAILQ_FOREACH_SAFE(vr, &sc->r_bogus, list, vr2) { VTAILQ_FOREACH_SAFE(vr, &sc->r_bogus, list, vr2) {
free(TRUST_ME(vr->ptr)); free(vr->ptr);
FREE_OBJ(vr); FREE_OBJ(vr);
} }
sc->head->magic = 0; sc->head->alloc_seq = 0;
VWMB();
FREE_OBJ(sc); FREE_OBJ(sc);
} }
...@@ -31,6 +31,8 @@ ...@@ -31,6 +31,8 @@
#include "vre.h" #include "vre.h"
#define VSM_CLASS_PARAM "Params"
struct params { struct params {
/* Unprivileged user / group */ /* Unprivileged user / group */
......
...@@ -82,7 +82,6 @@ void mgt_sandbox_solaris_privsep(void); ...@@ -82,7 +82,6 @@ void mgt_sandbox_solaris_privsep(void);
/* mgt_shmem.c */ /* mgt_shmem.c */
void mgt_SHM_Init(void); void mgt_SHM_Init(void);
void mgt_SHM_Pid(void);
/* stevedore_mgt.c */ /* stevedore_mgt.c */
void STV_Config(const char *spec); void STV_Config(const char *spec);
......
...@@ -493,13 +493,13 @@ mgt_cli_secret(const char *S_arg) ...@@ -493,13 +493,13 @@ mgt_cli_secret(const char *S_arg)
{ {
int i, fd; int i, fd;
char buf[BUFSIZ]; char buf[BUFSIZ];
volatile char *p; char *p;
/* Save in shmem */ /* Save in shmem */
i = strlen(S_arg); i = strlen(S_arg);
p = VSM_Alloc(i + 1, "Arg", "-S", ""); p = VSM_Alloc(i + 1L, "Arg", "-S", "");
AN(p); AN(p);
memcpy(TRUST_ME(p), S_arg, i + 1); memcpy(p, S_arg, i + 1L);
srandomdev(); /* XXX: why here ??? */ srandomdev(); /* XXX: why here ??? */
fd = open(S_arg, O_RDONLY); fd = open(S_arg, O_RDONLY);
...@@ -527,7 +527,7 @@ mgt_cli_telnet(const char *T_arg) ...@@ -527,7 +527,7 @@ mgt_cli_telnet(const char *T_arg)
struct vss_addr **ta; struct vss_addr **ta;
int i, n, sock, good; int i, n, sock, good;
struct telnet *tn; struct telnet *tn;
volatile char *p; char *p;
struct vsb *vsb; struct vsb *vsb;
char abuf[VTCP_ADDRBUFSIZE]; char abuf[VTCP_ADDRBUFSIZE];
char pbuf[VTCP_PORTBUFSIZE]; char pbuf[VTCP_PORTBUFSIZE];
...@@ -566,7 +566,7 @@ mgt_cli_telnet(const char *T_arg) ...@@ -566,7 +566,7 @@ mgt_cli_telnet(const char *T_arg)
/* Save in shmem */ /* Save in shmem */
p = VSM_Alloc(VSB_len(vsb) + 1, "Arg", "-T", ""); p = VSM_Alloc(VSB_len(vsb) + 1, "Arg", "-T", "");
AN(p); AN(p);
memcpy(TRUST_ME(p), VSB_data(vsb), VSB_len(vsb) + 1); memcpy(p, VSB_data(vsb), VSB_len(vsb) + 1);
VSB_delete(vsb); VSB_delete(vsb);
} }
......
...@@ -630,8 +630,6 @@ main(int argc, char * const *argv) ...@@ -630,8 +630,6 @@ main(int argc, char * const *argv)
if (!d_flag && !F_flag) if (!d_flag && !F_flag)
AZ(varnish_daemon(1, 0)); AZ(varnish_daemon(1, 0));
mgt_SHM_Pid();
if (pfh != NULL && VPF_Write(pfh)) if (pfh != NULL && VPF_Write(pfh))
fprintf(stderr, "NOTE: Could not write PID file\n"); fprintf(stderr, "NOTE: Could not write PID file\n");
......
...@@ -48,7 +48,6 @@ ...@@ -48,7 +48,6 @@
#include <unistd.h> #include <unistd.h>
#include "mgt/mgt.h" #include "mgt/mgt.h"
#include "common/heritage.h"
#include "common/params.h" #include "common/params.h"
#include "mgt/mgt_param.h" #include "mgt/mgt_param.h"
......
...@@ -53,7 +53,6 @@ ...@@ -53,7 +53,6 @@
#include <unistd.h> #include <unistd.h>
#include "mgt/mgt.h" #include "mgt/mgt.h"
#include "common/heritage.h"
#include "common/params.h" #include "common/params.h"
/*--------------------------------------------------------------------*/ /*--------------------------------------------------------------------*/
......
...@@ -90,7 +90,6 @@ ...@@ -90,7 +90,6 @@
#include <sys/stat.h> #include <sys/stat.h>
#include <fcntl.h> #include <fcntl.h>
#include <signal.h>
#include <stdint.h> #include <stdint.h>
#include <stdio.h> #include <stdio.h>
#include <stdlib.h> #include <stdlib.h>
...@@ -103,7 +102,6 @@ ...@@ -103,7 +102,6 @@
#include "flopen.h" #include "flopen.h"
#include "vapi/vsc_int.h" #include "vapi/vsc_int.h"
#include "vapi/vsl_int.h"
#include "vapi/vsm_int.h" #include "vapi/vsm_int.h"
#include "vmb.h" #include "vmb.h"
...@@ -117,88 +115,96 @@ ...@@ -117,88 +115,96 @@
struct VSC_C_main *VSC_C_main; struct VSC_C_main *VSC_C_main;
static int vsl_fd = -1; static int vsm_fd = -1;
/*-------------------------------------------------------------------- /*--------------------------------------------------------------------
* Check that we are not started with the same -n argument as an already * Check that we are not started with the same -n argument as an already
* running varnishd * running varnishd.
*
* Non-zero return means we should exit and not trample the file.
*
*/ */
static void static int
vsl_n_check(int fd) vsm_n_check(void)
{ {
struct VSM_head slh; int fd, i;
int i;
struct stat st; struct stat st;
pid_t pid; pid_t pid;
struct VSM_head vsmh;
int retval = 2;
AZ(fstat(fd, &st)); fd = open(VSM_FILENAME, O_RDWR, 0644);
if (!S_ISREG(st.st_mode)) if (fd < 0)
ARGV_ERR("\tshmlog: Not a file\n"); return (0);
/* Test if the SHMFILE is locked by other Varnish */ AZ(fstat(fd, &st));
if (fltest(fd, &pid) > 0) { if (!S_ISREG(st.st_mode)) {
fprintf(stderr, fprintf(stderr,
"SHMFILE locked by running varnishd master (pid=%jd)\n", "VSM (%s) not a regular file.\n", VSM_FILENAME);
(intmax_t)pid); } else {
i = fltest(fd, &pid);
if (i < 0) {
fprintf(stderr, fprintf(stderr,
"(Use unique -n arguments if you want multiple " "Cannot determine locking status of VSM (%s)\n.",
"instances)\n"); VSM_FILENAME);
exit(2); } else if (i == 0) {
/*
* File is unlocked, mark it as dead, to help any
* consumers still stuck on it.
*/
if (pread(fd, &vsmh, sizeof vsmh, 0) == sizeof vsmh) {
vsmh.alloc_seq = 0;
(void)pwrite(fd, &vsmh, sizeof vsmh, 0);
} }
retval = 0;
/* Read owning pid from SHMFILE */ } else {
memset(&slh, 0, sizeof slh); /* XXX: for flexelint */ /* The VSM is locked, we won't touch it. */
i = read(fd, &slh, sizeof slh);
if (i != sizeof slh)
return;
if (slh.magic != VSM_HEAD_MAGIC)
return;
if (slh.hdrsize != sizeof slh)
return;
if (slh.master_pid != 0 && !kill(slh.master_pid, 0)) {
fprintf(stderr, fprintf(stderr,
"WARNING: Taking over SHMFILE marked as owned by " "VSM locked by running varnishd master (pid=%jd)\n"
"running process (pid=%jd)\n", "(Use unique -n arguments if you want"
(intmax_t)slh.master_pid); " multiple instances)\n", (intmax_t)pid);
}
} }
(void)close(fd);
return (retval);
} }
/*-------------------------------------------------------------------- /*--------------------------------------------------------------------
* Build a new shmlog file * Build a zeroed file
*/ */
static void static int
vsl_buildnew(const char *fn, ssize_t size) vsm_zerofile(const char *fn, ssize_t size)
{ {
int i; int fd;
unsigned u; ssize_t i, u;
char buf[64*1024]; char buf[64*1024];
int flags; int flags;
(void)unlink(fn); fd = flopen(fn, O_RDWR | O_CREAT | O_EXCL | O_NONBLOCK, 0644);
vsl_fd = flopen(fn, O_RDWR | O_CREAT | O_EXCL | O_NONBLOCK, 0644); if (fd < 0) {
if (vsl_fd < 0) {
fprintf(stderr, "Could not create %s: %s\n", fprintf(stderr, "Could not create %s: %s\n",
fn, strerror(errno)); fn, strerror(errno));
exit (1); return (-1);
} }
flags = fcntl(vsl_fd, F_GETFL); flags = fcntl(fd, F_GETFL);
assert(flags != -1); assert(flags != -1);
flags &= ~O_NONBLOCK; flags &= ~O_NONBLOCK;
AZ(fcntl(vsl_fd, F_SETFL, flags)); AZ(fcntl(fd, F_SETFL, flags));
memset(buf, 0, sizeof buf); memset(buf, 0, sizeof buf);
for (u = 0; u < size; ) { for (u = 0; u < size; ) {
i = write(vsl_fd, buf, sizeof buf); i = write(fd, buf, sizeof buf);
if (i <= 0) { if (i <= 0) {
fprintf(stderr, "Write error %s: %s\n", fprintf(stderr, "Write error %s: %s\n",
fn, strerror(errno)); fn, strerror(errno));
exit (1); return (-1);
} }
u += i; u += i;
} }
AZ(ftruncate(vsl_fd, (off_t)size)); AZ(ftruncate(fd, (off_t)size));
return (fd);
} }
/*-------------------------------------------------------------------- /*--------------------------------------------------------------------
...@@ -209,48 +215,59 @@ static ...@@ -209,48 +215,59 @@ static
void void
mgt_shm_atexit(void) mgt_shm_atexit(void)
{ {
#if 0
if (getpid() == VSM_head->master_pid) if (heritage.vsm != NULL)
VSM_head->master_pid = 0; VSM_common_delete(&heritage.vsm);
#endif
} }
void void
mgt_SHM_Init(void) mgt_SHM_Init(void)
{ {
int i, fill; int i;
uintmax_t size, ps; uintmax_t size, ps;
void *p; void *p;
#if 0 char fnbuf[64];
uint32_t *vsl_log_start;
#endif
fill = 1;
size = mgt_param.vsl_space + mgt_param.vsm_space; size = mgt_param.vsl_space + mgt_param.vsm_space;
ps = getpagesize(); ps = getpagesize();
size += ps - 1; size += ps - 1;
size &= ~(ps - 1); size &= ~(ps - 1);
i = open(VSM_FILENAME, O_RDWR, 0644); /* Collision check with already running varnishd */
if (i >= 0) { i = vsm_n_check();
vsl_n_check(i); if (i)
(void)close(i); exit(i);
}
vsl_buildnew(VSM_FILENAME, size); bprintf(fnbuf, "%s.%jd", VSM_FILENAME, (intmax_t)getpid());
vsm_fd = vsm_zerofile(fnbuf, size);
if (vsm_fd < 0)
exit(1);
p = (void *)mmap(NULL, size, p = (void *)mmap(NULL, size,
PROT_READ|PROT_WRITE, PROT_READ|PROT_WRITE,
MAP_HASSEMAPHORE | MAP_NOSYNC | MAP_SHARED, MAP_HASSEMAPHORE | MAP_NOSYNC | MAP_SHARED,
vsl_fd, 0); vsm_fd, 0);
xxxassert(p != MAP_FAILED);
heritage.vsm = VSM_common_new(p, size); if (p == MAP_FAILED) {
fprintf(stderr, "Mmap error %s: %s\n", fnbuf, strerror(errno));
exit (-1);
}
/* This may or may not work */
(void)mlock(p, size); (void)mlock(p, size);
heritage.vsm = VSM_common_new(p, size);
if (rename(fnbuf, VSM_FILENAME)) {
fprintf(stderr, "Rename failed %s -> %s: %s\n",
fnbuf, VSM_FILENAME, strerror(errno));
(void)unlink(fnbuf);
exit (-1);
}
AZ(atexit(mgt_shm_atexit)); AZ(atexit(mgt_shm_atexit));
/* XXX: We need to zero params if we dealloc/clean/wash */
cache_param = VSM_Alloc(sizeof *cache_param, VSM_CLASS_PARAM, "", ""); cache_param = VSM_Alloc(sizeof *cache_param, VSM_CLASS_PARAM, "", "");
AN(cache_param); AN(cache_param);
*cache_param = mgt_param; *cache_param = mgt_param;
...@@ -258,36 +275,4 @@ mgt_SHM_Init(void) ...@@ -258,36 +275,4 @@ mgt_SHM_Init(void)
PAN_panicstr_len = 64 * 1024; PAN_panicstr_len = 64 * 1024;
PAN_panicstr = VSM_Alloc(PAN_panicstr_len, PAN_CLASS, "", ""); PAN_panicstr = VSM_Alloc(PAN_panicstr_len, PAN_CLASS, "", "");
AN(PAN_panicstr); AN(PAN_panicstr);
#if 0
VSM_head->master_pid = getpid();
memset(&VSM_head->head, 0, sizeof VSM_head->head);
VSM_head->head.magic = VSM_CHUNK_MAGIC;
VSM_head->head.len =
(uint8_t*)(VSM_head) + size - (uint8_t*)&VSM_head->head;
bprintf(VSM_head->head.class, "%s", VSM_CLASS_FREE);
VWMB();
vsm_end = (void*)((uint8_t*)VSM_head + size);
VSC_C_main = VSM_Alloc(sizeof *VSC_C_main,
VSC_CLASS, VSC_TYPE_MAIN, "");
AN(VSC_C_main);
do
VSM_head->alloc_seq = random();
while (VSM_head->alloc_seq == 0);
#endif
}
void
mgt_SHM_Pid(void)
{
#if 0
VSM_head->master_pid = getpid();
#endif
} }
...@@ -32,8 +32,16 @@ ...@@ -32,8 +32,16 @@
#define VAPI_VSM_H_INCLUDED #define VAPI_VSM_H_INCLUDED
struct VSM_head; struct VSM_head;
struct VSM_chunk;
struct VSM_data; struct VSM_data;
struct VSM_fantom {
struct VSM_chunk *chunk;
void *b;
void *e;
uintptr_t priv;
};
/*--------------------------------------------------------------------- /*---------------------------------------------------------------------
* VSM level access functions * VSM level access functions
*/ */
...@@ -46,6 +54,7 @@ struct VSM_data *VSM_New(void); ...@@ -46,6 +54,7 @@ struct VSM_data *VSM_New(void);
* referencing the same or different shared memory files. * referencing the same or different shared memory files.
* Returns: * Returns:
* Pointer to usable VSL_data handle. * Pointer to usable VSL_data handle.
* NULL: malloc failed.
*/ */
typedef void VSM_diag_f(void *priv, const char *fmt, ...); typedef void VSM_diag_f(void *priv, const char *fmt, ...);
...@@ -66,7 +75,7 @@ int VSM_n_Arg(struct VSM_data *vd, const char *n_arg); ...@@ -66,7 +75,7 @@ int VSM_n_Arg(struct VSM_data *vd, const char *n_arg);
* and VSC_Arg() functions. * and VSC_Arg() functions.
* Returns: * Returns:
* 1 on success * 1 on success
* -1 on failure, with diagnostic on stderr. * -1 on failure, with diagnostic.
*/ */
const char *VSM_Name(const struct VSM_data *vd); const char *VSM_Name(const struct VSM_data *vd);
......
...@@ -29,6 +29,67 @@ ...@@ -29,6 +29,67 @@
* Define the layout of the shared memory log segment. * Define the layout of the shared memory log segment.
* *
* NB: THIS IS NOT A PUBLIC API TO VARNISH! * NB: THIS IS NOT A PUBLIC API TO VARNISH!
*
* There is a lot of diplomacy and protocol involved with the VSM segment
* since there is no way to (and no desire to!) lock between the readers
* and the writer.
*
* In particular we want the readers to seamlessly jump from one VSM instance
* to another when the child restarts.
*
* The VSM life-cycle there is:
*
* Manager creates VSM file under temp name
*
* Temp VSM file is initialized such that VSM_head is consistent
* with a non-zero alloc_seq
*
* Manager renames Temp VSM file to correct filename as atomic
* operation.
*
* When manager abandons VSM file, alloc_seq is set to zero, which
* never happens in any other circumstances.
*
* If a manager is started and finds and old abandonned VSM segment
* it will zero the alloc_seq in it, before replacing the file.
*
* Subscribers will have to monitor two things to make sure they have
* the current VSM instance: The alloc_seq field and the inode number
* of the path-name. The former check is by far the cheaper and the
* latter check should only be employed when lack of activity in the
* VSM segment raises suspicion that something has happened.
*
* The allocations ("chunks") in the VSM forms a linked list, starting with
* VSM_head->first, with the first/next fields being byte offsets relative
* to the start of the VSM segment.
*
* The last chunk on the list, has next == 0.
*
* New chunks are appended to the list, no matter where in the VSM
* they happen to be allocated.
*
* Chunk allocation sequence is:
* Find free space
* Zero payload
* Init Chunk header
* Write memory barrier
* update hdr->first or $last->next pointer
* hdr->alloc_seq changes
* Write memory barrier
*
* Chunk contents should be designed so that zero bytes are not mistaken
* for valid contents.
*
* Chunk deallocation sequence is:
* update hdr->first or $prev->next pointer
* Write memory barrier
* this->len = 0
* hdr->alloc_seq changes
* Write memory barrier
*
* The space occupied by the chunk is put on a cooling list and is not
* recycled for at least a minute.
*
*/ */
#ifndef VSM_INT_H_INCLUDED #ifndef VSM_INT_H_INCLUDED
...@@ -36,80 +97,23 @@ ...@@ -36,80 +97,23 @@
#define VSM_FILENAME "_.vsm" #define VSM_FILENAME "_.vsm"
/*
* This structure describes each allocation from the shmlog
*/
struct VSM_chunk { struct VSM_chunk {
#define VSM_CHUNK_MAGIC 0xa15712e5 /* From /dev/random */ #define VSM_CHUNK_MAGIC 0xa15712e5 /* From /dev/random */
unsigned magic; unsigned magic;
unsigned len; /* Incl VSM_chunk */ ssize_t len; /* Incl VSM_chunk */
unsigned next; /* Offset in shmem */ ssize_t next; /* Offset in shmem */
unsigned state; /* XXX remove */
char class[8]; char class[8];
char type[8]; char type[8];
char ident[64]; char ident[64];
}; };
#define VSM_NEXT(sha) ((void*)((uintptr_t)(sha) + (sha)->len))
#define VSM_PTR(sha) ((void*)((uintptr_t)((sha) + 1)))
struct VSM_head { struct VSM_head {
#define VSM_HEAD_MAGIC 0xe75f7e91 /* From /dev/random */ #define VSM_HEAD_MAGIC 0xe75f7e91 /* From /dev/random */
unsigned magic; unsigned magic;
ssize_t hdrsize;
unsigned hdrsize; ssize_t shm_size;
unsigned first; /* Offset, first chunk */ ssize_t first; /* Offset, first chunk */
uint64_t starttime;
int64_t master_pid;
int64_t child_pid;
unsigned shm_size;
unsigned alloc_seq; unsigned alloc_seq;
/* Must be last element */
struct VSM_chunk head;
}; };
/*
* You must include "miniobj.h" and have an assert function to be
* able to use the VSM_ITER() macro.
*/
#ifdef CHECK_OBJ_NOTNULL
extern struct VSM_head *VSM_head;
extern const struct VSM_chunk *vsm_end;
static inline struct VSM_chunk *
vsm_iter_0(void)
{
CHECK_OBJ_NOTNULL(VSM_head, VSM_HEAD_MAGIC);
CHECK_OBJ_NOTNULL(&VSM_head->head, VSM_CHUNK_MAGIC);
return (&VSM_head->head);
}
static inline void
vsm_iter_n(struct VSM_chunk **pp)
{
CHECK_OBJ_NOTNULL(VSM_head, VSM_HEAD_MAGIC);
CHECK_OBJ_NOTNULL(*pp, VSM_CHUNK_MAGIC);
*pp = VSM_NEXT(*pp);
if (*pp >= vsm_end) {
*pp = NULL;
return;
}
CHECK_OBJ_NOTNULL(*pp, VSM_CHUNK_MAGIC);
}
#define VSM_ITER(vd) for ((vd) = vsm_iter_0(); (vd) != NULL; vsm_iter_n(&vd))
#else
#define VSM_ITER(vd) while (YOU_NEED_MINIOBJ_TO_USE_VSM_ITER)
#endif /* CHECK_OBJ_NOTNULL */
#endif /* VSM_INT_H_INCLUDED */ #endif /* VSM_INT_H_INCLUDED */
...@@ -390,7 +390,8 @@ VSL_Open(struct VSM_data *vd, int diag) ...@@ -390,7 +390,8 @@ VSL_Open(struct VSM_data *vd, int diag)
/*--------------------------------------------------------------------*/ /*--------------------------------------------------------------------*/
int VSL_Matched(const struct VSM_data *vd, uint64_t bitmap) int
VSL_Matched(const struct VSM_data *vd, uint64_t bitmap)
{ {
if (vd->vsl->num_matchers > 0) { if (vd->vsl->num_matchers > 0) {
uint64_t t; uint64_t t;
......
...@@ -62,7 +62,8 @@ VSM_New(void) ...@@ -62,7 +62,8 @@ VSM_New(void)
struct VSM_data *vd; struct VSM_data *vd;
ALLOC_OBJ(vd, VSM_MAGIC); ALLOC_OBJ(vd, VSM_MAGIC);
AN(vd); if (vd == NULL)
return (vd);
vd->diag = (VSM_diag_f*)fprintf; vd->diag = (VSM_diag_f*)fprintf;
vd->priv = stderr; vd->priv = stderr;
...@@ -132,15 +133,22 @@ VSM_Delete(struct VSM_data *vd) ...@@ -132,15 +133,22 @@ VSM_Delete(struct VSM_data *vd)
if (vd->vsl != NULL) if (vd->vsl != NULL)
VSL_Delete(vd); VSL_Delete(vd);
free(vd); FREE_OBJ(vd);
} }
/*--------------------------------------------------------------------*/ /*--------------------------------------------------------------------
* The internal VSM open function
*
* Return:
* 0 = sucess
* 1 = failure
*
*/
static int static int
vsm_open(struct VSM_data *vd, int diag) vsm_open(struct VSM_data *vd, int diag)
{ {
int i, j; int i;
struct VSM_head slh; struct VSM_head slh;
CHECK_OBJ_NOTNULL(vd, VSM_MAGIC); CHECK_OBJ_NOTNULL(vd, VSM_MAGIC);
...@@ -155,7 +163,7 @@ vsm_open(struct VSM_data *vd, int diag) ...@@ -155,7 +163,7 @@ vsm_open(struct VSM_data *vd, int diag)
return (1); return (1);
} }
assert(fstat(vd->vsm_fd, &vd->fstat) == 0); AZ(fstat(vd->vsm_fd, &vd->fstat));
if (!S_ISREG(vd->fstat.st_mode)) { if (!S_ISREG(vd->fstat.st_mode)) {
if (diag) if (diag)
vd->diag(vd->priv, "%s is not a regular file\n", vd->diag(vd->priv, "%s is not a regular file\n",
...@@ -174,16 +182,16 @@ vsm_open(struct VSM_data *vd, int diag) ...@@ -174,16 +182,16 @@ vsm_open(struct VSM_data *vd, int diag)
vd->vsm_fd = -1; vd->vsm_fd = -1;
return (1); return (1);
} }
if (slh.magic != VSM_HEAD_MAGIC) { if (slh.magic != VSM_HEAD_MAGIC || slh.alloc_seq == 0) {
if (diag) if (diag)
vd->diag(vd->priv, "Wrong magic number in file %s\n", vd->diag(vd->priv, "Not a ready VSM file %s\n",
vd->fname); vd->fname);
AZ(close(vd->vsm_fd)); AZ(close(vd->vsm_fd));
vd->vsm_fd = -1; vd->vsm_fd = -1;
return (1); return (1);
} }
vd->VSM_head = (void *)mmap(NULL, slh.shm_size, vd->VSM_head = mmap(NULL, slh.shm_size,
PROT_READ, MAP_SHARED|MAP_HASSEMAPHORE, vd->vsm_fd, 0); PROT_READ, MAP_SHARED|MAP_HASSEMAPHORE, vd->vsm_fd, 0);
if (vd->VSM_head == MAP_FAILED) { if (vd->VSM_head == MAP_FAILED) {
if (diag) if (diag)
...@@ -195,20 +203,7 @@ vsm_open(struct VSM_data *vd, int diag) ...@@ -195,20 +203,7 @@ vsm_open(struct VSM_data *vd, int diag)
return (1); return (1);
} }
vd->vsm_end = (uint8_t *)vd->VSM_head + slh.shm_size; vd->vsm_end = (uint8_t *)vd->VSM_head + slh.shm_size;
vd->my_alloc_seq = vd->VSM_head->alloc_seq;
for (j = 0; j < 20 && vd->VSM_head->alloc_seq == 0; j++)
(void)usleep(50000);
if (vd->VSM_head->alloc_seq == 0) {
if (diag)
vd->diag(vd->priv, "File not initialized %s\n",
vd->fname);
assert(0 == munmap((void*)vd->VSM_head, slh.shm_size));
AZ(close(vd->vsm_fd));
vd->vsm_fd = -1;
vd->VSM_head = NULL;
return (1);
}
vd->alloc_seq = vd->VSM_head->alloc_seq;
if (vd->vsl != NULL) if (vd->vsl != NULL)
VSL_Open_CallBack(vd); VSL_Open_CallBack(vd);
...@@ -238,10 +233,10 @@ VSM_Close(struct VSM_data *vd) ...@@ -238,10 +233,10 @@ VSM_Close(struct VSM_data *vd)
CHECK_OBJ_NOTNULL(vd, VSM_MAGIC); CHECK_OBJ_NOTNULL(vd, VSM_MAGIC);
if (vd->VSM_head == NULL) if (vd->VSM_head == NULL)
return; return;
assert(0 == munmap((void*)vd->VSM_head, vd->VSM_head->shm_size)); AZ(munmap((void*)vd->VSM_head, vd->VSM_head->shm_size));
vd->VSM_head = NULL; vd->VSM_head = NULL;
assert(vd->vsm_fd >= 0); assert(vd->vsm_fd >= 0);
assert(0 == close(vd->vsm_fd)); AZ(close(vd->vsm_fd));
vd->vsm_fd = -1; vd->vsm_fd = -1;
} }
...@@ -330,10 +325,10 @@ VSM_iter0(struct VSM_data *vd) ...@@ -330,10 +325,10 @@ VSM_iter0(struct VSM_data *vd)
{ {
CHECK_OBJ_NOTNULL(vd, VSM_MAGIC); CHECK_OBJ_NOTNULL(vd, VSM_MAGIC);
vd->alloc_seq = vd->VSM_head->alloc_seq; vd->my_alloc_seq = vd->VSM_head->alloc_seq;
while (vd->alloc_seq == 0) { while (vd->my_alloc_seq == 0) {
(void)usleep(50000); (void)usleep(50000);
vd->alloc_seq = vd->VSM_head->alloc_seq; vd->my_alloc_seq = vd->VSM_head->alloc_seq;
} }
CHECK_OBJ_NOTNULL(&vd->VSM_head->head, VSM_CHUNK_MAGIC); CHECK_OBJ_NOTNULL(&vd->VSM_head->head, VSM_CHUNK_MAGIC);
return (&vd->VSM_head->head); return (&vd->VSM_head->head);
...@@ -344,7 +339,7 @@ VSM_itern(const struct VSM_data *vd, struct VSM_chunk **pp) ...@@ -344,7 +339,7 @@ VSM_itern(const struct VSM_data *vd, struct VSM_chunk **pp)
{ {
CHECK_OBJ_NOTNULL(vd, VSM_MAGIC); CHECK_OBJ_NOTNULL(vd, VSM_MAGIC);
if (vd->alloc_seq != vd->VSM_head->alloc_seq) { if (vd->my_alloc_seq != vd->VSM_head->alloc_seq) {
*pp = NULL; *pp = NULL;
return; return;
} }
......
...@@ -44,13 +44,12 @@ struct VSM_data { ...@@ -44,13 +44,12 @@ struct VSM_data {
char *n_opt; char *n_opt;
char *fname; char *fname;
struct stat fstat; struct stat fstat;
int vsm_fd; int vsm_fd;
struct VSM_head *VSM_head; struct VSM_head *VSM_head;
void *vsm_end; void *vsm_end;
unsigned alloc_seq; unsigned my_alloc_seq;
/* Stuff relating the stats fields start here */ /* Stuff relating the stats fields start here */
......
Markdown is supported
0% or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment