1 Add a ioctl which dumps out all of the in-use buffer heads for a block device
3 Signed-off-by: "Theodore Ts'o" <tytso@mit.edu>
5 block/compat_ioctl.c | 4 ++++
6 block/ioctl.c | 11 +++++++++++
7 fs/buffer.c | 40 ++++++++++++++++++++++++++++++++++++++++
8 3 files changed, 55 insertions(+), 0 deletions(-)
10 diff --git a/block/compat_ioctl.c b/block/compat_ioctl.c
11 index 4eb8e9e..2535cb1 100644
12 --- a/block/compat_ioctl.c
13 +++ b/block/compat_ioctl.c
15 #include <linux/types.h>
16 #include <linux/uaccess.h>
18 +/* For debugging purposes; see block/ioctl.c */
19 +#define BLKDUMPUSEDBUFFERS _IO(0x12,130)
21 static int compat_put_ushort(unsigned long arg, unsigned short val)
23 return put_user(val, (unsigned short __user *)compat_ptr(arg));
24 @@ -749,6 +752,7 @@ long compat_blkdev_ioctl(struct file *file, unsigned cmd, unsigned long arg)
25 return compat_put_int(arg, bdev_alignment_offset(bdev));
26 case BLKDISCARDZEROES:
27 return compat_put_uint(arg, bdev_discard_zeroes_data(bdev));
28 + case BLKDUMPUSEDBUFFERS:
32 diff --git a/block/ioctl.c b/block/ioctl.c
33 index be48ea5..8cc002b 100644
37 #include <linux/blktrace_api.h>
38 #include <asm/uaccess.h>
40 +/* For debugging purposes */
41 +#define BLKDUMPUSEDBUFFERS _IO(0x12,130)
42 +extern void dump_used_buffers(struct block_device *bdev);
44 static int blkpg_ioctl(struct block_device *bdev, struct blkpg_ioctl_arg __user *arg)
46 struct block_device *bdevp;
47 @@ -332,6 +336,13 @@ int blkdev_ioctl(struct block_device *bdev, fmode_t mode, unsigned cmd,
48 ret = blk_trace_ioctl(bdev, cmd, (char __user *) arg);
51 + case BLKDUMPUSEDBUFFERS:
52 + if (!capable(CAP_SYS_ADMIN))
54 + dump_used_buffers(bdev);
59 ret = __blkdev_driver_ioctl(bdev, mode, cmd, arg);
61 diff --git a/fs/buffer.c b/fs/buffer.c
62 index 6fa5302..8438330 100644
66 #include <linux/writeback.h>
67 #include <linux/hash.h>
68 #include <linux/suspend.h>
69 +#include <linux/pagevec.h>
70 #include <linux/buffer_head.h>
71 #include <linux/task_io_accounting_ops.h>
72 #include <linux/bio.h>
73 @@ -300,6 +301,45 @@ static void free_more_memory(void)
77 +void dump_used_buffers(struct block_device *bdev)
79 + struct inode *bd_inode = bdev->bd_inode;
80 + struct address_space *bd_mapping = bd_inode->i_mapping;
81 + struct buffer_head *bh, *head;
82 + struct pagevec pvec;
83 + unsigned long index = 0;
84 + int nr_pages, i, count, total = 0;
85 + char b[BDEVNAME_SIZE];
87 + spin_lock(&bd_mapping->private_lock);
88 + printk(KERN_INFO "Begin dump of block device %s\n", bdevname(bdev, b));
90 + nr_pages = pagevec_lookup(&pvec, bd_mapping, index, PAGEVEC_SIZE);
93 + for (i = 0; i < nr_pages; i++) {
94 + struct page *page = pvec.pages[i];
95 + index = page->index + 1;
97 + if (!page_has_buffers(page))
99 + bh = head = page_buffers(page);
101 + count = atomic_read(&bh->b_count);
104 + "buffer in-use: block %Lu count %d\n",
105 + (unsigned long long) bh->b_blocknr, count);
108 + bh = bh->b_this_page;
109 + } while (bh != head);
112 + printk(KERN_INFO "Total number of in-use buffers: %d\n", total);
113 + spin_unlock(&bd_mapping->private_lock);
117 * I/O completion handler for block_read_full_page() - pages
118 * which come unlocked at the end of I/O.