Skip to content

Commit 8017c27

Browse files
Sebastian Andrzej SiewiorKAGA-KOKO
authored andcommitted
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 <[email protected]> Cc: Mark Rutland <[email protected]> Cc: "Michael S. Tsirkin" <[email protected]> Cc: Peter Zijlstra <[email protected]> Cc: [email protected] Cc: Will Deacon <[email protected]> Cc: [email protected] Cc: [email protected] Link: http://lkml.kernel.org/r/[email protected] Signed-off-by: Thomas Gleixner <[email protected]>
1 parent 8df0387 commit 8017c27

File tree

2 files changed

+87
-24
lines changed

2 files changed

+87
-24
lines changed

drivers/net/virtio_net.c

Lines changed: 86 additions & 24 deletions
Original file line numberDiff line numberDiff line change
@@ -138,8 +138,9 @@ struct virtnet_info {
138138
/* Does the affinity hint is set for virtqueues? */
139139
bool affinity_hint_set;
140140

141-
/* CPU hot plug notifier */
142-
struct notifier_block nb;
141+
/* CPU hotplug instances for online & dead */
142+
struct hlist_node node;
143+
struct hlist_node node_dead;
143144

144145
/* Control VQ buffers: protected by the rtnl lock */
145146
struct virtio_net_ctrl_hdr ctrl_hdr;
@@ -1237,25 +1238,53 @@ static void virtnet_set_affinity(struct virtnet_info *vi)
12371238
vi->affinity_hint_set = true;
12381239
}
12391240

1240-
static int virtnet_cpu_callback(struct notifier_block *nfb,
1241-
unsigned long action, void *hcpu)
1241+
static int virtnet_cpu_online(unsigned int cpu, struct hlist_node *node)
12421242
{
1243-
struct virtnet_info *vi = container_of(nfb, struct virtnet_info, nb);
1243+
struct virtnet_info *vi = hlist_entry_safe(node, struct virtnet_info,
1244+
node);
1245+
virtnet_set_affinity(vi);
1246+
return 0;
1247+
}
12441248

1245-
switch(action & ~CPU_TASKS_FROZEN) {
1246-
case CPU_ONLINE:
1247-
case CPU_DOWN_FAILED:
1248-
case CPU_DEAD:
1249-
virtnet_set_affinity(vi);
1250-
break;
1251-
case CPU_DOWN_PREPARE:
1252-
virtnet_clean_affinity(vi, (long)hcpu);
1253-
break;
1254-
default:
1255-
break;
1256-
}
1249+
static int virtnet_cpu_dead(unsigned int cpu, struct hlist_node *node)
1250+
{
1251+
struct virtnet_info *vi = hlist_entry_safe(node, struct virtnet_info,
1252+
node_dead);
1253+
virtnet_set_affinity(vi);
1254+
return 0;
1255+
}
12571256

1258-
return NOTIFY_OK;
1257+
static int virtnet_cpu_down_prep(unsigned int cpu, struct hlist_node *node)
1258+
{
1259+
struct virtnet_info *vi = hlist_entry_safe(node, struct virtnet_info,
1260+
node);
1261+
1262+
virtnet_clean_affinity(vi, cpu);
1263+
return 0;
1264+
}
1265+
1266+
static enum cpuhp_state virtionet_online;
1267+
1268+
static int virtnet_cpu_notif_add(struct virtnet_info *vi)
1269+
{
1270+
int ret;
1271+
1272+
ret = cpuhp_state_add_instance_nocalls(virtionet_online, &vi->node);
1273+
if (ret)
1274+
return ret;
1275+
ret = cpuhp_state_add_instance_nocalls(CPUHP_VIRT_NET_DEAD,
1276+
&vi->node_dead);
1277+
if (!ret)
1278+
return ret;
1279+
cpuhp_state_remove_instance_nocalls(virtionet_online, &vi->node);
1280+
return ret;
1281+
}
1282+
1283+
static void virtnet_cpu_notif_remove(struct virtnet_info *vi)
1284+
{
1285+
cpuhp_state_remove_instance_nocalls(virtionet_online, &vi->node);
1286+
cpuhp_state_remove_instance_nocalls(CPUHP_VIRT_NET_DEAD,
1287+
&vi->node_dead);
12591288
}
12601289

12611290
static void virtnet_get_ringparam(struct net_device *dev,
@@ -1879,8 +1908,7 @@ static int virtnet_probe(struct virtio_device *vdev)
18791908

18801909
virtio_device_ready(vdev);
18811910

1882-
vi->nb.notifier_call = &virtnet_cpu_callback;
1883-
err = register_hotcpu_notifier(&vi->nb);
1911+
err = virtnet_cpu_notif_add(vi);
18841912
if (err) {
18851913
pr_debug("virtio_net: registering cpu notifier failed\n");
18861914
goto free_unregister_netdev;
@@ -1934,7 +1962,7 @@ static void virtnet_remove(struct virtio_device *vdev)
19341962
{
19351963
struct virtnet_info *vi = vdev->priv;
19361964

1937-
unregister_hotcpu_notifier(&vi->nb);
1965+
virtnet_cpu_notif_remove(vi);
19381966

19391967
/* Make sure no work handler is accessing the device. */
19401968
flush_work(&vi->config_work);
@@ -1953,7 +1981,7 @@ static int virtnet_freeze(struct virtio_device *vdev)
19531981
struct virtnet_info *vi = vdev->priv;
19541982
int i;
19551983

1956-
unregister_hotcpu_notifier(&vi->nb);
1984+
virtnet_cpu_notif_remove(vi);
19571985

19581986
/* Make sure no work handler is accessing the device */
19591987
flush_work(&vi->config_work);
@@ -1997,7 +2025,7 @@ static int virtnet_restore(struct virtio_device *vdev)
19972025
virtnet_set_queues(vi, vi->curr_queue_pairs);
19982026
rtnl_unlock();
19992027

2000-
err = register_hotcpu_notifier(&vi->nb);
2028+
err = virtnet_cpu_notif_add(vi);
20012029
if (err)
20022030
return err;
20032031

@@ -2039,7 +2067,41 @@ static struct virtio_driver virtio_net_driver = {
20392067
#endif
20402068
};
20412069

2042-
module_virtio_driver(virtio_net_driver);
2070+
static __init int virtio_net_driver_init(void)
2071+
{
2072+
int ret;
2073+
2074+
ret = cpuhp_setup_state_multi(CPUHP_AP_ONLINE_DYN, "AP_VIRT_NET_ONLINE",
2075+
virtnet_cpu_online,
2076+
virtnet_cpu_down_prep);
2077+
if (ret < 0)
2078+
goto out;
2079+
virtionet_online = ret;
2080+
ret = cpuhp_setup_state_multi(CPUHP_VIRT_NET_DEAD, "VIRT_NET_DEAD",
2081+
NULL, virtnet_cpu_dead);
2082+
if (ret)
2083+
goto err_dead;
2084+
2085+
ret = register_virtio_driver(&virtio_net_driver);
2086+
if (ret)
2087+
goto err_virtio;
2088+
return 0;
2089+
err_virtio:
2090+
cpuhp_remove_multi_state(CPUHP_VIRT_NET_DEAD);
2091+
err_dead:
2092+
cpuhp_remove_multi_state(virtionet_online);
2093+
out:
2094+
return ret;
2095+
}
2096+
module_init(virtio_net_driver_init);
2097+
2098+
static __exit void virtio_net_driver_exit(void)
2099+
{
2100+
cpuhp_remove_multi_state(CPUHP_VIRT_NET_DEAD);
2101+
cpuhp_remove_multi_state(virtionet_online);
2102+
unregister_virtio_driver(&virtio_net_driver);
2103+
}
2104+
module_exit(virtio_net_driver_exit);
20432105

20442106
MODULE_DEVICE_TABLE(virtio, id_table);
20452107
MODULE_DESCRIPTION("Virtio network driver");

include/linux/cpuhotplug.h

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -14,6 +14,7 @@ enum cpuhp_state {
1414
CPUHP_PERF_SUPERH,
1515
CPUHP_X86_HPET_DEAD,
1616
CPUHP_X86_APB_DEAD,
17+
CPUHP_VIRT_NET_DEAD,
1718
CPUHP_WORKQUEUE_PREP,
1819
CPUHP_POWER_NUMA_PREPARE,
1920
CPUHP_HRTIMERS_PREPARE,

0 commit comments

Comments
 (0)