diff --git a/module/bdev/aio/bdev_aio.c b/module/bdev/aio/bdev_aio.c index 52bdbb373..382623460 100644 --- a/module/bdev/aio/bdev_aio.c +++ b/module/bdev/aio/bdev_aio.c @@ -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) { diff --git a/module/bdev/aio/bdev_aio.h b/module/bdev/aio/bdev_aio.h index deedc922a..232ffc150 100644 --- a/module/bdev/aio/bdev_aio.h +++ b/module/bdev/aio/bdev_aio.h @@ -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); diff --git a/module/bdev/aio/bdev_aio_rpc.c b/module/bdev/aio/bdev_aio_rpc.c index 973924e93..2af791768 100644 --- a/module/bdev/aio/bdev_aio_rpc.c +++ b/module/bdev/aio/bdev_aio_rpc.c @@ -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); diff --git a/python/spdk/rpc/bdev.py b/python/spdk/rpc/bdev.py index 5fea40c01..b1e52b886 100644 --- a/python/spdk/rpc/bdev.py +++ b/python/spdk/rpc/bdev.py @@ -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) diff --git a/scripts/rpc.py b/scripts/rpc.py index 75d0e9e8c..3cf1da14f 100755 --- a/scripts/rpc.py +++ b/scripts/rpc.py @@ -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):