Add patch SR-ext4-resize-mark-new-group-EXT_BG_INODE_ZEROED.patch
[ext4-patch-queue/an.git] / dump-in-use-buffers
blob58cf4ec4646d6f415dd5d68c04c95b8fb8e4249d
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)
9         switch (cmd) {
10         case HDIO_GETGEO:
11                 return compat_hdio_getgeo(disk, bdev, compat_ptr(arg));
12 +       case BLKDUMPUSEDBUFFERS:
13         case BLKFLSBUF:
14         case BLKROSET:
15         case BLKDISCARD:
16 diff --git a/block/ioctl.c b/block/ioctl.c
17 index c832d63..9b73953 100644
18 --- a/block/ioctl.c
19 +++ b/block/ioctl.c
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);
22                 unlock_kernel();
23                 break;
24 +       case BLKDUMPUSEDBUFFERS:
25 +               if (!capable(CAP_SYS_ADMIN))
26 +                       return -EACCES;
27 +               dump_used_buffers(bdev);
28 +               ret = 0;
29 +               break;
31         default:
32                 ret = __blkdev_driver_ioctl(bdev, mode, cmd, arg);
33         }
34 diff --git a/fs/buffer.c b/fs/buffer.c
35 index 6569fda..852e7ac 100644
36 --- a/fs/buffer.c
37 +++ b/fs/buffer.c
38 @@ -33,6 +33,7 @@
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)
47  }
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));
62 +       while (1) {
63 +               nr_pages = pagevec_lookup(&pvec, bd_mapping, index, PAGEVEC_SIZE);
64 +               if (nr_pages == 0)
65 +                       break;
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))
71 +                               continue;
72 +                       bh = head = page_buffers(page);
73 +                       do {
74 +                               count = atomic_read(&bh->b_count);
75 +                               if (count) {
76 +                                       printk(KERN_INFO
77 +                                              "buffer in-use: block %Lu count %d\n",
78 +                                              (unsigned long long) bh->b_blocknr, count);
79 +                                       total++;
80 +                               }
81 +                               bh = bh->b_this_page;
82 +                       } while (bh != head);
83 +               }
84 +       }
85 +       printk(KERN_INFO "Total number of in-use buffers: %d\n", total);
86 +       spin_unlock(&bd_mapping->private_lock);
89  /*
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 */