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