Resolving pathnames
When a process opens a file, the POSIX-compliant open() library routine first sends the pathname to procnto, where the pathname is compared against the prefix tree to determine which resource managers should be sent the open() message.
The prefix tree may contain identical or partially
overlapping regions of authority—multiple servers
can register the same prefix. If the regions are identical,
the order of resolution can be specified (see Ordering mountpoints,
below).
If the regions are overlapping,
the responses from the path manager are ordered with the longest prefixes first;
for prefixes of equal length, the same specified order of resolution
applies as for identical regions.
Prefix | Description |
---|---|
/ | Power-Safe filesystem (fs-qnx6.so) |
/dev/ser1 | Serial device manager (devc-ser*) |
/dev/ser2 | Serial device manager (devc-ser*) |
/dev/hd0 | Raw disk volume (devb-eide) |
The filesystem manager has registered a prefix for a mounted Power-Safe filesystem (i.e., /). The block device driver has registered a prefix for a block special file that represents an entire physical hard drive (i.e., /dev/hd0). The serial device manager has registered two prefixes for the two PC serial ports.
This pathname: | matches: | and resolves to: |
---|---|---|
/dev/ser1 | /dev/ser1 | devc-ser* |
/dev/ser2 | /dev/ser2 | devc-ser* |
/dev/ser | / | fs-qnx6.so |
/dev/hd0 | /dev/hd0 | devb-eide.so |
/usr/jhsmith/test | / | fs-qnx6.so |
Ordering mountpoints
- before
- Mount the filesystem so that it's resolved before any other filesystems mounted at the same pathname (in other words, it's placed in front of any existing mount). When you access a file, the system looks on this filesystem first.
- after
- Mount the filesystem so that it's resolved after any other filesystems mounted at the same pathname (in other words, it's placed behind any existing mounts). When you access a file, the system looks on this filesystem last, and only if the file wasn't found on any other filesystems.
If you specify the appropriate before option, the filesystem floats in front of any other filesystems mounted at the same mountpoint, except those that you later mount with before. If you specify after, the filesystem goes behind any other filesystems mounted at the same mountpoint, except those that are already mounted with after. So, the search order for these filesystems is:
- those mounted with before
- those mounted with no flags
- those mounted with after
with each list searched in order of mount requests. The first server to claim the name gets it. You would typically use after to have a filesystem wait at the back and pick up things the no one else is handling, and before to make sure a filesystem looks first at filenames.
Single-device mountpoints
- Server A
- A Power-Safe filesystem. Its mountpoint is /. It contains the files bin/true and bin/false.
- Server B
- A flash filesystem. Its mountpoint is /bin. It contains the files ls and echo.
- Server C
- A single device that generates numbers. Its mountpoint is /dev/random.
Mountpoint | Server |
---|---|
/ | Server A (Power-Safe filesystem) |
/bin | Server B (flash filesystem) |
/dev/random | Server C (device) |
Of course, each Server
name is actually an
abbreviation for the nd, pid, chid for that
particular server channel.
int fd;
fd = open("/dev/random", ...);
read(fd, ...);
close(fd);
- Server C (most likely; longest path match)
- Server A (least likely; shortest path match)
- Server C receives a null path, since the request came in on the same path as the mountpoint.
- Server A receives the path dev/random, since its mountpoint was /.
As soon as one server positively acknowledges the request, the library won't contact the remaining servers. This means Server A is contacted only if Server C denies the request.
This process is fairly straightforward with single device entries, where the first server is generally the server that will handle the request. Where it becomes interesting is in the case of unioned filesystem mountpoints.
Unioned filesystem mountpoints
Let's assume we have two servers set up as before:
- Server A
- A Power-Safe filesystem. Its mountpoint is /. It contains the files bin/true and bin/false.
- Server B
- A flash filesystem. Its mountpoint is /bin. It contains the files ls and echo.
Note that each server has a /bin directory, but with different contents.
Once both servers are mounted, you would see the following due to the union of the mountpoints:
- /
- Server A
- /bin
- Servers A and B
- /bin/echo
- Server B
- /bin/false
- Server A
- /bin/ls
- Server B
- /bin/true
- Server A
DIR *dirp;
dirp = opendir("/bin", ...);
closedir(dirp);
This results in:
- Server B receives a null path, since the request came in on the same path as the mountpoint.
- Server A receives the path "bin", since its mountpoint was "/".
The result now is that we have a collection of file descriptors to servers who handle the path /bin (in this case two servers); the actual directory name entries are read in turn when a readdir() is called. If any of the names in the directory are accessed with a regular open, then the normal resolution procedure takes place and only one server is accessed.
For a more detailed look at this, see
Unioned filesystems
in the Resource Managers chapter of Getting Started with the QNX OS.
Why overlay mountpoints?
This overlaying of mountpoints is a very handy feature when doing field updates, servicing, etc. It also makes for a more unified system, where pathnames result in connections to servers regardless of what services they're providing, thus resulting in a more unified API.