I have a complicated relationship with 9P2000.L. On the one hand it's been a useful way to build file systems for Linux, and I've gotten some mileage out of that. On the other hand, I'm not crazy about having a different protocol to 9P (I've read through a lot of what's been said on 9fans about this, going back many years).
I've been trying an experiment over the last few weeks to see if I can pass the extra Linux file system features over 9P (9P2000) as an application of 9P rather than using a separate protocol. I want to be able to connect two Linux machines using 9P, but have the full Linux file system semantics available across the connection: symbolic links, moving files and directories around, nanosecond time stamps, open modes, record locking, the whole bit. I also want that to work properly with a Plan 9 machine between them. Linux programs should see a Linux file system, Plan 9 programs should see a Plan 9 file system. I think it's easiest to explain by walking through an end-to-end example. First, I altered my Linux 9P (9P2000) file server to offer an encoding of the linuxiness (is that a word??) For example, here's a test directory on my Linux machine. lyssa@pibysix:~/t $ *ls -l* total 28 -rw-r--r-- 1 lyssa lyssa 6 Feb 8 11:41 bar lrwxrwxrwx 1 lyssa lyssa 6 Feb 7 22:17 bin -> ../bin -rw-r--r-- 1 lyssa lyssa 6 Feb 10 15:06 foo -rw-r--r-- 1 lyssa lyssa 1 Feb 9 15:31 foop -rw-r--r-- 1 lyssa lyssa 1 Feb 9 18:33 foop2 drwxr-xr-x 2 lyssa lyssa 4096 Feb 7 00:54 foot lrwxrwxrwx 1 lyssa lyssa 3 Feb 7 01:06 hello -> foo lrwxrwxrwx 1 lyssa lyssa 5 Feb 11 02:08 hello6 -> hello -rw-r--r-- 1 lyssa lyssa 38 Feb 8 00:58 hi lrwxrwxrwx 1 lyssa lyssa 2 Feb 9 01:28 hi2 -> hi lrwxrwxrwx 1 lyssa lyssa 13 Feb 11 03:20 somenewlinkname -> one/two/three lyssa@pibysix:~/t $ If I mount it on Plan 9 with my 9P server, it looks like this: term% *pwd* /usr/glenda/mnt/home/lyssa/t term% *ls -lp* --rw-r--r-- M 1061 glenda glenda 6 Feb 8 11:41 bar d-rwxr-xr-x M 1061 glenda glenda 0 Feb 6 23:51 bin --rw-r--r-- M 1061 glenda glenda 6 Feb 10 15:06 foo --rw-r--r-- M 1061 glenda glenda 1 Feb 9 15:31 foop --rw-r--r-- M 1061 glenda glenda 1 Feb 9 18:33 foop2 d-rwxr-xr-x M 1061 glenda glenda 0 Feb 7 00:54 foot --rw-r--r-- M 1061 glenda glenda 6 Feb 10 15:06 hello --rw-r--r-- M 1061 glenda glenda 6 Feb 10 15:06 hello6 --rw-r--r-- M 1061 glenda glenda 38 Feb 8 00:58 hi --rw-r--r-- M 1061 glenda glenda 38 Feb 8 00:58 hi2 ----------- M 1061 '(0)' glenda 0 Jan 1 1970 somenewlinkname term% These files all behave as you might expect from a vanilla 9P server. (the symbolic links are followed - the bottom one is a broken link. A long and involved conversation could be had about this, but can we not do that right now?) I've added an invisible virtual extension to the namespace my Linux 9P server offers: For any given file "/a/b/c/foo", there is a control file, "/a/b/c/,ctl/foo" which gives access to all its linuxy gloriousness: term% *cat ,ctl/foo* dev 45831 inode 265868 mode 0100644 nlink 1 uid 1001 gid 1001 rdev 0 size 6 blksize 4096 blocks 8 atime 1739199962 mtime 1739199962 ctime 1739466812 atimensec 460383798 mtimensec 470383712 ctimensec 926076796 name foo term% You can also write commands into these files to change some of the properties - as you might expect. Here are the control files in the (unlisted) virtual directory ",ctl": term% *ls -lp ,ctl* --rw-r--r-- M 1061 glenda glenda 0 Feb 8 11:41 bar --rw-r--r-- M 1061 glenda glenda 0 Feb 6 23:51 bin --rw-r--r-- M 1061 glenda glenda 0 Feb 10 15:06 foo --rw-r--r-- M 1061 glenda glenda 0 Feb 9 15:31 foop --rw-r--r-- M 1061 glenda glenda 0 Feb 9 18:33 foop2 --rw-r--r-- M 1061 glenda glenda 0 Feb 7 00:54 foot --rw-r--r-- M 1061 glenda glenda 0 Feb 10 15:06 hello --rw-r--r-- M 1061 glenda glenda 0 Feb 10 15:06 hello6 --rw-r--r-- M 1061 glenda glenda 0 Feb 8 00:58 hi --rw-r--r-- M 1061 glenda glenda 0 Feb 8 00:58 hi2 --rw-r--r-- M 1061 '(0)' glenda 0 Jan 1 1970 somenewlinkname term% ",ctl" is a simple example of a means to pass parameters down a Twalk to later requests by using weird file names. You can pass other parameters... term% *ls -lp ,nofollow* --rw-r--r-- M 1061 glenda glenda 6 Feb 8 11:41 bar a-r--r--r-- M 1061 glenda glenda 6 Feb 7 22:17 bin --rw-r--r-- M 1061 glenda glenda 6 Feb 10 15:06 foo --rw-r--r-- M 1061 glenda glenda 1 Feb 9 15:31 foop --rw-r--r-- M 1061 glenda glenda 1 Feb 9 18:33 foop2 d-rwxr-xr-x M 1061 glenda glenda 0 Feb 7 00:54 foot a-r--r--r-- M 1061 glenda glenda 3 Feb 7 01:06 hello a-r--r--r-- M 1061 glenda glenda 5 Feb 11 02:08 hello6 --rw-r--r-- M 1061 glenda glenda 38 Feb 8 00:58 hi a-r--r--r-- M 1061 glenda glenda 2 Feb 9 01:28 hi2 a---------- M 1061 glenda glenda 13 Feb 11 03:20 somenewlinkname term% This provides a way to avoid following the symbolic links. Symlinks show up as append-only, read-only files, which is a bit of a hack, I suppose, but perhaps okay for now. When you don't follow symlinks, they present their link target. term% *cat ,nofollow/bin; echo* ../bin term% And you can access the control file of a link: term% *cat ,ctl,nofollow/bin* dev 45831 inode 263367 mode 0120777 nlink 1 uid 1001 gid 1001 rdev 0 size 6 blksize 4096 blocks 0 atime 1738966670 mtime 1738966670 ctime 1738966670 atimensec 484184178 mtimensec 484184178 ctimensec 484184178 name bin symlink ..%2Fbin term% You can make new symbolic links from plan 9. (where's that Linux ls(1) program?) term% *ls -l ../../../bin/ls* --rwxr-xr-x M 1061 '(0)' glenda 108752 Feb 28 2019 ../../../bin/ls term% Let's link to it: term% *echo symlink ../../../bin/ls another >,ctl/,* term% *ls -lp* --rwxr-xr-x M 1061 '(0)' glenda 108752 Feb 28 2019 another --rw-r--r-- M 1061 glenda glenda 6 Feb 8 11:41 bar d-rwxr-xr-x M 1061 glenda glenda 0 Feb 6 23:51 bin --rw-r--r-- M 1061 glenda glenda 6 Feb 10 15:06 foo --rw-r--r-- M 1061 glenda glenda 1 Feb 9 15:31 foop --rw-r--r-- M 1061 glenda glenda 1 Feb 9 18:33 foop2 d-rwxr-xr-x M 1061 glenda glenda 0 Feb 7 00:54 foot --rw-r--r-- M 1061 glenda glenda 6 Feb 10 15:06 hello --rw-r--r-- M 1061 glenda glenda 6 Feb 10 15:06 hello6 --rw-r--r-- M 1061 glenda glenda 38 Feb 8 00:58 hi --rw-r--r-- M 1061 glenda glenda 38 Feb 8 00:58 hi2 ----------- M 1061 '(0)' glenda 0 Jan 1 1970 somenewlinkname term% ",ctl/," is a name for the control file for the directory itself. Commands written there can be used to make symlinks, move files, etc. It has an alias in the parent directory's ,ctl directory. So that's the general idea. Linux extras are hidden from Plan 9, but accessible. Second, I built an client adapter for Linux that uses these extra mechanisms. It serves 9P2000.L, which it mounts locally using v9fs - the Linux 9P client, but speaks "9P-with-benefits" across the network as a client. I have it in mind to do a version for FUSE one day, instead of using v9fs. Exportfs on my plan 9 machine is serving the namespace above that included a mount of my Linux 9P server, above. I've mounted that on Linux in /mnt/mnt. So now Linux is looking at Plan 9, which is looking at Linux: lyssa@pibysix:/mnt/mnt/usr/glenda/mnt/home/lyssa/t *$ ls -l* total 24 lrwxrwxrwx 1 lyssa lyssa 15 Feb 13 18:00 another -> ../../../bin/ls -rw-r--r-- 1 lyssa lyssa 6 Feb 8 11:41 bar lrwxrwxrwx 1 lyssa lyssa 6 Feb 7 22:17 bin -> ../bin -rw-r--r-- 1 lyssa lyssa 6 Feb 10 15:06 foo -rw-r--r-- 1 lyssa lyssa 1 Feb 9 15:31 foop -rw-r--r-- 1 lyssa lyssa 1 Feb 9 18:33 foop2 drwxr-xr-x 2 lyssa lyssa 4096 Feb 7 00:54 foot lrwxrwxrwx 1 lyssa lyssa 3 Feb 7 01:06 hello -> foo lrwxrwxrwx 1 lyssa lyssa 5 Feb 11 02:08 hello6 -> hello -rw-r--r-- 1 lyssa lyssa 38 Feb 8 00:58 hi lrwxrwxrwx 1 lyssa lyssa 2 Feb 9 01:28 hi2 -> hi lrwxrwxrwx 1 lyssa lyssa 13 Feb 11 03:20 somenewlinkname -> one/two/three All that linuxy goodness is passed through Plan 9 as shown above. Linux does not expect file systems to follow symbolic links themselves, so the adapter uses ",nofollow". Here's the same directory with the links resolved by Linux: lyssa@pibysix:/mnt/mnt/usr/glenda/mnt/home/lyssa/t $ *ls -lL* total 24 -rwxr-xr-x 1 root root 108752 Feb 28 2019 another -rw-r--r-- 1 lyssa lyssa 6 Feb 8 11:41 bar drwxr-xr-x 2 lyssa lyssa 4096 Feb 6 23:51 bin -rw-r--r-- 1 lyssa lyssa 6 Feb 10 15:06 foo -rw-r--r-- 1 lyssa lyssa 1 Feb 9 15:31 foop -rw-r--r-- 1 lyssa lyssa 1 Feb 9 18:33 foop2 drwxr-xr-x 2 lyssa lyssa 4096 Feb 7 00:54 foot -rw-r--r-- 1 lyssa lyssa 6 Feb 10 15:06 hello -rw-r--r-- 1 lyssa lyssa 6 Feb 10 15:06 hello6 -rw-r--r-- 1 lyssa lyssa 38 Feb 8 00:58 hi -rw-r--r-- 1 lyssa lyssa 38 Feb 8 00:58 hi2 ?????????? ? ? ? ? ? somenewlinkname lyssa@pibysix:/mnt/mnt/usr/glenda/mnt/home/lyssa/t $ Lets make a link on Linux, by passing the request through plan 9 and back to Linux: lyssa@pibysix:/mnt/mnt/usr/glenda/mnt/home/lyssa/t $ *ln -s ../../../bin/ls another2* * The "ln" command makes a symlinkat(2) system call into the Linux kernel. * The v9fs driver in the kernel fields the call and issues a Tsymlink 9P2000.L message to my mounted adapter through a pipe. * My adapter receives that and translates it into a 9P Twalk to the control file for the containing directory, Topens the file and issues a 9P Twrite with the "symlink" command in it, which goes over the network to Plan 9 * exportfs running on Plan 9 receives the Twalk, Topen and Twrite, and makes open(2) and pwrite(2) calls to the Plan 9 kernel. * devmnt in the Plan 9 kernel - I think... - issues the same Twalk, Topen and Twrite requests over the network to my Linux 9P server. * My 9P server receives the Twrite command and issues a symlinkat(2) system call. * The Linux server kernel makes the symbolic link. (there were some clunks and closes as well). lyssa@pibysix:/mnt/mnt/usr/glenda/mnt/home/lyssa/t $ *ls -l* total 24 lrwxrwxrwx 1 lyssa lyssa 15 Feb 13 18:00 another -> ../../../bin/ls lrwxrwxrwx 1 lyssa lyssa 15 Feb 13 18:03 another2 -> ../../../bin/ls -rw-r--r-- 1 lyssa lyssa 6 Feb 8 11:41 bar lrwxrwxrwx 1 lyssa lyssa 6 Feb 7 22:17 bin -> ../bin -rw-r--r-- 1 lyssa lyssa 6 Feb 10 15:06 foo -rw-r--r-- 1 lyssa lyssa 1 Feb 9 15:31 foop -rw-r--r-- 1 lyssa lyssa 1 Feb 9 18:33 foop2 drwxr-xr-x 2 lyssa lyssa 4096 Feb 7 00:54 foot lrwxrwxrwx 1 lyssa lyssa 3 Feb 7 01:06 hello -> foo lrwxrwxrwx 1 lyssa lyssa 5 Feb 11 02:08 hello6 -> hello -rw-r--r-- 1 lyssa lyssa 38 Feb 8 00:58 hi lrwxrwxrwx 1 lyssa lyssa 2 Feb 9 01:28 hi2 -> hi lrwxrwxrwx 1 lyssa lyssa 13 Feb 11 03:20 somenewlinkname -> one/two/three lyssa@pibysix:/mnt/mnt/usr/glenda/mnt/home/lyssa/t $ So now Linux can mount file systems over 9P, and still see all the nanosecond timestamps and other stuff: lyssa@pibysix:~/mnt/mnt/usr/glenda/mnt/home/lyssa/t $ *stat foo* File: foo Size: 6 Blocks: 8 IO Block: 4096 regular file Device: 36h/54d Inode: 265870 Links: 1 Access: (0644/-rw-r--r--) Uid: ( 1001/ lyssa) Gid: ( 1001/ lyssa) Access: 2025-02-10 15:06:02.460383798 +0000 Modify: 2025-02-10 15:06:02.470383712 +0000 Change: 2025-02-10 18:32:05.271025091 +0000 Birth: - lyssa@pibysix:~ (I suppose nanosecond resolution timestamps must be important to some people...) My adapter is operating in a heterogeneous file system in this example, where part of it has this extended behaviour, and part of it does not. There's no mode switch or barriers - it just looks for the virtual files, and if they're not there it does the standard thing. If I'd bound some other part of the Plan 9 space over part of the the mounted Linux space before I exported it, the adapter would just fall back to vanilla behaviour when file accesses are in that subtree. It's a work in progress. Linux is not actually my platform of choice, and symbolic links are not exactly my spirit animal, but it's a familiar context for exploring the ideas. I don't know what people think? This is about my third iteration of this idea. I'm not sure I'm done with it yet. I wondering whether it would be better to have a single control file per directory and some kind of sub-protocol going through it. It would possibly be a less chatty alternative. But somehow not very appealing. I'm open to suggestions. ------------------------------------------ 9fans: 9fans Permalink: https://9fans.topicbox.com/groups/9fans/T0f2c2342a05a3d6e-M9edffaa3ab33367c91c650f8 Delivery options: https://9fans.topicbox.com/groups/9fans/subscription