ublk-cpp v0.1
A ublk library for std::execution.
Loading...
Searching...
No Matches
daemon.hpp
Go to the documentation of this file.
1
6
7#pragma once
8
11#include "ublk/detail/io.hpp"
13#include "ublk/detail/shm.hpp"
14#include "ublk/detail/utils.hpp"
15#include "ublk/handler.hpp"
16#include "ublk/runtime.hpp"
17#include "ublk/ublk_cmd.h"
18#include <condy.hpp>
19#include <stdexcept>
20
21namespace ublk {
22namespace detail {
23
24inline bool need_recovery(const ublksrv_ctrl_dev_info *info) noexcept {
25 return info->state == UBLK_S_DEV_QUIESCED ||
26 info->state == UBLK_S_DEV_FAIL_IO;
27}
28
29struct daemon_setup_t {
30 template <typename Sched, typename Alloc>
31 ex::task<bool, TaskEnv<Sched, Alloc>> invoke(int control_fd,
32 ublksrv_ctrl_dev_info *info) {
33 if (info->dev_id == -1) {
34 co_await raw::add_dev(control_fd, info);
35 co_return true;
36 }
37
38 auto s = raw::add_dev(control_fd, info) |
39 ex::upon_error([&](std::error_code ec) {
40 if (ec.value() != EEXIST) {
41 throw std::system_error(ec, "add_dev");
42 }
43 return -ec.value();
44 });
45 auto r = co_await std::move(s);
46 if (r != -EEXIST) {
47 co_return true;
48 }
49
50 co_await control_get_dev_info_t{}.invoke<Sched, Alloc>(
51 control_fd, info->dev_id, info);
52
53 if (info->flags & UBLK_F_USER_RECOVERY && need_recovery(info)) {
54 co_await (control_start_user_recovery_t{}.invoke<Sched, Alloc>(
55 control_fd, info->dev_id) |
56 ex::write_env(ex::prop{fetch_dev_info, info}));
57 }
58
59 co_return false;
60 }
61};
62
63struct daemon_configure_t {
64 template <typename Sched, typename Alloc>
65 ex::task<bool, TaskEnv<Sched, Alloc>>
66 invoke(int control_fd, uint32_t dev_id, ublk_params *params) {
67 ublksrv_ctrl_dev_info info;
68 co_await cached_get_dev_info<Sched, Alloc>(control_fd, dev_id, &info);
69
70 if (info.state == UBLK_S_DEV_DEAD) {
71 co_await (control_set_params_t{}.invoke<Sched, Alloc>(
72 control_fd, dev_id, params) |
73 ex::write_env(ex::prop{fetch_dev_info, &info}));
74 co_return true;
75 } else {
76 co_await (control_get_params_t{}.invoke<Sched, Alloc>(
77 control_fd, dev_id, params) |
78 ex::write_env(ex::prop{fetch_dev_info, &info}));
79 co_return false;
80 }
81 }
82};
83
84struct daemon_start_t {
85 template <typename Sched, typename Alloc>
86 ex::task<void, TaskEnv<Sched, Alloc>>
87 invoke(int control_fd, uint32_t dev_id, int32_t daemon_pid) {
88 ublksrv_ctrl_dev_info info;
89 co_await cached_get_dev_info<Sched, Alloc>(control_fd, dev_id, &info);
90
91 if (!need_recovery(&info)) {
92 co_await (control_start_dev_t{}.invoke<Sched, Alloc>(
93 control_fd, dev_id, daemon_pid) |
94 ex::write_env(ex::prop{fetch_dev_info, &info}));
95 } else if (info.flags & UBLK_F_USER_RECOVERY) {
96 co_await (control_end_user_recovery_t{}.invoke<Sched, Alloc>(
97 control_fd, dev_id, daemon_pid) |
98 ex::write_env(ex::prop{fetch_dev_info, &info}));
99 } else {
100 throw std::runtime_error(
101 "device can neither be started nor recovered");
102 }
103 }
104};
105
106struct daemon_run_t {
107 template <typename Sched, typename Alloc, IoHandler Handler>
108 ex::task<void, TaskEnv<Sched, Alloc>>
109 invoke(int control_fd, uint32_t dev_id, Handler *handler,
110 const RuntimeOptions *runtime_options, size_t nr_files,
111 size_t nr_buffers) {
112 auto alloc = co_await ex::read_env(ex::get_allocator);
113
114 ublksrv_ctrl_dev_info info;
115 co_await cached_get_dev_info<Sched, Alloc>(control_fd, dev_id, &info);
116
117 nr_files = std::max<size_t>(nr_files, 1);
118 if (info.flags & (UBLK_F_SUPPORT_ZERO_COPY | UBLK_F_AUTO_BUF_REG)) {
119 nr_buffers = std::max<size_t>(nr_buffers, info.queue_depth);
120 }
121 auto options = runtime_options
122 ? runtime_options->build(info.queue_depth)
123 : RuntimeOptions().build(info.queue_depth);
124
125 AllocVector<std::unique_ptr<IoLoop>, decltype(alloc)> loops(alloc);
126 loops.reserve(info.nr_hw_queues);
127 for (uint16_t q_id = 0; q_id < info.nr_hw_queues; q_id++) {
128 cpu_set_t cpuset;
129 co_await (control_get_queue_affinity_t{}.invoke<Sched, Alloc>(
130 control_fd, dev_id, q_id, &cpuset) |
131 ex::write_env(ex::prop{fetch_dev_info, &info}));
132 auto loop =
133 std::make_unique<IoLoop>(options, nr_files, nr_buffers, cpuset);
134 loops.push_back(std::move(loop));
135 options.enable_attach_wq(loops[0]->runtime());
136 }
137
138 std::string path = dev_path(dev_id);
139 int ublkc_fd = co_await condy::async_open(path.c_str(), O_RDWR, 0);
140 auto d = defer([&]() noexcept { close(ublkc_fd); });
141
142 ex::simple_counting_scope scope;
143 AllocVector<std::exception_ptr, decltype(alloc)> errs(info.nr_hw_queues,
144 alloc);
145 for (uint16_t q_id = 0; q_id < info.nr_hw_queues; q_id++) {
146 auto sched = loops[q_id]->get_scheduler();
147 auto env = ex::env{ex::prop{ex::get_allocator, alloc},
148 ex::prop{fetch_dev_info, &info}};
149 auto task = io_run_dev_t{}.invoke<decltype(sched), Alloc>(
150 ublkc_fd, q_id, &info, handler) |
151 ex::write_env(std::move(env));
152 auto s = ex::starts_on(sched, std::move(task)) |
153 ex::upon_error(
154 [&, q_id](const std::exception_ptr &ep) noexcept {
155 errs[q_id] = ep;
156 });
157 ex::spawn(std::move(s), scope.get_token());
158 }
159 co_await scope.join();
160
161 for (auto &ep : errs) {
162 if (ep) {
163 std::rethrow_exception(ep);
164 }
165 }
166 }
167};
168
169struct daemon_shm_server_t {
170 template <typename Sched, typename Alloc, ShmHandler Handler>
171 auto invoke(int control_fd, uint32_t dev_id, std::string_view path,
172 Handler *handler, uint32_t flags) {
173 return shm_server_run<Sched, Alloc>(
174 path, Session<Sched, Alloc, Handler>(control_fd, dev_id, flags,
175 *handler));
176 }
177};
178
179} // namespace detail
180} // namespace ublk
Implementation of ublk control command interface.
Implementation of the ublk I/O loop for processing I/O requests on a dedicated scheduler.
The std::execution backend namespace used by ublk-cpp.
Handler concepts for ublk server.
Helpful condy runtime wrapper for running a dedicated I/O loop on a pinned thread.
auto add_dev(Fd fd, ublksrv_ctrl_dev_info *info) noexcept
Add a new ublk device.
Definition raw.hpp:80
The main namespace of the ublk-cpp library.
Definition ublk.hpp:21
constexpr fetch_dev_info_t fetch_dev_info
Query object instance of fetch_dev_info_t.
Definition query.hpp:45
Runtime options based on condy::RuntimeOptions.
Implementation of the shared-memory buffer registration service over a Unix domain socket.
Small utility helpers.