17#include <sys/signalfd.h>
18#include <system_error>
23namespace ex = condy::detail::ex;
25void prep_dev_info(ublksrv_ctrl_dev_info &info, uint32_t dev_id,
26 uint64_t flags)
noexcept {
29 info.nr_hw_queues = 1;
30 info.queue_depth = 128;
31 info.max_io_buf_bytes = 512 << 10;
35void prep_params(ublk_params ¶ms,
36 const ublksrv_ctrl_dev_info &info)
noexcept {
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;
48void print_usage(
const char *prog) {
49 std::println(
"Usage: {} -n <dev_id>", prog);
50 std::println(
"Run a no-op ublk block device.");
52 std::println(
"Options:");
53 std::println(
" -n <dev_id> ublk device id to use");
54 std::println(
" -h show this help and exit");
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(); }};
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...",
72int main(
int argc,
char *argv[])
noexcept(
false) {
75 while ((opt = getopt(argc, argv,
"n:h")) != -1) {
78 dev_id = std::stoul(optarg);
83 return opt ==
'h' ? 0 : 1;
90 sigaddset(&mask, SIGINT);
91 sigaddset(&mask, SIGTERM);
92 sigprocmask(SIG_BLOCK, &mask,
nullptr);
94 int signal_fd = signalfd(-1, &mask, SFD_NONBLOCK);
96 throw std::system_error(errno, std::generic_category(),
"signalfd");
98 auto d = ublk::detail::defer([&]
noexcept { close(signal_fd); });
100 int ctrl_fd = open(
"/dev/ublk-control", O_RDWR | O_CLOEXEC);
102 throw std::system_error(errno, std::generic_category(),
103 "open /dev/ublk-control");
105 auto d2 = ublk::detail::defer([&]
noexcept { close(ctrl_fd); });
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);
115 ublksrv_ctrl_dev_info info;
118 auto handle_io(
const ublk::IoData &data)
noexcept {
119 return ex::just(data.iod->nr_sectors * 512);
123 ex::inplace_stop_source stop_source;
127 ex::let_value([&]()
noexcept {
129 if (features & UBLK_F_USER_RECOVERY) {
130 flags |= UBLK_F_USER_RECOVERY;
132 prep_dev_info(info, dev_id, flags);
135 ex::let_value([&](
bool)
noexcept {
136 prep_params(params, info);
139 ex::let_value([&](
bool)
noexcept {
140 ex::sender
auto daemon =
142 ex::then([&]()
noexcept { stop_source.request_stop(); });
143 ex::sender
auto start =
145 ex::let_value([&]() {
146 return wait_signal(ctrl_fd, signal_fd, info.dev_id,
149 return ex::when_all(daemon, start);
152 [&]()
noexcept {
return ublk::del_dev(ctrl_fd, info.dev_id); });
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());
Concept of an async handler with handle_io(const IoData&).
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.
auto start(int control_fd, uint32_t dev_id, int32_t daemon_pid) noexcept
Start the device, served by this daemon, if possible.
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.
auto run(int control_fd, uint32_t dev_id, Handler &handler, Options options) noexcept
Run the daemon serving a device until it stops.
auto stop_dev(int control_fd, uint32_t dev_id) noexcept
Stop a ublk device.
auto get_features(int control_fd, uint64_t *features) noexcept
Get the feature flags supported by the ublk driver.
auto del_dev(int control_fd, uint32_t dev_id) noexcept
Delete a ublk device.
Main include file for the ublk-cpp library.