Update SPDK

Signed-off-by: Keith Lucas <keith.lucas@suse.com>
This commit is contained in:
Keith Lucas 2022-06-30 13:27:26 -04:00
parent 0606fa0f67
commit 7843af57fc
7 changed files with 140 additions and 118 deletions

View File

@ -167,6 +167,8 @@ static void longhorn_check_pause_complete(struct longhorn_bdev *longhorn_bdev)
}
TAILQ_INIT(&longhorn_bdev->pause_cbs);
}
void bdev_longhorn_pause_io(void *cb_arg) {
@ -279,11 +281,6 @@ longhorn_bdev_cleanup(struct longhorn_bdev *longhorn_bdev)
free(longhorn_bdev->bdev.name);
free(longhorn_bdev->base_bdev_info);
#if 0
if (longhorn_bdev->config) {
longhorn_bdev->config->longhorn_bdev = NULL;
}
#endif
free(longhorn_bdev);
}
@ -330,6 +327,11 @@ longhorn_bdev_free_base_bdev_resource(struct longhorn_bdev *longhorn_bdev,
longhorn_bdev->num_base_bdevs_discovered--;
}
static void
longhorn_volume_nvmf_stop(struct spdk_nvmf_subsystem *subsystem,
void *arg, int status)
{
}
/*
* brief:
* longhorn_bdev_destruct is the destruct function table pointer for longhorn bdev
@ -344,8 +346,19 @@ longhorn_bdev_destruct(void *ctxt)
{
struct longhorn_bdev *longhorn_bdev = ctxt;
struct longhorn_base_bdev_info *base_info;
struct spdk_nvmf_tgt *tgt;
struct spdk_nvmf_subsystem *subsystem;
SPDK_DEBUGLOG(bdev_longhorn, "longhorn_bdev_destruct\n");
SPDK_ERRLOG("longhorn_bdev_destruct\n");
tgt = spdk_nvmf_get_tgt(NULL);
subsystem = spdk_nvmf_tgt_find_subsystem(tgt, longhorn_bdev->nqn);
if (subsystem != NULL) {
spdk_nvmf_subsystem_stop(subsystem, longhorn_volume_nvmf_stop, NULL);
}
longhorn_bdev->destruct_called = true;
//LONGHORN_FOR_EACH_BASE_BDEV(longhorn_bdev, base_info) {
@ -549,6 +562,12 @@ longhorn_bdev_get_io_channel(void *ctxt)
return spdk_get_io_channel(longhorn_bdev);
}
static int
_longhorn_bdev_dump_info_json(void *ctx, struct spdk_json_write_ctx *w) {
struct longhorn_bdev *bdev = ctx;
return longhorn_bdev_dump_info_json(bdev, w);
}
/*
* brief:
@ -560,10 +579,10 @@ longhorn_bdev_get_io_channel(void *ctxt)
* 0 - success
* non zero - failure
*/
static int
longhorn_bdev_dump_info_json(void *ctx, struct spdk_json_write_ctx *w)
int
longhorn_bdev_dump_info_json(struct longhorn_bdev *longhorn_bdev, struct spdk_json_write_ctx *w)
{
struct longhorn_bdev *longhorn_bdev = ctx;
struct longhorn_base_bdev_info *base_info;
SPDK_DEBUGLOG(bdev_longhorn, "longhorn_bdev_dump_config_json\n");
@ -614,7 +633,6 @@ longhorn_bdev_write_config_json(struct spdk_bdev *bdev, struct spdk_json_write_c
spdk_json_write_named_string(w, "name", bdev->name);
spdk_json_write_named_array_begin(w, "base_bdevs");
//LONGHORN_FOR_EACH_BASE_BDEV(longhorn_bdev, base_info) {
TAILQ_FOREACH(base_info, &longhorn_bdev->base_bdevs_head, infos) {
if (base_info->bdev) {
spdk_json_write_string(w, base_info->bdev->name);
@ -632,7 +650,7 @@ static const struct spdk_bdev_fn_table g_longhorn_bdev_fn_table = {
.submit_request = longhorn_bdev_submit_request,
.io_type_supported = longhorn_bdev_io_type_supported,
.get_io_channel = longhorn_bdev_get_io_channel,
.dump_info_json = longhorn_bdev_dump_info_json,
.dump_info_json = _longhorn_bdev_dump_info_json,
.write_config_json = longhorn_bdev_write_config_json,
};
@ -933,12 +951,11 @@ longhorn_bdev_create(const char *name, const char *address, uint8_t num_base_bde
if (address != NULL && address[0] != '\0') {
longhorn_bdev->address = strdup(address);
longhorn_bdev->nqn = spdk_sprintf_alloc(VOLUME_FORMAT, address);
} else {
longhorn_bdev->nqn = spdk_sprintf_alloc(VOLUME_FORMAT, "127.0.0.1");
longhorn_bdev->address = strdup("127.0.0.1");
}
longhorn_bdev->nqn = longhorn_generate_volume_nqn(name);
longhorn_bdev->io_ops = 0;
longhorn_bdev->num_base_bdevs = num_base_bdevs;
@ -1092,7 +1109,6 @@ longhorn_bdev_configure(struct longhorn_bdev *longhorn_bdev)
struct spdk_bdev *longhorn_bdev_gen;
struct longhorn_base_bdev_info *base_info;
int rc = 0;
char *nqn;
assert(longhorn_bdev->state == RAID_BDEV_STATE_CONFIGURING);
assert(longhorn_bdev->num_base_bdevs_discovered == longhorn_bdev->num_base_bdevs);
@ -1147,14 +1163,13 @@ longhorn_bdev_configure(struct longhorn_bdev *longhorn_bdev)
SPDK_DEBUGLOG(bdev_longhorn, "longhorn bdev is created with name %s, longhorn_bdev %p\n",
longhorn_bdev_gen->name, longhorn_bdev);
nqn = spdk_sprintf_alloc(VOLUME_FORMAT, longhorn_bdev_gen->name);
if (longhorn_bdev->address) {
longhorn_publish_nvmf(longhorn_bdev_gen->name, nqn,
longhorn_publish_nvmf(longhorn_bdev_gen->name, longhorn_bdev->nqn,
longhorn_bdev->address,
4420, longhorn_bdev_nvmf_cb, NULL);
} else {
longhorn_publish_nvmf(longhorn_bdev_gen->name, nqn, "127.0.0.1",
longhorn_publish_nvmf(longhorn_bdev_gen->name, longhorn_bdev->nqn, "127.0.0.1",
4420, longhorn_bdev_nvmf_cb, NULL);
}
@ -1297,7 +1312,6 @@ longhorn_bdev_event_base_bdev(enum spdk_bdev_event_type type, struct spdk_bdev *
}
#if 0
/*
* brief:
* Remove base bdevs from the longhorn bdev one by one. Skip any base bdev which
@ -1308,17 +1322,17 @@ longhorn_bdev_event_base_bdev(enum spdk_bdev_event_type type, struct spdk_bdev *
* cb_ctx - argument to callback function
*/
void
longhorn_bdev_remove_base_devices(struct longhorn_bdev_config *longhorn_cfg,
longhorn_bdev_remove_base_devices(const char *longhorn_name,
longhorn_bdev_destruct_cb cb_fn, void *cb_arg)
{
struct longhorn_bdev *longhorn_bdev;
struct longhorn_base_bdev_info *base_info;
SPDK_DEBUGLOG(bdev_longhorn, "longhorn_bdev_remove_base_devices\n");
longhorn_bdev = longhorn_bdev_find_by_name(longhorn_name);
longhorn_bdev = longhorn_cfg->longhorn_bdev;
if (longhorn_bdev == NULL) {
SPDK_DEBUGLOG(bdev_longhorn, "longhorn bdev %s doesn't exist now\n", longhorn_cfg->name);
SPDK_DEBUGLOG(bdev_longhorn, "longhorn bdev %s doesn't exist now\n", longhorn_name);
if (cb_fn) {
cb_fn(cb_arg, 0);
}
@ -1336,7 +1350,6 @@ longhorn_bdev_remove_base_devices(struct longhorn_bdev_config *longhorn_cfg,
longhorn_bdev->destroy_started = true;
//LONGHORN_FOR_EACH_BASE_BDEV(longhorn_bdev, base_info) {
TAILQ_FOREACH(base_info, &longhorn_bdev->base_bdevs_head, infos) {
if (base_info->bdev == NULL) {
continue;
@ -1365,7 +1378,6 @@ longhorn_bdev_remove_base_devices(struct longhorn_bdev_config *longhorn_cfg,
longhorn_bdev_deconfigure(longhorn_bdev, cb_fn, cb_arg);
}
#endif
/*
* brief:
@ -1773,63 +1785,9 @@ int longhorn_bdev_remove_replica(char *name, char *lvs, char *addr, uint16_t nvm
return 0;
}
int longhorn_bdev_add_base_replica(struct longhorn_base_bdev_info *base_info)
{
struct longhorn_bdev *longhorn_bdev;
struct longhorn_bdev_io_channel *io_channel;
struct io_channel_add_ctx *ctx;
int rc;
atomic_uint *num_io_channels_to_add;
rc = pthread_mutex_trylock(&longhorn_bdev->base_bdevs_mutex);
if (rc != 0) {
if (errno == EBUSY) {
SPDK_ERRLOG("Longhorn bdev '%s' is busy\n",
longhorn_bdev->bdev.name);
}
return -errno;
}
// claim
TAILQ_REMOVE(&longhorn_bdev->base_bdevs_head, base_info, infos);
/* signal each longhorn_io to stop using the bdev */
SPDK_DEBUGLOG(bdev_longhorn,"num io channels %u\n", longhorn_bdev->num_io_channels);
num_io_channels_to_add = calloc(1, sizeof(atomic_int));
atomic_init(num_io_channels_to_add, longhorn_bdev->num_io_channels);
TAILQ_FOREACH(io_channel, &longhorn_bdev->io_channel_head, channels) {
ctx = calloc(1, sizeof (*ctx));
ctx->base_info = base_info;
ctx->io_channel = io_channel;
ctx->num_io_channels_to_add = num_io_channels_to_add;
if (!io_channel->deleted) {
spdk_thread_send_msg(io_channel->thread, longhorn_io_channel_add_bdev, ctx);
}
}
pthread_mutex_unlock(&longhorn_bdev->base_bdevs_mutex);
return 0;
}
int longhorn_volume_add_replica(char *name, char *lvs, char *addr, uint16_t nvmf_port, uint16_t comm_port) {
struct longhorn_bdev *longhorn_bdev;
//struct longhorn_base_bdev_info *base_info;
struct longhorn_bdev_io_channel *io_channel;
//struct io_channel_remove_ctx *ctx;
int rc;
/* Create base_info and add to base_info list */
@ -1858,7 +1816,7 @@ int longhorn_volume_add_replica(char *name, char *lvs, char *addr, uint16_t nvmf
}
longhorn_bdev->op_in_progress = true;
longhorn_bdev->op_in_progress = true;
longhorn_bdev->pause_op = LONGHORN_PAUSE_OP_ADD;
pthread_mutex_unlock(&longhorn_bdev->base_bdevs_mutex);

View File

@ -264,7 +264,7 @@ typedef void (*longhorn_bdev_destruct_cb)(void *cb_ctx, int rc);
int longhorn_bdev_create(const char *name, const char *address, uint8_t num_base_bdevs);
int longhorn_bdev_add_base_devices(struct longhorn_bdev_config *longhorn_cfg);
void longhorn_bdev_remove_base_devices(struct longhorn_bdev_config *longhorn_cfg,
void longhorn_bdev_remove_base_devices(const char *longhorn_name,
longhorn_bdev_destruct_cb cb_fn, void *cb_ctx);
int longhorn_bdev_config_add(const char *longhorn_name, uint8_t num_base_bdevs,
struct longhorn_bdev_config **_longhorn_cfg);
@ -297,5 +297,7 @@ void longhorn_volume_add_pause_cb(struct longhorn_bdev *longhorn_dev,
longhorn_pause_cb cb_fn,
void *cb_arg);
int longhorn_volume_add_replica(char *name, char *lvs, char *addr, uint16_t nvmf_port, uint16_t comm_port);
int
longhorn_bdev_dump_info_json(struct longhorn_bdev *bdev, struct spdk_json_write_ctx *w);
#endif /* SPDK_BDEV_RAID_INTERNAL_H */

View File

@ -150,10 +150,21 @@ longhorn_submit_read_request(struct longhorn_bdev_io *longhorn_io)
bdev_io->u.bdev.offset_blocks, bdev_io->u.bdev.num_blocks, longhorn_bdev_io_completion,
longhorn_io);
if (ret == -ENOMEM) {
longhorn_bdev_queue_io_wait(longhorn_io, base_info->bdev, base_ch,
_longhorn_submit_rw_request);
} else if (ret != 0) {
return;
}
#if 0
atomic_fetch_add(&longhorn_bdev->io_ops, 1);
atomic_fetch_add(&longhorn_ch->io_ops, 1);
longhorn_io->submitted = true;
#endif
if (ret != 0) {
SPDK_ERRLOG("bdev io submit error not due to ENOMEM, it should not happen\n");
assert(false);
longhorn_bdev_io_complete(longhorn_io, SPDK_BDEV_IO_STATUS_FAILED);
@ -182,9 +193,6 @@ longhorn_submit_write_request(struct longhorn_bdev_io *longhorn_io)
TAILQ_FOREACH(base_channel, &longhorn_ch->base_channels, channels) {
//for (pd_idx = 0; pd_idx < longhorn_bdev->num_base_bdevs; pd_idx++) {
//base_ch = longhorn_ch->base_channel[pd_idx];
//base_info = &longhorn_bdev->base_bdev_info[pd_idx];
base_ch = base_channel->base_channel;
base_info = base_channel->base_info;
@ -307,7 +315,14 @@ longhorn_submit_null_payload_request(struct longhorn_bdev_io *longhorn_io)
if (ret == -ENOMEM) {
longhorn_bdev_queue_io_wait(longhorn_io, base_info->bdev, base_ch,
_longhorn_submit_null_payload_request);
} else if (ret != 0) {
return;
}
atomic_fetch_add(&longhorn_bdev->io_ops, 1);
atomic_fetch_add(&longhorn_ch->io_ops, 1);
longhorn_io->submitted = true;
if (ret != 0) {
SPDK_ERRLOG("bdev io submit error not due to ENOMEM, it should not happen\n");
assert(false);
longhorn_bdev_io_complete(longhorn_io, SPDK_BDEV_IO_STATUS_FAILED);

View File

@ -1,12 +1,20 @@
#include "spdk/nvmf.h"
#include "spdk/string.h"
#include "spdk/util.h"
#include "spdk/bdev.h"
#include "bdev_longhorn_nvmf.h"
static bool tcp_transport_created = false;
struct longhorn_publish_nvmf_ctx {
longhorn_publish_nvmf_cb cb_fn;
void *cb_arg;
};
static void
longhorn_tgt_add_transport_done(void *cb_arg, int status)
{
@ -20,6 +28,13 @@ longhorn_tgt_add_transport_done(void *cb_arg, int status)
static void
longhorn_subsystem_add_done(struct spdk_nvmf_subsystem *subsystem,
void *cb_arg, int status) {
struct longhorn_publish_nvmf_ctx *ctx = cb_arg;
if (ctx != NULL) {
(*ctx->cb_fn)(ctx->cb_arg);
free(ctx);
}
}
void longhorn_nvmf_create_transport(spdk_nvmf_tgt_add_transport_done_fn cb_fn,
@ -33,6 +48,11 @@ void longhorn_nvmf_create_transport(spdk_nvmf_tgt_add_transport_done_fn cb_fn,
transport = spdk_nvmf_transport_create("tcp", &opts);
if (transport == NULL) {
} else {
tcp_transport_created = true;
}
if (cb_fn != NULL) {
spdk_nvmf_tgt_add_transport(tgt, transport, cb_fn, cb_arg);
} else {
@ -128,22 +148,22 @@ void longhorn_nvmf_subsystem_add_ns(const char *nqn, const char *bdev_name) {
spdk_nvmf_subsystem_pause(subsystem, 0, add_ns_pause_cb, bdev_name);
}
struct longhorn_publish_nvmf_ctx {
longhorn_publish_nvmf_cb cb_fn;
void *cb_arg;
};
static void _longhorn_publish_nvmf(const char *bdev_name, const char *nqn, const char *addr, uint16_t port, longhorn_publish_nvmf_cb cb_fn, void *cb_arg) {
struct spdk_nvmf_tgt *tgt;
struct spdk_nvmf_subsystem *subsystem;
struct spdk_nvmf_ns_opts ns_opts;
struct spdk_nvmf_listen_opts listen_opts;
struct spdk_nvme_transport_id *trid;
struct longhorn_publish_nvmf_ctx *ctx;
tgt = spdk_nvmf_get_tgt(NULL);
subsystem = spdk_nvmf_tgt_find_subsystem(tgt, nqn);
if (subsystem == NULL) {
subsystem = spdk_nvmf_subsystem_create(tgt, nqn, SPDK_NVMF_SUBTYPE_NVME,
0);
}
spdk_nvmf_subsystem_set_allow_any_host(subsystem, true);
@ -159,7 +179,11 @@ static void _longhorn_publish_nvmf(const char *bdev_name, const char *nqn, const
spdk_nvmf_tgt_listen_ext(tgt, trid, &listen_opts);
spdk_nvmf_subsystem_add_listener(subsystem, trid, add_listener_cb, trid);
spdk_nvmf_subsystem_start(subsystem, longhorn_subsystem_add_done, NULL);
ctx = calloc(1, sizeof(*ctx));
ctx->cb_fn = cb_fn;
ctx->cb_arg = cb_arg;
spdk_nvmf_subsystem_start(subsystem, longhorn_subsystem_add_done, ctx);
}
@ -247,7 +271,6 @@ void longhorn_attach_nvmf(const char *bdev_name_prefix, const char *nqn,
longhorn_attach_nvmf_cb cb_fn, void *cb_arg) {
struct spdk_nvme_transport_id *trid;
size_t len;
struct spdk_nvme_host_id hostid = {};
uint32_t prchk_flags = 0;
struct longhorn_attach_nvmf_ctx *ctx;
@ -267,8 +290,9 @@ void longhorn_attach_nvmf(const char *bdev_name_prefix, const char *nqn,
spdk_nvme_ctrlr_get_default_ctrlr_opts(&ctx->opts, sizeof(ctx->opts));
bdev_nvme_create(trid, &hostid, bdev_name_prefix, ctx->names, ctx->count,
prchk_flags, longhorn_nvme_create_cb, ctx, &ctx->opts);
bdev_nvme_create(trid, bdev_name_prefix, ctx->names, ctx->count,
prchk_flags, longhorn_nvme_create_cb, ctx, &ctx->opts,
false, 0, 0, 0);
}
@ -322,5 +346,21 @@ longhorn_generate_replica_nqn(const char *lvs, const char *name) {
return nqn;
}
char *
longhorn_generate_volume_nqn(const char *name) {
char *nqn = spdk_sprintf_alloc(VOLUME_FORMAT, name);
return nqn;
}
char *
longhorn_generate_snapshot_nqn(const char *name) {
char *nqn = spdk_sprintf_alloc(SNAPSHOT_FORMAT, name);
return nqn;
}
char *
longhorn_generate_replica_snapshot_nqn(const char *lvs, const char *name) {
char *nqn = spdk_sprintf_alloc(REPLICA_SNAPSHOT_FORMAT, lvs, name);
return nqn;
}

View File

@ -7,6 +7,8 @@
#define VOLUME_FORMAT "nqn.2021-12.io.longhorn.volume:%s"
#define REPLICA_FORMAT "nqn.2021-12.io.longhorn.replica:%s/%s"
#define SNAPSHOT_FORMAT "nqn.2021-12.io.longhorn.snapshot:%s"
#define REPLICA_SNAPSHOT_FORMAT "nqn.2021-12.io.longhorn.replica.snapshot:%s/%s"
void longhorn_nvmf_create_transport(spdk_nvmf_tgt_add_transport_done_fn cb_fn,
void *cb_arg);
@ -26,6 +28,12 @@ void longhorn_attach_nvmf(const char *bdev_name_prefix, const char *nqn, const c
char *
longhorn_generate_replica_nqn(const char *lvs, const char *name);
char *
longhorn_generate_volume_nqn(const char *name);
char *
longhorn_generate_snapshot_nqn(const char *name);
char *
longhorn_generate_replica_snapshot_nqn(const char *lvs, const char *name);
#endif /* _BDEV_LONGHORN_NVMF_H_ */

View File

@ -121,19 +121,31 @@ rpc_bdev_longhorn_get_bdevs(struct spdk_jsonrpc_request *request,
/* Get longhorn bdev list based on the category requested */
if (strcmp(req.category, "all") == 0) {
TAILQ_FOREACH(longhorn_bdev, &g_longhorn_bdev_list, global_link) {
spdk_json_write_string(w, longhorn_bdev->bdev.name);
spdk_json_write_object_begin(w);
spdk_json_write_named_string(w, "name", longhorn_bdev->name);
longhorn_bdev_dump_info_json(longhorn_bdev, w);
spdk_json_write_object_end(w);
}
} else if (strcmp(req.category, "online") == 0) {
TAILQ_FOREACH(longhorn_bdev, &g_longhorn_bdev_configured_list, state_link) {
spdk_json_write_string(w, longhorn_bdev->bdev.name);
spdk_json_write_object_begin(w);
spdk_json_write_named_string(w, "name", longhorn_bdev->name);
longhorn_bdev_dump_info_json(longhorn_bdev, w);
spdk_json_write_object_end(w);
}
} else if (strcmp(req.category, "configuring") == 0) {
TAILQ_FOREACH(longhorn_bdev, &g_longhorn_bdev_configuring_list, state_link) {
spdk_json_write_string(w, longhorn_bdev->bdev.name);
spdk_json_write_object_begin(w);
spdk_json_write_named_string(w, "name", longhorn_bdev->name);
longhorn_bdev_dump_info_json(longhorn_bdev, w);
spdk_json_write_object_end(w);
}
} else {
TAILQ_FOREACH(longhorn_bdev, &g_longhorn_bdev_offline_list, state_link) {
spdk_json_write_string(w, longhorn_bdev->bdev.name);
spdk_json_write_object_begin(w);
spdk_json_write_named_string(w, "name", longhorn_bdev->name);
longhorn_bdev_dump_info_json(longhorn_bdev, w);
spdk_json_write_object_end(w);
}
}
spdk_json_write_array_end(w);
@ -144,6 +156,7 @@ cleanup:
}
SPDK_RPC_REGISTER("bdev_longhorn_get_bdevs", rpc_bdev_longhorn_get_bdevs, SPDK_RPC_RUNTIME)
SPDK_RPC_REGISTER_ALIAS_DEPRECATED(bdev_longhorn_get_bdevs, get_longhorn_bdevs)
SPDK_RPC_REGISTER_ALIAS_DEPRECATED(bdev_longhorn_get_bdevs, longhorn_volume_list)
struct longhorn_replica {
char *addr;
@ -460,12 +473,6 @@ bdev_longhorn_delete_done(void *cb_arg, int rc)
goto exit;
}
#if 0
longhorn_cfg = ctx->longhorn_cfg;
assert(longhorn_cfg->longhorn_bdev == NULL);
longhorn_bdev_config_cleanup(longhorn_cfg);
#endif
spdk_jsonrpc_send_bool_response(request, true);
exit:
@ -504,20 +511,11 @@ rpc_bdev_longhorn_delete(struct spdk_jsonrpc_request *request,
goto cleanup;
}
#if 0
ctx->longhorn_cfg = longhorn_bdev_config_find_by_name(ctx->req.name);
if (ctx->longhorn_cfg == NULL) {
spdk_jsonrpc_send_error_response_fmt(request, ENODEV,
"longhorn bdev %s is not found in config",
ctx->req.name);
goto cleanup;
}
#endif
ctx->request = request;
/* Remove all the base bdevs from this longhorn bdev before deleting the longhorn bdev */
//longhorn_bdev_remove_base_devices(ctx->longhorn_cfg, bdev_longhorn_delete_done, ctx);
longhorn_bdev_remove_base_devices(ctx->req.name, bdev_longhorn_delete_done, ctx);
return;
@ -527,6 +525,7 @@ cleanup:
}
SPDK_RPC_REGISTER("bdev_longhorn_delete", rpc_bdev_longhorn_delete, SPDK_RPC_RUNTIME)
SPDK_RPC_REGISTER_ALIAS_DEPRECATED(bdev_longhorn_delete, destroy_longhorn_bdev)
SPDK_RPC_REGISTER_ALIAS_DEPRECATED(bdev_longhorn_delete, longhorn_volume_stop)
struct cluster_entry {
int cluster;

View File

@ -336,7 +336,7 @@ static void longhorn_bdev_snapshot(void *arg)
static void longhorn_snapshot_pause_complete(struct longhorn_bdev *bdev,
void longhorn_snapshot_pause_complete(struct longhorn_bdev *bdev,
void *arg) {
struct longhorn_snapshot_ctx *ctx = arg;
ctx->bdev = bdev;