[PATCH] bfs iget() abuses
authorAl Viro <viro@ftp.linux.org.uk>
Tue, 4 Oct 2005 16:48:44 +0000 (17:48 +0100)
committerLinus Torvalds <torvalds@g5.osdl.org>
Tue, 4 Oct 2005 20:22:01 +0000 (13:22 -0700)
bfs_fill_super() walks the inode table to get the bitmap of free inodes
and collect stats.  It has no business using iget() for that - it's a
lot of extra work, extra icache pollution and more complex code.
Switched to walking the damn thing directly.

Note: that also allows to kill ->i_dsk_ino in there - separate patch if
Tigran can confirm that this field can be zero only for deleted inodes
(i.e.  something that could only be found during that scan and not by
normal lookups).

Signed-off-by: Al Viro <viro@zeniv.linux.org.uk>
Signed-off-by: Linus Torvalds <torvalds@osdl.org>
fs/bfs/inode.c

index 868af0f..3af6c73 100644 (file)
@@ -362,23 +362,41 @@ static int bfs_fill_super(struct super_block *s, void *data, int silent)
        info->si_lf_eblk = 0;
        info->si_lf_sblk = 0;
        info->si_lf_ioff = 0;
+       bh = NULL;
        for (i=BFS_ROOT_INO; i<=info->si_lasti; i++) {
-               inode = iget(s,i);
-               if (BFS_I(inode)->i_dsk_ino == 0)
+               struct bfs_inode *di;
+               int block = (i - BFS_ROOT_INO)/BFS_INODES_PER_BLOCK + 1;
+               int off = (i - BFS_ROOT_INO) % BFS_INODES_PER_BLOCK;
+               unsigned long sblock, eblock;
+
+               if (!off) {
+                       brelse(bh);
+                       bh = sb_bread(s, block);
+               }
+
+               if (!bh)
+                       continue;
+
+               di = (struct bfs_inode *)bh->b_data + off;
+
+               if (!di->i_ino) {
                        info->si_freei++;
-               else {
-                       set_bit(i, info->si_imap);
-                       info->si_freeb -= inode->i_blocks;
-                       if (BFS_I(inode)->i_eblock > info->si_lf_eblk) {
-                               info->si_lf_eblk = BFS_I(inode)->i_eblock;
-                               info->si_lf_sblk = BFS_I(inode)->i_sblock;
-                               info->si_lf_ioff = BFS_INO2OFF(i);
-                       }
+                       continue;
+               }
+               set_bit(i, info->si_imap);
+               info->si_freeb -= BFS_FILEBLOCKS(di);
+
+               sblock =  le32_to_cpu(di->i_sblock);
+               eblock =  le32_to_cpu(di->i_eblock);
+               if (eblock > info->si_lf_eblk) {
+                       info->si_lf_eblk = eblock;
+                       info->si_lf_sblk = sblock;
+                       info->si_lf_ioff = BFS_INO2OFF(i);
                }
-               iput(inode);
        }
+       brelse(bh);
        if (!(s->s_flags & MS_RDONLY)) {
-               mark_buffer_dirty(bh);
+               mark_buffer_dirty(info->si_sbh);
                s->s_dirt = 1;
        } 
        dump_imap("read_super", s);