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>
4 diff --git a/block/compat_ioctl.c b/block/compat_ioctl.c
5 index 3d3e7a4..5c428a8 100644
6 --- a/block/compat_ioctl.c
7 +++ b/block/compat_ioctl.c
8 @@ -705,6 +705,7 @@ long compat_blkdev_ioctl(struct file *file, unsigned cmd, unsigned long arg)
11 return compat_hdio_getgeo(disk, bdev, compat_ptr(arg));
12 + case BLKDUMPUSEDBUFFERS:
16 diff --git a/block/ioctl.c b/block/ioctl.c
17 index c832d63..9b73953 100644
20 @@ -367,6 +367,13 @@ int blkdev_ioctl(struct block_device *bdev, fmode_t mode, unsigned cmd,
21 ret = blk_trace_ioctl(bdev, cmd, (char __user *) arg);
24 + case BLKDUMPUSEDBUFFERS:
25 + if (!capable(CAP_SYS_ADMIN))
27 + dump_used_buffers(bdev);
32 ret = __blkdev_driver_ioctl(bdev, mode, cmd, arg);
34 diff --git a/fs/buffer.c b/fs/buffer.c
35 index 6569fda..852e7ac 100644
39 #include <linux/writeback.h>
40 #include <linux/hash.h>
41 #include <linux/suspend.h>
42 +#include <linux/pagevec.h>
43 #include <linux/buffer_head.h>
44 #include <linux/task_io_accounting_ops.h>
45 #include <linux/bio.h>
46 @@ -246,6 +247,45 @@ void thaw_bdev(struct block_device *bdev, struct super_block *sb)
48 EXPORT_SYMBOL(thaw_bdev);
50 +void dump_used_buffers(struct block_device *bdev)
52 + struct inode *bd_inode = bdev->bd_inode;
53 + struct address_space *bd_mapping = bd_inode->i_mapping;
54 + struct buffer_head *bh, *head;
55 + struct pagevec pvec;
56 + unsigned long index = 0;
57 + int nr_pages, i, count, total = 0;
58 + char b[BDEVNAME_SIZE];
60 + spin_lock(&bd_mapping->private_lock);
61 + printk(KERN_INFO "Begin dump of block device %s\n", bdevname(bdev, b));
63 + nr_pages = pagevec_lookup(&pvec, bd_mapping, index, PAGEVEC_SIZE);
66 + for (i = 0; i < nr_pages; i++) {
67 + struct page *page = pvec.pages[i];
68 + index = page->index + 1;
70 + if (!page_has_buffers(page))
72 + bh = head = page_buffers(page);
74 + count = atomic_read(&bh->b_count);
77 + "buffer in-use: block %Lu count %d\n",
78 + (unsigned long long) bh->b_blocknr, count);
81 + bh = bh->b_this_page;
82 + } while (bh != head);
85 + printk(KERN_INFO "Total number of in-use buffers: %d\n", total);
86 + spin_unlock(&bd_mapping->private_lock);
90 * Various filesystems appear to want __find_get_block to be non-blocking.
91 * But it's the page lock which protects the buffers. To get around this,
92 diff --git a/include/linux/buffer_head.h b/include/linux/buffer_head.h
93 index 3ce64b9..053e644 100644
94 --- a/include/linux/buffer_head.h
95 +++ b/include/linux/buffer_head.h
96 @@ -193,6 +193,7 @@ void write_boundary_block(struct block_device *bdev,
97 sector_t bblock, unsigned blocksize);
98 int bh_uptodate_or_lock(struct buffer_head *bh);
99 int bh_submit_read(struct buffer_head *bh);
100 +void dump_used_buffers(struct block_device *bdev);
102 extern int buffer_heads_over_limit;
104 diff --git a/include/linux/fs.h b/include/linux/fs.h
105 index 5b248d6..a08e4d0 100644
106 --- a/include/linux/fs.h
107 +++ b/include/linux/fs.h
108 @@ -231,6 +231,8 @@ extern int dir_notify_enable;
109 #define BLKTRACETEARDOWN _IO(0x12,118)
110 #define BLKDISCARD _IO(0x12,119)
112 +#define BLKDUMPUSEDBUFFERS _IO(0x12,130)
114 #define BMAP_IOCTL 1 /* obsolete - kept for compatibility */
115 #define FIBMAP _IO(0x00,1) /* bmap access */
116 #define FIGETBSZ _IO(0x00,2) /* get the block size used for bmap */