ublk-cpp v0.0
Loading...
Searching...
No Matches
nop.cpp
Go to the documentation of this file.
1
7
8#include <cerrno>
9#include <condy.hpp>
10#include <csignal>
11#include <cstdint>
12#include <exception>
13#include <fcntl.h>
14#include <getopt.h>
15#include <iostream>
16#include <print>
17#include <sys/signalfd.h>
18#include <system_error>
19#include <thread>
20#include <ublk.hpp>
21#include <unistd.h>
22
23namespace ex = condy::detail::ex;
24
25void prep_dev_info(ublksrv_ctrl_dev_info &info, uint32_t dev_id,
26 uint64_t flags) noexcept {
27 info = {};
28 info.dev_id = dev_id;
29 info.nr_hw_queues = 1;
30 info.queue_depth = 128;
31 info.max_io_buf_bytes = 512 << 10;
32 info.flags = flags;
33}
34
35void prep_params(ublk_params &params,
36 const ublksrv_ctrl_dev_info &info) noexcept {
37 params = {};
38 params.len = sizeof(params);
39 params.types = UBLK_PARAM_TYPE_BASIC;
40 params.basic.logical_bs_shift = 9;
41 params.basic.physical_bs_shift = 12;
42 params.basic.io_opt_shift = 12;
43 params.basic.io_min_shift = 9;
44 params.basic.max_sectors = info.max_io_buf_bytes >> 9;
45 params.basic.dev_sectors = (250ull * 1024 * 1024 * 1024) >> 9;
46}
47
48void print_usage(const char *prog) {
49 std::println("Usage: {} -n <dev_id>", prog);
50 std::println("Run a no-op ublk block device.");
51 std::println();
52 std::println("Options:");
53 std::println(" -n <dev_id> ublk device id to use");
54 std::println(" -h show this help and exit");
55}
56
57ex::task<void> wait_signal(int ctrl_fd, int signal_fd, uint32_t dev_id,
58 ex::inplace_stop_source &source) {
59 std::println("ublk-nop: ublk device {} is running...", dev_id);
60 auto parent_token = co_await ex::read_env(ex::get_stop_token);
61 ex::inplace_stop_callback cb{parent_token,
62 [&] noexcept { source.request_stop(); }};
63 signalfd_siginfo si;
64 co_await (condy::async_read(signal_fd, condy::buffer(&si, sizeof(si)), 0) |
65 ex::write_env(ex::prop{ex::get_stop_token, source.get_token()}));
66 std::println("ublk-nop: received signal {}, shutting down...",
67 si.ssi_signo);
68 co_await ublk::stop_dev(ctrl_fd, dev_id);
69}
70
71// NOLINTNEXTLINE(bugprone-unsafe-to-allow-exceptions)
72int main(int argc, char *argv[]) noexcept(false) {
73 uint32_t dev_id = -1;
74 int opt;
75 while ((opt = getopt(argc, argv, "n:h")) != -1) {
76 switch (opt) {
77 case 'n':
78 dev_id = std::stoul(optarg);
79 break;
80 case 'h':
81 default:
82 print_usage(argv[0]);
83 return opt == 'h' ? 0 : 1;
84 }
85 }
86
87 try {
88 sigset_t mask;
89 sigemptyset(&mask);
90 sigaddset(&mask, SIGINT);
91 sigaddset(&mask, SIGTERM);
92 sigprocmask(SIG_BLOCK, &mask, nullptr);
93
94 int signal_fd = signalfd(-1, &mask, SFD_NONBLOCK);
95 if (signal_fd < 0) {
96 throw std::system_error(errno, std::generic_category(), "signalfd");
97 }
98 auto d = ublk::detail::defer([&] noexcept { close(signal_fd); });
99
100 int ctrl_fd = open("/dev/ublk-control", O_RDWR | O_CLOEXEC);
101 if (ctrl_fd < 0) {
102 throw std::system_error(errno, std::generic_category(),
103 "open /dev/ublk-control");
104 }
105 auto d2 = ublk::detail::defer([&] noexcept { close(ctrl_fd); });
106
107 condy::RuntimeOptions options;
108 options.enable_sqe128();
109 condy::Runtime runtime(options);
110 std::jthread loop([&]() { runtime.run(); });
111 auto d3 = ublk::detail::defer([&] noexcept { runtime.allow_exit(); });
112 ex::scheduler auto sched = condy::get_scheduler(runtime);
113
114 uint64_t features;
115 ublksrv_ctrl_dev_info info;
116 ublk_params params;
117 struct {
118 auto handle_io(const ublk::IoData &data) noexcept {
119 return ex::just(data.iod->nr_sectors * 512);
120 }
121 } handler;
122 static_assert(ublk::IoHandler<decltype(handler)>);
123 ex::inplace_stop_source stop_source;
124
125 ex::sender auto s =
126 ublk::get_features(ctrl_fd, &features) |
127 ex::let_value([&]() noexcept {
128 uint64_t flags = 0;
129 if (features & UBLK_F_USER_RECOVERY) {
130 flags |= UBLK_F_USER_RECOVERY;
131 }
132 prep_dev_info(info, dev_id, flags);
133 return ublk::daemon::setup(ctrl_fd, &info);
134 }) |
135 ex::let_value([&](bool) noexcept {
136 prep_params(params, info);
137 return ublk::daemon::configure(ctrl_fd, info.dev_id, &params);
138 }) |
139 ex::let_value([&](bool) noexcept {
140 ex::sender auto daemon =
141 ublk::daemon::run(ctrl_fd, info.dev_id, handler, {}) |
142 ex::then([&]() noexcept { stop_source.request_stop(); });
143 ex::sender auto start =
144 ublk::daemon::start(ctrl_fd, info.dev_id, getpid()) |
145 ex::let_value([&]() {
146 return wait_signal(ctrl_fd, signal_fd, info.dev_id,
147 stop_source);
148 });
149 return ex::when_all(daemon, start);
150 }) |
151 ex::let_value(
152 [&]() noexcept { return ublk::del_dev(ctrl_fd, info.dev_id); });
153
154 ex::sync_wait(ex::starts_on(sched, s));
155 } catch (const std::system_error &e) {
156 std::println(std::cerr, "ublk-nop: {}", e.what());
157 return e.code().value();
158 } catch (const std::exception &e) {
159 std::println(std::cerr, "ublk-nop: {}", e.what());
160 return 1;
161 }
162
163 return 0;
164}
Concept of an async handler with handle_io(const IoData&).
Definition handler.hpp:36
auto setup(int control_fd, ublksrv_ctrl_dev_info *info) noexcept
Ensure the device described by info has been created and return its current information.
Definition daemon.hpp:27
auto start(int control_fd, uint32_t dev_id, int32_t daemon_pid) noexcept
Start the device, served by this daemon, if possible.
Definition daemon.hpp:55
auto configure(int control_fd, uint32_t dev_id, ublk_params *params) noexcept
Ensure the device has been configured and return its current configuration in params.
Definition daemon.hpp:42
auto run(int control_fd, uint32_t dev_id, Handler &handler, Options options) noexcept
Run the daemon serving a device until it stops.
Definition daemon.hpp:82
auto stop_dev(int control_fd, uint32_t dev_id) noexcept
Stop a ublk device.
Definition control.hpp:81
auto get_features(int control_fd, uint64_t *features) noexcept
Get the feature flags supported by the ublk driver.
Definition control.hpp:142
auto del_dev(int control_fd, uint32_t dev_id) noexcept
Delete a ublk device.
Definition control.hpp:58
Main include file for the ublk-cpp library.