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:
Yuhua 2022-10-11 18:15:36 +08:00 committed by Tomasz Zawadzki
parent 0954302091
commit 4c6a2e3daa
5 changed files with 34 additions and 9 deletions

View File

@ -55,6 +55,7 @@ struct file_disk {
int fd;
TAILQ_ENTRY(file_disk) link;
bool block_size_override;
bool readonly;
};
/* For user space reaping of completions */
@ -99,11 +100,12 @@ static int
bdev_aio_open(struct file_disk *disk)
{
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) {
/* Try without O_DIRECT for non-disk files */
fd = open(disk->filename, O_RDWR);
fd = open(disk->filename, io_flag);
if (fd < 0) {
SPDK_ERRLOG("open() failed (file:%s), errno %d: %s\n",
disk->filename, errno, spdk_strerror(errno));
@ -227,7 +229,6 @@ bdev_aio_destruct_cb(void *io_device)
if (rc < 0) {
SPDK_ERRLOG("bdev_aio_close() failed\n");
}
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
_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) {
/* Read and write operations must be performed on buffers aligned to
* bdev->required_alignment. If user specified unaligned buffers,
* 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_WRITE:
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_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:
bdev_aio_flush((struct file_disk *)bdev_io->bdev->ctxt,
(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_bool(w, "block_size_override", fdisk->block_size_override);
spdk_json_write_named_bool(w, "readonly", fdisk->readonly);
spdk_json_write_object_end(w);
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_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);
@ -685,7 +701,7 @@ bdev_aio_group_destroy_cb(void *io_device, void *ctx_buf)
}
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;
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");
return -ENOMEM;
}
fdisk->readonly = readonly;
fdisk->filename = strdup(filename);
if (!fdisk->filename) {

View File

@ -11,7 +11,7 @@
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);
void bdev_aio_delete(const char *name, delete_aio_bdev_complete cb_fn, void *cb_arg);

View File

@ -13,6 +13,7 @@ struct rpc_construct_aio {
char *name;
char *filename;
uint32_t block_size;
bool readonly;
};
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},
{"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},
{"readonly", offsetof(struct rpc_construct_aio, readonly), spdk_json_decode_bool, true},
};
static void
@ -71,7 +73,7 @@ rpc_bdev_aio_create(struct spdk_jsonrpc_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) {
spdk_jsonrpc_send_error_response(request, rc, spdk_strerror(-rc));
free_rpc_construct_aio(ctx);

View File

@ -370,13 +370,14 @@ def bdev_raid_delete(client, name):
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.
Args:
filename: path to device or file (ex: /dev/sda)
name: name of block device
block_size: block size of device (optional; autodetected if omitted)
readonly: set aio bdev as read-only
Returns:
Name of created block device.
@ -387,6 +388,9 @@ def bdev_aio_create(client, filename, name, block_size=None):
if block_size:
params['block_size'] = block_size
if readonly:
params['readonly'] = readonly
return client.call('bdev_aio_create', params)

View File

@ -424,12 +424,14 @@ if __name__ == "__main__":
print_json(rpc.bdev.bdev_aio_create(args.client,
filename=args.filename,
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.add_argument('filename', help='Path to device or file (ex: /dev/sda)')
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("-r", "--readonly", action='store_true', help='Set this bdev as read-only')
p.set_defaults(func=bdev_aio_create)
def bdev_aio_rescan(args):