mirror of
				https://github.com/torvalds/linux.git
				synced 2025-11-04 10:40:15 +02:00 
			
		
		
		
	net/virtio-net: Convert to hotplug state machine
Install the callbacks via the state machine. The driver supports multiple instances and therefore the new cpuhp_state_add_instance_nocalls() infrastrucure is used. The driver currently uses get_online_cpus() to avoid missing a CPU hotplug event while invoking virtnet_set_affinity(). This could be avoided by using cpuhp_state_add_instance() variant which holds the hotplug lock and invokes callback during registration. This is more or less a 1:1 conversion of the current code. Signed-off-by: Sebastian Andrzej Siewior <bigeasy@linutronix.de> Cc: Mark Rutland <mark.rutland@arm.com> Cc: "Michael S. Tsirkin" <mst@redhat.com> Cc: Peter Zijlstra <peterz@infradead.org> Cc: netdev@vger.kernel.org Cc: Will Deacon <will.deacon@arm.com> Cc: virtualization@lists.linux-foundation.org Cc: rt@linutronix.de Link: http://lkml.kernel.org/r/1471024183-12666-7-git-send-email-bigeasy@linutronix.de Signed-off-by: Thomas Gleixner <tglx@linutronix.de>
This commit is contained in:
		
							parent
							
								
									8df038725a
								
							
						
					
					
						commit
						8017c27919
					
				
					 2 changed files with 87 additions and 24 deletions
				
			
		| 
						 | 
					@ -138,8 +138,9 @@ struct virtnet_info {
 | 
				
			||||||
	/* Does the affinity hint is set for virtqueues? */
 | 
						/* Does the affinity hint is set for virtqueues? */
 | 
				
			||||||
	bool affinity_hint_set;
 | 
						bool affinity_hint_set;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
	/* CPU hot plug notifier */
 | 
						/* CPU hotplug instances for online & dead */
 | 
				
			||||||
	struct notifier_block nb;
 | 
						struct hlist_node node;
 | 
				
			||||||
 | 
						struct hlist_node node_dead;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
	/* Control VQ buffers: protected by the rtnl lock */
 | 
						/* Control VQ buffers: protected by the rtnl lock */
 | 
				
			||||||
	struct virtio_net_ctrl_hdr ctrl_hdr;
 | 
						struct virtio_net_ctrl_hdr ctrl_hdr;
 | 
				
			||||||
| 
						 | 
					@ -1237,25 +1238,53 @@ static void virtnet_set_affinity(struct virtnet_info *vi)
 | 
				
			||||||
	vi->affinity_hint_set = true;
 | 
						vi->affinity_hint_set = true;
 | 
				
			||||||
}
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
static int virtnet_cpu_callback(struct notifier_block *nfb,
 | 
					static int virtnet_cpu_online(unsigned int cpu, struct hlist_node *node)
 | 
				
			||||||
			        unsigned long action, void *hcpu)
 | 
					 | 
				
			||||||
{
 | 
					{
 | 
				
			||||||
	struct virtnet_info *vi = container_of(nfb, struct virtnet_info, nb);
 | 
						struct virtnet_info *vi = hlist_entry_safe(node, struct virtnet_info,
 | 
				
			||||||
 | 
											   node);
 | 
				
			||||||
 | 
						virtnet_set_affinity(vi);
 | 
				
			||||||
 | 
						return 0;
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
	switch(action & ~CPU_TASKS_FROZEN) {
 | 
					static int virtnet_cpu_dead(unsigned int cpu, struct hlist_node *node)
 | 
				
			||||||
	case CPU_ONLINE:
 | 
					{
 | 
				
			||||||
	case CPU_DOWN_FAILED:
 | 
						struct virtnet_info *vi = hlist_entry_safe(node, struct virtnet_info,
 | 
				
			||||||
	case CPU_DEAD:
 | 
											   node_dead);
 | 
				
			||||||
		virtnet_set_affinity(vi);
 | 
						virtnet_set_affinity(vi);
 | 
				
			||||||
		break;
 | 
						return 0;
 | 
				
			||||||
	case CPU_DOWN_PREPARE:
 | 
					}
 | 
				
			||||||
		virtnet_clean_affinity(vi, (long)hcpu);
 | 
					 | 
				
			||||||
		break;
 | 
					 | 
				
			||||||
	default:
 | 
					 | 
				
			||||||
		break;
 | 
					 | 
				
			||||||
	}
 | 
					 | 
				
			||||||
 | 
					
 | 
				
			||||||
	return NOTIFY_OK;
 | 
					static int virtnet_cpu_down_prep(unsigned int cpu, struct hlist_node *node)
 | 
				
			||||||
 | 
					{
 | 
				
			||||||
 | 
						struct virtnet_info *vi = hlist_entry_safe(node, struct virtnet_info,
 | 
				
			||||||
 | 
											   node);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						virtnet_clean_affinity(vi, cpu);
 | 
				
			||||||
 | 
						return 0;
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					static enum cpuhp_state virtionet_online;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					static int virtnet_cpu_notif_add(struct virtnet_info *vi)
 | 
				
			||||||
 | 
					{
 | 
				
			||||||
 | 
						int ret;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						ret = cpuhp_state_add_instance_nocalls(virtionet_online, &vi->node);
 | 
				
			||||||
 | 
						if (ret)
 | 
				
			||||||
 | 
							return ret;
 | 
				
			||||||
 | 
						ret = cpuhp_state_add_instance_nocalls(CPUHP_VIRT_NET_DEAD,
 | 
				
			||||||
 | 
										       &vi->node_dead);
 | 
				
			||||||
 | 
						if (!ret)
 | 
				
			||||||
 | 
							return ret;
 | 
				
			||||||
 | 
						cpuhp_state_remove_instance_nocalls(virtionet_online, &vi->node);
 | 
				
			||||||
 | 
						return ret;
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					static void virtnet_cpu_notif_remove(struct virtnet_info *vi)
 | 
				
			||||||
 | 
					{
 | 
				
			||||||
 | 
						cpuhp_state_remove_instance_nocalls(virtionet_online, &vi->node);
 | 
				
			||||||
 | 
						cpuhp_state_remove_instance_nocalls(CPUHP_VIRT_NET_DEAD,
 | 
				
			||||||
 | 
										    &vi->node_dead);
 | 
				
			||||||
}
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
static void virtnet_get_ringparam(struct net_device *dev,
 | 
					static void virtnet_get_ringparam(struct net_device *dev,
 | 
				
			||||||
| 
						 | 
					@ -1879,8 +1908,7 @@ static int virtnet_probe(struct virtio_device *vdev)
 | 
				
			||||||
 | 
					
 | 
				
			||||||
	virtio_device_ready(vdev);
 | 
						virtio_device_ready(vdev);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
	vi->nb.notifier_call = &virtnet_cpu_callback;
 | 
						err = virtnet_cpu_notif_add(vi);
 | 
				
			||||||
	err = register_hotcpu_notifier(&vi->nb);
 | 
					 | 
				
			||||||
	if (err) {
 | 
						if (err) {
 | 
				
			||||||
		pr_debug("virtio_net: registering cpu notifier failed\n");
 | 
							pr_debug("virtio_net: registering cpu notifier failed\n");
 | 
				
			||||||
		goto free_unregister_netdev;
 | 
							goto free_unregister_netdev;
 | 
				
			||||||
| 
						 | 
					@ -1934,7 +1962,7 @@ static void virtnet_remove(struct virtio_device *vdev)
 | 
				
			||||||
{
 | 
					{
 | 
				
			||||||
	struct virtnet_info *vi = vdev->priv;
 | 
						struct virtnet_info *vi = vdev->priv;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
	unregister_hotcpu_notifier(&vi->nb);
 | 
						virtnet_cpu_notif_remove(vi);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
	/* Make sure no work handler is accessing the device. */
 | 
						/* Make sure no work handler is accessing the device. */
 | 
				
			||||||
	flush_work(&vi->config_work);
 | 
						flush_work(&vi->config_work);
 | 
				
			||||||
| 
						 | 
					@ -1953,7 +1981,7 @@ static int virtnet_freeze(struct virtio_device *vdev)
 | 
				
			||||||
	struct virtnet_info *vi = vdev->priv;
 | 
						struct virtnet_info *vi = vdev->priv;
 | 
				
			||||||
	int i;
 | 
						int i;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
	unregister_hotcpu_notifier(&vi->nb);
 | 
						virtnet_cpu_notif_remove(vi);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
	/* Make sure no work handler is accessing the device */
 | 
						/* Make sure no work handler is accessing the device */
 | 
				
			||||||
	flush_work(&vi->config_work);
 | 
						flush_work(&vi->config_work);
 | 
				
			||||||
| 
						 | 
					@ -1997,7 +2025,7 @@ static int virtnet_restore(struct virtio_device *vdev)
 | 
				
			||||||
	virtnet_set_queues(vi, vi->curr_queue_pairs);
 | 
						virtnet_set_queues(vi, vi->curr_queue_pairs);
 | 
				
			||||||
	rtnl_unlock();
 | 
						rtnl_unlock();
 | 
				
			||||||
 | 
					
 | 
				
			||||||
	err = register_hotcpu_notifier(&vi->nb);
 | 
						err = virtnet_cpu_notif_add(vi);
 | 
				
			||||||
	if (err)
 | 
						if (err)
 | 
				
			||||||
		return err;
 | 
							return err;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
| 
						 | 
					@ -2039,7 +2067,41 @@ static struct virtio_driver virtio_net_driver = {
 | 
				
			||||||
#endif
 | 
					#endif
 | 
				
			||||||
};
 | 
					};
 | 
				
			||||||
 | 
					
 | 
				
			||||||
module_virtio_driver(virtio_net_driver);
 | 
					static __init int virtio_net_driver_init(void)
 | 
				
			||||||
 | 
					{
 | 
				
			||||||
 | 
						int ret;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						ret = cpuhp_setup_state_multi(CPUHP_AP_ONLINE_DYN, "AP_VIRT_NET_ONLINE",
 | 
				
			||||||
 | 
									      virtnet_cpu_online,
 | 
				
			||||||
 | 
									      virtnet_cpu_down_prep);
 | 
				
			||||||
 | 
						if (ret < 0)
 | 
				
			||||||
 | 
							goto out;
 | 
				
			||||||
 | 
						virtionet_online = ret;
 | 
				
			||||||
 | 
						ret = cpuhp_setup_state_multi(CPUHP_VIRT_NET_DEAD, "VIRT_NET_DEAD",
 | 
				
			||||||
 | 
									      NULL, virtnet_cpu_dead);
 | 
				
			||||||
 | 
						if (ret)
 | 
				
			||||||
 | 
							goto err_dead;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					        ret = register_virtio_driver(&virtio_net_driver);
 | 
				
			||||||
 | 
						if (ret)
 | 
				
			||||||
 | 
							goto err_virtio;
 | 
				
			||||||
 | 
						return 0;
 | 
				
			||||||
 | 
					err_virtio:
 | 
				
			||||||
 | 
						cpuhp_remove_multi_state(CPUHP_VIRT_NET_DEAD);
 | 
				
			||||||
 | 
					err_dead:
 | 
				
			||||||
 | 
						cpuhp_remove_multi_state(virtionet_online);
 | 
				
			||||||
 | 
					out:
 | 
				
			||||||
 | 
						return ret;
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
 | 
					module_init(virtio_net_driver_init);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					static __exit void virtio_net_driver_exit(void)
 | 
				
			||||||
 | 
					{
 | 
				
			||||||
 | 
						cpuhp_remove_multi_state(CPUHP_VIRT_NET_DEAD);
 | 
				
			||||||
 | 
						cpuhp_remove_multi_state(virtionet_online);
 | 
				
			||||||
 | 
						unregister_virtio_driver(&virtio_net_driver);
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
 | 
					module_exit(virtio_net_driver_exit);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
MODULE_DEVICE_TABLE(virtio, id_table);
 | 
					MODULE_DEVICE_TABLE(virtio, id_table);
 | 
				
			||||||
MODULE_DESCRIPTION("Virtio network driver");
 | 
					MODULE_DESCRIPTION("Virtio network driver");
 | 
				
			||||||
| 
						 | 
					
 | 
				
			||||||
| 
						 | 
					@ -14,6 +14,7 @@ enum cpuhp_state {
 | 
				
			||||||
	CPUHP_PERF_SUPERH,
 | 
						CPUHP_PERF_SUPERH,
 | 
				
			||||||
	CPUHP_X86_HPET_DEAD,
 | 
						CPUHP_X86_HPET_DEAD,
 | 
				
			||||||
	CPUHP_X86_APB_DEAD,
 | 
						CPUHP_X86_APB_DEAD,
 | 
				
			||||||
 | 
						CPUHP_VIRT_NET_DEAD,
 | 
				
			||||||
	CPUHP_WORKQUEUE_PREP,
 | 
						CPUHP_WORKQUEUE_PREP,
 | 
				
			||||||
	CPUHP_POWER_NUMA_PREPARE,
 | 
						CPUHP_POWER_NUMA_PREPARE,
 | 
				
			||||||
	CPUHP_HRTIMERS_PREPARE,
 | 
						CPUHP_HRTIMERS_PREPARE,
 | 
				
			||||||
| 
						 | 
					
 | 
				
			||||||
		Loading…
	
		Reference in a new issue