Skip to content

Instantly share code, notes, and snippets.

@erickt
Created December 9, 2010 20:29
Show Gist options
  • Select an option

  • Save erickt/735283 to your computer and use it in GitHub Desktop.

Select an option

Save erickt/735283 to your computer and use it in GitHub Desktop.
function __task_file_handle_filp:long(task:long, fd:long) %{ /* pure */
struct task_struct *p = (struct task_struct *)((long)THIS->task);
struct files_struct *files;
struct file *filp;
rcu_read_lock();
if ((files = kread(&p->files))) {
if ((filp = fcheck_files(files, THIS->fd))) {
THIS->__retvalue = (long)filp;
}
}
CATCH_DEREF_FAULT();
rcu_read_unlock();
%}
function __task_dentry_prepend:string(dentry:long,name:string)
{
dname = d_name(dentry)
/*
* In case we are following down a mount point trigger, we can get
* multiple instances of a root mount.
*/
c = substr(name, strlen(name)-1, strlen(name)-1)
if (dname == "/" && c == "/")
return name
if (name == "") {
return dname;
} else {
return sprintf("%s/%s", dname, name)
}
}
/**
* sfunction task_dentry_path - get the full dentry path
*
* Returns the full dirent name (full path to the root), like
* the kernel d_path function.
* @task: task_struct pointer.
* @dentry: direntry pointer.
* @vfsmnt: vfsmnt pointer.
*/
function __task_dentry_path(task:long, dentry:long, vfsmnt:long)
{
root = & @cast(task, "task_struct")->fs->root
while (1) {
if (dentry == @cast(root, "path")->dentry &&
vfsmnt == @cast(root, "path")->mnt)
break;
if (dentry == @cast(vfsmnt, "vfsmount")->mnt_root ||
__dentry_IS_ROOT(dentry)) {
/* Global root? */
if (@cast(vfsmnt, "vfsmount")->mnt_parent == vfsmnt) {
return sprintf("/%s", name)
}
dentry = @cast(vfsmnt, "vfsmount")->mnt_mountpoint
vfsmnt = @cast(vfsmnt, "vfsmount")->mnt_parent
continue
}
name = __task_dentry_prepend(dentry, name)
dentry = @cast(dentry, "dentry")->d_parent
}
return sprintf("/%s", name)
}
/**
* sfunction task_file_handle_path - get the full path of a file descriptor
*
* Returns the full dirent name (full path to the root), like the kernel d_path function.
* @task: task_struct pointer.
* @fd: file descriptor.
*/
function task_file_handle_path:string(task:long, fd:long)
{
filp = __task_file_handle_filp(task, fd)
if (!filp) {
return ""
}
dentry = (@defined(@cast(filp,"file")->f_path->dentry)
? @cast(filp,"file")->f_path->dentry
: @cast(filp,"file")->f_dentry)
vfsmnt = (@defined(@cast(filp,"file")->f_path->mnt)
? @cast(filp,"file")->f_path->mnt
: @cast(filp,"file")->f_vfsmnt)
return __task_dentry_path(task, dentry, vfsmnt)
}
global openedFileActiveTime = $1
global openedFileSleepTime = $2
global openedFileEnabled = 0
global openedFileSampleTime = 0
global fileIOActiveTime = $3
global fileIOSleepTime = $4
global fileIOEnabled = 0
global fileIOSampleTime = 0
global files, iostats, deltas
# Look up the file.
function find_file_path(task, p, fd)
{
file = files[p, fd]
if (file == "") {
file = task_file_handle_path(task, fd)
}
return file
}
# Log the io traffic.
function report_io(pid, fd, syscall, tstamp, file)
{
count = @count(iostats[pid, fd, syscall])
if (count > 0) {
minsample = @min(iostats[pid, fd, syscall])
maxsample = @max(iostats[pid, fd, syscall])
total = @sum(iostats[pid, fd, syscall])
printf("io:%d:%d:%d:%d:%d:%d:%d:%s\n",
tstamp, pid,
syscall, minsample, maxsample, count, total, file)
}
}
# Save the file when a file gets opened.
probe kernel.function("sys_open").return
{
if ($return >= 0) {
p = pid()
task = task_current()
# Save the filename in a cache.
file = task_file_handle_path(task, $return)
if (file != "") {
files[p, $return] = file
if (openedFileEnabled) {
printf("file:%d:%d:%s\n", gettimeofday_ns(), p, file)
}
}
}
}
# If a file gets closed, report those statistics right away.
probe kernel.function("sys_close")
{
p = pid()
task = task_current()
# Look up the filename in a cache.
file = find_file_path(task, p, $fd)
# If we found a file, report it.
if (file != "") {
tstamp = gettimeofday_ns()
report_io(p, $fd, 0, tstamp, file)
report_io(p, $fd, 1, tstamp, file)
report_io(p, $fd, 2, tstamp, file)
}
# Clean up our caches.
delete iostats[p, $fd, 0]
delete iostats[p, $fd, 1]
delete iostats[p, $fd, 2]
delete files[p, $fd]
}
# Record all the read iowait time and their traffic.
probe kernel.function("sys_read") if (fileIOEnabled)
{
deltas[tid(), 1] = gettimeofday_ns()
}
probe kernel.function("sys_read").return.maxactive(20) if (fileIOEnabled)
{
t = tid()
starttime = deltas[t, 1]
delete deltas[t, 1]
# We ignore a return of 0 bytes because that means we are at the end of the
# file.
if ($return > 0) {
p = pid()
# Save that this fd has data.
if (starttime != 0) {
iostats[p, $fd, 0] <<< gettimeofday_ns() - starttime
}
iostats[p, $fd, 1] <<< $return
}
}
# Record all the write iowait time and their traffic.
probe kernel.function("sys_write") if (fileIOEnabled)
{
deltas[tid(), 2] = gettimeofday_ns()
}
probe kernel.function("sys_write").return.maxactive(20) if (fileIOEnabled)
{
t = tid()
starttime = deltas[t, 2]
delete deltas[t, 2]
if ($return >= 0) {
p = pid()
# Save that this fd has data.
if (starttime != 0) {
iostats[p, $fd, 0] <<< gettimeofday_ns() - starttime
}
iostats[p, $fd, 2] <<< $return
}
}
# Report all the statistics and clear the caches.
function report_all_stats(tstamp)
{
foreach ([p, fd, syscall] in iostats) {
file = files[p, fd]
if (file != "") {
task = pid2task(p)
if (task) {
file = find_file_path(task, p, fd)
}
}
if (file != "") {
files[p, fd] = file
report_io(p, fd, 0, tstamp, file)
report_io(p, fd, 1, tstamp, file)
report_io(p, fd, 2, tstamp, file)
}
}
# Clean up all the io stat caches.
delete iostats
}
# Cycle whether or not we are gathering statistics.
probe timer.s(1) if (openedFileSleepTime != 0 || fileIOSleepTime != 0)
{
tstamp = gettimeofday_ns()
tstamp_s = tstamp / 1000000000
report_all_stats(tstamp)
# Toggle tracking opened files.
if (openedFileSleepTime != 0) {
if (openedFileEnabled) {
if (tstamp_s - openedFileSampleTime > openedFileActiveTime) {
openedFileEnabled = 0
openedFileSampleTime = tstamp_s
}
} else {
if (tstamp_s - openedFileSampleTime > openedFileSleepTime) {
openedFileEnabled = 1
openedFileSampleTime = tstamp_s
}
}
}
# Toggle tracking file io.
if (fileIOSleepTime != 0) {
if (fileIOEnabled) {
if (tstamp_s - fileIOSampleTime > fileIOActiveTime) {
fileIOEnabled = 0
fileIOSampleTime = tstamp_s
}
} else {
if (tstamp_s - fileIOSampleTime > fileIOSleepTime) {
fileIOEnabled = 1
fileIOSampleTime = tstamp_s
}
}
}
}
# Clear the file cache every 30 seconds.
probe timer.s(30)
{
delete files
}
probe begin
{
openedFileEnabled = openedFileActiveTime != 0
fileIOEnabled = fileIOActiveTime != 0
}
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment