Documentation
¶
Overview ¶
Package fs is a pure-Go virtio-fs (FUSE-over-virtio) guest driver. It drives a modern (Virtio 1.0+) PCI virtio-fs device through the transport interfaces defined in github.com/go-virtio/common; the same code drives a UEFI-backed device, a bare-metal device, or a virtio-mmio device depending on which common.Transport implementation the caller supplies.
Scope — this package owns device bring-up, the request virtqueue, the FUSE-over-virtio descriptor-chain framing (readable [fuse_in_header | in-args], writable [fuse_out_header | out-args]; Virtio 1.2 §5.11), and a read-only mount closure: Init, Lookup, GetAttr, Open, Read, Release, Forget, Destroy. Write-side FUSE ops are out of scope.
- Modern transport (VIRTIO_F_VERSION_1 mandatory). Legacy devices are rejected by the common init sequence.
- Queue 0 is the hiprio queue; queues 1..num_request_queues are the request queues (Virtio 1.2 §5.11.2). This driver issues all FUSE requests on the first request queue (index 1) and does not use the hiprio queue (no FUSE_INTERRUPT / FUSE_FORGET fast-path needed for a read-only mount).
- No virtio feature bit beyond VIRTIO_F_VERSION_1 is negotiated. (VIRTIO_FS_F_NOTIFICATION exists but is not required for the request path.)
The FUSE protocol itself is versioned independently of virtio: this driver speaks FUSE major 7 and negotiates the minor down to whatever the device offers (FUSE_INIT, Linux fuse.h).
References:
- Virtio 1.2 §5.11 "File System Device" — device-type 26 binding, virtio_fs_config (tag[36] + le32 num_request_queues), queue layout (hiprio + request queues).
- Linux include/uapi/linux/virtio_fs.h — struct virtio_fs_config.
- Linux include/uapi/linux/virtio_ids.h — VIRTIO_ID_FS = 26.
- Linux include/uapi/linux/fuse.h — every FUSE wire struct + opcode cited at its use site below (FUSE_KERNEL_VERSION = 7).
- Virtio 1.1 §3.1.1 "Device Initialization" — the status-bit choreography (shared with blk/net/console via common).
Index ¶
- Constants
- Variables
- func AcceptFeatures(deviceFeatures uint64) (uint64, error)
- type Attr
- type Entry
- type VirtioFS
- func (f *VirtioFS) Destroy() error
- func (f *VirtioFS) Forget(nodeid uint64, nlookup uint64) error
- func (f *VirtioFS) GetAttr(nodeid uint64) (Attr, error)
- func (f *VirtioFS) Init() error
- func (f *VirtioFS) Lookup(parent uint64, name string) (Entry, error)
- func (f *VirtioFS) Open(nodeid uint64) (uint64, error)
- func (f *VirtioFS) Read(nodeid, fh, off uint64, size uint32) ([]byte, error)
- func (f *VirtioFS) Release(nodeid, fh uint64) error
- func (f *VirtioFS) RequestQueue() *common.Virtqueue
Constants ¶
const ( FuseOpLookup uint32 = 1 FuseOpForget uint32 = 2 FuseOpGetattr uint32 = 3 FuseOpOpen uint32 = 14 FuseOpRead uint32 = 15 FuseOpRelease uint32 = 18 FuseOpInit uint32 = 26 FuseOpDestroy uint32 = 38 )
FUSE opcodes (Linux fuse.h: enum fuse_opcode). Only the read-only mount subset is defined.
const AcceptedFeatures uint64 = common.FeatureVersion1
AcceptedFeatures is the feature mask the driver negotiates ON — only the non-negotiable VIRTIO_F_VERSION_1.
const FuseKernelMinorVersion uint32 = 31
FuseKernelMinorVersion is the FUSE minor version the driver proposes in FUSE_INIT; the negotiated minor is min(proposed, device-offered) (Linux fuse.h: FUSE_KERNEL_MINOR_VERSION). We propose a conservative 31 (the baseline virtiofsd requires) and accept whatever the device reports back.
const FuseKernelVersion uint32 = 7
FuseKernelVersion is the FUSE major protocol version this driver speaks (Linux fuse.h: FUSE_KERNEL_VERSION = 7).
const HiprioQueueIdx uint16 = 0
HiprioQueueIdx is the index of the hiprio queue (queue 0) — used for FUSE_FORGET / FUSE_INTERRUPT priority requests (Virtio 1.2 §5.11.2). This read-only driver does not submit on it.
const RequestQueueIdx uint16 = 1
RequestQueueIdx is the index of the first request queue. Queue 0 is hiprio; request queues start at index 1 (Virtio 1.2 §5.11.2).
const RequestQueueSize uint16 = 16
RequestQueueSize is the desired ring size (clamped + rounded during setup). A FUSE request consumes 2–4 descriptors; the driver issues them one at a time.
const TxPollIterations = 200000
TxPollIterations is the default busy-poll budget for one request.
Variables ¶
var ( ErrNotModernDevice = fsError("go-virtio/fs: device doesn't offer VIRTIO_F_VERSION_1 (legacy-only)") ErrFeaturesNotOK = fsError("go-virtio/fs: FEATURES_OK status bit didn't stick after DriverFeature write") ErrInitWrongDeviceID = fsError("go-virtio/fs: PCI device ID is not 0x105A (modern virtio-fs device)") ErrQueueNotAvailable = fsError("go-virtio/fs: device reports QueueSize=0 for the request queue") ErrRequestTimeout = fsError("go-virtio/fs: request poll timeout (device did not complete the request)") ErrFuseError = fsError("go-virtio/fs: device returned a non-zero fuse_out_header.error") ErrFuseVersion = fsError("go-virtio/fs: device FUSE major version is not 7") ErrShortReply = fsError("go-virtio/fs: device wrote fewer reply bytes than the op requires") ErrNoEntry = fsError("go-virtio/fs: FUSE_LOOKUP returned nodeid 0 (no such entry)") ErrZeroSize = fsError("go-virtio/fs: Read size must be positive") )
Sentinel errors for the virtio-fs path.
Functions ¶
func AcceptFeatures ¶
AcceptFeatures returns the negotiated mask (requires VERSION_1).
Types ¶
type Attr ¶
type Attr struct {
Ino uint64 // inode number
Size uint64 // file size in bytes
Mode uint32 // st_mode (type + permission bits)
Nlink uint32 // link count
}
Attr is the decoded subset of FUSE fuse_attr (Linux fuse.h) the read-only mount surface exposes. Only the fields a caller needs to stat + read a file are decoded.
type Entry ¶
type Entry struct {
NodeID uint64 // nodeid to use in subsequent ops (0 = negative lookup)
Attr Attr
}
Entry is the decoded result of a FUSE_LOOKUP (fuse_entry_out): the node id assigned to the looked-up name plus its attributes.
type VirtioFS ¶
type VirtioFS struct {
// Cfg is the modern-transport handle.
Cfg *common.ModernConfig
// Tag is the virtio_fs_config mount tag (Virtio 1.2 §5.11.5), the
// name the guest mounts ("-o tag"). Trailing NULs are trimmed.
Tag string
// NumRequestQueues is the device-advertised request-queue count
// (virtio_fs_config.num_request_queues).
NumRequestQueues uint32
// NegotiatedFeatures records the virtio feature handshake result.
NegotiatedFeatures uint64
// FuseMajor / FuseMinor record the negotiated FUSE protocol version
// (populated by Init).
FuseMajor uint32
FuseMinor uint32
// contains filtered or unexported fields
}
VirtioFS wraps one initialised virtio-fs device.
func OpenVirtioFS ¶
OpenVirtioFS drives the full bring-up of one virtio-fs device:
- Verify the PCI device ID is 0x105A (modern virtio-fs).
- InitModernConfig walks PCI caps + populates the BAR locators.
- Reset → ACK → DRIVER status progression.
- Read DeviceFeature, require VERSION_1, mask, write DriverFeature.
- Set FEATURES_OK, verify it stuck.
- Read virtio_fs_config (tag + num_request_queues).
- Allocate + publish the first request queue (index 1).
- DRIVER_OK status.
The caller next calls Init() to perform the FUSE_INIT handshake.
func (*VirtioFS) Destroy ¶
Destroy performs FUSE_DESTROY (Linux fuse.h, opcode 38), tearing down the FUSE session. No in-args; the device writes a fuse_out_header with no out-args.
func (*VirtioFS) Forget ¶
Forget performs FUSE_FORGET (Linux fuse.h, opcode 2) on `nodeid`, telling the device to drop `nlookup` references to the node. in-args are fuse_forget_in{nlookup}. FUSE_FORGET has no reply at all (the device does not write a fuse_out_header), so this submits the request and reclaims without awaiting out-args.
func (*VirtioFS) GetAttr ¶
GetAttr performs FUSE_GETATTR (Linux fuse.h, opcode 3) on `nodeid`. in-args are fuse_getattr_in{getattr_flags=0, dummy=0, fh=0} (a path-based getattr, no open handle). The reply is fuse_attr_out{attr_valid, attr_valid_nsec, dummy, attr}.
func (*VirtioFS) Init ¶
Init performs the FUSE_INIT handshake (Linux fuse.h, opcode 26). It sends fuse_init_in{major=7, minor, max_readahead, flags} on nodeid 0 and parses fuse_init_out{major, minor, ...}, recording the negotiated version. Returns ErrFuseVersion if the device reports a major other than 7 (the only major this driver speaks).
func (*VirtioFS) Lookup ¶
Lookup performs FUSE_LOOKUP (Linux fuse.h, opcode 1): resolve `name` within directory node `parent`. The in-args are the NUL-terminated name; the reply is fuse_entry_out{nodeid, ..., attr}. A nodeid of 0 means a negative lookup (name does not exist) — returned as ErrNoEntry.
func (*VirtioFS) Open ¶
Open performs FUSE_OPEN (Linux fuse.h, opcode 14) on `nodeid`. The in-args are fuse_open_in{flags, open_flags}; the driver opens read-only (flags = O_RDONLY = 0). The reply is fuse_open_out{fh, open_flags, backing_id}; the returned fh is used in Read/Release.
func (*VirtioFS) Read ¶
Read performs FUSE_READ (Linux fuse.h, opcode 15) on (nodeid, fh), reading up to `size` bytes at byte offset `off`. The in-args are fuse_read_in{fh, offset, size, read_flags, lock_owner, flags, padding}; the reply is raw file bytes (no out-args struct — the device writes the data directly after fuse_out_header). The returned slice length is min(size, bytes-available) — a short read at EOF.
func (*VirtioFS) Release ¶
Release performs FUSE_RELEASE (Linux fuse.h, opcode 18) on (nodeid, fh), closing the open handle. in-args are fuse_release_in{fh, flags, release_flags, lock_owner}; there are no out-args.
func (*VirtioFS) RequestQueue ¶
RequestQueue exposes the request virtqueue handle for diagnostics.