Re: [PATCH] bdi: Fix another oops in wb_workfn()

2018-05-26 Thread Tetsuo Handa
Tejun Heo wrote:
> On Sun, May 27, 2018 at 11:21:25AM +0900, Tetsuo Handa wrote:
> > syzbot is still hitting NULL pointer dereference at wb_workfn() [1].
> > This might be because we overlooked that delayed_work_timer_fn() does not
> > check WB_registered before calling __queue_work() while mod_delayed_work()
> > does not wait for already started delayed_work_timer_fn() because it uses
> > del_timer() rather than del_timer_sync().
> 
> It shouldn't be that as dwork timer is an irq safe timer.  Even if
> that's the case, the right thing to do would be fixing workqueue
> rather than reaching into workqueue internals from backing-dev code.
> 

Do you think that there is possibility that __queue_work() is almost 
concurrently
executed from two CPUs, one from mod_delayed_work(bdi_wq, >dwork, 0) from
wb_shutdown() path (which is called without spin_lock_bh(>work_lock)) and
the other from delayed_work_timer_fn() path (which is called without checking
WB_registered bit under spin_lock_bh(>work_lock)) ?


Re: [PATCH] bdi: Fix another oops in wb_workfn()

2018-05-26 Thread Tejun Heo
On Sun, May 27, 2018 at 11:21:25AM +0900, Tetsuo Handa wrote:
> From 8a8222698163d1fe180258566e9a3ff43f54fcd9 Mon Sep 17 00:00:00 2001
> From: Tetsuo Handa 
> Date: Sun, 27 May 2018 11:08:20 +0900
> Subject: [PATCH] bdi: Fix another oops in wb_workfn()
> 
> syzbot is still hitting NULL pointer dereference at wb_workfn() [1].
> This might be because we overlooked that delayed_work_timer_fn() does not
> check WB_registered before calling __queue_work() while mod_delayed_work()
> does not wait for already started delayed_work_timer_fn() because it uses
> del_timer() rather than del_timer_sync().

It shouldn't be that as dwork timer is an irq safe timer.  Even if
that's the case, the right thing to do would be fixing workqueue
rather than reaching into workqueue internals from backing-dev code.

Thanks.

-- 
tejun


[PATCH] bdi: Fix another oops in wb_workfn()

2018-05-26 Thread Tetsuo Handa
>From 8a8222698163d1fe180258566e9a3ff43f54fcd9 Mon Sep 17 00:00:00 2001
From: Tetsuo Handa 
Date: Sun, 27 May 2018 11:08:20 +0900
Subject: [PATCH] bdi: Fix another oops in wb_workfn()

syzbot is still hitting NULL pointer dereference at wb_workfn() [1].
This might be because we overlooked that delayed_work_timer_fn() does not
check WB_registered before calling __queue_work() while mod_delayed_work()
does not wait for already started delayed_work_timer_fn() because it uses
del_timer() rather than del_timer_sync().

Make wb_shutdown() be careful about wb_wakeup_delayed() path.

[1] 
https://syzkaller.appspot.com/bug?id=e0818ccb7e46190b3f1038b0c794299208ed4206

Signed-off-by: Tetsuo Handa 
Reported-by: syzbot 
Cc: Tejun Heo 
Cc: Dave Chinner 
Cc: Jan Kara 
Cc: Jens Axboe 
---
 mm/backing-dev.c | 15 ++-
 1 file changed, 14 insertions(+), 1 deletion(-)

diff --git a/mm/backing-dev.c b/mm/backing-dev.c
index 7441bd9..31e1d7e 100644
--- a/mm/backing-dev.c
+++ b/mm/backing-dev.c
@@ -372,11 +372,24 @@ static void wb_shutdown(struct bdi_writeback *wb)
 
cgwb_remove_from_bdi_list(wb);
/*
+* mod_delayed_work() is not appropriate here, for
+* delayed_work_timer_fn() from wb_wakeup_delayed() does not check
+* WB_registered before calling __queue_work().
+*/
+   del_timer_sync(>dwork.timer);
+   /*
+* Clear WORK_STRUCT_PENDING_BIT in order to make sure that next
+* queue_delayed_work() actually enqueues this work to the tail, for
+* wb_wakeup_delayed() already set WORK_STRUCT_PENDING_BIT before
+* scheduling delayed_work_timer_fn().
+*/
+   cancel_delayed_work_sync(>dwork);
+   /*
 * Drain work list and shutdown the delayed_work.  !WB_registered
 * tells wb_workfn() that @wb is dying and its work_list needs to
 * be drained no matter what.
 */
-   mod_delayed_work(bdi_wq, >dwork, 0);
+   queue_delayed_work(bdi_wq, >dwork, 0);
flush_delayed_work(>dwork);
WARN_ON(!list_empty(>work_list));
/*
-- 
1.8.3.1




Re: general protection fault in wb_workfn (2)

2018-05-26 Thread Tetsuo Handa
Forwarding 
http://lkml.kernel.org/r/201805251915.fgh64517.hvfjoolffmq...@i-love.sakura.ne.jp
 .

Jan Kara wrote:
> > void delayed_work_timer_fn(struct timer_list *t)
> > {
> > struct delayed_work *dwork = from_timer(dwork, t, timer);
> > 
> > /* should have been called from irqsafe timer with irq already off */
> > __queue_work(dwork->cpu, dwork->wq, >work);
> > }
> > 
> > Then, wb_workfn() is after all scheduled even if we check for
> > WB_registered bit, isn't it?
> 
> It can be queued after WB_registered bit is cleared but it cannot be queued
> after mod_delayed_work(bdi_wq, >dwork, 0) has finished. That function
> deletes the pending timer (the timer cannot be armed again because
> WB_registered is cleared) and queues what should be the last round of
> wb_workfn().

mod_delayed_work() deletes the pending timer but does not wait for already
invoked timer handler to complete because it is using del_timer() rather than
del_timer_sync(). Then, what happens if __queue_work() is almost concurrently
executed from two CPUs, one from mod_delayed_work(bdi_wq, >dwork, 0) from
wb_shutdown() path (which is called without spin_lock_bh(>work_lock)) and
the other from delayed_work_timer_fn() path (which is called without checking
WB_registered bit under spin_lock_bh(>work_lock)) ?

wb_wakeup_delayed() {
  spin_lock_bh(>work_lock);
  if (test_bit(WB_registered, >state)) // succeeds
queue_delayed_work(bdi_wq, >d_work, timeout) {
  queue_delayed_work_on(WORK_CPU_UNBOUND, bdi_wq, >d_work, timeout) {
 if (!test_and_set_bit(WORK_STRUCT_PENDING_BIT, 
work_data_bits(>d_work.work))) { // succeeds
   __queue_delayed_work(WORK_CPU_UNBOUND, bdi_wq, >d_work, timeout) 
{
 add_timer(timer); // schedules for delayed_work_timer_fn()
   }
 }
  }
}
  spin_unlock_bh(>work_lock);
}

delayed_work_timer_fn() {
  // del_timer() already returns false at this point because this timer
  // is already inside handler. But something took long here enough to
  // wait for __queue_work() from wb_shutdown() path to finish?
  __queue_work(WORK_CPU_UNBOUND, bdi_wq, >d_work.work) {
insert_work(pwq, work, worklist, work_flags);
  }
}

wb_shutdown() {
  mod_delayed_work(bdi_wq, >dwork, 0) {
mod_delayed_work_on(WORK_CPU_UNBOUND, bdi_wq, >dwork, 0) {
  ret = try_to_grab_pending(>dwork.work, true, ) {
if (likely(del_timer(>dwork.timer))) // fails because already in 
delayed_work_timer_fn()
  return 1;
if (!test_and_set_bit(WORK_STRUCT_PENDING_BIT, 
work_data_bits(>dwork.work))) // fails because already set by 
queue_delayed_work()
  return 0;
// Returns 1 or -ENOENT after doing something?
  }
  if (ret >= 0)
__queue_delayed_work(WORK_CPU_UNBOUND, bdi_wq, >dwork, 0) {
  __queue_work(WORK_CPU_UNBOUND, bdi_wq, >dwork.work) {
insert_work(pwq, work, worklist, work_flags);
  }
}
}
  }
}



Re: [PATCH 13/14] nvme: use the changed namespaces list log to clear ns data changed AENs

2018-05-26 Thread Christoph Hellwig
On Sat, May 26, 2018 at 12:05:02PM +, Popuri, Sriram wrote:
> Reading the spec it looks like ns log is alternate approach:
> 
> "Namespace Attribute Changed: The Identify Namespace data structure for one 
> or more namespaces, as well as the Namespace List returned when the Identify 
> command is issued with the CNS field set to 02h, have changed. Host software 
> may use this event as an indication that it should read the Identify 
> Namespace data structures for each namespace to determine what has changed.
> 
> Alternatively, host software may request the Changed Namespace List (Log 
> Identifier 04h) to determine which namespaces in this controller have changed 
> Identify Namespace information since the last time the log page was read."
> 
> My question is: Does the target needs to implement log page 04h as this is an 
> optional log page and the text above suggests its used in alternate way?

Section 5.2 clearly states that each AER comes with a log page to
clear it, and the above does not contain any language to explicitly
override it. So my reading of the spec is that to clear the event you need
to read the log page, but to find out what has changed you might issue
Identify commands instead.

> If target is not required to implement, then I guess your change should still 
> work because if log page 04h fails, it fails back to rescan. Correct?

Independ of what the spec actually requires, the code tries to robust
as possible and falls back to doing the manual scan.

> I think you can optimize this by checking the "Log Page Identifier" field in 
> your result and accordingly setting EVENT_NS_CHANGED. I assume target would 
> clear this if log page 04h is not supported.

We can try that, but I'm not sure what it is going to buy us.


RE: [PATCH 13/14] nvme: use the changed namespaces list log to clear ns data changed AENs

2018-05-26 Thread Popuri, Sriram
Reading the spec it looks like ns log is alternate approach:

"Namespace Attribute Changed: The Identify Namespace data structure for one or 
more namespaces, as well as the Namespace List returned when the Identify 
command is issued with the CNS field set to 02h, have changed. Host software 
may use this event as an indication that it should read the Identify Namespace 
data structures for each namespace to determine what has changed.

Alternatively, host software may request the Changed Namespace List (Log 
Identifier 04h) to determine which namespaces in this controller have changed 
Identify Namespace information since the last time the log page was read."

My question is: Does the target needs to implement log page 04h as this is an 
optional log page and the text above suggests its used in alternate way?

If target is not required to implement, then I guess your change should still 
work because if log page 04h fails, it fails back to rescan. Correct?
I think you can optimize this by checking the "Log Page Identifier" field in 
your result and accordingly setting EVENT_NS_CHANGED. I assume target would 
clear this if log page 04h is not supported.

"23:16  Log Page Identifier: Indicates the log page associated with the 
asynchronous event. This log page needs to be read by the host to clear the 
event"

Regards,
~Sriram

-Original Message-
From: Linux-nvme  On Behalf Of 
Christoph Hellwig
Sent: Saturday, May 26, 2018 3:58 PM
To: linux-n...@lists.infradead.org
Cc: Jens Axboe ; Keith Busch ; 
linux-block@vger.kernel.org; Sagi Grimberg ; Hannes Reinecke 

Subject: [PATCH 13/14] nvme: use the changed namespaces list log to clear ns 
data changed AENs

Per section 5.2 we need to issue the corresponding log page to clear an AEN, so 
for a namespace data changed AEN we need to read the changed namespace list 
log.  And once we read that log anyway we might as well use it to optimize the 
rescan.

Signed-off-by: Christoph Hellwig 
---
 drivers/nvme/host/core.c | 51 
 drivers/nvme/host/nvme.h |  2 ++
 2 files changed, 49 insertions(+), 4 deletions(-)

diff --git a/drivers/nvme/host/core.c b/drivers/nvme/host/core.c index 
06cd04dcffbc..1ae77428a1a5 100644
--- a/drivers/nvme/host/core.c
+++ b/drivers/nvme/host/core.c
@@ -3194,6 +3194,42 @@ static void nvme_scan_ns_sequential(struct nvme_ctrl 
*ctrl, unsigned nn)
nvme_remove_invalid_namespaces(ctrl, nn);  }
 
+static bool nvme_scan_changed_ns_log(struct nvme_ctrl *ctrl) {
+   size_t log_size = NVME_MAX_CHANGED_NAMESPACES * sizeof(__le32);
+   __le32 *log;
+   int error, i;
+   bool ret = false;
+
+   log = kzalloc(log_size, GFP_KERNEL);
+   if (!log)
+   return false;
+
+   error = nvme_get_log(ctrl, NVME_LOG_CHANGED_NS, log, log_size);
+   if (error) {
+   dev_warn(ctrl->device,
+   "reading changed ns log failed: %d\n", error);
+   goto out_free_log;
+   }
+
+   if (log[0] == cpu_to_le32(0x))
+   goto out_free_log;
+
+   for (i = 0; i < NVME_MAX_CHANGED_NAMESPACES; i++) {
+   u32 nsid = le32_to_cpu(log[i]);
+
+   if (nsid == 0)
+   break;
+   dev_info(ctrl->device, "rescanning namespace %d.\n", nsid);
+   nvme_validate_ns(ctrl, nsid);
+   }
+   ret = true;
+
+out_free_log:
+   kfree(log);
+   return ret;
+}
+
 static void nvme_scan_work(struct work_struct *work)  {
struct nvme_ctrl *ctrl =
@@ -3206,6 +3242,12 @@ static void nvme_scan_work(struct work_struct *work)
 
WARN_ON_ONCE(!ctrl->tagset);
 
+   if (test_and_clear_bit(EVENT_NS_CHANGED, >events)) {
+   if (nvme_scan_changed_ns_log(ctrl))
+   goto out_sort_namespaces;
+   dev_info(ctrl->device, "rescanning namespaces.\n");
+   }
+
if (nvme_identify_ctrl(ctrl, ))
return;
 
@@ -3213,14 +3255,15 @@ static void nvme_scan_work(struct work_struct *work)
if (ctrl->vs >= NVME_VS(1, 1, 0) &&
!(ctrl->quirks & NVME_QUIRK_IDENTIFY_CNS)) {
if (!nvme_scan_ns_list(ctrl, nn))
-   goto done;
+   goto out_free_id;
}
nvme_scan_ns_sequential(ctrl, nn);
- done:
+out_free_id:
+   kfree(id);
+out_sort_namespaces:
down_write(>namespaces_rwsem);
list_sort(NULL, >namespaces, ns_cmp);
up_write(>namespaces_rwsem);
-   kfree(id);
 }
 
 /*
@@ -3340,7 +3383,7 @@ static void nvme_handle_aen_notice(struct nvme_ctrl 
*ctrl, u32 result)  {
switch ((result & 0xff00) >> 8) {
case NVME_AER_NOTICE_NS_CHANGED:
-   dev_info(ctrl->device, "rescanning\n");
+   set_bit(EVENT_NS_CHANGED, >events);

[PATCH 08/14] nvmet: implement the changed namespaces log

2018-05-26 Thread Christoph Hellwig
Just keep a per-controller buffer of changed namespaces and copy it out
in the get log page implementation.

Signed-off-by: Christoph Hellwig 
---
 drivers/nvme/target/admin-cmd.c | 23 +
 drivers/nvme/target/core.c  | 44 ++---
 drivers/nvme/target/nvmet.h |  3 +++
 3 files changed, 61 insertions(+), 9 deletions(-)

diff --git a/drivers/nvme/target/admin-cmd.c b/drivers/nvme/target/admin-cmd.c
index e96bb02c4f2c..82d521f60a43 100644
--- a/drivers/nvme/target/admin-cmd.c
+++ b/drivers/nvme/target/admin-cmd.c
@@ -126,6 +126,26 @@ static void nvmet_execute_get_log_page_smart(struct 
nvmet_req *req)
nvmet_req_complete(req, status);
 }
 
+static void nvmet_execute_get_log_changed_ns(struct nvmet_req *req)
+{
+   struct nvmet_ctrl *ctrl = req->sq->ctrl;
+   u16 status = NVME_SC_INTERNAL;
+   size_t len;
+
+   if (req->data_len != NVME_MAX_CHANGED_NAMESPACES * sizeof(__le32))
+   goto out;
+
+   mutex_lock(>lock);
+   len = ctrl->nr_changed_ns * sizeof(__le32);
+   status = nvmet_copy_to_sgl(req, 0, ctrl->changed_ns_list, len);
+   if (!status)
+   status = nvmet_zero_sgl(req, len, req->data_len - len);
+   ctrl->nr_changed_ns = 0;
+   mutex_unlock(>lock);
+out:
+   nvmet_req_complete(req, status);
+}
+
 static void nvmet_execute_identify_ctrl(struct nvmet_req *req)
 {
struct nvmet_ctrl *ctrl = req->sq->ctrl;
@@ -543,6 +563,9 @@ u16 nvmet_parse_admin_cmd(struct nvmet_req *req)
 */
req->execute = nvmet_execute_get_log_page_noop;
return 0;
+   case NVME_LOG_CHANGED_NS:
+   req->execute = nvmet_execute_get_log_changed_ns;
+   return 0;
}
break;
case nvme_admin_identify:
diff --git a/drivers/nvme/target/core.c b/drivers/nvme/target/core.c
index 55c4bc693aa2..424ad41af980 100644
--- a/drivers/nvme/target/core.c
+++ b/drivers/nvme/target/core.c
@@ -144,6 +144,30 @@ static void nvmet_add_async_event(struct nvmet_ctrl *ctrl, 
u8 event_type,
schedule_work(>async_event_work);
 }
 
+static void nvmet_add_to_changed_ns_log(struct nvmet_ctrl *ctrl, u32 nsid)
+{
+   mutex_lock(>lock);
+   if (ctrl->nr_changed_ns < NVME_MAX_CHANGED_NAMESPACES) {
+   ctrl->changed_ns_list[ctrl->nr_changed_ns++] =
+   cpu_to_le32(nsid);
+   } else if (ctrl->nr_changed_ns == NVME_MAX_CHANGED_NAMESPACES) {
+   ctrl->changed_ns_list[0] = cpu_to_le32(0x);
+   }
+   mutex_unlock(>lock);
+}
+
+static void nvmet_ns_changed(struct nvmet_subsys *subsys, u32 nsid)
+{
+   struct nvmet_ctrl *ctrl;
+
+   list_for_each_entry(ctrl, >ctrls, subsys_entry) {
+   nvmet_add_to_changed_ns_log(ctrl, nsid);
+   nvmet_add_async_event(ctrl, NVME_AER_TYPE_NOTICE,
+   NVME_AER_NOTICE_NS_CHANGED,
+   NVME_LOG_CHANGED_NS);
+   }
+}
+
 int nvmet_register_transport(const struct nvmet_fabrics_ops *ops)
 {
int ret = 0;
@@ -287,7 +311,6 @@ static void nvmet_ns_dev_disable(struct nvmet_ns *ns)
 int nvmet_ns_enable(struct nvmet_ns *ns)
 {
struct nvmet_subsys *subsys = ns->subsys;
-   struct nvmet_ctrl *ctrl;
int ret = 0;
 
mutex_lock(>lock);
@@ -326,9 +349,7 @@ int nvmet_ns_enable(struct nvmet_ns *ns)
list_add_tail_rcu(>dev_link, >dev_link);
}
 
-   list_for_each_entry(ctrl, >ctrls, subsys_entry)
-   nvmet_add_async_event(ctrl, NVME_AER_TYPE_NOTICE, 0, 0);
-
+   nvmet_ns_changed(subsys, ns->nsid);
ns->enabled = true;
ret = 0;
 out_unlock:
@@ -342,7 +363,6 @@ int nvmet_ns_enable(struct nvmet_ns *ns)
 void nvmet_ns_disable(struct nvmet_ns *ns)
 {
struct nvmet_subsys *subsys = ns->subsys;
-   struct nvmet_ctrl *ctrl;
 
mutex_lock(>lock);
if (!ns->enabled)
@@ -368,9 +388,7 @@ void nvmet_ns_disable(struct nvmet_ns *ns)
percpu_ref_exit(>ref);
 
mutex_lock(>lock);
-   list_for_each_entry(ctrl, >ctrls, subsys_entry)
-   nvmet_add_async_event(ctrl, NVME_AER_TYPE_NOTICE, 0, 0);
-
+   nvmet_ns_changed(subsys, ns->nsid);
nvmet_ns_dev_disable(ns);
 out_unlock:
mutex_unlock(>lock);
@@ -832,11 +850,16 @@ u16 nvmet_alloc_ctrl(const char *subsysnqn, const char 
*hostnqn,
kref_init(>ref);
ctrl->subsys = subsys;
 
+   ctrl->changed_ns_list = kmalloc_array(NVME_MAX_CHANGED_NAMESPACES,
+   sizeof(__le32), GFP_KERNEL);
+   if (!ctrl->changed_ns_list)
+   goto out_free_ctrl;
+
ctrl->cqs = kcalloc(subsys->max_qid + 1,
sizeof(struct nvmet_cq *),
GFP_KERNEL);
if (!ctrl->cqs)
-   goto out_free_ctrl;
+   goto 

[PATCH 13/14] nvme: use the changed namespaces list log to clear ns data changed AENs

2018-05-26 Thread Christoph Hellwig
Per section 5.2 we need to issue the corresponding log page to clear an
AEN, so for a namespace data changed AEN we need to read the changed
namespace list log.  And once we read that log anyway we might as well
use it to optimize the rescan.

Signed-off-by: Christoph Hellwig 
---
 drivers/nvme/host/core.c | 51 
 drivers/nvme/host/nvme.h |  2 ++
 2 files changed, 49 insertions(+), 4 deletions(-)

diff --git a/drivers/nvme/host/core.c b/drivers/nvme/host/core.c
index 06cd04dcffbc..1ae77428a1a5 100644
--- a/drivers/nvme/host/core.c
+++ b/drivers/nvme/host/core.c
@@ -3194,6 +3194,42 @@ static void nvme_scan_ns_sequential(struct nvme_ctrl 
*ctrl, unsigned nn)
nvme_remove_invalid_namespaces(ctrl, nn);
 }
 
+static bool nvme_scan_changed_ns_log(struct nvme_ctrl *ctrl)
+{
+   size_t log_size = NVME_MAX_CHANGED_NAMESPACES * sizeof(__le32);
+   __le32 *log;
+   int error, i;
+   bool ret = false;
+
+   log = kzalloc(log_size, GFP_KERNEL);
+   if (!log)
+   return false;
+
+   error = nvme_get_log(ctrl, NVME_LOG_CHANGED_NS, log, log_size);
+   if (error) {
+   dev_warn(ctrl->device,
+   "reading changed ns log failed: %d\n", error);
+   goto out_free_log;
+   }
+
+   if (log[0] == cpu_to_le32(0x))
+   goto out_free_log;
+
+   for (i = 0; i < NVME_MAX_CHANGED_NAMESPACES; i++) {
+   u32 nsid = le32_to_cpu(log[i]);
+
+   if (nsid == 0)
+   break;
+   dev_info(ctrl->device, "rescanning namespace %d.\n", nsid);
+   nvme_validate_ns(ctrl, nsid);
+   }
+   ret = true;
+
+out_free_log:
+   kfree(log);
+   return ret;
+}
+
 static void nvme_scan_work(struct work_struct *work)
 {
struct nvme_ctrl *ctrl =
@@ -3206,6 +3242,12 @@ static void nvme_scan_work(struct work_struct *work)
 
WARN_ON_ONCE(!ctrl->tagset);
 
+   if (test_and_clear_bit(EVENT_NS_CHANGED, >events)) {
+   if (nvme_scan_changed_ns_log(ctrl))
+   goto out_sort_namespaces;
+   dev_info(ctrl->device, "rescanning namespaces.\n");
+   }
+
if (nvme_identify_ctrl(ctrl, ))
return;
 
@@ -3213,14 +3255,15 @@ static void nvme_scan_work(struct work_struct *work)
if (ctrl->vs >= NVME_VS(1, 1, 0) &&
!(ctrl->quirks & NVME_QUIRK_IDENTIFY_CNS)) {
if (!nvme_scan_ns_list(ctrl, nn))
-   goto done;
+   goto out_free_id;
}
nvme_scan_ns_sequential(ctrl, nn);
- done:
+out_free_id:
+   kfree(id);
+out_sort_namespaces:
down_write(>namespaces_rwsem);
list_sort(NULL, >namespaces, ns_cmp);
up_write(>namespaces_rwsem);
-   kfree(id);
 }
 
 /*
@@ -3340,7 +3383,7 @@ static void nvme_handle_aen_notice(struct nvme_ctrl 
*ctrl, u32 result)
 {
switch ((result & 0xff00) >> 8) {
case NVME_AER_NOTICE_NS_CHANGED:
-   dev_info(ctrl->device, "rescanning\n");
+   set_bit(EVENT_NS_CHANGED, >events);
nvme_queue_scan(ctrl);
break;
case NVME_AER_NOTICE_FW_ACT_STARTING:
diff --git a/drivers/nvme/host/nvme.h b/drivers/nvme/host/nvme.h
index 11681278fdf6..07e8bfe705c6 100644
--- a/drivers/nvme/host/nvme.h
+++ b/drivers/nvme/host/nvme.h
@@ -189,6 +189,8 @@ struct nvme_ctrl {
struct delayed_work ka_work;
struct nvme_command ka_cmd;
struct work_struct fw_act_work;
+#define EVENT_NS_CHANGED   (1 << 0)
+   unsigned long events;
 
/* Power saving configuration */
u64 ps_max_latency_us;
-- 
2.17.0



[PATCH 14/14] nvme: limit warnings from nvme_identify_ns

2018-05-26 Thread Christoph Hellwig
When rescanning namespaces after an AEN we will issue Identify Namespace
comands to namespaces that have gone away, so don't warn for this specific
case.

Signed-off-by: Christoph Hellwig 
---
 drivers/nvme/host/core.c | 4 +++-
 1 file changed, 3 insertions(+), 1 deletion(-)

diff --git a/drivers/nvme/host/core.c b/drivers/nvme/host/core.c
index 1ae77428a1a5..7ad3cfc9d4e1 100644
--- a/drivers/nvme/host/core.c
+++ b/drivers/nvme/host/core.c
@@ -984,7 +984,9 @@ static struct nvme_id_ns *nvme_identify_ns(struct nvme_ctrl 
*ctrl,
 
error = nvme_submit_sync_cmd(ctrl->admin_q, , id, sizeof(*id));
if (error) {
-   dev_warn(ctrl->device, "Identify namespace failed\n");
+   /* don't warn on a namespace that has gone away */
+   if (error < 0 || ((error & ~NVME_SC_DNR) != NVME_SC_INVALID_NS))
+   dev_warn(ctrl->device, "Identify namespace failed\n");
kfree(id);
return NULL;
}
-- 
2.17.0



[PATCH 07/14] nvmet: split log page implementation

2018-05-26 Thread Christoph Hellwig
Remove the common code to allocate a buffer and copy it into the SGL.
Instead the two no-op implementations just zero the SGL directly, and
the smart log allocates a buffer on its own.  This prepares for the
more elaborate ANA log page.

Signed-off-by: Christoph Hellwig 
---
 drivers/nvme/target/admin-cmd.c | 99 -
 1 file changed, 36 insertions(+), 63 deletions(-)

diff --git a/drivers/nvme/target/admin-cmd.c b/drivers/nvme/target/admin-cmd.c
index b2ba95b2eef7..e96bb02c4f2c 100644
--- a/drivers/nvme/target/admin-cmd.c
+++ b/drivers/nvme/target/admin-cmd.c
@@ -32,6 +32,11 @@ u32 nvmet_get_log_page_len(struct nvme_command *cmd)
return len;
 }
 
+static void nvmet_execute_get_log_page_noop(struct nvmet_req *req)
+{
+   nvmet_req_complete(req, nvmet_zero_sgl(req, 0, req->data_len));
+}
+
 static u16 nvmet_get_smart_log_nsid(struct nvmet_req *req,
struct nvme_smart_log *slog)
 {
@@ -97,74 +102,26 @@ static u16 nvmet_get_smart_log_all(struct nvmet_req *req,
return NVME_SC_SUCCESS;
 }
 
-static u16 nvmet_get_smart_log(struct nvmet_req *req,
-   struct nvme_smart_log *slog)
-{
-   u16 status;
-
-   WARN_ON(req == NULL || slog == NULL);
-   if (req->cmd->get_log_page.nsid == cpu_to_le32(NVME_NSID_ALL))
-   status = nvmet_get_smart_log_all(req, slog);
-   else
-   status = nvmet_get_smart_log_nsid(req, slog);
-   return status;
-}
-
-static void nvmet_execute_get_log_page(struct nvmet_req *req)
+static void nvmet_execute_get_log_page_smart(struct nvmet_req *req)
 {
-   struct nvme_smart_log *smart_log;
-   size_t data_len = nvmet_get_log_page_len(req->cmd);
-   void *buf;
-   u16 status = 0;
+   struct nvme_smart_log *log;
+   u16 status = NVME_SC_INTERNAL;
 
-   buf = kzalloc(data_len, GFP_KERNEL);
-   if (!buf) {
-   status = NVME_SC_INTERNAL;
+   if (req->data_len != sizeof(*log))
goto out;
-   }
 
-   switch (req->cmd->get_log_page.lid) {
-   case NVME_LOG_ERROR:
-   /*
-* We currently never set the More bit in the status field,
-* so all error log entries are invalid and can be zeroed out.
-* This is called a minum viable implementation (TM) of this
-* mandatory log page.
-*/
-   break;
-   case NVME_LOG_SMART:
-   /*
-* XXX: fill out actual smart log
-*
-* We might have a hard time coming up with useful values for
-* many of the fields, and even when we have useful data
-* available (e.g. units or commands read/written) those aren't
-* persistent over power loss.
-*/
-   if (data_len != sizeof(*smart_log)) {
-   status = NVME_SC_INTERNAL;
-   goto err;
-   }
-   smart_log = buf;
-   status = nvmet_get_smart_log(req, smart_log);
-   if (status)
-   goto err;
-   break;
-   case NVME_LOG_FW_SLOT:
-   /*
-* We only support a single firmware slot which always is
-* active, so we can zero out the whole firmware slot log and
-* still claim to fully implement this mandatory log page.
-*/
-   break;
-   default:
-   BUG();
-   }
+   log = kzalloc(sizeof(*log), GFP_KERNEL);
+   if (!log)
+   goto out;
 
-   status = nvmet_copy_to_sgl(req, 0, buf, data_len);
+   if (req->cmd->get_log_page.nsid == cpu_to_le32(NVME_NSID_ALL))
+   status = nvmet_get_smart_log_all(req, log);
+   else
+   status = nvmet_get_smart_log_nsid(req, log);
+   if (status)
+   goto out;
 
-err:
-   kfree(buf);
+   status = nvmet_copy_to_sgl(req, 0, log, sizeof(*log));
 out:
nvmet_req_complete(req, status);
 }
@@ -566,9 +523,25 @@ u16 nvmet_parse_admin_cmd(struct nvmet_req *req)
 
switch (cmd->get_log_page.lid) {
case NVME_LOG_ERROR:
+   /*
+* We currently never set the More bit in the status
+* field, so all error log entries are invalid and can
+* be zeroed out.  This is called a minum viable
+* implementation (TM) of this mandatory log page.
+*/
+   req->execute = nvmet_execute_get_log_page_noop;
+   return 0;
case NVME_LOG_SMART:
+   req->execute = nvmet_execute_get_log_page_smart;
+   return 0;
case NVME_LOG_FW_SLOT:
-   req->execute = nvmet_execute_get_log_page;
+

[PATCH 12/14] nvme: mark nvme_queue_scan static

2018-05-26 Thread Christoph Hellwig
And move it toward the top of the file to avoid a forward declaration.

Signed-off-by: Christoph Hellwig 
---
 drivers/nvme/host/core.c | 19 +--
 drivers/nvme/host/nvme.h |  1 -
 2 files changed, 9 insertions(+), 11 deletions(-)

diff --git a/drivers/nvme/host/core.c b/drivers/nvme/host/core.c
index c0bc76d98194..06cd04dcffbc 100644
--- a/drivers/nvme/host/core.c
+++ b/drivers/nvme/host/core.c
@@ -100,6 +100,15 @@ static struct class *nvme_subsys_class;
 static void nvme_ns_remove(struct nvme_ns *ns);
 static int nvme_revalidate_disk(struct gendisk *disk);
 
+static void nvme_queue_scan(struct nvme_ctrl *ctrl)
+{
+   /*
+* Only new queue scan work when admin and IO queues are both alive
+*/
+   if (ctrl->state == NVME_CTRL_LIVE)
+   queue_work(nvme_wq, >scan_work);
+}
+
 int nvme_reset_ctrl(struct nvme_ctrl *ctrl)
 {
if (!nvme_change_ctrl_state(ctrl, NVME_CTRL_RESETTING))
@@ -3214,16 +3223,6 @@ static void nvme_scan_work(struct work_struct *work)
kfree(id);
 }
 
-void nvme_queue_scan(struct nvme_ctrl *ctrl)
-{
-   /*
-* Only new queue scan work when admin and IO queues are both alive
-*/
-   if (ctrl->state == NVME_CTRL_LIVE)
-   queue_work(nvme_wq, >scan_work);
-}
-EXPORT_SYMBOL_GPL(nvme_queue_scan);
-
 /*
  * This function iterates the namespace list unlocked to allow recovery from
  * controller failure. It is up to the caller to ensure the namespace list is
diff --git a/drivers/nvme/host/nvme.h b/drivers/nvme/host/nvme.h
index dcf9e9592c1a..11681278fdf6 100644
--- a/drivers/nvme/host/nvme.h
+++ b/drivers/nvme/host/nvme.h
@@ -395,7 +395,6 @@ void nvme_stop_ctrl(struct nvme_ctrl *ctrl);
 void nvme_put_ctrl(struct nvme_ctrl *ctrl);
 int nvme_init_identify(struct nvme_ctrl *ctrl);
 
-void nvme_queue_scan(struct nvme_ctrl *ctrl);
 void nvme_remove_namespaces(struct nvme_ctrl *ctrl);
 
 int nvme_sec_submit(void *data, u16 spsp, u8 secp, void *buffer, size_t len,
-- 
2.17.0



[PATCH 11/14] nvme: submit AEN event configuration on startup

2018-05-26 Thread Christoph Hellwig
From: Hannes Reinecke 

We should register for AEN events; some law-abiding targets might
not be sending us AENs otherwise.

Signed-off-by: Hannes Reinecke 
[hch: slight cleanups]
Signed-off-by: Christoph Hellwig 
---
 drivers/nvme/host/core.c | 17 +
 drivers/nvme/host/nvme.h |  1 +
 2 files changed, 18 insertions(+)

diff --git a/drivers/nvme/host/core.c b/drivers/nvme/host/core.c
index 86cb78653155..c0bc76d98194 100644
--- a/drivers/nvme/host/core.c
+++ b/drivers/nvme/host/core.c
@@ -1030,6 +1030,21 @@ int nvme_set_queue_count(struct nvme_ctrl *ctrl, int 
*count)
 }
 EXPORT_SYMBOL_GPL(nvme_set_queue_count);
 
+#define NVME_AEN_SUPPORTED \
+   (NVME_AEN_CFG_NS_ATTR | NVME_AEN_CFG_FW_ACT)
+
+static void nvme_enable_aen(struct nvme_ctrl *ctrl)
+{
+   u32 result;
+   int status;
+
+   status = nvme_set_features(ctrl, NVME_FEAT_ASYNC_EVENT,
+   ctrl->oaes & NVME_AEN_SUPPORTED, NULL, 0, );
+   if (status)
+   dev_warn(ctrl->device, "Failed to configure AEN (cfg %x)\n",
+ctrl->oaes & NVME_AEN_SUPPORTED);
+}
+
 static int nvme_submit_io(struct nvme_ns *ns, struct nvme_user_io __user *uio)
 {
struct nvme_user_io io;
@@ -2347,6 +2362,7 @@ int nvme_init_identify(struct nvme_ctrl *ctrl)
 
ctrl->oacs = le16_to_cpu(id->oacs);
ctrl->oncs = le16_to_cpup(>oncs);
+   ctrl->oaes = le32_to_cpu(id->oaes);
atomic_set(>abort_limit, id->acl + 1);
ctrl->vwc = id->vwc;
ctrl->cntlid = le16_to_cpup(>cntlid);
@@ -3379,6 +3395,7 @@ void nvme_start_ctrl(struct nvme_ctrl *ctrl)
 
if (ctrl->queue_count > 1) {
nvme_queue_scan(ctrl);
+   nvme_enable_aen(ctrl);
queue_work(nvme_wq, >async_event_work);
nvme_start_queues(ctrl);
}
diff --git a/drivers/nvme/host/nvme.h b/drivers/nvme/host/nvme.h
index ec6e4acc4d48..dcf9e9592c1a 100644
--- a/drivers/nvme/host/nvme.h
+++ b/drivers/nvme/host/nvme.h
@@ -176,6 +176,7 @@ struct nvme_ctrl {
u16 kas;
u8 npss;
u8 apsta;
+   u32 oaes;
u32 aen_result;
unsigned int shutdown_timeout;
unsigned int kato;
-- 
2.17.0



[PATCH 09/14] nvmet: Add AEN configuration support

2018-05-26 Thread Christoph Hellwig
From: Hannes Reinecke 

AEN configuration via the 'Get Features' and 'Set Features' admin
command is mandatory, so we should be implemeting handling for it.

Signed-off-by: Hannes Reinecke 
[hch: use WRITE_ONCE, check for invalid values]
Signed-off-by: Christoph Hellwig 
---
 drivers/nvme/target/admin-cmd.c | 13 -
 drivers/nvme/target/core.c  |  3 +++
 drivers/nvme/target/nvmet.h |  3 +++
 3 files changed, 18 insertions(+), 1 deletion(-)

diff --git a/drivers/nvme/target/admin-cmd.c b/drivers/nvme/target/admin-cmd.c
index 82d521f60a43..20d9ce5064f8 100644
--- a/drivers/nvme/target/admin-cmd.c
+++ b/drivers/nvme/target/admin-cmd.c
@@ -432,6 +432,16 @@ static void nvmet_execute_set_features(struct nvmet_req 
*req)
req->sq->ctrl->kato = DIV_ROUND_UP(val32, 1000);
nvmet_set_result(req, req->sq->ctrl->kato);
break;
+   case NVME_FEAT_ASYNC_EVENT:
+   val32 = le32_to_cpu(req->cmd->common.cdw10[1]);
+   if (val32 & ~NVMET_AEN_SUPPORTED) {
+   status = NVME_SC_INVALID_FIELD | NVME_SC_DNR;
+   break;
+   }
+
+   WRITE_ONCE(req->sq->ctrl->aen_enabled, val32);
+   nvmet_set_result(req, val32);
+   break;
case NVME_FEAT_HOST_ID:
status = NVME_SC_CMD_SEQ_ERROR | NVME_SC_DNR;
break;
@@ -470,9 +480,10 @@ static void nvmet_execute_get_features(struct nvmet_req 
*req)
break;
case NVME_FEAT_WRITE_ATOMIC:
break;
+#endif
case NVME_FEAT_ASYNC_EVENT:
+   nvmet_set_result(req, READ_ONCE(req->sq->ctrl->aen_enabled));
break;
-#endif
case NVME_FEAT_VOLATILE_WC:
nvmet_set_result(req, 1);
break;
diff --git a/drivers/nvme/target/core.c b/drivers/nvme/target/core.c
index 424ad41af980..53e2386b73cf 100644
--- a/drivers/nvme/target/core.c
+++ b/drivers/nvme/target/core.c
@@ -162,6 +162,8 @@ static void nvmet_ns_changed(struct nvmet_subsys *subsys, 
u32 nsid)
 
list_for_each_entry(ctrl, >ctrls, subsys_entry) {
nvmet_add_to_changed_ns_log(ctrl, nsid);
+   if (!(READ_ONCE(ctrl->aen_enabled) & NVME_AEN_CFG_NS_ATTR))
+   continue;
nvmet_add_async_event(ctrl, NVME_AER_TYPE_NOTICE,
NVME_AER_NOTICE_NS_CHANGED,
NVME_LOG_CHANGED_NS);
@@ -849,6 +851,7 @@ u16 nvmet_alloc_ctrl(const char *subsysnqn, const char 
*hostnqn,
 
kref_init(>ref);
ctrl->subsys = subsys;
+   WRITE_ONCE(ctrl->aen_enabled, NVMET_AEN_SUPPORTED);
 
ctrl->changed_ns_list = kmalloc_array(NVME_MAX_CHANGED_NAMESPACES,
sizeof(__le32), GFP_KERNEL);
diff --git a/drivers/nvme/target/nvmet.h b/drivers/nvme/target/nvmet.h
index bcd88b5c9d99..50c8300ea572 100644
--- a/drivers/nvme/target/nvmet.h
+++ b/drivers/nvme/target/nvmet.h
@@ -30,6 +30,8 @@
 #define NVMET_ASYNC_EVENTS 4
 #define NVMET_ERROR_LOG_SLOTS  128
 
+#define NVMET_AEN_SUPPORTEDNVME_AEN_CFG_NS_ATTR
+
 /* 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
  * offset starts in the data section of connect()
@@ -123,6 +125,7 @@ struct nvmet_ctrl {
u16 cntlid;
u32 kato;
 
+   u32 aen_enabled;
struct nvmet_req*async_event_cmds[NVMET_ASYNC_EVENTS];
unsigned intnr_async_event_cmds;
struct list_headasync_events;
-- 
2.17.0



[PATCH 04/14] nvme.h: add the changed namespace list log

2018-05-26 Thread Christoph Hellwig
Signed-off-by: Christoph Hellwig 
---
 include/linux/nvme.h | 3 +++
 1 file changed, 3 insertions(+)

diff --git a/include/linux/nvme.h b/include/linux/nvme.h
index c37103a4ad38..7ce0f3cf4409 100644
--- a/include/linux/nvme.h
+++ b/include/linux/nvme.h
@@ -751,6 +751,7 @@ enum {
NVME_LOG_ERROR  = 0x01,
NVME_LOG_SMART  = 0x02,
NVME_LOG_FW_SLOT= 0x03,
+   NVME_LOG_CHANGED_NS = 0x04,
NVME_LOG_CMD_EFFECTS= 0x05,
NVME_LOG_DISC   = 0x70,
NVME_LOG_RESERVATION= 0x80,
@@ -759,6 +760,8 @@ enum {
NVME_FWACT_ACTV = (2 << 3),
 };
 
+#define NVME_MAX_CHANGED_NAMESPACES1024
+
 struct nvme_identify {
__u8opcode;
__u8flags;
-- 
2.17.0



[PATCH 03/14] nvme.h: untangle AEN notice definitions

2018-05-26 Thread Christoph Hellwig
Stop including the event type in the definitions for the notice type.

Signed-off-by: Christoph Hellwig 
---
 drivers/nvme/host/core.c | 30 ++
 include/linux/nvme.h |  8 ++--
 2 files changed, 24 insertions(+), 14 deletions(-)

diff --git a/drivers/nvme/host/core.c b/drivers/nvme/host/core.c
index 2c4cf65641a6..86cb78653155 100644
--- a/drivers/nvme/host/core.c
+++ b/drivers/nvme/host/core.c
@@ -3321,6 +3321,21 @@ static void nvme_fw_act_work(struct work_struct *work)
nvme_get_fw_slot_info(ctrl);
 }
 
+static void nvme_handle_aen_notice(struct nvme_ctrl *ctrl, u32 result)
+{
+   switch ((result & 0xff00) >> 8) {
+   case NVME_AER_NOTICE_NS_CHANGED:
+   dev_info(ctrl->device, "rescanning\n");
+   nvme_queue_scan(ctrl);
+   break;
+   case NVME_AER_NOTICE_FW_ACT_STARTING:
+   queue_work(nvme_wq, >fw_act_work);
+   break;
+   default:
+   dev_warn(ctrl->device, "async event result %08x\n", result);
+   }
+}
+
 void nvme_complete_async_event(struct nvme_ctrl *ctrl, __le16 status,
volatile union nvme_result *res)
 {
@@ -3330,6 +3345,9 @@ void nvme_complete_async_event(struct nvme_ctrl *ctrl, 
__le16 status,
return;
 
switch (result & 0x7) {
+   case NVME_AER_NOTICE:
+   nvme_handle_aen_notice(ctrl, result);
+   break;
case NVME_AER_ERROR:
case NVME_AER_SMART:
case NVME_AER_CSS:
@@ -3339,18 +3357,6 @@ void nvme_complete_async_event(struct nvme_ctrl *ctrl, 
__le16 status,
default:
break;
}
-
-   switch (result & 0xff07) {
-   case NVME_AER_NOTICE_NS_CHANGED:
-   dev_info(ctrl->device, "rescanning\n");
-   nvme_queue_scan(ctrl);
-   break;
-   case NVME_AER_NOTICE_FW_ACT_STARTING:
-   queue_work(nvme_wq, >fw_act_work);
-   break;
-   default:
-   dev_warn(ctrl->device, "async event result %08x\n", result);
-   }
queue_work(nvme_wq, >async_event_work);
 }
 EXPORT_SYMBOL_GPL(nvme_complete_async_event);
diff --git a/include/linux/nvme.h b/include/linux/nvme.h
index 4112e2bd747f..c37103a4ad38 100644
--- a/include/linux/nvme.h
+++ b/include/linux/nvme.h
@@ -436,10 +436,14 @@ enum {
 enum {
NVME_AER_ERROR  = 0,
NVME_AER_SMART  = 1,
+   NVME_AER_NOTICE = 2,
NVME_AER_CSS= 6,
NVME_AER_VS = 7,
-   NVME_AER_NOTICE_NS_CHANGED  = 0x0002,
-   NVME_AER_NOTICE_FW_ACT_STARTING = 0x0102,
+};
+
+enum {
+   NVME_AER_NOTICE_NS_CHANGED  = 0x00,
+   NVME_AER_NOTICE_FW_ACT_STARTING = 0x01,
 };
 
 struct nvme_lba_range_type {
-- 
2.17.0



nvme/nvmet AEN and log page fixups

2018-05-26 Thread Christoph Hellwig
Hi all,

this series started as prep work for ANA, but has grown a lot.

The idea is to make the AEN handling in the target closer to what
the standard says, and implement the changed namespaces list log page,
which is required to clear the namespace attribute notice event.

One the host side this just makes sure we actually have the events
we handle enabled using Set Features, and it fixes the handling of
the namespace attribute notice event so that it actually does get
cleared by issuing the log page.

Last but not last two block cleanups are thrown in so that we don't
print a pointless message when we delete a namespaces, and also
unexport the function printing said message as it should only be
called from the core code.


[PATCH 06/14] nvmet: add a new nvmet_zero_sgl helper

2018-05-26 Thread Christoph Hellwig
Zeroes the SGL in the payload.

Signed-off-by: Christoph Hellwig 
---
 drivers/nvme/target/core.c  | 7 +++
 drivers/nvme/target/nvmet.h | 1 +
 2 files changed, 8 insertions(+)

diff --git a/drivers/nvme/target/core.c b/drivers/nvme/target/core.c
index 800aaf96ddcd..55c4bc693aa2 100644
--- a/drivers/nvme/target/core.c
+++ b/drivers/nvme/target/core.c
@@ -57,6 +57,13 @@ u16 nvmet_copy_from_sgl(struct nvmet_req *req, off_t off, 
void *buf, size_t len)
return 0;
 }
 
+u16 nvmet_zero_sgl(struct nvmet_req *req, off_t off, size_t len)
+{
+   if (sg_zero_buffer(req->sg, req->sg_cnt, len, off) != len)
+   return NVME_SC_SGL_INVALID_DATA | NVME_SC_DNR;
+   return 0;
+}
+
 static unsigned int nvmet_max_nsid(struct nvmet_subsys *subsys)
 {
struct nvmet_ns *ns;
diff --git a/drivers/nvme/target/nvmet.h b/drivers/nvme/target/nvmet.h
index 2d09afcfe505..a4e14eb15d4e 100644
--- a/drivers/nvme/target/nvmet.h
+++ b/drivers/nvme/target/nvmet.h
@@ -330,6 +330,7 @@ u16 nvmet_copy_to_sgl(struct nvmet_req *req, off_t off, 
const void *buf,
size_t len);
 u16 nvmet_copy_from_sgl(struct nvmet_req *req, off_t off, void *buf,
size_t len);
+u16 nvmet_zero_sgl(struct nvmet_req *req, off_t off, size_t len);
 
 u32 nvmet_get_log_page_len(struct nvme_command *cmd);
 
-- 
2.17.0



[PATCH 01/14] block: unexport check_disk_size_change

2018-05-26 Thread Christoph Hellwig
Only used in block_dev.c and the partitions code, and it should remain
that way..

Signed-off-by: Christoph Hellwig 
---
 fs/block_dev.c | 1 -
 1 file changed, 1 deletion(-)

diff --git a/fs/block_dev.c b/fs/block_dev.c
index 7ec920e27065..771ddfa29dc9 100644
--- a/fs/block_dev.c
+++ b/fs/block_dev.c
@@ -1342,7 +1342,6 @@ void check_disk_size_change(struct gendisk *disk, struct 
block_device *bdev)
flush_disk(bdev, false);
}
 }
-EXPORT_SYMBOL(check_disk_size_change);
 
 /**
  * revalidate_disk - wrapper for lower-level driver's revalidate_disk call-back
-- 
2.17.0



[PATCH 05/14] nvme.h: add AER configuration symbols

2018-05-26 Thread Christoph Hellwig
From: Hannes Reinecke 

Signed-off-by: Hannes Reinecke 
[hch: split from a larger patch]
Signed-off-by: Christoph Hellwig 
---
 include/linux/nvme.h | 5 +
 1 file changed, 5 insertions(+)

diff --git a/include/linux/nvme.h b/include/linux/nvme.h
index 7ce0f3cf4409..2950ce957656 100644
--- a/include/linux/nvme.h
+++ b/include/linux/nvme.h
@@ -446,6 +446,11 @@ enum {
NVME_AER_NOTICE_FW_ACT_STARTING = 0x01,
 };
 
+enum {
+   NVME_AEN_CFG_NS_ATTR= 1 << 8,
+   NVME_AEN_CFG_FW_ACT = 1 << 9,
+};
+
 struct nvme_lba_range_type {
__u8type;
__u8attributes;
-- 
2.17.0



[PATCH 02/14] block: don't print a message when the device went away

2018-05-26 Thread Christoph Hellwig
The information about a size change in this case just creates confusion.

Signed-off-by: Christoph Hellwig 
---
 block/partition-generic.c |  4 ++--
 fs/block_dev.c| 14 +-
 include/linux/fs.h|  2 +-
 3 files changed, 12 insertions(+), 8 deletions(-)

diff --git a/block/partition-generic.c b/block/partition-generic.c
index db57cced9b98..9fe4816a1289 100644
--- a/block/partition-generic.c
+++ b/block/partition-generic.c
@@ -518,7 +518,7 @@ int rescan_partitions(struct gendisk *disk, struct 
block_device *bdev)
 
if (disk->fops->revalidate_disk)
disk->fops->revalidate_disk(disk);
-   check_disk_size_change(disk, bdev);
+   check_disk_size_change(disk, bdev, true);
bdev->bd_invalidated = 0;
if (!get_capacity(disk) || !(state = check_partition(disk, bdev)))
return 0;
@@ -643,7 +643,7 @@ int invalidate_partitions(struct gendisk *disk, struct 
block_device *bdev)
return res;
 
set_capacity(disk, 0);
-   check_disk_size_change(disk, bdev);
+   check_disk_size_change(disk, bdev, false);
bdev->bd_invalidated = 0;
/* tell userspace that the media / partition table may have changed */
kobject_uevent(_to_dev(disk)->kobj, KOBJ_CHANGE);
diff --git a/fs/block_dev.c b/fs/block_dev.c
index 771ddfa29dc9..81c57c14fae8 100644
--- a/fs/block_dev.c
+++ b/fs/block_dev.c
@@ -1322,21 +1322,25 @@ static void flush_disk(struct block_device *bdev, bool 
kill_dirty)
  * check_disk_size_change - checks for disk size change and adjusts bdev size.
  * @disk: struct gendisk to check
  * @bdev: struct bdev to adjust.
+ * @verbose: if %true log a message about a size change if there is any
  *
  * This routine checks to see if the bdev size does not match the disk size
  * and adjusts it if it differs. When shrinking the bdev size, its all caches
  * are freed.
  */
-void check_disk_size_change(struct gendisk *disk, struct block_device *bdev)
+void check_disk_size_change(struct gendisk *disk, struct block_device *bdev,
+   bool verbose)
 {
loff_t disk_size, bdev_size;
 
disk_size = (loff_t)get_capacity(disk) << 9;
bdev_size = i_size_read(bdev->bd_inode);
if (disk_size != bdev_size) {
-   printk(KERN_INFO
-  "%s: detected capacity change from %lld to %lld\n",
-  disk->disk_name, bdev_size, disk_size);
+   if (verbose) {
+   printk(KERN_INFO
+  "%s: detected capacity change from %lld to 
%lld\n",
+  disk->disk_name, bdev_size, disk_size);
+   }
i_size_write(bdev->bd_inode, disk_size);
if (bdev_size > disk_size)
flush_disk(bdev, false);
@@ -1363,7 +1367,7 @@ int revalidate_disk(struct gendisk *disk)
return ret;
 
mutex_lock(>bd_mutex);
-   check_disk_size_change(disk, bdev);
+   check_disk_size_change(disk, bdev, ret == 0);
bdev->bd_invalidated = 0;
mutex_unlock(>bd_mutex);
bdput(bdev);
diff --git a/include/linux/fs.h b/include/linux/fs.h
index 760d8da1b6c7..d8d4831af9ff 100644
--- a/include/linux/fs.h
+++ b/include/linux/fs.h
@@ -2570,7 +2570,7 @@ extern bool is_bad_inode(struct inode *);
 
 #ifdef CONFIG_BLOCK
 extern void check_disk_size_change(struct gendisk *disk,
-  struct block_device *bdev);
+   struct block_device *bdev, bool verbose);
 extern int revalidate_disk(struct gendisk *);
 extern int check_disk_change(struct block_device *);
 extern int __invalidate_device(struct block_device *, bool);
-- 
2.17.0