Skip site navigation (1)Skip section navigation (2)
Date:      Tue, 23 Oct 2007 00:15:20 GMT
From:      Marko Zec <zec@FreeBSD.org>
To:        Perforce Change Reviews <perforce@FreeBSD.org>
Subject:   PERFORCE change 127941 for review
Message-ID:  <200710230015.l9N0FKJd020587@repoman.freebsd.org>

next in thread | raw e-mail | index | archive | help
http://perforce.freebsd.org/chv.cgi?CH=127941

Change 127941 by zec@zec_tpx32 on 2007/10/23 00:14:43

	Replace a flat vimage naming scheme with a hierarchical one.
	
	"default" as a vimage name is deprecated.  "." always
	corresponds to the current vimage.  Naming of direct child
	vimages hasn't changed, however each level in vimage
	hierarchy now has an independent naming scope.  For example,
	a vimage named "x" can have a child named "x", which was
	impossible with the old flat naming model.  Direct addressing
	of vimages deeper in the hierarchy is possible using "." as
	a delimeter, for example "x.x" corresponds to child "x" of
	vimage "x".  It is also possible to instantiate new vimages
	at arbitrary levels bellow current position in the hierarchy,
	for example "vimage -c x.y" would create a vimage "y" as a
	child of "x".  Command "vimage x vimage -c y" would have the
	same effect.

Affected files ...

.. //depot/projects/vimage/src/sys/kern/kern_vimage.c#50 edit

Differences ...

==== //depot/projects/vimage/src/sys/kern/kern_vimage.c#50 (text+ko) ====

@@ -64,7 +64,7 @@
 MALLOC_DEFINE(M_VPROCG, "vprocg", "process group control block");
 MALLOC_DEFINE(M_VCPU, "vcpu", "cpu resource control block");
 
-static struct vimage *vi_alloc(char *, int);
+static struct vimage *vi_alloc(struct vimage *, char *);
 static int vi_destroy(struct vimage *);
 static void vnet_mod_complete_registration(struct vnet_modlink *);
 static int vnet_mod_constructor(struct vnet_modlink *);
@@ -444,6 +444,76 @@
 }
 
 
+static struct vimage *
+vimage_by_name(struct vimage *top, char *name)
+{
+	struct vimage *vip;
+	char *next_name;
+	int namelen;
+
+	next_name = strchr(name, '.');
+	if (next_name != NULL) {
+		namelen = next_name - name;
+		next_name++;
+		if (namelen == 0) {
+			if (strlen(next_name) == 0)
+				return(top);	/* '.' == this vimage */
+			else
+				return(NULL);
+		}
+	} else
+		namelen = strlen(name);
+	if (namelen == 0)
+		return(NULL);
+	LIST_FOREACH(vip, &top->vi_child_head, vi_sibilings)
+		if (strncmp(name, vip->vi_name, namelen) == 0) {
+			if (next_name != NULL)
+				return(vimage_by_name(vip, next_name));
+			else
+				return(vip);
+		}
+	return(NULL);
+}
+
+
+static int
+vimage_relative_name(struct vimage *top, struct vimage *where,
+    char *buffer, int bufflen)
+{
+	if (where == top) {
+		sprintf(buffer, ".");
+		return(1);
+	}
+
+	if (where->vi_parent != top) {
+		int len;
+
+		len  = vimage_relative_name(top, where->vi_parent,
+		    buffer, bufflen);
+		bufflen -= (len + 1);
+		buffer += len;
+		sprintf(buffer++, ".");
+	}
+
+	sprintf(buffer, "%s", where->vi_name);
+	return(strlen(where->vi_name));
+}
+
+
+static struct vimage *
+vimage_get_next(struct vimage *top, struct vimage *where)
+{
+	do {
+		where = LIST_NEXT(where, vi_le);
+		if (where == NULL)
+			where = LIST_FIRST(&vimage_head);
+		if (vi_child_of(top, where))
+			return(where);
+	} while (where != top);
+	return(NULL);
+}
+
+
 int
 vi_td_ioctl(cmd, vi_req, td)
 	u_long cmd;
@@ -453,44 +523,23 @@
 	int error;
 	struct vimage *vip = TD_TO_VIMAGE(td);
 	struct vimage *vip_r = NULL;
-	struct vimage *tvip;
 
 	error = suser(td); /* XXX replace with priv(9) */
 	if (error)
 		return (error);
 
-	VNET_LIST_LOCK(); /* XXX should lock vimage list... */
-	if (strlen(vi_req->vi_name)) {
-		LIST_FOREACH(tvip, &vimage_head, vi_le)
-			if (strcmp(vi_req->vi_name, tvip->vi_name)==0) {
-				vip_r = tvip;
-				break;
-			}
-		if (vip_r == NULL && !(vi_req->req_action & VI_CREATE)) {
-			VNET_LIST_UNLOCK(); /* XXX */
+	vip_r = vimage_by_name(vip, vi_req->vi_name);
+	if (vip_r == NULL && !(vi_req->req_action & VI_CREATE))
+		return (ESRCH);
+	if (vip_r != NULL && vi_req->req_action & VI_CREATE)
+		return (EADDRINUSE);
+	if (vi_req->req_action == VI_GETNEXT) {
+		vip_r = vimage_get_next(vip, vip_r);
+		if (vip_r == NULL)
 			return (ESRCH);
-		}
-		if (vip_r != NULL && vi_req->req_action & VI_CREATE) {
-			VNET_LIST_UNLOCK(); /* XXX */
-			return (EADDRINUSE);
-		}
-		if (vi_req->req_action == VI_GETNEXT) {
-vi_getnext_loop:
-			if ((vip_r = LIST_NEXT(vip_r, vi_le)) == 0)
-				vip_r = LIST_FIRST(&vimage_head);
-			if (vip_r == vip) {
-				VNET_LIST_UNLOCK(); /* XXX */
-				return (ESRCH);
-			}
-			if (!vi_child_of(vip, vip_r))
-				goto vi_getnext_loop;
-		}
+	}
 
-	} else
-		vip_r = vip;
-	VNET_LIST_UNLOCK(); /* XXX */
-
-	if (vip_r && !vi_child_of(vip, vip_r) &&
+	if (vip_r && !vi_child_of(vip, vip_r) && /* XXX delete the rest! */
 	    vi_req->req_action != VI_GET && vi_req->req_action != VI_GETNEXT)
 		return (EPERM);
 
@@ -498,7 +547,7 @@
 
 	case SIOCGPVIMAGE:
 		vi_req->vi_id = vip_r->vi_id;
-		bcopy(&vip_r->vi_name, &vi_req->vi_name,
+		vimage_relative_name(vip, vip_r, vi_req->vi_name,
 		    sizeof (vi_req->vi_name));
 		bcopy(&vip_r->v_procg->_averunnable, &vi_req->averunnable,
 		    sizeof (vi_req->averunnable));
@@ -520,7 +569,6 @@
 
 			/*
 			 * XXX priv_check()?
-			 * XXX refcounting ucred -> vimage ?
 			 * XXX allow only a single td per proc here?
 			 */
 			newcred = crget();
@@ -545,14 +593,23 @@
 		}
 
 		if (vi_req->req_action & VI_CREATE) {
-			vip_r = vi_alloc(vi_req->vi_name,
-			    vi_req->vi_maxsockets);
+			char *dotpos;
+
+			dotpos = strrchr(vi_req->vi_name, '.');
+			if (dotpos != NULL) {
+				*dotpos = 0;
+				vip = vimage_by_name(vip, vi_req->vi_name);
+				if (vip == NULL)
+					return (ESRCH);
+				dotpos++;
+				vip_r = vi_alloc(vip, dotpos);
+			} else
+				vip_r = vi_alloc(vip, vi_req->vi_name);
 			if (vip_r == NULL)
 				return (ENOMEM);
-
-			vip_r->vi_parent = vip;
 		}
 
+		/* XXX What the hell is this doing here? */
 		if (vip == vip_r && !IS_DEFAULT_VIMAGE(vip))
 			return (EPERM);
 	}
@@ -591,7 +648,7 @@
 
 
 struct vimage *
-vi_alloc(char *name, int maxsock)
+vi_alloc(struct vimage *parent, char *name)
 {
 	struct vimage *vip;
 	struct vnet *vnet;
@@ -613,6 +670,15 @@
 	if (vip == NULL)
 		panic("vi_alloc: malloc failed for vimage \"%s\"\n", name);
 	vip->vi_id = last_vi_id++;
+	LIST_INIT(&vip->vi_child_head);
+	sprintf(vip->vi_name, "%s", name);
+	vip->vi_parent = parent;
+	/* XXX locking */
+	if (parent != NULL)
+		LIST_INSERT_HEAD(&parent->vi_child_head, vip, vi_sibilings);
+	else if (!LIST_EMPTY(&vimage_head))
+		panic("there can be only one default vimage!");
+	LIST_INSERT_HEAD(&vimage_head, vip, vi_le);
 
 	vnet = vi_malloc(sizeof(struct vnet), M_VNET, M_NOWAIT | M_ZERO);
 	if (vnet == NULL)
@@ -633,9 +699,6 @@
 	vip->v_cpu = vcpu;
 	vcpu->vcpu_id = last_vcpu_id++;
 
-	/* Struct vimage initialization */
-	sprintf(vip->vi_name, "%s", name);
-
 	/* Struct vprocg initialization - perhaps move to anther place? */
 	V_averunnable.fscale = FSCALE;
 
@@ -656,9 +719,6 @@
 	LIST_INSERT_HEAD(&vcpu_head, vcpu, vcpu_le);
 	mtx_unlock_spin(&vcpu_list_mtx);
 
-	/* XXX locking */
-	LIST_INSERT_HEAD(&vimage_head, vip, vi_le);
-
 vi_alloc_done:
 	return (vip);
 }
@@ -679,6 +739,9 @@
 	struct vnet_modlink *vml;
 
 	/* XXX Beware of races -> more locking to be done... */
+	if (!LIST_EMPTY(&vip->vi_child_head))
+		return (EBUSY);
+
 	if (vprocg->nprocs != 0)
 		return (EBUSY);
 
@@ -689,6 +752,18 @@
 		printf("vi_destroy: %s ucredrefc %d\n",
 		    vip->vi_name, vip->vi_ucredrefc);
 
+	/* Point with no return - cleanup MUST succeed! */
+	/* XXX locking */
+	LIST_REMOVE(vip, vi_le);
+	LIST_REMOVE(vip, vi_sibilings);
+
+	/* XXX locking */
+	LIST_REMOVE(vprocg, vprocg_le);
+
+	mtx_lock_spin(&vcpu_list_mtx);
+	LIST_REMOVE(vcpu, vcpu_le);
+	mtx_unlock_spin(&vcpu_list_mtx);
+
 	VNET_LIST_LOCK();
 	LIST_REMOVE(vnet, vnet_le);
 	VNET_LIST_UNLOCK();
@@ -720,19 +795,10 @@
 	CURVNET_RESTORE();
 
 	/* hopefully, we are finally OK to free the vnet container itself! */
-	vnet->vnet_magic_n = -1;
+	vnet->vnet_magic_n = 0xdeadbeef;
 	vi_free(vnet, M_VNET);
-
-	/* XXX lock those bellow... */
-	LIST_REMOVE(vprocg, vprocg_le);
 	vi_free(vprocg, M_VPROCG);
-
-	mtx_lock_spin(&vcpu_list_mtx);
-	LIST_REMOVE(vcpu, vcpu_le);
-	mtx_unlock_spin(&vcpu_list_mtx);
 	vi_free(vcpu, M_VCPU);
-
-	LIST_REMOVE(vip, vi_le);
 	vi_free(vip, M_VIMAGE);
 
 	return (0);
@@ -830,7 +896,7 @@
 
 	mtx_init(&vcpu_list_mtx, "vcpu_list_mtx", NULL, MTX_SPIN);
 
-	vi_alloc("default", 0);
+	vi_alloc(NULL, "");	/* Default vimage has no name */
 
 	/* We MUST clear curvnet in vi_init_done before going SMP. */
 	curvnet = LIST_FIRST(&vnet_head);



Want to link to this message? Use this URL: <https://mail-archive.FreeBSD.org/cgi/mid.cgi?200710230015.l9N0FKJd020587>