Skip to content

Commit

Permalink
lvs: additional support for lvs live grow and bdev resize
Browse files Browse the repository at this point in the history
Added helpers for support live lvs grow in client apps.
Added experimental support for malloc bdev resize, which is needed for live
grow tests.

Signed-off-by: Dmitry Savitskiy <[email protected]>
  • Loading branch information
dsavitskiy committed Aug 30, 2024
1 parent 981a969 commit e5f7aa4
Show file tree
Hide file tree
Showing 12 changed files with 281 additions and 35 deletions.
26 changes: 26 additions & 0 deletions include/spdk/bdev_module.h
Original file line number Diff line number Diff line change
Expand Up @@ -1349,6 +1349,32 @@ uint64_t spdk_bdev_io_get_submit_tsc(struct spdk_bdev_io *bdev_io);
*/
int spdk_bdev_notify_blockcnt_change(struct spdk_bdev *bdev, uint64_t size);

/**
* spdk_bdev_resize() callback.
*
* \param bdev Block device being resized.
* \param cb_arg Argument passed to the resize function.
* \param status 0 for successfull resize, negated errno on failure.
*/
typedef void (*spdk_resize_cb)(struct spdk_bdev *bdev, void *cb_arg, int status);

/**
* Resizes the bdev.
*
* Change number of blocks for provided block device.
* It can only be called on a registered bdev.
*
* \param bdev Block device to change.
* \param size New size of bdev.
* \param resize_cb Called after the new size is applied.
* \param cb_arg Argument to pass to callback function.
* \return 0 on success, negated errno on failure.
*/
int spdk_bdev_resize(struct spdk_bdev *bdev,
uint64_t size,
spdk_resize_cb resize_cb,
void *cb_arg);

/**
* Translates NVMe status codes to SCSI status information.
*
Expand Down
18 changes: 18 additions & 0 deletions include/spdk/blob.h
Original file line number Diff line number Diff line change
Expand Up @@ -476,6 +476,24 @@ uint64_t spdk_bs_free_cluster_count(struct spdk_blob_store *bs);
*/
uint64_t spdk_bs_total_data_cluster_count(struct spdk_blob_store *bs);

/**
* Get the blobstore metadata size in pages.
*
* \param bs blobstore to query.
*
* \return the blobstore metadata size in pages.
*/
uint64_t spdk_bs_get_md_len(struct spdk_blob_store *bs);

/**
* Get the number of used metadata pages.
*
* \param bs blobstore to query.
*
* \return the number of used metadata pages.
*/
uint64_t spdk_bs_get_used_md(struct spdk_blob_store *bs);

/**
* Get the blob id.
*
Expand Down
56 changes: 46 additions & 10 deletions include/spdk/lvol.h
Original file line number Diff line number Diff line change
Expand Up @@ -58,7 +58,7 @@ struct spdk_lvs_opts {
uint32_t num_md_pages_per_cluster_ratio;

/**
* The size of spdk_lvol_opts according to the caller of this library is used for ABI
* The size of spdk_lvs_opts according to the caller of this library is used for ABI
* compatibility. The library uses this field to know how many fields in this
* structure are valid. And the library will populate any remaining fields with default
* values. After that, new added fields should be put in the end of the struct.
Expand Down Expand Up @@ -190,6 +190,45 @@ int spdk_lvs_unload(struct spdk_lvol_store *lvol_store,
int spdk_lvs_destroy(struct spdk_lvol_store *lvol_store,
spdk_lvs_op_complete cb_fn, void *cb_arg);

/**
* Parameters for lvs initialization.
*/
struct spdk_lvol_opts {
/**
* The size of spdk_lvol_opts according to the caller of this library is used for ABI
* compatibility. The library uses this field to know how many fields in this
* structure are valid. And the library will populate any remaining fields with default
* values. After that, new added fields should be put in the end of the struct.
*/
uint32_t opts_size;

/** Name of lvol. */
const char *name;

/** Optional uuid of the new volume or null if it should be autogenerated. */
const char *uuid;

/** Size of lvol in bytes. */
uint64_t size;

/** Enables thin provisioning (disabled by default). */
bool thin_provision;

/** Use extent table (enabled by default). */
bool use_extent_table;

/** Changes default data clusters clear method. */
enum lvol_clear_method clear_method;
} __attribute__((packed));
SPDK_STATIC_ASSERT(sizeof(struct spdk_lvol_opts) == 34, "Incorrect size");

/**
* Initialize an spdk_lvol_opts structure to the defaults.
*
* \param opts Pointer to the spdk_lvol_opts structure to initialize.
*/
void spdk_lvol_opts_init(struct spdk_lvol_opts *opts);

/**
* Create lvol on given lvolstore with specified size.
*
Expand All @@ -208,22 +247,19 @@ int spdk_lvol_create(struct spdk_lvol_store *lvs, const char *name, uint64_t sz,
spdk_lvol_op_with_handle_complete cb_fn, void *cb_arg);

/**
* Same as above but allows to specify uuid of the new lvol.
* Create lvol on given lvolstore with specified options.
*
* \param lvs Handle to lvolstore.
* \param name Name of lvol.
* \param sz size of lvol in bytes.
* \param thin_provisioned Enables thin provisioning.
* \param clear_method Changes default data clusters clear method
* \param uuid uuid of the new volume or null if it should be autogenerated.
* \param lvol_opts Options for lvol.
* \param cb_fn Completion callback.
* \param cb_arg Completion callback custom arguments.
*
* \return 0 on success, negative errno on failure.
*/
int spdk_lvol_create_with_uuid(struct spdk_lvol_store *lvs, const char *name, uint64_t sz,
bool thin_provisioned, enum lvol_clear_method clear_method,
const char *uuid, spdk_lvol_op_with_handle_complete cb_fn, void *cb_arg);
int spdk_lvol_create_with_opts(struct spdk_lvol_store *lvs,
const struct spdk_lvol_opts *lvol_opts,
spdk_lvol_op_with_handle_complete cb_fn,
void *cb_arg);

/**
* Create snapshot of given lvol.
Expand Down
13 changes: 13 additions & 0 deletions lib/bdev/bdev.c
Original file line number Diff line number Diff line change
Expand Up @@ -5139,6 +5139,13 @@ _resize_notify(void *ctx)

int
spdk_bdev_notify_blockcnt_change(struct spdk_bdev *bdev, uint64_t size)
{
return spdk_bdev_resize(bdev, size, NULL, NULL);
}

int
spdk_bdev_resize(struct spdk_bdev *bdev, uint64_t size,
spdk_resize_cb resize_cb, void *cb_arg)
{
struct spdk_bdev_desc *desc;
int ret;
Expand All @@ -5153,8 +5160,14 @@ spdk_bdev_notify_blockcnt_change(struct spdk_bdev *bdev, uint64_t size)
if (!TAILQ_EMPTY(&bdev->internal.open_descs) &&
bdev->blockcnt > size) {
ret = -EBUSY;
if (resize_cb != NULL) {
resize_cb(bdev, cb_arg, ret);
}
} else {
bdev->blockcnt = size;
if (resize_cb != NULL) {
resize_cb(bdev, cb_arg, 0);
}
TAILQ_FOREACH(desc, &bdev->internal.open_descs, link) {
event_notify(desc, _resize_notify);
}
Expand Down
18 changes: 18 additions & 0 deletions lib/blob/blobstore.c
Original file line number Diff line number Diff line change
Expand Up @@ -6167,6 +6167,24 @@ spdk_bs_total_data_cluster_count(struct spdk_blob_store *bs)
return bs->total_data_clusters;
}

uint64_t
spdk_bs_get_md_len(struct spdk_blob_store *bs)
{
return bs->md_len;
}

uint64_t
spdk_bs_get_used_md(struct spdk_blob_store *bs)
{
uint64_t res = 0;

spdk_spin_lock(&bs->used_lock);
res = spdk_bit_array_count_set(bs->used_md_pages);
spdk_spin_unlock(&bs->used_lock);

return res;
}

static int
bs_register_md_thread(struct spdk_blob_store *bs)
{
Expand Down
49 changes: 38 additions & 11 deletions lib/lvol/lvol.c
Original file line number Diff line number Diff line change
Expand Up @@ -1266,20 +1266,40 @@ lvs_verify_lvol_name(struct spdk_lvol_store *lvs, const char *name)
return 0;
}

void
spdk_lvol_opts_init(struct spdk_lvol_opts *o)
{
memset(o, 0, sizeof(*o));
o->name = NULL;
o->uuid = NULL;
o->size = 0;
o->thin_provision = false;
o->use_extent_table = true;
o->clear_method = LVOL_CLEAR_WITH_NONE;
o->opts_size = sizeof(*o);
}

int
spdk_lvol_create(struct spdk_lvol_store *lvs, const char *name, uint64_t sz,
bool thin_provision, enum lvol_clear_method clear_method,
spdk_lvol_op_with_handle_complete cb_fn,
void *cb_arg)
{
return spdk_lvol_create_with_uuid(lvs, name, sz, thin_provision,
clear_method, NULL, cb_fn, cb_arg);
struct spdk_lvol_opts opts;

spdk_lvol_opts_init(&opts);
opts.name = name;
opts.size = sz;
opts.thin_provision = thin_provision;
opts.clear_method = clear_method;

return spdk_lvol_create_with_opts(lvs, &opts, cb_fn, cb_arg);
}

int
spdk_lvol_create_with_uuid(struct spdk_lvol_store *lvs, const char *name, uint64_t sz,
bool thin_provision, enum lvol_clear_method clear_method,
const char *uuid, spdk_lvol_op_with_handle_complete cb_fn,
spdk_lvol_create_with_opts(struct spdk_lvol_store *lvs,
const struct spdk_lvol_opts *lvol_opts,
spdk_lvol_op_with_handle_complete cb_fn,
void *cb_arg)
{
struct spdk_lvol_with_handle_req *req;
Expand All @@ -1290,12 +1310,14 @@ spdk_lvol_create_with_uuid(struct spdk_lvol_store *lvs, const char *name, uint64
char *xattr_names[] = {LVOL_NAME, LVOL_UUID};
int rc;

assert(lvol_opts);

if (lvs == NULL) {
SPDK_ERRLOG("lvol store does not exist\n");
return -EINVAL;
}

rc = lvs_verify_lvol_name(lvs, name);
rc = lvs_verify_lvol_name(lvs, lvol_opts->name);
if (rc < 0) {
return rc;
}
Expand All @@ -1310,15 +1332,19 @@ spdk_lvol_create_with_uuid(struct spdk_lvol_store *lvs, const char *name, uint64
req->cb_fn = cb_fn;
req->cb_arg = cb_arg;

if (uuid) {
if (spdk_uuid_parse(&parsed_uuid, uuid) != 0) {
if (lvol_opts->uuid) {
if (spdk_uuid_parse(&parsed_uuid, lvol_opts->uuid) != 0) {
free(req);
SPDK_ERRLOG("Invalid lvol uuid provided\n");
return -EINVAL;
}
}

lvol = lvol_alloc(lvs, name, uuid ? &parsed_uuid : NULL, thin_provision, clear_method);
lvol = lvol_alloc(lvs,
lvol_opts->name,
lvol_opts->uuid ? &parsed_uuid : NULL,
lvol_opts->thin_provision,
lvol_opts->clear_method);
if (!lvol) {
free(req);
SPDK_ERRLOG("Cannot alloc memory for lvol base pointer\n");
Expand All @@ -1327,8 +1353,9 @@ spdk_lvol_create_with_uuid(struct spdk_lvol_store *lvs, const char *name, uint64

req->lvol = lvol;
spdk_blob_opts_init(&opts, sizeof(opts));
opts.thin_provision = thin_provision;
opts.num_clusters = spdk_divide_round_up(sz, spdk_bs_get_cluster_size(bs));
opts.thin_provision = lvol_opts->thin_provision;
opts.use_extent_table = lvol_opts->use_extent_table;
opts.num_clusters = spdk_divide_round_up(lvol_opts->size, spdk_bs_get_cluster_size(bs));
opts.clear_method = lvol->clear_method;
opts.xattrs.count = SPDK_COUNTOF(xattr_names);
opts.xattrs.names = xattr_names;
Expand Down
3 changes: 2 additions & 1 deletion lib/lvol/spdk_lvol.map
Original file line number Diff line number Diff line change
Expand Up @@ -9,12 +9,13 @@
spdk_lvs_destroy;
spdk_lvs_grow;
spdk_lvs_grow_live;
spdk_lvol_opts_init;
spdk_lvol_create;
spdk_lvol_create_snapshot;
spdk_lvol_create_snapshot_ext;
spdk_lvol_create_clone;
spdk_lvol_create_clone_ext;
spdk_lvol_create_with_uuid;
spdk_lvol_create_with_opts;
spdk_lvol_create_snapshot_ext;
spdk_lvol_rename;
spdk_lvol_deletable;
Expand Down
12 changes: 5 additions & 7 deletions module/bdev/lvol/vbdev_lvol.c
Original file line number Diff line number Diff line change
Expand Up @@ -2291,11 +2291,10 @@ vbdev_lvol_set_external_parent(struct spdk_lvol *lvol, const char *esnap_name,

SPDK_LOG_REGISTER_COMPONENT(vbdev_lvol)

int
vbdev_lvol_create_with_uuid(struct spdk_lvol_store *lvs, const char *name, uint64_t sz,
bool thin_provision, enum lvol_clear_method clear_method,
const char *uuid, spdk_lvol_op_with_handle_complete cb_fn,
void *cb_arg)
int vbdev_lvol_create_with_opts(struct spdk_lvol_store *lvs,
const struct spdk_lvol_opts *lvol_opts,
spdk_lvol_op_with_handle_complete cb_fn,
void *cb_arg)
{
struct spdk_lvol_with_handle_req *req;
int rc;
Expand All @@ -2307,8 +2306,7 @@ vbdev_lvol_create_with_uuid(struct spdk_lvol_store *lvs, const char *name, uint6
req->cb_fn = cb_fn;
req->cb_arg = cb_arg;

rc = spdk_lvol_create_with_uuid(lvs, name, sz, thin_provision, clear_method,
uuid, _vbdev_lvol_create_cb, req);
rc = spdk_lvol_create_with_opts(lvs, lvol_opts, _vbdev_lvol_create_cb, req);
if (rc != 0) {
free(req);
}
Expand Down
6 changes: 3 additions & 3 deletions module/bdev/lvol/vbdev_lvol.h
Original file line number Diff line number Diff line change
Expand Up @@ -52,9 +52,9 @@ int vbdev_lvol_create(struct spdk_lvol_store *lvs, const char *name, uint64_t sz
spdk_lvol_op_with_handle_complete cb_fn,
void *cb_arg);

int vbdev_lvol_create_with_uuid(struct spdk_lvol_store *lvs, const char *name, uint64_t sz,
bool thin_provisioned, enum lvol_clear_method clear_method,
const char *uuid, spdk_lvol_op_with_handle_complete cb_fn,
int vbdev_lvol_create_with_opts(struct spdk_lvol_store *lvs,
const struct spdk_lvol_opts *lvol_opts,
spdk_lvol_op_with_handle_complete cb_fn,
void *cb_arg);

void vbdev_lvol_create_snapshot(struct spdk_lvol *lvol, const char *snapshot_name,
Expand Down
12 changes: 9 additions & 3 deletions module/bdev/lvol/vbdev_lvol_rpc.c
Original file line number Diff line number Diff line change
Expand Up @@ -1686,6 +1686,7 @@ spdk_rpc_construct_ms_lvol_bdev(struct spdk_jsonrpc_request *request,
enum lvol_clear_method clear_method;
int rc;
struct spdk_lvol_store *lvs = NULL;
struct spdk_lvol_opts lvol_opts;

SPDK_INFOLOG(lvol_rpc, "Creating blob\n");

Expand Down Expand Up @@ -1725,9 +1726,14 @@ spdk_rpc_construct_ms_lvol_bdev(struct spdk_jsonrpc_request *request,
clear_method = LVOL_CLEAR_WITH_DEFAULT;
}

rc = vbdev_lvol_create_with_uuid(lvs, req.lvol_name, req.size,
req.thin_provision, clear_method, req.uuid,
rpc_bdev_lvol_create_cb, request);
spdk_lvol_opts_init(&lvol_opts);
lvol_opts.name = req.lvol_name;
lvol_opts.size = req.size;
lvol_opts.thin_provision = req.thin_provision;
lvol_opts.clear_method = clear_method;
lvol_opts.uuid = req.uuid;

rc = vbdev_lvol_create_with_opts(lvs, &lvol_opts, rpc_bdev_lvol_create_cb, request);
if (rc < 0) {
goto invalid;
}
Expand Down
Loading

0 comments on commit e5f7aa4

Please sign in to comment.