9pfs is a network filesystem protocol developed for Plan 9. 9pfs is very simple and describes a series of commands and responses. It is completely independent from the communication channels, in fact many clients and servers support multiple channels, usually called “transports”. For example the Linux client supports tcp and unix sockets, fds, virtio and rdma.
This document won’t cover the full 9pfs specification. Please refer to this paper and this website for a detailed description of it. However it is useful to know that each 9pfs request and response has the following header:
struct header {
uint32_t size;
uint8_t id;
uint16_t tag;
} __attribute__((packed));
0 4 5 7
+---------+--+----+
| size |id|tag |
+---------+--+----+
size The size of the request or response.
id The 9pfs request or response operation.
tag Unique id that identifies a specific request/response pair. It is used to multiplex operations on a single channel.
It is possible to have multiple requests in-flight at any given time.
This document describes a Xen based transport for 9pfs, in the traditional PV frontend and backend format. The PV frontend is used by the client to send commands to the server. The PV backend is used by the 9pfs server to receive commands from clients and send back responses.
The transport protocol supports multiple rings up to the maximum supported by the backend. The size of every ring is also configurable and can span multiple pages, up to the maximum supported by the backend (although it cannot be more than 2MB). The design is to exploit parallelism at the vCPU level and support multiple outstanding requests simultaneously.
This document does not cover the 9pfs client/server design or implementation, only the transport for it.
The frontend and the backend connect via xenstore to exchange information. The toolstack creates front and back nodes with state XenbusStateInitialising. The protocol node name is 9pfs.
Multiple rings are supported for each frontend and backend connection.
Backend specific properties, written by the backend, read by the frontend:
versions
Values: <string>
List of comma separated protocol versions supported by the backend.
For example "1,2,3". Currently the value is just "1", as there is
only one version. N.B.: this is the version of the Xen trasport
protocol, not the version of 9pfs supported by the server.
max-rings
Values: <uint32_t>
The maximum supported number of rings per frontend.
max-ring-page-order
Values: <uint32_t>
The maximum supported size of a memory allocation in units of
log2n(machine pages), e.g. 1 = 2 pages, 2 == 4 pages, etc. It
must be at least 1.
Backend configuration nodes, written by the toolstack, read by the backend:
path
Values: <string>
Host filesystem path to share.
tag
Values: <string>
Alphanumeric tag that identifies the 9pfs share. The client needs
to know the tag to be able to mount it.
security-model
Values: "none"
*none*: files are stored using the same credentials as they are
created on the guest (no user ownership squash or remap)
Only "none" is supported in this version of the protocol.
version
Values: <string>
Protocol version, chosen among the ones supported by the backend
(see **versions** under [Backend XenBus Nodes]). Currently the
value must be "1".
num-rings
Values: <uint32_t>
Number of rings. It needs to be lower or equal to max-rings.
event-channel-<num> (event-channel-0, event-channel-1, etc)
Values: <uint32_t>
The identifier of the Xen event channel used to signal activity
in the ring buffer. One for each ring.
ring-ref<num> (ring-ref0, ring-ref1, etc)
Values: <uint32_t>
The Xen grant reference granting permission for the backend to
map a page with information to setup a share ring. One for each
ring.
Initialization:
*Front* *Back*
XenbusStateInitialising XenbusStateInitialising
- Query virtual device - Query backend device
properties. identification data.
- Setup OS device instance. - Publish backend features
- Allocate and initialize the and transport parameters
request ring. |
- Publish transport parameters |
that will be in effect during V
this connection. XenbusStateInitWait
|
|
V
XenbusStateInitialised
- Query frontend transport parameters.
- Connect to the request ring and
event channel.
|
|
V
XenbusStateConnected
- Query backend device properties.
- Finalize OS virtual device
instance.
|
|
V
XenbusStateConnected
Once frontend and backend are connected, they have a shared page per ring, which are used to setup the rings, and an event channel per ring, which are used to send notifi