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);
--
⑨