All of lore.kernel.org
 help / color / mirror / Atom feed
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.

  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 an external index of several public inboxes,
see mirroring instructions on how to clone and mirror
all data and code used by this external index.