PERFORCE change 127941 for review

Marko Zec zec at FreeBSD.org
Mon Oct 22 17:15:22 PDT 2007


http://perforce.freebsd.org/chv.cgi?CH=127941

Change 127941 by zec at 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);


More information about the p4-projects mailing list