如何在Linux中跟踪每个文件的IO操作?

我需要跟踪read特定文件的系统调用,而我目前正在通过parsingstrace的输出来做到这一点。 由于read操作文件描述符,我必须跟踪fdpath之间的当前映射。 另外,必须监视seek以保持跟踪中当前位置的最新状态。

在Linux中有更好的方法来获得每个应用程序,每个文件path的IO跟踪吗?

Solutions Collecting From Web of "如何在Linux中跟踪每个文件的IO操作?"

首先,您可能不需要保持跟踪,因为fdpath之间的映射在/proc/PID/fd/可用。

其次,也许你应该使用LD_PRELOAD技巧,并在C中open重载, seekread系统调用。 这里和那里有一些关于如何重载malloc / free的文章。

我猜这些系统调用应用相同的技巧不会太差。 它需要在C中实现,但是它应该比解析strace输出要少得多的代码和精确度。

你可以等待文件被打开,这样你可以在启动过程之后学习fd和attach strace:

strace -p pid -e trace = file -e read = fd

systemtap – 一种用于Linux的DTrace重新实现 – 可能对此有所帮助。

和strace一样,你只有fd,但是脚本能力很容易维护一个fd的文件名(除非像dup这样有趣的东西)。 有示例脚本iotime说明它。

 #! /usr/bin/env stap /* * Copyright (C) 2006-2007 Red Hat Inc. * * This copyrighted material is made available to anyone wishing to use, * modify, copy, or redistribute it subject to the terms and conditions * of the GNU General Public License v.2. * * You should have received a copy of the GNU General Public License * along with this program. If not, see <http://www.gnu.org/licenses/>. * * Print out the amount of time spent in the read and write systemcall * when each file opened by the process is closed. Note that the systemtap * script needs to be running before the open operations occur for * the script to record data. * * This script could be used to to find out which files are slow to load * on a machine. eg * * stap iotime.stp -c 'firefox' * * Output format is: * timestamp pid (executabable) info_type path ... * * 200283135 2573 (cupsd) access /etc/printcap read: 0 write: 7063 * 200283143 2573 (cupsd) iotime /etc/printcap time: 69 * */ global start global time_io function timestamp:long() { return gettimeofday_us() - start } function proc:string() { return sprintf("%d (%s)", pid(), execname()) } probe begin { start = gettimeofday_us() } global filehandles, fileread, filewrite probe syscall.open.return { filename = user_string($filename) if ($return != -1) { filehandles[pid(), $return] = filename } else { printf("%d %s access %s fail\n", timestamp(), proc(), filename) } } probe syscall.read.return { p = pid() fd = $fd bytes = $return time = gettimeofday_us() - @entry(gettimeofday_us()) if (bytes > 0) fileread[p, fd] += bytes time_io[p, fd] <<< time } probe syscall.write.return { p = pid() fd = $fd bytes = $return time = gettimeofday_us() - @entry(gettimeofday_us()) if (bytes > 0) filewrite[p, fd] += bytes time_io[p, fd] <<< time } probe syscall.close { if ([pid(), $fd] in filehandles) { printf("%d %s access %s read: %d write: %d\n", timestamp(), proc(), filehandles[pid(), $fd], fileread[pid(), $fd], filewrite[pid(), $fd]) if (@count(time_io[pid(), $fd])) printf("%d %s iotime %s time: %d\n", timestamp(), proc(), filehandles[pid(), $fd], @sum(time_io[pid(), $fd])) } delete fileread[pid(), $fd] delete filewrite[pid(), $fd] delete filehandles[pid(), $fd] delete time_io[pid(),$fd] } 

它只能处理一定数量的文件,因为哈希映射是有限的。

我觉得超载openseekread是一个很好的解决方案。 但只是FYI,如果你想解析和分析strace输出编程,我做了类似之前,把我的代码在github: https : //github.com/johnlcf/Stana/wiki

(我这样做是因为我必须分析别人运行的程序的结果,这不容易让他们做LD_PRELOAD。)

可能最不丑陋的做法是使用fanotify。 Fanotify是一个Linux内核工具,允许便宜地观看文件系统事件。 我不确定它是否允许通过PID进行过滤,但它确实将PID传递给了您的程序,以便检查您是否感兴趣。

这是一个很好的代码示例: http : //bazaar.launchpad.net/~pitti/fatrace/trunk/view/head : /fatrace.c

但是,目前似乎没有记录。 所有我能找到的文档是http://www.spinics.net/lists/linux-man/msg02302.html和http://lkml.indiana.edu/hypermail/linux/kernel/0811.1/01668.html

像strace一样解析命令行utils是很麻烦的; 你可以使用ptrace()系统调用。 有关详细信息,请参阅man ptrace