fix: (blkio) enforce disk io buffer size alignment (to block size)
[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 static struct cake_pile* blkio_reqpile;
6
7 void
8 blkio_init()
9 {
10     blkio_reqpile = cake_new_pile("blkio_req", sizeof(struct blkio_req), 1, 0);
11 }
12
13 static inline struct blkio_req*
14 __blkio_req_create(struct vecbuf* buffer,
15                    u64_t start_lba,
16                    blkio_cb completed,
17                    void* evt_args,
18                    u32_t options)
19 {
20     options = options & ~0xf;
21     struct blkio_req* breq = (struct blkio_req*)cake_grab(blkio_reqpile);
22     *breq = (struct blkio_req){ .blk_addr = start_lba,
23                                 .completed = completed,
24                                 .flags = options,
25                                 .evt_args = evt_args };
26     breq->vbuf = buffer;
27     waitq_init(&breq->wait);
28     return breq;
29 }
30
31 struct blkio_req*
32 blkio_vrd(struct vecbuf* buffer,
33           u64_t start_lba,
34           blkio_cb completed,
35           void* evt_args,
36           u32_t options)
37 {
38     return __blkio_req_create(buffer, start_lba, completed, evt_args, options);
39 }
40
41 struct blkio_req*
42 blkio_vwr(struct vecbuf* buffer,
43           u64_t start_lba,
44           blkio_cb completed,
45           void* evt_args,
46           u32_t options)
47 {
48     struct blkio_req* breq =
49       __blkio_req_create(buffer, start_lba, completed, evt_args, options);
50     breq->flags |= BLKIO_WRITE;
51     return breq;
52 }
53
54 void
55 blkio_free_req(struct blkio_req* req)
56 {
57     cake_release(blkio_reqpile, (void*)req);
58 }
59
60 struct blkio_context*
61 blkio_newctx(req_handler handler)
62 {
63     struct blkio_context* ctx =
64       (struct blkio_context*)vzalloc(sizeof(struct blkio_context));
65     ctx->handle_one = handler;
66
67     llist_init_head(&ctx->queue);
68
69     return ctx;
70 }
71
72 void
73 blkio_commit(struct blkio_context* ctx, struct blkio_req* req)
74 {
75     req->flags |= BLKIO_PENDING;
76     req->io_ctx = ctx;
77     llist_append(&ctx->queue, &req->reqs);
78
79     // if the pipeline is not running (e.g., stalling). Then we should schedule
80     // one immediately and kick it started.
81     if (!ctx->busy) {
82         blkio_schedule(ctx);
83     }
84 }
85
86 void
87 blkio_schedule(struct blkio_context* ctx)
88 {
89     if (llist_empty(&ctx->queue)) {
90         return;
91     }
92
93     struct blkio_req* head = (struct blkio_req*)ctx->queue.next;
94     llist_delete(&head->reqs);
95
96     head->flags |= BLKIO_BUSY;
97     head->io_ctx->busy++;
98
99     ctx->handle_one(head);
100 }
101
102 void
103 blkio_complete(struct blkio_req* req)
104 {
105     req->flags &= ~(BLKIO_BUSY | BLKIO_PENDING);
106
107     if (req->completed) {
108         req->completed(req);
109     }
110
111     // FIXME Not working in first process! Need a dummy process.
112     // Wake all blocked processes on completion,
113     //  albeit should be no more than one process in everycase (by design)
114     pwake_all(&req->wait);
115
116     if ((req->flags & BLKIO_FOC)) {
117         blkio_free_req(req);
118     }
119
120     req->io_ctx->busy--;
121 }