Menu
On this page

A ublk device’s behavior is fixed at creation by a 64-bit set of UBLK_F_* flags in struct ublksrv_ctrl_dev_info.flags. Some flags select a protocol (how data moves, how I/O commands are issued), some enable optional control commands, and a few are pure capability bits that the kernel sets on its own. The 7.3-rc5 header defines 21 of them, bits 0 through 20.

This chapter explains how flags are negotiated, summarizes every flag in one table, and then describes each group. The chapters on data copy modes, batch I/O, user recovery, unprivileged devices, zoned devices and integrity metadata go deeper on the larger features.

How negotiation works#

There are two mechanisms, and a careful server uses both.

The ADD_DEV round trip#

UBLK_U_CMD_ADD_DEV takes a struct ublksrv_ctrl_dev_info by pointer. The server fills in flags with what it wants; the kernel validates the request, edits flags, and copies the whole structure back before the command completes. The returned flags are the device’s features for its entire life. Nothing changes them later.

Unknown bits do not fail the command. The kernel masks the request with its compiled-in UBLK_F_ALL, so a flag the running kernel has never heard of is silently cleared. Always compare the returned flags with the ones you asked for and treat a missing bit as “not supported here”.

In the 7.3-rc5 driver, ublk_ctrl_add_dev() applies these rules in order (6.17 has the same list minus the integrity, descriptor-size and batch items):

  1. Privilege. A caller with CAP_SYS_ADMIN always gets a privileged device: UBLK_F_UNPRIVILEGED_DEV is cleared. A caller without it must set UBLK_F_UNPRIVILEGED_DEV, or the command fails with -EPERM.
  2. Recovery combinations. The recovery bits must be one of: none, USER_RECOVERY, USER_RECOVERY | USER_RECOVERY_REISSUE, or USER_RECOVERY | USER_RECOVERY_FAIL_IO. Anything else (for example REISSUE without USER_RECOVERY, or both modifiers) is -EINVAL.
  3. Quiesce. UBLK_F_QUIESCE without UBLK_F_USER_RECOVERY is -EINVAL.
  4. Unprivileged restrictions. For an unprivileged device the kernel silently drops USER_RECOVERY and USER_RECOVERY_REISSUE, and rejects USER_COPY, SUPPORT_ZERO_COPY or AUTO_BUF_REG with -EINVAL, because each of those would let an untrusted server leave kernel memory uninitialized in a READ.
  5. Integrity. UBLK_F_INTEGRITY without UBLK_F_USER_COPY is -EINVAL.
  6. Descriptor size. With UBLK_F_IO_DESC_SIZE, io_desc_size must be at least 24, a multiple of 8, and at most 256, or -EINVAL. Without it, the kernel sets io_desc_size to 24.
  7. Masking. flags &= UBLK_F_ALL. UBLK_F_INTEGRITY is only in UBLK_F_ALL when the kernel is built with CONFIG_BLK_DEV_INTEGRITY.
  8. Forced capability bits. The kernel ORs in CMD_IOCTL_ENCODE (6.4+), URING_CMD_COMP_IN_TASK (6.5+), PER_IO_DAEMON (6.16+) and BUF_REG_OFF_DAEMON (6.17+), and since 7.0 also SAFE_STOP_DEV. These report what the driver does; they do not select anything.
  9. Batch cleanup. With UBLK_F_BATCH_IO, PER_IO_DAEMON and NEED_GET_DATA are cleared again: batch mode has no per-I/O daemons and no get-data step.
  10. Copy-mode cleanup. NEED_GET_DATA is cleared if USER_COPY, SUPPORT_ZERO_COPY or AUTO_BUF_REG is set, since none of those modes copies WRITE data at all.
  11. Zoned. UBLK_F_ZONED requires a kernel built with CONFIG_BLK_DEV_ZONED and either USER_COPY or SUPPORT_ZERO_COPY; otherwise -EINVAL.

GET_FEATURES#

Linux 6.5+ UBLK_U_CMD_GET_FEATURES returns the kernel’s whole UBLK_F_ALL mask: every flag this kernel knows, independent of any device. Point addr at an 8-byte buffer and set len to exactly UBLK_FEATURES_LEN (8); any other length is -EINVAL. The driver handles it before looking up a device or checking permissions, so dev_id is ignored and anyone who can open /dev/ublk-control may ask.

__u64 features = 0;
struct ublksrv_ctrl_cmd c = {
	.dev_id   = (__u32)-1,
	.queue_id = (__u16)-1,
	.addr     = (__u64)(uintptr_t)&features,
	.len      = UBLK_FEATURES_LEN,          /* must be exactly 8 */
};
int res = ctrl_cmd(ctrl_ring, UBLK_U_CMD_GET_FEATURES, &c); /* 0x80207513 */
if (res < 0)
	features = 0;   /* pre-6.5 kernel: fall back to probing with ADD_DEV */

On kernels older than 6.5 the opcode is not recognized. Because the old driver looks the device up by dev_id before dispatching, the error is typically -ENODEV rather than -EOPNOTSUPP; treat any failure as “no GET_FEATURES”. (With a dev_id that names an existing device, 6.3 and 6.4 return -ENOTSUPP, 524; 6.0 to 6.2 return -EPERM to a caller without CAP_SYS_ADMIN.)

The two mechanisms answer different questions. GET_FEATURES says what the driver supports in general, which is what you want before deciding how to configure a device. The ADD_DEV result says what this particular device got after validation, privilege checks and kernel configuration, which is what you must actually honor.

All flags at a glance#

“Since” is the first mainline release whose UAPI header defines the flag. Requirements are enforced by the kernel unless marked as convention.

BitFlagSinceWhat it doesRequires / excludesChapter
0UBLK_F_SUPPORT_ZERO_COPY6.0 (works from 6.15)Zero copy through io_uring fixed buffers: REGISTER_IO_BUF / UNREGISTER_IO_BUFExcludes unprivilegedData copy
1UBLK_F_URING_CMD_COMP_IN_TASK6.0Complete I/O commands with io_uring_cmd_complete_in_taskForced on by current kernelsbelow
2UBLK_F_NEED_GET_DATA6.0Deliver WRITEs without data; server supplies a buffer with NEED_GET_DATACleared by any non-copy modeData copy
3UBLK_F_USER_RECOVERY6.1Keep the device across a server exit; recover with a new serverDropped for unprivilegedRecovery
4UBLK_F_USER_RECOVERY_REISSUE6.1On server exit, requeue I/O the server had received instead of failing itUSER_RECOVERY; not with FAIL_IORecovery
5UBLK_F_UNPRIVILEGED_DEV6.3Device created and controlled by a non-root ownerExcludes user copy and zero copyUnprivileged
6UBLK_F_CMD_IOCTL_ENCODE6.4Commands use ioctl-encoded UBLK_U_* opcodesForced onbelow
7UBLK_F_USER_COPY6.5Server copies data with pread/pwrite on /dev/ublkcNExcludes unprivilegedData copy
8UBLK_F_ZONED6.6Zoned block device: zone ops, REPORT_ZONES, zone appendUSER_COPY or SUPPORT_ZERO_COPYZoned
9UBLK_F_USER_RECOVERY_FAIL_IO6.13With no server, fail new I/O immediately instead of queueing itUSER_RECOVERY; not with REISSUERecovery
10UBLK_F_UPDATE_SIZE6.16Resize a live device with UBLK_U_CMD_UPDATE_SIZEbelow
11UBLK_F_AUTO_BUF_REG6.16Kernel registers each request buffer in the server’s io_uring automaticallyExcludes unprivilegedData copy
12UBLK_F_QUIESCE6.16Enables UBLK_U_CMD_QUIESCE_DEV for planned server handoverUSER_RECOVERYRecovery
13UBLK_F_PER_IO_DAEMON6.16Each (queue, tag) may be served by its own taskForced on, except with BATCH_IObelow
14UBLK_F_BUF_REG_OFF_DAEMON6.17REGISTER_IO_BUF / UNREGISTER_IO_BUF from any taskForced onData copy
15UBLK_F_BATCH_IO7.0Per-queue batch commands replace per-tag FETCH and COMMITExcludes the per-tag commands; clears PER_IO_DAEMON and NEED_GET_DATABatch I/O
16UBLK_F_INTEGRITY7.0Requests carry integrity (protection information) buffersUSER_COPY; kernel with CONFIG_BLK_DEV_INTEGRITYIntegrity
17UBLK_F_SAFE_STOP_DEV7.0Advertises UBLK_U_CMD_TRY_STOP_DEV: stop only if nobody has the disk openForced on in 7.3below
18UBLK_F_NO_AUTO_PART_SCAN7.0Do not scan for partitions when the device startsbelow
19UBLK_F_SHMEM_ZC7.1Shared-memory zero copy via UBLK_U_CMD_REG_BUFAllowed for unprivilegedData copy
20UBLK_F_IO_DESC_SIZE7.3Server-chosen descriptor slot size in ublksrv_ctrl_dev_info.io_desc_size24 to 256, multiple of 8below

Data copy flags#

These decide how request data moves between the block request and the server. Exactly one mode applies to a device: the default copy, NEED_GET_DATA, USER_COPY, or zero copy (SUPPORT_ZERO_COPY and/or AUTO_BUF_REG). SHMEM_ZC is a fast path layered on top. The data copy chapter covers each mode in full; this is the short version.

  • UBLK_F_SUPPORT_ZERO_COPY (bit 0). The bit was reserved in 6.0 but did nothing useful until 6.15 added UBLK_U_IO_REGISTER_IO_BUF and UBLK_U_IO_UNREGISTER_IO_BUF. The server installs a request’s pages into an io_uring sparse buffer table and points *_FIXED operations at them; the server’s own code never touches the data. With this flag, FETCH_REQ and COMMIT_AND_FETCH_REQ must pass addr = 0; a non-zero address is -EINVAL.
  • UBLK_F_NEED_GET_DATA (bit 2). A WRITE first arrives with UBLK_IO_RES_NEED_GET_DATA (1) and no data; the server answers with UBLK_U_IO_NEED_GET_DATA carrying a buffer address, and only then does the kernel copy. One extra round trip per WRITE. It exists for servers that cannot pre-allocate per-tag buffers; new servers should not use it.
  • UBLK_F_USER_COPY (bit 7). The kernel never copies. The server reads WRITE data with pread() and supplies READ data with pwrite() on /dev/ublkcN, at an offset that encodes queue, tag and byte offset. Fetch and commit pass addr = 0.
  • UBLK_F_AUTO_BUF_REG (bit 11). Like zero copy, but the kernel registers the request buffer into the server’s io_uring before delivering the request and unregisters it at commit, removing two commands per I/O. The buffer index travels in the FETCH_REQ / COMMIT_AND_FETCH_REQ SQE’s addr field as a struct ublk_auto_buf_reg.
  • UBLK_F_BUF_REG_OFF_DAEMON (bit 14). Lets any task, not only the tag’s daemon, issue REGISTER_IO_BUF and UNREGISTER_IO_BUF; UNREGISTER_IO_BUF then ignores q_id and tag. Forced on since it was introduced in 6.17, so it only tells you the kernel behaves this way.
  • UBLK_F_SHMEM_ZC (bit 19). The server registers shared memory (memfd, hugetlbfs) with UBLK_U_CMD_REG_BUF. When an O_DIRECT request’s pages are inside a registered buffer, the descriptor carries UBLK_IO_F_SHMEM_ZC and addr encodes buffer index and offset instead of a server address. Requests that do not match fall back to the normal path silently. Unlike the other zero-copy modes, the kernel accepts it on unprivileged devices.

Recovery flags#

These decide what happens when the server process exits while the device is live. The recovery chapter has the state machine and the full sequence.

  • UBLK_F_USER_RECOVERY (bit 3). Without it, a server exit stops the device: /dev/ublkbN disappears and every pending request fails. With it, the device stays, moves to UBLK_S_DEV_QUIESCED, queues new I/O, and fails the requests the server had already received. A new server takes over with START_USER_RECOVERY and END_USER_RECOVERY.
  • UBLK_F_USER_RECOVERY_REISSUE (bit 4). Same, but requests the dead server had received are requeued and later reissued to the new server. That can execute a write twice, so use it only for backends where a repeated write is harmless.
  • UBLK_F_USER_RECOVERY_FAIL_IO (bit 9, 6.13). The device stays but enters UBLK_S_DEV_FAIL_IO: all I/O, old and new, fails immediately until a new server recovers it. Applications see errors instead of hanging.
  • UBLK_F_QUIESCE (bit 12, 6.16). Enables UBLK_U_CMD_QUIESCE_DEV, which quiesces a live device on request so a new server can take over without the old one crashing. data[0] is a timeout in milliseconds, 0 meaning forever; the command returns -EBUSY if no tag on some queue goes idle in time. The kernel only accepts this flag together with USER_RECOVERY.

Recovery flags are not available for unprivileged devices: the kernel clears USER_RECOVERY and REISSUE rather than failing ADD_DEV, so check the returned flags.

Protocol and threading flags#

  • UBLK_F_URING_CMD_COMP_IN_TASK (bit 1). In the original driver this chose between two ways of completing an I/O command in the daemon’s context (task_work_add versus io_uring_cmd_complete_in_task), mainly for benchmarking. Current drivers always use the io_uring path and force the bit on, so requesting it changes nothing (the task_work_add path was removed in 6.5; 6.1 to 6.4 already forced the bit for modular builds).
  • UBLK_F_CMD_IOCTL_ENCODE (bit 6, 6.4). Marks a kernel that understands the ioctl-encoded UBLK_U_CMD_* and UBLK_U_IO_* opcodes, for example UBLK_U_CMD_ADD_DEV = _IOWR('u', 0x04, struct ublksrv_ctrl_cmd) = 0xc0207504. The driver forces the bit on; whether the old raw opcodes (UBLK_CMD_ADD_DEV = 0x04) are still accepted depends on CONFIG_BLKDEV_UBLK_LEGACY_OPCODES. Commands added after 6.4, such as GET_FEATURES, exist only in encoded form. Use the encoded opcodes. The bit has been forced on since 6.4.
  • UBLK_F_PER_IO_DAEMON (bit 13, 6.16). The task that issues FETCH_REQ for a (queue, tag) pair becomes that I/O’s daemon, and only it may issue later commands for the pair. Before 6.16 the daemon was per queue, so one thread had to own every tag of a queue. With per-I/O daemons a server can spread one queue’s tags across several threads. Forced on, except on batch-mode devices, which have no daemons at all.
  • UBLK_F_BATCH_IO (bit 15, 7.0). Replaces the per-tag FETCH_REQ / COMMIT_AND_FETCH_REQ / NEED_GET_DATA commands with per-queue batch commands: PREP_IO_CMDS, COMMIT_IO_CMDS and a multishot FETCH_IO_CMDS. There are no per-I/O daemons in batch mode; any task may handle any tag. See Batch I/O.

Device feature flags#

  • UBLK_F_UNPRIVILEGED_DEV (bit 5, 6.3). Lets a user without CAP_SYS_ADMIN create a device they own. Every control command except ADD_DEV must then carry the path of /dev/ublkcN so the kernel can check the caller’s permission on it. Unprivileged devices cannot use user copy, zero copy or recovery, and the kernel suppresses partition scanning whenever any queue is served by a task without CAP_SYS_ADMIN. See Unprivileged devices.
  • UBLK_F_ZONED (bit 8, 6.6). Exposes a host-managed zoned device: zone open, close, finish, reset and reset-all, zone append, and REPORT_ZONES requests reach the server. Requires UBLK_PARAM_TYPE_ZONED parameters, a non-zero chunk_sectors, and USER_COPY or SUPPORT_ZERO_COPY. See Zoned devices.
  • UBLK_F_UPDATE_SIZE (bit 10, 6.16). Advertises UBLK_U_CMD_UPDATE_SIZE, which sets a started device’s capacity to data[0] 512-byte sectors and notifies userspace with a resize uevent. Neither 6.17 nor 7.3-rc5 checks the flag when handling the command, so treat it as a capability bit and request it anyway. On a device that has not been started, 7.3-rc5 returns -ENODEV.
  • UBLK_F_INTEGRITY (bit 16, 7.0). Requests can carry an integrity (protection information) buffer, flagged with UBLK_IO_F_INTEGRITY and copied with pread/pwrite using UBLKSRV_IO_INTEGRITY_FLAG in the offset. Requires USER_COPY and UBLK_PARAM_TYPE_INTEGRITY. See Integrity metadata.
  • UBLK_F_SAFE_STOP_DEV (bit 17, 7.0). Advertises UBLK_U_CMD_TRY_STOP_DEV (0xc0207517), a stop that fails with -EBUSY if anything has /dev/ublkbN open, instead of tearing the disk out from under a mounted filesystem. If nothing has it open, the kernel blocks new opens and stops the device exactly like STOP_DEV. A device that is not started returns -ENODEV. 7.3-rc5 forces the bit on and does not check it when handling the command.
  • UBLK_F_NO_AUTO_PART_SCAN (bit 18, 7.0). Turns off the partition scan that normally follows START_DEV. Since 6.19 the scan no longer runs inside START_DEV: the kernel suppresses it while adding the disk, to avoid a deadlock if the server fails mid-scan, and then schedules it asynchronously for trusted servers (earlier kernels scanned synchronously inside add_disk, so the server saw READs while START_DEV was in flight). With this flag the asynchronous scan is skipped and the suppression is lifted, so a later manual rescan (partprobe, BLKRRPART) still works. Partition scanning stays off permanently when any queue is served by a task without CAP_SYS_ADMIN (since 7.0-rc4).
  • UBLK_F_IO_DESC_SIZE (bit 20, 7.3). The server chooses the size of each descriptor slot in ublksrv_ctrl_dev_info.io_desc_size, the 16-bit field at offset 6 that was pad0 before 7.3: at least 24 (sizeof(struct ublksrv_io_desc)), a multiple of 8, at most 256. Without the flag the kernel reports 24 there. The descriptor for tag t is at t * io_desc_size, a queue’s mmap length is round_up(queue_depth * io_desc_size, PAGE_SIZE), and the per-queue mmap stride becomes round_up(UBLK_MAX_QUEUE_DEPTH * io_desc_size, PAGE_SIZE). In 7.3 the kernel fills only the 24-byte struct ublksrv_io_desc in each slot; the rest is padding, which lets a server avoid false sharing between descriptors served by different threads and leaves room for future fields.

go-ublk#

go-ublk calls GET_FEATURES before every ADD_DEV and compares the request against it. A requested feature the kernel does not list fails Create with an error that wraps syscall.EOPNOTSUPP and names the missing flags, before anything is created. The flags ADD_DEV returns are checked again, so a feature the kernel silently clears is an error too, never a quietly weaker device. On kernels without GET_FEATURES (before 6.5) the check happens only after ADD_DEV.

Each DeviceParams option maps to its flag: Recovery to the USER_RECOVERY family, EnableZeroCopy, EnableUserCopy, EnableUnprivileged, EnableZoned, Integrity, NeedGetData, BatchIO, ThreadsPerQueue (PER_IO_DAEMON), SharedMemoryZeroCopy, SafeStop, NoPartitionScan and IODescSize. Three flags are requested whenever the kernel has them, because they cost nothing: UPDATE_SIZE (for Device.Resize), QUIESCE on recoverable devices (for Device.Detach), and AUTO_BUF_REG with zero copy. go-ublk always sends ioctl-encoded opcodes and does not request CMD_IOCTL_ENCODE or URING_CMD_COMP_IN_TASK, which the kernel forces on.

ublk.Probe() reports what the running kernel supports, and Device.Features() what a device was granted.

Reference table#

Every feature flag with its value, introducing release and go-ublk status. Expand a row for details.

Generated from include/uapi/linux/ublk_cmd.h at Linux v7.3-rc5 on 2026-10-04. 21 feature flags.

go-ublk
NameValueSinceSummarygo-ublk
UBLK_F_SUPPORT_ZERO_COPY 1ULL<<0 (0x1) 6.0 Zero copy via io_uring kernel fixed buffers (REGISTER/UNREGISTER_IO_BUF).
Details

Reserved in v6.0 but stripped by ADD_DEV (flags &= ~UBLK_F_SUPPORT_ZERO_COPY, “We are not ready to support zero copy”) on every kernel through v6.14. Functional since v6.15 (1f6540e2aabb): the kernel no longer copies data to/from the server buffer (ublk_need_map_io() false), FETCH/COMMIT must pass addr = 0, and the server reaches request pages only through REGISTER_IO_BUF + fixed-buffer io_uring ops. Decoupled from USER_COPY in v6.15-rc5 (69edf98be844). The server should align ublk_param_dma_align and ublk_param_segment with its backend. Clears NEED_GET_DATA.

Conflicts with
UBLK_F_UNPRIVILEGED_DEV
Notes
On 6.0–6.14 the bit is silently dropped from the negotiated flags, so check the written-back flags.
Commit
71f28f3136af
go-ublk
DeviceParams.EnableZeroCopy with a ZeroCopyBackend (a backing file): the engine registers each request buffer (AUTO_BUF_REG when the kernel lists it, otherwise REGISTER_IO_BUF + linked UNREGISTER_IO_BUF) and reads/writes the file with fixed-buffer ops, fdatasync and fallocate on the queue’s ring. Not offered to Handlers; excludes user copy, NEED_GET_DATA and unprivileged.
supported
UBLK_F_URING_CMD_COMP_IN_TASK 1ULL<<1 (0x2) 6.0 Always dispatch requests to the server via io_uring_cmd_complete_in_task().
Details

v6.0–v6.4: selected io_uring_cmd_complete_in_task() instead of task_work_add() for dispatch (task_work_add was only usable when ublk_drv was built in; for a module the flag was forced on since v6.1-rc4, 224e858f215a). v6.5 removed the task_work_add path (29dc5d06613f) and forces the flag on in every ADD_DEV reply; it has no effect since.

Notes
Informational only on v6.5+.
Commit
0edb3696c171
go-ublk
Not requested; the kernel forces it on and ignores it since 6.5.
n/a
UBLK_F_NEED_GET_DATA 1ULL<<2 (0x4) 6.0 Two-phase WRITE: deliver WRITEs without data, server supplies the buffer with UBLK_U_IO_NEED_GET_DATA.
Details

For WRITE requests (v6.0–v6.3 also FLUSH) the FETCH/COMMIT CQE returns UBLK_IO_RES_NEED_GET_DATA; the server allocates a buffer and issues NEED_GET_DATA, the kernel copies the payload and completes it with UBLK_IO_RES_OK. FETCH may pass addr = 0; COMMIT may pass addr = 0 unless the request is a READ. Cleared by ADD_DEV when combined with USER_COPY (v6.5+), SUPPORT_ZERO_COPY or AUTO_BUF_REG (v6.15/6.16+) or BATCH_IO (v7.0+).

Conflicts with
UBLK_F_USER_COPY, UBLK_F_SUPPORT_ZERO_COPY, UBLK_F_AUTO_BUF_REG, UBLK_F_BATCH_IO
Notes
Added for servers with existing buffer management; costs an extra round trip per WRITE.
Commit
4e18403d9485
go-ublk
DeviceParams.NeedGetData; the engine issues NEED_GET_DATA.
supported
UBLK_F_USER_RECOVERY 1ULL<<3 (0x8) 6.1 Keep the device (and /dev/ublkbN) when the server dies so a new server can recover it.
Details

When the server exits, ublk_ch_release_work_fn aborts what the server held and moves the device to UBLK_S_DEV_QUIESCED (or FAIL_IO with RECOVERY_FAIL_IO) instead of stopping it. Requests issued to the server are failed with EIO (default), requeued (REISSUE) or failed (FAIL_IO); new requests are requeued (default/REISSUE) or failed with BLK_STS_TARGET (FAIL_IO). A new server recovers with START_USER_RECOVERY, re-opens/mmaps /dev/ublkcN, fetches every tag, then END_USER_RECOVERY. Silently cleared for unprivileged devices. Full protocol and version history: semantics.md §9.

Conflicts with
UBLK_F_UNPRIVILEGED_DEV
Notes
Recovery was reworked in v6.15 (detection moved to char-device release; reset moved out of START_USER_RECOVERY). Known unfixed-before-v7.1 UAF on the recovery reset path: f7700a4415af.
Commit
77a440e2cbb4
go-ublk
DeviceParams.Recovery (RecoveryQueue / RecoveryReissue / RecoveryFailIO), Device.Detach, ublk.Recover.
supported
UBLK_F_USER_RECOVERY_REISSUE 1ULL<<4 (0x10) 6.1 With USER_RECOVERY: requeue (re-issue) requests that were with the dead server.
Details

__ublk_fail_req requeues instead of failing outstanding requests (ublk_nosrv_should_reissue_outstanding), so the new server sees them again after END_USER_RECOVERY. The backend must tolerate a write being applied twice. Silently cleared for unprivileged devices. Only valid together with USER_RECOVERY and not with FAIL_IO (EINVAL since v6.13, d00c0ea17955).

Requires
UBLK_F_USER_RECOVERY
Conflicts with
UBLK_F_USER_RECOVERY_FAIL_IO
Commit
a0d41dc11374
go-ublk
RecoveryReissue.
supported
UBLK_F_UNPRIVILEGED_DEV 1ULL<<5 (0x20) 6.3 Let a non-root user create and own a device.
Details

ADD_DEV without CAP_SYS_ADMIN requires this flag (else EPERM); with CAP_SYS_ADMIN the flag is cleared. The kernel records the caller’s uid/gid; every later control command must carry the /dev/ublkcN path prefix (dev_path_len) and pass an inode permission check; only the owner may open /dev/ublkbN (v6.3, 48a905198024); partitions are never scanned; an I/O timeout SIGKILLs the server (v6.4, c0b79b0ff53b); at most ublks_max (default 64) such devices exist. USER_RECOVERY/REISSUE are silently dropped; USER_COPY (v6.12, 42aafd8b48ad, 6.6.58), SUPPORT_ZERO_COPY (v6.15) and AUTO_BUF_REG (v6.16) are rejected. Needs a udev rule making /dev/ublk-control accessible and chowning ublkc*/ublkb* to owner_uid/gid.

Conflicts with
UBLK_F_USER_COPY, UBLK_F_SUPPORT_ZERO_COPY, UBLK_F_AUTO_BUF_REG, UBLK_F_USER_RECOVERY
Notes
Before v6.12 an unprivileged USER_COPY server could leak uninitialized kernel memory by under-filling READs.
Commit
4093cb5a0634
go-ublk
DeviceParams.EnableUnprivileged; every control command gets the path prefix automatically (ctrl.devRequest).
supported
UBLK_F_CMD_IOCTL_ENCODE 1ULL<<6 (0x40) 6.4 Advertises that the kernel accepts ioctl-encoded (UBLK_U_*) opcodes.
Details

Set in every ADD_DEV reply since v6.4 (flags |= UBLK_F_CMD_IOCTL_ENCODE); the driver never reads the bit from the request. Its presence in GET_FEATURES / the ADD_DEV reply is how a server knows UBLK_U_* opcodes work.

Commit
2d786e66c966
go-ublk
Always requested; go-ublk sends only ioctl-encoded opcodes.
supported
UBLK_F_USER_COPY 1ULL<<7 (0x80) 6.5 Move data with pread()/pwrite() on /dev/ublkcN instead of kernel copies into a server buffer.
Details

The kernel never touches the server buffer; FETCH/COMMIT pass addr = 0 (except ZONE_APPEND’s LBA). The server copies with pread/pwrite (or io_uring READ/WRITE) at offset UBLKSRV_IO_BUF_OFFSET + (q_id << UBLK_QID_OFF) + (tag << UBLK_TAG_OFF) + byte_offset (+ UBLKSRV_IO_INTEGRITY_FLAG for the integrity buffer): read() copies a WRITE/ZONE_APPEND payload out, write() fills a READ/REPORT_ZONES. Allowed only while the server owns the request. Required by ZONED (or ZERO_COPY) and INTEGRITY. Rejected for unprivileged devices since v6.12. Details: semantics.md §5.

Conflicts with
UBLK_F_UNPRIVILEGED_DEV, UBLK_F_NEED_GET_DATA
Notes
Per-request data is limited to 32 MiB by the 25-bit offset field.
Commit
1172d5b8beca
go-ublk
DeviceParams.EnableUserCopy; the engine pread/pwrites on the char fd.
supported
UBLK_F_ZONED 1ULL<<8 (0x100) 6.6 Zoned block device (host-managed) support.
Details

Requires CONFIG_BLK_DEV_ZONED and USER_COPY or SUPPORT_ZERO_COPY (ADD_DEV EINVAL otherwise) and UBLK_PARAM_TYPE_ZONED params (with chunk_sectors = zone size, a power of two). Adds the zone operations, UBLK_IO_OP_REPORT_ZONES (server fills a struct blk_zone array), and zone append, whose written sector is returned in COMMIT’s zone_append_lba.

Requires
UBLK_F_USER_COPY
Notes
UBLK_F_SUPPORT_ZERO_COPY also satisfies the requirement (v6.15+).
Commit
29802d7ca33b
go-ublk
DeviceParams.EnableZoned + Zoned (zone size, open/active limits, max append); Handler-only (zone ops, Request.ReportZones, CompleteZoneAppend); user copy is turned on automatically.
supported
UBLK_F_USER_RECOVERY_FAIL_IO 1ULL<<9 (0x200) 6.13 With USER_RECOVERY: fail all I/O while no server is attached, instead of queueing it.
Details

After the server dies the device goes to UBLK_S_DEV_FAIL_IO: outstanding requests fail with EIO, new requests fail immediately with BLK_STS_TARGET (ublk_prep_req), until a new server completes recovery. Valid only with USER_RECOVERY and not with REISSUE.

Requires
UBLK_F_USER_RECOVERY
Conflicts with
UBLK_F_USER_RECOVERY_REISSUE
Commit
59eaa01ce7a6
go-ublk
RecoveryFailIO.
supported
UBLK_F_UPDATE_SIZE 1ULL<<10 (0x400) 6.16 Advertises UBLK_U_CMD_UPDATE_SIZE (online resize).
Details

Purely informational: the driver does not check the bit when handling UPDATE_SIZE.

Commit
98b995660bff
go-ublk
Requested when the kernel lists it; Device.Resize.
supported
UBLK_F_AUTO_BUF_REG 1ULL<<11 (0x800) 6.16 Zero copy without explicit commands: register each request buffer automatically before dispatch.
Details

FETCH/COMMIT pass a ublk_auto_buf_reg in sqe->addr (index + flags, reserved fields 0, else EINVAL). Before completing the fetch CQE the kernel registers the request bvec at that index in the same io_uring’s sparse buffer table and unregisters it at COMMIT (if COMMIT goes to the same ring; otherwise the server must UNREGISTER_IO_BUF). If registration fails: with UBLK_AUTO_BUF_REG_FALLBACK the CQE is delivered with UBLK_IO_F_NEED_REG_BUF set in the descriptor; without it the request is failed with EIO and the uring_cmd stays pending. Compatible with SUPPORT_ZERO_COPY; clears NEED_GET_DATA; rejected for unprivileged devices.

Conflicts with
UBLK_F_UNPRIVILEGED_DEV, UBLK_F_NEED_GET_DATA
Notes
Buffer table max 16K entries per io_uring.
Commit
99c1e4eb6a3f
go-ublk
Requested automatically with EnableZeroCopy when the kernel lists it; FETCH/COMMIT carry {Index: tag, Flags: UBLK_AUTO_BUF_REG_FALLBACK} and a request arriving with UBLK_IO_F_NEED_REG_BUF is registered manually.
supported
UBLK_F_QUIESCE 1ULL<<12 (0x1000) 6.16 Enables UBLK_U_CMD_QUIESCE_DEV (drain for live server upgrade).
Details

Must be combined with USER_RECOVERY (ADD_DEV EINVAL otherwise). QUIESCE_DEV returns EOPNOTSUPP without it.

Requires
UBLK_F_USER_RECOVERY
Commit
b465ae7b2524
go-ublk
Requested with any RecoveryMode when the kernel lists it; used by Device.Detach.
supported
UBLK_F_PER_IO_DAEMON 1ULL<<13 (0x2000) 6.16 Each (queue, tag) may have its own daemon task instead of one task per queue.
Details

Capability flag: v6.16+ always report it (except with BATCH_IO, where the kernel clears it since there is no daemon at all). The task that issues a tag’s FETCH_REQ owns that tag; other tags of the same queue can be served by other tasks, so a server can spread one hot queue over several threads. On older kernels all tags of a queue must be served by one task.

Conflicts with
UBLK_F_BATCH_IO
Commit
ab03a61c6614
go-ublk
DeviceParams.ThreadsPerQueue > 1 splits a queue’s tags across engines (requires the flag).
supported
UBLK_F_BUF_REG_OFF_DAEMON 1ULL<<14 (0x4000) 6.17 REGISTER/UNREGISTER_IO_BUF may be issued from any task.
Details

Capability flag always reported since v6.17. UNREGISTER_IO_BUF also ignores q_id/tag.

Requires
UBLK_F_SUPPORT_ZERO_COPY
Commit
763ff02ce287
go-ublk
go-ublk issues REGISTER/UNREGISTER_IO_BUF on the tag’s own engine thread, so it never needs off-daemon registration.
n/a
UBLK_F_BATCH_IO 1ULL<<15 (0x8000) 7.0 Per-queue batch I/O commands (PREP/COMMIT/FETCH_IO_CMDS) replace per-tag FETCH/COMMIT.
Details

The device’s char node uses ublk_ch_batch_io_fops; per-tag FETCH_REQ/COMMIT_AND_FETCH_REQ/NEED_GET_DATA are rejected; REGISTER/UNREGISTER_IO_BUF still work. No daemon task: any task can serve any tag. Clears PER_IO_DAEMON and NEED_GET_DATA. FETCH_IO_CMDS needs multishot uring_cmd (v6.18+ io_uring) and provided buffer rings. Protocol: semantics.md §8.

Conflicts with
UBLK_F_NEED_GET_DATA, UBLK_F_PER_IO_DAEMON
Notes
Several recovery fixes landed after 7.0 (e4c4bfec2bb8, 8a14be55bdc6 [7.2.7]).
Commit
e2723e6ce602
go-ublk
DeviceParams.BatchIO (copy and user-copy modes; not with zero copy).
supported
UBLK_F_INTEGRITY 1ULL<<16 (0x10000) 7.0 Requests may carry an integrity/metadata (PI) buffer.
Details

Requires USER_COPY (ADD_DEV EINVAL) and a kernel with CONFIG_BLK_DEV_INTEGRITY (otherwise absent from UBLK_F_ALL). Configure with UBLK_PARAM_TYPE_INTEGRITY; requests with metadata have UBLK_IO_F_INTEGRITY set and the server reads/writes the metadata with pread/pwrite at the user-copy offset OR’ed with UBLKSRV_IO_INTEGRITY_FLAG (bit 62).

Requires
UBLK_F_USER_COPY
Commit
98bf2256855e
go-ublk
DeviceParams.Integrity (IntegrityParams: metadata size, interval, checksum, reftag, PI offset, tag size); user copy forced on; Backends implement IntegrityBackend, Handlers get Request.Integrity.
supported
UBLK_F_SAFE_STOP_DEV 1ULL<<17 (0x20000) 7.0 Advertises UBLK_U_CMD_TRY_STOP_DEV.
Details

Always reported since v7.0.

Commit
93ada1b3da39
go-ublk
DeviceParams.SafeStop -> TRY_STOP_DEV.
supported
UBLK_F_NO_AUTO_PART_SCAN 1ULL<<18 (0x40000) 7.0 Do not scan partitions when the device starts.
Details

START_DEV skips the async partition scan and clears GD_SUPPRESS_PART_SCAN (only for trusted daemons; v7.0-rc4 155a3bedccaf) so a later BLKRRPART works.

Commit
8443e2087e70
go-ublk
DeviceParams.NoPartitionScan.
supported
UBLK_F_SHMEM_ZC 1ULL<<19 (0x80000) 7.1 Shared-memory zero copy: requests whose pages lie in a registered buffer arrive by reference.
Details

The server registers memfd/hugetlbfs memory it shares with clients via UBLK_U_CMD_REG_BUF. When a request’s pages all fall contiguously inside one registered buffer (PFN maple-tree match, ublk_try_buf_match) the descriptor gets UBLK_IO_F_SHMEM_ZC and addr = ublk_shmem_zc_addr(index, offset); no copy happens in either direction. Non-matching requests use the normal path. A READ_ONLY buffer only matches WRITEs. Only O_DIRECT client I/O can match.

Commit
08677040a911
go-ublk
DeviceParams.SharedMemoryZeroCopy; requests in registered regions arrive with FlagSharedMemory and Data pointing into the region.
supported
UBLK_F_IO_DESC_SIZE 1ULL<<20 (0x100000) 7.3-rc1 Server chooses the per-tag descriptor stride (ublksrv_ctrl_dev_info.io_desc_size).
Details

With the flag, ADD_DEV takes io_desc_size (24..256, multiple of 8) from dev_info (former pad0); otherwise it is set to 24. The mmapped descriptor array uses that stride: descriptor of tag t at t * io_desc_size, mmap length round_up(depth * io_desc_size, PAGE_SIZE), and queue q at offset q * round_up(4096 * io_desc_size, PAGE_SIZE). Bytes past the 24-byte ublksrv_io_desc are reserved for future kernel fields.

Notes
Unreleased as of 2026-10-04 (v7.3-rc).
Commit
5c0958d80190
go-ublk
DeviceParams.IODescSize; the engine honors the stride and exposes the extra bytes as Request.DescriptorExtra.
supported