xtc_bdev(3)

---

xtc_bdev(3)

portable block-device I/O over async fibers

XTC_BDEV(3) Library Functions Manual XTC_BDEV(3)

xtc_bdev_open, xtc_bdev_close, xtc_bdev_logical_sector, xtc_bdev_physical_sector, xtc_bdev_capacity, xtc_bdev_pread, xtc_bdev_pwrite, xtc_bdev_flushportable block-device I/O over async fibers

#include <xtc.h>
#include <xtc_bdev.h>

int
xtc_bdev_open(const char *path, int flags, xtc_bdev_t **out);

void
xtc_bdev_close(xtc_bdev_t *b);

uint32_t
xtc_bdev_logical_sector(const xtc_bdev_t *b);

uint32_t
xtc_bdev_physical_sector(const xtc_bdev_t *b);

uint64_t
xtc_bdev_capacity(const xtc_bdev_t *b);

ssize_t
xtc_bdev_pread(xtc_bdev_t *b, void *buf, size_t n, uint64_t off);

ssize_t
xtc_bdev_pwrite(xtc_bdev_t *b, const void *buf, size_t n, uint64_t off);

int
xtc_bdev_flush(xtc_bdev_t *b);

These provide a small, uniform surface for reading and writing a raw block device -- or a regular file treated as one -- with sector-aligned positioned I/O that suspends the calling fiber and resumes it on completion, keeping the fiber's loop live for other work while the I/O is outstanding. They are built directly on xtc_aio(3) and inherit its model: the read and write hot path routes through () and (), and the flush through ().

() opens path and probes its geometry, storing the handle in out. flags is a mask of XTC_BDEV_READ and XTC_BDEV_WRITE. The probe uses the host's native query:

  • Linux: BLKSSZGET (logical sector), BLKPBSZGET (physical sector), BLKGETSIZE64 (capacity); a real device is opened O_DIRECT so transfers bypass the page cache.
  • FreeBSD and macOS: DIOCGSECTORSIZE and DIOCGMEDIASIZE (the Darwin block-size / block-count IOCTLs on macOS).
  • illumos and Solaris: DKIOCGMEDIAINFO.
  • Windows: IOCTL_DISK_GET_DRIVE_GEOMETRY_EX (presently a defaults-returning stub).
  • Fallback -- a regular file or an unqueryable target: logical 512, physical 4096, capacity from fstat(2), buffered I/O.

() closes the device and frees the handle; NULL is a no-op.

(), (), and () report the probed logical sector size, physical sector size, and total capacity in bytes.

() reads n bytes into buf, and () writes n bytes from buf, at absolute byte offset off. Both off and n must be multiples of the logical sector size; a misaligned request returns XTC_E_INVAL before any I/O is issued. () flushes the device's data and metadata durably.

xtc_bdev_pread() and xtc_bdev_pwrite() return the number of bytes transferred (>= 0); a short read at end of device returns the partial count. On failure they return a negative XTC_E_ code. xtc_bdev_open() and xtc_bdev_flush() return XTC_OK or a negative XTC_E_ code. The size accessors return 0 on a NULL handle.

Call xtc_bdev_pread(), xtc_bdev_pwrite(), and xtc_bdev_flush() from a fiber running on a loop for the async path; off a loop they run synchronously on the calling thread, as with xtc_aio(3).

Open a device, write and read back one logical sector:

xtc_bdev_t *b;
if (xtc_bdev_open("/dev/sdb", XTC_BDEV_READ | XTC_BDEV_WRITE, &b) != XTC_OK)
	return -1;
uint32_t s = xtc_bdev_logical_sector(b);
if (xtc_bdev_pwrite(b, buf, s, 0) != (ssize_t)s) return -1;
if (xtc_bdev_flush(b) != XTC_OK) return -1;
if (xtc_bdev_pread(b, buf, s, 0) != (ssize_t)s) return -1;
xtc_bdev_close(b);

xtc_aio(3), xtc_fs(3), xtc_loop(3)

The xtc project.

July 6, 2026 Debian

View the mdoc source