feat: (iso9660) implement file read (for both interleaved and non-interleaved mode)
[lunaix-os.git] / lunaix-os / kernel / block / blkio.c
1 #include <lunaix/blkio.h>
2 #include <lunaix/mm/cake.h>
3 #include <lunaix/mm/valloc.h>
4
5 #include <hal/cpu.h>
6
7 static struct cake_pile* blkio_reqpile;
8
9 void
10 blkio_init()
11 {
12     blkio_reqpile = cake_new_pile("blkio_req", sizeof(struct blkio_req), 1, 0);
13 }
14
15 static inline struct blkio_req*
16 __blkio_req_create(struct vecbuf* buffer,
17                    u64_t start_lba,
18                    blkio_cb completed,
19                    void* evt_args,
20                    u32_t options)
21 {
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,
26                                 .flags = options,
27                                 .evt_args = evt_args };
28     breq->vbuf = buffer;
29     waitq_init(&breq->wait);
30     return breq;
31 }
32
33 struct blkio_req*
34 blkio_vrd(struct vecbuf* buffer,
35           u64_t start_lba,
36           blkio_cb completed,
37           void* evt_args,
38           u32_t options)
39 {
40     return __blkio_req_create(buffer, start_lba, completed, evt_args, options);
41 }
42
43 struct blkio_req*
44 blkio_vwr(struct vecbuf* buffer,
45           u64_t start_lba,
46           blkio_cb completed,
47           void* evt_args,
48           u32_t options)
49 {
50     struct blkio_req* breq =
51       __blkio_req_create(buffer, start_lba, completed, evt_args, options);
52     breq->flags |= BLKIO_WRITE;
53     return breq;
54 }
55
56 void
57 blkio_free_req(struct blkio_req* req)
58 {
59     cake_release(blkio_reqpile, (void*)req);
60 }
61
62 struct blkio_context*
63 blkio_newctx(req_handler handler)
64 {
65     struct blkio_context* ctx =
66       (struct blkio_context*)vzalloc(sizeof(struct blkio_context));
67     ctx->handle_one = handler;
68
69     llist_init_head(&ctx->queue);
70
71     return ctx;
72 }
73
74 void
75 blkio_commit(struct blkio_context* ctx, struct blkio_req* req, int options)
76 {
77     req->flags |= BLKIO_PENDING;
78     req->io_ctx = ctx;
79     llist_append(&ctx->queue, &req->reqs);
80
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
85     // called?
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.
91
92     if (!ctx->busy) {
93         if ((options & BLKIO_WAIT)) {
94             cpu_disable_interrupt();
95             blkio_schedule(ctx);
96             pwait(&req->wait);
97             return;
98         }
99         blkio_schedule(ctx);
100     } else if ((options & BLKIO_WAIT)) {
101         pwait(&req->wait);
102     }
103 }
104
105 void
106 blkio_schedule(struct blkio_context* ctx)
107 {
108     if (llist_empty(&ctx->queue)) {
109         return;
110     }
111
112     struct blkio_req* head = (struct blkio_req*)ctx->queue.next;
113     llist_delete(&head->reqs);
114
115     head->flags |= BLKIO_BUSY;
116     head->io_ctx->busy++;
117
118     ctx->handle_one(head);
119 }
120
121 void
122 blkio_complete(struct blkio_req* req)
123 {
124     req->flags &= ~(BLKIO_BUSY | BLKIO_PENDING);
125
126     if (req->completed) {
127         req->completed(req);
128     }
129
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);
133
134     if ((req->flags & BLKIO_FOC)) {
135         blkio_free_req(req);
136     }
137
138     req->io_ctx->busy--;
139 }