Re: Namer, mountab etc.

From: Andrew Valencia <vandys_at_nospam.org>
Date: Sun Oct 31 1993 - 17:09:10 PST

[nick@nsis.cl.nec.co.jp (Gavin Thomas Nicol) writes:]

> Do you think you could send out a description of the design of
>mountab, namer etc., and the way the interact with open() etc? Thanks
>very much in advance.

Sure, thanks for prompting me to do this.

The VSTa microkernel does not have any filesystem code. Not only does this
mean that the kernel does not know about inodes, directory entries, and so
forth. It also means that he does not understand what an "open file" is,
nor "file position", nor "path name lookup".

Filesystems are an illusion created by cooperation between servers
and the C library. By agreeing to certain message types and arguments,
they can talk about common file operations. The file include/sys/fs.h
defines these messages; servers implement them from the main message
handling loop, and clients generally request them through the C library.

If you go into vsta/libc/open.c, you will see what is, in UNIX-ese, the
"namei" loop--the loop which maps string pathnames into open files. It
does this by finding the longest initial match between the filename you
want to open, and a path in its mount table. For example:

        fd = open("/usr/local/lib/table.txt", O_READ);

Mount table: Path Connection
                / (DOS server)
                /dev/wd (WD server)
                /env (Environment variable server)
                /usr/local (VstaFS server)
                /namer (Name server)

The match would be against /usr/local, since this matches to more positions
than any other entry. The matched part is stripped, and the path lookup
now walks through each remaining part. So the filesystem server which happens
to be mounted under /usr/local for the current process will see successive
lookups for "lib", and then "table.txt".

All well and good, but the question occurs: how do you get your mount table
set up in the first place? Since you start with your mount table empty,
you can't very well open a file! If you happen to know some desirable
server is at port address 1234, you could:

        port = msg_connect(1234, ACC_READ);
        mountport("/path", port);

A small set of port addresses--just enough to boot--are at "well known
addresses". This includes the keyboard, screen, and namer server. It
does NOT include disk drivers or root filesystems. In fact, there are
more well-known addresses assigned than are needed. I should probably
fix this.

Anyway, the reason that all these vitally needed resources are not
given fixed addresses is that such a mechanism is too inflexible.
Instead, the "namer" server is started, and all future queries and
updates concerning who is using what port number are handled through
this single server. Like most servers, namer presents a
filesystem-like view of the symbols it maps. The content of each file
is an ASCII number, which is the port number registered for that
string. Given the mount table above, where the namer server is under
/namer (and assuming we have sufficient privileges--sys.sys is needed),
we could "register" a number ourselves, simply by:

        cd /namer
        mkdir andy-devs
        cd andy-devs
        cat > dev1
        12345
        ^D

In fact, this is how all servers register themselves, although a couple
library routines encapsulate all this tedium. A server would do something
like:

        port_name n;
        port_t p;
        struct msg m;

        /* Get port, let system choose ID */
        p = msg_port(0, &n);

        /* Offer to the system as fs/root, the boot/default filesystem */
        namer_register("fs/root", n);
        ...

        /* Start serving requests as this filesystem */
        while (msg_receive(p, &m) > 0) {
                ...
        }

And a client could do:

        port_name n;
        port_t p;
        char buf[128];

        /* Look up fs/root, get its port address */
        n = namer_find("fs/root");

        /* Connect to server, with access for reading */
        p = msg_connect(n, ACC_READ);

        /* Open foobar on this filesystem connection */
        m.m_nseg = 1;
        m.m_buf = "foobar";
        m.m_buflen = strlen(m.m_buf)+1; /* Include terminating '\0' in cnt */
        m.m_arg = ACC_READ;
        m.m_arg1 = 0;
        m.m_op = FS_OPEN;
        x = msg_send(p, &m);
        if (x > 0) { ... }

Although, frankly, it's much easier to put it in the mount table and
start using it through a more typical POSIX interfaces:

        mountport("/d", p);
        fd = open("/d/foobar", O_READ);
        while (read(fd, buf, sizeof(buf)) > 0) {
                ...
        }

There was a subtle difference between the last two examples. The
former, where we sent FS_OPEN messages ourselves, would walk the actual
connection down to the file which was to be opened. Thus, the initial
connection would be to the root filesystem, and after a successful
FS_OPEN, the connection would instead correspond to the file "foobar".
In the latter, the mount table holds the open connection to the
server's root, and open() requests do a clone() to get a distinct copy of this
connection, and then walk *it* down to the requested file. This leaves
the original connection at the root so further uses of the mount point
will work.

Setting up mount tables for yourself is tedious work. That's why bin/login
will read /vsta/etc/fstab during your login, and put initial entries into
your mount table. Hopefully, you can read this file, cd over to /namer,
look around, and start to get a feel for the links and interactions which
map names to ports, and organize a "filesystem" view on top of a collection
of open connections to various servers.

                                                Andy
Received on Sun Oct 31 17:17:10 1993

This archive was generated by hypermail 2.1.8 : Wed Sep 21 2005 - 19:37:12 PDT