bdev/aio: implement read-only
Support Aio bdev 'readonly' option in RPC call. The read-only flag can be dumped from the bdev info. Any writes on a read-only aio bdev will be fail. Signed-off-by: Yuhua <yuhua@smartx.com> Change-Id: I939f72479f8953a3678a8df3083ecce0f96844fb Reviewed-on: https://review.spdk.io/gerrit/c/spdk/spdk/+/14955 Reviewed-by: GangCao <gang.cao@intel.com> Reviewed-by: Changpeng Liu <changpeng.liu@intel.com> Reviewed-by: Aleksey Marchuk <alexeymar@nvidia.com> Tested-by: SPDK CI Jenkins <sys_sgci@intel.com> Community-CI: Mellanox Build Bot
This commit is contained in:
parent
0954302091
commit
4c6a2e3daa
@ -55,6 +55,7 @@ struct file_disk {
|
|||||||
int fd;
|
int fd;
|
||||||
TAILQ_ENTRY(file_disk) link;
|
TAILQ_ENTRY(file_disk) link;
|
||||||
bool block_size_override;
|
bool block_size_override;
|
||||||
|
bool readonly;
|
||||||
};
|
};
|
||||||
|
|
||||||
/* For user space reaping of completions */
|
/* For user space reaping of completions */
|
||||||
@ -99,11 +100,12 @@ static int
|
|||||||
bdev_aio_open(struct file_disk *disk)
|
bdev_aio_open(struct file_disk *disk)
|
||||||
{
|
{
|
||||||
int fd;
|
int fd;
|
||||||
|
int io_flag = disk->readonly ? O_RDONLY : O_RDWR;
|
||||||
|
|
||||||
fd = open(disk->filename, O_RDWR | O_DIRECT);
|
fd = open(disk->filename, io_flag | O_DIRECT);
|
||||||
if (fd < 0) {
|
if (fd < 0) {
|
||||||
/* Try without O_DIRECT for non-disk files */
|
/* Try without O_DIRECT for non-disk files */
|
||||||
fd = open(disk->filename, O_RDWR);
|
fd = open(disk->filename, io_flag);
|
||||||
if (fd < 0) {
|
if (fd < 0) {
|
||||||
SPDK_ERRLOG("open() failed (file:%s), errno %d: %s\n",
|
SPDK_ERRLOG("open() failed (file:%s), errno %d: %s\n",
|
||||||
disk->filename, errno, spdk_strerror(errno));
|
disk->filename, errno, spdk_strerror(errno));
|
||||||
@ -227,7 +229,6 @@ bdev_aio_destruct_cb(void *io_device)
|
|||||||
if (rc < 0) {
|
if (rc < 0) {
|
||||||
SPDK_ERRLOG("bdev_aio_close() failed\n");
|
SPDK_ERRLOG("bdev_aio_close() failed\n");
|
||||||
}
|
}
|
||||||
|
|
||||||
aio_free_disk(fdisk);
|
aio_free_disk(fdisk);
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -474,15 +475,25 @@ bdev_aio_get_buf_cb(struct spdk_io_channel *ch, struct spdk_bdev_io *bdev_io,
|
|||||||
static int
|
static int
|
||||||
_bdev_aio_submit_request(struct spdk_io_channel *ch, struct spdk_bdev_io *bdev_io)
|
_bdev_aio_submit_request(struct spdk_io_channel *ch, struct spdk_bdev_io *bdev_io)
|
||||||
{
|
{
|
||||||
|
struct file_disk *fdisk = (struct file_disk *)bdev_io->bdev->ctxt;
|
||||||
|
|
||||||
switch (bdev_io->type) {
|
switch (bdev_io->type) {
|
||||||
/* Read and write operations must be performed on buffers aligned to
|
/* Read and write operations must be performed on buffers aligned to
|
||||||
* bdev->required_alignment. If user specified unaligned buffers,
|
* bdev->required_alignment. If user specified unaligned buffers,
|
||||||
* get the aligned buffer from the pool by calling spdk_bdev_io_get_buf. */
|
* get the aligned buffer from the pool by calling spdk_bdev_io_get_buf. */
|
||||||
case SPDK_BDEV_IO_TYPE_READ:
|
case SPDK_BDEV_IO_TYPE_READ:
|
||||||
case SPDK_BDEV_IO_TYPE_WRITE:
|
|
||||||
spdk_bdev_io_get_buf(bdev_io, bdev_aio_get_buf_cb,
|
spdk_bdev_io_get_buf(bdev_io, bdev_aio_get_buf_cb,
|
||||||
bdev_io->u.bdev.num_blocks * bdev_io->bdev->blocklen);
|
bdev_io->u.bdev.num_blocks * bdev_io->bdev->blocklen);
|
||||||
return 0;
|
return 0;
|
||||||
|
case SPDK_BDEV_IO_TYPE_WRITE:
|
||||||
|
if (fdisk->readonly) {
|
||||||
|
spdk_bdev_io_complete(bdev_io, SPDK_BDEV_IO_STATUS_FAILED);
|
||||||
|
} else {
|
||||||
|
spdk_bdev_io_get_buf(bdev_io, bdev_aio_get_buf_cb,
|
||||||
|
bdev_io->u.bdev.num_blocks * bdev_io->bdev->blocklen);
|
||||||
|
}
|
||||||
|
return 0;
|
||||||
|
|
||||||
case SPDK_BDEV_IO_TYPE_FLUSH:
|
case SPDK_BDEV_IO_TYPE_FLUSH:
|
||||||
bdev_aio_flush((struct file_disk *)bdev_io->bdev->ctxt,
|
bdev_aio_flush((struct file_disk *)bdev_io->bdev->ctxt,
|
||||||
(struct bdev_aio_task *)bdev_io->driver_ctx);
|
(struct bdev_aio_task *)bdev_io->driver_ctx);
|
||||||
@ -567,6 +578,10 @@ bdev_aio_dump_info_json(void *ctx, struct spdk_json_write_ctx *w)
|
|||||||
|
|
||||||
spdk_json_write_named_string(w, "filename", fdisk->filename);
|
spdk_json_write_named_string(w, "filename", fdisk->filename);
|
||||||
|
|
||||||
|
spdk_json_write_named_bool(w, "block_size_override", fdisk->block_size_override);
|
||||||
|
|
||||||
|
spdk_json_write_named_bool(w, "readonly", fdisk->readonly);
|
||||||
|
|
||||||
spdk_json_write_object_end(w);
|
spdk_json_write_object_end(w);
|
||||||
|
|
||||||
return 0;
|
return 0;
|
||||||
@ -587,6 +602,7 @@ bdev_aio_write_json_config(struct spdk_bdev *bdev, struct spdk_json_write_ctx *w
|
|||||||
spdk_json_write_named_uint32(w, "block_size", bdev->blocklen);
|
spdk_json_write_named_uint32(w, "block_size", bdev->blocklen);
|
||||||
}
|
}
|
||||||
spdk_json_write_named_string(w, "filename", fdisk->filename);
|
spdk_json_write_named_string(w, "filename", fdisk->filename);
|
||||||
|
spdk_json_write_named_bool(w, "readonly", fdisk->readonly);
|
||||||
spdk_json_write_object_end(w);
|
spdk_json_write_object_end(w);
|
||||||
|
|
||||||
spdk_json_write_object_end(w);
|
spdk_json_write_object_end(w);
|
||||||
@ -685,7 +701,7 @@ bdev_aio_group_destroy_cb(void *io_device, void *ctx_buf)
|
|||||||
}
|
}
|
||||||
|
|
||||||
int
|
int
|
||||||
create_aio_bdev(const char *name, const char *filename, uint32_t block_size)
|
create_aio_bdev(const char *name, const char *filename, uint32_t block_size, bool readonly)
|
||||||
{
|
{
|
||||||
struct file_disk *fdisk;
|
struct file_disk *fdisk;
|
||||||
uint32_t detected_block_size;
|
uint32_t detected_block_size;
|
||||||
@ -697,6 +713,7 @@ create_aio_bdev(const char *name, const char *filename, uint32_t block_size)
|
|||||||
SPDK_ERRLOG("Unable to allocate enough memory for aio backend\n");
|
SPDK_ERRLOG("Unable to allocate enough memory for aio backend\n");
|
||||||
return -ENOMEM;
|
return -ENOMEM;
|
||||||
}
|
}
|
||||||
|
fdisk->readonly = readonly;
|
||||||
|
|
||||||
fdisk->filename = strdup(filename);
|
fdisk->filename = strdup(filename);
|
||||||
if (!fdisk->filename) {
|
if (!fdisk->filename) {
|
||||||
|
@ -11,7 +11,7 @@
|
|||||||
|
|
||||||
typedef void (*delete_aio_bdev_complete)(void *cb_arg, int bdeverrno);
|
typedef void (*delete_aio_bdev_complete)(void *cb_arg, int bdeverrno);
|
||||||
|
|
||||||
int create_aio_bdev(const char *name, const char *filename, uint32_t block_size);
|
int create_aio_bdev(const char *name, const char *filename, uint32_t block_size, bool readonly);
|
||||||
|
|
||||||
int bdev_aio_rescan(const char *name);
|
int bdev_aio_rescan(const char *name);
|
||||||
void bdev_aio_delete(const char *name, delete_aio_bdev_complete cb_fn, void *cb_arg);
|
void bdev_aio_delete(const char *name, delete_aio_bdev_complete cb_fn, void *cb_arg);
|
||||||
|
@ -13,6 +13,7 @@ struct rpc_construct_aio {
|
|||||||
char *name;
|
char *name;
|
||||||
char *filename;
|
char *filename;
|
||||||
uint32_t block_size;
|
uint32_t block_size;
|
||||||
|
bool readonly;
|
||||||
};
|
};
|
||||||
|
|
||||||
struct rpc_construct_aio_ctx {
|
struct rpc_construct_aio_ctx {
|
||||||
@ -32,6 +33,7 @@ static const struct spdk_json_object_decoder rpc_construct_aio_decoders[] = {
|
|||||||
{"name", offsetof(struct rpc_construct_aio, name), spdk_json_decode_string},
|
{"name", offsetof(struct rpc_construct_aio, name), spdk_json_decode_string},
|
||||||
{"filename", offsetof(struct rpc_construct_aio, filename), spdk_json_decode_string},
|
{"filename", offsetof(struct rpc_construct_aio, filename), spdk_json_decode_string},
|
||||||
{"block_size", offsetof(struct rpc_construct_aio, block_size), spdk_json_decode_uint32, true},
|
{"block_size", offsetof(struct rpc_construct_aio, block_size), spdk_json_decode_uint32, true},
|
||||||
|
{"readonly", offsetof(struct rpc_construct_aio, readonly), spdk_json_decode_bool, true},
|
||||||
};
|
};
|
||||||
|
|
||||||
static void
|
static void
|
||||||
@ -71,7 +73,7 @@ rpc_bdev_aio_create(struct spdk_jsonrpc_request *request,
|
|||||||
}
|
}
|
||||||
|
|
||||||
ctx->request = request;
|
ctx->request = request;
|
||||||
rc = create_aio_bdev(ctx->req.name, ctx->req.filename, ctx->req.block_size);
|
rc = create_aio_bdev(ctx->req.name, ctx->req.filename, ctx->req.block_size, ctx->req.readonly);
|
||||||
if (rc) {
|
if (rc) {
|
||||||
spdk_jsonrpc_send_error_response(request, rc, spdk_strerror(-rc));
|
spdk_jsonrpc_send_error_response(request, rc, spdk_strerror(-rc));
|
||||||
free_rpc_construct_aio(ctx);
|
free_rpc_construct_aio(ctx);
|
||||||
|
@ -370,13 +370,14 @@ def bdev_raid_delete(client, name):
|
|||||||
return client.call('bdev_raid_delete', params)
|
return client.call('bdev_raid_delete', params)
|
||||||
|
|
||||||
|
|
||||||
def bdev_aio_create(client, filename, name, block_size=None):
|
def bdev_aio_create(client, filename, name, block_size=None, readonly=False):
|
||||||
"""Construct a Linux AIO block device.
|
"""Construct a Linux AIO block device.
|
||||||
|
|
||||||
Args:
|
Args:
|
||||||
filename: path to device or file (ex: /dev/sda)
|
filename: path to device or file (ex: /dev/sda)
|
||||||
name: name of block device
|
name: name of block device
|
||||||
block_size: block size of device (optional; autodetected if omitted)
|
block_size: block size of device (optional; autodetected if omitted)
|
||||||
|
readonly: set aio bdev as read-only
|
||||||
|
|
||||||
Returns:
|
Returns:
|
||||||
Name of created block device.
|
Name of created block device.
|
||||||
@ -387,6 +388,9 @@ def bdev_aio_create(client, filename, name, block_size=None):
|
|||||||
if block_size:
|
if block_size:
|
||||||
params['block_size'] = block_size
|
params['block_size'] = block_size
|
||||||
|
|
||||||
|
if readonly:
|
||||||
|
params['readonly'] = readonly
|
||||||
|
|
||||||
return client.call('bdev_aio_create', params)
|
return client.call('bdev_aio_create', params)
|
||||||
|
|
||||||
|
|
||||||
|
@ -424,12 +424,14 @@ if __name__ == "__main__":
|
|||||||
print_json(rpc.bdev.bdev_aio_create(args.client,
|
print_json(rpc.bdev.bdev_aio_create(args.client,
|
||||||
filename=args.filename,
|
filename=args.filename,
|
||||||
name=args.name,
|
name=args.name,
|
||||||
block_size=args.block_size))
|
block_size=args.block_size,
|
||||||
|
readonly=args.readonly))
|
||||||
|
|
||||||
p = subparsers.add_parser('bdev_aio_create', help='Add a bdev with aio backend')
|
p = subparsers.add_parser('bdev_aio_create', help='Add a bdev with aio backend')
|
||||||
p.add_argument('filename', help='Path to device or file (ex: /dev/sda)')
|
p.add_argument('filename', help='Path to device or file (ex: /dev/sda)')
|
||||||
p.add_argument('name', help='Block device name')
|
p.add_argument('name', help='Block device name')
|
||||||
p.add_argument('block_size', help='Block size for this bdev', type=int, nargs='?')
|
p.add_argument('block_size', help='Block size for this bdev', type=int, nargs='?')
|
||||||
|
p.add_argument("-r", "--readonly", action='store_true', help='Set this bdev as read-only')
|
||||||
p.set_defaults(func=bdev_aio_create)
|
p.set_defaults(func=bdev_aio_create)
|
||||||
|
|
||||||
def bdev_aio_rescan(args):
|
def bdev_aio_rescan(args):
|
||||||
|
Loading…
Reference in New Issue
Block a user