1// SPDX-License-Identifier: GPL-3.0-or-later
2
3#include "blockdev.h"
4#include "proto/blockdev.services.h"
5#include "ramdisk.hpp"
6
7#include <iostream>
8#include <librpc/macro_magic.h>
9#include <librpc/rpc_client.h>
10#include <librpc/rpc_server++.hpp>
11#include <librpc/rpc_server.h>
12#include <memory>
13#include <mos/mos_global.h>
14#include <pb_decode.h>
15#include <pb_encode.h>
16
17class RAMDiskServer
18 : public IBlockdevDeviceService
19 , public RAMDisk
20{
21 public:
22 explicit RAMDiskServer(const std::string &servername, const size_t nbytes) : IBlockdevDeviceService(servername), RAMDisk(nbytes)
23 {
24 }
25
26 rpc_result_code_t read_block(rpc_context_t *, mosrpc_blockdev_read_block_request *req, mosrpc_blockdev_read_block_response *resp) override
27 {
28 if (req->n_boffset + req->n_blocks > nblocks())
29 {
30 resp->result.success = false;
31 resp->result.error = strdup(string: "Out of bounds");
32 return RPC_RESULT_OK;
33 }
34
35 resp->data = (pb_bytes_array_t *) malloc(PB_BYTES_ARRAY_T_ALLOCSIZE(req->n_blocks * block_size()));
36 const auto read = RAMDisk::read_block(block: req->n_boffset, nblocks: req->n_blocks, buf: resp->data->bytes);
37 resp->data->size = read * block_size();
38
39 resp->result.success = true;
40 resp->result.error = nullptr;
41
42 return RPC_RESULT_OK;
43 }
44
45 rpc_result_code_t write_block(rpc_context_t *, mosrpc_blockdev_write_block_request *req, mosrpc_blockdev_write_block_response *resp) override
46 {
47 RAMDisk::write_block(block: req->n_boffset, nblocks: req->n_blocks, buf: req->data->bytes);
48
49 resp->result.success = true;
50 resp->result.error = nullptr;
51
52 resp->n_blocks = req->n_blocks;
53
54 return RPC_RESULT_OK;
55 }
56};
57
58int main(int argc, char **argv)
59{
60 std::cout << "RAMDisk for MOS" << std::endl;
61
62 std::string blockdev_name;
63 size_t size = 0;
64
65 const auto get_size = [](const char *str) -> size_t
66 {
67 size_t size = 0;
68 if (sscanf(buffer: str, format: "%zu", &size) != 1)
69 std::cerr << "Invalid size" << std::endl, exit(status: 1);
70
71 if (strstr(pattern: str, s: "K"))
72 size *= 1 KB;
73 else if (strstr(pattern: str, s: "M"))
74 size *= 1 MB;
75 else if (strstr(pattern: str, s: "G"))
76 size *= 1 GB;
77
78 return size;
79 };
80
81 switch (argc)
82 {
83 case 1: blockdev_name = "ramdisk", size = 1 MB; break;
84 case 2:
85 {
86 size = get_size(argv[1]);
87 blockdev_name = "ramdisk";
88 break;
89 }
90 case 3:
91 {
92 size = get_size(argv[1]);
93 blockdev_name = argv[2];
94 break;
95 }
96 default:
97 {
98 std::cerr << "Usage: " << argv[0] << " <size> [name]" << std::endl;
99 std::cerr << " " << argv[0] << " 1024" << std::endl;
100 std::cerr << " " << argv[0] << " 1M my_disk" << std::endl;
101 std::cerr << " " << argv[0] << " 5G my_disk2" << std::endl;
102 return 1;
103 }
104 }
105
106 RAMDiskServer ramdisk_server("ramdisk." + blockdev_name, size);
107
108 const auto blockdev_manager = std::make_unique<BlockdevManagerStub>(BLOCKDEV_MANAGER_RPC_SERVER_NAME);
109
110 mosrpc_blockdev_register_device_request req{ .server_name = strdup(string: ramdisk_server.get_name().c_str()),
111 .device_info = {
112 .name = strdup(string: blockdev_name.c_str()),
113 .size = ramdisk_server.nblocks() * ramdisk_server.block_size(),
114 .block_size = ramdisk_server.block_size(),
115 .n_blocks = ramdisk_server.nblocks(),
116 } };
117 mosrpc_blockdev_register_device_response resp;
118 blockdev_manager->register_device(request: &req, response: &resp);
119 if (!resp.result.success)
120 {
121 if (!resp.result.error)
122 {
123 std::cerr << "Failed to register blockdev: unknown error" << std::endl;
124 return -1;
125 }
126
127 std::cerr << "Failed to register blockdev: " << resp.result.error << std::endl;
128 return -1;
129 }
130
131 // int ret = resp.id;
132 ramdisk_server.run();
133 std::cout << "RAMDisk server terminated" << std::endl;
134 return 0;
135}
136