DEVSTAT(9) | Kernel Developer's Manual | DEVSTAT(9) |
devstat
,
devstat_add_entry
,
devstat_end_transaction
,
devstat_end_transaction_bio
,
devstat_end_transaction_bio_bt
,
devstat_remove_entry
,
devstat_start_transaction
,
devstat_start_transaction_bio
—
kernel interface for keeping device statistics
#include
<sys/devicestat.h>
void
devstat_add_entry
(struct devstat
*ds, const char *dev_name, int
unit_number, uint32_t block_size,
devstat_support_flags flags,
devstat_type_flags device_type,
devstat_priority priority);
void
devstat_remove_entry
(struct
devstat *ds);
void
devstat_start_transaction
(struct
devstat *ds, const struct bintime *now);
void
devstat_start_transaction_bio
(struct
devstat *ds, struct bio *bp);
void
devstat_end_transaction
(struct devstat
*ds, uint32_t bytes,
devstat_tag_type tag_type,
devstat_trans_flags flags, const
struct bintime *now, const struct bintime
*then);
void
devstat_end_transaction_bio
(struct
devstat *ds, const struct bio *bp);
void
devstat_end_transaction_bio_bt
(struct
devstat *ds, const struct bio *bp,
const struct bintime *now);
The devstat subsystem is an interface for recording device
statistics, as its name implies. The idea is to keep reasonably detailed
statistics while utilizing a minimum amount of CPU time to record them.
Thus, no statistical calculations are actually performed in the kernel
portion of the devstat
code. Instead, that is left
for user programs to handle.
The historical and antiquated devstat
model assumed a single active IO operation per device, which is not accurate
for most disk-like drivers in the 2000s and beyond. New consumers of the
interface should almost certainly use only the "bio" variants of
the start and end transacation routines.
devstat_add_entry
()
registers a device with the devstat
subsystem. The
caller is expected to have already allocated and zeroed the devstat
structure before calling this function.
devstat_add_entry
() takes several arguments:
devstat
list, it should be set to 0.devstat
's list of devices. Devices
are sorted first by priority (highest to lowest), and then by attach
order. See below for a complete list of available priorities.devstat_remove_entry
()
removes a device from the devstat
subsystem. It
takes the devstat structure for the device in question as an argument. The
devstat
generation number is incremented and the
number of devices is decremented.
devstat_start_transaction
()
registers the start of a transaction with the
devstat
subsystem. Optionally, if the caller already
has a binuptime
() value available, it may be passed
in *now. Usually the caller can just pass
NULL
for now, and the routine
will gather the current binuptime
() itself. The busy
count is incremented with each transaction start. When a device goes from
idle to busy, the system uptime is recorded in the
busy_from field of the devstat
structure.
devstat_start_transaction_bio
()
records the binuptime
() in the provided bio's
bio_t0 and then invokes
devstat_start_transaction
().
devstat_end_transaction
()
registers the end of a transaction with the devstat
subsystem. It takes six arguments:
binuptime
() at the end of the transaction, or
NULL
.binuptime
() at the beginning of the
transaction, or NULL
.If now is
NULL
, it collects the current time from
binuptime
().
If then is NULL
, the operation
is not tracked in the devstat
duration table.
devstat_end_transaction_bio
()
is a thin wrapper for
devstat_end_transaction_bio_bt
() with a
NULL
now parameter.
devstat_end_transaction_bio_bt
()
is a wrapper for devstat_end_transaction
() which
pulls all needed information from a struct bio
prepared by devstat_start_transaction_bio
(). The bio
must be ready for
biodone
()
(i.e., bio_bcount and bio_resid
must be correctly initialized).
The devstat structure is composed of the following fields:
There should be one and only one transaction start event and one transaction end event for each transaction.
DEVSTAT_READ
), written (index
DEVSTAT_WRITE
), freed or erased (index
DEVSTAT_FREE
), or other (index
DEVSTAT_NO_DATA
). All values are unsigned 64-bit
integers.DEVSTAT_NO_DATA
or "other" represents the number of transactions to the device
which are neither reads, writes, nor frees. For instance, SCSI drivers
often send a test unit ready command to SCSI devices. The test unit ready
command does not read or write any data. It merely causes the device to
return its status.devstat_end_transaction
()
API and do not provide a non-NULL then are not
accounted for.)getmicrotime
()
that the device was registered.devstat
list. The second
parameter is attach order. See below for a list of available
priorities.Each device is given a device type. Pass-through devices have the same underlying device type and interface as the device they provide an interface for, but they also have the pass-through flag set. The base device types are identical to the SCSI device type numbers, so with SCSI peripherals, the device type returned from an inquiry is usually ORed with the SCSI interface type and the pass-through flag if appropriate. The device type flags are as follows:
typedef enum { DEVSTAT_TYPE_DIRECT = 0x000, DEVSTAT_TYPE_SEQUENTIAL = 0x001, DEVSTAT_TYPE_PRINTER = 0x002, DEVSTAT_TYPE_PROCESSOR = 0x003, DEVSTAT_TYPE_WORM = 0x004, DEVSTAT_TYPE_CDROM = 0x005, DEVSTAT_TYPE_SCANNER = 0x006, DEVSTAT_TYPE_OPTICAL = 0x007, DEVSTAT_TYPE_CHANGER = 0x008, DEVSTAT_TYPE_COMM = 0x009, DEVSTAT_TYPE_ASC0 = 0x00a, DEVSTAT_TYPE_ASC1 = 0x00b, DEVSTAT_TYPE_STORARRAY = 0x00c, DEVSTAT_TYPE_ENCLOSURE = 0x00d, DEVSTAT_TYPE_FLOPPY = 0x00e, DEVSTAT_TYPE_MASK = 0x00f, DEVSTAT_TYPE_IF_SCSI = 0x010, DEVSTAT_TYPE_IF_IDE = 0x020, DEVSTAT_TYPE_IF_OTHER = 0x030, DEVSTAT_TYPE_IF_MASK = 0x0f0, DEVSTAT_TYPE_PASS = 0x100 } devstat_type_flags;
Devices have a priority associated with them, which controls
roughly where they are placed in the devstat
list.
The priorities are as follows:
typedef enum { DEVSTAT_PRIORITY_MIN = 0x000, DEVSTAT_PRIORITY_OTHER = 0x020, DEVSTAT_PRIORITY_PASS = 0x030, DEVSTAT_PRIORITY_FD = 0x040, DEVSTAT_PRIORITY_WFD = 0x050, DEVSTAT_PRIORITY_TAPE = 0x060, DEVSTAT_PRIORITY_CD = 0x090, DEVSTAT_PRIORITY_DISK = 0x110, DEVSTAT_PRIORITY_ARRAY = 0x120, DEVSTAT_PRIORITY_MAX = 0xfff } devstat_priority;
Each device has associated with it flags to indicate what operations are supported or not supported. The devstat_support_flags values are as follows:
Transactions to a device fall into
one of three categories, which are represented in the
flags passed into
devstat_end_transaction
().
The transaction types are as follows:
typedef enum { DEVSTAT_NO_DATA = 0x00, DEVSTAT_READ = 0x01, DEVSTAT_WRITE = 0x02, DEVSTAT_FREE = 0x03 } devstat_trans_flags;
There are four possible values for
the tag_type argument to
devstat_end_transaction
():
The tag type values correspond to
the lower four bits of the SCSI tag definitions. In CAM, for instance, the
tag_action from the CCB is ORed with 0xf to determine
the tag type to pass in to
devstat_end_transaction
().
There is a macro, DEVSTAT_VERSION
that is
defined in
<sys/devicestat.h>
. This is
the current version of the devstat
subsystem, and it
should be incremented each time a change is made that would require
recompilation of userland programs that access
devstat
statistics. Userland programs use this
version, via the kern.devstat.version
sysctl
variable to determine whether they are in
sync with the kernel devstat
structures.
The devstat
statistics system appeared in
FreeBSD 3.0.
Kenneth Merry <ken@FreeBSD.org>
There may be a need for spl
() protection
around some of the devstat
list manipulation code to
ensure, for example, that the list of devices is not changed while someone
is fetching the kern.devstat.all
sysctl
variable.
August 22, 2018 | Debian |