From: hch@lst.de (Christoph Hellwig)
Subject: [PATCH V3] nvmet: add simple file backed ns support
Date: Wed, 9 May 2018 07:53:56 +0200 [thread overview]
Message-ID: <20180509055356.GA18926@lst.de> (raw)
In-Reply-To: <20180508053829.406-1-chaitanya.kulkarni@wdc.com>
Hi Chaitanya,
this looks great. A couple mostly cosmetic comments below:
> + /* for file backed ns just return */
> + if (!ns->bdev)
> + goto out;
>
> @@ -71,6 +77,9 @@ static u16 nvmet_get_smart_log_all(struct nvmet_req *req,
>
> rcu_read_lock();
> list_for_each_entry_rcu(ns, &ctrl->subsys->namespaces, dev_link) {
> + /* for file backed ns just return */
Maybe expand the comment a bit that we don't have the data and this
is the best we can do?
> +static int nvmet_ns_enable_blk(struct nvmet_ns *ns)
s/blk/blkdev/
> +{
> + int blk_flags = FMODE_READ | FMODE_WRITE;
> +
> + ns->bdev = blkdev_get_by_path(ns->device_path, blk_flags, NULL);
I'd say just kill the blk_flags variable and pass the flags directly
to blkdev_get_by_path.
> + if (IS_ERR(ns->bdev)) {
> + pr_err("failed to open block device %s: (%ld)\n",
> + ns->device_path, PTR_ERR(ns->bdev));
This is going to be printed everytime we open a file, isn't it?
Maybe skip the error print for the error code we get in the case
where the path actually is a file.
> + ns->bdev = NULL;
> + return -1;
This should be
return PTR_ERR(ns->bdev);
> + }
> + ns->size = i_size_read(ns->bdev->bd_inode);
> + ns->blksize_shift =
> + blksize_bits(bdev_logical_block_size(ns->bdev));
This fits into a single line:
ns->blksize_shift = blksize_bits(bdev_logical_block_size(ns->bdev));
> +static int nvmet_ns_enable_file(struct nvmet_ns *ns)
> +{
> + int ret;
> + int flags = O_RDWR | O_LARGEFILE | O_DIRECT;
> + struct kstat stat;
> +
> + ns->file = filp_open(ns->device_path, flags, 0);
No need for the flags argument either.
> + if (!ns->file || IS_ERR(ns->file)) {
filp_open never returns NULL, so you just need the IS_ERR check.
> + pr_err("failed to open file %s: (%ld)\n",
> + ns->device_path, PTR_ERR(ns->bdev));
> + ns->file = NULL;
> + return -1;
This should be:
return PTR_ERR(ns->bdev);
> + }
> +
> + ret = vfs_getattr(&ns->file->f_path,
> + &stat, STATX_INO, AT_STATX_SYNC_AS_STAT);
I think we want AT_STATX_FORCE_SYNC here, and STATX_INO is the wrong
value to ask for (but no one really looks at ir yet, so for now it
happens to work just fine).
So this should be:
ret = vfs_getattr(&ns->file->f_path, &stat, STATX_SIZE,
AT_STATX_FORCE_SYNC);
> + if (ret)
> + goto err;
> +
> + ns->size = stat.size;
> + ns->blksize_shift = file_inode(ns->file)->i_blkbits;
> +
> + return ret;
> +err:
> + fput(ns->file);
> + ns->size = ns->blksize_shift = 0;
Please use a separate line for each assignment.
> + ns->file = NULL;
> +
> + return ret;
No need for the blank line here.
> +static int nvmet_ns_dev_enable(struct nvmet_ns *ns)
> +{
> + int ret = 0;
> +
> + ret = nvmet_ns_enable_blk(ns);
> + if (ret)
> + ret = nvmet_ns_enable_file(ns);
> +
> + return ret;
Same here. Also I suspect this function can be removed and the two
calls just be done in the only caller.
> +static void nvmet_flush_work_file(struct work_struct *work)
> +{
> + int ret;
> + struct nvmet_req *req;
> +
> + req = container_of(work, struct nvmet_req, flush_work);
Maybe:
struct nvmet_req *req = container_of(work, struct nvmet_req, work);
int ret;
> +static void nvmet_execute_discard_file(struct nvmet_req *req)
> +{
> + struct nvme_dsm_range range;
> + int mode = FALLOC_FL_PUNCH_HOLE | FALLOC_FL_KEEP_SIZE;
> + loff_t offset;
> + loff_t len;
> + int i, ret;
> +
> + for (i = 0; i <= le32_to_cpu(req->cmd->dsm.nr); i++) {
> + if (nvmet_copy_from_sgl(req, i * sizeof(range), &range,
> + sizeof(range)))
> + break;
> + offset = le64_to_cpu(range.slba) << req->ns->blksize_shift;
> + len = le32_to_cpu(range.nlb) << req->ns->blksize_shift;
> + ret = vfs_fallocate(req->ns->file, mode, offset, len);
> + if (ret)
> + break;
> + }
> +
> + nvmet_req_complete(req, ret < 0 ? NVME_SC_INTERNAL | NVME_SC_DNR : 0);
> +}
Discard and write zeroes should probably also be exectured using the
work struct as they will usually block.
> u16 nvmet_parse_io_cmd(struct nvmet_req *req)
> {
> struct nvme_command *cmd = req->cmd;
> @@ -207,20 +341,33 @@ u16 nvmet_parse_io_cmd(struct nvmet_req *req)
> switch (cmd->common.opcode) {
> case nvme_cmd_read:
> case nvme_cmd_write:
> - req->execute = nvmet_execute_rw;
> + if (req->ns->file)
> + req->execute = nvmet_execute_rw_file;
> + else
> + req->execute = nvmet_execute_rw;
> req->data_len = nvmet_rw_len(req);
Maybe it would be cleaner to have separate parse_block_io_cmd/
parse_file_io_cmd helpers? (I'm not entirely sure, use your own
judgement)
> diff --git a/drivers/nvme/target/nvmet.h b/drivers/nvme/target/nvmet.h
> index 15fd84a..60f399f 100644
> --- a/drivers/nvme/target/nvmet.h
> +++ b/drivers/nvme/target/nvmet.h
> @@ -26,6 +26,8 @@
> #include <linux/configfs.h>
> #include <linux/rcupdate.h>
> #include <linux/blkdev.h>
> +#include <linux/file.h>
> +#include <linux/falloc.h>
We shouldn't really need these in nvmet.h, only in io-cmd.c, with
possible an empty forward declaration for struct file here.
> @@ -224,6 +227,8 @@ struct nvmet_req {
> struct scatterlist *sg;
> struct bio inline_bio;
> struct bio_vec inline_bvec[NVMET_MAX_INLINE_BIOVEC];
> + struct kiocb iocb;
> + struct bio_vec *bvec;
> int sg_cnt;
> /* data length as parsed from the command: */
> size_t data_len;
> @@ -234,6 +239,7 @@ struct nvmet_req {
>
> void (*execute)(struct nvmet_req *req);
> const struct nvmet_fabrics_ops *ops;
> + struct work_struct flush_work;
I think we want a union between the block and file fields to
not bloat the structure, e.g.
union {
struct {
struct bio inline_bio;
} b;
struct {
struct kiocb iocb;
struct bio_vec *bvev;
struct work_struct work;
} f;
};
plus auditing for other files only used in one path.
next prev parent reply other threads:[~2018-05-09 5:53 UTC|newest]
Thread overview: 6+ messages / expand[flat|nested] mbox.gz Atom feed top
2018-05-08 5:38 [PATCH V3] nvmet: add simple file backed ns support Chaitanya Kulkarni
2018-05-09 5:53 ` Christoph Hellwig [this message]
2018-05-10 3:51 ` chaitany kulkarni
2018-05-09 14:53 ` Sagi Grimberg
2018-05-10 3:59 ` chaitany kulkarni
2018-05-10 17:40 ` Christoph Hellwig
Reply instructions:
You may reply publicly to this message via plain-text email
using any one of the following methods:
* Save the following mbox file, import it into your mail client,
and reply-to-all from there: mbox
Avoid top-posting and favor interleaved quoting:
https://en.wikipedia.org/wiki/Posting_style#Interleaved_style
* Reply using the --to, --cc, and --in-reply-to
switches of git-send-email(1):
git send-email \
--in-reply-to=20180509055356.GA18926@lst.de \
--to=hch@lst.de \
/path/to/YOUR_REPLY
https://kernel.org/pub/software/scm/git/docs/git-send-email.html
* If your mail client supports setting the In-Reply-To header
via mailto: links, try the mailto: link
Be sure your reply has a Subject: header at the top and a blank line
before the message body.
This is a public inbox, see mirroring instructions
for how to clone and mirror all data and code used for this inbox;
as well as URLs for NNTP newsgroup(s).