ANDROID: fs: FS tracepoints to track IO.
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>
This commit is contained in:
parent
27f0430c61
commit
31f42471b1
8 changed files with 242 additions and 4 deletions
|
@ -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);
|
||||
|
|
|
@ -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;
|
||||
}
|
||||
|
||||
|
|
|
@ -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;
|
||||
}
|
||||
|
|
|
@ -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;
|
||||
|
|
|
@ -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;
|
||||
}
|
||||
|
|
30
fs/mpage.c
30
fs/mpage.c
|
@ -30,6 +30,14 @@
|
|||
#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);
|
||||
|
|
31
include/trace/events/android_fs.h
Normal file
31
include/trace/events/android_fs.h
Normal file
|
@ -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>
|
79
include/trace/events/android_fs_template.h
Normal file
79
include/trace/events/android_fs_template.h
Normal file
|
@ -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 */
|
Loading…
Add table
Reference in a new issue