Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Add RPC support and overhaul configuration system #41

Merged
merged 12 commits into from
Aug 13, 2024
1 change: 1 addition & 0 deletions .gitignore
Original file line number Diff line number Diff line change
Expand Up @@ -13,3 +13,4 @@ qemu/bzImage

subprojects/liburing-*
subprojects/packagecache
subprojects/nlohmann_json-*
14 changes: 14 additions & 0 deletions docs/configuration.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,14 @@
# Configuring LSVD

LSVD is configured using a JSON file. When creating an image, we will
try to read the following paths and parse them for configuration options:

- Default built-in configuration
- `/usr/local/etc/lsvd.json`
- `./lsvd.json`
- user supplied path

The file read last has highest priority.

We will also first try to parse the user-supplied path as a JSON object, and if
that fails try treat it as a path and read it from a file.
18 changes: 18 additions & 0 deletions docs/example_config.json
Original file line number Diff line number Diff line change
@@ -0,0 +1,18 @@
{
"rcache_dir": "/tmp/lsvd",
"rcache_size": 524288000,
"rcache_fetch_window": 12,
"wlog_dir": "/tmp/lsvd",
"wlog_bytes": 524288000,
"wlog_write_window": 8,
"wlog_chunk_bytes": 2097152,
"antithrash_ratio": 67,
"backend_obj_bytes": 8388608,
"backend_write_window": 8,
"checkpoint_interval_objs": 500,
"flush_timeout_ms": 2000,
"flush_interval_ms": 1000,
"gc_threshold_pc": 60,
"gc_write_window": 4,
"no_gc": false
}
6 changes: 6 additions & 0 deletions meson.build
Original file line number Diff line number Diff line change
Expand Up @@ -30,6 +30,12 @@ executable(
dependencies: lsvd_deps + [dependency('_spdk')],
)

executable(
'lsvd_tgt',
lsvd_tgt,
dependencies: lsvd_deps + [dependency('_spdk')],
)

executable(
'imgtool',
['src/imgtool.cc'],
Expand Down
33 changes: 26 additions & 7 deletions src/bdev_lsvd.cc
Original file line number Diff line number Diff line change
Expand Up @@ -2,7 +2,9 @@
#include "spdk/bdev_module.h"
#include <future>

#include "backend.h"
#include "bdev_lsvd.h"
#include "config.h"
#include "image.h"
#include "request.h"
#include "smartiov.h"
Expand Down Expand Up @@ -217,15 +219,32 @@ int bdev_lsvd_create(str img_name, rados_ioctx_t ioctx, lsvd_config cfg)
return 0;
}

int bdev_lsvd_delete(std::string img_name)
int bdev_lsvd_create(str pool_name, str image_name, str user_cfg)
{
auto p = std::promise<int>();
spdk_bdev_unregister_by_name(
auto be = connect_to_pool(pool_name);
auto cfg = lsvd_config::from_user_cfg(user_cfg);
PR_RET_IF(!cfg.has_value(), -1, "Failed to read config file");

return bdev_lsvd_create(image_name, be, cfg.value());
}

void bdev_lsvd_delete(str img_name, std::function<void(int)> cb)
{
log_info("Deleting image '{}'", img_name);
auto rc = spdk_bdev_unregister_by_name(
img_name.c_str(), &lsvd_if,
// some of the ugliest lifetime management code you'll ever see, but
// it should work
[](void *arg, int rc) {
auto p = (std::promise<int> *)arg;
p->set_value(rc);
log_info("Image deletion done, rc = {}", rc);
auto cb = (std::function<void(int)> *)arg;
(*cb)(rc);
delete cb;
},
&p);
return p.get_future().get();
new std::function<void(int)>(cb));

if (rc != 0) {
log_error("Failed to delete image '{}': {}", img_name, rc);
cb(rc);
}
}
4 changes: 3 additions & 1 deletion src/bdev_lsvd.h
Original file line number Diff line number Diff line change
@@ -1,8 +1,10 @@
#pragma once

#include <rados/librados.h>
#include <functional>

#include "config.h"

int bdev_lsvd_create(str img_name, rados_ioctx_t io_ctx, lsvd_config cfg);
int bdev_lsvd_delete(str img_name);
int bdev_lsvd_create(str pool_name, str image_name, str cfg_path);
void bdev_lsvd_delete(str img_name, std::function<void(int)> cb);
104 changes: 104 additions & 0 deletions src/bdev_lsvd_rpc.cc
Original file line number Diff line number Diff line change
@@ -0,0 +1,104 @@
#include "spdk/bdev.h"
#include "spdk/json.h"
#include "spdk/jsonrpc.h"
#include "spdk/likely.h"
#include "spdk/log.h"
#include "spdk/nvme.h"
#include "spdk/rpc.h"
#include "spdk/util.h"

#include "bdev_lsvd.h"
#include "utils.h"

/**
* We only expose 2 RPC endpoints: create and delete. Unlike RBD, we will not
* have commands to manage ceph clusters; each image will create its own.
*/

struct rpc_create_lsvd {
char *image_name;
char *pool_name;
char *config;
};

static const struct spdk_json_object_decoder rpc_create_lsvd_decoders[] = {
{"image_name", offsetof(rpc_create_lsvd, image_name),
spdk_json_decode_string, false},
{"pool_name", offsetof(rpc_create_lsvd, pool_name), spdk_json_decode_string,
false},
{"config", offsetof(rpc_create_lsvd, config), spdk_json_decode_string,
true},
};

static void rpc_bdev_lsvd_create(spdk_jsonrpc_request *req_json,
const spdk_json_val *params)
{
std::unique_ptr<rpc_create_lsvd, decltype([](auto p) {
free(p->image_name);
free(p->pool_name);
free(p->config);
})>
req(new rpc_create_lsvd());

auto rc = spdk_json_decode_object(params, rpc_create_lsvd_decoders,
SPDK_COUNTOF(rpc_create_lsvd_decoders),
req.get());
if (rc != 0) {
spdk_jsonrpc_send_error_response(req_json, rc,
"Failed to parse rpc json");
return;
}

rc = bdev_lsvd_create(req->pool_name, req->image_name, req->config);
if (rc != 0) {
spdk_jsonrpc_send_error_response(req_json, rc,
"Failed to create lsvd bdev");
return;
}

auto w = spdk_jsonrpc_begin_result(req_json);
spdk_json_write_bool(w, true);
spdk_jsonrpc_end_result(req_json, w);
}

SPDK_RPC_REGISTER("bdev_lsvd_create", rpc_bdev_lsvd_create, SPDK_RPC_RUNTIME)

struct rpc_delete_lsvd {
char *image_name;
};

static const struct spdk_json_object_decoder rpc_delete_lsvd_decoders[] = {
{"image_name", offsetof(rpc_delete_lsvd, image_name),
spdk_json_decode_string, false},
};

static void rpc_bdev_lsvd_delete(struct spdk_jsonrpc_request *req_json,
const struct spdk_json_val *params)
{
std::unique_ptr<rpc_delete_lsvd,
decltype([](auto p) { free(p->image_name); })>
req(new rpc_delete_lsvd());

int rc = spdk_json_decode_object(params, rpc_delete_lsvd_decoders,
SPDK_COUNTOF(rpc_delete_lsvd_decoders),
req.get());
if (rc != 0) {
spdk_jsonrpc_send_error_response(req_json, rc,
"Failed to parse rpc json");
return;
}

bdev_lsvd_delete(req->image_name, [=](int rc) {
if (rc == 0) {
auto w = spdk_jsonrpc_begin_result(req_json);
spdk_json_write_bool(w, true);
spdk_jsonrpc_end_result(req_json, w);
} else {
log_error("Failed to destroy lsvd bdev, rc = {}", rc);
spdk_jsonrpc_send_error_response(req_json, rc,
"Failed to destroy lsvd bdev");
}
});
}

SPDK_RPC_REGISTER("bdev_lsvd_delete", rpc_bdev_lsvd_delete, SPDK_RPC_RUNTIME)
Loading
Loading