commit 0b2bb3ee51023cbb01c53c7358550324c16c5d21 from: int16h date: Thu Dec 4 22:40:35 2025 UTC FIX: Kernel: add exponential backoff to portal_recv busy-wait loop; New IPC_BLOCK_BACKEND_STATUS_IDLE code; blockd: return IDLE instead of BUSY when no work pending; ramdiskd: handle IDLE status with aggressive backoff; virtio-blk: add IDLE status handling; reduced IDLE backoff from 100ms to 10ms. commit - 2b4233ff2aff2093784c67e84ca4def9b306af90 commit + 0b2bb3ee51023cbb01c53c7358550324c16c5d21 blob - 613fbc2c635d4282e77ae7186f6b373241096b9b blob + e0f3f450c0c4ff44732013e3789f1ecd59495f32 --- kernel/include/ipc/block_backend.h +++ kernel/include/ipc/block_backend.h @@ -16,6 +16,7 @@ #define IPC_BLOCK_BACKEND_STATUS_BUSY (-16) #define IPC_BLOCK_BACKEND_STATUS_NO_DEVICE (-19) #define IPC_BLOCK_BACKEND_STATUS_NOT_FOUND (-2) +#define IPC_BLOCK_BACKEND_STATUS_IDLE (-11) /* No work pending, back off */ #define IPC_BLOCK_BACKEND_F_WRITE (1U << 0) #define IPC_BLOCK_BACKEND_F_FLUSH (1U << 1) blob - e5ccd6b63d9f4530d7e98acabbce4140db186d59 blob + e54e7b1630be5ae6733b3f5c617b303662168be7 --- kernel/kmain.c +++ kernel/kmain.c @@ -255,23 +255,23 @@ kmain_post_mm(void) boot_log_result("ramdiskd", rc == 0); } - // rc = user_pci_server_prepare(); - // #ifdef LENIX_DEBUG - // boot_log_result("Preparing pci-daemon...", rc == 0); - // #endif - // if (rc == 0) { - // rc = user_pci_server_launch(); - // boot_log_result("pci-server", rc == 0); - // } + rc = user_pci_server_prepare(); + #ifdef LENIX_DEBUG + boot_log_result("Preparing pci-daemon...", rc == 0); + #endif + if (rc == 0) { + rc = user_pci_server_launch(); + boot_log_result("pci-server", rc == 0); + } - // rc = user_virtio_blk_server_prepare(); - // #ifdef LENIX_DEBUG - // boot_log_result("Preparing virtio-blk driver...", rc == 0); - // #endif - // if (rc == 0) { - // rc = user_virtio_blk_server_launch(); - // boot_log_result("virtio-blk driver", rc == 0); - // } + rc = user_virtio_blk_server_prepare(); + #ifdef LENIX_DEBUG + boot_log_result("Preparing virtio-blk driver...", rc == 0); + #endif + if (rc == 0) { + rc = user_virtio_blk_server_launch(); + boot_log_result("virtio-blk driver", rc == 0); + } rc = user_fs_server_prepare(); #ifdef LENIX_DEBUG blob - 85a3e35904db9c528f4bd3ff5c390100b305bde3 blob + b5178db6a14be3b563df9512d35cdc9fc32dec17 --- kernel/sys/syscall.c +++ kernel/sys/syscall.c @@ -4393,11 +4393,29 @@ sys_portal_recv_impl(uint64_t buf_addr, uint64_t len, task = sched_current_task(); sched_task_set_last_ipc_sender(task, NULL, IPC_PORTAL_INVALID_HANDLE); deadlock_recv_start(task, 5000); /* 5 second timeout */ - for (;;) { - msg = ipc_mailbox_recv(mbox); - if (msg != NULL) - break; - sched_yield(); + { + uint32_t spins = 0; + for (;;) { + msg = ipc_mailbox_recv(mbox); + if (msg != NULL) + break; + /* + * Exponential backoff to reduce CPU usage when idle: + * - First 100 iterations: just yield + * - Next 1000 iterations: yield + memory barrier + * - After that: multiple yields per iteration + */ + spins++; + sched_yield(); + if (spins > 100) { + __asm__ __volatile__("" ::: "memory"); + if (spins > 1000) { + /* Extra yields to reduce poll rate when idle */ + for (uint32_t i = 0; i < 10; i++) + sched_yield(); + } + } + } } deadlock_recv_end(task); blob - c8a44830303f6cc04bf624602c1539c00af6a9a7 blob + b52d797730313aeb3a8a9f81be2cc0b17c57f5f1 --- servers/block/blockd/main.c +++ servers/block/blockd/main.c @@ -8,6 +8,7 @@ #include #include #include +#include #include #include #include @@ -20,6 +21,7 @@ struct blockd_backend_device { uint64_t block_count; bool request_pending; bool waiting_completion; + uint64_t waiting_since_ms; /* timestamp when waiting started */ struct ipc_block_service_request pending_req; struct ipc_block_service_request queue[8]; size_t queue_head; @@ -27,6 +29,8 @@ struct blockd_backend_device { size_t queue_len; }; +#define BLOCKD_BACKEND_TIMEOUT_MS 10000 /* 10 second backend timeout */ + #define BLOCKD_BACKEND_MAX_DEVICES 8 #define BLOCKD_BACKEND_QUEUE_DEPTH 8 @@ -74,7 +78,19 @@ static bool blockd_backend_queue_pop(struct blockd_bac struct ipc_block_service_request *req_out); static void blockd_backend_promote_queued(struct blockd_backend_device *slot); static void blockd_register_with_namesvc(portal_handle_t bootstrap); +static void blockd_check_device_timeouts(void); +static uint64_t blockd_now_ms(void); +static uint64_t +blockd_now_ms(void) +{ + struct timespec ts; + if (clock_gettime(CLOCK_MONOTONIC, &ts) != 0) + return 0; + return (uint64_t)ts.tv_sec * 1000ULL + + (uint64_t)ts.tv_nsec / 1000000ULL; +} + static void blockd_log(const char *msg) { @@ -396,6 +412,7 @@ blockd_backend_handle_io_fetch(const struct ipc_block_ memcpy(resp.data, pending->data, resp.data_len); slot->request_pending = false; slot->waiting_completion = true; + slot->waiting_since_ms = blockd_now_ms(); #ifdef LENIX_DEBUG blockd_log_int("[blockd] backend fetch token=", (int)pending->token); @@ -403,8 +420,8 @@ blockd_backend_handle_io_fetch(const struct ipc_block_ } else if (slot != NULL && slot->waiting_completion) { resp.status = IPC_BLOCK_BACKEND_STATUS_BUSY; } else if (slot != NULL) { - /* Device exists but no work is queued; tell backend to repoll */ - resp.status = IPC_BLOCK_BACKEND_STATUS_BUSY; + /* Device exists but no work is queued; tell backend to back off */ + resp.status = IPC_BLOCK_BACKEND_STATUS_IDLE; } if (blockd_backend_portal != IPC_PORTAL_INVALID_HANDLE) ipc_service_respond(blockd_backend_portal, resp.token, @@ -421,8 +438,10 @@ blockd_backend_handle_io_response( if (resp_pkt == NULL) return; slot = blockd_backend_find(resp_pkt->device_id); - if (slot == NULL || !slot->waiting_completion) + if (slot == NULL) return; + if (!slot->waiting_completion) + return; blockd_log_int("[blockd] backend response token=", (int)resp_pkt->token); if (resp_pkt->status != IPC_BLOCK_BACKEND_STATUS_OK) { blockd_log_hex64("[blockd] backend response error status=", @@ -583,12 +602,21 @@ main(int argc, char **argv, char **envp) blockd_log("[blockd] service online"); static uint8_t portal_buf[BLOCKD_PORTAL_BUF_MAX]; + static uint64_t last_diag_ms = 0; while (1) { if (blockd_terminate) { blockd_log("[blockd] SIGTERM received, exiting cleanly"); return 0; } + + /* Periodic diagnostic: check for stuck devices */ + uint64_t now = blockd_now_ms(); + if (now - last_diag_ms > 5000) { + blockd_check_device_timeouts(); + last_diag_ms = now; + } + ssize_t n = portal_recv(portal_buf, sizeof(portal_buf)); if (n <= 0) continue; @@ -623,6 +651,42 @@ main(int argc, char **argv, char **envp) } static void +blockd_check_device_timeouts(void) +{ + uint64_t now = blockd_now_ms(); + + for (size_t i = 0; i < BLOCKD_BACKEND_MAX_DEVICES; i++) { + struct blockd_backend_device *slot = &blockd_backend_devices[i]; + if (!slot->in_use || !slot->waiting_completion) + continue; + + uint64_t wait_ms = now - slot->waiting_since_ms; + if (wait_ms > BLOCKD_BACKEND_TIMEOUT_MS) { + /* Backend timed out - clear stuck state and fail the request */ + printf("[blockd] TIMEOUT dev=%u waited=%llu ms, clearing stuck state\n", + slot->device_id, (unsigned long long)wait_ms); + + struct ipc_block_service_response out; + memset(&out, 0, sizeof(out)); + out.token = slot->pending_req.token; + out.status = -110; /* ETIMEDOUT */ + out.bytes_transferred = 0; + out.data_len = 0; + slot->waiting_completion = false; + block_service_respond(&out); + + /* Promote any queued requests */ + blockd_backend_promote_queued(slot); + } else if (wait_ms > 2000) { + /* Log warning if waiting more than 2s */ + printf("[blockd] WAITING dev=%u for %llu ms token=%u\n", + slot->device_id, (unsigned long long)wait_ms, + slot->pending_req.token); + } + } +} + +static void blockd_register_with_namesvc(portal_handle_t bootstrap) { const int max_attempts = 1000; blob - 31d009bd2efb5259b88c1e081a78064f45be2a27 blob + d1c4d5e4aeee461471f0ef637db351c94dc009f7 --- servers/block/ramdiskd/main.c +++ servers/block/ramdiskd/main.c @@ -513,9 +513,21 @@ main(void) } if (work.status != IPC_BLOCK_BACKEND_STATUS_OK) { - if (work.status == IPC_BLOCK_BACKEND_STATUS_BUSY) { + if (work.status == IPC_BLOCK_BACKEND_STATUS_IDLE) { /* - * Adaptive back-off for BUSY responses: + * IDLE = no work pending at all. + * Back off moderately since there's nothing to do. + * Reset BUSY timeout since this is normal idle state. + * Use 10ms (not 100ms) to stay responsive during boot. + */ + busy_counter = 0; + busy_start_ms = 0; + busy_timeout_logged = false; + poll(NULL, 0, 10); /* 10ms backoff when idle */ + } else if (work.status == IPC_BLOCK_BACKEND_STATUS_BUSY) { + /* + * BUSY = blockd is waiting for completion of prior request. + * Use adaptive back-off: * - Tier 1 (first 100): 1ms sleep * - Tier 2 (100-1000): 5ms sleep * - Tier 3 (1000+): 10ms sleep blob - 768c4f6a04501c3621e0023a3e78238a919658dd blob + e016b6bd71e754ac8b92f98ae6faa2b0081a4edc --- servers/block/virtio-blk/main.c +++ servers/block/virtio-blk/main.c @@ -806,8 +806,9 @@ virtio_backend_loop(struct virtio_blk_driver *drv, &work, sizeof(work)) != 0) continue; if (work.status == IPC_BLOCK_BACKEND_STATUS_BUSY || - work.status == IPC_BLOCK_BACKEND_STATUS_NOT_FOUND) { - /* No work yet; back off briefly */ + work.status == IPC_BLOCK_BACKEND_STATUS_NOT_FOUND || + work.status == IPC_BLOCK_BACKEND_STATUS_IDLE) { + /* No work yet; back off briefly (longer for IDLE) */ busy_spins++; if (busy_spins > 10000) { if (virtio_log_verbose_enabled() && @@ -818,7 +819,11 @@ virtio_backend_loop(struct virtio_blk_driver *drv, } busy_spins = 0; } - poll(NULL, 0, 1); + /* Use moderate backoff for IDLE (no work pending) */ + if (work.status == IPC_BLOCK_BACKEND_STATUS_IDLE) + poll(NULL, 0, 10); + else + poll(NULL, 0, 1); continue; } busy_spins = 0;