Initial commit of an I/O provider for DTrace on FreeBSD.
These probes are most useful when looking into the structures they provide, which are listed in io.d. For example: dtrace -n 'io:genunix::start { printf("%d\n", args[0]->bio_bcount); }' Note that the I/O systems in FreeBSD and Solaris/Illumos are sufficiently different that there is not a 1:1 mapping from scripts that work with one to the other. MFC after: 1 month
This commit is contained in:
parent
f5afad7389
commit
3fac94ba94
Notes:
svn2git
2020-12-20 02:59:44 +00:00
svn path=/head/; revision=238366
@ -45,6 +45,7 @@ SRCS= dt_aggregate.c \
|
|||||||
gmatch.c
|
gmatch.c
|
||||||
|
|
||||||
DSRCS= errno.d \
|
DSRCS= errno.d \
|
||||||
|
io.d \
|
||||||
psinfo.d \
|
psinfo.d \
|
||||||
signal.d \
|
signal.d \
|
||||||
unistd.d
|
unistd.d
|
||||||
|
@ -27,114 +27,50 @@
|
|||||||
|
|
||||||
#pragma ident "%Z%%M% %I% %E% SMI"
|
#pragma ident "%Z%%M% %I% %E% SMI"
|
||||||
|
|
||||||
#pragma D depends_on module unix
|
|
||||||
#pragma D depends_on provider io
|
#pragma D depends_on provider io
|
||||||
|
|
||||||
inline int B_BUSY = B_BUSY;
|
|
||||||
#pragma D binding "1.0" B_BUSY
|
|
||||||
inline int B_DONE = 0x00000200;
|
|
||||||
#pragma D binding "1.0" B_DONE
|
|
||||||
inline int B_ERROR = B_ERROR;
|
|
||||||
#pragma D binding "1.0" B_ERROR
|
|
||||||
inline int B_PAGEIO = B_PAGEIO;
|
|
||||||
#pragma D binding "1.0" B_PAGEIO
|
|
||||||
inline int B_PHYS = B_PHYS;
|
|
||||||
#pragma D binding "1.0" B_PHYS
|
|
||||||
inline int B_READ = B_READ;
|
|
||||||
#pragma D binding "1.0" B_READ
|
|
||||||
inline int B_WRITE = B_WRITE;
|
|
||||||
#pragma D binding "1.0" B_WRITE
|
|
||||||
inline int B_ASYNC = 0x00000004;
|
|
||||||
#pragma D binding "1.0" B_ASYNC
|
|
||||||
|
|
||||||
typedef struct bufinfo {
|
|
||||||
int b_flags; /* buffer status */
|
|
||||||
size_t b_bcount; /* number of bytes */
|
|
||||||
caddr_t b_addr; /* buffer address */
|
|
||||||
uint64_t b_lblkno; /* block # on device */
|
|
||||||
uint64_t b_blkno; /* expanded block # on device */
|
|
||||||
size_t b_resid; /* # of bytes not transferred */
|
|
||||||
size_t b_bufsize; /* size of allocated buffer */
|
|
||||||
caddr_t b_iodone; /* I/O completion routine */
|
|
||||||
int b_error; /* expanded error field */
|
|
||||||
dev_t b_edev; /* extended device */
|
|
||||||
} bufinfo_t;
|
|
||||||
|
|
||||||
#pragma D binding "1.0" translator
|
|
||||||
translator bufinfo_t < struct buf *B > {
|
|
||||||
b_flags = B->b_flags;
|
|
||||||
b_addr = B->b_un.b_addr;
|
|
||||||
b_bcount = B->b_bcount;
|
|
||||||
b_lblkno = B->_b_blkno._f;
|
|
||||||
b_blkno = sizeof (long) == 8 ? B->_b_blkno._f : B->_b_blkno._p._l;
|
|
||||||
b_resid = B->b_resid;
|
|
||||||
b_bufsize = B->b_bufsize;
|
|
||||||
b_iodone = (caddr_t)B->b_iodone;
|
|
||||||
b_error = B->b_error;
|
|
||||||
b_edev = B->b_edev;
|
|
||||||
};
|
|
||||||
|
|
||||||
typedef struct devinfo {
|
typedef struct devinfo {
|
||||||
int dev_major; /* major number */
|
int dev_major; /* major number */
|
||||||
int dev_minor; /* minor number */
|
int dev_minor; /* minor number */
|
||||||
int dev_instance; /* instance number */
|
int dev_instance; /* instance number */
|
||||||
string dev_name; /* name of device */
|
string dev_name; /* name of device */
|
||||||
string dev_statname; /* name of device + instance/minor */
|
string dev_statname; /* name of device + instance/minor */
|
||||||
string dev_pathname; /* pathname of device */
|
string dev_pathname; /* pathname of device */
|
||||||
} devinfo_t;
|
} devinfo_t;
|
||||||
|
|
||||||
#pragma D binding "1.0" translator
|
#pragma D binding "1.0" translator
|
||||||
translator devinfo_t < struct buf *B > {
|
translator devinfo_t < struct devstat *D > {
|
||||||
dev_major = B->b_dip != NULL ? getmajor(B->b_edev) :
|
dev_major = D->device_number;
|
||||||
getmajor(B->b_file->v_vfsp->vfs_dev);
|
dev_minor = D->unit_number;
|
||||||
dev_minor = B->b_dip != NULL ? getminor(B->b_edev) :
|
dev_instance = 0;
|
||||||
getminor(B->b_file->v_vfsp->vfs_dev);
|
dev_name = stringof(D->device_name);
|
||||||
dev_instance = B->b_dip == NULL ?
|
dev_statname = stringof(D->device_name);
|
||||||
getminor(B->b_file->v_vfsp->vfs_dev) :
|
dev_pathname = stringof(D->device_name);
|
||||||
((struct dev_info *)B->b_dip)->devi_instance;
|
|
||||||
dev_name = B->b_dip == NULL ? "nfs" :
|
|
||||||
stringof(`devnamesp[getmajor(B->b_edev)].dn_name);
|
|
||||||
dev_statname = strjoin(B->b_dip == NULL ? "nfs" :
|
|
||||||
stringof(`devnamesp[getmajor(B->b_edev)].dn_name),
|
|
||||||
lltostr(B->b_dip == NULL ? getminor(B->b_file->v_vfsp->vfs_dev) :
|
|
||||||
((struct dev_info *)B->b_dip)->devi_instance == 0 &&
|
|
||||||
((struct dev_info *)B->b_dip)->devi_parent != NULL &&
|
|
||||||
((struct dev_info *)B->b_dip)->devi_parent->devi_node_name ==
|
|
||||||
"pseudo" ? getminor(B->b_edev) :
|
|
||||||
((struct dev_info *)B->b_dip)->devi_instance));
|
|
||||||
dev_pathname = B->b_dip == NULL ? "<nfs>" :
|
|
||||||
ddi_pathname(B->b_dip, getminor(B->b_edev));
|
|
||||||
};
|
};
|
||||||
|
|
||||||
typedef struct fileinfo {
|
typedef struct bufinfo {
|
||||||
string fi_name; /* name (basename of fi_pathname) */
|
int b_flags; /* flags */
|
||||||
string fi_dirname; /* directory (dirname of fi_pathname) */
|
long b_bcount; /* number of bytes */
|
||||||
string fi_pathname; /* full pathname */
|
caddr_t b_addr; /* buffer address */
|
||||||
offset_t fi_offset; /* offset within file */
|
uint64_t b_blkno; /* expanded block # on device */
|
||||||
string fi_fs; /* filesystem */
|
uint64_t b_lblkno; /* block # on device */
|
||||||
string fi_mount; /* mount point of file system */
|
size_t b_resid; /* # of bytes not transferred */
|
||||||
int fi_oflags; /* open(2) flags for file descriptor */
|
size_t b_bufsize; /* size of allocated buffer */
|
||||||
} fileinfo_t;
|
/* caddr_t b_iodone; I/O completion routine */
|
||||||
|
int b_error; /* expanded error field */
|
||||||
|
/* dev_t b_edev; extended device */
|
||||||
|
} bufinfo_t;
|
||||||
|
|
||||||
#pragma D binding "1.0" translator
|
#pragma D binding "1.0" translator
|
||||||
translator fileinfo_t < struct buf *B > {
|
translator bufinfo_t < struct bio *B > {
|
||||||
fi_name = B->b_file == NULL ? "<none>" :
|
b_flags = B->bio_flags;
|
||||||
B->b_file->v_path == NULL ? "<unknown>" :
|
b_bcount = B->bio_bcount;
|
||||||
basename(cleanpath(B->b_file->v_path));
|
b_addr = B->bio_data;
|
||||||
fi_dirname = B->b_file == NULL ? "<none>" :
|
b_blkno = 0;
|
||||||
B->b_file->v_path == NULL ? "<unknown>" :
|
b_lblkno = 0;
|
||||||
dirname(cleanpath(B->b_file->v_path));
|
b_resid = B->bio_resid;
|
||||||
fi_pathname = B->b_file == NULL ? "<none>" :
|
b_bufsize = 0; /* XXX gnn */
|
||||||
B->b_file->v_path == NULL ? "<unknown>" :
|
b_error = B->bio_error;
|
||||||
cleanpath(B->b_file->v_path);
|
|
||||||
fi_offset = B->b_offset;
|
|
||||||
fi_fs = B->b_file == NULL ? "<none>" :
|
|
||||||
stringof(B->b_file->v_op->vnop_name);
|
|
||||||
fi_mount = B->b_file == NULL ? "<none>" :
|
|
||||||
B->b_file->v_vfsp->vfs_vnodecovered == NULL ? "/" :
|
|
||||||
B->b_file->v_vfsp->vfs_vnodecovered->v_path == NULL ? "<unknown>" :
|
|
||||||
cleanpath(B->b_file->v_vfsp->vfs_vnodecovered->v_path);
|
|
||||||
fi_oflags = 0;
|
|
||||||
};
|
};
|
||||||
|
|
||||||
/*
|
/*
|
||||||
@ -158,63 +94,17 @@ inline int O_APPEND = 0x0008;
|
|||||||
#pragma D binding "1.1" O_APPEND
|
#pragma D binding "1.1" O_APPEND
|
||||||
inline int O_CREAT = 0x0200;
|
inline int O_CREAT = 0x0200;
|
||||||
#pragma D binding "1.1" O_CREAT
|
#pragma D binding "1.1" O_CREAT
|
||||||
inline int O_DSYNC = O_DSYNC;
|
|
||||||
#pragma D binding "1.1" O_DSYNC
|
|
||||||
inline int O_EXCL = 0x0800;
|
inline int O_EXCL = 0x0800;
|
||||||
#pragma D binding "1.1" O_EXCL
|
#pragma D binding "1.1" O_EXCL
|
||||||
inline int O_LARGEFILE = O_LARGEFILE;
|
|
||||||
#pragma D binding "1.1" O_LARGEFILE
|
|
||||||
inline int O_NOCTTY = 0x8000;
|
inline int O_NOCTTY = 0x8000;
|
||||||
#pragma D binding "1.1" O_NOCTTY
|
#pragma D binding "1.1" O_NOCTTY
|
||||||
inline int O_NONBLOCK = 0x0004;
|
inline int O_NONBLOCK = 0x0004;
|
||||||
#pragma D binding "1.1" O_NONBLOCK
|
#pragma D binding "1.1" O_NONBLOCK
|
||||||
inline int O_NDELAY = 0x0004;
|
inline int O_NDELAY = 0x0004;
|
||||||
#pragma D binding "1.1" O_NDELAY
|
#pragma D binding "1.1" O_NDELAY
|
||||||
inline int O_RSYNC = O_RSYNC;
|
|
||||||
#pragma D binding "1.1" O_RSYNC
|
|
||||||
inline int O_SYNC = 0x0080;
|
inline int O_SYNC = 0x0080;
|
||||||
#pragma D binding "1.1" O_SYNC
|
#pragma D binding "1.1" O_SYNC
|
||||||
inline int O_TRUNC = 0x0400;
|
inline int O_TRUNC = 0x0400;
|
||||||
#pragma D binding "1.1" O_TRUNC
|
#pragma D binding "1.1" O_TRUNC
|
||||||
inline int O_XATTR = O_XATTR;
|
|
||||||
#pragma D binding "1.1" O_XATTR
|
|
||||||
|
|
||||||
#pragma D binding "1.1" translator
|
|
||||||
translator fileinfo_t < struct file *F > {
|
|
||||||
fi_name = F == NULL ? "<none>" :
|
|
||||||
F->f_vnode->v_path == NULL ? "<unknown>" :
|
|
||||||
basename(cleanpath(F->f_vnode->v_path));
|
|
||||||
fi_dirname = F == NULL ? "<none>" :
|
|
||||||
F->f_vnode->v_path == NULL ? "<unknown>" :
|
|
||||||
dirname(cleanpath(F->f_vnode->v_path));
|
|
||||||
fi_pathname = F == NULL ? "<none>" :
|
|
||||||
F->f_vnode->v_path == NULL ? "<unknown>" :
|
|
||||||
cleanpath(F->f_vnode->v_path);
|
|
||||||
fi_offset = F == NULL ? 0 : F->f_offset;
|
|
||||||
fi_fs = F == NULL ? "<none>" : stringof(F->f_vnode->v_op->vnop_name);
|
|
||||||
fi_mount = F == NULL ? "<none>" :
|
|
||||||
F->f_vnode->v_vfsp->vfs_vnodecovered == NULL ? "/" :
|
|
||||||
F->f_vnode->v_vfsp->vfs_vnodecovered->v_path == NULL ? "<unknown>" :
|
|
||||||
cleanpath(F->f_vnode->v_vfsp->vfs_vnodecovered->v_path);
|
|
||||||
fi_oflags = F == NULL ? 0 : F->f_flag + (int)FOPEN;
|
|
||||||
};
|
|
||||||
|
|
||||||
inline fileinfo_t fds[int fd] = xlate <fileinfo_t> (
|
|
||||||
fd >= 0 && fd < curthread->t_procp->p_user.u_finfo.fi_nfiles ?
|
|
||||||
curthread->t_procp->p_user.u_finfo.fi_list[fd].uf_file : NULL);
|
|
||||||
|
|
||||||
#pragma D attributes Stable/Stable/Common fds
|
|
||||||
#pragma D binding "1.1" fds
|
|
||||||
|
|
||||||
#pragma D binding "1.2" translator
|
|
||||||
translator fileinfo_t < struct vnode *V > {
|
|
||||||
fi_name = V->v_path == NULL ? "<unknown>" :
|
|
||||||
basename(cleanpath(V->v_path));
|
|
||||||
fi_dirname = V->v_path == NULL ? "<unknown>" :
|
|
||||||
dirname(cleanpath(V->v_path));
|
|
||||||
fi_pathname = V->v_path == NULL ? "<unknown>" : cleanpath(V->v_path);
|
|
||||||
fi_fs = stringof(V->v_op->vnop_name);
|
|
||||||
fi_mount = V->v_vfsp->vfs_vnodecovered == NULL ? "/" :
|
|
||||||
V->v_vfsp->vfs_vnodecovered->v_path == NULL ? "<unknown>" :
|
|
||||||
cleanpath(V->v_vfsp->vfs_vnodecovered->v_path);
|
|
||||||
};
|
|
||||||
|
232
sys/kern/dtio_kdtrace.c
Normal file
232
sys/kern/dtio_kdtrace.c
Normal file
@ -0,0 +1,232 @@
|
|||||||
|
/*-
|
||||||
|
* Copyright (c) 2012 Advanced Computing Technologies LLC
|
||||||
|
* Written by George Neville-Neil gnn@freebsd.org
|
||||||
|
* All rights reserved.
|
||||||
|
*
|
||||||
|
* Redistribution and use in source and binary forms, with or without
|
||||||
|
* modification, are permitted provided that the following conditions
|
||||||
|
* are met:
|
||||||
|
* 1. Redistributions of source code must retain the above copyright
|
||||||
|
* notice, this list of conditions and the following disclaimer.
|
||||||
|
* 2. Redistributions in binary form must reproduce the above copyright
|
||||||
|
* notice, this list of conditions and the following disclaimer in the
|
||||||
|
* documentation and/or other materials provided with the distribution.
|
||||||
|
*
|
||||||
|
* THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND
|
||||||
|
* ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
|
||||||
|
* IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
|
||||||
|
* ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE
|
||||||
|
* FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
|
||||||
|
* DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
|
||||||
|
* OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
|
||||||
|
* HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
|
||||||
|
* LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
|
||||||
|
* OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
|
||||||
|
* SUCH DAMAGE.
|
||||||
|
*/
|
||||||
|
|
||||||
|
#include <sys/cdefs.h>
|
||||||
|
__FBSDID("$FreeBSD$");
|
||||||
|
|
||||||
|
#include <sys/param.h>
|
||||||
|
#include <sys/systm.h>
|
||||||
|
#include <sys/conf.h>
|
||||||
|
#include <sys/kernel.h>
|
||||||
|
#include <sys/malloc.h>
|
||||||
|
#include <sys/module.h>
|
||||||
|
|
||||||
|
#include <sys/dtrace.h>
|
||||||
|
#include "../sys/dtrace_bsd.h"
|
||||||
|
|
||||||
|
|
||||||
|
static int dtio_unload(void);
|
||||||
|
static void dtio_getargdesc(void *, dtrace_id_t, void *,
|
||||||
|
dtrace_argdesc_t *);
|
||||||
|
static void dtio_provide(void *, dtrace_probedesc_t *);
|
||||||
|
static void dtio_destroy(void *, dtrace_id_t, void *);
|
||||||
|
static void dtio_enable(void *, dtrace_id_t, void *);
|
||||||
|
static void dtio_disable(void *, dtrace_id_t, void *);
|
||||||
|
static void dtio_load(void *);
|
||||||
|
|
||||||
|
static dtrace_pattr_t dtio_attr = {
|
||||||
|
{ DTRACE_STABILITY_STABLE, DTRACE_STABILITY_STABLE, DTRACE_CLASS_COMMON },
|
||||||
|
{ DTRACE_STABILITY_PRIVATE, DTRACE_STABILITY_PRIVATE, DTRACE_CLASS_UNKNOWN },
|
||||||
|
{ DTRACE_STABILITY_PRIVATE, DTRACE_STABILITY_PRIVATE, DTRACE_CLASS_UNKNOWN },
|
||||||
|
{ DTRACE_STABILITY_STABLE, DTRACE_STABILITY_STABLE, DTRACE_CLASS_COMMON },
|
||||||
|
{ DTRACE_STABILITY_STABLE, DTRACE_STABILITY_STABLE, DTRACE_CLASS_COMMON },
|
||||||
|
};
|
||||||
|
|
||||||
|
static char *genunix = "genunix";
|
||||||
|
|
||||||
|
/*
|
||||||
|
* Name strings.
|
||||||
|
*/
|
||||||
|
static char *dtio_start_str = "start";
|
||||||
|
static char *dtio_done_str = "done";
|
||||||
|
static char *dtio_wait_start_str = "wait-start";
|
||||||
|
static char *dtio_wait_done_str = "wait-done";
|
||||||
|
|
||||||
|
static dtrace_pops_t dtio_pops = {
|
||||||
|
dtio_provide,
|
||||||
|
NULL,
|
||||||
|
dtio_enable,
|
||||||
|
dtio_disable,
|
||||||
|
NULL,
|
||||||
|
NULL,
|
||||||
|
dtio_getargdesc,
|
||||||
|
NULL,
|
||||||
|
NULL,
|
||||||
|
dtio_destroy
|
||||||
|
};
|
||||||
|
|
||||||
|
static dtrace_provider_id_t dtio_id;
|
||||||
|
|
||||||
|
extern uint32_t dtio_start_id;
|
||||||
|
extern uint32_t dtio_done_id;
|
||||||
|
extern uint32_t dtio_wait_start_id;
|
||||||
|
extern uint32_t dtio_wait_done_id;
|
||||||
|
|
||||||
|
static void
|
||||||
|
dtio_getargdesc(void *arg, dtrace_id_t id, void *parg,
|
||||||
|
dtrace_argdesc_t *desc)
|
||||||
|
{
|
||||||
|
const char *p = NULL;
|
||||||
|
|
||||||
|
switch (desc->dtargd_ndx) {
|
||||||
|
case 0:
|
||||||
|
p = "struct bio *";
|
||||||
|
break;
|
||||||
|
case 1:
|
||||||
|
p = "struct devstat *";
|
||||||
|
break;
|
||||||
|
default:
|
||||||
|
desc->dtargd_ndx = DTRACE_ARGNONE;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (p != NULL)
|
||||||
|
strlcpy(desc->dtargd_native, p, sizeof(desc->dtargd_native));
|
||||||
|
}
|
||||||
|
|
||||||
|
static void
|
||||||
|
dtio_provide(void *arg, dtrace_probedesc_t *desc)
|
||||||
|
{
|
||||||
|
if (desc != NULL)
|
||||||
|
return;
|
||||||
|
|
||||||
|
if (dtrace_probe_lookup(dtio_id, genunix, NULL,
|
||||||
|
dtio_start_str) == 0) {
|
||||||
|
dtio_start_id = dtrace_probe_create(dtio_id, genunix, NULL,
|
||||||
|
dtio_start_str, 0, NULL);
|
||||||
|
}
|
||||||
|
if (dtrace_probe_lookup(dtio_id, genunix, NULL, dtio_done_str) == 0) {
|
||||||
|
dtio_done_id = dtrace_probe_create(dtio_id, genunix, NULL,
|
||||||
|
dtio_done_str, 0, NULL);
|
||||||
|
}
|
||||||
|
if (dtrace_probe_lookup(dtio_id, genunix, NULL,
|
||||||
|
dtio_wait_start_str) == 0) {
|
||||||
|
dtio_wait_start_id = dtrace_probe_create(dtio_id, genunix,
|
||||||
|
NULL,
|
||||||
|
dtio_wait_start_str,
|
||||||
|
0, NULL);
|
||||||
|
}
|
||||||
|
if (dtrace_probe_lookup(dtio_id, genunix, NULL,
|
||||||
|
dtio_wait_done_str) == 0) {
|
||||||
|
dtio_wait_done_id = dtrace_probe_create(dtio_id, genunix, NULL,
|
||||||
|
dtio_wait_done_str, 0, NULL);
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
static void
|
||||||
|
dtio_destroy(void *arg, dtrace_id_t id, void *parg)
|
||||||
|
{
|
||||||
|
}
|
||||||
|
|
||||||
|
static void
|
||||||
|
dtio_enable(void *arg, dtrace_id_t id, void *parg)
|
||||||
|
{
|
||||||
|
if (id == dtio_start_id)
|
||||||
|
dtrace_io_start_probe =
|
||||||
|
(dtrace_io_start_probe_func_t)dtrace_probe;
|
||||||
|
else if (id == dtio_done_id)
|
||||||
|
dtrace_io_done_probe =
|
||||||
|
(dtrace_io_done_probe_func_t)dtrace_probe;
|
||||||
|
else if (id == dtio_wait_start_id)
|
||||||
|
dtrace_io_wait_start_probe =
|
||||||
|
(dtrace_io_wait_start_probe_func_t)dtrace_probe;
|
||||||
|
else if (id == dtio_wait_done_id)
|
||||||
|
dtrace_io_wait_done_probe =
|
||||||
|
(dtrace_io_wait_done_probe_func_t)dtrace_probe;
|
||||||
|
else
|
||||||
|
printf("dtrace io provider: unknown ID\n");
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
static void
|
||||||
|
dtio_disable(void *arg, dtrace_id_t id, void *parg)
|
||||||
|
{
|
||||||
|
if (id == dtio_start_id)
|
||||||
|
dtrace_io_start_probe = NULL;
|
||||||
|
else if (id == dtio_done_id)
|
||||||
|
dtrace_io_done_probe = NULL;
|
||||||
|
else if (id == dtio_wait_start_id)
|
||||||
|
dtrace_io_wait_start_probe = NULL;
|
||||||
|
else if (id == dtio_wait_done_id)
|
||||||
|
dtrace_io_wait_done_probe = NULL;
|
||||||
|
else
|
||||||
|
printf("dtrace io provider: unknown ID\n");
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
static void
|
||||||
|
dtio_load(void *dummy)
|
||||||
|
{
|
||||||
|
if (dtrace_register("io", &dtio_attr, DTRACE_PRIV_USER, NULL,
|
||||||
|
&dtio_pops, NULL, &dtio_id) != 0)
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
static int
|
||||||
|
dtio_unload()
|
||||||
|
{
|
||||||
|
dtrace_io_start_probe = NULL;
|
||||||
|
dtrace_io_done_probe = NULL;
|
||||||
|
dtrace_io_wait_start_probe = NULL;
|
||||||
|
dtrace_io_wait_done_probe = NULL;
|
||||||
|
|
||||||
|
return (dtrace_unregister(dtio_id));
|
||||||
|
}
|
||||||
|
|
||||||
|
static int
|
||||||
|
dtio_modevent(module_t mod __unused, int type, void *data __unused)
|
||||||
|
{
|
||||||
|
int error = 0;
|
||||||
|
|
||||||
|
switch (type) {
|
||||||
|
case MOD_LOAD:
|
||||||
|
break;
|
||||||
|
|
||||||
|
case MOD_UNLOAD:
|
||||||
|
break;
|
||||||
|
|
||||||
|
case MOD_SHUTDOWN:
|
||||||
|
break;
|
||||||
|
|
||||||
|
default:
|
||||||
|
error = EOPNOTSUPP;
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
|
||||||
|
return (error);
|
||||||
|
}
|
||||||
|
|
||||||
|
SYSINIT(dtio_load, SI_SUB_DTRACE_PROVIDER, SI_ORDER_ANY,
|
||||||
|
dtio_load, NULL);
|
||||||
|
SYSUNINIT(dtio_unload, SI_SUB_DTRACE_PROVIDER, SI_ORDER_ANY,
|
||||||
|
dtio_unload, NULL);
|
||||||
|
|
||||||
|
DEV_MODULE(dtio, dtio_modevent, NULL);
|
||||||
|
MODULE_VERSION(dtio, 1);
|
||||||
|
MODULE_DEPEND(dtio, dtrace, 1, 1, 1);
|
||||||
|
MODULE_DEPEND(dtio, opensolaris, 1, 1, 1);
|
@ -29,6 +29,8 @@
|
|||||||
#include <sys/cdefs.h>
|
#include <sys/cdefs.h>
|
||||||
__FBSDID("$FreeBSD$");
|
__FBSDID("$FreeBSD$");
|
||||||
|
|
||||||
|
#include "opt_kdtrace.h"
|
||||||
|
|
||||||
#include <sys/param.h>
|
#include <sys/param.h>
|
||||||
#include <sys/kernel.h>
|
#include <sys/kernel.h>
|
||||||
#include <sys/systm.h>
|
#include <sys/systm.h>
|
||||||
@ -44,6 +46,54 @@ __FBSDID("$FreeBSD$");
|
|||||||
|
|
||||||
#include <machine/atomic.h>
|
#include <machine/atomic.h>
|
||||||
|
|
||||||
|
#ifdef KDTRACE_HOOKS
|
||||||
|
#include <sys/dtrace_bsd.h>
|
||||||
|
|
||||||
|
dtrace_io_start_probe_func_t dtrace_io_start_probe;
|
||||||
|
dtrace_io_done_probe_func_t dtrace_io_done_probe;
|
||||||
|
dtrace_io_wait_start_probe_func_t dtrace_io_wait_start_probe;
|
||||||
|
dtrace_io_wait_done_probe_func_t dtrace_io_wait_done_probe;
|
||||||
|
|
||||||
|
uint32_t dtio_start_id;
|
||||||
|
uint32_t dtio_done_id;
|
||||||
|
uint32_t dtio_wait_start_id;
|
||||||
|
uint32_t dtio_wait_done_id;
|
||||||
|
|
||||||
|
#define DTRACE_DEVSTAT_START() \
|
||||||
|
if (dtrace_io_start_probe != NULL) \
|
||||||
|
(*dtrace_io_start_probe)(dtio_start_id, NULL, ds);
|
||||||
|
|
||||||
|
#define DTRACE_DEVSTAT_BIO_START() \
|
||||||
|
if (dtrace_io_start_probe != NULL) \
|
||||||
|
(*dtrace_io_start_probe)(dtio_start_id, bp, ds);
|
||||||
|
|
||||||
|
#define DTRACE_DEVSTAT_DONE() \
|
||||||
|
if (dtrace_io_done_probe != NULL) \
|
||||||
|
(*dtrace_io_done_probe)(dtio_done_id, NULL, ds);
|
||||||
|
|
||||||
|
#define DTRACE_DEVSTAT_BIO_DONE() \
|
||||||
|
if (dtrace_io_done_probe != NULL) \
|
||||||
|
(*dtrace_io_done_probe)(dtio_done_id, bp, ds);
|
||||||
|
|
||||||
|
#define DTRACE_DEVSTAT_WAIT_START() \
|
||||||
|
if (dtrace_io_wait_start_probe != NULL) \
|
||||||
|
(*dtrace_io_wait_start_probe)(dtio_wait_start_id, NULL, ds);
|
||||||
|
|
||||||
|
#define DTRACE_DEVSTAT_WAIT_DONE() \
|
||||||
|
if (dtrace_io_wait_done_probe != NULL) \
|
||||||
|
(*dtrace_io_wait_done_probe)(dtio_wait_done_id, NULL, ds);
|
||||||
|
|
||||||
|
#else /* ! KDTRACE_HOOKS */
|
||||||
|
|
||||||
|
#define DTRACE_DEVSTAT_START()
|
||||||
|
|
||||||
|
#define DTRACE_DEVSTAT_DONE()
|
||||||
|
|
||||||
|
#define DTRACE_DEVSTAT_WAIT_START()
|
||||||
|
|
||||||
|
#define DTRACE_DEVSTAT_WAIT_DONE()
|
||||||
|
#endif /* KDTRACE_HOOKS */
|
||||||
|
|
||||||
static int devstat_num_devs;
|
static int devstat_num_devs;
|
||||||
static long devstat_generation = 1;
|
static long devstat_generation = 1;
|
||||||
static int devstat_version = DEVSTAT_VERSION;
|
static int devstat_version = DEVSTAT_VERSION;
|
||||||
@ -227,6 +277,7 @@ devstat_start_transaction(struct devstat *ds, struct bintime *now)
|
|||||||
}
|
}
|
||||||
ds->start_count++;
|
ds->start_count++;
|
||||||
atomic_add_rel_int(&ds->sequence0, 1);
|
atomic_add_rel_int(&ds->sequence0, 1);
|
||||||
|
DTRACE_DEVSTAT_START();
|
||||||
}
|
}
|
||||||
|
|
||||||
void
|
void
|
||||||
@ -241,6 +292,7 @@ devstat_start_transaction_bio(struct devstat *ds, struct bio *bp)
|
|||||||
|
|
||||||
binuptime(&bp->bio_t0);
|
binuptime(&bp->bio_t0);
|
||||||
devstat_start_transaction(ds, &bp->bio_t0);
|
devstat_start_transaction(ds, &bp->bio_t0);
|
||||||
|
DTRACE_DEVSTAT_BIO_START();
|
||||||
}
|
}
|
||||||
|
|
||||||
/*
|
/*
|
||||||
@ -312,6 +364,7 @@ devstat_end_transaction(struct devstat *ds, uint32_t bytes,
|
|||||||
|
|
||||||
ds->end_count++;
|
ds->end_count++;
|
||||||
atomic_add_rel_int(&ds->sequence0, 1);
|
atomic_add_rel_int(&ds->sequence0, 1);
|
||||||
|
DTRACE_DEVSTAT_DONE();
|
||||||
}
|
}
|
||||||
|
|
||||||
void
|
void
|
||||||
@ -334,6 +387,7 @@ devstat_end_transaction_bio(struct devstat *ds, struct bio *bp)
|
|||||||
|
|
||||||
devstat_end_transaction(ds, bp->bio_bcount - bp->bio_resid,
|
devstat_end_transaction(ds, bp->bio_bcount - bp->bio_resid,
|
||||||
DEVSTAT_TAG_SIMPLE, flg, NULL, &bp->bio_t0);
|
DEVSTAT_TAG_SIMPLE, flg, NULL, &bp->bio_t0);
|
||||||
|
DTRACE_DEVSTAT_BIO_DONE();
|
||||||
}
|
}
|
||||||
|
|
||||||
/*
|
/*
|
||||||
|
@ -9,6 +9,7 @@ SUBDIR= dtmalloc \
|
|||||||
dtrace \
|
dtrace \
|
||||||
dtraceall \
|
dtraceall \
|
||||||
dtrace_test \
|
dtrace_test \
|
||||||
|
dtio \
|
||||||
prototype \
|
prototype \
|
||||||
sdt \
|
sdt \
|
||||||
systrace
|
systrace
|
||||||
|
13
sys/modules/dtrace/dtio/Makefile
Normal file
13
sys/modules/dtrace/dtio/Makefile
Normal file
@ -0,0 +1,13 @@
|
|||||||
|
# $FreeBSD$
|
||||||
|
|
||||||
|
.PATH: ${.CURDIR}/../../../kern
|
||||||
|
|
||||||
|
KMOD= dtio
|
||||||
|
SRCS= dtio_kdtrace.c \
|
||||||
|
vnode_if.h
|
||||||
|
|
||||||
|
CFLAGS+= -I${.CURDIR}/../../../cddl/compat/opensolaris \
|
||||||
|
-I${.CURDIR}/../../../cddl/contrib/opensolaris/uts/common \
|
||||||
|
-I${.CURDIR}/../../..
|
||||||
|
|
||||||
|
.include <bsd.kmod.mk>
|
@ -65,6 +65,7 @@ MODULE_VERSION(dtraceall, 1);
|
|||||||
MODULE_DEPEND(dtraceall, cyclic, 1, 1, 1);
|
MODULE_DEPEND(dtraceall, cyclic, 1, 1, 1);
|
||||||
MODULE_DEPEND(dtraceall, opensolaris, 1, 1, 1);
|
MODULE_DEPEND(dtraceall, opensolaris, 1, 1, 1);
|
||||||
MODULE_DEPEND(dtraceall, dtrace, 1, 1, 1);
|
MODULE_DEPEND(dtraceall, dtrace, 1, 1, 1);
|
||||||
|
MODULE_DEPEND(dtraceall, dtio, 1, 1, 1);
|
||||||
MODULE_DEPEND(dtraceall, dtmalloc, 1, 1, 1);
|
MODULE_DEPEND(dtraceall, dtmalloc, 1, 1, 1);
|
||||||
MODULE_DEPEND(dtraceall, dtnfscl, 1, 1, 1);
|
MODULE_DEPEND(dtraceall, dtnfscl, 1, 1, 1);
|
||||||
MODULE_DEPEND(dtraceall, dtnfsclient, 1, 1, 1);
|
MODULE_DEPEND(dtraceall, dtnfsclient, 1, 1, 1);
|
||||||
|
@ -38,6 +38,8 @@ struct thread;
|
|||||||
struct vattr;
|
struct vattr;
|
||||||
struct vnode;
|
struct vnode;
|
||||||
struct reg;
|
struct reg;
|
||||||
|
struct devstat;
|
||||||
|
struct bio;
|
||||||
|
|
||||||
/*
|
/*
|
||||||
* Cyclic clock function type definition used to hook the cyclic
|
* Cyclic clock function type definition used to hook the cyclic
|
||||||
@ -168,6 +170,23 @@ extern dtrace_nfsclient_nfs23_done_probe_func_t
|
|||||||
extern dtrace_nfsclient_nfs23_done_probe_func_t
|
extern dtrace_nfsclient_nfs23_done_probe_func_t
|
||||||
dtrace_nfscl_nfs234_done_probe;
|
dtrace_nfscl_nfs234_done_probe;
|
||||||
|
|
||||||
|
/* IO Provider hooks, really hook into devstat */
|
||||||
|
typedef void (*dtrace_io_start_probe_func_t)(uint32_t, struct bio *,
|
||||||
|
struct devstat *);
|
||||||
|
extern dtrace_io_start_probe_func_t dtrace_io_start_probe;
|
||||||
|
|
||||||
|
typedef void (*dtrace_io_done_probe_func_t)(uint32_t, struct bio *,
|
||||||
|
struct devstat *);
|
||||||
|
extern dtrace_io_done_probe_func_t dtrace_io_done_probe;
|
||||||
|
|
||||||
|
typedef void (*dtrace_io_wait_start_probe_func_t)(uint32_t, uintptr_t *,
|
||||||
|
struct devstat *);
|
||||||
|
extern dtrace_io_wait_start_probe_func_t dtrace_io_wait_start_probe;
|
||||||
|
|
||||||
|
typedef void (*dtrace_io_wait_done_probe_func_t)(uint32_t, uintptr_t *,
|
||||||
|
struct devstat *);
|
||||||
|
extern dtrace_io_wait_done_probe_func_t dtrace_io_wait_done_probe;
|
||||||
|
|
||||||
/*
|
/*
|
||||||
* Functions which allow the dtrace module to check that the kernel
|
* Functions which allow the dtrace module to check that the kernel
|
||||||
* hooks have been compiled with sufficient space for it's private
|
* hooks have been compiled with sufficient space for it's private
|
||||||
|
Loading…
Reference in New Issue
Block a user