2-setup_gdt.md (#22)
[lunaix-os.git] / lunaix-os / kernel / block / blkio.c
index 44531c4091636ef09309db1e6dc59135b553d767..9fcd670e350286b28a1a251eaf8503f7498650c6 100644 (file)
@@ -2,6 +2,8 @@
 #include <lunaix/mm/cake.h>
 #include <lunaix/mm/valloc.h>
 
+#include <sys/cpu.h>
+
 static struct cake_pile* blkio_reqpile;
 
 void
@@ -24,6 +26,7 @@ __blkio_req_create(struct vecbuf* buffer,
                                 .flags = options,
                                 .evt_args = evt_args };
     breq->vbuf = buffer;
+    waitq_init(&breq->wait);
     return breq;
 }
 
@@ -69,16 +72,33 @@ blkio_newctx(req_handler handler)
 }
 
 void
-blkio_commit(struct blkio_context* ctx, struct blkio_req* req)
+blkio_commit(struct blkio_context* ctx, struct blkio_req* req, int options)
 {
     req->flags |= BLKIO_PENDING;
     req->io_ctx = ctx;
     llist_append(&ctx->queue, &req->reqs);
 
     // if the pipeline is not running (e.g., stalling). Then we should schedule
-    // one immediately and kick it start.
+    // one immediately and kick it started.
+    // NOTE: Possible race condition between blkio_commit and pwait.
+    // Consider: what if scheduler complete the request before pwait even get
+    // called?
+    // Two possible work around:
+    //  #1. we disable the interrupt before schedule the request.
+    //  #2. we do scheduling within interrupt context (e.g., attach a timer)
+    // As we don't want to overwhelming the interrupt context and also keep the
+    // request RTT as small as possible, hence #1 is preferred.
+
     if (!ctx->busy) {
+        if ((options & BLKIO_WAIT)) {
+            cpu_disable_interrupt();
+            blkio_schedule(ctx);
+            pwait(&req->wait);
+            return;
+        }
         blkio_schedule(ctx);
+    } else if ((options & BLKIO_WAIT)) {
+        pwait(&req->wait);
     }
 }
 
@@ -102,14 +122,18 @@ void
 blkio_complete(struct blkio_req* req)
 {
     req->flags &= ~(BLKIO_BUSY | BLKIO_PENDING);
+
     if (req->completed) {
         req->completed(req);
     }
+
+    // Wake all blocked processes on completion,
+    //  albeit should be no more than one process in everycase (by design)
+    pwake_all(&req->wait);
+
     if ((req->flags & BLKIO_FOC)) {
         blkio_free_req(req);
     }
 
     req->io_ctx->busy--;
-
-    blkio_schedule(req->io_ctx);
 }
\ No newline at end of file