ANDROID: fs: FS tracepoints to track IO.
authorMohan Srinivasan <srmohan@google.com>
Tue, 20 Sep 2016 00:33:50 +0000 (17:33 -0700)
committerAmit Pundir <amit.pundir@linaro.org>
Wed, 12 Oct 2016 12:04:22 +0000 (17:34 +0530)
Adds tracepoints in ext4/f2fs/mpage to track readpages/buffered
write()s. This allows us to track files that are being read/written
to PIDs.

Change-Id: I26bd36f933108927d6903da04d8cb42fd9c3ef3d
Signed-off-by: Mohan Srinivasan <srmohan@google.com>
fs/ext4/inline.c
fs/ext4/inode.c
fs/ext4/readpage.c
fs/f2fs/data.c
fs/f2fs/inline.c
fs/mpage.c
include/trace/events/android_fs.h [new file with mode: 0644]
include/trace/events/android_fs_template.h [new file with mode: 0644]

index d884989cc83dd99238a710f8131ab38b1139c7ca..af34979684a4df6f7f35f22a4cf30bcb57007a1b 100644 (file)
@@ -18,6 +18,7 @@
 #include "ext4.h"
 #include "xattr.h"
 #include "truncate.h"
+#include <trace/events/android_fs.h>
 
 #define EXT4_XATTR_SYSTEM_DATA "data"
 #define EXT4_MIN_INLINE_DATA_SIZE      ((sizeof(__le32) * EXT4_N_BLOCKS))
@@ -500,6 +501,9 @@ int ext4_readpage_inline(struct inode *inode, struct page *page)
                return -EAGAIN;
        }
 
+       trace_android_fs_dataread_start(inode, page_offset(page), PAGE_SIZE,
+                                       current->pid, current->comm);
+
        /*
         * Current inline data can only exist in the 1st page,
         * So for all the other pages, just set them uptodate.
@@ -511,6 +515,8 @@ int ext4_readpage_inline(struct inode *inode, struct page *page)
                SetPageUptodate(page);
        }
 
+       trace_android_fs_dataread_end(inode, page_offset(page), PAGE_SIZE);
+
        up_read(&EXT4_I(inode)->xattr_sem);
 
        unlock_page(page);
index 28702932a9083730e493126e29f94ae4922ed35d..a152ab6048795c897e722203375369512af1e4ef 100644 (file)
@@ -44,6 +44,7 @@
 #include "truncate.h"
 
 #include <trace/events/ext4.h>
+#include <trace/events/android_fs.h>
 
 #define MPAGE_DA_EXTENT_TAIL 0x01
 
@@ -1016,6 +1017,8 @@ static int ext4_write_begin(struct file *file, struct address_space *mapping,
        pgoff_t index;
        unsigned from, to;
 
+       trace_android_fs_datawrite_start(inode, pos, len,
+                                        current->pid, current->comm);
        trace_ext4_write_begin(inode, pos, len, flags);
        /*
         * Reserve one block more for addition to orphan list in case
@@ -1152,6 +1155,7 @@ static int ext4_write_end(struct file *file,
        int ret = 0, ret2;
        int i_size_changed = 0;
 
+       trace_android_fs_datawrite_end(inode, pos, len);
        trace_ext4_write_end(inode, pos, len, copied);
        if (ext4_test_inode_state(inode, EXT4_STATE_ORDERED_MODE)) {
                ret = ext4_jbd2_file_inode(handle, inode);
@@ -1260,6 +1264,7 @@ static int ext4_journalled_write_end(struct file *file,
        unsigned from, to;
        int size_changed = 0;
 
+       trace_android_fs_datawrite_end(inode, pos, len);
        trace_ext4_journalled_write_end(inode, pos, len, copied);
        from = pos & (PAGE_CACHE_SIZE - 1);
        to = from + len;
@@ -2727,6 +2732,8 @@ static int ext4_da_write_begin(struct file *file, struct address_space *mapping,
                                        len, flags, pagep, fsdata);
        }
        *fsdata = (void *)0;
+       trace_android_fs_datawrite_start(inode, pos, len,
+                                        current->pid, current->comm);
        trace_ext4_da_write_begin(inode, pos, len, flags);
 
        if (ext4_test_inode_state(inode, EXT4_STATE_MAY_INLINE_DATA)) {
@@ -2845,6 +2852,7 @@ static int ext4_da_write_end(struct file *file,
                return ext4_write_end(file, mapping, pos,
                                      len, copied, page, fsdata);
 
+       trace_android_fs_datawrite_end(inode, pos, len);
        trace_ext4_da_write_end(inode, pos, len, copied);
        start = pos & (PAGE_CACHE_SIZE - 1);
        end = start + copied - 1;
@@ -3333,12 +3341,31 @@ static ssize_t ext4_direct_IO(struct kiocb *iocb, struct iov_iter *iter,
        if (ext4_has_inline_data(inode))
                return 0;
 
+       if (trace_android_fs_dataread_start_enabled() &&
+           (iov_iter_rw(iter) == READ))
+               trace_android_fs_dataread_start(inode, offset, count,
+                                               current->pid,
+                                               current->comm);
+       if (trace_android_fs_datawrite_start_enabled() &&
+           (iov_iter_rw(iter) == WRITE))
+               trace_android_fs_datawrite_start(inode, offset, count,
+                                                current->pid,
+                                                current->comm);
+
        trace_ext4_direct_IO_enter(inode, offset, count, iov_iter_rw(iter));
        if (ext4_test_inode_flag(inode, EXT4_INODE_EXTENTS))
                ret = ext4_ext_direct_IO(iocb, iter, offset);
        else
                ret = ext4_ind_direct_IO(iocb, iter, offset);
        trace_ext4_direct_IO_exit(inode, offset, count, iov_iter_rw(iter), ret);
+
+       if (trace_android_fs_dataread_start_enabled() &&
+           (iov_iter_rw(iter) == READ))
+               trace_android_fs_dataread_end(inode, offset, count);
+       if (trace_android_fs_datawrite_start_enabled() &&
+           (iov_iter_rw(iter) == WRITE))
+               trace_android_fs_datawrite_end(inode, offset, count);
+
        return ret;
 }
 
index 5dc5e95063de2a7e42749a94464f00f7c50be4b8..1ce24a6759a090de564813b6639e011da10b3271 100644 (file)
@@ -45,6 +45,7 @@
 #include <linux/cleancache.h>
 
 #include "ext4.h"
+#include <trace/events/android_fs.h>
 
 /*
  * Call ext4_decrypt on every single page, reusing the encryption
@@ -86,6 +87,17 @@ static inline bool ext4_bio_encrypted(struct bio *bio)
 #endif
 }
 
+static void
+ext4_trace_read_completion(struct bio *bio)
+{
+       struct page *first_page = bio->bi_io_vec[0].bv_page;
+
+       if (first_page != NULL)
+               trace_android_fs_dataread_end(first_page->mapping->host,
+                                             page_offset(first_page),
+                                             bio->bi_iter.bi_size);
+}
+
 /*
  * I/O completion handler for multipage BIOs.
  *
@@ -103,6 +115,9 @@ static void mpage_end_io(struct bio *bio)
        struct bio_vec *bv;
        int i;
 
+       if (trace_android_fs_dataread_start_enabled())
+               ext4_trace_read_completion(bio);
+
        if (ext4_bio_encrypted(bio)) {
                struct ext4_crypto_ctx *ctx = bio->bi_private;
 
@@ -130,6 +145,24 @@ static void mpage_end_io(struct bio *bio)
        bio_put(bio);
 }
 
+static void
+ext4_submit_bio_read(struct bio *bio)
+{
+       if (trace_android_fs_dataread_start_enabled()) {
+               struct page *first_page = bio->bi_io_vec[0].bv_page;
+
+               if (first_page != NULL) {
+                       trace_android_fs_dataread_start(
+                               first_page->mapping->host,
+                               page_offset(first_page),
+                               bio->bi_iter.bi_size,
+                               current->pid,
+                               current->comm);
+               }
+       }
+       submit_bio(READ, bio);
+}
+
 int ext4_mpage_readpages(struct address_space *mapping,
                         struct list_head *pages, struct page *page,
                         unsigned nr_pages)
@@ -271,7 +304,7 @@ int ext4_mpage_readpages(struct address_space *mapping,
                 */
                if (bio && (last_block_in_bio != blocks[0] - 1)) {
                submit_and_realloc:
-                       submit_bio(READ, bio);
+                       ext4_submit_bio_read(bio);
                        bio = NULL;
                }
                if (bio == NULL) {
@@ -303,14 +336,14 @@ int ext4_mpage_readpages(struct address_space *mapping,
                if (((map.m_flags & EXT4_MAP_BOUNDARY) &&
                     (relative_block == map.m_len)) ||
                    (first_hole != blocks_per_page)) {
-                       submit_bio(READ, bio);
+                       ext4_submit_bio_read(bio);
                        bio = NULL;
                } else
                        last_block_in_bio = blocks[blocks_per_page - 1];
                goto next_page;
        confused:
                if (bio) {
-                       submit_bio(READ, bio);
+                       ext4_submit_bio_read(bio);
                        bio = NULL;
                }
                if (!PageUptodate(page))
@@ -323,6 +356,6 @@ int ext4_mpage_readpages(struct address_space *mapping,
        }
        BUG_ON(pages && !list_empty(pages));
        if (bio)
-               submit_bio(READ, bio);
+               ext4_submit_bio_read(bio);
        return 0;
 }
index 972eab7ac07193da485df3efc6b6c11c99dacd97..e692958d6e7859995d970d0364fbd36b1a7abd08 100644 (file)
@@ -26,6 +26,7 @@
 #include "segment.h"
 #include "trace.h"
 #include <trace/events/f2fs.h>
+#include <trace/events/android_fs.h>
 
 static void f2fs_read_end_io(struct bio *bio)
 {
@@ -1401,6 +1402,8 @@ static int f2fs_write_begin(struct file *file, struct address_space *mapping,
        struct dnode_of_data dn;
        int err = 0;
 
+       trace_android_fs_datawrite_start(inode, pos, len,
+                                        current->pid, current->comm);
        trace_f2fs_write_begin(inode, pos, len, flags);
 
        f2fs_balance_fs(sbi);
@@ -1529,6 +1532,7 @@ static int f2fs_write_end(struct file *file,
 {
        struct inode *inode = page->mapping->host;
 
+       trace_android_fs_datawrite_end(inode, pos, len);
        trace_f2fs_write_end(inode, pos, len, copied);
 
        set_page_dirty(page);
@@ -1582,6 +1586,16 @@ static ssize_t f2fs_direct_IO(struct kiocb *iocb, struct iov_iter *iter,
 
        trace_f2fs_direct_IO_enter(inode, offset, count, iov_iter_rw(iter));
 
+       if (trace_android_fs_dataread_start_enabled() &&
+           (iov_iter_rw(iter) == READ))
+               trace_android_fs_dataread_start(inode, offset,
+                                               count, current->pid,
+                                               current->comm);
+       if (trace_android_fs_datawrite_start_enabled() &&
+           (iov_iter_rw(iter) == WRITE))
+               trace_android_fs_datawrite_start(inode, offset, count,
+                                                current->pid, current->comm);
+
        if (iov_iter_rw(iter) == WRITE) {
                __allocate_data_blocks(inode, offset, count);
                if (unlikely(f2fs_cp_error(F2FS_I_SB(inode)))) {
@@ -1595,6 +1609,13 @@ out:
        if (err < 0 && iov_iter_rw(iter) == WRITE)
                f2fs_write_failed(mapping, offset + count);
 
+       if (trace_android_fs_dataread_start_enabled() &&
+           (iov_iter_rw(iter) == READ))
+               trace_android_fs_dataread_end(inode, offset, count);
+       if (trace_android_fs_datawrite_start_enabled() &&
+           (iov_iter_rw(iter) == WRITE))
+               trace_android_fs_datawrite_end(inode, offset, count);
+
        trace_f2fs_direct_IO_exit(inode, offset, count, iov_iter_rw(iter), err);
 
        return err;
index bda7126466c09f9b16f4d275cac5b287a06c9142..d2c5d69ba0b146bd2bd3a9b3a507f4e2655765ce 100644 (file)
@@ -13,6 +13,7 @@
 
 #include "f2fs.h"
 #include "node.h"
+#include <trace/events/android_fs.h>
 
 bool f2fs_may_inline_data(struct inode *inode)
 {
@@ -84,14 +85,22 @@ int f2fs_read_inline_data(struct inode *inode, struct page *page)
 {
        struct page *ipage;
 
+       trace_android_fs_dataread_start(inode, page_offset(page),
+                                       PAGE_SIZE, current->pid,
+                                       current->comm);
+
        ipage = get_node_page(F2FS_I_SB(inode), inode->i_ino);
        if (IS_ERR(ipage)) {
+               trace_android_fs_dataread_end(inode, page_offset(page),
+                                             PAGE_SIZE);
                unlock_page(page);
                return PTR_ERR(ipage);
        }
 
        if (!f2fs_has_inline_data(inode)) {
                f2fs_put_page(ipage, 1);
+               trace_android_fs_dataread_end(inode, page_offset(page),
+                                             PAGE_SIZE);
                return -EAGAIN;
        }
 
@@ -102,6 +111,8 @@ int f2fs_read_inline_data(struct inode *inode, struct page *page)
 
        SetPageUptodate(page);
        f2fs_put_page(ipage, 1);
+       trace_android_fs_dataread_end(inode, page_offset(page),
+                                     PAGE_SIZE);
        unlock_page(page);
        return 0;
 }
index 1480d3a180370fe3922a7724e613d09b896f9d00..5c65d8942692fd468558c9cac0052216af75a2bb 100644 (file)
 #include <linux/cleancache.h>
 #include "internal.h"
 
+#define CREATE_TRACE_POINTS
+#include <trace/events/android_fs.h>
+
+EXPORT_TRACEPOINT_SYMBOL(android_fs_datawrite_start);
+EXPORT_TRACEPOINT_SYMBOL(android_fs_datawrite_end);
+EXPORT_TRACEPOINT_SYMBOL(android_fs_dataread_start);
+EXPORT_TRACEPOINT_SYMBOL(android_fs_dataread_end);
+
 /*
  * I/O completion handler for multipage BIOs.
  *
@@ -47,6 +55,16 @@ static void mpage_end_io(struct bio *bio)
        struct bio_vec *bv;
        int i;
 
+       if (trace_android_fs_dataread_end_enabled() &&
+           (bio_data_dir(bio) == READ)) {
+               struct page *first_page = bio->bi_io_vec[0].bv_page;
+
+               if (first_page != NULL)
+                       trace_android_fs_dataread_end(first_page->mapping->host,
+                                                     page_offset(first_page),
+                                                     bio->bi_iter.bi_size);
+       }
+
        bio_for_each_segment_all(bv, bio, i) {
                struct page *page = bv->bv_page;
                page_endio(page, bio_data_dir(bio), bio->bi_error);
@@ -57,6 +75,18 @@ static void mpage_end_io(struct bio *bio)
 
 static struct bio *mpage_bio_submit(int rw, struct bio *bio)
 {
+       if (trace_android_fs_dataread_start_enabled() && (rw == READ)) {
+               struct page *first_page = bio->bi_io_vec[0].bv_page;
+
+               if (first_page != NULL) {
+                       trace_android_fs_dataread_start(
+                               first_page->mapping->host,
+                               page_offset(first_page),
+                               bio->bi_iter.bi_size,
+                               current->pid,
+                               current->comm);
+               }
+       }
        bio->bi_end_io = mpage_end_io;
        guard_bio_eod(rw, bio);
        submit_bio(rw, bio);
diff --git a/include/trace/events/android_fs.h b/include/trace/events/android_fs.h
new file mode 100644 (file)
index 0000000..531da43
--- /dev/null
@@ -0,0 +1,31 @@
+#undef TRACE_SYSTEM
+#define TRACE_SYSTEM android_fs
+
+#if !defined(_TRACE_ANDROID_FS_H) || defined(TRACE_HEADER_MULTI_READ)
+#define _TRACE_ANDROID_FS_H
+
+#include <linux/tracepoint.h>
+#include <trace/events/android_fs_template.h>
+
+DEFINE_EVENT(android_fs_data_start_template, android_fs_dataread_start,
+       TP_PROTO(struct inode *inode, loff_t offset, int bytes,
+                pid_t pid, char *command),
+       TP_ARGS(inode, offset, bytes, pid, command));
+
+DEFINE_EVENT(android_fs_data_end_template, android_fs_dataread_end,
+       TP_PROTO(struct inode *inode, loff_t offset, int bytes),
+       TP_ARGS(inode, offset, bytes));
+
+DEFINE_EVENT(android_fs_data_start_template, android_fs_datawrite_start,
+       TP_PROTO(struct inode *inode, loff_t offset, int bytes,
+                pid_t pid, char *command),
+       TP_ARGS(inode, offset, bytes, pid, command));
+
+DEFINE_EVENT(android_fs_data_end_template, android_fs_datawrite_end,
+       TP_PROTO(struct inode *inode, loff_t offset, int bytes),
+       TP_ARGS(inode, offset, bytes));
+
+#endif /* _TRACE_ANDROID_FS_H */
+
+/* This part must be outside protection */
+#include <trace/define_trace.h>
diff --git a/include/trace/events/android_fs_template.h b/include/trace/events/android_fs_template.h
new file mode 100644 (file)
index 0000000..618988b
--- /dev/null
@@ -0,0 +1,79 @@
+#if !defined(_TRACE_ANDROID_FS_TEMPLATE_H) || defined(TRACE_HEADER_MULTI_READ)
+#define _TRACE_ANDROID_FS_TEMPLATE_H
+
+#include <linux/tracepoint.h>
+
+DECLARE_EVENT_CLASS(android_fs_data_start_template,
+       TP_PROTO(struct inode *inode, loff_t offset, int bytes,
+                pid_t pid, char *command),
+       TP_ARGS(inode, offset, bytes, pid, command),
+       TP_STRUCT__entry(
+               __array(char, path, MAX_FILTER_STR_VAL);
+               __field(char *, pathname);
+               __field(loff_t, offset);
+               __field(int,    bytes);
+               __field(loff_t, i_size);
+               __string(cmdline, command);
+               __field(pid_t,  pid);
+               __field(ino_t,  ino);
+       ),
+       TP_fast_assign(
+               {
+                       struct dentry *d;
+
+                       /*
+                        * Grab a reference to the inode here because
+                        * d_obtain_alias() will either drop the inode
+                        * reference if it locates an existing dentry
+                        * or transfer the reference to the new dentry
+                        * created. In our case, the file is still open,
+                        * so the dentry is guaranteed to exist (connected),
+                        * so d_obtain_alias() drops the reference we
+                        * grabbed here.
+                        */
+                       ihold(inode);
+                       d = d_obtain_alias(inode);
+                       if (!IS_ERR(d)) {
+                               __entry->pathname = dentry_path(d,
+                                                       __entry->path,
+                                                       MAX_FILTER_STR_VAL);
+                               dput(d);
+                       } else
+                               __entry->pathname = ERR_PTR(-EINVAL);
+                       __entry->offset         = offset;
+                       __entry->bytes          = bytes;
+                       __entry->i_size         = i_size_read(inode);
+                       __assign_str(cmdline, command);
+                       __entry->pid            = pid;
+                       __entry->ino            = inode->i_ino;
+               }
+       ),
+       TP_printk("entry_name %s, offset %llu, bytes %d, cmdline %s,"
+                 " pid %d, i_size %llu, ino %lu",
+                 (IS_ERR(__entry->pathname) ? "ERROR" : __entry->pathname),
+                 __entry->offset, __entry->bytes, __get_str(cmdline),
+                 __entry->pid, __entry->i_size,
+                 (unsigned long) __entry->ino)
+);
+
+DECLARE_EVENT_CLASS(android_fs_data_end_template,
+       TP_PROTO(struct inode *inode, loff_t offset, int bytes),
+       TP_ARGS(inode, offset, bytes),
+       TP_STRUCT__entry(
+               __field(ino_t,  ino);
+               __field(loff_t, offset);
+               __field(int,    bytes);
+       ),
+       TP_fast_assign(
+               {
+                       __entry->ino            = inode->i_ino;
+                       __entry->offset         = offset;
+                       __entry->bytes          = bytes;
+               }
+       ),
+       TP_printk("ino %lu, offset %llu, bytes %d",
+                 (unsigned long) __entry->ino,
+                 __entry->offset, __entry->bytes)
+);
+
+#endif /* _TRACE_ANDROID_FS_TEMPLATE_H */