]> git.ipfire.org Git - thirdparty/kernel/stable-queue.git/commitdiff
4.19-stable patches
authorGreg Kroah-Hartman <gregkh@linuxfoundation.org>
Sun, 26 May 2024 13:52:19 +0000 (15:52 +0200)
committerGreg Kroah-Hartman <gregkh@linuxfoundation.org>
Sun, 26 May 2024 13:52:19 +0000 (15:52 +0200)
added patches:
nilfs2-fix-potential-hang-in-nilfs_detach_log_writer.patch
nilfs2-fix-unexpected-freezing-of-nilfs_segctor_sync.patch

queue-4.19/nilfs2-fix-potential-hang-in-nilfs_detach_log_writer.patch [new file with mode: 0644]
queue-4.19/nilfs2-fix-unexpected-freezing-of-nilfs_segctor_sync.patch [new file with mode: 0644]
queue-4.19/series

diff --git a/queue-4.19/nilfs2-fix-potential-hang-in-nilfs_detach_log_writer.patch b/queue-4.19/nilfs2-fix-potential-hang-in-nilfs_detach_log_writer.patch
new file mode 100644 (file)
index 0000000..aa342eb
--- /dev/null
@@ -0,0 +1,110 @@
+From eb85dace897c5986bc2f36b3c783c6abb8a4292e Mon Sep 17 00:00:00 2001
+From: Ryusuke Konishi <konishi.ryusuke@gmail.com>
+Date: Mon, 20 May 2024 22:26:21 +0900
+Subject: nilfs2: fix potential hang in nilfs_detach_log_writer()
+
+From: Ryusuke Konishi <konishi.ryusuke@gmail.com>
+
+commit eb85dace897c5986bc2f36b3c783c6abb8a4292e upstream.
+
+Syzbot has reported a potential hang in nilfs_detach_log_writer() called
+during nilfs2 unmount.
+
+Analysis revealed that this is because nilfs_segctor_sync(), which
+synchronizes with the log writer thread, can be called after
+nilfs_segctor_destroy() terminates that thread, as shown in the call trace
+below:
+
+nilfs_detach_log_writer
+  nilfs_segctor_destroy
+    nilfs_segctor_kill_thread  --> Shut down log writer thread
+    flush_work
+      nilfs_iput_work_func
+        nilfs_dispose_list
+          iput
+            nilfs_evict_inode
+              nilfs_transaction_commit
+                nilfs_construct_segment (if inode needs sync)
+                  nilfs_segctor_sync  --> Attempt to synchronize with
+                                          log writer thread
+                           *** DEADLOCK ***
+
+Fix this issue by changing nilfs_segctor_sync() so that the log writer
+thread returns normally without synchronizing after it terminates, and by
+forcing tasks that are already waiting to complete once after the thread
+terminates.
+
+The skipped inode metadata flushout will then be processed together in the
+subsequent cleanup work in nilfs_segctor_destroy().
+
+Link: https://lkml.kernel.org/r/20240520132621.4054-4-konishi.ryusuke@gmail.com
+Signed-off-by: Ryusuke Konishi <konishi.ryusuke@gmail.com>
+Reported-by: syzbot+e3973c409251e136fdd0@syzkaller.appspotmail.com
+Closes: https://syzkaller.appspot.com/bug?extid=e3973c409251e136fdd0
+Tested-by: Ryusuke Konishi <konishi.ryusuke@gmail.com>
+Cc: <stable@vger.kernel.org>
+Cc: "Bai, Shuangpeng" <sjb7183@psu.edu>
+Signed-off-by: Andrew Morton <akpm@linux-foundation.org>
+Signed-off-by: Greg Kroah-Hartman <gregkh@linuxfoundation.org>
+---
+ fs/nilfs2/segment.c |   21 ++++++++++++++++++---
+ 1 file changed, 18 insertions(+), 3 deletions(-)
+
+--- a/fs/nilfs2/segment.c
++++ b/fs/nilfs2/segment.c
+@@ -2229,6 +2229,14 @@ static int nilfs_segctor_sync(struct nil
+       for (;;) {
+               set_current_state(TASK_INTERRUPTIBLE);
++              /*
++               * Synchronize only while the log writer thread is alive.
++               * Leave flushing out after the log writer thread exits to
++               * the cleanup work in nilfs_segctor_destroy().
++               */
++              if (!sci->sc_task)
++                      break;
++
+               if (atomic_read(&wait_req.done)) {
+                       err = wait_req.err;
+                       break;
+@@ -2244,7 +2252,7 @@ static int nilfs_segctor_sync(struct nil
+       return err;
+ }
+-static void nilfs_segctor_wakeup(struct nilfs_sc_info *sci, int err)
++static void nilfs_segctor_wakeup(struct nilfs_sc_info *sci, int err, bool force)
+ {
+       struct nilfs_segctor_wait_request *wrq, *n;
+       unsigned long flags;
+@@ -2252,7 +2260,7 @@ static void nilfs_segctor_wakeup(struct
+       spin_lock_irqsave(&sci->sc_wait_request.lock, flags);
+       list_for_each_entry_safe(wrq, n, &sci->sc_wait_request.head, wq.entry) {
+               if (!atomic_read(&wrq->done) &&
+-                  nilfs_cnt32_ge(sci->sc_seq_done, wrq->seq)) {
++                  (force || nilfs_cnt32_ge(sci->sc_seq_done, wrq->seq))) {
+                       wrq->err = err;
+                       atomic_set(&wrq->done, 1);
+               }
+@@ -2392,7 +2400,7 @@ static void nilfs_segctor_notify(struct
+       if (mode == SC_LSEG_SR) {
+               sci->sc_state &= ~NILFS_SEGCTOR_COMMIT;
+               sci->sc_seq_done = sci->sc_seq_accepted;
+-              nilfs_segctor_wakeup(sci, err);
++              nilfs_segctor_wakeup(sci, err, false);
+               sci->sc_flush_request = 0;
+       } else {
+               if (mode == SC_FLUSH_FILE)
+@@ -2774,6 +2782,13 @@ static void nilfs_segctor_destroy(struct
+               || sci->sc_seq_request != sci->sc_seq_done);
+       spin_unlock(&sci->sc_state_lock);
++      /*
++       * Forcibly wake up tasks waiting in nilfs_segctor_sync(), which can
++       * be called from delayed iput() via nilfs_evict_inode() and can race
++       * with the above log writer thread termination.
++       */
++      nilfs_segctor_wakeup(sci, 0, true);
++
+       if (flush_work(&sci->sc_iput_work))
+               flag = true;
diff --git a/queue-4.19/nilfs2-fix-unexpected-freezing-of-nilfs_segctor_sync.patch b/queue-4.19/nilfs2-fix-unexpected-freezing-of-nilfs_segctor_sync.patch
new file mode 100644 (file)
index 0000000..e261a6e
--- /dev/null
@@ -0,0 +1,82 @@
+From 936184eadd82906992ff1f5ab3aada70cce44cee Mon Sep 17 00:00:00 2001
+From: Ryusuke Konishi <konishi.ryusuke@gmail.com>
+Date: Mon, 20 May 2024 22:26:20 +0900
+Subject: nilfs2: fix unexpected freezing of nilfs_segctor_sync()
+
+From: Ryusuke Konishi <konishi.ryusuke@gmail.com>
+
+commit 936184eadd82906992ff1f5ab3aada70cce44cee upstream.
+
+A potential and reproducible race issue has been identified where
+nilfs_segctor_sync() would block even after the log writer thread writes a
+checkpoint, unless there is an interrupt or other trigger to resume log
+writing.
+
+This turned out to be because, depending on the execution timing of the
+log writer thread running in parallel, the log writer thread may skip
+responding to nilfs_segctor_sync(), which causes a call to schedule()
+waiting for completion within nilfs_segctor_sync() to lose the opportunity
+to wake up.
+
+The reason why waking up the task waiting in nilfs_segctor_sync() may be
+skipped is that updating the request generation issued using a shared
+sequence counter and adding an wait queue entry to the request wait queue
+to the log writer, are not done atomically.  There is a possibility that
+log writing and request completion notification by nilfs_segctor_wakeup()
+may occur between the two operations, and in that case, the wait queue
+entry is not yet visible to nilfs_segctor_wakeup() and the wake-up of
+nilfs_segctor_sync() will be carried over until the next request occurs.
+
+Fix this issue by performing these two operations simultaneously within
+the lock section of sc_state_lock.  Also, following the memory barrier
+guidelines for event waiting loops, move the call to set_current_state()
+in the same location into the event waiting loop to ensure that a memory
+barrier is inserted just before the event condition determination.
+
+Link: https://lkml.kernel.org/r/20240520132621.4054-3-konishi.ryusuke@gmail.com
+Fixes: 9ff05123e3bf ("nilfs2: segment constructor")
+Signed-off-by: Ryusuke Konishi <konishi.ryusuke@gmail.com>
+Tested-by: Ryusuke Konishi <konishi.ryusuke@gmail.com>
+Cc: <stable@vger.kernel.org>
+Cc: "Bai, Shuangpeng" <sjb7183@psu.edu>
+Signed-off-by: Andrew Morton <akpm@linux-foundation.org>
+Signed-off-by: Greg Kroah-Hartman <gregkh@linuxfoundation.org>
+---
+ fs/nilfs2/segment.c |   17 +++++++++++++----
+ 1 file changed, 13 insertions(+), 4 deletions(-)
+
+--- a/fs/nilfs2/segment.c
++++ b/fs/nilfs2/segment.c
+@@ -2207,19 +2207,28 @@ static int nilfs_segctor_sync(struct nil
+       struct nilfs_segctor_wait_request wait_req;
+       int err = 0;
+-      spin_lock(&sci->sc_state_lock);
+       init_wait(&wait_req.wq);
+       wait_req.err = 0;
+       atomic_set(&wait_req.done, 0);
++      init_waitqueue_entry(&wait_req.wq, current);
++
++      /*
++       * To prevent a race issue where completion notifications from the
++       * log writer thread are missed, increment the request sequence count
++       * "sc_seq_request" and insert a wait queue entry using the current
++       * sequence number into the "sc_wait_request" queue at the same time
++       * within the lock section of "sc_state_lock".
++       */
++      spin_lock(&sci->sc_state_lock);
+       wait_req.seq = ++sci->sc_seq_request;
++      add_wait_queue(&sci->sc_wait_request, &wait_req.wq);
+       spin_unlock(&sci->sc_state_lock);
+-      init_waitqueue_entry(&wait_req.wq, current);
+-      add_wait_queue(&sci->sc_wait_request, &wait_req.wq);
+-      set_current_state(TASK_INTERRUPTIBLE);
+       wake_up(&sci->sc_wait_daemon);
+       for (;;) {
++              set_current_state(TASK_INTERRUPTIBLE);
++
+               if (atomic_read(&wait_req.done)) {
+                       err = wait_req.err;
+                       break;
index 9f9b18cb08a6e86b27f9ef96699e5a572f36faa0..6bb32bcd7e3005477d905dad4ece0173398836d4 100644 (file)
@@ -1,4 +1,6 @@
 speakup-fix-sizeof-vs-array_size-bug.patch
 ring-buffer-fix-a-race-between-readers-and-resize-checks.patch
 net-smc91x-fix-m68k-kernel-compilation-for-coldfire-cpu.patch
+nilfs2-fix-unexpected-freezing-of-nilfs_segctor_sync.patch
+nilfs2-fix-potential-hang-in-nilfs_detach_log_writer.patch
 tty-n_gsm-fix-possible-out-of-bounds-in-gsm0_receive.patch