#!/usr/sbin/dtrace -s
/*
** iosnoop.d - A program to print I/O events as they happen, with useful
**	details such as UID, PID, inode, command, etc. 
**	Written in DTrace (Solaris 10 build 51).
**
** 29-Mar-2004, ver 0.60. 	(check for newer versions)
**
**
** USAGE:	./iosnoop.d
**
**	Different styles of output can be selected by changing
**	the "FORMAT" variable below.
**
**	iosnoop.d reads block I/O disk events.
** 	
** FIELDS:
**		TIME	timestamp for the disk event, us
**		SIZE	size of operation, bytes
**		DEV	extended device number of the slice
**		MOUNT	mount point (or "0" if the data was not available)
**		STIME 	timestamp for the disk request, us
**		...
**
** Standard Disclaimer: This is freeware, use at your own risk.
**
** ToDo: More details, modes of operation, process different I/O types...
**
** 12-Mar-2004	Brendan Gregg	Created this.
**
*/

inline int FORMAT = 1;
/*			1 - Default output (includes PPID, VNODE)
**			2 - Timestamp output (includes TIME)
**			3 - Everything, space delimited (for spreadsheets)
*/

#pragma D option quiet


/*
**  Print header
*/
dtrace:::BEGIN /FORMAT == 1/ { 
	printf("%5s %5s %5s %6s %-10s %-7s %-10s %5s %s\n",
	 "UID","PID","PPID","SIZE","MOUNT","BLOCK","VNODE","INODE","CMD");
}
dtrace:::BEGIN /FORMAT == 2/ { 
	printf("%-14s %5s %5s %6s %-10s %-7s %5s %s\n",
	 "TIME","UID","PID","SIZE","MOUNT","BLOCK","INODE","CMD");
}
dtrace:::BEGIN /FORMAT == 3/ { 
	printf("%s %s %s %s %s %s %s %s %s %s %s %s\n","TIME","STIME","UID",
	 "PID","PPID","SIZE","DEV","MOUNT","BLOCK","VNODE","INODE","CMD");
}


fbt:genunix:bdev_strategy:entry
{
	/*
	**  Process strategy event
	*/

	/* fetch details */
	this->bufp = (buf_t *)arg0;
	this->dev = this->bufp->b_edev;
	blk = this->bufp->_b_blkno._f;

	/* store strategy details */
	str_uid[this->dev,blk] = curpsinfo->pr_euid;
	str_pid[this->dev,blk] = pid;
	str_ppid[this->dev,blk] = curpsinfo->pr_ppid;
	str_args[this->dev,blk] = (char *)curpsinfo->pr_psargs;
	str_time[this->dev,blk] = timestamp;
}


fbt:genunix:biodone:entry
{
	/*
	**  Process biodone event
	*/

	/* fetch details */
	this->bufp = (buf_t *)arg0;
	this->dev = this->bufp->b_edev;
	blk = this->bufp->_b_blkno._f;
	this->pagep = (page_t *)this->bufp->b_pages;
	this->vnodep = (int)this->pagep == 0 ? 
		0 : (vnode_t *)this->pagep->p_vnode;
	this->vnode =  (int)this->vnodep == 0 ? 
		0 : (int)this->vnodep;
	this->inodep = (int)this->vnodep == 0 ? 
		0 : (inode_t *)this->vnodep->v_data;
	this->inode =  (int)this->inodep == 0 ? 
		0 : this->inodep->i_number;
	this->vfsp = (int)this->vnodep == 0 ? 
		0 : (vfs_t *)this->vnodep->v_vfsp;
	mountstr = (int)this->vfsp == 0 ? 
		"0" : stringof(this->vfsp->vfs_mntpt);

	/* check this is a valid mount string */
	first = (int)this->vfsp == 0 ? 
		"0" : stringof(copyin((uintptr_t)this->vfsp->vfs_mntpt,1));
	mountstr = first == "/" ? mountstr : "0";

	/* fetch strategy values */
	this->suid = str_uid[this->dev,blk];
	this->spid = str_pid[this->dev,blk];
	this->sppid = str_ppid[this->dev,blk];
	sargs = (int)str_args[this->dev,blk] == 0 ? 
		"" : str_args[this->dev,blk];
	this->stime = str_time[this->dev,blk];

	/* memory cleanup */
	str_uid[this->dev,blk] = 0;
	str_pid[this->dev,blk] = 0;
	str_ppid[this->dev,blk] = 0;
	str_args[this->dev,blk] = 0;
	str_time[this->dev,blk] = 0;
}


/*
**  Print event details
*/
fbt:genunix:biodone:entry /FORMAT == 1/ {
	printf("%5d %5d %5d %6d %-10s %-7d %-10x %5d %s\n",
	 this->suid,this->spid,this->sppid,this->bufp->b_bcount,mountstr,
	 this->bufp->_b_blkno._f,this->vnode,this->inode,stringof(sargs));
}
fbt:genunix:biodone:entry /FORMAT == 2/ {
	printf("%-14d %5d %5d %6d %-10s %-7d %5d %s\n",
	 timestamp/1000,this->suid,this->spid,this->bufp->b_bcount,mountstr,
	 this->bufp->_b_blkno._f,this->inode,stringof(sargs));
}
fbt:genunix:biodone:entry /FORMAT == 3/ {
	printf("%d %d %d %d %d %d %d %s %d %x %d %s\n",
	 timestamp/1000,this->stime/1000,this->suid,this->spid,this->sppid,
	 this->bufp->b_bcount,this->bufp->b_edev,mountstr,
	 this->bufp->_b_blkno._f,this->vnode,this->inode,stringof(sargs));
}

