add patch move-trans-handling-and-completion-deferal-out-of-_ext4_get_block
[ext4-patch-queue.git] / dump-in-use-buffers
blobcda73dc530bc908781785465e474ce3c1384d1fb
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 ---
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
14 @@ -11,6 +11,9 @@
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)
22  {
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:
29         case BLKFLSBUF:
30         case BLKROSET:
31         case BLKDISCARD:
32 diff --git a/block/ioctl.c b/block/ioctl.c
33 index be48ea5..8cc002b 100644
34 --- a/block/ioctl.c
35 +++ b/block/ioctl.c
36 @@ -8,6 +8,10 @@
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)
45  {
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);
49                 unlock_kernel();
50                 break;
51 +       case BLKDUMPUSEDBUFFERS:
52 +               if (!capable(CAP_SYS_ADMIN))
53 +                       return -EACCES;
54 +               dump_used_buffers(bdev);
55 +               ret = 0;
56 +               break;
58         default:
59                 ret = __blkdev_driver_ioctl(bdev, mode, cmd, arg);
60         }
61 diff --git a/fs/buffer.c b/fs/buffer.c
62 index 6fa5302..8438330 100644
63 --- a/fs/buffer.c
64 +++ b/fs/buffer.c
65 @@ -33,6 +33,7 @@
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)
74         }
75  }
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));
89 +       while (1) {
90 +               nr_pages = pagevec_lookup(&pvec, bd_mapping, index, PAGEVEC_SIZE);
91 +               if (nr_pages == 0)
92 +                       break;
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))
98 +                               continue;
99 +                       bh = head = page_buffers(page);
100 +                       do {
101 +                               count = atomic_read(&bh->b_count);
102 +                               if (count) {
103 +                                       printk(KERN_INFO
104 +                                              "buffer in-use: block %Lu count %d\n",
105 +                                              (unsigned long long) bh->b_blocknr, count);
106 +                                       total++;
107 +                               }
108 +                               bh = bh->b_this_page;
109 +                       } while (bh != head);
110 +               }
111 +       }
112 +       printk(KERN_INFO "Total number of in-use buffers: %d\n", total);
113 +       spin_unlock(&bd_mapping->private_lock);
116  /*
117   * I/O completion handler for block_read_full_page() - pages
118   * which come unlocked at the end of I/O.