DKSUBR(9)
πΎ DKSUBR(9) β the disk driver subroutine glow-up π
okay so real talk: this is a page from the Kernel Developer's Manual, and it's literally the shared toolbox that every disk driver gets to raid so nobody has to rewrite the same boilerplate forty times. bestie, it's giving "communal closet, everyone looks cute." β¨
πΈ NAME πΈ
dk_softc, dk_init, dk_attach, dk_detach, dk_open, dk_close, dk_size, dk_dump, dk_ioctl, dk_strategy, dk_strategy_defer, dk_strategy_pending, dk_start, dk_done, dk_drain, dk_discard, dk_getdefaultlabel, dk_getdisklabel β disk driver subroutines π
β¨ SYNOPSIS β¨
#include <sys/bufq.h>
#include <sys/disk.h>
#include <dev/dkvar.h>
void
dk_init(struct dk_softc *, device_t, int dtype);
void
dk_attach(struct dk_softc *);
void
dk_detach(struct dk_softc *);
int
dk_open(struct dk_softc *, dev_t, int flags, int fmt, struct lwp *);
int
dk_close(struct dk_softc *, dev_t, int flags, int fmt, struct lwp *);
int
dk_discard(struct dk_softc *, dev_t, off_t pos, off_t len);
int
dk_size(struct dk_softc *, dev_t);
int
dk_dump(struct dk_softc *, dev_t, daddr_t blkno, void *vav,
size_t size);
int
dk_ioctl(struct dk_softc *, dev_t, u_long cmd, void *data, int flag,
struct lwp *);
void
dk_strategy(struct dk_softc *, struct buf *);
int
dk_strategy_defer(struct dk_softc *, struct buf *);
int
dk_strategy_pending(struct dk_softc *);
void
dk_start(struct dk_softc *, struct buf *);
void
dk_done(struct dk_softc *, struct buf *);
int
dk_drain(struct dk_softc *);
void
dk_getdefaultlabel(struct dk_softc *, struct disklabel *);
void
dk_getdisklabel(struct dk_softc *, dev_t);
π¦ DESCRIPTION π¦
The disk driver subroutines are the communal glue code for all disk drivers, and they exist purely to cut down on the amount of copy-pasted duplicated code floating around. For a whole lot of disk drivers, their own entry points can be left as basically stubs β like, literally two lines and a vibe check. π₯
The subroutines fold a driver's softc data structures into:
struct dk_softc {
device_t sc_dev;
struct disk sc_dkdev;
struct bufq_state sc_bufq;
krndsource_t sc_rnd_source;
...
}
So yeah β the dk_softc structure replaces the device_t member of the driver's softc struct. no cap.
The following is a brief description of each function in the framework (a little tour, if you will π§):
dk_init()β Initialize thedk_softcstructure.dk_attach()β Attach the framework after the driver has attached thedisk(9)subsystem, created abufq(9), and is ready to handle I/O.dk_detach()β Undodk_attach.dk_open()β Handles the open steps for thedisk(9)framework, acquires the disklabel, and validates the open parameters. The driver may provide thed_firstopencallback to handle initialization steps.dk_close()β Handles the close steps for thedisk(9)framework. The driver may provide thed_lastclosecallback to handle finalization steps. Heads up:dk_openanddk_closeare serialized by theopenlockmutex. πdk_discard()β Validates parameters, computes raw block numbers, and passes those to thed_discardcallback.dk_size()β Returns dump size info from thedisklabel(9), and opens and closes the driver when necessary.dk_dump()β Validates parameters, computes raw block numbers, and iterates over thed_dumpblockscallback in appropriate chunks determined by thed_iosizecallback.dk_ioctl()β Handles the ioctlsDIOCKLABEL,DIOCWLABEL,DIOCGDEFLABEL,DIOCGSTRATEGY, andDIOCSSTRATEGY, and passes other disk ioctls through thedisk(9)framework. ReturnsENOTTYwhen an ioctl isn't implemented. This routine runs as a fallback to handle commands that aren't specific to the driver.dk_strategy()β Validates parameters, computes raw block numbers, queues a buffer for I/O, and triggers queue processing by callingdk_start.dk_strategy_defer()β Alternative todk_strategythat only queues the buffer. Drivers that implement a separate I/O thread can usedk_strategy_deferinside their own strategy routine and signal the thread through a private interface. π§΅dk_strategy_pending()β Called by an I/O thread to determine if work has been queued bydk_strategy_defer. The driver must then calldk_startto trigger queue processing.dk_start()β Ifbp != NULL, put it into the queue. Runs thed_diskstartcallback for every buffer until the queue is empty or the callback returnsEAGAIN. In that latter case, the buffer is saved and issued on the next queue run. This also callsdisk_busyaccordingly to handle I/O metrics. πdk_done()β Called by the driver when an I/O operation completed.dk_donelogs errors, callsdisk_unbusyto handle I/O metrics, and collects entropy for thecprng(9). π²dk_drain()β Aborts all queued I/O. You must call this function instead ofbufq_drain()so it cooperates withdk_start.dk_getdefaultlabel()β Computes a common default disklabel for all disk drivers. Some drivers provide device-specific information or assign specific disk formats to partitions. Such drivers may implement thed_labelcallback, which is called bydk_getdefaultlabelafter initializing the label with common values.dk_getdisklabel()β Reads the disklabel with the machine-dependent low-level functionreaddisklabeland does sanity checks. π
π DRIVER INTERFACE π
The driver needs to provide a common set of entry points that get used by the disk driver subroutines and the disk(9) framework. Here's the whole squad:
struct dkdriver {
void (*d_strategy)(struct buf *);
void (*d_minphys)(struct buf *);
int (*d_open)(dev_t, int, int, struct lwp *);
int (*d_close)(dev_t, int, int, struct lwp *);
int (*d_diskstart)(device_t, struct buf *);
void (*d_iosize)(device_t, int *);
int (*d_dumpblocks)(device_t, void *, daddr_t, int);
int (*d_lastclose)(device_t);
int (*d_discard)(device_t, off_t, off_t);
int (*d_firstopen)(device_t, dev_t, int, int);
void (*d_label)(device_t, struct disklabel *);
};
d_strategy()β The driver strategy routine queues a single buffer for I/O and starts queue processing as appropriate.d_minphys()β The driver minphys routine limits the bufferb_bcountto the maximum size for an I/O transfer supported by the driver and hardware. It also callsminphysto apply the platform limit.d_open()β The driver open routine.d_close()β The driver close routine.d_diskstart()β Issues a single I/O request, called bydk_start.d_iosize()β Truncates I/O size to the driver limit. This is similar tominphysbut operates on an integer value instead of a buffer.d_dumpblocks()β Issues a single I/O request, called bydk_dump.d_lastclose()β Private cleanup after the last user is finished. Often used to flush write caches. πΏd_discard()β Issues a single I/O request to invalidate a disk region.d_firstopen()β Private initialization when the first user opens the driver.
π SEE ALSO π
cgd(4), ld(4), cprng(9), disk(9), driver(9)
π HISTORY π
The NetBSD common disk driver subroutines appeared in NetBSD 2.0 as a base for the cryptographic disk driver, and were extended to handle disk wedges in NetBSD 4.0. Most functionality provided by ld(4) was included and extended in NetBSD 8.0 to support other disk drivers. The callback interface used by the disk(9) framework has been merged as well. look at her go π«Ά
okay that's the whole page, bestie β every flag, every callback, every struct field, nothing skipped. you're welcome π
and that's a wrap! this one shipped out from Debian on November 28, 2016 β iconic date, iconic page. go forth and write extremely cute disk drivers πππ¦πΈβ
π¦ where this page comes from
- nixpkgs unstable: netbsd-source 11.0
- Copyright (c) 2016 The NetBSD Foundation, Inc
- π girlified by deepseek-ai/DeepSeek-V4.1-Flash-1017 on : a language model's rewrite of the original, under its terms