bcachefs: Make sure bch2_move_ratelimit() also waits for move_ops
authorKent Overstreet <kent.overstreet@linux.dev>
Thu, 23 Nov 2023 04:44:47 +0000 (23:44 -0500)
committerKent Overstreet <kent.overstreet@linux.dev>
Fri, 24 Nov 2023 07:10:28 +0000 (02:10 -0500)
This adds move_ctxt_wait_event_timeout(), which can sleep for a timeout
while also issueing pending moves as reads complete.

Co-developed-by: Daniel Hill <daniel@gluo.nz>
Signed-off-by: Kent Overstreet <kent.overstreet@linux.dev>
fs/bcachefs/move.c
fs/bcachefs/move.h

index 7819ed8d9df97d4f1493d369e0ff157744fa405f..71f86535281646c6c22d3372f5b72c3915d6284a 100644 (file)
@@ -500,22 +500,13 @@ int bch2_move_ratelimit(struct moving_context *ctxt)
        do {
                delay = ctxt->rate ? bch2_ratelimit_delay(ctxt->rate) : 0;
 
-
-               if (delay) {
-                       if (delay > HZ / 10)
-                               bch2_trans_unlock_long(ctxt->trans);
-                       else
-                               bch2_trans_unlock(ctxt->trans);
-                       set_current_state(TASK_INTERRUPTIBLE);
-               }
-
-               if ((current->flags & PF_KTHREAD) && kthread_should_stop()) {
-                       __set_current_state(TASK_RUNNING);
+               if ((current->flags & PF_KTHREAD) && kthread_should_stop())
                        return 1;
-               }
 
                if (delay)
-                       schedule_timeout(delay);
+                       move_ctxt_wait_event_timeout(ctxt,
+                                       freezing(current) || kthread_should_stop(),
+                                       delay);
 
                if (unlikely(freezing(current))) {
                        bch2_moving_ctxt_flush_all(ctxt);
index 07cf9d42643b4fe537b6db513285efc1f65bd366..0906aa2d1de29c328fbbe9a43ca877eb7fc02471 100644 (file)
@@ -38,6 +38,25 @@ struct moving_context {
        wait_queue_head_t       wait;
 };
 
+#define move_ctxt_wait_event_timeout(_ctxt, _cond, _timeout)                   \
+({                                                                             \
+       int _ret = 0;                                                           \
+       while (true) {                                                          \
+               bool cond_finished = false;                                     \
+               bch2_moving_ctxt_do_pending_writes(_ctxt);                      \
+                                                                               \
+               if (_cond)                                                      \
+                       break;                                                  \
+               bch2_trans_unlock_long((_ctxt)->trans);                         \
+               _ret = __wait_event_timeout((_ctxt)->wait,                      \
+                            bch2_moving_ctxt_next_pending_write(_ctxt) ||      \
+                            (cond_finished = (_cond)), _timeout);              \
+               if (_ret || ( cond_finished))                                   \
+                       break;                                                  \
+       }                                                                       \
+       _ret;                                                                   \
+})
+
 #define move_ctxt_wait_event(_ctxt, _cond)                             \
 do {                                                                   \
        bool cond_finished = false;                                     \