git: plan9front

Download patch

ref: 085bc82e05255be82f47000b850235afaae64d9e
parent: 7e1d4d0c4c7c4942bd3e399903c42a2344ad1687
author: cinap_lenrek <cinap_lenrek@felloff.net>
date: Sun Jul 6 08:41:34 EDT 2025

kernel: avoid smalloc() for process groups

Make new*grp() / dup*grp() functions error() instead
of waiting for memory to become available.

This means rfork() will now return error when the
system is out of memory instead of hanging and
waiting until resources become available.

--- a/sys/src/9/port/chan.c
+++ b/sys/src/9/port/chan.c
@@ -609,7 +609,9 @@
 {
 	Mhead *mh;
 
-	mh = smalloc(sizeof(Mhead));
+	mh = malloc(sizeof(Mhead));
+	if(mh == nil)
+		error(Enomem);
 	mh->ref = 1;
 	mh->from = from;
 	incref(from);
@@ -714,6 +716,11 @@
 
 	pg = up->pgrp;
 	wlock(&pg->ns);
+	if(waserror()){
+		wunlock(&pg->ns);
+		mountfree(nm);
+		nexterror();
+	}
 	l = &MOUNTH(pg, old->qid);
 	for(m = *l; m != nil; m = m->hash){
 		if(eqchan(m->from, old, 1))
@@ -730,8 +737,14 @@
 		 *  if this is a union mount, add the old
 		 *  node to the mount chain.
 		 */
-		if(order != MREPL)
+		if(order != MREPL){
+			if(waserror()){
+				putmhead(m);
+				nexterror();
+			}
 			m->mount = newmount(old, 0, nil);
+			poperror();
+		}
 		*l = m;
 	}
 	wlock(&m->lock);
@@ -752,6 +765,7 @@
 	}
 	wunlock(&m->lock);
 	wunlock(&pg->ns);
+	poperror();
 
 	mountfree(um);
 
--- a/sys/src/9/port/devenv.c
+++ b/sys/src/9/port/devenv.c
@@ -395,6 +395,18 @@
 	devwstat,
 };
 
+Egrp*
+newegrp(void)
+{
+	Egrp *eg;
+
+	eg = malloc(sizeof(Egrp));
+	if(eg == nil)
+		error(Enomem);
+	eg->ref = 1;
+	return eg;
+}
+
 void
 envcpy(Egrp *to, Egrp *from)
 {
--- a/sys/src/9/port/pgrp.c
+++ b/sys/src/9/port/pgrp.c
@@ -27,7 +27,9 @@
 {
 	Pgrp *p;
 
-	p = smalloc(sizeof(Pgrp));
+	p = malloc(sizeof(Pgrp));
+	if(p == nil)
+		error(Enomem);
 	p->ref = 1;
 	return p;
 }
@@ -37,7 +39,9 @@
 {
 	Rgrp *r;
 
-	r = smalloc(sizeof(Rgrp));
+	r = malloc(sizeof(Rgrp));
+	if(r == nil)
+		error(Enomem);
 	r->ref = 1;
 	return r;
 }
@@ -102,17 +106,28 @@
 
 	wlock(&to->ns);
 	rlock(&from->ns);
+	if(waserror()){
+		runlock(&from->ns);
+		wunlock(&to->ns);
+		nexterror();
+	}
 	order = nil;
 	for(i = 0; i < MNTHASH; i++) {
 		l = &to->mnthash[i];
 		for(f = from->mnthash[i]; f != nil; f = f->hash) {
 			rlock(&f->lock);
+			if(waserror()){
+				runlock(&f->lock);
+				nexterror();
+			}
 			mh = newmhead(f->from);
 			*l = mh;
 			l = &mh->hash;
 			link = &mh->mount;
 			for(m = f->mount; m != nil; m = m->next) {
-				n = smalloc(sizeof(Mount));
+				n = malloc(sizeof(Mount));
+				if(n == nil)
+					error(Enomem);
 				n->mountid = m->mountid;
 				n->mflag = m->mflag;
 				n->to = m->to;
@@ -124,6 +139,7 @@
 				link = &n->next;
 			}
 			runlock(&f->lock);
+			poperror();
 		}
 	}
 	/*
@@ -133,6 +149,7 @@
 		m->mountid = nextmount();
 	runlock(&from->ns);
 	wunlock(&to->ns);
+	poperror();
 }
 
 Fgrp*
@@ -142,12 +159,20 @@
 	Chan *c;
 	int i;
 
-	new = smalloc(sizeof(Fgrp));
+	new = malloc(sizeof(Fgrp));
+	if(new == nil)
+		error(Enomem);
+	new->ref = 1;
 	if(f == nil){
-		new->flag = smalloc(DELTAFD*sizeof(new->flag[0]));
-		new->fd = smalloc(DELTAFD*sizeof(new->fd[0]));
 		new->nfd = DELTAFD;
-		new->ref = 1;
+		new->fd = malloc(DELTAFD*sizeof(new->fd[0]));
+		new->flag = malloc(DELTAFD*sizeof(new->flag[0]));
+		if(new->fd == nil || new->flag == nil){
+			free(new->flag);
+			free(new->fd);
+			free(new);
+			error(Enomem);
+		}
 		return new;
 	}
 
@@ -158,26 +183,20 @@
 	if(i != 0)
 		new->nfd += DELTAFD - i;
 	new->fd = malloc(new->nfd*sizeof(new->fd[0]));
-	if(new->fd == nil){
-		unlock(f);
-		free(new);
-		error("no memory for fgrp");
-	}
 	new->flag = malloc(new->nfd*sizeof(new->flag[0]));
-	if(new->flag == nil){
+	if(new->fd == nil || new->flag == nil){
 		unlock(f);
+		free(new->flag);
 		free(new->fd);
 		free(new);
-		error("no memory for fgrp");
+		error(Enomem);
 	}
-	new->ref = 1;
-
 	new->maxfd = f->maxfd;
 	for(i = 0; i <= f->maxfd; i++) {
 		if((c = f->fd[i]) != nil){
-			incref(c);
 			new->fd[i] = c;
 			new->flag[i] = f->flag[i];
+			incref(c);
 		}
 	}
 	unlock(f);
@@ -206,8 +225,8 @@
 		}
 	up->closingfgrp = nil;
 
-	free(f->fd);
 	free(f->flag);
+	free(f->fd);
 	free(f);
 }
 
@@ -247,7 +266,9 @@
 {
 	Mount *m;
 
-	m = smalloc(sizeof(Mount));
+	m = malloc(sizeof(Mount));
+	if(m == nil)
+		error(Enomem);
 	m->to = to;
 	incref(to);
 	m->mountid = nextmount();
--- a/sys/src/9/port/portfns.h
+++ b/sys/src/9/port/portfns.h
@@ -214,6 +214,7 @@
 _Noreturn void	namelenerror(char*, int, char*);
 int		needpages(void*);
 Chan*		newchan(void);
+Egrp*		newegrp(void);
 int		newfd(Chan*, int);
 Mhead*		newmhead(Chan*);
 Mount*		newmount(Chan*, int, char*);
--- a/sys/src/9/port/sysfile.c
+++ b/sys/src/9/port/sysfile.c
@@ -45,14 +45,13 @@
 	oldfd = f->fd;
 	oldflag = f->flag;
 	newfd = malloc((nfd+DELTAFD)*sizeof(newfd[0]));
-	if(newfd == nil)
-		goto Exhausted;
-	memmove(newfd, oldfd, nfd*sizeof(newfd[0]));
 	newflag = malloc((nfd+DELTAFD)*sizeof(newflag[0]));
-	if(newflag == nil){
+	if(newfd == nil || newflag == nil){
+		free(newflag);
 		free(newfd);
 		goto Exhausted;
 	}
+	memmove(newfd, oldfd, nfd*sizeof(newfd[0]));
 	memmove(newflag, oldflag, nfd*sizeof(newflag[0]));
 	f->fd = newfd;
 	f->flag = newflag;
--- a/sys/src/9/port/sysproc.c
+++ b/sys/src/9/port/sysproc.c
@@ -26,14 +26,15 @@
 uintptr
 sysrfork(va_list list)
 {
-	Proc *p;
-	int n, i;
-	Fgrp *ofg;
-	Pgrp *opg;
-	Rgrp *org;
-	Egrp *oeg;
+	/*
+	 * Code using RFNOMNT expects to block all but
+	 * the following devices.
+	 */
+	static char nomntdevs[] = "|decp";
+
 	ulong pid, flag;
-	char *devs;
+	int n, i;
+	Proc *p;
 
 	flag = va_arg(list, ulong);
 	/* Check flags before we commit */
@@ -44,46 +45,82 @@
 	if((flag & (RFENVG|RFCENVG)) == (RFENVG|RFCENVG))
 		error(Ebadarg);
 
-	/*
-	 * Code using RFNOMNT expects to block all but
-	 * the following devices.
-	 */
-	devs = "|decp";
 	if((flag&RFPROC) == 0) {
+		Fgrp *ofg;
+		Pgrp *opg;
+		Rgrp *org;
+		Egrp *oeg;
+
 		if(flag & (RFMEM|RFNOWAIT))
 			error(Ebadarg);
+
+		ofg = up->fgrp;
+		opg = up->pgrp;
+		org = up->rgrp;
+		oeg = up->egrp;
+
+		if(waserror()){
+			if(up->fgrp != ofg){
+				closefgrp(up->fgrp);
+				up->fgrp = ofg;
+			}
+			if(up->pgrp != opg){
+				closepgrp(up->pgrp);
+				up->pgrp = opg;
+			}
+			if(up->rgrp != org){
+				closergrp(up->rgrp);
+				up->rgrp = org;
+			}
+			if(up->egrp != oeg){
+				closeegrp(up->egrp);
+				up->egrp = oeg;
+			}
+			nexterror();
+		}
+
+		/* File descriptors */
 		if(flag & (RFFDG|RFCFDG)) {
-			ofg = up->fgrp;
 			if(flag & RFFDG)
 				up->fgrp = dupfgrp(ofg);
 			else
 				up->fgrp = dupfgrp(nil);
-			closefgrp(ofg);
 		}
+
+		/* Process group */
 		if(flag & (RFNAMEG|RFCNAMEG)) {
-			opg = up->pgrp;
 			up->pgrp = newpgrp();
 			if(flag & RFNAMEG)
 				pgrpcpy(up->pgrp, opg);
 			/* inherit notallowed */
 			memmove(up->pgrp->notallowed, opg->notallowed, sizeof up->pgrp->notallowed);
-			closepgrp(opg);
 		}
-		if(flag & RFNOMNT)
-			devmask(up->pgrp, 1, devs);
-		if(flag & RFREND) {
-			org = up->rgrp;
+
+		/* Rendezvous group */
+		if(flag & RFREND)
 			up->rgrp = newrgrp();
-			closergrp(org);
-		}
+
+		/* Environment group */
 		if(flag & (RFENVG|RFCENVG)) {
-			oeg = up->egrp;
-			up->egrp = smalloc(sizeof(Egrp));
-			up->egrp->ref = 1;
+			up->egrp = newegrp();
 			if(flag & RFENVG)
 				envcpy(up->egrp, oeg);
-			closeegrp(oeg);
 		}
+
+		if(ofg != up->fgrp)
+			closefgrp(ofg);
+		if(opg != up->pgrp)
+			closepgrp(opg);
+		if(org != up->rgrp)
+			closergrp(org);
+		if(oeg != up->egrp)
+			closeegrp(oeg);
+
+		poperror();
+
+		if(flag & RFNOMNT)
+			devmask(up->pgrp, 1, nomntdevs);
+
 		if(flag & RFNOTEG){
 			qlock(&up->debug);
 			setnoteid(up, 0);	/* can't error() with 0 argument */
@@ -174,7 +211,7 @@
 	}
 	else {
 		p->fgrp = up->fgrp;
-		incref(p->fgrp);
+		incref(up->fgrp);
 	}
 
 	/* Process groups */
@@ -187,33 +224,34 @@
 	}
 	else {
 		p->pgrp = up->pgrp;
-		incref(p->pgrp);
+		incref(up->pgrp);
 	}
-	if(flag & RFNOMNT)
-		devmask(p->pgrp, 1, devs);
 
+	/* Rendezvous group */
 	if(flag & RFREND)
 		p->rgrp = newrgrp();
 	else {
-		incref(up->rgrp);
 		p->rgrp = up->rgrp;
+		incref(up->rgrp);
 	}
 
 	/* Environment group */
 	if(flag & (RFENVG|RFCENVG)) {
-		p->egrp = smalloc(sizeof(Egrp));
-		p->egrp->ref = 1;
+		p->egrp = newegrp();
 		if(flag & RFENVG)
 			envcpy(p->egrp, up->egrp);
 	}
 	else {
 		p->egrp = up->egrp;
-		incref(p->egrp);
+		incref(up->egrp);
 	}
 
 	procfork(p);
 
 	poperror();	/* abortion */
+
+	if(flag & RFNOMNT)
+		devmask(p->pgrp, 1, nomntdevs);
 
 	if((flag&RFNOWAIT) == 0){
 		p->parent = up;
--