2

I am interested in getting statistics about filesystem reads and writes, specifically to an NFS mount.

I know there are many tools such as iostat, nfsstat and inotifywait but there are issues I have with each program.

I cannot use anything that would require me to walk the filesystem or explicitly mention file names due to the complexity of the hierarchy.

Is there a program that can do the following on demand?

  1. show reads / writes
  2. show path of read / write
  3. show byte quantity

By on demand, I mean on execution time. Point (3) is not mandatory.

For example, I would like to be able to do something like the following:

$ magicIOprogram
read, 512, /path/to/file1
read, 256, /path/to/file2
write, 15, /path/to/file3
write, 10562, /path/to/file4

If there are ways to get this information using the aforementioned tools that I am unaware of, it would also be a adequate solution.

6
  • 1
    iosnoop from perf-tools does some of what you're asking for, but I imagine it won't work on NFS. (See unix.stackexchange.com/questions/205147/… for an example.) You could look at tcpdump and Wireshark, perhaps there's an NFS analyser which would give you the necessary information... Jul 13, 2015 at 10:10
  • @StephenKitt doesn't seem like a bad idea, but after a quick look, its seems there is no output of path. thanks for the alternative, never used iosnoop. Jul 13, 2015 at 10:15
  • 1
    Yup that's why I didn't offer it as an answer. Jul 13, 2015 at 10:55
  • Have you looked into using Linux auditing to solve your need? Jul 14, 2015 at 0:06
  • @AndrewHenle can you be more specific? such as the inotify set of tools? I can't use anything that would need to walk the filesystem, the hierarchy is very complex. Jul 15, 2015 at 8:16

2 Answers 2

2

You might want to try systemtap.

Here is a slightly modified example showing opens, reads and writes every 100ms:

#! /usr/bin/env stap

global fileread, filewrite

probe syscall.open.return {
    if ($return != -1) {
        printf("open, %s, %d/%d\n", user_string($filename), pid(), $return)
    }
}

probe syscall.read.return {
    p = pid()
    fd = $fd
    bytes = $return
    if (bytes > 0)
        fileread[p, fd] += bytes
}

probe syscall.write.return {
    p = pid()
    fd = $fd
    bytes = $return
    if (bytes > 0)
        filewrite[p, fd] += bytes
}

probe timer.ms(100) {
    foreach (v = [p,fd] in fileread) {
        printf("read, %d, %d/%d\n", v, p, fd)
    }                                                                                                                                                                                          
    delete fileread                                                                                                                                                                            
    foreach (v = [p,fd] in filewrite) {                                                                                                                                                        
        printf("write, %d, %d/%d\n", v, p, fd)                                                                                                                                                 
    }                                                                                                                                                                                          
    delete filewrite                                                                                                                                                                           
}

The format of output lines is:

  • open, (pathname), (pid)/(fd)

  • read, (bytes), (pid)/(fd)

  • write, (bytes), (pid)/(fd)

1
  • Providing a link to a possible solution is great but you should also include the relevant part here. Jul 17, 2015 at 23:48
1
+50

Linux's auditd can get the information for points 1 and 2.

Assuming you are running RHEL/CentOS 6 and have an nfs share mounted as /mnt/nfs/foo:

$ tree /mnt/nfs/foo
/mnt/nfs/foo
|-- a
|   `-- foo
|-- b
    `-- bar

You will need to define the following rules in /etc/audit/audit.rules:

# Delete existing rules
-D
# Set buffer size
-b 320
# Log read and write operations
-w /mnt/nfs/foo -p r -k read -k nfs
-w /mnt/nfs/foo -p w -k write -k nfs

And then reload the auditd service with /etc/init.d/auditd reload.

Once that is done you can use ausearch and aureport to read the event logs generated by auditd:

$ cat /mnt/nfs/foo/a/foo
$ echo 'test' > /mnt/nfs/foo/b/bar
$ ausearch -k nfs | aureport -f
File Report
===============================================
# date time file syscall success exe auid event
===============================================
1. 07/15/2015 11:39:04 /mnt/nfs/foo/a/foo 2 yes /bin/cat 500 59
2. 07/15/2015 11:39:05 /mnt/nfs/foo/b/bar 2 yes /bin/bash 500 60

One caveat that it will only be able to collect the information from the client side. If your client is un-trusted you can not use this method to safely determine what they are accessing over nfs.

2
  • I think this is a good solution, but it is very verbose. It also shows all executions in the specified folder (such as /bin/ls or /bin/bash). Is there a way to decrease verbosity? Also, I don't see how to distinguish reads from writes, is it the last column? (respectively numbers 59/60 in your example) Jul 21, 2015 at 7:36
  • When using -k nfs as an argument to ausearch it's matching the -k nfs definition in /etc/audit/audit.rules. The keys read and write are also defined so you could also do ausearch -k read or ausearch -k write to see just reads or just writes. In terms of verbosity I'd suggest piping through awk to just get the information you need.
    – p8952
    Jul 21, 2015 at 8:57

You must log in to answer this question.

Not the answer you're looking for? Browse other questions tagged .