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; 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) {

View File

@ -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);

View File

@ -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);

View File

@ -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)

View File

@ -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):