fragmap: implement bdev_lvol_get_fragmap
Get a fragmap for a specific segment of a logical volume using the provided offset and size. A fragmap is a bitmap that records the allocation status of clusters. A value of "1" indicates that a cluster is allocated, whereas "0" signifies that a cluster is unallocated. Longhorn 6138 Signed-off-by: Derek Su <derek.su@suse.com>
This commit is contained in:
parent
271915912f
commit
0168515003
@ -496,6 +496,7 @@ Example response:
|
||||
"bdev_lvol_rename_lvstore",
|
||||
"bdev_lvol_create_lvstore",
|
||||
"bdev_lvol_shallow_copy",
|
||||
"bdev_lvol_get_fragmap",
|
||||
"bdev_daos_delete",
|
||||
"bdev_daos_create",
|
||||
"bdev_daos_resize"
|
||||
@ -10084,6 +10085,52 @@ Example response:
|
||||
}
|
||||
~~~
|
||||
|
||||
### bdev_lvol_get_fragmap {#bdev_lvol_get_fragmap}
|
||||
|
||||
Get a fragmap for a specific segment of a logical volume using the provided offset and size.
|
||||
A fragmap is a bitmap that records the allocation status of clusters. A value of "1" indicates
|
||||
that a cluster is allocated, whereas "0" signifies that a cluster is unallocated.
|
||||
|
||||
#### Parameters
|
||||
|
||||
Name | Optional | Type | Description
|
||||
----------------------- | -------- | ----------- | -----------
|
||||
name | Required | string | UUID or alias of the logical volume
|
||||
offset | Optional | number | Offset in bytes of the specific segment of the logical volume (Default: 0)
|
||||
size | Optional | number | Size in bytes of the specific segment of the logical volume (Default: 0 for representing the entire file)
|
||||
|
||||
#### Example
|
||||
|
||||
Example request:
|
||||
|
||||
~~~json
|
||||
{
|
||||
"jsonrpc": "2.0",
|
||||
"method": "bdev_lvol_get_fragmap",
|
||||
"id": 1,
|
||||
"params": {
|
||||
"name": "8a47421a-20cf-444f-845c-d97ad0b0bd8e",
|
||||
"offset": 0,
|
||||
"size": 41943040
|
||||
}
|
||||
}
|
||||
~~~
|
||||
|
||||
Example response:
|
||||
|
||||
~~~json
|
||||
{
|
||||
"jsonrpc": "2.0",
|
||||
"id": 1,
|
||||
"result": {
|
||||
"cluster_size": 4194304,
|
||||
"num_clusters": 10,
|
||||
"num_allocated_clusters": 0,
|
||||
"fragmap": "AAA="
|
||||
}
|
||||
}
|
||||
~~~
|
||||
|
||||
## RAID
|
||||
|
||||
### bdev_raid_get_bdevs {#rpc_bdev_raid_get_bdevs}
|
||||
|
@ -168,6 +168,14 @@ void spdk_bit_array_load_mask(struct spdk_bit_array *ba, const void *mask);
|
||||
*/
|
||||
void spdk_bit_array_clear_mask(struct spdk_bit_array *ba);
|
||||
|
||||
/**
|
||||
* Encode a bit array into a base64 string.
|
||||
*
|
||||
* @param array Bit array to encode.
|
||||
* @return base64 string.
|
||||
*/
|
||||
char *spdk_bit_array_to_base64_string(const struct spdk_bit_array *array);
|
||||
|
||||
#ifdef __cplusplus
|
||||
}
|
||||
#endif
|
||||
|
@ -22,6 +22,7 @@ extern "C" {
|
||||
struct spdk_bs_dev;
|
||||
struct spdk_lvol_store;
|
||||
struct spdk_lvol;
|
||||
struct spdk_fragmap;
|
||||
|
||||
enum lvol_clear_method {
|
||||
LVOL_CLEAR_WITH_DEFAULT = BLOB_CLEAR_WITH_DEFAULT,
|
||||
@ -116,6 +117,16 @@ typedef void (*spdk_lvol_op_with_handle_complete)(void *cb_arg, struct spdk_lvol
|
||||
*/
|
||||
typedef void (*spdk_lvol_op_complete)(void *cb_arg, int lvolerrno);
|
||||
|
||||
/**
|
||||
* Callback definition for lvol operations with handle to fragmap
|
||||
*
|
||||
* @param cb_arg Custom arguments
|
||||
* @param fragmap Handle to fragmap or NULL when lvolerrno is set
|
||||
* @param lvolerrno Error
|
||||
*/
|
||||
typedef void (*spdk_lvol_op_with_fragmap_handle_complete)(void *cb_arg,
|
||||
struct spdk_fragmap *fragmap, int lvolerrno);
|
||||
|
||||
/**
|
||||
* Callback definition for spdk_lvol_iter_clones.
|
||||
*
|
||||
|
@ -308,6 +308,20 @@ spdk_memset_s(void *data, size_t data_size, int ch, size_t count)
|
||||
#endif
|
||||
}
|
||||
|
||||
/**
|
||||
* @brief Check if \b dividend is divisible by \b divisor
|
||||
*
|
||||
* @param dividend Dividend
|
||||
* @param divisor Divisor which is a power of 2
|
||||
* @return true
|
||||
* @return false
|
||||
*/
|
||||
static inline bool
|
||||
spdk_is_divisible_by(uint64_t dividend, uint64_t divisor)
|
||||
{
|
||||
return (dividend & (divisor - 1)) == 0;
|
||||
}
|
||||
|
||||
#ifdef __cplusplus
|
||||
}
|
||||
#endif
|
||||
|
@ -115,6 +115,30 @@ struct spdk_lvol {
|
||||
TAILQ_ENTRY(spdk_lvol) degraded_link;
|
||||
};
|
||||
|
||||
struct spdk_fragmap {
|
||||
struct spdk_bit_array *map;
|
||||
|
||||
uint64_t cluster_size;
|
||||
uint64_t block_size;
|
||||
uint64_t num_clusters;
|
||||
uint64_t num_allocated_clusters;
|
||||
};
|
||||
|
||||
struct spdk_fragmap_req {
|
||||
struct spdk_bdev *bdev;
|
||||
struct spdk_bdev_desc *bdev_desc;
|
||||
struct spdk_io_channel *bdev_io_channel;
|
||||
|
||||
struct spdk_fragmap fragmap;
|
||||
|
||||
uint64_t offset;
|
||||
uint64_t size;
|
||||
uint64_t current_offset;
|
||||
|
||||
spdk_lvol_op_with_fragmap_handle_complete cb_fn;
|
||||
void *cb_arg;
|
||||
};
|
||||
|
||||
struct lvol_store_bdev *vbdev_lvol_store_first(void);
|
||||
struct lvol_store_bdev *vbdev_lvol_store_next(struct lvol_store_bdev *prev);
|
||||
|
||||
|
@ -11,6 +11,7 @@
|
||||
|
||||
#include "spdk/likely.h"
|
||||
#include "spdk/util.h"
|
||||
#include "spdk/base64.h"
|
||||
|
||||
typedef uint64_t spdk_bit_array_word;
|
||||
#define SPDK_BIT_ARRAY_WORD_TZCNT(x) (__builtin_ctzll(x))
|
||||
@ -491,3 +492,49 @@ spdk_bit_pool_free_all_bits(struct spdk_bit_pool *pool)
|
||||
pool->lowest_free_bit = 0;
|
||||
pool->free_count = spdk_bit_array_capacity(pool->array);
|
||||
}
|
||||
|
||||
static int
|
||||
bits_to_bytes(const int bits)
|
||||
{
|
||||
return ((bits + 7) >> 3);
|
||||
}
|
||||
|
||||
char *
|
||||
spdk_bit_array_to_base64_string(const struct spdk_bit_array *array)
|
||||
{
|
||||
uint32_t bit_count = spdk_bit_array_capacity(array);
|
||||
size_t byte_count = bits_to_bytes(bit_count);
|
||||
void *bytes;
|
||||
char *encoded;
|
||||
size_t total_size;
|
||||
int rc;
|
||||
|
||||
bytes = calloc(byte_count, sizeof(char));
|
||||
if (bytes == NULL) {
|
||||
return NULL;
|
||||
}
|
||||
|
||||
for (uint32_t i = 0; i < bit_count; i++) {
|
||||
if (spdk_bit_array_get(array, i)) {
|
||||
// Set the bit in bytes's correct position
|
||||
((uint8_t *)bytes)[i / 8] |= 1 << (i % 8);
|
||||
}
|
||||
}
|
||||
|
||||
total_size = spdk_base64_get_encoded_strlen(byte_count) + 1;
|
||||
encoded = calloc(total_size, sizeof(char));
|
||||
if (encoded == NULL) {
|
||||
free(bytes);
|
||||
return NULL;
|
||||
}
|
||||
|
||||
rc = spdk_base64_encode(encoded, bytes, byte_count);
|
||||
if (rc != 0) {
|
||||
free(bytes);
|
||||
free(encoded);
|
||||
return NULL;
|
||||
}
|
||||
|
||||
free(bytes);
|
||||
return encoded;
|
||||
}
|
@ -11,6 +11,8 @@
|
||||
#include "spdk/string.h"
|
||||
#include "spdk/uuid.h"
|
||||
#include "spdk/blob.h"
|
||||
#include "spdk/bit_array.h"
|
||||
#include "spdk/base64.h"
|
||||
|
||||
#include "vbdev_lvol.h"
|
||||
|
||||
@ -2087,4 +2089,185 @@ vbdev_lvol_shallow_copy(struct spdk_lvol *lvol, const char *bdev_name,
|
||||
spdk_lvol_shallow_copy(lvol, ext_dev, _vbdev_lvol_shallow_copy_cb, req);
|
||||
}
|
||||
|
||||
static void seek_hole_done_cb(struct spdk_bdev_io *bdev_io, bool success, void *cb_arg);
|
||||
|
||||
static void
|
||||
get_fragmap_done(struct spdk_fragmap_req *req, int error_code, const char *error_msg)
|
||||
{
|
||||
req->cb_fn(req->cb_arg, &req->fragmap, error_code);
|
||||
|
||||
spdk_bit_array_free(&req->fragmap.map);
|
||||
spdk_put_io_channel(req->bdev_io_channel);
|
||||
spdk_bdev_close(req->bdev_desc);
|
||||
free(req);
|
||||
}
|
||||
|
||||
static void
|
||||
seek_data_done_cb(struct spdk_bdev_io *bdev_io, bool success, void *cb_arg)
|
||||
{
|
||||
struct spdk_fragmap_req *req = cb_arg;
|
||||
uint64_t next_data_offset_blocks;
|
||||
int rc;
|
||||
|
||||
next_data_offset_blocks = spdk_bdev_io_get_seek_offset(bdev_io);
|
||||
spdk_bdev_free_io(bdev_io);
|
||||
|
||||
req->current_offset = next_data_offset_blocks * req->fragmap.block_size;
|
||||
|
||||
if (next_data_offset_blocks == UINT64_MAX || req->current_offset >= req->offset + req->size) {
|
||||
get_fragmap_done(req, 0, NULL);
|
||||
return;
|
||||
}
|
||||
|
||||
rc = spdk_bdev_seek_hole(req->bdev_desc, req->bdev_io_channel,
|
||||
spdk_divide_round_up(req->current_offset, req->fragmap.block_size),
|
||||
seek_hole_done_cb, req);
|
||||
if (rc != 0) {
|
||||
get_fragmap_done(req, rc, "failed to seek hole");
|
||||
}
|
||||
}
|
||||
|
||||
static void
|
||||
seek_hole_done_cb(struct spdk_bdev_io *bdev_io, bool success, void *cb_arg)
|
||||
{
|
||||
struct spdk_fragmap_req *req = cb_arg;
|
||||
uint64_t next_offset;
|
||||
uint64_t start_cluster;
|
||||
uint64_t num_clusters;
|
||||
int rc;
|
||||
|
||||
next_offset = spdk_bdev_io_get_seek_offset(bdev_io) * req->fragmap.block_size;
|
||||
spdk_bdev_free_io(bdev_io);
|
||||
|
||||
next_offset = spdk_min(next_offset, req->offset + req->size);
|
||||
|
||||
start_cluster = spdk_divide_round_up(req->current_offset - req->offset, req->fragmap.cluster_size);
|
||||
num_clusters = spdk_divide_round_up(next_offset - req->current_offset, req->fragmap.cluster_size);
|
||||
|
||||
for (uint64_t i = 0; i < num_clusters; i++) {
|
||||
spdk_bit_array_set(req->fragmap.map, start_cluster + i);
|
||||
}
|
||||
req->fragmap.num_allocated_clusters += num_clusters;
|
||||
|
||||
req->current_offset = next_offset;
|
||||
|
||||
if (req->current_offset == req->offset + req->size) {
|
||||
get_fragmap_done(req, 0, NULL);
|
||||
return;
|
||||
}
|
||||
|
||||
rc = spdk_bdev_seek_data(req->bdev_desc, req->bdev_io_channel,
|
||||
spdk_divide_round_up(req->current_offset, req->fragmap.block_size),
|
||||
seek_data_done_cb, req);
|
||||
if (rc != 0) {
|
||||
get_fragmap_done(req, rc, "failed to seek data");
|
||||
}
|
||||
}
|
||||
|
||||
static void
|
||||
dummy_bdev_event_cb(enum spdk_bdev_event_type type, struct spdk_bdev *bdev, void *ctx)
|
||||
{
|
||||
}
|
||||
|
||||
void
|
||||
vbdev_lvol_get_fragmap(struct spdk_lvol *lvol, uint64_t offset, uint64_t size,
|
||||
spdk_lvol_op_with_fragmap_handle_complete cb_fn, void *cb_arg)
|
||||
{
|
||||
struct spdk_bdev_desc *desc;
|
||||
struct spdk_io_channel *channel;
|
||||
struct spdk_bit_array *fragmap;
|
||||
struct spdk_fragmap_req *req;
|
||||
uint64_t cluster_size, num_clusters, block_size, num_blocks, lvol_size, segment_size;
|
||||
int rc;
|
||||
|
||||
// Create a bitmap recording the allocated clusters
|
||||
cluster_size = spdk_bs_get_cluster_size(lvol->lvol_store->blobstore);
|
||||
block_size = spdk_bdev_get_block_size(lvol->bdev);
|
||||
num_blocks = spdk_bdev_get_num_blocks(lvol->bdev);
|
||||
lvol_size = num_blocks * block_size;
|
||||
|
||||
if (offset + size > lvol_size) {
|
||||
SPDK_ERRLOG("offset %lu and size %lu exceed lvol size %lu\n",
|
||||
offset, size, lvol_size);
|
||||
cb_fn(cb_arg, NULL, -EINVAL);
|
||||
return;
|
||||
}
|
||||
|
||||
segment_size = size;
|
||||
if (size == 0) {
|
||||
segment_size = lvol_size;
|
||||
}
|
||||
|
||||
if (!spdk_is_divisible_by(offset, cluster_size) ||
|
||||
!spdk_is_divisible_by(segment_size, cluster_size)) {
|
||||
SPDK_ERRLOG("offset %lu and size %lu must be a multiple of cluster size %lu\n",
|
||||
offset, segment_size, cluster_size);
|
||||
cb_fn(cb_arg, NULL, -EINVAL);
|
||||
return;
|
||||
}
|
||||
|
||||
num_clusters = spdk_divide_round_up(segment_size, cluster_size);
|
||||
fragmap = spdk_bit_array_create(num_clusters);
|
||||
if (fragmap == NULL) {
|
||||
SPDK_ERRLOG("failed to allocate fragmap with num_clusters %lu\n", num_clusters);
|
||||
cb_fn(cb_arg, NULL, -ENOMEM);
|
||||
return;
|
||||
}
|
||||
|
||||
// Construct a fragmap of the lvol
|
||||
rc = spdk_bdev_open_ext(lvol->bdev->name, false,
|
||||
dummy_bdev_event_cb, NULL, &desc);
|
||||
if (rc != 0) {
|
||||
spdk_bit_array_free(&fragmap);
|
||||
SPDK_ERRLOG("could not open bdev %s\n", lvol->bdev->name);
|
||||
cb_fn(cb_arg, NULL, rc);
|
||||
return;
|
||||
}
|
||||
|
||||
channel = spdk_bdev_get_io_channel(desc);
|
||||
if (channel == NULL) {
|
||||
spdk_bit_array_free(&fragmap);
|
||||
spdk_bdev_close(desc);
|
||||
SPDK_ERRLOG("could not allocate I/O channel.\n");
|
||||
cb_fn(cb_arg, NULL, -ENOMEM);
|
||||
return;
|
||||
}
|
||||
|
||||
req = calloc(1, sizeof(struct spdk_fragmap_req));
|
||||
if (req == NULL) {
|
||||
SPDK_ERRLOG("could not allocate fragmap_io\n");
|
||||
spdk_put_io_channel(channel);
|
||||
spdk_bdev_close(desc);
|
||||
spdk_bit_array_free(&fragmap);
|
||||
cb_fn(cb_arg, NULL, -ENOMEM);
|
||||
return;
|
||||
}
|
||||
|
||||
req->bdev = lvol->bdev;
|
||||
req->bdev_desc = desc;
|
||||
req->bdev_io_channel = channel;
|
||||
req->offset = offset;
|
||||
req->size = segment_size;
|
||||
req->current_offset = offset;
|
||||
req->cb_fn = cb_fn;
|
||||
req->cb_arg = cb_arg;
|
||||
req->fragmap.map = fragmap;
|
||||
req->fragmap.num_clusters = num_clusters;
|
||||
req->fragmap.block_size = block_size;
|
||||
req->fragmap.cluster_size = cluster_size;
|
||||
req->fragmap.num_allocated_clusters = 0;
|
||||
|
||||
rc = spdk_bdev_seek_data(desc, channel,
|
||||
spdk_divide_round_up(offset, block_size),
|
||||
seek_data_done_cb, req);
|
||||
if (rc != 0) {
|
||||
SPDK_ERRLOG("failed to seek data\n");
|
||||
spdk_put_io_channel(channel);
|
||||
spdk_bdev_close(desc);
|
||||
spdk_bit_array_free(&fragmap);
|
||||
free(req);
|
||||
cb_fn(cb_arg, NULL, rc);
|
||||
}
|
||||
}
|
||||
|
||||
SPDK_LOG_REGISTER_COMPONENT(vbdev_lvol)
|
||||
|
@ -136,4 +136,17 @@ int vbdev_lvol_esnap_dev_create(void *bs_ctx, void *blob_ctx, struct spdk_blob *
|
||||
void vbdev_lvol_shallow_copy(struct spdk_lvol *lvol, const char *bdev_name,
|
||||
spdk_lvol_op_complete cb_fn, void *cb_arg);
|
||||
|
||||
/**
|
||||
* @brief Get a fragmap for a specific segment of a logical volume using the provided offset and size
|
||||
*
|
||||
* @param lvol Handle to lvol
|
||||
* @param offset Offset in bytes of the specific segment of the logical volume
|
||||
* @param size Size in bytes of the specific segment of the logical volume
|
||||
* @param cb_fn Completion callback
|
||||
* @param cb_arg Completion callback custom arguments
|
||||
*/
|
||||
void
|
||||
vbdev_lvol_get_fragmap(struct spdk_lvol *lvol, uint64_t offset, uint64_t size,
|
||||
spdk_lvol_op_with_fragmap_handle_complete cb_fn, void *cb_arg);
|
||||
|
||||
#endif /* SPDK_VBDEV_LVOL_H */
|
||||
|
@ -10,6 +10,8 @@
|
||||
#include "vbdev_lvol.h"
|
||||
#include "spdk/string.h"
|
||||
#include "spdk/log.h"
|
||||
#include "spdk/bdev_module.h"
|
||||
#include "spdk/bit_array.h"
|
||||
|
||||
SPDK_LOG_REGISTER_COMPONENT(lvol_rpc)
|
||||
|
||||
@ -1505,3 +1507,96 @@ cleanup:
|
||||
|
||||
SPDK_RPC_REGISTER("bdev_lvol_shallow_copy_status", rpc_bdev_lvol_shallow_copy_status,
|
||||
SPDK_RPC_RUNTIME)
|
||||
|
||||
struct rpc_bdev_lvol_get_fragmap {
|
||||
char *name;
|
||||
uint64_t offset;
|
||||
uint64_t size;
|
||||
};
|
||||
|
||||
static void
|
||||
free_rpc_bdev_lvol_get_fragmap(struct rpc_bdev_lvol_get_fragmap *r)
|
||||
{
|
||||
free(r->name);
|
||||
}
|
||||
|
||||
static const struct spdk_json_object_decoder rpc_bdev_lvol_get_fragmap_decoders[] = {
|
||||
{"name", offsetof(struct rpc_bdev_lvol_get_fragmap, name), spdk_json_decode_string, true},
|
||||
{"offset", offsetof(struct rpc_bdev_lvol_get_fragmap, offset), spdk_json_decode_uint64, true},
|
||||
{"size", offsetof(struct rpc_bdev_lvol_get_fragmap, size), spdk_json_decode_uint64, true},
|
||||
};
|
||||
|
||||
static void
|
||||
rpc_bdev_lvol_get_fragmap_cb(void *cb_arg, struct spdk_fragmap *fragmap, int lvolerrno)
|
||||
{
|
||||
struct spdk_json_write_ctx *w;
|
||||
struct spdk_jsonrpc_request *request = cb_arg;
|
||||
char *encoded;
|
||||
|
||||
if (lvolerrno != 0) {
|
||||
goto invalid;
|
||||
}
|
||||
|
||||
encoded = spdk_bit_array_to_base64_string(fragmap->map);
|
||||
if (encoded == NULL) {
|
||||
SPDK_ERRLOG("Failed to encode fragmap to base64 string\n");
|
||||
lvolerrno = -EINVAL;
|
||||
goto invalid;
|
||||
}
|
||||
|
||||
w = spdk_jsonrpc_begin_result(request);
|
||||
spdk_json_write_object_begin(w);
|
||||
|
||||
spdk_json_write_named_uint64(w, "cluster_size", fragmap->cluster_size);
|
||||
spdk_json_write_named_uint64(w, "num_clusters", fragmap->num_clusters);
|
||||
spdk_json_write_named_uint64(w, "num_allocated_clusters", fragmap->num_allocated_clusters);
|
||||
spdk_json_write_named_string(w, "fragmap", encoded);
|
||||
|
||||
spdk_json_write_object_end(w);
|
||||
spdk_jsonrpc_end_result(request, w);
|
||||
|
||||
free(encoded);
|
||||
return;
|
||||
|
||||
invalid:
|
||||
spdk_jsonrpc_send_error_response(request, SPDK_JSONRPC_ERROR_INVALID_PARAMS,
|
||||
spdk_strerror(-lvolerrno));
|
||||
}
|
||||
|
||||
static void
|
||||
rpc_bdev_lvol_get_fragmap(struct spdk_jsonrpc_request *request, const struct spdk_json_val *params)
|
||||
{
|
||||
struct rpc_bdev_lvol_get_fragmap req = {};
|
||||
struct spdk_bdev *bdev;
|
||||
struct spdk_lvol *lvol;
|
||||
|
||||
if (spdk_json_decode_object(params, rpc_bdev_lvol_get_fragmap_decoders,
|
||||
SPDK_COUNTOF(rpc_bdev_lvol_get_fragmap_decoders),
|
||||
&req)) {
|
||||
SPDK_ERRLOG("spdk_json_decode_object failed\n");
|
||||
spdk_jsonrpc_send_error_response(request, SPDK_JSONRPC_ERROR_INTERNAL_ERROR,
|
||||
"spdk_json_decode_object failed");
|
||||
goto cleanup;
|
||||
}
|
||||
|
||||
bdev = spdk_bdev_get_by_name(req.name);
|
||||
if (bdev == NULL) {
|
||||
SPDK_ERRLOG("bdev '%s' does not exist\n", req.name);
|
||||
spdk_jsonrpc_send_error_response(request, -ENODEV, spdk_strerror(ENODEV));
|
||||
goto cleanup;
|
||||
}
|
||||
|
||||
lvol = vbdev_lvol_get_from_bdev(bdev);
|
||||
if (lvol == NULL) {
|
||||
SPDK_ERRLOG("lvol does not exist\n");
|
||||
spdk_jsonrpc_send_error_response(request, -ENODEV, spdk_strerror(ENODEV));
|
||||
goto cleanup;
|
||||
}
|
||||
|
||||
vbdev_lvol_get_fragmap(lvol, req.offset, req.size, rpc_bdev_lvol_get_fragmap_cb, request);
|
||||
|
||||
cleanup:
|
||||
free_rpc_bdev_lvol_get_fragmap(&req);
|
||||
}
|
||||
|
||||
SPDK_RPC_REGISTER("bdev_lvol_get_fragmap", rpc_bdev_lvol_get_fragmap, SPDK_RPC_RUNTIME)
|
||||
|
@ -249,6 +249,25 @@ def bdev_lvol_shallow_copy_status(client, src_lvol_name):
|
||||
return client.call('bdev_lvol_shallow_copy_status', params)
|
||||
|
||||
|
||||
def bdev_lvol_get_fragmap(client, name, offset=0, size=0):
|
||||
"""Get a fragmap for a specific segment of a logical volume using the provided offset and size
|
||||
|
||||
Args:
|
||||
name: lvol bdev name
|
||||
offset: offset in bytes of the specific segment of the logical volume
|
||||
size: size in bytes of the specific segment of the logical volume
|
||||
"""
|
||||
params = {
|
||||
'name': name,
|
||||
}
|
||||
if offset:
|
||||
params['offset'] = offset
|
||||
if size:
|
||||
params['size'] = size
|
||||
|
||||
return client.call('bdev_lvol_get_fragmap', params)
|
||||
|
||||
|
||||
def bdev_lvol_delete_lvstore(client, uuid=None, lvs_name=None):
|
||||
"""Destroy a logical volume store.
|
||||
|
||||
|
@ -2059,6 +2059,17 @@ Format: 'user:u1 secret:s1 muser:mu1 msecret:ms1,user:u2 secret:s2 muser:mu2 mse
|
||||
p.add_argument('src_lvol_name', help='source lvol name')
|
||||
p.set_defaults(func=bdev_lvol_shallow_copy_status)
|
||||
|
||||
def bdev_lvol_get_fragmap(args):
|
||||
print_json(rpc.lvol.bdev_lvol_get_fragmap(args.client,
|
||||
name=args.name,
|
||||
offset=args.offset,
|
||||
size=args.size))
|
||||
p = subparsers.add_parser('bdev_lvol_get_fragmap', help='Get a fragmap for a specific segment of a logical volume using the provided offset and size.')
|
||||
p.add_argument('name', help='lvol bdev name')
|
||||
p.add_argument('--offset', help='offset in bytes of the specific segment of the logical volume', type=int, required=False)
|
||||
p.add_argument('--size', help='size in bytes of the specific segment of the logical volume', type=int, required=False)
|
||||
p.set_defaults(func=bdev_lvol_get_fragmap)
|
||||
|
||||
def bdev_lvol_delete_lvstore(args):
|
||||
rpc.lvol.bdev_lvol_delete_lvstore(args.client,
|
||||
uuid=args.uuid,
|
||||
|
52
test/lvol/fragmap.sh
Executable file
52
test/lvol/fragmap.sh
Executable file
@ -0,0 +1,52 @@
|
||||
#!/usr/bin/env bash
|
||||
# SPDX-License-Identifier: BSD-3-Clause
|
||||
# Copyright (C) 2023 SUSE LLC.
|
||||
# All rights reserved.
|
||||
#
|
||||
testdir=$(readlink -f $(dirname $0))
|
||||
rootdir=$(readlink -f $testdir/../..)
|
||||
source $rootdir/test/common/autotest_common.sh
|
||||
source $rootdir/test/lvol/common.sh
|
||||
source $rootdir/test/bdev/nbd_common.sh
|
||||
|
||||
function test_fragmap() {
|
||||
# Create lvs
|
||||
bs_malloc_name=$(rpc_cmd bdev_malloc_create 20 $MALLOC_BS)
|
||||
lvs_uuid=$(rpc_cmd bdev_lvol_create_lvstore "$bs_malloc_name" lvs_test)
|
||||
|
||||
# Create lvol with 4 cluster
|
||||
lvol_size=$((LVS_DEFAULT_CLUSTER_SIZE_MB * 4))
|
||||
lvol_uuid=$(rpc_cmd bdev_lvol_create -u "$lvs_uuid" lvol_test "$lvol_size" -t)
|
||||
|
||||
# Fill second and fourth cluster of lvol
|
||||
nbd_start_disks "$DEFAULT_RPC_ADDR" "$lvol_uuid" /dev/nbd0
|
||||
dd if=/dev/urandom of=/dev/nbd0 oflag=direct bs="$LVS_DEFAULT_CLUSTER_SIZE" count=1 seek=1
|
||||
dd if=/dev/urandom of=/dev/nbd0 oflag=direct bs="$LVS_DEFAULT_CLUSTER_SIZE" count=1 seek=3
|
||||
nbd_stop_disks "$DEFAULT_RPC_ADDR" /dev/nbd0
|
||||
|
||||
# Create snapshots of lvol bdev
|
||||
snapshot_uuid=$(rpc_cmd bdev_lvol_snapshot lvs_test/lvol_test lvol_snapshot)
|
||||
|
||||
# Fill first and third cluster of lvol
|
||||
nbd_start_disks "$DEFAULT_RPC_ADDR" "$lvol_uuid" /dev/nbd0
|
||||
dd if=/dev/urandom of=/dev/nbd0 oflag=direct bs="$LVS_DEFAULT_CLUSTER_SIZE" count=1
|
||||
dd if=/dev/urandom of=/dev/nbd0 oflag=direct bs="$LVS_DEFAULT_CLUSTER_SIZE" count=1 seek=2
|
||||
nbd_stop_disks "$DEFAULT_RPC_ADDR" /dev/nbd0
|
||||
|
||||
|
||||
|
||||
# Stop nbd devices
|
||||
nbd_stop_disks "$DEFAULT_RPC_ADDR" /dev/nbd1
|
||||
nbd_stop_disks "$DEFAULT_RPC_ADDR" /dev/nbd0
|
||||
}
|
||||
|
||||
$SPDK_BIN_DIR/spdk_tgt &
|
||||
spdk_pid=$!
|
||||
trap 'killprocess "$spdk_pid"; exit 1' SIGINT SIGTERM EXIT
|
||||
waitforlisten $spdk_pid
|
||||
modprobe nbd
|
||||
|
||||
run_test "test_shallow_copy_compare" test_shallow_copy_compare
|
||||
|
||||
trap - SIGINT SIGTERM EXIT
|
||||
killprocess $spdk_pid
|
Loading…
Reference in New Issue
Block a user