]> git.itanic.dy.fi Git - linux-stable/commitdiff
ext4, jbd2: add an optimized bmap for the journal inode
authorTheodore Ts'o <tytso@mit.edu>
Wed, 8 Mar 2023 04:15:49 +0000 (23:15 -0500)
committerTheodore Ts'o <tytso@mit.edu>
Sat, 11 Mar 2023 05:44:24 +0000 (00:44 -0500)
The generic bmap() function exported by the VFS takes locks and does
checks that are not necessary for the journal inode.  So allow the
file system to set a journal-optimized bmap function in
journal->j_bmap.

Reported-by: syzbot+9543479984ae9e576000@syzkaller.appspotmail.com
Link: https://syzkaller.appspot.com/bug?id=e4aaa78795e490421c79f76ec3679006c8ff4cf0
Signed-off-by: Theodore Ts'o <tytso@mit.edu>
fs/ext4/super.c
fs/jbd2/journal.c
include/linux/jbd2.h

index 2192b4111442727903c92104ba180e29547f2362..46b7345d2b6a91d68fb598571a4be4e43901f779 100644 (file)
@@ -5742,6 +5742,28 @@ static struct inode *ext4_get_journal_inode(struct super_block *sb,
        return journal_inode;
 }
 
+static int ext4_journal_bmap(journal_t *journal, sector_t *block)
+{
+       struct ext4_map_blocks map;
+       int ret;
+
+       if (journal->j_inode == NULL)
+               return 0;
+
+       map.m_lblk = *block;
+       map.m_len = 1;
+       ret = ext4_map_blocks(NULL, journal->j_inode, &map, 0);
+       if (ret <= 0) {
+               ext4_msg(journal->j_inode->i_sb, KERN_CRIT,
+                        "journal bmap failed: block %llu ret %d\n",
+                        *block, ret);
+               jbd2_journal_abort(journal, ret ? ret : -EIO);
+               return ret;
+       }
+       *block = map.m_pblk;
+       return 0;
+}
+
 static journal_t *ext4_get_journal(struct super_block *sb,
                                   unsigned int journal_inum)
 {
@@ -5762,6 +5784,7 @@ static journal_t *ext4_get_journal(struct super_block *sb,
                return NULL;
        }
        journal->j_private = sb;
+       journal->j_bmap = ext4_journal_bmap;
        ext4_init_journal_params(sb, journal);
        return journal;
 }
index 2696f43e7239f809bcc1ff7b784ea51d94fa6f99..c84f588fdcd038e8b7dd85f5384710c12cd31025 100644 (file)
@@ -970,10 +970,13 @@ int jbd2_journal_bmap(journal_t *journal, unsigned long blocknr,
 {
        int err = 0;
        unsigned long long ret;
-       sector_t block = 0;
+       sector_t block = blocknr;
 
-       if (journal->j_inode) {
-               block = blocknr;
+       if (journal->j_bmap) {
+               err = journal->j_bmap(journal, &block);
+               if (err == 0)
+                       *retp = block;
+       } else if (journal->j_inode) {
                ret = bmap(journal->j_inode, &block);
 
                if (ret || !block) {
index 2170e0cc279d5cb823f5be2cca53cc3d9b5eece8..6ffa34c51a11be21bea2dc0832562cb1ac54e72c 100644 (file)
@@ -1308,6 +1308,14 @@ struct journal_s
                                    struct buffer_head *bh,
                                    enum passtype pass, int off,
                                    tid_t expected_commit_id);
+
+       /**
+        * @j_bmap:
+        *
+        * Bmap function that should be used instead of the generic
+        * VFS bmap function.
+        */
+       int (*j_bmap)(struct journal_s *journal, sector_t *block);
 };
 
 #define jbd2_might_wait_for_commit(j) \