From: hch@lst.de (Christoph Hellwig)
Subject: [PATCH V5] nvmet: add simple file backed ns support
Date: Thu, 17 May 2018 14:47:14 +0200 [thread overview]
Message-ID: <20180517124714.GA31470@lst.de> (raw)
In-Reply-To: <20180517054558.5648-1-chaitanya.kulkarni@wdc.com>
On Thu, May 17, 2018@01:45:58AM -0400, Chaitanya Kulkarni wrote:
> This patch adds simple file backed namespace support for
> NVMeOF target.
>
> In current implementation NVMeOF supports block
> device backed namespaces on the target side.
> With this implementation regular file(s) can be used
> to initialize the namespace(s) via target side
> configfs interface.
>
> For admin smart log command on the target side, we only
> use block device backed namespaces to compute target
> side smart log.
>
> The new file io-cmd-file.c is responsible for handling
> the code for I/O commands when ns is file backed. Also,
> we introduce mempools based slow path for file backed
> ns.
Please use ~ 73 lines for the changelog to instead of line wrapping
earlier.
> +static int nvmet_ns_enable_blkdev(struct nvmet_ns *ns)
> +static int nvmet_ns_enable_file(struct nvmet_ns *ns)
I think these should be moved to io-cmd.c and io-cmd-file.c
respectively, including adding little helpers for close, so that
the code dealing with file structures or block devices is relatively
isolated now that we split up the implementation files.
Sagi - what do you think about renaming io-cmd.c to io-cmd-bdev.c
while we're at it?
> + ns->cachep = kmem_cache_create("nvmet-fs",
what about nvmet-bvec as the name?
> + if (req->ns->file)
> + return nvmet_parse_io_cmd_file(req);
> + else if (req->ns->bdev)
> + return nvmet_parse_io_cmd_blkdev(req);
> +
> + WARN_ON_ONCE("failed to parse io cmd: invalid ns handle");
> +
> + return NVME_SC_INVALID_OPCODE | NVME_SC_DNR;
I'd just leave it at and if/else, things will blow up nicely if this
invariant ever gets broken:
if (req->ns->file)
return nvmet_parse_io_cmd_file(req);
else
return nvmet_parse_io_cmd_blkdev(req);
> + * This program is free software; you can redistribute it and/or
> + * modify it under the terms of the GNU General Public License
> + * as published by the Free Software Foundation; either version 2
> + * of the License, or (at your option) any later version.
> + *
> + * This program is distributed in the hope that it will be useful,
> + * but WITHOUT ANY WARRANTY; without even the implied warranty of
> + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
> + * GNU General Public License for more details.
You can remove this whole boilerplate given that you have a SPDX tag.
> +typedef ssize_t (*call_iter_t) (struct kiocb *, struct iov_iter *);
> +typedef void (*ki_complete_t)(struct kiocb *iocb, long ret, long ret2);
No need for these typedefs.
> + if ((bv_cnt == NVMET_MAX_BVEC) || ((nr_bvec - 1) == 0)) {
No need for all but the outer braces.
> + init_completion(&req->f.io_complete);
> +
> + ret = nvmet_issue_bvec(req, pos, bv_cnt, len, io_done);
> + if (ret == -EIOCBQUEUED)
> + wait_for_completion(&req->f.io_complete);
Instead of using your own completion, the synchronous case should just
not set a ki_complete callback at all, which means the file system
will handle the I/O synchronously for you.
That probably means you can share the actual low-level routine for
doing I/O, just don't set ki_complete in the is_sync case, and have
some sort of outer loop chunking up into nr_bvec sized chunks
> + req->f.bvec = req->inline_bvec;
> + if (nr_bvec > NVMET_MAX_INLINE_BIOVEC) {
> + req->f.bvec = kmalloc_array(nr_bvec, sizeof(struct bio_vec),
> + GFP_KERNEL);
> + /* fallback */
> + if (!req->f.bvec) {
> + req->f.bvec = mempool_alloc(req->ns->mempool,
> + GFP_KERNEL);
> + if (!req->f.bvec)
> + goto out;
> + slow_path = true;
> + }
> + }
> +
> + req->f.bvec = mempool_alloc(req->ns->mempool,
> + GFP_KERNEL);
> + if (!req->f.bvec)
> + goto out;
> + slow_path = true;
This seems to always hit the slow path. How about this instead:
if (nr_bvec > NVMET_MAX_INLINE_BIOVEC) {
req->f.bvec = kmalloc_array(nr_bvec, sizeof(struct bio_vec),
GFP_KERNEL);
} else {
req->f.bvec = req->inline_bvec;
}
/* fallback under memory pressure */
if (unlikely(!req->f.bvec)) {
req->f.bvec = mempool_alloc(req->ns->mempool, GFP_KERNEL);
if (nr_bvec > NVMET_MAX_MEMPOOL_BVEC)
is_sync = true;
}
}
Also I think NVMET_MAX_BVEC should be NVMET_MAX_MEMPOOL_BVEC and
the actual I/O functions really don't need most of the arguments as
far as I can tell. mempool_alloc with a GFP_KERNEL argument can't
fail it will just block forever, so no need to chek the return value
there.
> -static inline u32 nvmet_rw_len(struct nvmet_req *req)
> +inline u32 nvmet_rw_len(struct nvmet_req *req)
> {
> return ((u32)le16_to_cpu(req->cmd->rw.length) + 1) <<
> req->ns->blksize_shift;
I'd keep this as an inline and just move it to nvmet.h
> +#define NVMET_MAX_BVEC 16
> +#define NVMET_MPOOL_MIN_OBJ NVMET_MAX_BVEC
Even if both of these are 16 they aren't really related, so please
define NVMET_MPOOL_MIN_OBJ directly. Also with the move of the
enable function these can be kept in io-cmd-file.c.
> /* Helper Macros when NVMe error is NVME_SC_CONNECT_INVALID_PARAM
> * The 16 bit shift is to set IATTR bit to 1, which means offending
> @@ -43,6 +45,7 @@ struct nvmet_ns {
> struct list_head dev_link;
> struct percpu_ref ref;
> struct block_device *bdev;
> + struct file *file;
> u32 nsid;
> u32 blksize_shift;
> loff_t size;
> @@ -57,6 +60,8 @@ struct nvmet_ns {
> struct config_group group;
>
> struct completion disable_done;
> + mempool_t *mempool;
> + struct kmem_cache *cachep;
I'd name these bvec_pool an bvec_cache.
next prev parent reply other threads:[~2018-05-17 12:47 UTC|newest]
Thread overview: 5+ messages / expand[flat|nested] mbox.gz Atom feed top
2018-05-17 5:45 [PATCH V5] nvmet: add simple file backed ns support Chaitanya Kulkarni
2018-05-17 12:47 ` Christoph Hellwig [this message]
2018-05-17 21:14 ` Keith Busch
2018-05-17 22:39 ` Chaitanya Kulkarni
2018-05-18 9:06 ` 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=20180517124714.GA31470@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).