netfs: Fix looping in wait functions
authorDavid Howells <dhowells@redhat.com>
Tue, 1 Jul 2025 16:38:39 +0000 (17:38 +0100)
committerChristian Brauner <brauner@kernel.org>
Tue, 1 Jul 2025 20:37:13 +0000 (22:37 +0200)
netfs_wait_for_request() and netfs_wait_for_pause() can loop forever if
netfs_collect_in_app() returns 2, indicating that it wants to repeat
because the ALL_QUEUED flag isn't yet set and there are no subreqs left
that haven't been collected.

The problem is that, unless collection is offloaded (OFFLOAD_COLLECTION),
we have to return to the application thread to continue and eventually set
ALL_QUEUED after pausing to deal with a retry - but we never get there.

Fix this by inserting checks for the IN_PROGRESS and PAUSE flags as
appropriate before cycling round - and add cond_resched() for good measure.

Fixes: 2b1424cd131c ("netfs: Fix wait/wake to be consistent about the waitqueue used")
Signed-off-by: David Howells <dhowells@redhat.com>
Link: https://lore.kernel.org/20250701163852.2171681-5-dhowells@redhat.com
Tested-by: Steve French <sfrench@samba.org>
Reviewed-by: Paulo Alcantara <pc@manguebit.org>
cc: netfs@lists.linux.dev
cc: linux-fsdevel@vger.kernel.org
Signed-off-by: Christian Brauner <brauner@kernel.org>
fs/netfs/misc.c

index 7f31c3cbfe015f6eb1875fc66bda3e2db658947e..127a269938bb9a7e5aff445322f30d49b87400b4 100644 (file)
@@ -430,8 +430,8 @@ static int netfs_collect_in_app(struct netfs_io_request *rreq,
 /*
  * Wait for a request to complete, successfully or otherwise.
  */
-static ssize_t netfs_wait_for_request(struct netfs_io_request *rreq,
-                                     bool (*collector)(struct netfs_io_request *rreq))
+static ssize_t netfs_wait_for_in_progress(struct netfs_io_request *rreq,
+                                         bool (*collector)(struct netfs_io_request *rreq))
 {
        DEFINE_WAIT(myself);
        ssize_t ret;
@@ -447,6 +447,9 @@ static ssize_t netfs_wait_for_request(struct netfs_io_request *rreq,
                        case 1:
                                goto all_collected;
                        case 2:
+                               if (!netfs_check_rreq_in_progress(rreq))
+                                       break;
+                               cond_resched();
                                continue;
                        }
                }
@@ -485,12 +488,12 @@ all_collected:
 
 ssize_t netfs_wait_for_read(struct netfs_io_request *rreq)
 {
-       return netfs_wait_for_request(rreq, netfs_read_collection);
+       return netfs_wait_for_in_progress(rreq, netfs_read_collection);
 }
 
 ssize_t netfs_wait_for_write(struct netfs_io_request *rreq)
 {
-       return netfs_wait_for_request(rreq, netfs_write_collection);
+       return netfs_wait_for_in_progress(rreq, netfs_write_collection);
 }
 
 /*
@@ -514,6 +517,10 @@ static void netfs_wait_for_pause(struct netfs_io_request *rreq,
                        case 1:
                                goto all_collected;
                        case 2:
+                               if (!netfs_check_rreq_in_progress(rreq) ||
+                                   !test_bit(NETFS_RREQ_PAUSE, &rreq->flags))
+                                       break;
+                               cond_resched();
                                continue;
                        }
                }