From mboxrd@z Thu Jan 1 00:00:00 1970 To: 9fans@cse.psu.edu Subject: Re: [9fans] namespace oddness From: "Russ Cox" Date: Mon, 19 Nov 2007 09:53:09 -0500 In-Reply-To: MIME-Version: 1.0 Content-Type: text/plain; charset="US-ASCII" Content-Transfer-Encoding: 7bit Message-Id: <20071119145319.46D7E1E8C22@holo.morphisms.net> Topicbox-Message-UUID: 013e9f7c-ead3-11e9-9d60-3106f5b1d025 > what's going on here? the bind of an empty directory onto > /net seems to disrupt the mount table somehow. > i can't think of an existing feature of the namespace > implementation that would explain this behaviour. > is something ignoring the device number, maybe? > > does anyone else get the same behaviour? > > % bind /net /net.alt > % mkdir /tmp/empty > % bind /tmp/empty /net > % cd /net.alt/tcp > Can't cd /net.alt/tcp: '/net.alt/tcp' file does not exist > cpu% ls -l /net.alt/tcp > ls: /net.alt/tcp: '/net.alt/tcp' file does not exist > % cd /net.alt > % cd tcp > % ls -l > --rw-rw-rw- I 0 network bootes 0 Jun 28 12:36 clone > --r--r--r-- I 0 network bootes 0 Jun 28 12:36 stats > % It has nothing to do with device numbers, since you can produce the same situation with directories on a single file server: cpu% for(i in d1 d2 d3 d4) mkdir $i && echo >$i/this_is_$i cpu% bind d2 d3 cpu% bind d1 d2 cpu% ls d1 d1/this_is_d1 cpu% ls d2 d2/this_is_d1 cpu% ls d3 d3/this_is_d2 cpu% ls d3/this_is_d2 ls: d3/this_is_d2: 'd3/this_is_d2' file does not exist cpu% ls d3/this_is_d1 d3/this_is_d1 cpu% The name space is a mapping from old files to new files. After "bind d2 d3" and "bind d1 d2", the name space looks like d3 -> d2 d2 -> d1 Only one name space rule is used, so d3 translates to d2, even though d2 translates to d1. That is, the rules are not applied repeatedly or recursively. And in the example above, opening d3 for read (as in "ls d3") does behave correctly, but evaluating the path "d3/this_is_d2" apparently translates d3 repeatedly, getting d1 instead of d2. That's the problem. In fact, path evaluation applies the rules exactly twice: cpu% bind d3 d4 cpu% bind d2 d3 cpu% bind d1 d2 # Now the name space looks like: # # d4 -> d3 # d3 -> d2 # d2 -> d1 cpu% ls d1 d1/this_is_d1 cpu% ls d2 d2/this_is_d1 cpu% ls d3 d3/this_is_d2 cpu% ls d4 d4/this_is_d3 cpu% ls d4/this_is_d3 ls: d4/this_is_d3: 'd4/this_is_d3' file does not exist cpu% ls d4/this_is_d2 d4/this_is_d2 cpu% ls d4/this_is_d1 ls: d4/this_is_d1: 'd4/this_is_d1' file does not exist cpu% If path evaluation applied the rules three or more times then the "ls d4/this_is_d1" would have succeded just as "ls d3/this_is_d1" did in the first example. Now it's easy to guess what is going on. In the kernel, the domount and findmount functions translate an active fid (a Chan) according to the current name space. The behavior you have found suggests that somewhere during path name evaluation (namec), domount is is being called twice on some Chan instead of just once. Sure enough, the invariant mentioned at the top of the loop in namec: An invariant is that each time through the loop, c is on the undomount side of the mount point is not true in the case where a mount point was encountered in the resulting walk qids: if(!nomount) for(i=0; inqid && iqid[i])) break; If this succeeds, then next time around the loop nc (which becomes c) is on the domount side, not the undomount side. So the actual invariant is a little more complex. I've fixed the bug and submitted a patch. Thanks for the report. Russ