@@ -203,6 +203,7 @@ struct nvme_tcp_ctrl {
static LIST_HEAD(nvme_tcp_ctrl_list);
static DEFINE_MUTEX(nvme_tcp_ctrl_mutex);
+static struct notifier_block nvme_tcp_netdevice_nb;
static struct workqueue_struct *nvme_tcp_wq;
static const struct blk_mq_ops nvme_tcp_mq_ops;
static const struct blk_mq_ops nvme_tcp_admin_mq_ops;
@@ -3126,6 +3127,31 @@ static struct nvme_ctrl *nvme_tcp_create_ctrl(struct device *dev,
return ERR_PTR(ret);
}
+static int nvme_tcp_netdev_event(struct notifier_block *this,
+ unsigned long event, void *ptr)
+{
+ struct net_device *ndev = netdev_notifier_info_to_dev(ptr);
+ struct nvme_tcp_ctrl *ctrl;
+
+ switch (event) {
+ case NETDEV_GOING_DOWN:
+ mutex_lock(&nvme_tcp_ctrl_mutex);
+ list_for_each_entry(ctrl, &nvme_tcp_ctrl_list, list) {
+ if (ndev != ctrl->offloading_netdev)
+ continue;
+ nvme_tcp_error_recovery(&ctrl->ctrl);
+ }
+ mutex_unlock(&nvme_tcp_ctrl_mutex);
+ flush_workqueue(nvme_reset_wq);
+ /*
+ * The associated controllers teardown has completed,
+ * ddp contexts were also torn down so we should be
+ * safe to continue...
+ */
+ }
+ return NOTIFY_DONE;
+}
+
static struct nvmf_transport_ops nvme_tcp_transport = {
.name = "tcp",
.module = THIS_MODULE,
@@ -3140,13 +3166,26 @@ static struct nvmf_transport_ops nvme_tcp_transport = {
static int __init nvme_tcp_init_module(void)
{
+ int ret;
+
nvme_tcp_wq = alloc_workqueue("nvme_tcp_wq",
WQ_MEM_RECLAIM | WQ_HIGHPRI, 0);
if (!nvme_tcp_wq)
return -ENOMEM;
+ nvme_tcp_netdevice_nb.notifier_call = nvme_tcp_netdev_event;
+ ret = register_netdevice_notifier(&nvme_tcp_netdevice_nb);
+ if (ret) {
+ pr_err("failed to register netdev notifier\n");
+ goto out_free_workqueue;
+ }
+
nvmf_register_transport(&nvme_tcp_transport);
return 0;
+
+out_free_workqueue:
+ destroy_workqueue(nvme_tcp_wq);
+ return ret;
}
static void __exit nvme_tcp_cleanup_module(void)
@@ -3154,6 +3193,7 @@ static void __exit nvme_tcp_cleanup_module(void)
struct nvme_tcp_ctrl *ctrl;
nvmf_unregister_transport(&nvme_tcp_transport);
+ unregister_netdevice_notifier(&nvme_tcp_netdevice_nb);
mutex_lock(&nvme_tcp_ctrl_mutex);
list_for_each_entry(ctrl, &nvme_tcp_ctrl_list, list)