Skip to content

Commit

Permalink
virtio scsi: Convert to hotplug state machine
Browse files Browse the repository at this point in the history
Install the callbacks via the state machine. It uses the multi instance
infrastructure of the hotplug code to handle each interface.

virtscsi_set_affinity() is removed from virtscsi_init() because
virtscsi_cpu_notif_add() (the function which registers the instance) is invoked
right after it and the cpuhp_state_add_instance() functions invokes the startup
callback on all online CPUs.

The same thing can not be applied virtscsi_cpu_notif_remove() because
virtscsi_remove_vqs() invokes virtscsi_set_affinity() with affinity = false as
argument but the old CPU_DEAD state invoked the function with affinity = true
(which does not match the DEAD callback).

Signed-off-by: Sebastian Andrzej Siewior <bigeasy@linutronix.de>
Cc: "James E.J. Bottomley" <jejb@linux.vnet.ibm.com>
Cc: linux-scsi@vger.kernel.org
Cc: "Martin K. Petersen" <martin.petersen@oracle.com>
Cc: "Michael S. Tsirkin" <mst@redhat.com>
Cc: Peter Zijlstra <peterz@infradead.org>
Cc: virtualization@lists.linux-foundation.org
Cc: rt@linutronix.de
Link: http://lkml.kernel.org/r/20160906170457.32393-11-bigeasy@linutronix.de
Signed-off-by: Thomas Gleixner <tglx@linutronix.de>
  • Loading branch information
Sebastian Andrzej Siewior authored and Thomas Gleixner committed Sep 19, 2016
1 parent a4e0591 commit 8904f5a
Show file tree
Hide file tree
Showing 2 changed files with 50 additions and 27 deletions.
76 changes: 49 additions & 27 deletions drivers/scsi/virtio_scsi.c
Original file line number Diff line number Diff line change
Expand Up @@ -107,8 +107,8 @@ struct virtio_scsi {
/* If the affinity hint is set for virtqueues */
bool affinity_hint_set;

/* CPU hotplug notifier */
struct notifier_block nb;
struct hlist_node node;
struct hlist_node node_dead;

/* Protected by event_vq lock */
bool stop_events;
Expand All @@ -118,6 +118,7 @@ struct virtio_scsi {
struct virtio_scsi_vq req_vqs[];
};

static enum cpuhp_state virtioscsi_online;
static struct kmem_cache *virtscsi_cmd_cache;
static mempool_t *virtscsi_cmd_pool;

Expand Down Expand Up @@ -852,21 +853,33 @@ static void virtscsi_set_affinity(struct virtio_scsi *vscsi, bool affinity)
put_online_cpus();
}

static int virtscsi_cpu_callback(struct notifier_block *nfb,
unsigned long action, void *hcpu)
static int virtscsi_cpu_online(unsigned int cpu, struct hlist_node *node)
{
struct virtio_scsi *vscsi = container_of(nfb, struct virtio_scsi, nb);
switch(action) {
case CPU_ONLINE:
case CPU_ONLINE_FROZEN:
case CPU_DEAD:
case CPU_DEAD_FROZEN:
__virtscsi_set_affinity(vscsi, true);
break;
default:
break;
}
return NOTIFY_OK;
struct virtio_scsi *vscsi = hlist_entry_safe(node, struct virtio_scsi,
node);
__virtscsi_set_affinity(vscsi, true);
return 0;
}

static int virtscsi_cpu_notif_add(struct virtio_scsi *vi)
{
int ret;

ret = cpuhp_state_add_instance(virtioscsi_online, &vi->node);
if (ret)
return ret;

ret = cpuhp_state_add_instance(CPUHP_VIRT_SCSI_DEAD, &vi->node_dead);
if (ret)
cpuhp_state_remove_instance(virtioscsi_online, &vi->node);
return ret;
}

static void virtscsi_cpu_notif_remove(struct virtio_scsi *vi)
{
cpuhp_state_remove_instance_nocalls(virtioscsi_online, &vi->node);
cpuhp_state_remove_instance_nocalls(CPUHP_VIRT_SCSI_DEAD,
&vi->node_dead);
}

static void virtscsi_init_vq(struct virtio_scsi_vq *virtscsi_vq,
Expand Down Expand Up @@ -929,8 +942,6 @@ static int virtscsi_init(struct virtio_device *vdev,
virtscsi_init_vq(&vscsi->req_vqs[i - VIRTIO_SCSI_VQ_BASE],
vqs[i]);

virtscsi_set_affinity(vscsi, true);

virtscsi_config_set(vdev, cdb_size, VIRTIO_SCSI_CDB_SIZE);
virtscsi_config_set(vdev, sense_size, VIRTIO_SCSI_SENSE_SIZE);

Expand Down Expand Up @@ -987,12 +998,9 @@ static int virtscsi_probe(struct virtio_device *vdev)
if (err)
goto virtscsi_init_failed;

vscsi->nb.notifier_call = &virtscsi_cpu_callback;
err = register_hotcpu_notifier(&vscsi->nb);
if (err) {
pr_err("registering cpu notifier failed\n");
err = virtscsi_cpu_notif_add(vscsi);
if (err)
goto scsi_add_host_failed;
}

cmd_per_lun = virtscsi_config_get(vdev, cmd_per_lun) ?: 1;
shost->cmd_per_lun = min_t(u32, cmd_per_lun, shost->can_queue);
Expand Down Expand Up @@ -1049,7 +1057,7 @@ static void virtscsi_remove(struct virtio_device *vdev)

scsi_remove_host(shost);

unregister_hotcpu_notifier(&vscsi->nb);
virtscsi_cpu_notif_remove(vscsi);

virtscsi_remove_vqs(vdev);
scsi_host_put(shost);
Expand All @@ -1061,7 +1069,7 @@ static int virtscsi_freeze(struct virtio_device *vdev)
struct Scsi_Host *sh = virtio_scsi_host(vdev);
struct virtio_scsi *vscsi = shost_priv(sh);

unregister_hotcpu_notifier(&vscsi->nb);
virtscsi_cpu_notif_remove(vscsi);
virtscsi_remove_vqs(vdev);
return 0;
}
Expand All @@ -1076,12 +1084,11 @@ static int virtscsi_restore(struct virtio_device *vdev)
if (err)
return err;

err = register_hotcpu_notifier(&vscsi->nb);
err = virtscsi_cpu_notif_add(vscsi);
if (err) {
vdev->config->del_vqs(vdev);
return err;
}

virtio_device_ready(vdev);

if (virtio_has_feature(vdev, VIRTIO_SCSI_F_HOTPLUG))
Expand Down Expand Up @@ -1136,6 +1143,16 @@ static int __init init(void)
pr_err("mempool_create() for virtscsi_cmd_pool failed\n");
goto error;
}
ret = cpuhp_setup_state_multi(CPUHP_AP_ONLINE_DYN,
"scsi/virtio:online",
virtscsi_cpu_online, NULL);
if (ret < 0)
goto error;
virtioscsi_online = ret;
ret = cpuhp_setup_state_multi(CPUHP_VIRT_SCSI_DEAD, "scsi/virtio:dead",
NULL, virtscsi_cpu_online);
if (ret)
goto error;
ret = register_virtio_driver(&virtio_scsi_driver);
if (ret < 0)
goto error;
Expand All @@ -1151,12 +1168,17 @@ static int __init init(void)
kmem_cache_destroy(virtscsi_cmd_cache);
virtscsi_cmd_cache = NULL;
}
if (virtioscsi_online)
cpuhp_remove_multi_state(virtioscsi_online);
cpuhp_remove_multi_state(CPUHP_VIRT_SCSI_DEAD);
return ret;
}

static void __exit fini(void)
{
unregister_virtio_driver(&virtio_scsi_driver);
cpuhp_remove_multi_state(virtioscsi_online);
cpuhp_remove_multi_state(CPUHP_VIRT_SCSI_DEAD);
mempool_destroy(virtscsi_cmd_pool);
kmem_cache_destroy(virtscsi_cmd_cache);
}
Expand Down
1 change: 1 addition & 0 deletions include/linux/cpuhotplug.h
Original file line number Diff line number Diff line change
Expand Up @@ -24,6 +24,7 @@ enum cpuhp_state {
CPUHP_ARM_OMAP_WAKE_DEAD,
CPUHP_IRQ_POLL_DEAD,
CPUHP_BLOCK_SOFTIRQ_DEAD,
CPUHP_VIRT_SCSI_DEAD,
CPUHP_WORKQUEUE_PREP,
CPUHP_POWER_NUMA_PREPARE,
CPUHP_HRTIMERS_PREPARE,
Expand Down

0 comments on commit 8904f5a

Please sign in to comment.