Skip to content
Draft
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
2 changes: 1 addition & 1 deletion docs/guide.md
Original file line number Diff line number Diff line change
Expand Up @@ -231,7 +231,7 @@ ex::sync_wait(ex::starts_on(sched, s));

### Unprivileged Mode

The control commands provided by ublk-cpp support unprivileged mode natively, and this is transparent to upper-layer users. You only need one set of code to deal with both modes. (Of course, you may still need udev configuration logic similar to what [ublksrv describes](https://github.com/ublk-org/ublksrv#unprivileged-mode), and use sleep and retry to handle the race conditions caused by permission changes. But there is only so much ublk-cpp can do.)
The control commands provided by ublk-cpp support unprivileged mode natively, and this is transparent to upper-layer users. You only need one set of code to deal with both modes. (Of course, you may still need udev configuration logic similar to what [ublksrv describes](https://github.com/ublk-org/ublksrv#unprivileged-mode).)

### Raw APIs

Expand Down
41 changes: 29 additions & 12 deletions include/ublk/detail/control.hpp
Original file line number Diff line number Diff line change
Expand Up @@ -6,9 +6,12 @@
#pragma once

#include "ublk/detail/path.hpp"
#include "ublk/detail/retry.hpp"
#include "ublk/detail/task.hpp"
#include "ublk/raw.hpp"
#include <cerrno>
#include <condy.hpp>
#include <system_error>

namespace ublk {
namespace detail {
Expand All @@ -20,19 +23,33 @@ struct control_get_dev_info_t {
ex::task<void, TaskEnv<Sched, Alloc>> invoke(int fd, uint32_t dev_id,
ublksrv_ctrl_dev_info *info) {
DevPathBuf<ublksrv_ctrl_dev_info> buf(dev_id);
auto s =
raw::get_dev_info2(fd, dev_id, &buf, sizeof(buf), DEV_PATH_LEN) |
ex::then([&](int32_t r) noexcept {
*info = buf.payload;
return r;
}) |
ex::let_error([&](std::error_code ec) {
if (ec.value() != EOPNOTSUPP) {
throw std::system_error(ec, "get_dev_info2");
bool ok = co_await retry<Sched, Alloc>(
[&]() -> ex::task<bool, TaskEnv<Sched, Alloc>> {
int32_t r =
co_await (raw::get_dev_info2(fd, dev_id, &buf, sizeof(buf),
DEV_PATH_LEN) |
ex::upon_error([](std::error_code ec) noexcept {
return -ec.value();
}));
if (r >= 0) {
*info = buf.payload;
co_return true;
}
return raw::get_dev_info(fd, dev_id, info);
});
co_await std::move(s);
if (r == -EACCES) {
co_return false;
}
if (r == -EOPNOTSUPP) {
co_await raw::get_dev_info(fd, dev_id, info);
co_return true;
}
throw std::system_error(-r, std::generic_category(),
"get_dev_info2");
},
20, 100);
if (!ok) {
throw std::system_error(EACCES, std::generic_category(),
"get_dev_info2");
}
}
};

Expand Down
37 changes: 37 additions & 0 deletions include/ublk/detail/retry.hpp
Original file line number Diff line number Diff line change
@@ -0,0 +1,37 @@
#pragma once

#include "ublk/detail/task.hpp"
#include <condy.hpp>
#include <cstddef>
#include <cstdint>
#include <system_error>

namespace ublk {
namespace detail {

namespace ex = condy::detail::ex;

template <typename Sched, typename Alloc, typename Fn>
inline ex::task<bool, TaskEnv<Sched, Alloc>> retry(Fn fn, size_t max_retry,
int64_t sleep_ms) {
if (co_await fn()) {
co_return true;
}
__kernel_timespec ts = {};
ts.tv_sec = sleep_ms / 1000;
ts.tv_nsec = (sleep_ms % 1000) * 1'000'000;
bool ok = false;
for (size_t i = 0; i < max_retry; i++) {
co_await (condy::async_timeout(&ts, 0, 0) |
ex::upon_error(
[](std::error_code ec) noexcept { return -ec.value(); }));
ok = co_await fn();
if (ok) {
break;
}
}
co_return ok;
}

} // namespace detail
} // namespace ublk
7 changes: 0 additions & 7 deletions tests/test_control.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -33,9 +33,6 @@ TEST_CASE("test control") {
unprivileged ? UBLK_F_UNPRIVILEGED_DEV : 0);
ex::sync_wait(ex::starts_on(sched, ublk::add_dev(control_fd, &info)));
REQUIRE(info.dev_id == dev_id);
if (unprivileged) {
std::this_thread::sleep_for(std::chrono::milliseconds(100));
}
ex::sync_wait(
ex::starts_on(sched, ublk::del_dev(control_fd, info.dev_id)));
}
Expand All @@ -62,10 +59,6 @@ TEST_CASE("test control") {
[](const std::exception_ptr &) noexcept {})));
});

if (unprivileged) {
std::this_thread::sleep_for(std::chrono::milliseconds(100));
}

SUBCASE("del_dev_async") {
// TODO: Kernel bug
// https://lore.kernel.org/linux-block/20260901142438.237586-1-yi1tang.yang@gmail.com/
Expand Down
3 changes: 0 additions & 3 deletions tests/test_daemon.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -47,9 +47,6 @@ TEST_CASE("test daemon") {
auto d2 = ublk::detail::defer([&]() noexcept {
ex::sync_wait(ex::starts_on(sched, ublk::del_dev(control_fd, dev_id)));
});
if (unprivileged) {
std::this_thread::sleep_for(std::chrono::milliseconds(100));
}

std::tie(applyed) =
// NOLINTNEXTLINE(bugprone-unchecked-optional-access)
Expand Down
7 changes: 0 additions & 7 deletions tests/test_io.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -80,10 +80,6 @@ TEST_CASE("test io") {
ex::sync_wait(
ex::starts_on(sched, ublk::del_dev(control_fd, dev_id)));
});
if (unprivileged) {
// Wait for udev to chown /dev/ublkcN.
std::this_thread::sleep_for(std::chrono::milliseconds(100));
}

ublk_params params = {};
fill_params(params);
Expand Down Expand Up @@ -236,9 +232,6 @@ TEST_CASE("test io") {
ex::upon_error(
[](const std::exception_ptr &) noexcept {})));
});
if (unprivileged) {
std::this_thread::sleep_for(std::chrono::milliseconds(100));
}

ublk_params params = {};
fill_params(params);
Expand Down
3 changes: 0 additions & 3 deletions tests/test_query.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -74,9 +74,6 @@ TEST_CASE("test query - cached_get_dev_info cache miss") {
auto d2 = ublk::detail::defer([&]() noexcept {
ex::sync_wait(ex::starts_on(sched, ublk::del_dev(control_fd, dev_id)));
});
if (unprivileged) {
std::this_thread::sleep_for(std::chrono::milliseconds(100));
}

// No cached info in the env -> miss -> fetch via syscall.
ublksrv_ctrl_dev_info out{};
Expand Down
Loading