[master] b4f9d54 Add a VSL_Check function to check a record pointers validity.

Martin Blix Grydeland martin at varnish-cache.org
Wed May 15 14:46:14 CEST 2013


commit b4f9d54697eb54a0eae60b106eb7962824bcf97a
Author: Martin Blix Grydeland <martin at varnish-software.com>
Date:   Wed May 1 17:32:03 2013 +0200

    Add a VSL_Check function to check a record pointers validity.
    
    Introduce a VSLC_ptr type to represent a record pointer.

diff --git a/bin/varnishtest/vtc_varnish.c b/bin/varnishtest/vtc_varnish.c
index 64b24b8..80f9674 100644
--- a/bin/varnishtest/vtc_varnish.c
+++ b/bin/varnishtest/vtc_varnish.c
@@ -227,12 +227,12 @@ varnishlog_thread(void *priv)
 		} else if (i != 1)
 			break;
 
-		tag = VSL_TAG(c->ptr);
-		vxid = VSL_ID(c->ptr);
-		len = VSL_LEN(c->ptr);
-		type = VSL_CLIENT(c->ptr) ? 'c' : VSL_BACKEND(c->ptr) ?
+		tag = VSL_TAG(c->rec.ptr);
+		vxid = VSL_ID(c->rec.ptr);
+		len = VSL_LEN(c->rec.ptr);
+		type = VSL_CLIENT(c->rec.ptr) ? 'c' : VSL_BACKEND(c->rec.ptr) ?
 		    'b' : '-';
-		data = VSL_CDATA(c->ptr);
+		data = VSL_CDATA(c->rec.ptr);
 		v->vsl_tag_count[tag]++;
 		vtc_log(v->vl, 4, "vsl| %10u %-15s %c %.*s", vxid,
 		    VSL_tags[tag], type, (int)len, data);
diff --git a/include/vapi/vsl.h b/include/vapi/vsl.h
index 023b65f..4bb1d60 100644
--- a/include/vapi/vsl.h
+++ b/include/vapi/vsl.h
@@ -51,8 +51,14 @@
 struct VSL_data;
 struct VSLQ;
 
-struct VSL_cursor {
+struct VSLC_ptr {
 	const uint32_t		*ptr; /* Record pointer */
+	unsigned		priv;
+};
+
+struct VSL_cursor {
+	/* The record this cursor points to */
+	struct VSLC_ptr		rec;
 
 	/* If not -1, the vxid of all records in this set */
 	int32_t			vxid;
@@ -151,6 +157,18 @@ int VSL_ResetCursor(struct VSL_cursor *c);
 	 *    -1: Operation not supported
 	 */
 
+int VSL_Check(const struct VSL_cursor *c, const struct VSLC_ptr *ptr);
+	/*
+	 * Check if the VSLC_ptr structure points to a value that is still
+	 * valid:
+	 *
+	 * Return values:
+	 *    -1: Operation not supported
+	 *     0: Not valid
+	 *     1: Valid - warning level
+	 *     2: Valid
+	 */
+
 int VSL_Next(struct VSL_cursor *c);
 	/*
 	 * Return raw pointer to next VSL record.
diff --git a/include/vapi/vsl_int.h b/include/vapi/vsl_int.h
index c42198a..f65dc9f 100644
--- a/include/vapi/vsl_int.h
+++ b/include/vapi/vsl_int.h
@@ -68,9 +68,9 @@
 struct VSL_head {
 #define VSL_HEAD_MARKER		"VSLHEAD0"	/* Incr. as version# */
 	char			marker[VSM_MARKER_LEN];
-	ssize_t			segments[VSL_SEGMENTS];
-	unsigned		segment;	/* Current varnishd segment */
-	unsigned		seq;		/* Non-zero seq number */
+	volatile ssize_t	segments[VSL_SEGMENTS];
+	volatile unsigned	segment;	/* Current varnishd segment */
+	volatile unsigned	seq;		/* Non-zero seq number */
 	uint32_t		log[];
 };
 
diff --git a/lib/libvarnishapi/vsl.c b/lib/libvarnishapi/vsl.c
index 994d76d..25e1898 100644
--- a/lib/libvarnishapi/vsl.c
+++ b/lib/libvarnishapi/vsl.c
@@ -140,9 +140,9 @@ VSL_Match(struct VSL_data *vsl, const struct VSL_cursor *c)
 	enum VSL_tag_e tag;
 
 	CHECK_OBJ_NOTNULL(vsl, VSL_MAGIC);
-	if (c == NULL || c->ptr == NULL)
+	if (c == NULL || c->rec.ptr == NULL)
 		return (0);
-	tag = VSL_TAG(c->ptr);
+	tag = VSL_TAG(c->rec.ptr);
 	if (tag <= SLT__Bogus || tag >= SLT__Reserved)
 		return (0);
 	if (vbit_test(vsl->vbm_select, tag))
@@ -165,15 +165,16 @@ VSL_PrintVXID(struct VSL_data *vsl, const struct VSL_cursor *c, void *fo)
 	int i;
 
 	CHECK_OBJ_NOTNULL(vsl, VSL_MAGIC);
-	if (c == NULL || c->ptr == NULL)
+	if (c == NULL || c->rec.ptr == NULL)
 		return (0);
 	if (fo == NULL)
 		fo = stdout;
-	tag = VSL_TAG(c->ptr);
-	vxid = VSL_ID(c->ptr);
-	len = VSL_LEN(c->ptr);
-	type = VSL_CLIENT(c->ptr) ? 'c' : VSL_BACKEND(c->ptr) ? 'b' : '-';
-	data = VSL_CDATA(c->ptr);
+	tag = VSL_TAG(c->rec.ptr);
+	vxid = VSL_ID(c->rec.ptr);
+	len = VSL_LEN(c->rec.ptr);
+	type = VSL_CLIENT(c->rec.ptr) ? 'c' : VSL_BACKEND(c->rec.ptr) ?
+	    'b' : '-';
+	data = VSL_CDATA(c->rec.ptr);
 
 	if (tag == SLT_Debug) {
 		i = fprintf(fo, "%10u %-15s %c \"", vxid, VSL_tags[tag], type);
@@ -211,15 +212,16 @@ VSL_PrintLevel(struct VSL_data *vsl, const struct VSL_cursor *c, void *fo)
 	int i;
 
 	CHECK_OBJ_NOTNULL(vsl, VSL_MAGIC);
-	if (c == NULL || c->ptr == NULL)
+	if (c == NULL || c->rec.ptr == NULL)
 		return (0);
 	if (fo == NULL)
 		fo = stdout;
 
-	tag = VSL_TAG(c->ptr);
-	len = VSL_LEN(c->ptr);
-	type = VSL_CLIENT(c->ptr) ? 'c' : VSL_BACKEND(c->ptr) ? 'b' : '-';
-	data = VSL_CDATA(c->ptr);
+	tag = VSL_TAG(c->rec.ptr);
+	len = VSL_LEN(c->rec.ptr);
+	type = VSL_CLIENT(c->rec.ptr) ? 'c' : VSL_BACKEND(c->rec.ptr) ?
+	    'b' : '-';
+	data = VSL_CDATA(c->rec.ptr);
 	lvl = c->level;
 	if (tag == SLT_Debug) {
 		i = fprintf(fo, "%2u %-15s %c \"", lvl, VSL_tags[tag],
diff --git a/lib/libvarnishapi/vsl_api.h b/lib/libvarnishapi/vsl_api.h
index a03aef7..039d57b 100644
--- a/lib/libvarnishapi/vsl_api.h
+++ b/lib/libvarnishapi/vsl_api.h
@@ -35,6 +35,11 @@
 
 #define VSL_FILE_HEAD			"VSL"
 
+struct vslc_shmptr {
+	uint32_t	*ptr;
+	unsigned	priv;
+};
+
 int vsl_diag(struct VSL_data *vsl, const char *fmt, ...)
     __printflike(2, 3);
 int vsl_skip(struct VSL_cursor *c, ssize_t words);
@@ -43,6 +48,8 @@ typedef void vslc_delete_f(void *);
 typedef int vslc_next_f(void *);
 typedef int vslc_reset_f(void *);
 typedef int vslc_skip_f(void *, ssize_t words);
+typedef int vslc_ref_f(void *, struct vslc_shmptr *ptr);
+typedef int vslc_check_f(const void *, const struct VSLC_ptr *ptr);
 
 struct vslc {
 	struct VSL_cursor		c;
@@ -53,6 +60,7 @@ struct vslc {
 	vslc_next_f			*next;
 	vslc_reset_f			*reset;
 	vslc_skip_f			*skip;
+	vslc_check_f			*check;
 };
 
 struct VSL_data {
diff --git a/lib/libvarnishapi/vsl_cursor.c b/lib/libvarnishapi/vsl_cursor.c
index bf4d1ec..1712ade 100644
--- a/lib/libvarnishapi/vsl_cursor.c
+++ b/lib/libvarnishapi/vsl_cursor.c
@@ -55,11 +55,10 @@ struct vslc_vsm {
 	struct VSM_data			*vsm;
 	struct VSM_fantom		vf;
 
-	volatile const struct VSL_head	*head;
-	volatile const uint32_t		*next;
+	const struct VSL_head		*head;
 	const uint32_t			*end;
 	ssize_t				segsize;
-	unsigned			seq;
+	struct VSLC_ptr			next;
 };
 
 static void
@@ -72,74 +71,101 @@ vslc_vsm_delete(void *cursor)
 }
 
 static int
-vslc_vsm_next(void *cursor)
+vslc_vsm_check(const void *cursor, const struct VSLC_ptr *ptr)
 {
-	struct vslc_vsm *c;
-	int diff;
-	unsigned segment;
-	uint32_t t;
+	const struct vslc_vsm *c;
+	unsigned seqdiff, segment, segdiff;
 
 	CAST_OBJ_NOTNULL(c, cursor, VSLC_VSM_MAGIC);
-	CHECK_OBJ_NOTNULL(c->vsm, VSM_MAGIC);
 
-	/* Assert pointers */
-	AN(c->next);
-	assert(c->next >= c->head->log);
-	assert(c->next < c->end);
+	if (ptr->ptr == NULL)
+		return (0);
 
 	/* Check sequence number */
-	diff = c->head->seq - c->seq;
-	if (c->head->seq < c->seq)
+	seqdiff = c->head->seq - ptr->priv;
+	if (c->head->seq < ptr->priv)
 		/* Wrap around skips 0 */
-		diff -= 1;
-	if (diff > 1)
-		return (-3);
+		seqdiff -= 1;
+	if (seqdiff > 1)
+		/* Too late */
+		return (0);
 
 	/* Check overrun */
-	segment = (c->next - c->head->log) / c->segsize;
+	segment = (ptr->ptr - c->head->log) / c->segsize;
 	if (segment >= VSL_SEGMENTS)
+		/* Rounding error spills to last segment */
 		segment = VSL_SEGMENTS - 1;
-	diff = (segment - c->head->segment) % VSL_SEGMENTS;
-	if (0 < diff && diff <= 2)
+	segdiff = (segment - c->head->segment) % VSL_SEGMENTS;
+	if (segdiff == 0 && seqdiff == 0)
+		/* In same segment, but close to tail */
+		return (2);
+	if (segdiff <= 2)
+		/* Too close to continue */
+		return (0);
+	if (segdiff <= 4)
+		/* Warning level */
+		return (1);
+	/* Safe */
+	return (2);
+}
+
+static int
+vslc_vsm_next(void *cursor)
+{
+	struct vslc_vsm *c;
+	int i;
+	uint32_t t;
+
+	CAST_OBJ_NOTNULL(c, cursor, VSLC_VSM_MAGIC);
+	CHECK_OBJ_NOTNULL(c->vsm, VSM_MAGIC);
+
+	/* Assert pointers */
+	AN(c->next.ptr);
+	assert(c->next.ptr >= c->head->log);
+	assert(c->next.ptr < c->end);
+
+	i = vslc_vsm_check(c, &c->next);
+	if (i <= 0)
+		/* Overrun */
 		return (-3);
 
 	/* Check VSL fantom and abandonment */
-	if (*c->next == VSL_ENDMARKER) {
+	if (*(volatile const uint32_t *)c->next.ptr == VSL_ENDMARKER) {
 		if (!VSM_StillValid(c->vsm, &c->vf) ||
 		    VSM_Abandoned(c->vsm))
 			return (-2);
 	}
 
 	while (1) {
-		assert(c->next >= c->head->log);
-		assert(c->next < c->end);
+		assert(c->next.ptr >= c->head->log);
+		assert(c->next.ptr < c->end);
 		AN(c->head->seq);
-		t = *c->next;
+		t = *(volatile const uint32_t *)c->next.ptr;
 		AN(t);
 
 		if (t == VSL_WRAPMARKER) {
 			/* Wrap around not possible at front */
-			assert(c->next != c->head->log);
-			c->next = c->head->log;
+			assert(c->next.ptr != c->head->log);
+			c->next.ptr = c->head->log;
 			continue;
 		}
 
 		if (t == VSL_ENDMARKER) {
-			if (c->next != c->head->log &&
-			    c->seq != c->head->seq) {
+			if (c->next.ptr != c->head->log &&
+			    c->next.priv != c->head->seq) {
 				/* ENDMARKER not at front and seq wrapped */
 				/* XXX: assert on this? */
-				c->next = c->head->log;
+				c->next.ptr = c->head->log;
 				continue;
 			}
 			return (0);
 		}
 
-		if (c->next == c->head->log)
-			c->seq = c->head->seq;
+		if (c->next.ptr == c->head->log)
+			c->next.priv = c->head->seq;
 
-		c->c.c.ptr = (void*)(uintptr_t)c->next; /* Loose volatile */
-		c->next = VSL_NEXT(c->next);
+		c->c.c.rec = c->next;
+		c->next.ptr = VSL_NEXT(c->next.ptr);
 		return (1);
 	}
 }
@@ -162,9 +188,9 @@ vslc_vsm_reset(void *cursor)
 	if (c->head->segments[segment] < 0)
 		segment = 0;
 	assert(c->head->segments[segment] >= 0);
-	c->next = c->head->log + c->head->segments[segment];
-	c->seq = c->head->seq;
-	c->c.c.ptr = NULL;
+	c->next.ptr = c->head->log + c->head->segments[segment];
+	c->next.priv = c->head->seq;
+	c->c.c.rec.ptr = NULL;
 
 	return (0);
 }
@@ -178,10 +204,10 @@ vslc_vsm_skip(void *cursor, ssize_t words)
 	if (words < 0)
 		return (-1);
 
-	c->next += words;
-	assert(c->next >= c->head->log);
-	assert(c->next < c->end);
-	c->c.c.ptr = NULL;
+	c->next.ptr += words;
+	assert(c->next.ptr >= c->head->log);
+	assert(c->next.ptr < c->end);
+	c->c.c.rec.ptr = NULL;
 
 	return (0);
 }
@@ -223,6 +249,7 @@ VSL_CursorVSM(struct VSL_data *vsl, struct VSM_data *vsm, int tail)
 	c->c.next = vslc_vsm_next;
 	c->c.reset = vslc_vsm_reset;
 	c->c.skip = vslc_vsm_skip;
+	c->c.check = vslc_vsm_check;
 
 	c->vsm = vsm;
 	c->vf = vf;
@@ -232,10 +259,12 @@ VSL_CursorVSM(struct VSL_data *vsl, struct VSM_data *vsm, int tail)
 
 	if (tail) {
 		/* Locate tail of log */
-		c->next = c->head->log + c->head->segments[c->head->segment];
-		while (c->next < c->end && *c->next != VSL_ENDMARKER)
-			c->next = VSL_NEXT(c->next);
-		c->seq = c->head->seq;
+		c->next.ptr = c->head->log +
+		    c->head->segments[c->head->segment];
+		while (c->next.ptr < c->end &&
+		    *(volatile const uint32_t *)c->next.ptr != VSL_ENDMARKER)
+			c->next.ptr = VSL_NEXT(c->next.ptr);
+		c->next.priv = c->head->seq;
 	} else
 		AZ(vslc_vsm_reset(&c->c));
 
@@ -293,7 +322,7 @@ vslc_file_next(void *cursor)
 		return (c->error);
 
 	do {
-		c->c.c.ptr = NULL;
+		c->c.c.rec.ptr = NULL;
 		assert(c->buflen >= 2 * 4);
 		i = vslc_file_readn(c->fd, c->buf, 2 * 4);
 		if (i < 0)
@@ -313,8 +342,9 @@ vslc_file_next(void *cursor)
 		if (i == 0)
 			return (-1);	/* EOF */
 		assert(i == l - 2 * 4);
-		c->c.c.ptr = c->buf;
-	} while (c->c.c.ptr != NULL && VSL_TAG(c->c.c.ptr) == SLT__Batch);
+		c->c.c.rec.ptr = c->buf;
+	} while (c->c.c.rec.ptr != NULL &&
+	    VSL_TAG(c->c.c.rec.ptr) == SLT__Batch);
 	return (1);
 }
 
@@ -423,3 +453,14 @@ vsl_skip(struct VSL_cursor *cursor, ssize_t words)
 		return (-1);
 	return ((c->skip)(c, words));
 }
+
+int
+VSL_Check(const struct VSL_cursor *cursor, const struct VSLC_ptr *ptr)
+{
+	const struct vslc *c;
+
+	CAST_OBJ_NOTNULL(c, (const void *)cursor, VSLC_MAGIC);
+	if (c->check == NULL)
+		return (-1);
+	return ((c->check)(c, ptr));
+}
diff --git a/lib/libvarnishapi/vsl_dispatch.c b/lib/libvarnishapi/vsl_dispatch.c
index 61b0518..c5389b9 100644
--- a/lib/libvarnishapi/vsl_dispatch.c
+++ b/lib/libvarnishapi/vsl_dispatch.c
@@ -181,7 +181,7 @@ vslc_raw_next(void *cursor)
 	assert(c->next >= c->start);
 	assert(c->next <= c->start + c->len);
 	if (c->next < c->start + c->len) {
-		c->c.c.ptr = c->next;
+		c->c.c.rec.ptr = c->next;
 		c->next = VSL_NEXT(c->next);
 		return (1);
 	}
@@ -198,7 +198,7 @@ vslc_raw_reset(void *cursor)
 	assert(c->next >= c->start);
 	assert(c->next <= c->start + c->len);
 	c->next = c->start;
-	c->c.c.ptr = NULL;
+	c->c.c.rec.ptr = NULL;
 
 	return (0);
 }
@@ -213,7 +213,7 @@ vslc_vtx_next(void *cursor)
 	assert(c->next >= c->vtx->start);
 	assert(c->next <= c->vtx->start + c->vtx->len);
 	if (c->next < c->vtx->start + c->vtx->len) {
-		c->c.c.ptr = c->next;
+		c->c.c.rec.ptr = c->next;
 		c->next = VSL_NEXT(c->next);
 		return (1);
 	}
@@ -230,7 +230,7 @@ vslc_vtx_reset(void *cursor)
 	assert(c->next >= c->vtx->start);
 	assert(c->next <= c->vtx->start + c->vtx->len);
 	c->next = c->vtx->start;
-	c->c.c.ptr = NULL;
+	c->c.c.rec.ptr = NULL;
 
 	return (0);
 }
@@ -790,13 +790,13 @@ vslq_raw(struct VSLQ *vslq, VSLQ_dispatch_f *func, void *priv)
 		i = VSL_Next(c);
 		if (i <= 0)
 			break;
-		AN(c->ptr);
+		AN(c->rec.ptr);
 		if (func == NULL)
 			continue;
-		rawc.start = c->ptr;
-		rawc.len = VSL_NEXT(c->ptr) - c->ptr;
+		rawc.start = c->rec.ptr;
+		rawc.len = VSL_NEXT(c->rec.ptr) - c->rec.ptr;
 		rawc.next = rawc.start;
-		rawc.c.c.ptr = NULL;
+		rawc.c.c.rec.ptr = NULL;
 
 		/* Query check goes here */
 		i = 0;
@@ -831,13 +831,13 @@ VSLQ_Dispatch(struct VSLQ *vslq, VSLQ_dispatch_f *func, void *priv)
 		i = VSL_Next(c);
 		if (i != 1)
 			break;
-		tag = VSL_TAG(c->ptr);
+		tag = VSL_TAG(c->rec.ptr);
 		if (tag == SLT__Batch) {
-			ptr = VSL_NEXT(c->ptr);
-			len = VSL_WORDS(c->ptr[1]);
+			ptr = VSL_NEXT(c->rec.ptr);
+			len = VSL_WORDS(c->rec.ptr[1]);
 			AZ(vsl_skip(c, len));
 		} else {
-			ptr = c->ptr;
+			ptr = c->rec.ptr;
 			len = VSL_NEXT(ptr) - ptr;
 		}
 		vxid = VSL_ID(ptr);
diff --git a/lib/libvarnishapi/vsl_query.c b/lib/libvarnishapi/vsl_query.c
index b4a403c..852f8d3 100644
--- a/lib/libvarnishapi/vsl_query.c
+++ b/lib/libvarnishapi/vsl_query.c
@@ -104,9 +104,9 @@ vslq_runquery(struct vslq_query *query, struct VSL_cursor *cp[])
 			if (i == 0)
 				break;
 			assert(i == 1);
-			AN(c->ptr);
-			len = VSL_LEN(c->ptr);
-			data = VSL_CDATA(c->ptr);
+			AN(c->rec.ptr);
+			len = VSL_LEN(c->rec.ptr);
+			data = VSL_CDATA(c->rec.ptr);
 			i = VRE_exec(query->regex, data, len, 0, 0, NULL, 0,
 			    NULL);
 			if (i != VRE_ERROR_NOMATCH) {



More information about the varnish-commit mailing list