commit - 2b4233ff2aff2093784c67e84ca4def9b306af90
commit + 0b2bb3ee51023cbb01c53c7358550324c16c5d21
blob - 613fbc2c635d4282e77ae7186f6b373241096b9b
blob + e0f3f450c0c4ff44732013e3789f1ecd59495f32
--- kernel/include/ipc/block_backend.h
+++ kernel/include/ipc/block_backend.h
#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
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
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
#include <lenix/service.h>
#include <lenix/server.h>
#include <lenix/signal.h>
+#include <lenix/time.h>
#include <lenix/namesvc_client.h>
#include <ipc/block_protocol.h>
#include <ipc/block_backend.h>
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;
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
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)
{
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);
} 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,
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=",
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;
}
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
}
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
&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() &&
}
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;