git: 9front

Download patch

ref: 579ce6fc009abbd96833cee0d1b4d31fe3296a1b
parent: 6acaee180ce451cb0da04ed956fde6e6d9226c39
author: cinap_lenrek <cinap_lenrek@felloff.net>
date: Sat Nov 15 22:21:35 EST 2025

kernel: fix namec() Aunmount semantics for directories

When unmounting a directory from a union, we must not
open it and use the qid from the walk to get the same
qid as was returned by Abind.

This fixes the error one gets when trying to unmound
/mnt/term/dev from /dev, which happens as exportfs
returns a different qid when opend vs walk in its
qid collision scheme.

--- a/sys/src/9/port/chan.c
+++ b/sys/src/9/port/chan.c
@@ -1302,11 +1302,8 @@
 	name = aname;
 
 	/*
-	 * When unmounting, the name parameter must be accessed
-	 * using Aopen in order to get the real chan from
-	 * something like /srv/cs or /fd/0. However when sandboxing,
-	 * unmounting a sharp from a union is a valid operation even
-	 * if the device is blocked.
+	 * When sandboxing, unmounting a sharp from a union is a valid
+	 * operation even if the device is blocked.
 	 */
 	devunmount = 0;
 	if(amode == Aunmount){
@@ -1316,7 +1313,6 @@
 		 */
 		if(name[0] == '#' && utflen(name) == 2)
 			devunmount = 1;
-		amode = Aopen;
 	}
 
 	/*
@@ -1420,6 +1416,14 @@
 		error("cannot exec directory");
 
 	switch(amode){
+	case Aunmount:
+		/*
+		 * When unmounting, the channel must be opend when not a directory
+		 * in order to get the real chan from something like /srv/cs or /fd/0.
+		 */ 
+		if((c->qid.type&QTDIR) == 0)
+			goto Open;
+		/* wet floor */
 	case Abind:
 		/* no need to maintain path - cannot dotdot an Abind */
 		m = nil;
@@ -1472,6 +1476,7 @@
 
 		case Aopen:
 		case Acreate:
+		case Aunmount:
 			/* only save the mount head if it's a multiple element union */
 			if(m != nil) {
 				rlock(&m->lock);
--