From: Hannes Reinecke <hare@suse.de>
To: Chaitanya Kulkarni <chaitanya.kulkarni@wdc.com>,
linux-nvme@lists.infradead.org
Cc: sagi@grimberg.me, hch@lst.de
Subject: Re: [PATCH V3 2/7] nvmet: add global thread for ns-resize AEN
Date: Mon, 27 Apr 2020 16:19:14 +0200 [thread overview]
Message-ID: <ba5afa3f-95ee-53a6-174c-ffbce69b7371@suse.de> (raw)
In-Reply-To: <20200419234856.59901-3-chaitanya.kulkarni@wdc.com>
On 4/20/20 1:48 AM, Chaitanya Kulkarni wrote:
> The change of size detection on the target should generate an AEN to
> the host. Right now there is no generic mechanism that allows us to add
> callbacks for the block and file backend so that we will get the
> notification for change of the size for block device and file backend.
> This patch adds global maintenance thread that checks for the size
> change and generates AEN when needed. This also adds a required lock
> needed to protect the ns->size variable which is updated under
> nvmet_ns_enable().
>
> Signed-off-by: Chaitanya Kulkarni <chaitanya.kulkarni@wdc.com>
> ---
> drivers/nvme/target/admin-cmd.c | 7 +-
> drivers/nvme/target/configfs.c | 2 +-
> drivers/nvme/target/core.c | 129 ++++++++++++++++++++++++++++++
> drivers/nvme/target/io-cmd-bdev.c | 9 ++-
> drivers/nvme/target/io-cmd-file.c | 15 ++--
> drivers/nvme/target/nvmet.h | 22 ++++-
> 6 files changed, 170 insertions(+), 14 deletions(-)
>
> diff --git a/drivers/nvme/target/admin-cmd.c b/drivers/nvme/target/admin-cmd.c
> index 4c79aa804887..a3bc2987c72a 100644
> --- a/drivers/nvme/target/admin-cmd.c
> +++ b/drivers/nvme/target/admin-cmd.c
> @@ -486,10 +486,9 @@ static void nvmet_execute_identify_ns(struct nvmet_req *req)
> if (!ns)
> goto done;
>
> - if (ns->bdev)
> - nvmet_bdev_ns_revalidate(ns);
> - else
> - nvmet_file_ns_revalidate(ns);
> + mutex_lock(&ns->subsys->lock);
> + nvmet_ns_revalidate(ns);
> + mutex_unlock(&ns->subsys->lock);
>
> /*
> * nuse = ncap = nsze isn't always true, but we have no way to find
> diff --git a/drivers/nvme/target/configfs.c b/drivers/nvme/target/configfs.c
> index 58cabd7b6fc5..b0e84027b3bc 100644
> --- a/drivers/nvme/target/configfs.c
> +++ b/drivers/nvme/target/configfs.c
> @@ -1469,7 +1469,7 @@ int __init nvmet_init_configfs(void)
> return 0;
> }
>
> -void __exit nvmet_exit_configfs(void)
> +void nvmet_exit_configfs(void)
> {
> configfs_unregister_subsystem(&nvmet_configfs_subsystem);
> }
> diff --git a/drivers/nvme/target/core.c b/drivers/nvme/target/core.c
> index b685f99d56a1..c42d24c1728e 100644
> --- a/drivers/nvme/target/core.c
> +++ b/drivers/nvme/target/core.c
> @@ -9,12 +9,15 @@
> #include <linux/rculist.h>
> #include <linux/pci-p2pdma.h>
> #include <linux/scatterlist.h>
> +#include <linux/delay.h>
> +#include <uapi/linux/sched/types.h>
>
> #define CREATE_TRACE_POINTS
> #include "trace.h"
>
> #include "nvmet.h"
>
> +struct nvmet_resize_monitor *monitor;
> struct workqueue_struct *buffered_io_wq;
> static const struct nvmet_fabrics_ops *nvmet_transports[NVMF_TRTYPE_MAX];
> static DEFINE_IDA(cntlid_ida);
> @@ -514,6 +517,59 @@ static void nvmet_p2pmem_ns_add_p2p(struct nvmet_ctrl *ctrl,
> ns->nsid);
> }
>
> +bool nvmet_ns_revalidate(struct nvmet_ns *ns)
> +{
> + if (ns->bdev)
> + return nvmet_bdev_ns_revalidate(ns);
> +
> + return nvmet_file_ns_revalidate(ns);
> +}
> +
> +static void __nvmet_handle_resize_ns(struct nvmet_subsys *s)
> +{
> + struct nvmet_ns *ns;
> +
> + mutex_lock(&s->lock);
> + list_for_each_entry_rcu(ns, &s->namespaces, dev_link, 1) {
> + if (nvmet_ns_revalidate(ns))
> + nvmet_ns_changed(ns->subsys, ns->nsid);
> + }
> + mutex_unlock(&s->lock);
> +}
> +
> +static int nvmet_ns_resize_monitor(void *data)
> +{
> + struct sched_param p = { .sched_priority = monitor->sched_priority };
> + struct nvmet_subsys_link *link;
> + struct nvmet_port *port;
> + u32 msec;
> +
> + complete(&monitor->wait);
> + sched_setscheduler(current, monitor->sched_policy, &p);
> +
> + while (!kthread_should_park()) {
> + down_read(&nvmet_config_sem);
> + list_for_each_entry(port, nvmet_ports, global_entry)
> + list_for_each_entry(link, &port->subsystems, entry)
> + __nvmet_handle_resize_ns(link->subsys);
> + up_read(&nvmet_config_sem);
> + schedule();
> + /* XXX: use better sleep wakeup mechanism */
> +
> + /*
> + * This allows user to change the sleep timtout without
> + * stopping monitor thread.
> + */
> + mutex_lock(&monitor->control_lock);
> + msec = monitor->msec;
> + mutex_unlock(&monitor->control_lock);
> + msleep(msec);
> + }
> +
> + kthread_parkme();
> + return 0;
> +}
> +
> int nvmet_ns_enable(struct nvmet_ns *ns)
> {
> struct nvmet_subsys *subsys = ns->subsys;
> @@ -1480,6 +1536,71 @@ void nvmet_subsys_put(struct nvmet_subsys *subsys)
> kref_put(&subsys->ref, nvmet_subsys_free);
> }
>
> +bool nvmet_enable_ns_resize_monitor(void)
> +{
> + lockdep_assert_held(&monitor->control_lock);
> +
> + if (monitor->thread)
> + goto out;
> +
> + monitor->thread = kthread_create(nvmet_ns_resize_monitor, NULL,
> + "nvmet_ns_resize");
> + if (monitor->thread) {
> + wake_up_process(monitor->thread);
> + wait_for_completion(&monitor->wait);
> + pr_debug("ns monitor thread started successfully\n");
> + }
> +
> +out:
> + return monitor->thread ? true : false;
> +}
> +
> +bool nvmet_disable_ns_resize_monitor(void)
> +{
> + bool ret = false;
> +
> + lockdep_assert_held(&monitor->control_lock);
> +
> + if (monitor->thread) {
> + kthread_park(monitor->thread);
> + kthread_stop(monitor->thread);
> + monitor->thread = NULL;
> + ret = true;
> + }
> +
> + kfree(monitor->thread);
> + return ret;
> +}
> +
> +int nvmet_init_ns_resize_monitor(void)
> +{
> + int ret;
> +
> + monitor = kzalloc(sizeof(*monitor), GFP_KERNEL);
> + if (!monitor)
> + return -ENOMEM;
> +
> + monitor->msec = NVMET_RESIZE_MON_MSEC;
> + monitor->sched_policy = SCHED_IDLE;
> + monitor->sched_priority = 0;
> + mutex_init(&monitor->control_lock);
> + init_completion(&monitor->wait);
> +
> + mutex_lock(&monitor->control_lock);
> + ret = nvmet_enable_ns_resize_monitor() ? 0 : -ENOMEM;
> + mutex_unlock(&monitor->control_lock);
> +
> + return ret;
> +}
> +
> +void nvmet_exit_ns_resize_monitor(void)
> +{
> + mutex_lock(&monitor->control_lock);
> + nvmet_disable_ns_resize_monitor();
> + mutex_unlock(&monitor->control_lock);
> + kfree(monitor);
> +}
> +
> static int __init nvmet_init(void)
> {
> int error;
> @@ -1500,8 +1621,15 @@ static int __init nvmet_init(void)
> error = nvmet_init_configfs();
> if (error)
> goto out_exit_discovery;
> +
> + error = nvmet_init_ns_resize_monitor();
> + if (error)
> + goto out_exit_configfs;
> +
> return 0;
>
> +out_exit_configfs:
> + nvmet_exit_configfs();
> out_exit_discovery:
> nvmet_exit_discovery();
> out_free_work_queue:
> @@ -1512,6 +1640,7 @@ static int __init nvmet_init(void)
>
> static void __exit nvmet_exit(void)
> {
> + nvmet_exit_ns_resize_monitor();
> nvmet_exit_configfs();
> nvmet_exit_discovery();
> ida_destroy(&cntlid_ida);
> diff --git a/drivers/nvme/target/io-cmd-bdev.c b/drivers/nvme/target/io-cmd-bdev.c
> index 0427e040e3dd..3cca08e9ad90 100644
> --- a/drivers/nvme/target/io-cmd-bdev.c
> +++ b/drivers/nvme/target/io-cmd-bdev.c
> @@ -75,9 +75,16 @@ void nvmet_bdev_ns_disable(struct nvmet_ns *ns)
> }
> }
>
> -void nvmet_bdev_ns_revalidate(struct nvmet_ns *ns)
> +bool nvmet_bdev_ns_revalidate(struct nvmet_ns *ns)
> {
> + bool change;
> +
> + lockdep_assert_held(&ns->subsys->lock);
> +
> + change = ns->size != i_size_read(ns->bdev->bd_inode) ? true : false;
> ns->size = i_size_read(ns->bdev->bd_inode);
> +
> + return change;
> }
>
> static u16 blk_to_nvme_status(struct nvmet_req *req, blk_status_t blk_sts)
> diff --git a/drivers/nvme/target/io-cmd-file.c b/drivers/nvme/target/io-cmd-file.c
> index 14364383d2fe..a2d82e55858b 100644
> --- a/drivers/nvme/target/io-cmd-file.c
> +++ b/drivers/nvme/target/io-cmd-file.c
> @@ -80,15 +80,20 @@ int nvmet_file_ns_enable(struct nvmet_ns *ns)
> return ret;
> }
>
> -void nvmet_file_ns_revalidate(struct nvmet_ns *ns)
> +bool nvmet_file_ns_revalidate(struct nvmet_ns *ns)
> {
> + struct path *f_path = &ns->file->f_path;
> + bool change = false;
> struct kstat stat;
>
> - if (vfs_getattr(&ns->file->f_path, &stat, STATX_SIZE,
> - AT_STATX_FORCE_SYNC))
> - return;
> + lockdep_assert_held(&ns->subsys->lock);
>
> - ns->size = stat.size;
> + if (vfs_getattr(f_path, &stat, STATX_SIZE, AT_STATX_FORCE_SYNC) == 0) {
> + change = ns->size != stat.size ? true : false;
> + ns->size = stat.size;
> + }
> +
> + return change;
> }
>
> static void nvmet_file_init_bvec(struct bio_vec *bv, struct scatterlist *sg)
> diff --git a/drivers/nvme/target/nvmet.h b/drivers/nvme/target/nvmet.h
> index 8b479d932a7b..7fe6d705cbf1 100644
> --- a/drivers/nvme/target/nvmet.h
> +++ b/drivers/nvme/target/nvmet.h
> @@ -23,6 +23,7 @@
> #define NVMET_ASYNC_EVENTS 4
> #define NVMET_ERROR_LOG_SLOTS 128
> #define NVMET_NO_ERROR_LOC ((u16)-1)
> +#define NVMET_RESIZE_MON_MSEC 500
> #define NVMET_DEFAULT_CTRL_MODEL "Linux"
>
> /*
> @@ -50,6 +51,17 @@
> #define IPO_IATTR_CONNECT_SQE(x) \
> (cpu_to_le32(offsetof(struct nvmf_connect_command, x)))
>
> +struct nvmet_resize_monitor {
> + u32 sched_priority;
> + u32 sched_policy;
> + struct mutex control_lock;
> + struct task_struct *thread;
> + struct completion wait;
> + u32 msec;
> +};
> +
> +extern struct nvmet_resize_monitor *monitor;
> +
> struct nvmet_ns {
> struct list_head dev_link;
> struct percpu_ref ref;
> @@ -477,7 +489,7 @@ void nvmet_add_async_event(struct nvmet_ctrl *ctrl, u8 event_type,
> #define NVMET_DISC_KATO_MS 120000
>
> int __init nvmet_init_configfs(void);
> -void __exit nvmet_exit_configfs(void);
> +void nvmet_exit_configfs(void);
>
> int __init nvmet_init_discovery(void);
> void nvmet_exit_discovery(void);
> @@ -498,8 +510,12 @@ void nvmet_file_ns_disable(struct nvmet_ns *ns);
> u16 nvmet_bdev_flush(struct nvmet_req *req);
> u16 nvmet_file_flush(struct nvmet_req *req);
> void nvmet_ns_changed(struct nvmet_subsys *subsys, u32 nsid);
> -void nvmet_bdev_ns_revalidate(struct nvmet_ns *ns);
> -void nvmet_file_ns_revalidate(struct nvmet_ns *ns);
> +bool nvmet_bdev_ns_revalidate(struct nvmet_ns *ns);
> +bool nvmet_file_ns_revalidate(struct nvmet_ns *ns);
> +bool nvmet_ns_revalidate(struct nvmet_ns *ns);
> +
> +bool nvmet_enable_ns_resize_monitor(void);
> +bool nvmet_disable_ns_resize_monitor(void);
>
> static inline u32 nvmet_rw_len(struct nvmet_req *req)
> {
>
I'm not a big fan of having single-purpose kthreads; this always smells
like a waste of resources.
Any particular reason why you didn't use workqueues here?
Cheers,
Hannes
--
Dr. Hannes Reinecke Teamlead Storage & Networking
hare@suse.de +49 911 74053 688
SUSE Software Solutions GmbH, Maxfeldstr. 5, 90409 Nürnberg
HRB 36809 (AG Nürnberg), Geschäftsführer: Felix Imendörffer
_______________________________________________
linux-nvme mailing list
linux-nvme@lists.infradead.org
http://lists.infradead.org/mailman/listinfo/linux-nvme
next prev parent reply other threads:[~2020-04-27 14:19 UTC|newest]
Thread overview: 16+ messages / expand[flat|nested] mbox.gz Atom feed top
2020-04-19 23:48 [PATCH V3 0/7] nvmet: add target ns revalidate support Chaitanya Kulkarni
2020-04-19 23:48 ` [PATCH V3 1/7] nvmet: add ns revalidation support Chaitanya Kulkarni
2020-04-19 23:48 ` [PATCH V3 2/7] nvmet: add global thread for ns-resize AEN Chaitanya Kulkarni
2020-04-27 14:19 ` Hannes Reinecke [this message]
2020-04-19 23:48 ` [PATCH V3 3/7] nvmet: export resize thread enable-disable attr Chaitanya Kulkarni
2020-04-19 23:48 ` [PATCH V3 4/7] nvmet: export resize thread scan interval Chaitanya Kulkarni
2020-04-19 23:48 ` [PATCH V3 5/7] nvmet: export resize thread sched attributes Chaitanya Kulkarni
2020-04-19 23:48 ` [PATCH V3 6/7] nvmet: export ns resize monitor attribute Chaitanya Kulkarni
2020-04-19 23:48 ` [PATCH V3 7/7] nvmet: add async event tracing support Chaitanya Kulkarni
2020-04-22 8:19 ` [PATCH V3 0/7] nvmet: add target ns revalidate support Christoph Hellwig
2020-04-23 6:03 ` Chaitanya Kulkarni
2020-04-23 8:20 ` Sagi Grimberg
2020-04-24 7:05 ` Christoph Hellwig
2020-04-24 8:34 ` Chaitanya Kulkarni
2020-04-24 19:08 ` Sagi Grimberg
2020-04-24 21:02 ` Sagi Grimberg
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=ba5afa3f-95ee-53a6-174c-ffbce69b7371@suse.de \
--to=hare@suse.de \
--cc=chaitanya.kulkarni@wdc.com \
--cc=hch@lst.de \
--cc=linux-nvme@lists.infradead.org \
--cc=sagi@grimberg.me \
/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