29 #include <sys/cdefs.h>
32 #include "opt_kdtrace.h"
34 #include <sys/param.h>
35 #include <sys/kernel.h>
36 #include <sys/systm.h>
38 #include <sys/devicestat.h>
40 #include <sys/sysctl.h>
41 #include <sys/malloc.h>
43 #include <sys/mutex.h>
48 #include <machine/atomic.h>
59 #define DTRACE_DEVSTAT_START() SDT_PROBE2(io, , , start, NULL, ds)
60 #define DTRACE_DEVSTAT_BIO_START() SDT_PROBE2(io, , , start, bp, ds)
61 #define DTRACE_DEVSTAT_DONE() SDT_PROBE2(io, , , done, NULL, ds)
62 #define DTRACE_DEVSTAT_BIO_DONE() SDT_PROBE2(io, , , done, bp, ds)
63 #define DTRACE_DEVSTAT_WAIT_START() SDT_PROBE2(io, , , wait__start, NULL, ds)
64 #define DTRACE_DEVSTAT_WAIT_DONE() SDT_PROBE2(io, , , wait__done, NULL, ds)
77 int unit_number, uint32_t block_size,
78 devstat_support_flags flags,
79 devstat_type_flags device_type,
87 int unit_number, uint32_t block_size,
88 devstat_support_flags flags,
89 devstat_type_flags device_type,
98 if (unit_number == -1) {
104 flags, device_type, priority);
116 int unit_number, uint32_t block_size,
117 devstat_support_flags flags,
118 devstat_type_flags device_type,
121 struct devstatlist *devstat_head;
122 struct devstat *ds_tmp;
139 STAILQ_INSERT_TAIL(devstat_head, ds, dev_links);
141 STAILQ_FOREACH(ds_tmp, devstat_head, dev_links) {
142 struct devstat *ds_next;
144 ds_next = STAILQ_NEXT(ds_tmp, dev_links);
152 if ((priority <= ds_tmp->priority)
153 && ((ds_next == NULL)
154 || (priority > ds_next->priority))) {
155 STAILQ_INSERT_AFTER(devstat_head, ds_tmp, ds,
158 }
else if (priority > ds_tmp->priority) {
164 if (ds_tmp == STAILQ_FIRST(devstat_head)) {
165 STAILQ_INSERT_HEAD(devstat_head,
169 STAILQ_INSERT_TAIL(devstat_head,
171 printf(
"devstat_add_entry: HELP! "
172 "sorting problem detected "
173 "for name %p unit %d\n",
174 dev_name, unit_number);
182 ds->unit_number = unit_number;
183 strlcpy(ds->device_name, dev_name, DEVSTAT_NAME_LEN);
184 ds->block_size = block_size;
186 ds->device_type = device_type;
198 struct devstatlist *devstat_head;
209 atomic_add_acq_int(&ds->sequence1, 1);
210 if (ds->id == NULL) {
212 STAILQ_REMOVE(devstat_head, ds, devstat, dev_links);
235 atomic_add_acq_int(&ds->sequence1, 1);
241 if (ds->start_count == ds->end_count) {
243 ds->busy_from = *now;
248 atomic_add_rel_int(&ds->sequence0, 1);
295 devstat_tag_type tag_type, devstat_trans_flags flags,
309 atomic_add_acq_int(&ds->sequence1, 1);
311 ds->bytes[flags] += bytes;
312 ds->operations[flags]++;
317 if ((ds->flags & DEVSTAT_NO_ORDERED_TAGS) == 0 &&
318 tag_type != DEVSTAT_TAG_NONE)
319 ds->tag_types[tag_type]++;
324 bintime_sub(&dt, then);
325 bintime_add(&ds->duration[flags], &dt);
330 bintime_sub(&dt, &ds->busy_from);
331 bintime_add(&ds->busy_time, &dt);
332 ds->busy_from = *now;
335 atomic_add_rel_int(&ds->sequence0, 1);
350 devstat_trans_flags flg;
356 if (bp->bio_cmd == BIO_DELETE)
358 else if (bp->bio_cmd == BIO_READ)
360 else if (bp->bio_cmd == BIO_WRITE)
363 flg = DEVSTAT_NO_DATA;
366 DEVSTAT_TAG_SIMPLE, flg, now, &bp->bio_t0);
399 error = SYSCTL_OUT(req, &mygen,
sizeof(mygen));
416 for (;nds != NULL;) {
417 error = SYSCTL_OUT(req, nds,
sizeof(
struct devstat));
424 nds = STAILQ_NEXT(nds, dev_links);
436 static SYSCTL_NODE(_kern, OID_AUTO, devstat, CTLFLAG_RD, NULL,
437 "Device Statistics");
439 SYSCTL_PROC(_kern_devstat, OID_AUTO, all, CTLFLAG_RD|CTLTYPE_OPAQUE,
440 NULL, 0,
sysctl_devstat,
"S,devstat",
"All devices in the devstat list");
445 SYSCTL_INT(_kern_devstat, OID_AUTO, numdevs, CTLFLAG_RD,
447 SYSCTL_LONG(_kern_devstat, OID_AUTO, generation, CTLFLAG_RD,
449 SYSCTL_INT(_kern_devstat, OID_AUTO, version, CTLFLAG_RD,
458 #define statsperpage (PAGE_SIZE / sizeof(struct devstat))
463 .d_version = D_VERSION,
464 .d_flags = D_NEEDGIANT,
471 struct devstat *stat;
476 static
MALLOC_DEFINE(M_DEVSTAT, "devstat", "Device statistics");
479 devstat_mmap(struct cdev *dev, vm_ooffset_t offset, vm_paddr_t *paddr,
480 int nprot, vm_memattr_t *memattr)
484 if (nprot != VM_PROT_READ)
486 TAILQ_FOREACH(spp, &pagelist, list) {
488 *paddr = vtophys(spp->stat);
496 static struct devstat *
508 DEVSTAT_DEVICE_NAME);
514 TAILQ_FOREACH(spp, &pagelist, list) {
521 spp2 =
malloc(
sizeof *spp, M_DEVSTAT, M_ZERO | M_WAITOK);
522 spp2->stat =
malloc(PAGE_SIZE, M_DEVSTAT, M_ZERO | M_WAITOK);
530 TAILQ_FOREACH(spp, &pagelist, list)
541 TAILQ_INSERT_TAIL(&pagelist, spp, list);
547 if (dsp->allocated == 0)
554 if (spp2 != NULL && spp2 != spp) {
555 free(spp2->stat, M_DEVSTAT);
556 free(spp2, M_DEVSTAT);
567 bzero(dsp,
sizeof *dsp);
568 TAILQ_FOREACH(spp, &pagelist, list) {
569 if (dsp >= spp->stat && dsp < (spp->stat +
statsperpage)) {
576 SYSCTL_INT(_debug_sizeof, OID_AUTO, devstat, CTLFLAG_RD,
577 SYSCTL_NULL_INT_PTR,
sizeof(
struct devstat),
"sizeof(struct devstat)");
void devstat_end_transaction_bio(struct devstat *ds, struct bio *bp)
static int devstat_num_devs
void devstat_end_transaction(struct devstat *ds, uint32_t bytes, devstat_tag_type tag_type, devstat_trans_flags flags, struct bintime *now, struct bintime *then)
void * malloc(unsigned long size, struct malloc_type *mtp, int flags)
static int devstat_current_devnumber
SDT_PROBE_DEFINE2(io,,, start,"struct bio *","struct devstat *")
void devstat_start_transaction(struct devstat *ds, struct bintime *now)
void devstat_end_transaction_bio_bt(struct devstat *ds, struct bio *bp, struct bintime *now)
struct cdev * make_dev_credf(int flags, struct cdevsw *devsw, int unit, struct ucred *cr, uid_t uid, gid_t gid, int mode, const char *fmt,...)
struct devstat * devstat_new_entry(const void *dev_name, int unit_number, uint32_t block_size, devstat_support_flags flags, devstat_type_flags device_type, devstat_priority priority)
void devstat_start_transaction_bio(struct devstat *ds, struct bio *bp)
static void devstat_add_entry(struct devstat *ds, const void *dev_name, int unit_number, uint32_t block_size, devstat_support_flags flags, devstat_type_flags device_type, devstat_priority priority)
static MALLOC_DEFINE(M_GZIP,"gzip_trees","Gzip trees")
static d_mmap_t devstat_mmap
#define DTRACE_DEVSTAT_BIO_START()
static SYSCTL_NODE(_kern, OID_AUTO, devstat, CTLFLAG_RD, NULL,"Device Statistics")
SYSCTL_PROC(_kern_devstat, OID_AUTO, all, CTLFLAG_RD|CTLTYPE_OPAQUE, NULL, 0, sysctl_devstat,"S,devstat","All devices in the devstat list")
#define DTRACE_DEVSTAT_DONE()
MTX_SYSINIT(devstat_mutex,&devstat_mutex,"devstat", MTX_DEF)
static struct devstat * devstat_alloc(void)
static TAILQ_HEAD(statspage)
#define DTRACE_DEVSTAT_BIO_DONE()
SYSCTL_LONG(_kern_devstat, OID_AUTO, generation, CTLFLAG_RD,&devstat_generation, 0,"Devstat list generation")
SYSCTL_INT(_kern_devstat, OID_AUTO, numdevs, CTLFLAG_RD,&devstat_num_devs, 0,"Number of devices in the devstat list")
static long devstat_generation
void devstat_remove_entry(struct devstat *ds)
void free(void *addr, struct malloc_type *mtp)
int printf(const char *fmt,...)
static void devstat_free(struct devstat *)
void bintime(struct bintime *bt)
static struct devstatlist device_statq
static int devstat_version
#define DTRACE_DEVSTAT_START()
void binuptime(struct bintime *bt)
static struct cdevsw devstat_cdevsw
static int sysctl_devstat(SYSCTL_HANDLER_ARGS)
static struct mtx devstat_mutex