summaryrefslogtreecommitdiffstats
path: root/net/switchdev/switchdev.c
diff options
context:
space:
mode:
authorPetr Machata <petrm@mellanox.com>2018-11-22 18:28:25 -0500
committerDavid S. Miller <davem@davemloft.net>2018-11-23 21:02:23 -0500
commita93e3b17227ed8b0db7e44d0302b4da7d07f9a35 (patch)
tree668db99bc01b59b8a3da2d19003f0a5843aaa0ae /net/switchdev/switchdev.c
parentec394af5ea1d8ee62681815d167115ac618bcb42 (diff)
switchdev: Add a blocking notifier chain
In general one can't assume that a switchdev notifier is called in a non-atomic context, and correspondingly, the switchdev notifier chain is an atomic one. However, port object addition and deletion messages are delivered from a process context. Even the MDB addition messages, whose delivery is scheduled from atomic context, are queued and the delivery itself takes place in blocking context. For VLAN messages in particular, keeping the blocking nature is important for error reporting. Therefore introduce a blocking notifier chain and related service functions to distribute the notifications for which a blocking context can be assumed. Signed-off-by: Petr Machata <petrm@mellanox.com> Reviewed-by: Jiri Pirko <jiri@mellanox.com> Reviewed-by: Ido Schimmel <idosch@mellanox.com> Signed-off-by: David S. Miller <davem@davemloft.net>
Diffstat (limited to 'net/switchdev/switchdev.c')
-rw-r--r--net/switchdev/switchdev.c26
1 files changed, 26 insertions, 0 deletions
diff --git a/net/switchdev/switchdev.c b/net/switchdev/switchdev.c
index 74b9d916a58b..e109bb97ce3f 100644
--- a/net/switchdev/switchdev.c
+++ b/net/switchdev/switchdev.c
@@ -535,6 +535,7 @@ int switchdev_port_obj_del(struct net_device *dev,
535EXPORT_SYMBOL_GPL(switchdev_port_obj_del); 535EXPORT_SYMBOL_GPL(switchdev_port_obj_del);
536 536
537static ATOMIC_NOTIFIER_HEAD(switchdev_notif_chain); 537static ATOMIC_NOTIFIER_HEAD(switchdev_notif_chain);
538static BLOCKING_NOTIFIER_HEAD(switchdev_blocking_notif_chain);
538 539
539/** 540/**
540 * register_switchdev_notifier - Register notifier 541 * register_switchdev_notifier - Register notifier
@@ -576,6 +577,31 @@ int call_switchdev_notifiers(unsigned long val, struct net_device *dev,
576} 577}
577EXPORT_SYMBOL_GPL(call_switchdev_notifiers); 578EXPORT_SYMBOL_GPL(call_switchdev_notifiers);
578 579
580int register_switchdev_blocking_notifier(struct notifier_block *nb)
581{
582 struct blocking_notifier_head *chain = &switchdev_blocking_notif_chain;
583
584 return blocking_notifier_chain_register(chain, nb);
585}
586EXPORT_SYMBOL_GPL(register_switchdev_blocking_notifier);
587
588int unregister_switchdev_blocking_notifier(struct notifier_block *nb)
589{
590 struct blocking_notifier_head *chain = &switchdev_blocking_notif_chain;
591
592 return blocking_notifier_chain_unregister(chain, nb);
593}
594EXPORT_SYMBOL_GPL(unregister_switchdev_blocking_notifier);
595
596int call_switchdev_blocking_notifiers(unsigned long val, struct net_device *dev,
597 struct switchdev_notifier_info *info)
598{
599 info->dev = dev;
600 return blocking_notifier_call_chain(&switchdev_blocking_notif_chain,
601 val, info);
602}
603EXPORT_SYMBOL_GPL(call_switchdev_blocking_notifiers);
604
579bool switchdev_port_same_parent_id(struct net_device *a, 605bool switchdev_port_same_parent_id(struct net_device *a,
580 struct net_device *b) 606 struct net_device *b)
581{ 607{