PUFFS(4)

NAME
puffs - Pass-to-Userspace Framework File System

SYNOPSIS
file-system PUFFS
pseudo-device putter

DESCRIPTION
THIS DOCUMENT IS HOPELESSLY OUT OF DATE. While some parts are still valid, please refer to the source code for current reality.

IMPORTANT NOTE! This document describes interfaces which are not yet guaranteed to be stable. In case you update your system sources, please recompile everything and fix compilation errors. If your sources are out-of-sync, incorrect operation may result.

puffs provides a framework for creating file systems as userspace servers. The in-kernel VFS attachment is controlled through a special device node, /dev/puffs. This document describes the operations on the device. People looking to implement file systems should prefer using the system through the convenience library described in puffs(3). Users wanting to access the device node directly should include the header sys/fs/puffs/puffs_msgif.h for relevant definitions.

  Mounting
The puffs device node should be opened once per file system instance (i.e. mount). The device itself is a cloning node, so the same node can be opened a practically unlimited number of times. Once the device is open, the file system can be mounted the normal way using the mount(2) system call and using the argument structure to control mount options:

    struct puffs_args {
    	int		pa_vers;
    	int		pa_fd;
    	unsigned int	pa_flags;
    	size_t		pa_maxreqlen;
    	char		pa_name[PUFFSNAMESIZE];
    	uint8_t		pa_vnopmask[PUFFS_VN_MAX];
    };

The member pa_vers is currently always 0 and ignored. The pa_fd member is the file descriptor number from opening the device node. pa_flags controls some operations specific to puffs:

PUFFS_KFLAG_ALLOWCTL
    Allow file system fcntl and ioctl operations. Allowing these has security implications as the file system can technically read anything out of a calling processes address space. This flag may additionally be enforced by the kernel security policy.

PUFFS_KFLAG_NOCACHE
    Do not store data in the page cache. This causes operations to always consult the user server instead of consulting the page cache. This makes sense in situations where there is relatively little bulk data to be transferred and the user server does not want to take part in complex cache management routines in case the file system data can be modified through routes other than the file system interface.

PUFFS_KFLAG_ALLOPS
    Transport all vnode operations to the file system server instead of just the ones specified by pa_vnopmask.

The pa_maxreqlen member signifies the length of the incoming data buffer in userspace. A good value is PUFFS_REQ_MAXSIZE, which is the maximum the kernel will use. A minimum value is also enforced, so the value of this field should be checked after the mount operation to determine the correct buffer size. During operation, in case request fetch is attempted with a buffer too short, the error E2BIG will be returned. The file system type is give in pa_name. It will always be prepended by "puffs:" by the kernel. Finally, the array pa_vnopmask specifies which operations are supported by the file system server. The array is indexed with PUFFS_VN_FOO and 0 means vnode operation FOO is unimplemented while non-zero means an implemented operation. This array is ignored if PUFFS_KFLAG_ALLOPS is given.

After a successful mount system call, the the ioctl PUFFSSTARTOP must be issued through the open device node. The parameter for this ioctl is the following structure:

    struct puffs_startreq {
    	void		*psr_cookie;
    	struct statvfs	psr_sb;
    };

The member psr_cookie should be set before calling. This signals the cookie value of the root node of the file system (see puffs(3) for more details on cookie strategies). The value of psr_sb should be filled with the same results as for a regular statvfs call. After successfully executing this operation the file system is active.

  Operation
Operations must be queried from the kernel using the ioctl PUFFSGETOP, processed, and the results pushed back to the kernel using PUFFSPUTOP. Normally the system will block until an event is available for PUFFSGETOP, but it is possible to set the file descriptor into non-blocking mode, in which case EWOULDBLOCK is returned if no event is available. Asynchronous I/O calls (i.e., select(2), poll(2), and kevent(2)) can be issued to be notified of events.

As the argument both get and push use the following structure:

    struct puffs_req {
    	uint64_t	preq_id;
    	uint8_t		preq_opclass;
    	uint8_t		preq_optype;
    	void		*preq_cookie;
    	int		preq_rv;
    	void		*preq_aux;
    	size_t		preq_auxlen;
    };

The member preq_id is used as an identifier in the reply. It should not be modified during the processing of a PUFFSGETOP - PUFFSPUTOP sequence. The members preq_opclass and preq_optype identify the request; they also are used for typing the data pointed to by preq_aux. Currently the mapping between these two is only documented in code in src/lib/libpuffs/puff.c:puffcall(). The handling of this will very likely change in the future towards a more automatic direction. The length of the buffer given to PUFFSGETOP is described by preq_auxlen and will be modified by the kernel to indicate how much data actually was transmitted. This is for the benefit of calls such as write, which transmit a variable amount of data. Similarly, the user server should fill in the amount of data the kernel must copy for PUFFSPUTOP; most of the time this will be constant for a given operation, but operations such as read want to adjust it dynamically. Finally, preq_rv is used by the userspace server to fill in the success value of the operation in question.

In case the macro PUFFSOP_WANTREPLY() returns false for preq_opclass, a return value is not wanted and PUFFSPUTOP should not be issued.

Additionally, an operation of type PUFFSSIZEOP is supported, but it is only used by the ioctl and fcntl operations and will likely go away in the future. It is not described here.

  Termination
The file system can be unmounted regularly using umount(8). It will automatically be unmounted in case the userspace server is killed or the control file descriptor closed, but in this case the userspace server will not be separately requested to unmount itself and this may result in data loss.

SEE ALSO
ioctl(2), mount(2), puffs(3), umount(8) Antti Kantee, March 2007, Proceedings of AsiaBSDCon 2007, pp. 29-42, puffs - Pass-to-Userspace Framework File System.

HISTORY
An unsupported experimental version of puffs first appeared in NetBSD 4.0.

AUTHORS
Antti Kantee <pooka@iki.fi>

BUGS
puffs is currently more like a souffle than puff pastry.