]> git.ipfire.org Git - thirdparty/linux.git/commitdiff
Merge tag 'ext4_for_linus-6.7-rc6' of git://git.kernel.org/pub/scm/linux/kernel/git...
authorLinus Torvalds <torvalds@linux-foundation.org>
Tue, 12 Dec 2023 19:37:04 +0000 (11:37 -0800)
committerLinus Torvalds <torvalds@linux-foundation.org>
Tue, 12 Dec 2023 19:37:04 +0000 (11:37 -0800)
Pull ext4 fixes from Ted Ts'o:
 "Fix various bugs / regressions for ext4, including a soft lockup, a
  WARN_ON, and a BUG"

* tag 'ext4_for_linus-6.7-rc6' of git://git.kernel.org/pub/scm/linux/kernel/git/tytso/ext4:
  jbd2: fix soft lockup in journal_finish_inode_data_buffers()
  ext4: fix warning in ext4_dio_write_end_io()
  jbd2: increase the journal IO's priority
  jbd2: correct the printing of write_flags in jbd2_write_superblock()
  ext4: prevent the normalized size from exceeding EXT_MAX_BLOCKS

fs/ext4/file.c
fs/ext4/mballoc.c
fs/jbd2/commit.c
fs/jbd2/journal.c
include/linux/jbd2.h

index 0166bb9ca160bdb5196aa9731b2c2daebd3c7116..6aa15dafc67786559d3b68ebfefd8f90e119b3fc 100644 (file)
@@ -349,9 +349,10 @@ static void ext4_inode_extension_cleanup(struct inode *inode, ssize_t count)
                return;
        }
        /*
-        * If i_disksize got extended due to writeback of delalloc blocks while
-        * the DIO was running we could fail to cleanup the orphan list in
-        * ext4_handle_inode_extension(). Do it now.
+        * If i_disksize got extended either due to writeback of delalloc
+        * blocks or extending truncate while the DIO was running we could fail
+        * to cleanup the orphan list in ext4_handle_inode_extension(). Do it
+        * now.
         */
        if (!list_empty(&EXT4_I(inode)->i_orphan) && inode->i_nlink) {
                handle_t *handle = ext4_journal_start(inode, EXT4_HT_INODE, 2);
@@ -386,10 +387,11 @@ static int ext4_dio_write_end_io(struct kiocb *iocb, ssize_t size,
         * blocks. But the code in ext4_iomap_alloc() is careful to use
         * zeroed/unwritten extents if this is possible; thus we won't leave
         * uninitialized blocks in a file even if we didn't succeed in writing
-        * as much as we intended.
+        * as much as we intended. Also we can race with truncate or write
+        * expanding the file so we have to be a bit careful here.
         */
-       WARN_ON_ONCE(i_size_read(inode) < READ_ONCE(EXT4_I(inode)->i_disksize));
-       if (pos + size <= READ_ONCE(EXT4_I(inode)->i_disksize))
+       if (pos + size <= READ_ONCE(EXT4_I(inode)->i_disksize) &&
+           pos + size <= i_size_read(inode))
                return size;
        return ext4_handle_inode_extension(inode, pos, size);
 }
index 454d5612641ee3c32e71114e4d6148c52b484459..d72b5e3c92ec4088b878246f431059906d8cf931 100644 (file)
@@ -4478,6 +4478,10 @@ ext4_mb_normalize_request(struct ext4_allocation_context *ac,
        start = max(start, rounddown(ac->ac_o_ex.fe_logical,
                        (ext4_lblk_t)EXT4_BLOCKS_PER_GROUP(ac->ac_sb)));
 
+       /* avoid unnecessary preallocation that may trigger assertions */
+       if (start + size > EXT_MAX_BLOCKS)
+               size = EXT_MAX_BLOCKS - start;
+
        /* don't cover already allocated blocks in selected range */
        if (ar->pleft && start <= ar->lleft) {
                size -= ar->lleft + 1 - start;
index 8d6f934c3d9543d3c87a77f5ec3566df7a2b2a37..5e122586e06ed0f9b9a36ebfe089ca7b3a75aee8 100644 (file)
@@ -119,7 +119,7 @@ static int journal_submit_commit_record(journal_t *journal,
        struct commit_header *tmp;
        struct buffer_head *bh;
        struct timespec64 now;
-       blk_opf_t write_flags = REQ_OP_WRITE | REQ_SYNC;
+       blk_opf_t write_flags = REQ_OP_WRITE | JBD2_JOURNAL_REQ_FLAGS;
 
        *cbh = NULL;
 
@@ -270,6 +270,7 @@ static int journal_finish_inode_data_buffers(journal_t *journal,
                        if (!ret)
                                ret = err;
                }
+               cond_resched();
                spin_lock(&journal->j_list_lock);
                jinode->i_flags &= ~JI_COMMIT_RUNNING;
                smp_mb();
@@ -395,8 +396,7 @@ void jbd2_journal_commit_transaction(journal_t *journal)
                 */
                jbd2_journal_update_sb_log_tail(journal,
                                                journal->j_tail_sequence,
-                                               journal->j_tail,
-                                               REQ_SYNC);
+                                               journal->j_tail, 0);
                mutex_unlock(&journal->j_checkpoint_mutex);
        } else {
                jbd2_debug(3, "superblock not updated\n");
@@ -715,6 +715,7 @@ start_journal_io:
 
                        for (i = 0; i < bufs; i++) {
                                struct buffer_head *bh = wbuf[i];
+
                                /*
                                 * Compute checksum.
                                 */
@@ -727,7 +728,8 @@ start_journal_io:
                                clear_buffer_dirty(bh);
                                set_buffer_uptodate(bh);
                                bh->b_end_io = journal_end_buffer_io_sync;
-                               submit_bh(REQ_OP_WRITE | REQ_SYNC, bh);
+                               submit_bh(REQ_OP_WRITE | JBD2_JOURNAL_REQ_FLAGS,
+                                         bh);
                        }
                        cond_resched();
 
index ed53188472f9aa9949d1c3c6338cba01f725b79a..206cb53ef2b06813a7344da309e0d811dd3e808c 100644 (file)
@@ -1100,8 +1100,7 @@ int __jbd2_update_log_tail(journal_t *journal, tid_t tid, unsigned long block)
         * space and if we lose sb update during power failure we'd replay
         * old transaction with possibly newly overwritten data.
         */
-       ret = jbd2_journal_update_sb_log_tail(journal, tid, block,
-                                             REQ_SYNC | REQ_FUA);
+       ret = jbd2_journal_update_sb_log_tail(journal, tid, block, REQ_FUA);
        if (ret)
                goto out;
 
@@ -1775,8 +1774,7 @@ static int journal_reset(journal_t *journal)
                 */
                jbd2_journal_update_sb_log_tail(journal,
                                                journal->j_tail_sequence,
-                                               journal->j_tail,
-                                               REQ_SYNC | REQ_FUA);
+                                               journal->j_tail, REQ_FUA);
                mutex_unlock(&journal->j_checkpoint_mutex);
        }
        return jbd2_journal_start_thread(journal);
@@ -1798,9 +1796,16 @@ static int jbd2_write_superblock(journal_t *journal, blk_opf_t write_flags)
                return -EIO;
        }
 
-       trace_jbd2_write_superblock(journal, write_flags);
+       /*
+        * Always set high priority flags to exempt from block layer's
+        * QOS policies, e.g. writeback throttle.
+        */
+       write_flags |= JBD2_JOURNAL_REQ_FLAGS;
        if (!(journal->j_flags & JBD2_BARRIER))
                write_flags &= ~(REQ_FUA | REQ_PREFLUSH);
+
+       trace_jbd2_write_superblock(journal, write_flags);
+
        if (buffer_write_io_error(bh)) {
                /*
                 * Oh, dear.  A previous attempt to write the journal
@@ -2050,7 +2055,7 @@ void jbd2_journal_update_sb_errno(journal_t *journal)
        jbd2_debug(1, "JBD2: updating superblock error (errno %d)\n", errcode);
        sb->s_errno    = cpu_to_be32(errcode);
 
-       jbd2_write_superblock(journal, REQ_SYNC | REQ_FUA);
+       jbd2_write_superblock(journal, REQ_FUA);
 }
 EXPORT_SYMBOL(jbd2_journal_update_sb_errno);
 
@@ -2171,8 +2176,7 @@ int jbd2_journal_destroy(journal_t *journal)
                                ++journal->j_transaction_sequence;
                        write_unlock(&journal->j_state_lock);
 
-                       jbd2_mark_journal_empty(journal,
-                                       REQ_SYNC | REQ_PREFLUSH | REQ_FUA);
+                       jbd2_mark_journal_empty(journal, REQ_PREFLUSH | REQ_FUA);
                        mutex_unlock(&journal->j_checkpoint_mutex);
                } else
                        err = -EIO;
@@ -2473,7 +2477,7 @@ int jbd2_journal_flush(journal_t *journal, unsigned int flags)
         * the magic code for a fully-recovered superblock.  Any future
         * commits of data to the journal will restore the current
         * s_start value. */
-       jbd2_mark_journal_empty(journal, REQ_SYNC | REQ_FUA);
+       jbd2_mark_journal_empty(journal, REQ_FUA);
 
        if (flags)
                err = __jbd2_journal_erase(journal, flags);
@@ -2519,7 +2523,7 @@ int jbd2_journal_wipe(journal_t *journal, int write)
        if (write) {
                /* Lock to make assertions happy... */
                mutex_lock_io(&journal->j_checkpoint_mutex);
-               jbd2_mark_journal_empty(journal, REQ_SYNC | REQ_FUA);
+               jbd2_mark_journal_empty(journal, REQ_FUA);
                mutex_unlock(&journal->j_checkpoint_mutex);
        }
 
index 6dcbb4eb80fb2085c578ef4c8fd40bfeba9d6db3..beb30719ee161bad0e01db32edfd14e610a6634c 100644 (file)
@@ -1374,6 +1374,9 @@ JBD2_FEATURE_INCOMPAT_FUNCS(csum2,                CSUM_V2)
 JBD2_FEATURE_INCOMPAT_FUNCS(csum3,             CSUM_V3)
 JBD2_FEATURE_INCOMPAT_FUNCS(fast_commit,       FAST_COMMIT)
 
+/* Journal high priority write IO operation flags */
+#define JBD2_JOURNAL_REQ_FLAGS         (REQ_META | REQ_SYNC | REQ_IDLE)
+
 /*
  * Journal flag definitions
  */