1 #include <lunaix/blkio.h>
2 #include <lunaix/mm/cake.h>
3 #include <lunaix/mm/valloc.h>
7 static struct cake_pile* blkio_reqpile;
12 blkio_reqpile = cake_new_pile("blkio_req", sizeof(struct blkio_req), 1, 0);
15 static inline struct blkio_req*
16 __blkio_req_create(struct vecbuf* buffer,
22 options = options & ~0xf;
23 struct blkio_req* breq = (struct blkio_req*)cake_grab(blkio_reqpile);
24 *breq = (struct blkio_req){ .blk_addr = start_lba,
25 .completed = completed,
27 .evt_args = evt_args };
29 waitq_init(&breq->wait);
34 blkio_vrd(struct vecbuf* buffer,
40 return __blkio_req_create(buffer, start_lba, completed, evt_args, options);
44 blkio_vwr(struct vecbuf* buffer,
50 struct blkio_req* breq =
51 __blkio_req_create(buffer, start_lba, completed, evt_args, options);
52 breq->flags |= BLKIO_WRITE;
57 blkio_free_req(struct blkio_req* req)
59 cake_release(blkio_reqpile, (void*)req);
63 blkio_newctx(req_handler handler)
65 struct blkio_context* ctx =
66 (struct blkio_context*)vzalloc(sizeof(struct blkio_context));
67 ctx->handle_one = handler;
69 llist_init_head(&ctx->queue);
75 blkio_commit(struct blkio_context* ctx, struct blkio_req* req, int options)
77 req->flags |= BLKIO_PENDING;
79 llist_append(&ctx->queue, &req->reqs);
81 // if the pipeline is not running (e.g., stalling). Then we should schedule
82 // one immediately and kick it started.
83 // NOTE: Possible race condition between blkio_commit and pwait.
84 // Consider: what if scheduler complete the request before pwait even get
86 // Two possible work around:
87 // #1. we disable the interrupt before schedule the request.
88 // #2. we do scheduling within interrupt context (e.g., attach a timer)
89 // As we don't want to overwhelming the interrupt context and also keep the
90 // request RTT as small as possible, hence #1 is preferred.
93 if ((options & BLKIO_WAIT)) {
94 cpu_disable_interrupt();
100 } else if ((options & BLKIO_WAIT)) {
106 blkio_schedule(struct blkio_context* ctx)
108 if (llist_empty(&ctx->queue)) {
112 struct blkio_req* head = (struct blkio_req*)ctx->queue.next;
113 llist_delete(&head->reqs);
115 head->flags |= BLKIO_BUSY;
116 head->io_ctx->busy++;
118 ctx->handle_one(head);
122 blkio_complete(struct blkio_req* req)
124 req->flags &= ~(BLKIO_BUSY | BLKIO_PENDING);
126 if (req->completed) {
130 // Wake all blocked processes on completion,
131 // albeit should be no more than one process in everycase (by design)
132 pwake_all(&req->wait);
134 if ((req->flags & BLKIO_FOC)) {