Buffers

Given that communicating long pathnames is required and that a buffer will be needed to retain these pathnames, two principal strategies exist for managing such buffers:

The buffers might be useful for transferring data. However, where file contents are memory-mapped, they become superfluous.

Considerations

The following considerations apply to the different strategies.

Client Allocation

Where clients would be allocating buffers, they would potentially be doing so for the single purpose of communicating a pathname, with the server not then using such buffers. Where this might occur, clients could potentially reuse buffers when opening new files.

(Alternatively, clients could donate their buffers to the pool of pages being used to provide file content, but they would need to completely relinquish them; otherwise, they might be able to interfere with the proper functioning of the filesystem. It might be difficult to enforce this, so it seems that using buffers purely for explicit data sharing is the most appropriate approach.)

There could be concern about servers relinquishing buffers if the client were to reuse them: the server could potentially interfere with the buffers. However, where buffers have been explicitly shared, the assumption would be that the other party would always be able to access them. Any sharing communication buffers would only ever involve two parties.

One fairly convincing argument for having the client allocate the buffers when sharing data with the server is that it follows the natural course of communication. The client will reference the buffer dataspace in its message, thus explicitly indicating the presence of data.

Server Allocation

Where servers would be allocating buffers, they would also be doing so to facilitate pathname transfer. However, they would not explicitly share the buffers with clients. Instead, the servers would use the buffers to support operation as dataspaces: clients would write to memory mapped into their address spaces, this memory being provided by the buffers, but the servers would moderate access.

Ultimately, upon opening an actual file, the buffers might then be used as part of the pool of pages providing file content, although it might instead be advantageous to allow the client to use the buffer repeatedly for the purpose of opening files.

Workflows

Client Allocation

With this strategy, the process of accessing a file is as follows:

  1. An application obtains a buffer provided by a dataspace and writes a path into it.
  2. To open the named file, it sends a message to the filesystem providing a reference to the buffer.
  3. The filesystem creates an object for accessing the file and passes the buffer reference to this object.
  4. The filesystem returns a reference to this file or resource object back to the application.

The following client-side pseudocode can be formulated:

# Allocate dataspace.

ds = alloc_dataspace()

# Write path to buffer. (This is just a memory-writing operation.)

ds.write(path)

# Obtain a reference to the file object.

f = fs.open(ds)
open_file(empty buffer)applicationapplication/home/user/file(user) filesystemopen(empty buffer)resource object/home/user/file

Server Allocation

With this strategy, the process of accessing a file is as follows:

  1. An application requests an "opener context" from the filesystem.
  2. The filesystem creates a context. This object must be capable of acting as a dataspace.
  3. The filesystem returns a reference to the context back to the application. This object will be associated with a buffer because, as a dataspace, it provides an accessible virtual memory region to the application and the filesystem.

Actually accessing a named file involves the following:

  1. The application obtains the buffer provided by the context (acting as a dataspace) and writes a path into it.
  2. To open the named file, it sends a message to the context.
  3. The context uses the underlying filesystem to create an object for accessing the file, passing a reference to the created object back to the application.

The following client-side pseudocode can be formulated:

# Obtain an context acting as a dataspace.

context = fs.open()

# Write path to buffer. (This is just a memory-writing operation.)

context.buffer.write(path)

# Open the actual file.

f = context.open(flags)
open_fileapplicationapplication(user) filesystemcontextapplicationcontext/home/user/file(write)applicationcontext/home/user/fileopencontext(empty buffer)(user) filesystem(open)resource object/home/user/file

Resources and Contexts

The following arrangement of classes is involved in the opening of files:

openingResourceSimplePagerOpenerContextObjectUserFilesystemObjectOpenerContextResourceOpenerSupportPagerResourceUserFilesystemResourcePagingBufferSupport