2009-11-11 18:31:04

by Aneesh Kumar K.V

[permalink] [raw]
Subject: [RFC PATCH 1/2] vfs: tracepoints for buffer flag updates

We collect the device details so that we can filter with device value

Signed-off-by: Aneesh Kumar K.V <[email protected]>
---
fs/buffer.c | 2 +
include/linux/buffer_head.h | 11 +++-
include/trace/events/buffer_head.h | 95 ++++++++++++++++++++++++++++++++++++
3 files changed, 106 insertions(+), 2 deletions(-)
create mode 100644 include/trace/events/buffer_head.h

diff --git a/fs/buffer.c b/fs/buffer.c
index 6fa5302..6f441aa 100644
--- a/fs/buffer.c
+++ b/fs/buffer.c
@@ -41,6 +41,8 @@
#include <linux/bitops.h>
#include <linux/mpage.h>
#include <linux/bit_spinlock.h>
+#define CREATE_TRACE_POINTS
+#include <trace/events/buffer_head.h>

static int fsync_buffers_list(spinlock_t *lock, struct list_head *list);

diff --git a/include/linux/buffer_head.h b/include/linux/buffer_head.h
index 16ed028..1780701 100644
--- a/include/linux/buffer_head.h
+++ b/include/linux/buffer_head.h
@@ -13,6 +13,7 @@
#include <linux/pagemap.h>
#include <linux/wait.h>
#include <asm/atomic.h>
+#include <trace/events/buffer_head.h>

#ifdef CONFIG_BLOCK

@@ -84,10 +85,12 @@ struct buffer_head {
static inline void set_buffer_##name(struct buffer_head *bh) \
{ \
set_bit(BH_##bit, &(bh)->b_state); \
+ trace_set_buffer_##name(bh); \
} \
static inline void clear_buffer_##name(struct buffer_head *bh) \
{ \
clear_bit(BH_##bit, &(bh)->b_state); \
+ trace_clear_buffer_##name(bh); \
} \
static inline int buffer_##name(const struct buffer_head *bh) \
{ \
@@ -100,11 +103,15 @@ static inline int buffer_##name(const struct buffer_head *bh) \
#define TAS_BUFFER_FNS(bit, name) \
static inline int test_set_buffer_##name(struct buffer_head *bh) \
{ \
- return test_and_set_bit(BH_##bit, &(bh)->b_state); \
+ int ret = test_and_set_bit(BH_##bit, &(bh)->b_state); \
+ trace_set_buffer_##name(bh); \
+ return ret; \
} \
static inline int test_clear_buffer_##name(struct buffer_head *bh) \
{ \
- return test_and_clear_bit(BH_##bit, &(bh)->b_state); \
+ int ret = test_and_clear_bit(BH_##bit, &(bh)->b_state); \
+ trace_clear_buffer_##name(bh); \
+ return ret; \
} \

/*
diff --git a/include/trace/events/buffer_head.h b/include/trace/events/buffer_head.h
new file mode 100644
index 0000000..07605b5
--- /dev/null
+++ b/include/trace/events/buffer_head.h
@@ -0,0 +1,95 @@
+#undef TRACE_SYSTEM
+#define TRACE_SYSTEM buffer_head
+
+#if !defined(_TRACE_BUFFER_HEAD_H) || defined(TRACE_HEADER_MULTI_READ)
+#define _TRACE_BUFFER_HEAD_H
+
+#include <linux/tracepoint.h>
+struct buffer_head;
+extern const char *jbd2_dev_to_name(dev_t device);
+
+
+#define BUFFER_HEAD_TRACE_EVENT(name) \
+TRACE_EVENT(set_buffer_##name, \
+ TP_PROTO(struct buffer_head *bh), \
+ \
+ TP_ARGS(bh), \
+ \
+ TP_STRUCT__entry( \
+ __field( void *, buffer ) \
+ __field( sector_t, block ) \
+ __field( unsigned long, state ) \
+ __field( dev_t, dev ) \
+ ), \
+ \
+ TP_fast_assign( \
+ __entry->buffer = bh; \
+ __entry->block = bh->b_blocknr; \
+ __entry->state = bh->b_state; \
+ if (bh->b_bdev) \
+ __entry->dev = disk_devt(bh->b_bdev->bd_disk); \
+ else \
+ __entry->dev = 0; \
+ ), \
+ \
+ TP_printk("bh = %p device = %s block = %llu new state = 0x%lx", \
+ __entry->buffer, jbd2_dev_to_name(__entry->dev), \
+ (unsigned long long) __entry->block, \
+ __entry->state) \
+); \
+ \
+TRACE_EVENT(clear_buffer_##name, \
+ TP_PROTO(struct buffer_head *bh), \
+ \
+ TP_ARGS(bh), \
+ \
+ TP_STRUCT__entry( \
+ __field( void *, buffer ) \
+ __field( sector_t, block ) \
+ __field( unsigned long, state ) \
+ __field( dev_t, dev ) \
+ ), \
+ \
+ TP_fast_assign( \
+ __entry->buffer = bh; \
+ __entry->block = bh->b_blocknr; \
+ __entry->state = bh->b_state; \
+ if (bh->b_bdev) \
+ __entry->dev = disk_devt(bh->b_bdev->bd_disk); \
+ else \
+ __entry->dev = 0; \
+ ), \
+ \
+ TP_printk("bh = %p device = %s block = %llu new state = 0x%lx", \
+ __entry->buffer, jbd2_dev_to_name(__entry->dev), \
+ (unsigned long long) __entry->block, \
+ __entry->state) \
+)
+
+BUFFER_HEAD_TRACE_EVENT(uptodate);
+BUFFER_HEAD_TRACE_EVENT(dirty);
+BUFFER_HEAD_TRACE_EVENT(locked);
+BUFFER_HEAD_TRACE_EVENT(req);
+BUFFER_HEAD_TRACE_EVENT(mapped);
+BUFFER_HEAD_TRACE_EVENT(new);
+BUFFER_HEAD_TRACE_EVENT(async_read);
+BUFFER_HEAD_TRACE_EVENT(async_write);
+BUFFER_HEAD_TRACE_EVENT(delay);
+BUFFER_HEAD_TRACE_EVENT(boundary);
+BUFFER_HEAD_TRACE_EVENT(write_io_error);
+BUFFER_HEAD_TRACE_EVENT(ordered);
+BUFFER_HEAD_TRACE_EVENT(eopnotsupp);
+BUFFER_HEAD_TRACE_EVENT(unwritten);
+
+/* jbd */
+BUFFER_HEAD_TRACE_EVENT(jbd);
+BUFFER_HEAD_TRACE_EVENT(jwrite);
+BUFFER_HEAD_TRACE_EVENT(jbddirty);
+BUFFER_HEAD_TRACE_EVENT(revoked);
+BUFFER_HEAD_TRACE_EVENT(revokevalid);
+BUFFER_HEAD_TRACE_EVENT(freed);
+
+#endif /* _TRACE_BUFFER_HEAD_H */
+
+/* This part must be outside protection */
+#include <trace/define_trace.h>
--
1.6.5.2.74.g610f9



2009-11-11 18:31:05

by Aneesh Kumar K.V

[permalink] [raw]
Subject: [RFC PATCH 2/2] ext[34]: Make sure we initialize the b_bdev field of dummy buffer_heads

buffer_head flag update trace point look at the b_bdev field to track
the backing device. For dummy buffer_heads used we expect this to be
NULL.

Signed-off-by: Aneesh Kumar K.V <[email protected]>
---
fs/buffer.c | 1 +
fs/ext3/inode.c | 1 +
fs/ext4/inode.c | 1 +
fs/jbd/journal.c | 1 +
fs/jbd2/journal.c | 2 ++
fs/mpage.c | 1 +
6 files changed, 7 insertions(+), 0 deletions(-)

diff --git a/fs/buffer.c b/fs/buffer.c
index 6f441aa..5c60fa3 100644
--- a/fs/buffer.c
+++ b/fs/buffer.c
@@ -2923,6 +2923,7 @@ sector_t generic_block_bmap(struct address_space *mapping, sector_t block,
struct inode *inode = mapping->host;
tmp.b_state = 0;
tmp.b_blocknr = 0;
+ tmp.b_bdev = NULL;
tmp.b_size = 1 << inode->i_blkbits;
get_block(inode, block, &tmp, 0);
return tmp.b_blocknr;
diff --git a/fs/ext3/inode.c b/fs/ext3/inode.c
index acf1b14..c7508aa 100644
--- a/fs/ext3/inode.c
+++ b/fs/ext3/inode.c
@@ -1007,6 +1007,7 @@ struct buffer_head *ext3_getblk(handle_t *handle, struct inode *inode,

dummy.b_state = 0;
dummy.b_blocknr = -1000;
+ dummy.b_bdev = NULL;
buffer_trace_init(&dummy.b_history);
err = ext3_get_blocks_handle(handle, inode, block, 1,
&dummy, create);
diff --git a/fs/ext4/inode.c b/fs/ext4/inode.c
index 5c5bc5d..dcb362d 100644
--- a/fs/ext4/inode.c
+++ b/fs/ext4/inode.c
@@ -1392,6 +1392,7 @@ struct buffer_head *ext4_getblk(handle_t *handle, struct inode *inode,

dummy.b_state = 0;
dummy.b_blocknr = -1000;
+ dummy.b_bdev = NULL;
buffer_trace_init(&dummy.b_history);
if (create)
flags |= EXT4_GET_BLOCKS_CREATE;
diff --git a/fs/jbd/journal.c b/fs/jbd/journal.c
index bd3c073..1572a08 100644
--- a/fs/jbd/journal.c
+++ b/fs/jbd/journal.c
@@ -303,6 +303,7 @@ int journal_write_metadata_buffer(transaction_t *transaction,
new_bh = alloc_buffer_head(GFP_NOFS|__GFP_NOFAIL);
/* keep subsequent assertions sane */
new_bh->b_state = 0;
+ new_bh->b_bdev = NULL;
init_buffer(new_bh, NULL, NULL);
atomic_set(&new_bh->b_count, 1);
new_jh = journal_add_journal_head(new_bh); /* This sleeps */
diff --git a/fs/jbd2/journal.c b/fs/jbd2/journal.c
index b0ab521..f18af08 100644
--- a/fs/jbd2/journal.c
+++ b/fs/jbd2/journal.c
@@ -2250,6 +2250,8 @@ const char *jbd2_dev_to_name(dev_t device)
struct block_device *bd;
static struct devname_cache *new_dev;

+ if (!device)
+ return "NULL";
rcu_read_lock();
if (devcache[i] && devcache[i]->device == device) {
ret = devcache[i]->devname;
diff --git a/fs/mpage.c b/fs/mpage.c
index 42381bd..eb72426 100644
--- a/fs/mpage.c
+++ b/fs/mpage.c
@@ -381,6 +381,7 @@ mpage_readpages(struct address_space *mapping, struct list_head *pages,

map_bh.b_state = 0;
map_bh.b_size = 0;
+ map_bh.b_bdev = NULL;
for (page_idx = 0; page_idx < nr_pages; page_idx++) {
struct page *page = list_entry(pages->prev, struct page, lru);

--
1.6.5.2.74.g610f9


2009-11-11 18:39:38

by Aneesh Kumar K.V

[permalink] [raw]
Subject: Re: [RFC PATCH 1/2] vfs: tracepoints for buffer flag updates

This patchset when enabled with stacktrace will give output like the below

dd-1905 [003] 26.445155: set_buffer_uptodate: bh = df5c28c0 device = vda block = 34817 new state= 0x23
dd-1905 [003] 26.445156: <stack trace>
=> set_buffer_uptodate
=> __block_commit_write
=> block_write_end
=> ext3_writeback_write_end
=> generic_file_buffered_write
=> __generic_file_aio_write
=> generic_file_aio_write
=> do_sync_write
dd-1905 [003] 26.445168: clear_buffer_new: bh = df5c28c0 device = vda block = 34817 new state = 0x23
dd-1905 [003] 26.445169: <stack trace>
=> clear_buffer_new
=> __block_commit_write
=> block_write_end
=> ext3_writeback_write_end
=> generic_file_buffered_write
=> __generic_file_aio_write
=> generic_file_aio_write
=> do_sync_write
dd-1905 [003] 26.445182: set_buffer_revokevalid: bh = df406540 device = vda block = 32835 new state= 0x310029
dd-1905 [003] 26.445183: <stack trace>
=> journal_cancel_revoke
=> do_get_write_access
=> journal_get_write_access
=> __ext3_journal_get_write_access
=> ext3_reserve_inode_write
=> ext3_mark_inode_dirty
=> ext3_dirty_inode
=> __mark_inode_dirty
dd-1905 [003] 26.445197: clear_buffer_revoked: bh = df406540 device = vda block = 32835 new state = 0x310029
dd-1905 [003] 26.445198: <stack trace>
=> journal_cancel_revoke
=> do_get_write_access
=> journal_get_write_access
=> __ext3_journal_get_write_access
=> ext3_reserve_inode_write
=> ext3_mark_inode_dirty
=> ext3_dirty_inode
=> __mark_inode_dirty


-aneesh