Commit Diff


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 <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>
@@ -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;