From d86b5e0e6bf5980d3136ab4a855522143f2dcb5d Mon Sep 17 00:00:00 2001 From: Adrian Bunk Date: Sat, 21 Jan 2006 00:46:55 +0100 Subject: [PATCH] net/: fix the WIRELESS_EXT abuse This patch contains the following changes: - add a CONFIG_WIRELESS_EXT select'ed by NET_RADIO for conditional code - remove the now no longer required #ifdef CONFIG_NET_RADIO from some #include's Based on a patch by Jean Tourrilhes . Signed-off-by: Adrian Bunk Signed-off-by: John W. Linville --- net/core/dev.c | 10 ++++------ 1 file changed, 4 insertions(+), 6 deletions(-) (limited to 'net/core/dev.c') diff --git a/net/core/dev.c b/net/core/dev.c index fd070a098f2..41ac7a8ddb0 100644 --- a/net/core/dev.c +++ b/net/core/dev.c @@ -110,10 +110,8 @@ #include #include #include -#ifdef CONFIG_NET_RADIO -#include /* Note : will define WIRELESS_EXT */ +#include #include -#endif /* CONFIG_NET_RADIO */ #include /* @@ -2028,7 +2026,7 @@ static struct file_operations softnet_seq_fops = { .release = seq_release, }; -#ifdef WIRELESS_EXT +#ifdef CONFIG_WIRELESS_EXT extern int wireless_proc_init(void); #else #define wireless_proc_init() 0 @@ -2581,7 +2579,7 @@ int dev_ioctl(unsigned int cmd, void __user *arg) ret = -EFAULT; return ret; } -#ifdef WIRELESS_EXT +#ifdef CONFIG_WIRELESS_EXT /* Take care of Wireless Extensions */ if (cmd >= SIOCIWFIRST && cmd <= SIOCIWLAST) { /* If command is `set a parameter', or @@ -2602,7 +2600,7 @@ int dev_ioctl(unsigned int cmd, void __user *arg) ret = -EFAULT; return ret; } -#endif /* WIRELESS_EXT */ +#endif /* CONFIG_WIRELESS_EXT */ return -EINVAL; } } -- cgit v1.2.3-70-g09d2 From 8f903c708fcc2b579ebf16542bf6109bad593a1d Mon Sep 17 00:00:00 2001 From: Jay Vosburgh Date: Tue, 21 Feb 2006 16:36:44 -0800 Subject: [PATCH] bonding: suppress duplicate packets Originally submitted by Kenzo Iwami; his original description is: The current bonding driver receives duplicate packets when broadcast/ multicast packets are sent by other devices or packets are flooded by the switch. In this patch, new flags are added in priv_flags of net_device structure to let the bonding driver discard duplicate packets in dev.c:skb_bond(). Modified by Jay Vosburgh to change a define name, update some comments, rearrange the new skb_bond() for clarity, clear all bonding priv_flags on slave release, and update the driver version. Signed-off-by: Kenzo Iwami Signed-off-by: Jay Vosburgh Signed-off-by: Jeff Garzik --- drivers/net/bonding/bond_main.c | 43 ++++++++++++++++++++-------------------- drivers/net/bonding/bond_sysfs.c | 6 ++++++ drivers/net/bonding/bonding.h | 33 +++++++++++++++++++++++++----- include/linux/if.h | 3 +++ include/linux/if_ether.h | 1 + net/core/dev.c | 26 +++++++++++++++++++++++- 6 files changed, 85 insertions(+), 27 deletions(-) (limited to 'net/core/dev.c') diff --git a/drivers/net/bonding/bond_main.c b/drivers/net/bonding/bond_main.c index bcf9f17daf0..623c87a8361 100644 --- a/drivers/net/bonding/bond_main.c +++ b/drivers/net/bonding/bond_main.c @@ -1040,6 +1040,10 @@ void bond_change_active_slave(struct bonding *bond, struct slave *new_active) if ((bond->params.mode == BOND_MODE_TLB) || (bond->params.mode == BOND_MODE_ALB)) { bond_alb_handle_active_change(bond, new_active); + if (old_active) + bond_set_slave_inactive_flags(old_active); + if (new_active) + bond_set_slave_active_flags(new_active); } else { bond->curr_active_slave = new_active; } @@ -1443,15 +1447,16 @@ int bond_enslave(struct net_device *bond_dev, struct net_device *slave_dev) switch (bond->params.mode) { case BOND_MODE_ACTIVEBACKUP: - /* if we're in active-backup mode, we need one and only one active - * interface. The backup interfaces will have their NOARP flag set - * because we need them to be completely deaf and not to respond to - * any ARP request on the network to avoid fooling a switch. Thus, - * since we guarantee that curr_active_slave always point to the last - * usable interface, we just have to verify this interface's flag. + /* if we're in active-backup mode, we need one and + * only one active interface. The backup interfaces + * will have their SLAVE_INACTIVE flag set because we + * need them to be drop all packets. Thus, since we + * guarantee that curr_active_slave always point to + * the last usable interface, we just have to verify + * this interface's flag. */ if (((!bond->curr_active_slave) || - (bond->curr_active_slave->dev->flags & IFF_NOARP)) && + (bond->curr_active_slave->dev->priv_flags & IFF_SLAVE_INACTIVE)) && (new_slave->link != BOND_LINK_DOWN)) { dprintk("This is the first active slave\n"); /* first slave or no active slave yet, and this link @@ -1492,6 +1497,8 @@ int bond_enslave(struct net_device *bond_dev, struct net_device *slave_dev) * is OK, so make this interface the active one */ bond_change_active_slave(bond, new_slave); + } else { + bond_set_slave_inactive_flags(new_slave); } break; default: @@ -1724,13 +1731,8 @@ int bond_release(struct net_device *bond_dev, struct net_device *slave_dev) addr.sa_family = slave_dev->type; dev_set_mac_address(slave_dev, &addr); - /* restore the original state of the - * IFF_NOARP flag that might have been - * set by bond_set_slave_inactive_flags() - */ - if ((slave->original_flags & IFF_NOARP) == 0) { - slave_dev->flags &= ~IFF_NOARP; - } + slave_dev->priv_flags &= ~(IFF_MASTER_8023AD | IFF_MASTER_ALB | + IFF_SLAVE_INACTIVE); kfree(slave); @@ -1816,12 +1818,8 @@ static int bond_release_all(struct net_device *bond_dev) addr.sa_family = slave_dev->type; dev_set_mac_address(slave_dev, &addr); - /* restore the original state of the IFF_NOARP flag that might have - * been set by bond_set_slave_inactive_flags() - */ - if ((slave->original_flags & IFF_NOARP) == 0) { - slave_dev->flags &= ~IFF_NOARP; - } + slave_dev->priv_flags &= ~(IFF_MASTER_8023AD | IFF_MASTER_ALB | + IFF_SLAVE_INACTIVE); kfree(slave); @@ -4061,14 +4059,17 @@ void bond_set_mode_ops(struct bonding *bond, int mode) bond_dev->hard_start_xmit = bond_xmit_broadcast; break; case BOND_MODE_8023AD: + bond_set_master_3ad_flags(bond); bond_dev->hard_start_xmit = bond_3ad_xmit_xor; if (bond->params.xmit_policy == BOND_XMIT_POLICY_LAYER34) bond->xmit_hash_policy = bond_xmit_hash_policy_l34; else bond->xmit_hash_policy = bond_xmit_hash_policy_l2; break; - case BOND_MODE_TLB: case BOND_MODE_ALB: + bond_set_master_alb_flags(bond); + /* FALLTHRU */ + case BOND_MODE_TLB: bond_dev->hard_start_xmit = bond_alb_xmit; bond_dev->set_mac_address = bond_alb_set_mac_address; break; diff --git a/drivers/net/bonding/bond_sysfs.c b/drivers/net/bonding/bond_sysfs.c index 041bcc58355..5a9bd95884b 100644 --- a/drivers/net/bonding/bond_sysfs.c +++ b/drivers/net/bonding/bond_sysfs.c @@ -424,6 +424,12 @@ static ssize_t bonding_store_mode(struct class_device *cd, const char *buf, size ret = -EINVAL; goto out; } else { + if (bond->params.mode == BOND_MODE_8023AD) + bond_unset_master_3ad_flags(bond); + + if (bond->params.mode == BOND_MODE_ALB) + bond_unset_master_alb_flags(bond); + bond->params.mode = new_value; bond_set_mode_ops(bond, bond->params.mode); printk(KERN_INFO DRV_NAME ": %s: setting mode to %s (%d).\n", diff --git a/drivers/net/bonding/bonding.h b/drivers/net/bonding/bonding.h index 3dd78d048c3..ce9dc9b4e2d 100644 --- a/drivers/net/bonding/bonding.h +++ b/drivers/net/bonding/bonding.h @@ -22,8 +22,8 @@ #include "bond_3ad.h" #include "bond_alb.h" -#define DRV_VERSION "3.0.1" -#define DRV_RELDATE "January 9, 2006" +#define DRV_VERSION "3.0.2" +#define DRV_RELDATE "February 21, 2006" #define DRV_NAME "bonding" #define DRV_DESCRIPTION "Ethernet Channel Bonding Driver" @@ -230,14 +230,37 @@ static inline struct bonding *bond_get_bond_by_slave(struct slave *slave) static inline void bond_set_slave_inactive_flags(struct slave *slave) { - slave->state = BOND_STATE_BACKUP; - slave->dev->flags |= IFF_NOARP; + struct bonding *bond = slave->dev->master->priv; + if (bond->params.mode != BOND_MODE_TLB && + bond->params.mode != BOND_MODE_ALB) + slave->state = BOND_STATE_BACKUP; + slave->dev->priv_flags |= IFF_SLAVE_INACTIVE; } static inline void bond_set_slave_active_flags(struct slave *slave) { slave->state = BOND_STATE_ACTIVE; - slave->dev->flags &= ~IFF_NOARP; + slave->dev->priv_flags &= ~IFF_SLAVE_INACTIVE; +} + +static inline void bond_set_master_3ad_flags(struct bonding *bond) +{ + bond->dev->priv_flags |= IFF_MASTER_8023AD; +} + +static inline void bond_unset_master_3ad_flags(struct bonding *bond) +{ + bond->dev->priv_flags &= ~IFF_MASTER_8023AD; +} + +static inline void bond_set_master_alb_flags(struct bonding *bond) +{ + bond->dev->priv_flags |= IFF_MASTER_ALB; +} + +static inline void bond_unset_master_alb_flags(struct bonding *bond) +{ + bond->dev->priv_flags &= ~IFF_MASTER_ALB; } struct vlan_entry *bond_next_vlan(struct bonding *bond, struct vlan_entry *curr); diff --git a/include/linux/if.h b/include/linux/if.h index ce627d9092e..12c6f6d157c 100644 --- a/include/linux/if.h +++ b/include/linux/if.h @@ -52,6 +52,9 @@ /* Private (from user) interface flags (netdevice->priv_flags). */ #define IFF_802_1Q_VLAN 0x1 /* 802.1Q VLAN device. */ #define IFF_EBRIDGE 0x2 /* Ethernet bridging device. */ +#define IFF_SLAVE_INACTIVE 0x4 /* bonding slave not the curr. active */ +#define IFF_MASTER_8023AD 0x8 /* bonding master, 802.3ad. */ +#define IFF_MASTER_ALB 0x10 /* bonding master, balance-alb. */ #define IF_GET_IFACE 0x0001 /* for querying only */ #define IF_GET_PROTO 0x0002 diff --git a/include/linux/if_ether.h b/include/linux/if_ether.h index 7a92c1ce145..ab08f35cbc3 100644 --- a/include/linux/if_ether.h +++ b/include/linux/if_ether.h @@ -61,6 +61,7 @@ #define ETH_P_8021Q 0x8100 /* 802.1Q VLAN Extended Header */ #define ETH_P_IPX 0x8137 /* IPX over DIX */ #define ETH_P_IPV6 0x86DD /* IPv6 over bluebook */ +#define ETH_P_SLOW 0x8809 /* Slow Protocol. See 802.3ad 43B */ #define ETH_P_WCCP 0x883E /* Web-cache coordination protocol * defined in draft-wilson-wrec-wccp-v2-00.txt */ #define ETH_P_PPP_DISC 0x8863 /* PPPoE discovery messages */ diff --git a/net/core/dev.c b/net/core/dev.c index 225e38ff57c..ef56c035d44 100644 --- a/net/core/dev.c +++ b/net/core/dev.c @@ -1446,8 +1446,29 @@ static inline struct net_device *skb_bond(struct sk_buff *skb) { struct net_device *dev = skb->dev; - if (dev->master) + if (dev->master) { + /* + * On bonding slaves other than the currently active + * slave, suppress duplicates except for 802.3ad + * ETH_P_SLOW and alb non-mcast/bcast. + */ + if (dev->priv_flags & IFF_SLAVE_INACTIVE) { + if (dev->master->priv_flags & IFF_MASTER_ALB) { + if (skb->pkt_type != PACKET_BROADCAST && + skb->pkt_type != PACKET_MULTICAST) + goto keep; + } + + if (dev->master->priv_flags & IFF_MASTER_8023AD && + skb->protocol == __constant_htons(ETH_P_SLOW)) + goto keep; + + kfree_skb(skb); + return NULL; + } +keep: skb->dev = dev->master; + } return dev; } @@ -1591,6 +1612,9 @@ int netif_receive_skb(struct sk_buff *skb) orig_dev = skb_bond(skb); + if (!orig_dev) + return NET_RX_DROP; + __get_cpu_var(netdev_rx_stat).total++; skb->h.raw = skb->nh.raw = skb->data; -- cgit v1.2.3-70-g09d2 From 5bdb98868062c1b14025883049551af343233187 Mon Sep 17 00:00:00 2001 From: Steve Grubb Date: Sat, 3 Dec 2005 08:39:35 -0500 Subject: [PATCH] promiscuous mode Hi, When a network interface goes into promiscuous mode, its an important security issue. The attached patch is intended to capture that action and send an event to the audit system. The patch carves out a new block of numbers for kernel detected anomalies. These are events that may indicate suspicious activity. Other examples of potential kernel anomalies would be: exceeding disk quota, rlimit violations, changes to syscall entry table. Signed-off-by: Steve Grubb Signed-off-by: Al Viro --- include/linux/audit.h | 7 ++++++- net/core/dev.c | 7 +++++++ 2 files changed, 13 insertions(+), 1 deletion(-) (limited to 'net/core/dev.c') diff --git a/include/linux/audit.h b/include/linux/audit.h index d760430c8de..1c47c59058c 100644 --- a/include/linux/audit.h +++ b/include/linux/audit.h @@ -35,7 +35,8 @@ * 1400 - 1499 SE Linux use * 1500 - 1599 kernel LSPP events * 1600 - 1699 kernel crypto events - * 1700 - 1999 future kernel use (maybe integrity labels and related events) + * 1700 - 1799 kernel anomaly records + * 1800 - 1999 future kernel use (maybe integrity labels and related events) * 2000 is for otherwise unclassified kernel audit messages (legacy) * 2001 - 2099 unused (kernel) * 2100 - 2199 user space anomaly records @@ -90,6 +91,10 @@ #define AUDIT_MAC_STATUS 1404 /* Changed enforcing,permissive,off */ #define AUDIT_MAC_CONFIG_CHANGE 1405 /* Changes to booleans */ +#define AUDIT_FIRST_KERN_ANOM_MSG 1700 +#define AUDIT_LAST_KERN_ANOM_MSG 1799 +#define AUDIT_ANOM_PROMISCUOUS 1700 /* Device changed promiscuous mode */ + #define AUDIT_KERNEL 2000 /* Asynchronous audit record. NOT A REQUEST. */ /* Rule flags */ diff --git a/net/core/dev.c b/net/core/dev.c index 2afb0de9532..e9f84a66ce8 100644 --- a/net/core/dev.c +++ b/net/core/dev.c @@ -115,6 +115,7 @@ #include #endif /* CONFIG_NET_RADIO */ #include +#include /* * The list of packet types we will receive (as opposed to discard) @@ -2120,6 +2121,12 @@ void dev_set_promiscuity(struct net_device *dev, int inc) printk(KERN_INFO "device %s %s promiscuous mode\n", dev->name, (dev->flags & IFF_PROMISC) ? "entered" : "left"); + audit_log(current->audit_context, GFP_ATOMIC, + AUDIT_ANOM_PROMISCUOUS, + "dev=%s prom=%d old_prom=%d auid=%u", + dev->name, (dev->flags & IFF_PROMISC), + (old_flags & IFF_PROMISC), + audit_get_loginuid(current->audit_context)); } } -- cgit v1.2.3-70-g09d2 From b00055aacdb172c05067612278ba27265fcd05ce Mon Sep 17 00:00:00 2001 From: Stefan Rompf Date: Mon, 20 Mar 2006 17:09:11 -0800 Subject: [NET] core: add RFC2863 operstate this patch adds a dormant flag to network devices, RFC2863 operstate derived from these flags and possibility for userspace interaction. It allows drivers to signal that a device is unusable for user traffic without disabling queueing (and therefore the possibility for protocol establishment traffic to flow) and a userspace supplicant (WPA, 802.1X) to mark a device unusable without changes to the driver. It is the result of our long discussion. However I must admit that it represents what Jamal and I agreed on with compromises towards Krzysztof, but Thomas and Krzysztof still disagree with some parts. Anyway I think it should be applied. Signed-off-by: Stefan Rompf Signed-off-by: David S. Miller --- include/linux/if.h | 26 +++++++++++++++++++++--- include/linux/netdevice.h | 35 +++++++++++++++++++++++++++++++-- include/linux/rtnetlink.h | 2 ++ net/core/dev.c | 14 ++++++++++--- net/core/link_watch.c | 40 +++++++++++++++++++++++++++++++++++++ net/core/net-sysfs.c | 41 ++++++++++++++++++++++++++++++++++++++ net/core/rtnetlink.c | 50 +++++++++++++++++++++++++++++++++++++++++++++++ 7 files changed, 200 insertions(+), 8 deletions(-) (limited to 'net/core/dev.c') diff --git a/include/linux/if.h b/include/linux/if.h index 12c6f6d157c..374e20ad8b0 100644 --- a/include/linux/if.h +++ b/include/linux/if.h @@ -33,7 +33,7 @@ #define IFF_LOOPBACK 0x8 /* is a loopback net */ #define IFF_POINTOPOINT 0x10 /* interface is has p-p link */ #define IFF_NOTRAILERS 0x20 /* avoid use of trailers */ -#define IFF_RUNNING 0x40 /* interface running and carrier ok */ +#define IFF_RUNNING 0x40 /* interface RFC2863 OPER_UP */ #define IFF_NOARP 0x80 /* no ARP protocol */ #define IFF_PROMISC 0x100 /* receive all packets */ #define IFF_ALLMULTI 0x200 /* receive all multicast packets*/ @@ -43,12 +43,16 @@ #define IFF_MULTICAST 0x1000 /* Supports multicast */ -#define IFF_VOLATILE (IFF_LOOPBACK|IFF_POINTOPOINT|IFF_BROADCAST|IFF_MASTER|IFF_SLAVE|IFF_RUNNING) - #define IFF_PORTSEL 0x2000 /* can set media type */ #define IFF_AUTOMEDIA 0x4000 /* auto media select active */ #define IFF_DYNAMIC 0x8000 /* dialup device with changing addresses*/ +#define IFF_LOWER_UP 0x10000 /* driver signals L1 up */ +#define IFF_DORMANT 0x20000 /* driver signals dormant */ + +#define IFF_VOLATILE (IFF_LOOPBACK|IFF_POINTOPOINT|IFF_BROADCAST|\ + IFF_MASTER|IFF_SLAVE|IFF_RUNNING|IFF_LOWER_UP|IFF_DORMANT) + /* Private (from user) interface flags (netdevice->priv_flags). */ #define IFF_802_1Q_VLAN 0x1 /* 802.1Q VLAN device. */ #define IFF_EBRIDGE 0x2 /* Ethernet bridging device. */ @@ -83,6 +87,22 @@ #define IF_PROTO_FR_ETH_PVC 0x200B #define IF_PROTO_RAW 0x200C /* RAW Socket */ +/* RFC 2863 operational status */ +enum { + IF_OPER_UNKNOWN, + IF_OPER_NOTPRESENT, + IF_OPER_DOWN, + IF_OPER_LOWERLAYERDOWN, + IF_OPER_TESTING, + IF_OPER_DORMANT, + IF_OPER_UP, +}; + +/* link modes */ +enum { + IF_LINK_MODE_DEFAULT, + IF_LINK_MODE_DORMANT, /* limit upward transition to dormant */ +}; /* * Device mapping structure. I'd just gone off and designed a diff --git a/include/linux/netdevice.h b/include/linux/netdevice.h index 7fda03d338d..b825be201bc 100644 --- a/include/linux/netdevice.h +++ b/include/linux/netdevice.h @@ -230,7 +230,8 @@ enum netdev_state_t __LINK_STATE_SCHED, __LINK_STATE_NOCARRIER, __LINK_STATE_RX_SCHED, - __LINK_STATE_LINKWATCH_PENDING + __LINK_STATE_LINKWATCH_PENDING, + __LINK_STATE_DORMANT, }; @@ -335,11 +336,14 @@ struct net_device */ - unsigned short flags; /* interface flags (a la BSD) */ + unsigned int flags; /* interface flags (a la BSD) */ unsigned short gflags; unsigned short priv_flags; /* Like 'flags' but invisible to userspace. */ unsigned short padded; /* How much padding added by alloc_netdev() */ + unsigned char operstate; /* RFC2863 operstate */ + unsigned char link_mode; /* mapping policy to operstate */ + unsigned mtu; /* interface MTU value */ unsigned short type; /* interface hardware type */ unsigned short hard_header_len; /* hardware hdr length */ @@ -714,6 +718,10 @@ static inline void dev_put(struct net_device *dev) /* Carrier loss detection, dial on demand. The functions netif_carrier_on * and _off may be called from IRQ context, but it is caller * who is responsible for serialization of these calls. + * + * The name carrier is inappropriate, these functions should really be + * called netif_lowerlayer_*() because they represent the state of any + * kind of lower layer not just hardware media. */ extern void linkwatch_fire_event(struct net_device *dev); @@ -729,6 +737,29 @@ extern void netif_carrier_on(struct net_device *dev); extern void netif_carrier_off(struct net_device *dev); +static inline void netif_dormant_on(struct net_device *dev) +{ + if (!test_and_set_bit(__LINK_STATE_DORMANT, &dev->state)) + linkwatch_fire_event(dev); +} + +static inline void netif_dormant_off(struct net_device *dev) +{ + if (test_and_clear_bit(__LINK_STATE_DORMANT, &dev->state)) + linkwatch_fire_event(dev); +} + +static inline int netif_dormant(const struct net_device *dev) +{ + return test_bit(__LINK_STATE_DORMANT, &dev->state); +} + + +static inline int netif_oper_up(const struct net_device *dev) { + return (dev->operstate == IF_OPER_UP || + dev->operstate == IF_OPER_UNKNOWN /* backward compat */); +} + /* Hot-plugging. */ static inline int netif_device_present(struct net_device *dev) { diff --git a/include/linux/rtnetlink.h b/include/linux/rtnetlink.h index d50482ba27f..edccefb4518 100644 --- a/include/linux/rtnetlink.h +++ b/include/linux/rtnetlink.h @@ -733,6 +733,8 @@ enum #define IFLA_MAP IFLA_MAP IFLA_WEIGHT, #define IFLA_WEIGHT IFLA_WEIGHT + IFLA_OPERSTATE, + IFLA_LINKMODE, __IFLA_MAX }; diff --git a/net/core/dev.c b/net/core/dev.c index ef56c035d44..8763c99fcb8 100644 --- a/net/core/dev.c +++ b/net/core/dev.c @@ -2174,12 +2174,20 @@ unsigned dev_get_flags(const struct net_device *dev) flags = (dev->flags & ~(IFF_PROMISC | IFF_ALLMULTI | - IFF_RUNNING)) | + IFF_RUNNING | + IFF_LOWER_UP | + IFF_DORMANT)) | (dev->gflags & (IFF_PROMISC | IFF_ALLMULTI)); - if (netif_running(dev) && netif_carrier_ok(dev)) - flags |= IFF_RUNNING; + if (netif_running(dev)) { + if (netif_oper_up(dev)) + flags |= IFF_RUNNING; + if (netif_carrier_ok(dev)) + flags |= IFF_LOWER_UP; + if (netif_dormant(dev)) + flags |= IFF_DORMANT; + } return flags; } diff --git a/net/core/link_watch.c b/net/core/link_watch.c index d43d1201275..e82a451d330 100644 --- a/net/core/link_watch.c +++ b/net/core/link_watch.c @@ -49,6 +49,45 @@ struct lw_event { /* Avoid kmalloc() for most systems */ static struct lw_event singleevent; +static unsigned char default_operstate(const struct net_device *dev) +{ + if (!netif_carrier_ok(dev)) + return (dev->ifindex != dev->iflink ? + IF_OPER_LOWERLAYERDOWN : IF_OPER_DOWN); + + if (netif_dormant(dev)) + return IF_OPER_DORMANT; + + return IF_OPER_UP; +} + + +static void rfc2863_policy(struct net_device *dev) +{ + unsigned char operstate = default_operstate(dev); + + if (operstate == dev->operstate) + return; + + write_lock_bh(&dev_base_lock); + + switch(dev->link_mode) { + case IF_LINK_MODE_DORMANT: + if (operstate == IF_OPER_UP) + operstate = IF_OPER_DORMANT; + break; + + case IF_LINK_MODE_DEFAULT: + default: + break; + }; + + dev->operstate = operstate; + + write_unlock_bh(&dev_base_lock); +} + + /* Must be called with the rtnl semaphore held */ void linkwatch_run_queue(void) { @@ -74,6 +113,7 @@ void linkwatch_run_queue(void) */ clear_bit(__LINK_STATE_LINKWATCH_PENDING, &dev->state); + rfc2863_policy(dev); if (dev->flags & IFF_UP) { if (netif_carrier_ok(dev)) { WARN_ON(dev->qdisc_sleeping == &noop_qdisc); diff --git a/net/core/net-sysfs.c b/net/core/net-sysfs.c index e8b2acbc8ea..21b68464cab 100644 --- a/net/core/net-sysfs.c +++ b/net/core/net-sysfs.c @@ -91,6 +91,7 @@ NETDEVICE_SHOW(iflink, fmt_dec); NETDEVICE_SHOW(ifindex, fmt_dec); NETDEVICE_SHOW(features, fmt_long_hex); NETDEVICE_SHOW(type, fmt_dec); +NETDEVICE_SHOW(link_mode, fmt_dec); /* use same locking rules as GIFHWADDR ioctl's */ static ssize_t format_addr(char *buf, const unsigned char *addr, int len) @@ -133,6 +134,43 @@ static ssize_t show_carrier(struct class_device *dev, char *buf) return -EINVAL; } +static ssize_t show_dormant(struct class_device *dev, char *buf) +{ + struct net_device *netdev = to_net_dev(dev); + + if (netif_running(netdev)) + return sprintf(buf, fmt_dec, !!netif_dormant(netdev)); + + return -EINVAL; +} + +static const char *operstates[] = { + "unknown", + "notpresent", /* currently unused */ + "down", + "lowerlayerdown", + "testing", /* currently unused */ + "dormant", + "up" +}; + +static ssize_t show_operstate(struct class_device *dev, char *buf) +{ + const struct net_device *netdev = to_net_dev(dev); + unsigned char operstate; + + read_lock(&dev_base_lock); + operstate = netdev->operstate; + if (!netif_running(netdev)) + operstate = IF_OPER_DOWN; + read_unlock(&dev_base_lock); + + if (operstate >= sizeof(operstates)) + return -EINVAL; /* should not happen */ + + return sprintf(buf, "%s\n", operstates[operstate]); +} + /* read-write attributes */ NETDEVICE_SHOW(mtu, fmt_dec); @@ -190,9 +228,12 @@ static struct class_device_attribute net_class_attributes[] = { __ATTR(ifindex, S_IRUGO, show_ifindex, NULL), __ATTR(features, S_IRUGO, show_features, NULL), __ATTR(type, S_IRUGO, show_type, NULL), + __ATTR(link_mode, S_IRUGO, show_link_mode, NULL), __ATTR(address, S_IRUGO, show_address, NULL), __ATTR(broadcast, S_IRUGO, show_broadcast, NULL), __ATTR(carrier, S_IRUGO, show_carrier, NULL), + __ATTR(dormant, S_IRUGO, show_dormant, NULL), + __ATTR(operstate, S_IRUGO, show_operstate, NULL), __ATTR(mtu, S_IRUGO | S_IWUSR, show_mtu, store_mtu), __ATTR(flags, S_IRUGO | S_IWUSR, show_flags, store_flags), __ATTR(tx_queue_len, S_IRUGO | S_IWUSR, show_tx_queue_len, diff --git a/net/core/rtnetlink.c b/net/core/rtnetlink.c index eca2976abb2..1c15a907066 100644 --- a/net/core/rtnetlink.c +++ b/net/core/rtnetlink.c @@ -179,6 +179,33 @@ rtattr_failure: } +static void set_operstate(struct net_device *dev, unsigned char transition) +{ + unsigned char operstate = dev->operstate; + + switch(transition) { + case IF_OPER_UP: + if ((operstate == IF_OPER_DORMANT || + operstate == IF_OPER_UNKNOWN) && + !netif_dormant(dev)) + operstate = IF_OPER_UP; + break; + + case IF_OPER_DORMANT: + if (operstate == IF_OPER_UP || + operstate == IF_OPER_UNKNOWN) + operstate = IF_OPER_DORMANT; + break; + }; + + if (dev->operstate != operstate) { + write_lock_bh(&dev_base_lock); + dev->operstate = operstate; + write_unlock_bh(&dev_base_lock); + netdev_state_change(dev); + } +} + static int rtnetlink_fill_ifinfo(struct sk_buff *skb, struct net_device *dev, int type, u32 pid, u32 seq, u32 change, unsigned int flags) @@ -208,6 +235,13 @@ static int rtnetlink_fill_ifinfo(struct sk_buff *skb, struct net_device *dev, RTA_PUT(skb, IFLA_WEIGHT, sizeof(weight), &weight); } + if (1) { + u8 operstate = netif_running(dev)?dev->operstate:IF_OPER_DOWN; + u8 link_mode = dev->link_mode; + RTA_PUT(skb, IFLA_OPERSTATE, sizeof(operstate), &operstate); + RTA_PUT(skb, IFLA_LINKMODE, sizeof(link_mode), &link_mode); + } + if (1) { struct rtnl_link_ifmap map = { .mem_start = dev->mem_start, @@ -399,6 +433,22 @@ static int do_setlink(struct sk_buff *skb, struct nlmsghdr *nlh, void *arg) dev->weight = *((u32 *) RTA_DATA(ida[IFLA_WEIGHT - 1])); } + if (ida[IFLA_OPERSTATE - 1]) { + if (ida[IFLA_OPERSTATE - 1]->rta_len != RTA_LENGTH(sizeof(u8))) + goto out; + + set_operstate(dev, *((u8 *) RTA_DATA(ida[IFLA_OPERSTATE - 1]))); + } + + if (ida[IFLA_LINKMODE - 1]) { + if (ida[IFLA_LINKMODE - 1]->rta_len != RTA_LENGTH(sizeof(u8))) + goto out; + + write_lock_bh(&dev_base_lock); + dev->link_mode = *((u8 *) RTA_DATA(ida[IFLA_LINKMODE - 1])); + write_unlock_bh(&dev_base_lock); + } + if (ifm->ifi_index >= 0 && ida[IFLA_IFNAME - 1]) { char ifname[IFNAMSIZ]; -- cgit v1.2.3-70-g09d2 From 6756ae4b4e97aba48c042b4aa6b77a18f507d2cb Mon Sep 17 00:00:00 2001 From: Stephen Hemminger Date: Mon, 20 Mar 2006 22:23:58 -0800 Subject: [NET]: Convert RTNL to mutex. This patch turns the RTNL from a semaphore to a new 2.6.16 mutex and gets rid of some of the leftover legacy. Signed-off-by: Stephen Hemminger Signed-off-by: David S. Miller --- drivers/net/8139too.c | 2 +- include/linux/rtnetlink.h | 20 +++++++------------- net/core/dev.c | 8 ++++---- net/core/link_watch.c | 4 ++-- net/core/netpoll.c | 6 +++--- net/core/rtnetlink.c | 28 +++++++++++++++++----------- net/ipv4/igmp.c | 24 ++++++++++++------------ net/ipv4/ipconfig.c | 10 +++++----- 8 files changed, 51 insertions(+), 51 deletions(-) (limited to 'net/core/dev.c') diff --git a/drivers/net/8139too.c b/drivers/net/8139too.c index e58d4c50c2e..f5ee064ab6b 100644 --- a/drivers/net/8139too.c +++ b/drivers/net/8139too.c @@ -1605,7 +1605,7 @@ static void rtl8139_thread (void *_data) if (tp->watchdog_fired) { tp->watchdog_fired = 0; rtl8139_tx_timeout_task(_data); - } else if (rtnl_shlock_nowait() == 0) { + } else if (rtnl_trylock()) { rtl8139_thread_iter (dev, tp, tp->mmio_addr); rtnl_unlock (); } else { diff --git a/include/linux/rtnetlink.h b/include/linux/rtnetlink.h index edccefb4518..d263853a8f1 100644 --- a/include/linux/rtnetlink.h +++ b/include/linux/rtnetlink.h @@ -907,6 +907,7 @@ struct tcamsg #ifdef __KERNEL__ #include +#include extern size_t rtattr_strlcpy(char *dest, const struct rtattr *rta, size_t size); static __inline__ int rtattr_strcmp(const struct rtattr *rta, const char *str) @@ -1038,24 +1039,17 @@ __rta_reserve(struct sk_buff *skb, int attrtype, int attrlen) extern void rtmsg_ifinfo(int type, struct net_device *dev, unsigned change); -extern struct semaphore rtnl_sem; - -#define rtnl_shlock() down(&rtnl_sem) -#define rtnl_shlock_nowait() down_trylock(&rtnl_sem) - -#define rtnl_shunlock() do { up(&rtnl_sem); \ - if (rtnl && rtnl->sk_receive_queue.qlen) \ - rtnl->sk_data_ready(rtnl, 0); \ - } while(0) - +/* RTNL is used as a global lock for all changes to network configuration */ extern void rtnl_lock(void); -extern int rtnl_lock_interruptible(void); extern void rtnl_unlock(void); +extern int rtnl_trylock(void); + extern void rtnetlink_init(void); +extern void __rtnl_unlock(void); #define ASSERT_RTNL() do { \ - if (unlikely(down_trylock(&rtnl_sem) == 0)) { \ - up(&rtnl_sem); \ + if (unlikely(rtnl_trylock())) { \ + rtnl_unlock(); \ printk(KERN_ERR "RTNL: assertion failed at %s (%d)\n", \ __FILE__, __LINE__); \ dump_stack(); \ diff --git a/net/core/dev.c b/net/core/dev.c index 8763c99fcb8..be1d896cc5b 100644 --- a/net/core/dev.c +++ b/net/core/dev.c @@ -2466,9 +2466,9 @@ int dev_ioctl(unsigned int cmd, void __user *arg) */ if (cmd == SIOCGIFCONF) { - rtnl_shlock(); + rtnl_lock(); ret = dev_ifconf((char __user *) arg); - rtnl_shunlock(); + rtnl_unlock(); return ret; } if (cmd == SIOCGIFNAME) @@ -2877,7 +2877,7 @@ static void netdev_wait_allrefs(struct net_device *dev) rebroadcast_time = warning_time = jiffies; while (atomic_read(&dev->refcnt) != 0) { if (time_after(jiffies, rebroadcast_time + 1 * HZ)) { - rtnl_shlock(); + rtnl_lock(); /* Rebroadcast unregister notification */ notifier_call_chain(&netdev_chain, @@ -2894,7 +2894,7 @@ static void netdev_wait_allrefs(struct net_device *dev) linkwatch_run_queue(); } - rtnl_shunlock(); + __rtnl_unlock(); rebroadcast_time = jiffies; } diff --git a/net/core/link_watch.c b/net/core/link_watch.c index e82a451d330..341de44c7ed 100644 --- a/net/core/link_watch.c +++ b/net/core/link_watch.c @@ -139,9 +139,9 @@ static void linkwatch_event(void *dummy) linkwatch_nextevent = jiffies + HZ; clear_bit(LW_RUNNING, &linkwatch_flags); - rtnl_shlock(); + rtnl_lock(); linkwatch_run_queue(); - rtnl_shunlock(); + rtnl_unlock(); } diff --git a/net/core/netpoll.c b/net/core/netpoll.c index ea51f8d02eb..e8e05cebd95 100644 --- a/net/core/netpoll.c +++ b/net/core/netpoll.c @@ -669,14 +669,14 @@ int netpoll_setup(struct netpoll *np) printk(KERN_INFO "%s: device %s not up yet, forcing it\n", np->name, np->dev_name); - rtnl_shlock(); + rtnl_lock(); if (dev_change_flags(ndev, ndev->flags | IFF_UP) < 0) { printk(KERN_ERR "%s: failed to open %s\n", np->name, np->dev_name); - rtnl_shunlock(); + rtnl_unlock(); goto release; } - rtnl_shunlock(); + rtnl_unlock(); atleast = jiffies + HZ/10; atmost = jiffies + 4*HZ; diff --git a/net/core/rtnetlink.c b/net/core/rtnetlink.c index 1c15a907066..ae10d3740fa 100644 --- a/net/core/rtnetlink.c +++ b/net/core/rtnetlink.c @@ -35,6 +35,7 @@ #include #include #include +#include #include #include @@ -51,25 +52,31 @@ #include #include -DECLARE_MUTEX(rtnl_sem); +static DEFINE_MUTEX(rtnl_mutex); void rtnl_lock(void) { - rtnl_shlock(); + mutex_lock(&rtnl_mutex); } -int rtnl_lock_interruptible(void) +void __rtnl_unlock(void) { - return down_interruptible(&rtnl_sem); + mutex_unlock(&rtnl_mutex); } - + void rtnl_unlock(void) { - rtnl_shunlock(); - + mutex_unlock(&rtnl_mutex); + if (rtnl && rtnl->sk_receive_queue.qlen) + rtnl->sk_data_ready(rtnl, 0); netdev_run_todo(); } +int rtnl_trylock(void) +{ + return mutex_trylock(&rtnl_mutex); +} + int rtattr_parse(struct rtattr *tb[], int maxattr, struct rtattr *rta, int len) { memset(tb, 0, sizeof(struct rtattr*)*maxattr); @@ -625,9 +632,9 @@ static void rtnetlink_rcv(struct sock *sk, int len) unsigned int qlen = 0; do { - rtnl_lock(); + mutex_lock(&rtnl_mutex); netlink_run_queue(sk, &qlen, &rtnetlink_rcv_msg); - up(&rtnl_sem); + mutex_unlock(&rtnl_mutex); netdev_run_todo(); } while (qlen); @@ -704,6 +711,5 @@ EXPORT_SYMBOL(rtnetlink_links); EXPORT_SYMBOL(rtnetlink_put_metrics); EXPORT_SYMBOL(rtnl); EXPORT_SYMBOL(rtnl_lock); -EXPORT_SYMBOL(rtnl_lock_interruptible); -EXPORT_SYMBOL(rtnl_sem); +EXPORT_SYMBOL(rtnl_trylock); EXPORT_SYMBOL(rtnl_unlock); diff --git a/net/ipv4/igmp.c b/net/ipv4/igmp.c index 64ce52bf048..3ec502f19da 100644 --- a/net/ipv4/igmp.c +++ b/net/ipv4/igmp.c @@ -1730,7 +1730,7 @@ int ip_mc_join_group(struct sock *sk , struct ip_mreqn *imr) if (!MULTICAST(addr)) return -EINVAL; - rtnl_shlock(); + rtnl_lock(); in_dev = ip_mc_find_dev(imr); @@ -1763,7 +1763,7 @@ int ip_mc_join_group(struct sock *sk , struct ip_mreqn *imr) ip_mc_inc_group(in_dev, addr); err = 0; done: - rtnl_shunlock(); + rtnl_unlock(); return err; } @@ -1837,7 +1837,7 @@ int ip_mc_source(int add, int omode, struct sock *sk, struct if (!MULTICAST(addr)) return -EINVAL; - rtnl_shlock(); + rtnl_lock(); imr.imr_multiaddr.s_addr = mreqs->imr_multiaddr; imr.imr_address.s_addr = mreqs->imr_interface; @@ -1947,7 +1947,7 @@ int ip_mc_source(int add, int omode, struct sock *sk, struct ip_mc_add_src(in_dev, &mreqs->imr_multiaddr, omode, 1, &mreqs->imr_sourceaddr, 1); done: - rtnl_shunlock(); + rtnl_unlock(); if (leavegroup) return ip_mc_leave_group(sk, &imr); return err; @@ -1970,7 +1970,7 @@ int ip_mc_msfilter(struct sock *sk, struct ip_msfilter *msf, int ifindex) msf->imsf_fmode != MCAST_EXCLUDE) return -EINVAL; - rtnl_shlock(); + rtnl_lock(); imr.imr_multiaddr.s_addr = msf->imsf_multiaddr; imr.imr_address.s_addr = msf->imsf_interface; @@ -2030,7 +2030,7 @@ int ip_mc_msfilter(struct sock *sk, struct ip_msfilter *msf, int ifindex) pmc->sfmode = msf->imsf_fmode; err = 0; done: - rtnl_shunlock(); + rtnl_unlock(); if (leavegroup) err = ip_mc_leave_group(sk, &imr); return err; @@ -2050,7 +2050,7 @@ int ip_mc_msfget(struct sock *sk, struct ip_msfilter *msf, if (!MULTICAST(addr)) return -EINVAL; - rtnl_shlock(); + rtnl_lock(); imr.imr_multiaddr.s_addr = msf->imsf_multiaddr; imr.imr_address.s_addr = msf->imsf_interface; @@ -2072,7 +2072,7 @@ int ip_mc_msfget(struct sock *sk, struct ip_msfilter *msf, goto done; msf->imsf_fmode = pmc->sfmode; psl = pmc->sflist; - rtnl_shunlock(); + rtnl_unlock(); if (!psl) { len = 0; count = 0; @@ -2091,7 +2091,7 @@ int ip_mc_msfget(struct sock *sk, struct ip_msfilter *msf, return -EFAULT; return 0; done: - rtnl_shunlock(); + rtnl_unlock(); return err; } @@ -2112,7 +2112,7 @@ int ip_mc_gsfget(struct sock *sk, struct group_filter *gsf, if (!MULTICAST(addr)) return -EINVAL; - rtnl_shlock(); + rtnl_lock(); err = -EADDRNOTAVAIL; @@ -2125,7 +2125,7 @@ int ip_mc_gsfget(struct sock *sk, struct group_filter *gsf, goto done; gsf->gf_fmode = pmc->sfmode; psl = pmc->sflist; - rtnl_shunlock(); + rtnl_unlock(); count = psl ? psl->sl_count : 0; copycount = count < gsf->gf_numsrc ? count : gsf->gf_numsrc; gsf->gf_numsrc = count; @@ -2146,7 +2146,7 @@ int ip_mc_gsfget(struct sock *sk, struct group_filter *gsf, } return 0; done: - rtnl_shunlock(); + rtnl_unlock(); return err; } diff --git a/net/ipv4/ipconfig.c b/net/ipv4/ipconfig.c index bb3613ec448..cb8a92f18ef 100644 --- a/net/ipv4/ipconfig.c +++ b/net/ipv4/ipconfig.c @@ -186,7 +186,7 @@ static int __init ic_open_devs(void) unsigned short oflags; last = &ic_first_dev; - rtnl_shlock(); + rtnl_lock(); /* bring loopback device up first */ if (dev_change_flags(&loopback_dev, loopback_dev.flags | IFF_UP) < 0) @@ -215,7 +215,7 @@ static int __init ic_open_devs(void) continue; } if (!(d = kmalloc(sizeof(struct ic_device), GFP_KERNEL))) { - rtnl_shunlock(); + rtnl_unlock(); return -1; } d->dev = dev; @@ -232,7 +232,7 @@ static int __init ic_open_devs(void) dev->name, able, d->xid)); } } - rtnl_shunlock(); + rtnl_unlock(); *last = NULL; @@ -251,7 +251,7 @@ static void __init ic_close_devs(void) struct ic_device *d, *next; struct net_device *dev; - rtnl_shlock(); + rtnl_lock(); next = ic_first_dev; while ((d = next)) { next = d->next; @@ -262,7 +262,7 @@ static void __init ic_close_devs(void) } kfree(d); } - rtnl_shunlock(); + rtnl_unlock(); } /* -- cgit v1.2.3-70-g09d2 From 8aca8a27d96cd75a30c380130496c98b658c9b98 Mon Sep 17 00:00:00 2001 From: Stephen Hemminger Date: Mon, 20 Mar 2006 22:26:39 -0800 Subject: [NET]: minor net_rx_action optimization The functions list_del followed by list_add_tail is equivalent to the existing inline list_move_tail. list_move_tail avoids unnecessary _LIST_POISON. Signed-off-by: Stephen Hemminger Signed-off-by: David S. Miller --- net/core/dev.c | 3 +-- 1 file changed, 1 insertion(+), 2 deletions(-) (limited to 'net/core/dev.c') diff --git a/net/core/dev.c b/net/core/dev.c index be1d896cc5b..ee044097f7f 100644 --- a/net/core/dev.c +++ b/net/core/dev.c @@ -1759,8 +1759,7 @@ static void net_rx_action(struct softirq_action *h) if (dev->quota <= 0 || dev->poll(dev, &budget)) { netpoll_poll_unlock(have); local_irq_disable(); - list_del(&dev->poll_list); - list_add_tail(&dev->poll_list, &queue->poll_list); + list_move_tail(&dev->poll_list, &queue->poll_list); if (dev->quota < 0) dev->quota += dev->weight; else -- cgit v1.2.3-70-g09d2 From 4a3e2f711a00a1feb72ae12fdc749da10179d185 Mon Sep 17 00:00:00 2001 From: Arjan van de Ven Date: Mon, 20 Mar 2006 22:33:17 -0800 Subject: [NET] sem2mutex: net/ Semaphore to mutex conversion. The conversion was generated via scripts, and the result was validated automatically via a script as well. Signed-off-by: Arjan van de Ven Signed-off-by: Ingo Molnar Signed-off-by: Andrew Morton Signed-off-by: David S. Miller --- include/net/xfrm.h | 3 ++- net/atm/ioctl.c | 15 ++++++++------- net/bluetooth/rfcomm/core.c | 8 +++++--- net/core/dev.c | 7 ++++--- net/core/flow.c | 7 ++++--- net/ipv4/ipcomp.c | 17 +++++++++-------- net/ipv4/netfilter/ip_queue.c | 11 ++++++----- net/ipv4/xfrm4_tunnel.c | 11 ++++++----- net/ipv6/ipcomp6.c | 15 ++++++++------- net/ipv6/netfilter/ip6_queue.c | 11 ++++++----- net/ipv6/xfrm6_tunnel.c | 11 ++++++----- net/key/af_key.c | 4 ++-- net/netfilter/nf_sockopt.c | 25 +++++++++++++------------ net/socket.c | 31 ++++++++++++++++--------------- net/sunrpc/cache.c | 17 +++++++++-------- net/sunrpc/sched.c | 11 ++++++----- net/unix/garbage.c | 7 ++++--- net/xfrm/xfrm_policy.c | 4 ++-- net/xfrm/xfrm_user.c | 4 ++-- 19 files changed, 118 insertions(+), 101 deletions(-) (limited to 'net/core/dev.c') diff --git a/include/net/xfrm.h b/include/net/xfrm.h index 156f52ef8a9..786371365f2 100644 --- a/include/net/xfrm.h +++ b/include/net/xfrm.h @@ -11,6 +11,7 @@ #include #include #include +#include #include #include @@ -24,7 +25,7 @@ extern struct sock *xfrm_nl; extern u32 sysctl_xfrm_aevent_etime; extern u32 sysctl_xfrm_aevent_rseqth; -extern struct semaphore xfrm_cfg_sem; +extern struct mutex xfrm_cfg_mutex; /* Organization of SPD aka "XFRM rules" ------------------------------------ diff --git a/net/atm/ioctl.c b/net/atm/ioctl.c index eb109af7eb4..851cfa6312a 100644 --- a/net/atm/ioctl.c +++ b/net/atm/ioctl.c @@ -18,6 +18,7 @@ #include #include #include +#include #include #include "resources.h" @@ -25,22 +26,22 @@ #include "common.h" -static DECLARE_MUTEX(ioctl_mutex); +static DEFINE_MUTEX(ioctl_mutex); static LIST_HEAD(ioctl_list); void register_atm_ioctl(struct atm_ioctl *ioctl) { - down(&ioctl_mutex); + mutex_lock(&ioctl_mutex); list_add_tail(&ioctl->list, &ioctl_list); - up(&ioctl_mutex); + mutex_unlock(&ioctl_mutex); } void deregister_atm_ioctl(struct atm_ioctl *ioctl) { - down(&ioctl_mutex); + mutex_lock(&ioctl_mutex); list_del(&ioctl->list); - up(&ioctl_mutex); + mutex_unlock(&ioctl_mutex); } EXPORT_SYMBOL(register_atm_ioctl); @@ -137,7 +138,7 @@ int vcc_ioctl(struct socket *sock, unsigned int cmd, unsigned long arg) error = -ENOIOCTLCMD; - down(&ioctl_mutex); + mutex_lock(&ioctl_mutex); list_for_each(pos, &ioctl_list) { struct atm_ioctl * ic = list_entry(pos, struct atm_ioctl, list); if (try_module_get(ic->owner)) { @@ -147,7 +148,7 @@ int vcc_ioctl(struct socket *sock, unsigned int cmd, unsigned long arg) break; } } - up(&ioctl_mutex); + mutex_unlock(&ioctl_mutex); if (error != -ENOIOCTLCMD) goto done; diff --git a/net/bluetooth/rfcomm/core.c b/net/bluetooth/rfcomm/core.c index 5b4253c61f6..e99010ce8bb 100644 --- a/net/bluetooth/rfcomm/core.c +++ b/net/bluetooth/rfcomm/core.c @@ -37,6 +37,8 @@ #include #include #include +#include + #include #include #include @@ -57,9 +59,9 @@ static unsigned int l2cap_mtu = RFCOMM_MAX_L2CAP_MTU; static struct task_struct *rfcomm_thread; -static DECLARE_MUTEX(rfcomm_sem); -#define rfcomm_lock() down(&rfcomm_sem); -#define rfcomm_unlock() up(&rfcomm_sem); +static DEFINE_MUTEX(rfcomm_mutex); +#define rfcomm_lock() mutex_lock(&rfcomm_mutex) +#define rfcomm_unlock() mutex_unlock(&rfcomm_mutex) static unsigned long rfcomm_event; diff --git a/net/core/dev.c b/net/core/dev.c index ee044097f7f..08dec6eb922 100644 --- a/net/core/dev.c +++ b/net/core/dev.c @@ -81,6 +81,7 @@ #include #include #include +#include #include #include #include @@ -2931,7 +2932,7 @@ static void netdev_wait_allrefs(struct net_device *dev) * 2) Since we run with the RTNL semaphore not held, we can sleep * safely in order to wait for the netdev refcnt to drop to zero. */ -static DECLARE_MUTEX(net_todo_run_mutex); +static DEFINE_MUTEX(net_todo_run_mutex); void netdev_run_todo(void) { struct list_head list = LIST_HEAD_INIT(list); @@ -2939,7 +2940,7 @@ void netdev_run_todo(void) /* Need to guard against multiple cpu's getting out of order. */ - down(&net_todo_run_mutex); + mutex_lock(&net_todo_run_mutex); /* Not safe to do outside the semaphore. We must not return * until all unregister events invoked by the local processor @@ -2996,7 +2997,7 @@ void netdev_run_todo(void) } out: - up(&net_todo_run_mutex); + mutex_unlock(&net_todo_run_mutex); } /** diff --git a/net/core/flow.c b/net/core/flow.c index c4f25385029..55789f832ed 100644 --- a/net/core/flow.c +++ b/net/core/flow.c @@ -20,6 +20,7 @@ #include #include #include +#include #include #include #include @@ -287,11 +288,11 @@ static void flow_cache_flush_per_cpu(void *data) void flow_cache_flush(void) { struct flow_flush_info info; - static DECLARE_MUTEX(flow_flush_sem); + static DEFINE_MUTEX(flow_flush_sem); /* Don't want cpus going down or up during this. */ lock_cpu_hotplug(); - down(&flow_flush_sem); + mutex_lock(&flow_flush_sem); atomic_set(&info.cpuleft, num_online_cpus()); init_completion(&info.completion); @@ -301,7 +302,7 @@ void flow_cache_flush(void) local_bh_enable(); wait_for_completion(&info.completion); - up(&flow_flush_sem); + mutex_unlock(&flow_flush_sem); unlock_cpu_hotplug(); } diff --git a/net/ipv4/ipcomp.c b/net/ipv4/ipcomp.c index d64e2ec8da7..c95020f7c81 100644 --- a/net/ipv4/ipcomp.c +++ b/net/ipv4/ipcomp.c @@ -24,6 +24,7 @@ #include #include #include +#include #include #include #include @@ -36,7 +37,7 @@ struct ipcomp_tfms { int users; }; -static DECLARE_MUTEX(ipcomp_resource_sem); +static DEFINE_MUTEX(ipcomp_resource_mutex); static void **ipcomp_scratches; static int ipcomp_scratch_users; static LIST_HEAD(ipcomp_tfms_list); @@ -253,7 +254,7 @@ error: } /* - * Must be protected by xfrm_cfg_sem. State and tunnel user references are + * Must be protected by xfrm_cfg_mutex. State and tunnel user references are * always incremented on success. */ static int ipcomp_tunnel_attach(struct xfrm_state *x) @@ -411,9 +412,9 @@ static void ipcomp_destroy(struct xfrm_state *x) if (!ipcd) return; xfrm_state_delete_tunnel(x); - down(&ipcomp_resource_sem); + mutex_lock(&ipcomp_resource_mutex); ipcomp_free_data(ipcd); - up(&ipcomp_resource_sem); + mutex_unlock(&ipcomp_resource_mutex); kfree(ipcd); } @@ -440,14 +441,14 @@ static int ipcomp_init_state(struct xfrm_state *x) if (x->props.mode) x->props.header_len += sizeof(struct iphdr); - down(&ipcomp_resource_sem); + mutex_lock(&ipcomp_resource_mutex); if (!ipcomp_alloc_scratches()) goto error; ipcd->tfms = ipcomp_alloc_tfms(x->calg->alg_name); if (!ipcd->tfms) goto error; - up(&ipcomp_resource_sem); + mutex_unlock(&ipcomp_resource_mutex); if (x->props.mode) { err = ipcomp_tunnel_attach(x); @@ -464,10 +465,10 @@ out: return err; error_tunnel: - down(&ipcomp_resource_sem); + mutex_lock(&ipcomp_resource_mutex); error: ipcomp_free_data(ipcd); - up(&ipcomp_resource_sem); + mutex_unlock(&ipcomp_resource_mutex); kfree(ipcd); goto out; } diff --git a/net/ipv4/netfilter/ip_queue.c b/net/ipv4/netfilter/ip_queue.c index 08f80e2ea2a..1655866c55b 100644 --- a/net/ipv4/netfilter/ip_queue.c +++ b/net/ipv4/netfilter/ip_queue.c @@ -35,6 +35,7 @@ #include #include #include +#include #include #include @@ -61,7 +62,7 @@ static unsigned int queue_dropped = 0; static unsigned int queue_user_dropped = 0; static struct sock *ipqnl; static LIST_HEAD(queue_list); -static DECLARE_MUTEX(ipqnl_sem); +static DEFINE_MUTEX(ipqnl_mutex); static void ipq_issue_verdict(struct ipq_queue_entry *entry, int verdict) @@ -539,7 +540,7 @@ ipq_rcv_sk(struct sock *sk, int len) struct sk_buff *skb; unsigned int qlen; - down(&ipqnl_sem); + mutex_lock(&ipqnl_mutex); for (qlen = skb_queue_len(&sk->sk_receive_queue); qlen; qlen--) { skb = skb_dequeue(&sk->sk_receive_queue); @@ -547,7 +548,7 @@ ipq_rcv_sk(struct sock *sk, int len) kfree_skb(skb); } - up(&ipqnl_sem); + mutex_unlock(&ipqnl_mutex); } static int @@ -708,8 +709,8 @@ cleanup_sysctl: cleanup_ipqnl: sock_release(ipqnl->sk_socket); - down(&ipqnl_sem); - up(&ipqnl_sem); + mutex_lock(&ipqnl_mutex); + mutex_unlock(&ipqnl_mutex); cleanup_netlink_notifier: netlink_unregister_notifier(&ipq_nl_notifier); diff --git a/net/ipv4/xfrm4_tunnel.c b/net/ipv4/xfrm4_tunnel.c index afbb0d4cc30..b08d56b117f 100644 --- a/net/ipv4/xfrm4_tunnel.c +++ b/net/ipv4/xfrm4_tunnel.c @@ -5,6 +5,7 @@ #include #include +#include #include #include #include @@ -26,19 +27,19 @@ static int ipip_xfrm_rcv(struct xfrm_state *x, struct xfrm_decap_state *decap, s } static struct xfrm_tunnel *ipip_handler; -static DECLARE_MUTEX(xfrm4_tunnel_sem); +static DEFINE_MUTEX(xfrm4_tunnel_mutex); int xfrm4_tunnel_register(struct xfrm_tunnel *handler) { int ret; - down(&xfrm4_tunnel_sem); + mutex_lock(&xfrm4_tunnel_mutex); ret = 0; if (ipip_handler != NULL) ret = -EINVAL; if (!ret) ipip_handler = handler; - up(&xfrm4_tunnel_sem); + mutex_unlock(&xfrm4_tunnel_mutex); return ret; } @@ -49,13 +50,13 @@ int xfrm4_tunnel_deregister(struct xfrm_tunnel *handler) { int ret; - down(&xfrm4_tunnel_sem); + mutex_lock(&xfrm4_tunnel_mutex); ret = 0; if (ipip_handler != handler) ret = -EINVAL; if (!ret) ipip_handler = NULL; - up(&xfrm4_tunnel_sem); + mutex_unlock(&xfrm4_tunnel_mutex); synchronize_net(); diff --git a/net/ipv6/ipcomp6.c b/net/ipv6/ipcomp6.c index 6107592fbd8..3c7b324cd20 100644 --- a/net/ipv6/ipcomp6.c +++ b/net/ipv6/ipcomp6.c @@ -50,6 +50,7 @@ #include #include #include +#include struct ipcomp6_tfms { struct list_head list; @@ -57,7 +58,7 @@ struct ipcomp6_tfms { int users; }; -static DECLARE_MUTEX(ipcomp6_resource_sem); +static DEFINE_MUTEX(ipcomp6_resource_mutex); static void **ipcomp6_scratches; static int ipcomp6_scratch_users; static LIST_HEAD(ipcomp6_tfms_list); @@ -405,9 +406,9 @@ static void ipcomp6_destroy(struct xfrm_state *x) if (!ipcd) return; xfrm_state_delete_tunnel(x); - down(&ipcomp6_resource_sem); + mutex_lock(&ipcomp6_resource_mutex); ipcomp6_free_data(ipcd); - up(&ipcomp6_resource_sem); + mutex_unlock(&ipcomp6_resource_mutex); kfree(ipcd); xfrm6_tunnel_free_spi((xfrm_address_t *)&x->props.saddr); @@ -436,14 +437,14 @@ static int ipcomp6_init_state(struct xfrm_state *x) if (x->props.mode) x->props.header_len += sizeof(struct ipv6hdr); - down(&ipcomp6_resource_sem); + mutex_lock(&ipcomp6_resource_mutex); if (!ipcomp6_alloc_scratches()) goto error; ipcd->tfms = ipcomp6_alloc_tfms(x->calg->alg_name); if (!ipcd->tfms) goto error; - up(&ipcomp6_resource_sem); + mutex_unlock(&ipcomp6_resource_mutex); if (x->props.mode) { err = ipcomp6_tunnel_attach(x); @@ -459,10 +460,10 @@ static int ipcomp6_init_state(struct xfrm_state *x) out: return err; error_tunnel: - down(&ipcomp6_resource_sem); + mutex_lock(&ipcomp6_resource_mutex); error: ipcomp6_free_data(ipcd); - up(&ipcomp6_resource_sem); + mutex_unlock(&ipcomp6_resource_mutex); kfree(ipcd); goto out; diff --git a/net/ipv6/netfilter/ip6_queue.c b/net/ipv6/netfilter/ip6_queue.c index af0635084df..344eab3b5da 100644 --- a/net/ipv6/netfilter/ip6_queue.c +++ b/net/ipv6/netfilter/ip6_queue.c @@ -35,6 +35,7 @@ #include #include #include +#include #include #include #include @@ -65,7 +66,7 @@ static unsigned int queue_dropped = 0; static unsigned int queue_user_dropped = 0; static struct sock *ipqnl; static LIST_HEAD(queue_list); -static DECLARE_MUTEX(ipqnl_sem); +static DEFINE_MUTEX(ipqnl_mutex); static void ipq_issue_verdict(struct ipq_queue_entry *entry, int verdict) @@ -537,7 +538,7 @@ ipq_rcv_sk(struct sock *sk, int len) struct sk_buff *skb; unsigned int qlen; - down(&ipqnl_sem); + mutex_lock(&ipqnl_mutex); for (qlen = skb_queue_len(&sk->sk_receive_queue); qlen; qlen--) { skb = skb_dequeue(&sk->sk_receive_queue); @@ -545,7 +546,7 @@ ipq_rcv_sk(struct sock *sk, int len) kfree_skb(skb); } - up(&ipqnl_sem); + mutex_unlock(&ipqnl_mutex); } static int @@ -704,8 +705,8 @@ cleanup_sysctl: cleanup_ipqnl: sock_release(ipqnl->sk_socket); - down(&ipqnl_sem); - up(&ipqnl_sem); + mutex_lock(&ipqnl_mutex); + mutex_unlock(&ipqnl_mutex); cleanup_netlink_notifier: netlink_unregister_notifier(&ipq_nl_notifier); diff --git a/net/ipv6/xfrm6_tunnel.c b/net/ipv6/xfrm6_tunnel.c index 8cfc58b96fc..08f9abbdf1d 100644 --- a/net/ipv6/xfrm6_tunnel.c +++ b/net/ipv6/xfrm6_tunnel.c @@ -31,6 +31,7 @@ #include #include #include +#include #ifdef CONFIG_IPV6_XFRM6_TUNNEL_DEBUG # define X6TDEBUG 3 @@ -357,19 +358,19 @@ static int xfrm6_tunnel_input(struct xfrm_state *x, struct xfrm_decap_state *dec } static struct xfrm6_tunnel *xfrm6_tunnel_handler; -static DECLARE_MUTEX(xfrm6_tunnel_sem); +static DEFINE_MUTEX(xfrm6_tunnel_mutex); int xfrm6_tunnel_register(struct xfrm6_tunnel *handler) { int ret; - down(&xfrm6_tunnel_sem); + mutex_lock(&xfrm6_tunnel_mutex); ret = 0; if (xfrm6_tunnel_handler != NULL) ret = -EINVAL; if (!ret) xfrm6_tunnel_handler = handler; - up(&xfrm6_tunnel_sem); + mutex_unlock(&xfrm6_tunnel_mutex); return ret; } @@ -380,13 +381,13 @@ int xfrm6_tunnel_deregister(struct xfrm6_tunnel *handler) { int ret; - down(&xfrm6_tunnel_sem); + mutex_lock(&xfrm6_tunnel_mutex); ret = 0; if (xfrm6_tunnel_handler != handler) ret = -EINVAL; if (!ret) xfrm6_tunnel_handler = NULL; - up(&xfrm6_tunnel_sem); + mutex_unlock(&xfrm6_tunnel_mutex); synchronize_net(); diff --git a/net/key/af_key.c b/net/key/af_key.c index 520fe70d099..859582275ca 100644 --- a/net/key/af_key.c +++ b/net/key/af_key.c @@ -3080,9 +3080,9 @@ static int pfkey_sendmsg(struct kiocb *kiocb, if (!hdr) goto out; - down(&xfrm_cfg_sem); + mutex_lock(&xfrm_cfg_mutex); err = pfkey_process(sk, skb, hdr); - up(&xfrm_cfg_sem); + mutex_unlock(&xfrm_cfg_mutex); out: if (err && hdr && pfkey_error(hdr, err, sk) == 0) diff --git a/net/netfilter/nf_sockopt.c b/net/netfilter/nf_sockopt.c index 61a833a9caa..0e5c5e20479 100644 --- a/net/netfilter/nf_sockopt.c +++ b/net/netfilter/nf_sockopt.c @@ -4,6 +4,7 @@ #include #include #include +#include #include #include "nf_internals.h" @@ -11,7 +12,7 @@ /* Sockopts only registered and called from user context, so net locking would be overkill. Also, [gs]etsockopt calls may sleep. */ -static DECLARE_MUTEX(nf_sockopt_mutex); +static DEFINE_MUTEX(nf_sockopt_mutex); static LIST_HEAD(nf_sockopts); /* Do exclusive ranges overlap? */ @@ -26,7 +27,7 @@ int nf_register_sockopt(struct nf_sockopt_ops *reg) struct list_head *i; int ret = 0; - if (down_interruptible(&nf_sockopt_mutex) != 0) + if (mutex_lock_interruptible(&nf_sockopt_mutex) != 0) return -EINTR; list_for_each(i, &nf_sockopts) { @@ -48,7 +49,7 @@ int nf_register_sockopt(struct nf_sockopt_ops *reg) list_add(®->list, &nf_sockopts); out: - up(&nf_sockopt_mutex); + mutex_unlock(&nf_sockopt_mutex); return ret; } EXPORT_SYMBOL(nf_register_sockopt); @@ -57,18 +58,18 @@ void nf_unregister_sockopt(struct nf_sockopt_ops *reg) { /* No point being interruptible: we're probably in cleanup_module() */ restart: - down(&nf_sockopt_mutex); + mutex_lock(&nf_sockopt_mutex); if (reg->use != 0) { /* To be woken by nf_sockopt call... */ /* FIXME: Stuart Young's name appears gratuitously. */ set_current_state(TASK_UNINTERRUPTIBLE); reg->cleanup_task = current; - up(&nf_sockopt_mutex); + mutex_unlock(&nf_sockopt_mutex); schedule(); goto restart; } list_del(®->list); - up(&nf_sockopt_mutex); + mutex_unlock(&nf_sockopt_mutex); } EXPORT_SYMBOL(nf_unregister_sockopt); @@ -80,7 +81,7 @@ static int nf_sockopt(struct sock *sk, int pf, int val, struct nf_sockopt_ops *ops; int ret; - if (down_interruptible(&nf_sockopt_mutex) != 0) + if (mutex_lock_interruptible(&nf_sockopt_mutex) != 0) return -EINTR; list_for_each(i, &nf_sockopts) { @@ -90,7 +91,7 @@ static int nf_sockopt(struct sock *sk, int pf, int val, if (val >= ops->get_optmin && val < ops->get_optmax) { ops->use++; - up(&nf_sockopt_mutex); + mutex_unlock(&nf_sockopt_mutex); ret = ops->get(sk, val, opt, len); goto out; } @@ -98,22 +99,22 @@ static int nf_sockopt(struct sock *sk, int pf, int val, if (val >= ops->set_optmin && val < ops->set_optmax) { ops->use++; - up(&nf_sockopt_mutex); + mutex_unlock(&nf_sockopt_mutex); ret = ops->set(sk, val, opt, *len); goto out; } } } } - up(&nf_sockopt_mutex); + mutex_unlock(&nf_sockopt_mutex); return -ENOPROTOOPT; out: - down(&nf_sockopt_mutex); + mutex_lock(&nf_sockopt_mutex); ops->use--; if (ops->cleanup_task) wake_up_process(ops->cleanup_task); - up(&nf_sockopt_mutex); + mutex_unlock(&nf_sockopt_mutex); return ret; } diff --git a/net/socket.c b/net/socket.c index 510ae18d220..e3c21d5ec28 100644 --- a/net/socket.c +++ b/net/socket.c @@ -68,6 +68,7 @@ #include #include #include +#include #include #include #include @@ -826,36 +827,36 @@ static ssize_t sock_aio_write(struct kiocb *iocb, const char __user *ubuf, * with module unload. */ -static DECLARE_MUTEX(br_ioctl_mutex); +static DEFINE_MUTEX(br_ioctl_mutex); static int (*br_ioctl_hook)(unsigned int cmd, void __user *arg) = NULL; void brioctl_set(int (*hook)(unsigned int, void __user *)) { - down(&br_ioctl_mutex); + mutex_lock(&br_ioctl_mutex); br_ioctl_hook = hook; - up(&br_ioctl_mutex); + mutex_unlock(&br_ioctl_mutex); } EXPORT_SYMBOL(brioctl_set); -static DECLARE_MUTEX(vlan_ioctl_mutex); +static DEFINE_MUTEX(vlan_ioctl_mutex); static int (*vlan_ioctl_hook)(void __user *arg); void vlan_ioctl_set(int (*hook)(void __user *)) { - down(&vlan_ioctl_mutex); + mutex_lock(&vlan_ioctl_mutex); vlan_ioctl_hook = hook; - up(&vlan_ioctl_mutex); + mutex_unlock(&vlan_ioctl_mutex); } EXPORT_SYMBOL(vlan_ioctl_set); -static DECLARE_MUTEX(dlci_ioctl_mutex); +static DEFINE_MUTEX(dlci_ioctl_mutex); static int (*dlci_ioctl_hook)(unsigned int, void __user *); void dlci_ioctl_set(int (*hook)(unsigned int, void __user *)) { - down(&dlci_ioctl_mutex); + mutex_lock(&dlci_ioctl_mutex); dlci_ioctl_hook = hook; - up(&dlci_ioctl_mutex); + mutex_unlock(&dlci_ioctl_mutex); } EXPORT_SYMBOL(dlci_ioctl_set); @@ -899,10 +900,10 @@ static long sock_ioctl(struct file *file, unsigned cmd, unsigned long arg) if (!br_ioctl_hook) request_module("bridge"); - down(&br_ioctl_mutex); + mutex_lock(&br_ioctl_mutex); if (br_ioctl_hook) err = br_ioctl_hook(cmd, argp); - up(&br_ioctl_mutex); + mutex_unlock(&br_ioctl_mutex); break; case SIOCGIFVLAN: case SIOCSIFVLAN: @@ -910,10 +911,10 @@ static long sock_ioctl(struct file *file, unsigned cmd, unsigned long arg) if (!vlan_ioctl_hook) request_module("8021q"); - down(&vlan_ioctl_mutex); + mutex_lock(&vlan_ioctl_mutex); if (vlan_ioctl_hook) err = vlan_ioctl_hook(argp); - up(&vlan_ioctl_mutex); + mutex_unlock(&vlan_ioctl_mutex); break; case SIOCGIFDIVERT: case SIOCSIFDIVERT: @@ -927,9 +928,9 @@ static long sock_ioctl(struct file *file, unsigned cmd, unsigned long arg) request_module("dlci"); if (dlci_ioctl_hook) { - down(&dlci_ioctl_mutex); + mutex_lock(&dlci_ioctl_mutex); err = dlci_ioctl_hook(cmd, argp); - up(&dlci_ioctl_mutex); + mutex_unlock(&dlci_ioctl_mutex); } break; default: diff --git a/net/sunrpc/cache.c b/net/sunrpc/cache.c index dcaa0c4453f..0acccfeeb28 100644 --- a/net/sunrpc/cache.c +++ b/net/sunrpc/cache.c @@ -26,6 +26,7 @@ #include #include #include +#include #include #include #include @@ -532,7 +533,7 @@ void cache_clean_deferred(void *owner) */ static DEFINE_SPINLOCK(queue_lock); -static DECLARE_MUTEX(queue_io_sem); +static DEFINE_MUTEX(queue_io_mutex); struct cache_queue { struct list_head list; @@ -561,7 +562,7 @@ cache_read(struct file *filp, char __user *buf, size_t count, loff_t *ppos) if (count == 0) return 0; - down(&queue_io_sem); /* protect against multiple concurrent + mutex_lock(&queue_io_mutex); /* protect against multiple concurrent * readers on this file */ again: spin_lock(&queue_lock); @@ -574,7 +575,7 @@ cache_read(struct file *filp, char __user *buf, size_t count, loff_t *ppos) } if (rp->q.list.next == &cd->queue) { spin_unlock(&queue_lock); - up(&queue_io_sem); + mutex_unlock(&queue_io_mutex); BUG_ON(rp->offset); return 0; } @@ -621,11 +622,11 @@ cache_read(struct file *filp, char __user *buf, size_t count, loff_t *ppos) } if (err == -EAGAIN) goto again; - up(&queue_io_sem); + mutex_unlock(&queue_io_mutex); return err ? err : count; } -static char write_buf[8192]; /* protected by queue_io_sem */ +static char write_buf[8192]; /* protected by queue_io_mutex */ static ssize_t cache_write(struct file *filp, const char __user *buf, size_t count, @@ -639,10 +640,10 @@ cache_write(struct file *filp, const char __user *buf, size_t count, if (count >= sizeof(write_buf)) return -EINVAL; - down(&queue_io_sem); + mutex_lock(&queue_io_mutex); if (copy_from_user(write_buf, buf, count)) { - up(&queue_io_sem); + mutex_unlock(&queue_io_mutex); return -EFAULT; } write_buf[count] = '\0'; @@ -651,7 +652,7 @@ cache_write(struct file *filp, const char __user *buf, size_t count, else err = -EINVAL; - up(&queue_io_sem); + mutex_unlock(&queue_io_mutex); return err ? err : count; } diff --git a/net/sunrpc/sched.c b/net/sunrpc/sched.c index e838d042f7f..dff07795bd1 100644 --- a/net/sunrpc/sched.c +++ b/net/sunrpc/sched.c @@ -18,6 +18,7 @@ #include #include #include +#include #include #include @@ -62,7 +63,7 @@ static LIST_HEAD(all_tasks); /* * rpciod-related stuff */ -static DECLARE_MUTEX(rpciod_sema); +static DEFINE_MUTEX(rpciod_mutex); static unsigned int rpciod_users; static struct workqueue_struct *rpciod_workqueue; @@ -1047,7 +1048,7 @@ rpciod_up(void) struct workqueue_struct *wq; int error = 0; - down(&rpciod_sema); + mutex_lock(&rpciod_mutex); dprintk("rpciod_up: users %d\n", rpciod_users); rpciod_users++; if (rpciod_workqueue) @@ -1070,14 +1071,14 @@ rpciod_up(void) rpciod_workqueue = wq; error = 0; out: - up(&rpciod_sema); + mutex_unlock(&rpciod_mutex); return error; } void rpciod_down(void) { - down(&rpciod_sema); + mutex_lock(&rpciod_mutex); dprintk("rpciod_down sema %d\n", rpciod_users); if (rpciod_users) { if (--rpciod_users) @@ -1094,7 +1095,7 @@ rpciod_down(void) destroy_workqueue(rpciod_workqueue); rpciod_workqueue = NULL; out: - up(&rpciod_sema); + mutex_unlock(&rpciod_mutex); } #ifdef RPC_DEBUG diff --git a/net/unix/garbage.c b/net/unix/garbage.c index 411802bd4d3..746c2f4a5fa 100644 --- a/net/unix/garbage.c +++ b/net/unix/garbage.c @@ -76,6 +76,7 @@ #include #include #include +#include #include #include @@ -169,7 +170,7 @@ static void maybe_unmark_and_push(struct sock *x) void unix_gc(void) { - static DECLARE_MUTEX(unix_gc_sem); + static DEFINE_MUTEX(unix_gc_sem); int i; struct sock *s; struct sk_buff_head hitlist; @@ -179,7 +180,7 @@ void unix_gc(void) * Avoid a recursive GC. */ - if (down_trylock(&unix_gc_sem)) + if (!mutex_trylock(&unix_gc_sem)) return; spin_lock(&unix_table_lock); @@ -308,5 +309,5 @@ void unix_gc(void) */ __skb_queue_purge(&hitlist); - up(&unix_gc_sem); + mutex_unlock(&unix_gc_sem); } diff --git a/net/xfrm/xfrm_policy.c b/net/xfrm/xfrm_policy.c index b46079263e8..f5eae9febd2 100644 --- a/net/xfrm/xfrm_policy.c +++ b/net/xfrm/xfrm_policy.c @@ -26,8 +26,8 @@ #include #include -DECLARE_MUTEX(xfrm_cfg_sem); -EXPORT_SYMBOL(xfrm_cfg_sem); +DEFINE_MUTEX(xfrm_cfg_mutex); +EXPORT_SYMBOL(xfrm_cfg_mutex); static DEFINE_RWLOCK(xfrm_policy_lock); diff --git a/net/xfrm/xfrm_user.c b/net/xfrm/xfrm_user.c index 7b1acd99516..4a7120a7e10 100644 --- a/net/xfrm/xfrm_user.c +++ b/net/xfrm/xfrm_user.c @@ -1486,9 +1486,9 @@ static void xfrm_netlink_rcv(struct sock *sk, int len) unsigned int qlen = 0; do { - down(&xfrm_cfg_sem); + mutex_lock(&xfrm_cfg_mutex); netlink_run_queue(sk, &qlen, &xfrm_user_rcv_msg); - up(&xfrm_cfg_sem); + mutex_unlock(&xfrm_cfg_mutex); } while (qlen); } -- cgit v1.2.3-70-g09d2 From 9f514950bb907e98f280492a091aa1889b97304e Mon Sep 17 00:00:00 2001 From: Herbert Xu Date: Sat, 25 Mar 2006 01:24:25 -0800 Subject: [NET]: Take RTNL when unregistering notifier The netdev notifier call chain is currently unregistered without taking any locks outside the notifier system. Because the notifier system itself does not synchronise unregistration with respect to the calling of the chain, we as its user need to do our own locking. We are supposed to take the RTNL for all calls to netdev notifiers, so taking the RTNL should be sufficient to protect it. The registration path in dev.c already takes the RTNL so it's OK. Signed-off-by: Herbert Xu Signed-off-by: David S. Miller --- net/core/dev.c | 7 ++++++- 1 file changed, 6 insertions(+), 1 deletion(-) (limited to 'net/core/dev.c') diff --git a/net/core/dev.c b/net/core/dev.c index 08dec6eb922..e0489ca731c 100644 --- a/net/core/dev.c +++ b/net/core/dev.c @@ -977,7 +977,12 @@ int register_netdevice_notifier(struct notifier_block *nb) int unregister_netdevice_notifier(struct notifier_block *nb) { - return notifier_chain_unregister(&netdev_chain, nb); + int err; + + rtnl_lock(); + err = notifier_chain_unregister(&netdev_chain, nb); + rtnl_unlock(); + return err; } /** -- cgit v1.2.3-70-g09d2 From e041c683412d5bf44dc2b109053e3b837b71742d Mon Sep 17 00:00:00 2001 From: Alan Stern Date: Mon, 27 Mar 2006 01:16:30 -0800 Subject: [PATCH] Notifier chain update: API changes The kernel's implementation of notifier chains is unsafe. There is no protection against entries being added to or removed from a chain while the chain is in use. The issues were discussed in this thread: http://marc.theaimsgroup.com/?l=linux-kernel&m=113018709002036&w=2 We noticed that notifier chains in the kernel fall into two basic usage classes: "Blocking" chains are always called from a process context and the callout routines are allowed to sleep; "Atomic" chains can be called from an atomic context and the callout routines are not allowed to sleep. We decided to codify this distinction and make it part of the API. Therefore this set of patches introduces three new, parallel APIs: one for blocking notifiers, one for atomic notifiers, and one for "raw" notifiers (which is really just the old API under a new name). New kinds of data structures are used for the heads of the chains, and new routines are defined for registration, unregistration, and calling a chain. The three APIs are explained in include/linux/notifier.h and their implementation is in kernel/sys.c. With atomic and blocking chains, the implementation guarantees that the chain links will not be corrupted and that chain callers will not get messed up by entries being added or removed. For raw chains the implementation provides no guarantees at all; users of this API must provide their own protections. (The idea was that situations may come up where the assumptions of the atomic and blocking APIs are not appropriate, so it should be possible for users to handle these things in their own way.) There are some limitations, which should not be too hard to live with. For atomic/blocking chains, registration and unregistration must always be done in a process context since the chain is protected by a mutex/rwsem. Also, a callout routine for a non-raw chain must not try to register or unregister entries on its own chain. (This did happen in a couple of places and the code had to be changed to avoid it.) Since atomic chains may be called from within an NMI handler, they cannot use spinlocks for synchronization. Instead we use RCU. The overhead falls almost entirely in the unregister routine, which is okay since unregistration is much less frequent that calling a chain. Here is the list of chains that we adjusted and their classifications. None of them use the raw API, so for the moment it is only a placeholder. ATOMIC CHAINS ------------- arch/i386/kernel/traps.c: i386die_chain arch/ia64/kernel/traps.c: ia64die_chain arch/powerpc/kernel/traps.c: powerpc_die_chain arch/sparc64/kernel/traps.c: sparc64die_chain arch/x86_64/kernel/traps.c: die_chain drivers/char/ipmi/ipmi_si_intf.c: xaction_notifier_list kernel/panic.c: panic_notifier_list kernel/profile.c: task_free_notifier net/bluetooth/hci_core.c: hci_notifier net/ipv4/netfilter/ip_conntrack_core.c: ip_conntrack_chain net/ipv4/netfilter/ip_conntrack_core.c: ip_conntrack_expect_chain net/ipv6/addrconf.c: inet6addr_chain net/netfilter/nf_conntrack_core.c: nf_conntrack_chain net/netfilter/nf_conntrack_core.c: nf_conntrack_expect_chain net/netlink/af_netlink.c: netlink_chain BLOCKING CHAINS --------------- arch/powerpc/platforms/pseries/reconfig.c: pSeries_reconfig_chain arch/s390/kernel/process.c: idle_chain arch/x86_64/kernel/process.c idle_notifier drivers/base/memory.c: memory_chain drivers/cpufreq/cpufreq.c cpufreq_policy_notifier_list drivers/cpufreq/cpufreq.c cpufreq_transition_notifier_list drivers/macintosh/adb.c: adb_client_list drivers/macintosh/via-pmu.c sleep_notifier_list drivers/macintosh/via-pmu68k.c sleep_notifier_list drivers/macintosh/windfarm_core.c wf_client_list drivers/usb/core/notify.c usb_notifier_list drivers/video/fbmem.c fb_notifier_list kernel/cpu.c cpu_chain kernel/module.c module_notify_list kernel/profile.c munmap_notifier kernel/profile.c task_exit_notifier kernel/sys.c reboot_notifier_list net/core/dev.c netdev_chain net/decnet/dn_dev.c: dnaddr_chain net/ipv4/devinet.c: inetaddr_chain It's possible that some of these classifications are wrong. If they are, please let us know or submit a patch to fix them. Note that any chain that gets called very frequently should be atomic, because the rwsem read-locking used for blocking chains is very likely to incur cache misses on SMP systems. (However, if the chain's callout routines may sleep then the chain cannot be atomic.) The patch set was written by Alan Stern and Chandra Seetharaman, incorporating material written by Keith Owens and suggestions from Paul McKenney and Andrew Morton. [jes@sgi.com: restructure the notifier chain initialization macros] Signed-off-by: Alan Stern Signed-off-by: Chandra Seetharaman Signed-off-by: Jes Sorensen Signed-off-by: Andrew Morton Signed-off-by: Linus Torvalds --- arch/alpha/kernel/setup.c | 5 +- arch/arm/mach-omap1/board-netstar.c | 2 +- arch/arm/mach-omap1/board-voiceblue.c | 2 +- arch/i386/kernel/traps.c | 17 +- arch/ia64/kernel/traps.c | 6 +- arch/mips/lasat/setup.c | 3 +- arch/mips/sgi-ip22/ip22-reset.c | 2 +- arch/mips/sgi-ip32/ip32-reset.c | 2 +- arch/parisc/kernel/pdc_chassis.c | 3 +- arch/powerpc/kernel/setup_64.c | 3 +- arch/powerpc/kernel/traps.c | 16 +- arch/powerpc/platforms/pseries/reconfig.c | 10 +- arch/ppc/platforms/prep_setup.c | 2 +- arch/s390/kernel/process.c | 11 +- arch/sparc64/kernel/traps.c | 17 +- arch/um/drivers/mconsole_kern.c | 3 +- arch/um/kernel/um_arch.c | 3 +- arch/x86_64/kernel/process.c | 17 +- arch/x86_64/kernel/traps.c | 18 +- arch/xtensa/platform-iss/setup.c | 2 +- drivers/base/memory.c | 8 +- drivers/char/ipmi/ipmi_msghandler.c | 4 +- drivers/char/ipmi/ipmi_si_intf.c | 7 +- drivers/char/ipmi/ipmi_watchdog.c | 6 +- drivers/cpufreq/cpufreq.c | 61 +++--- drivers/firmware/dcdbas.c | 19 +- drivers/macintosh/adb.c | 11 +- drivers/macintosh/adbhid.c | 3 +- drivers/macintosh/via-pmu.c | 2 +- drivers/macintosh/via-pmu68k.c | 7 +- drivers/macintosh/windfarm_core.c | 8 +- drivers/misc/ibmasm/heartbeat.c | 5 +- drivers/net/bonding/bond_main.c | 2 +- drivers/parisc/led.c | 14 +- drivers/parisc/power.c | 6 +- drivers/scsi/gdth.c | 9 +- drivers/usb/core/notify.c | 65 +----- drivers/video/fbmem.c | 31 +-- include/asm-i386/kdebug.h | 10 +- include/asm-ia64/kdebug.h | 4 +- include/asm-powerpc/kdebug.h | 12 +- include/asm-sparc64/kdebug.h | 11 +- include/asm-x86_64/kdebug.h | 23 +- include/linux/adb.h | 2 +- include/linux/kernel.h | 2 +- include/linux/memory.h | 1 - include/linux/netfilter_ipv4/ip_conntrack.h | 17 +- include/linux/notifier.h | 96 +++++++- include/net/netfilter/nf_conntrack.h | 17 +- kernel/cpu.c | 29 +-- kernel/module.c | 20 +- kernel/panic.c | 4 +- kernel/profile.c | 53 ++--- kernel/softlockup.c | 2 +- kernel/sys.c | 327 ++++++++++++++++++++++------ net/bluetooth/hci_core.c | 8 +- net/core/dev.c | 42 ++-- net/decnet/dn_dev.c | 10 +- net/ipv4/devinet.c | 16 +- net/ipv4/netfilter/ip_conntrack_core.c | 6 +- net/ipv6/addrconf.c | 10 +- net/netfilter/nf_conntrack_core.c | 6 +- net/netlink/af_netlink.c | 9 +- 63 files changed, 677 insertions(+), 472 deletions(-) (limited to 'net/core/dev.c') diff --git a/arch/alpha/kernel/setup.c b/arch/alpha/kernel/setup.c index 9402624453c..dd876967059 100644 --- a/arch/alpha/kernel/setup.c +++ b/arch/alpha/kernel/setup.c @@ -43,7 +43,7 @@ #include #include -extern struct notifier_block *panic_notifier_list; +extern struct atomic_notifier_head panic_notifier_list; static int alpha_panic_event(struct notifier_block *, unsigned long, void *); static struct notifier_block alpha_panic_block = { alpha_panic_event, @@ -500,7 +500,8 @@ setup_arch(char **cmdline_p) } /* Register a call for panic conditions. */ - notifier_chain_register(&panic_notifier_list, &alpha_panic_block); + atomic_notifier_chain_register(&panic_notifier_list, + &alpha_panic_block); #ifdef CONFIG_ALPHA_GENERIC /* Assume that we've booted from SRM if we haven't booted from MILO. diff --git a/arch/arm/mach-omap1/board-netstar.c b/arch/arm/mach-omap1/board-netstar.c index 60d5f8a3339..7520e602d7a 100644 --- a/arch/arm/mach-omap1/board-netstar.c +++ b/arch/arm/mach-omap1/board-netstar.c @@ -141,7 +141,7 @@ static int __init netstar_late_init(void) /* TODO: Setup front panel switch here */ /* Setup panic notifier */ - notifier_chain_register(&panic_notifier_list, &panic_block); + atomic_notifier_chain_register(&panic_notifier_list, &panic_block); return 0; } diff --git a/arch/arm/mach-omap1/board-voiceblue.c b/arch/arm/mach-omap1/board-voiceblue.c index bfd5fdd1a87..52e4a9d6964 100644 --- a/arch/arm/mach-omap1/board-voiceblue.c +++ b/arch/arm/mach-omap1/board-voiceblue.c @@ -235,7 +235,7 @@ static struct notifier_block panic_block = { static int __init voiceblue_setup(void) { /* Setup panic notifier */ - notifier_chain_register(&panic_notifier_list, &panic_block); + atomic_notifier_chain_register(&panic_notifier_list, &panic_block); return 0; } diff --git a/arch/i386/kernel/traps.c b/arch/i386/kernel/traps.c index 4624f8ca245..6b63a5aa1e4 100644 --- a/arch/i386/kernel/traps.c +++ b/arch/i386/kernel/traps.c @@ -92,22 +92,21 @@ asmlinkage void spurious_interrupt_bug(void); asmlinkage void machine_check(void); static int kstack_depth_to_print = 24; -struct notifier_block *i386die_chain; -static DEFINE_SPINLOCK(die_notifier_lock); +ATOMIC_NOTIFIER_HEAD(i386die_chain); int register_die_notifier(struct notifier_block *nb) { - int err = 0; - unsigned long flags; - vmalloc_sync_all(); - spin_lock_irqsave(&die_notifier_lock, flags); - err = notifier_chain_register(&i386die_chain, nb); - spin_unlock_irqrestore(&die_notifier_lock, flags); - return err; + return atomic_notifier_chain_register(&i386die_chain, nb); } EXPORT_SYMBOL(register_die_notifier); +int unregister_die_notifier(struct notifier_block *nb) +{ + return atomic_notifier_chain_unregister(&i386die_chain, nb); +} +EXPORT_SYMBOL(unregister_die_notifier); + static inline int valid_stack_ptr(struct thread_info *tinfo, void *p) { return p > (void *)tinfo && diff --git a/arch/ia64/kernel/traps.c b/arch/ia64/kernel/traps.c index dabd6c32641..7c1ddc8ac44 100644 --- a/arch/ia64/kernel/traps.c +++ b/arch/ia64/kernel/traps.c @@ -30,19 +30,19 @@ extern spinlock_t timerlist_lock; fpswa_interface_t *fpswa_interface; EXPORT_SYMBOL(fpswa_interface); -struct notifier_block *ia64die_chain; +ATOMIC_NOTIFIER_HEAD(ia64die_chain); int register_die_notifier(struct notifier_block *nb) { - return notifier_chain_register(&ia64die_chain, nb); + return atomic_notifier_chain_register(&ia64die_chain, nb); } EXPORT_SYMBOL_GPL(register_die_notifier); int unregister_die_notifier(struct notifier_block *nb) { - return notifier_chain_unregister(&ia64die_chain, nb); + return atomic_notifier_chain_unregister(&ia64die_chain, nb); } EXPORT_SYMBOL_GPL(unregister_die_notifier); diff --git a/arch/mips/lasat/setup.c b/arch/mips/lasat/setup.c index 83eb08b7a07..e9e9a89c674 100644 --- a/arch/mips/lasat/setup.c +++ b/arch/mips/lasat/setup.c @@ -165,7 +165,8 @@ void __init plat_setup(void) /* Set up panic notifier */ for (i = 0; i < sizeof(lasat_panic_block) / sizeof(struct notifier_block); i++) - notifier_chain_register(&panic_notifier_list, &lasat_panic_block[i]); + atomic_notifier_chain_register(&panic_notifier_list, + &lasat_panic_block[i]); lasat_reboot_setup(); diff --git a/arch/mips/sgi-ip22/ip22-reset.c b/arch/mips/sgi-ip22/ip22-reset.c index 92a3b3c15ed..a9c58e067b5 100644 --- a/arch/mips/sgi-ip22/ip22-reset.c +++ b/arch/mips/sgi-ip22/ip22-reset.c @@ -238,7 +238,7 @@ static int __init reboot_setup(void) request_irq(SGI_PANEL_IRQ, panel_int, 0, "Front Panel", NULL); init_timer(&blink_timer); blink_timer.function = blink_timeout; - notifier_chain_register(&panic_notifier_list, &panic_block); + atomic_notifier_chain_register(&panic_notifier_list, &panic_block); return 0; } diff --git a/arch/mips/sgi-ip32/ip32-reset.c b/arch/mips/sgi-ip32/ip32-reset.c index 0c948008b02..ab9d9cef089 100644 --- a/arch/mips/sgi-ip32/ip32-reset.c +++ b/arch/mips/sgi-ip32/ip32-reset.c @@ -193,7 +193,7 @@ static __init int ip32_reboot_setup(void) init_timer(&blink_timer); blink_timer.function = blink_timeout; - notifier_chain_register(&panic_notifier_list, &panic_block); + atomic_notifier_chain_register(&panic_notifier_list, &panic_block); request_irq(MACEISA_RTC_IRQ, ip32_rtc_int, 0, "rtc", NULL); diff --git a/arch/parisc/kernel/pdc_chassis.c b/arch/parisc/kernel/pdc_chassis.c index 2a01fe1bdc9..0cea6958f42 100644 --- a/arch/parisc/kernel/pdc_chassis.c +++ b/arch/parisc/kernel/pdc_chassis.c @@ -150,7 +150,8 @@ void __init parisc_pdc_chassis_init(void) if (handle) { /* initialize panic notifier chain */ - notifier_chain_register(&panic_notifier_list, &pdc_chassis_panic_block); + atomic_notifier_chain_register(&panic_notifier_list, + &pdc_chassis_panic_block); /* initialize reboot notifier chain */ register_reboot_notifier(&pdc_chassis_reboot_block); diff --git a/arch/powerpc/kernel/setup_64.c b/arch/powerpc/kernel/setup_64.c index 2f3fdad3559..e20c1fae342 100644 --- a/arch/powerpc/kernel/setup_64.c +++ b/arch/powerpc/kernel/setup_64.c @@ -579,7 +579,8 @@ void __init setup_arch(char **cmdline_p) panic_timeout = 180; if (ppc_md.panic) - notifier_chain_register(&panic_notifier_list, &ppc64_panic_block); + atomic_notifier_chain_register(&panic_notifier_list, + &ppc64_panic_block); init_mm.start_code = PAGE_OFFSET; init_mm.end_code = (unsigned long) _etext; diff --git a/arch/powerpc/kernel/traps.c b/arch/powerpc/kernel/traps.c index 98660aedeeb..9763faab673 100644 --- a/arch/powerpc/kernel/traps.c +++ b/arch/powerpc/kernel/traps.c @@ -74,19 +74,19 @@ EXPORT_SYMBOL(__debugger_dabr_match); EXPORT_SYMBOL(__debugger_fault_handler); #endif -struct notifier_block *powerpc_die_chain; -static DEFINE_SPINLOCK(die_notifier_lock); +ATOMIC_NOTIFIER_HEAD(powerpc_die_chain); int register_die_notifier(struct notifier_block *nb) { - int err = 0; - unsigned long flags; + return atomic_notifier_chain_register(&powerpc_die_chain, nb); +} +EXPORT_SYMBOL(register_die_notifier); - spin_lock_irqsave(&die_notifier_lock, flags); - err = notifier_chain_register(&powerpc_die_chain, nb); - spin_unlock_irqrestore(&die_notifier_lock, flags); - return err; +int unregister_die_notifier(struct notifier_block *nb) +{ + return atomic_notifier_chain_unregister(&powerpc_die_chain, nb); } +EXPORT_SYMBOL(unregister_die_notifier); /* * Trap & Exception support diff --git a/arch/powerpc/platforms/pseries/reconfig.c b/arch/powerpc/platforms/pseries/reconfig.c index 86cfa6ecdcf..5ad90676567 100644 --- a/arch/powerpc/platforms/pseries/reconfig.c +++ b/arch/powerpc/platforms/pseries/reconfig.c @@ -94,16 +94,16 @@ static struct device_node *derive_parent(const char *path) return parent; } -static struct notifier_block *pSeries_reconfig_chain; +static BLOCKING_NOTIFIER_HEAD(pSeries_reconfig_chain); int pSeries_reconfig_notifier_register(struct notifier_block *nb) { - return notifier_chain_register(&pSeries_reconfig_chain, nb); + return blocking_notifier_chain_register(&pSeries_reconfig_chain, nb); } void pSeries_reconfig_notifier_unregister(struct notifier_block *nb) { - notifier_chain_unregister(&pSeries_reconfig_chain, nb); + blocking_notifier_chain_unregister(&pSeries_reconfig_chain, nb); } static int pSeries_reconfig_add_node(const char *path, struct property *proplist) @@ -131,7 +131,7 @@ static int pSeries_reconfig_add_node(const char *path, struct property *proplist goto out_err; } - err = notifier_call_chain(&pSeries_reconfig_chain, + err = blocking_notifier_call_chain(&pSeries_reconfig_chain, PSERIES_RECONFIG_ADD, np); if (err == NOTIFY_BAD) { printk(KERN_ERR "Failed to add device node %s\n", path); @@ -171,7 +171,7 @@ static int pSeries_reconfig_remove_node(struct device_node *np) remove_node_proc_entries(np); - notifier_call_chain(&pSeries_reconfig_chain, + blocking_notifier_call_chain(&pSeries_reconfig_chain, PSERIES_RECONFIG_REMOVE, np); of_detach_node(np); diff --git a/arch/ppc/platforms/prep_setup.c b/arch/ppc/platforms/prep_setup.c index a0fc628ffb1..d95c05d9824 100644 --- a/arch/ppc/platforms/prep_setup.c +++ b/arch/ppc/platforms/prep_setup.c @@ -736,7 +736,7 @@ ibm_statusled_progress(char *s, unsigned short hex) hex = 0xfff; if (!notifier_installed) { ++notifier_installed; - notifier_chain_register(&panic_notifier_list, + atomic_notifier_chain_register(&panic_notifier_list, &ibm_statusled_block); } } diff --git a/arch/s390/kernel/process.c b/arch/s390/kernel/process.c index 99182a415fe..4a0f5a1551e 100644 --- a/arch/s390/kernel/process.c +++ b/arch/s390/kernel/process.c @@ -76,17 +76,17 @@ unsigned long thread_saved_pc(struct task_struct *tsk) /* * Need to know about CPUs going idle? */ -static struct notifier_block *idle_chain; +static ATOMIC_NOTIFIER_HEAD(idle_chain); int register_idle_notifier(struct notifier_block *nb) { - return notifier_chain_register(&idle_chain, nb); + return atomic_notifier_chain_register(&idle_chain, nb); } EXPORT_SYMBOL(register_idle_notifier); int unregister_idle_notifier(struct notifier_block *nb) { - return notifier_chain_unregister(&idle_chain, nb); + return atomic_notifier_chain_unregister(&idle_chain, nb); } EXPORT_SYMBOL(unregister_idle_notifier); @@ -95,7 +95,7 @@ void do_monitor_call(struct pt_regs *regs, long interruption_code) /* disable monitor call class 0 */ __ctl_clear_bit(8, 15); - notifier_call_chain(&idle_chain, CPU_NOT_IDLE, + atomic_notifier_call_chain(&idle_chain, CPU_NOT_IDLE, (void *)(long) smp_processor_id()); } @@ -116,7 +116,8 @@ static void default_idle(void) return; } - rc = notifier_call_chain(&idle_chain, CPU_IDLE, (void *)(long) cpu); + rc = atomic_notifier_call_chain(&idle_chain, + CPU_IDLE, (void *)(long) cpu); if (rc != NOTIFY_OK && rc != NOTIFY_DONE) BUG(); if (rc != NOTIFY_OK) { diff --git a/arch/sparc64/kernel/traps.c b/arch/sparc64/kernel/traps.c index df612e4f75f..ff090bb9734 100644 --- a/arch/sparc64/kernel/traps.c +++ b/arch/sparc64/kernel/traps.c @@ -43,18 +43,19 @@ #include #endif -struct notifier_block *sparc64die_chain; -static DEFINE_SPINLOCK(die_notifier_lock); +ATOMIC_NOTIFIER_HEAD(sparc64die_chain); int register_die_notifier(struct notifier_block *nb) { - int err = 0; - unsigned long flags; - spin_lock_irqsave(&die_notifier_lock, flags); - err = notifier_chain_register(&sparc64die_chain, nb); - spin_unlock_irqrestore(&die_notifier_lock, flags); - return err; + return atomic_notifier_chain_register(&sparc64die_chain, nb); } +EXPORT_SYMBOL(register_die_notifier); + +int unregister_die_notifier(struct notifier_block *nb) +{ + return atomic_notifier_chain_unregister(&sparc64die_chain, nb); +} +EXPORT_SYMBOL(unregister_die_notifier); /* When an irrecoverable trap occurs at tl > 0, the trap entry * code logs the trap state registers at every level in the trap diff --git a/arch/um/drivers/mconsole_kern.c b/arch/um/drivers/mconsole_kern.c index 54388d10bcf..1488816588e 100644 --- a/arch/um/drivers/mconsole_kern.c +++ b/arch/um/drivers/mconsole_kern.c @@ -762,7 +762,8 @@ static struct notifier_block panic_exit_notifier = { static int add_notifier(void) { - notifier_chain_register(&panic_notifier_list, &panic_exit_notifier); + atomic_notifier_chain_register(&panic_notifier_list, + &panic_exit_notifier); return(0); } diff --git a/arch/um/kernel/um_arch.c b/arch/um/kernel/um_arch.c index bb1c87211ac..7d51dd7201c 100644 --- a/arch/um/kernel/um_arch.c +++ b/arch/um/kernel/um_arch.c @@ -477,7 +477,8 @@ static struct notifier_block panic_exit_notifier = { void __init setup_arch(char **cmdline_p) { - notifier_chain_register(&panic_notifier_list, &panic_exit_notifier); + atomic_notifier_chain_register(&panic_notifier_list, + &panic_exit_notifier); paging_init(); strlcpy(saved_command_line, command_line, COMMAND_LINE_SIZE); *cmdline_p = command_line; diff --git a/arch/x86_64/kernel/process.c b/arch/x86_64/kernel/process.c index 0370720515f..70dd8e5c688 100644 --- a/arch/x86_64/kernel/process.c +++ b/arch/x86_64/kernel/process.c @@ -66,24 +66,17 @@ EXPORT_SYMBOL(boot_option_idle_override); void (*pm_idle)(void); static DEFINE_PER_CPU(unsigned int, cpu_idle_state); -static struct notifier_block *idle_notifier; -static DEFINE_SPINLOCK(idle_notifier_lock); +static ATOMIC_NOTIFIER_HEAD(idle_notifier); void idle_notifier_register(struct notifier_block *n) { - unsigned long flags; - spin_lock_irqsave(&idle_notifier_lock, flags); - notifier_chain_register(&idle_notifier, n); - spin_unlock_irqrestore(&idle_notifier_lock, flags); + atomic_notifier_chain_register(&idle_notifier, n); } EXPORT_SYMBOL_GPL(idle_notifier_register); void idle_notifier_unregister(struct notifier_block *n) { - unsigned long flags; - spin_lock_irqsave(&idle_notifier_lock, flags); - notifier_chain_unregister(&idle_notifier, n); - spin_unlock_irqrestore(&idle_notifier_lock, flags); + atomic_notifier_chain_unregister(&idle_notifier, n); } EXPORT_SYMBOL(idle_notifier_unregister); @@ -93,13 +86,13 @@ static DEFINE_PER_CPU(enum idle_state, idle_state) = CPU_NOT_IDLE; void enter_idle(void) { __get_cpu_var(idle_state) = CPU_IDLE; - notifier_call_chain(&idle_notifier, IDLE_START, NULL); + atomic_notifier_call_chain(&idle_notifier, IDLE_START, NULL); } static void __exit_idle(void) { __get_cpu_var(idle_state) = CPU_NOT_IDLE; - notifier_call_chain(&idle_notifier, IDLE_END, NULL); + atomic_notifier_call_chain(&idle_notifier, IDLE_END, NULL); } /* Called from interrupts to signify idle end */ diff --git a/arch/x86_64/kernel/traps.c b/arch/x86_64/kernel/traps.c index 7b148309c52..edaa9fe654d 100644 --- a/arch/x86_64/kernel/traps.c +++ b/arch/x86_64/kernel/traps.c @@ -69,20 +69,20 @@ asmlinkage void alignment_check(void); asmlinkage void machine_check(void); asmlinkage void spurious_interrupt_bug(void); -struct notifier_block *die_chain; -static DEFINE_SPINLOCK(die_notifier_lock); +ATOMIC_NOTIFIER_HEAD(die_chain); int register_die_notifier(struct notifier_block *nb) { - int err = 0; - unsigned long flags; - vmalloc_sync_all(); - spin_lock_irqsave(&die_notifier_lock, flags); - err = notifier_chain_register(&die_chain, nb); - spin_unlock_irqrestore(&die_notifier_lock, flags); - return err; + return atomic_notifier_chain_register(&die_chain, nb); +} +EXPORT_SYMBOL(register_die_notifier); + +int unregister_die_notifier(struct notifier_block *nb) +{ + return atomic_notifier_chain_unregister(&die_chain, nb); } +EXPORT_SYMBOL(unregister_die_notifier); static inline void conditional_sti(struct pt_regs *regs) { diff --git a/arch/xtensa/platform-iss/setup.c b/arch/xtensa/platform-iss/setup.c index 2e6dcbf0cc0..23790a5610e 100644 --- a/arch/xtensa/platform-iss/setup.c +++ b/arch/xtensa/platform-iss/setup.c @@ -108,5 +108,5 @@ static struct notifier_block iss_panic_block = { void __init platform_setup(char **p_cmdline) { - notifier_chain_register(&panic_notifier_list, &iss_panic_block); + atomic_notifier_chain_register(&panic_notifier_list, &iss_panic_block); } diff --git a/drivers/base/memory.c b/drivers/base/memory.c index 105a0d61eb1..dd547af4681 100644 --- a/drivers/base/memory.c +++ b/drivers/base/memory.c @@ -47,16 +47,16 @@ static struct kset_uevent_ops memory_uevent_ops = { .uevent = memory_uevent, }; -static struct notifier_block *memory_chain; +static BLOCKING_NOTIFIER_HEAD(memory_chain); int register_memory_notifier(struct notifier_block *nb) { - return notifier_chain_register(&memory_chain, nb); + return blocking_notifier_chain_register(&memory_chain, nb); } void unregister_memory_notifier(struct notifier_block *nb) { - notifier_chain_unregister(&memory_chain, nb); + blocking_notifier_chain_unregister(&memory_chain, nb); } /* @@ -140,7 +140,7 @@ static ssize_t show_mem_state(struct sys_device *dev, char *buf) static inline int memory_notify(unsigned long val, void *v) { - return notifier_call_chain(&memory_chain, val, v); + return blocking_notifier_call_chain(&memory_chain, val, v); } /* diff --git a/drivers/char/ipmi/ipmi_msghandler.c b/drivers/char/ipmi/ipmi_msghandler.c index b8fb87c6c29..40eb005b9d7 100644 --- a/drivers/char/ipmi/ipmi_msghandler.c +++ b/drivers/char/ipmi/ipmi_msghandler.c @@ -3744,7 +3744,7 @@ static int ipmi_init_msghandler(void) ipmi_timer.expires = jiffies + IPMI_TIMEOUT_JIFFIES; add_timer(&ipmi_timer); - notifier_chain_register(&panic_notifier_list, &panic_block); + atomic_notifier_chain_register(&panic_notifier_list, &panic_block); initialized = 1; @@ -3764,7 +3764,7 @@ static __exit void cleanup_ipmi(void) if (!initialized) return; - notifier_chain_unregister(&panic_notifier_list, &panic_block); + atomic_notifier_chain_unregister(&panic_notifier_list, &panic_block); /* This can't be called if any interfaces exist, so no worry about shutting down the interfaces. */ diff --git a/drivers/char/ipmi/ipmi_si_intf.c b/drivers/char/ipmi/ipmi_si_intf.c index 12f858dc999..35fbd4d8ed4 100644 --- a/drivers/char/ipmi/ipmi_si_intf.c +++ b/drivers/char/ipmi/ipmi_si_intf.c @@ -237,10 +237,10 @@ struct smi_info static int try_smi_init(struct smi_info *smi); -static struct notifier_block *xaction_notifier_list; +static ATOMIC_NOTIFIER_HEAD(xaction_notifier_list); static int register_xaction_notifier(struct notifier_block * nb) { - return notifier_chain_register(&xaction_notifier_list, nb); + return atomic_notifier_chain_register(&xaction_notifier_list, nb); } static void si_restart_short_timer(struct smi_info *smi_info); @@ -302,7 +302,8 @@ static enum si_sm_result start_next_msg(struct smi_info *smi_info) do_gettimeofday(&t); printk("**Start2: %d.%9.9d\n", t.tv_sec, t.tv_usec); #endif - err = notifier_call_chain(&xaction_notifier_list, 0, smi_info); + err = atomic_notifier_call_chain(&xaction_notifier_list, + 0, smi_info); if (err & NOTIFY_STOP_MASK) { rv = SI_SM_CALL_WITHOUT_DELAY; goto out; diff --git a/drivers/char/ipmi/ipmi_watchdog.c b/drivers/char/ipmi/ipmi_watchdog.c index 616539310d9..7ece9f3c8f7 100644 --- a/drivers/char/ipmi/ipmi_watchdog.c +++ b/drivers/char/ipmi/ipmi_watchdog.c @@ -1158,7 +1158,8 @@ static int __init ipmi_wdog_init(void) } register_reboot_notifier(&wdog_reboot_notifier); - notifier_chain_register(&panic_notifier_list, &wdog_panic_notifier); + atomic_notifier_chain_register(&panic_notifier_list, + &wdog_panic_notifier); printk(KERN_INFO PFX "driver initialized\n"); @@ -1176,7 +1177,8 @@ static __exit void ipmi_unregister_watchdog(void) release_nmi(&ipmi_nmi_handler); #endif - notifier_chain_unregister(&panic_notifier_list, &wdog_panic_notifier); + atomic_notifier_chain_unregister(&panic_notifier_list, + &wdog_panic_notifier); unregister_reboot_notifier(&wdog_reboot_notifier); if (! watchdog_user) diff --git a/drivers/cpufreq/cpufreq.c b/drivers/cpufreq/cpufreq.c index aed80e6aec6..9b6ae7dc8b8 100644 --- a/drivers/cpufreq/cpufreq.c +++ b/drivers/cpufreq/cpufreq.c @@ -52,9 +52,8 @@ static void handle_update(void *data); * changes to devices when the CPU clock speed changes. * The mutex locks both lists. */ -static struct notifier_block *cpufreq_policy_notifier_list; -static struct notifier_block *cpufreq_transition_notifier_list; -static DECLARE_RWSEM (cpufreq_notifier_rwsem); +static BLOCKING_NOTIFIER_HEAD(cpufreq_policy_notifier_list); +static BLOCKING_NOTIFIER_HEAD(cpufreq_transition_notifier_list); static LIST_HEAD(cpufreq_governor_list); @@ -247,8 +246,6 @@ void cpufreq_notify_transition(struct cpufreq_freqs *freqs, unsigned int state) dprintk("notification %u of frequency transition to %u kHz\n", state, freqs->new); - down_read(&cpufreq_notifier_rwsem); - policy = cpufreq_cpu_data[freqs->cpu]; switch (state) { @@ -266,20 +263,19 @@ void cpufreq_notify_transition(struct cpufreq_freqs *freqs, unsigned int state) freqs->old = policy->cur; } } - notifier_call_chain(&cpufreq_transition_notifier_list, - CPUFREQ_PRECHANGE, freqs); + blocking_notifier_call_chain(&cpufreq_transition_notifier_list, + CPUFREQ_PRECHANGE, freqs); adjust_jiffies(CPUFREQ_PRECHANGE, freqs); break; case CPUFREQ_POSTCHANGE: adjust_jiffies(CPUFREQ_POSTCHANGE, freqs); - notifier_call_chain(&cpufreq_transition_notifier_list, - CPUFREQ_POSTCHANGE, freqs); + blocking_notifier_call_chain(&cpufreq_transition_notifier_list, + CPUFREQ_POSTCHANGE, freqs); if (likely(policy) && likely(policy->cpu == freqs->cpu)) policy->cur = freqs->new; break; } - up_read(&cpufreq_notifier_rwsem); } EXPORT_SYMBOL_GPL(cpufreq_notify_transition); @@ -1007,7 +1003,7 @@ static int cpufreq_suspend(struct sys_device * sysdev, pm_message_t pmsg) freqs.old = cpu_policy->cur; freqs.new = cur_freq; - notifier_call_chain(&cpufreq_transition_notifier_list, + blocking_notifier_call_chain(&cpufreq_transition_notifier_list, CPUFREQ_SUSPENDCHANGE, &freqs); adjust_jiffies(CPUFREQ_SUSPENDCHANGE, &freqs); @@ -1088,7 +1084,8 @@ static int cpufreq_resume(struct sys_device * sysdev) freqs.old = cpu_policy->cur; freqs.new = cur_freq; - notifier_call_chain(&cpufreq_transition_notifier_list, + blocking_notifier_call_chain( + &cpufreq_transition_notifier_list, CPUFREQ_RESUMECHANGE, &freqs); adjust_jiffies(CPUFREQ_RESUMECHANGE, &freqs); @@ -1125,24 +1122,24 @@ static struct sysdev_driver cpufreq_sysdev_driver = { * changes in cpufreq policy. * * This function may sleep, and has the same return conditions as - * notifier_chain_register. + * blocking_notifier_chain_register. */ int cpufreq_register_notifier(struct notifier_block *nb, unsigned int list) { int ret; - down_write(&cpufreq_notifier_rwsem); switch (list) { case CPUFREQ_TRANSITION_NOTIFIER: - ret = notifier_chain_register(&cpufreq_transition_notifier_list, nb); + ret = blocking_notifier_chain_register( + &cpufreq_transition_notifier_list, nb); break; case CPUFREQ_POLICY_NOTIFIER: - ret = notifier_chain_register(&cpufreq_policy_notifier_list, nb); + ret = blocking_notifier_chain_register( + &cpufreq_policy_notifier_list, nb); break; default: ret = -EINVAL; } - up_write(&cpufreq_notifier_rwsem); return ret; } @@ -1157,24 +1154,24 @@ EXPORT_SYMBOL(cpufreq_register_notifier); * Remove a driver from the CPU frequency notifier list. * * This function may sleep, and has the same return conditions as - * notifier_chain_unregister. + * blocking_notifier_chain_unregister. */ int cpufreq_unregister_notifier(struct notifier_block *nb, unsigned int list) { int ret; - down_write(&cpufreq_notifier_rwsem); switch (list) { case CPUFREQ_TRANSITION_NOTIFIER: - ret = notifier_chain_unregister(&cpufreq_transition_notifier_list, nb); + ret = blocking_notifier_chain_unregister( + &cpufreq_transition_notifier_list, nb); break; case CPUFREQ_POLICY_NOTIFIER: - ret = notifier_chain_unregister(&cpufreq_policy_notifier_list, nb); + ret = blocking_notifier_chain_unregister( + &cpufreq_policy_notifier_list, nb); break; default: ret = -EINVAL; } - up_write(&cpufreq_notifier_rwsem); return ret; } @@ -1346,29 +1343,23 @@ static int __cpufreq_set_policy(struct cpufreq_policy *data, struct cpufreq_poli if (ret) goto error_out; - down_read(&cpufreq_notifier_rwsem); - /* adjust if necessary - all reasons */ - notifier_call_chain(&cpufreq_policy_notifier_list, CPUFREQ_ADJUST, - policy); + blocking_notifier_call_chain(&cpufreq_policy_notifier_list, + CPUFREQ_ADJUST, policy); /* adjust if necessary - hardware incompatibility*/ - notifier_call_chain(&cpufreq_policy_notifier_list, CPUFREQ_INCOMPATIBLE, - policy); + blocking_notifier_call_chain(&cpufreq_policy_notifier_list, + CPUFREQ_INCOMPATIBLE, policy); /* verify the cpu speed can be set within this limit, which might be different to the first one */ ret = cpufreq_driver->verify(policy); - if (ret) { - up_read(&cpufreq_notifier_rwsem); + if (ret) goto error_out; - } /* notification of the new policy */ - notifier_call_chain(&cpufreq_policy_notifier_list, CPUFREQ_NOTIFY, - policy); - - up_read(&cpufreq_notifier_rwsem); + blocking_notifier_call_chain(&cpufreq_policy_notifier_list, + CPUFREQ_NOTIFY, policy); data->min = policy->min; data->max = policy->max; diff --git a/drivers/firmware/dcdbas.c b/drivers/firmware/dcdbas.c index d6543fc4a92..339f405ff70 100644 --- a/drivers/firmware/dcdbas.c +++ b/drivers/firmware/dcdbas.c @@ -484,26 +484,15 @@ static void dcdbas_host_control(void) static int dcdbas_reboot_notify(struct notifier_block *nb, unsigned long code, void *unused) { - static unsigned int notify_cnt = 0; - switch (code) { case SYS_DOWN: case SYS_HALT: case SYS_POWER_OFF: if (host_control_on_shutdown) { /* firmware is going to perform host control action */ - if (++notify_cnt == 2) { - printk(KERN_WARNING - "Please wait for shutdown " - "action to complete...\n"); - dcdbas_host_control(); - } - /* - * register again and initiate the host control - * action on the second notification to allow - * everyone that registered to be notified - */ - register_reboot_notifier(nb); + printk(KERN_WARNING "Please wait for shutdown " + "action to complete...\n"); + dcdbas_host_control(); } break; } @@ -514,7 +503,7 @@ static int dcdbas_reboot_notify(struct notifier_block *nb, unsigned long code, static struct notifier_block dcdbas_reboot_nb = { .notifier_call = dcdbas_reboot_notify, .next = NULL, - .priority = 0 + .priority = INT_MIN }; static DCDBAS_BIN_ATTR_RW(smi_data); diff --git a/drivers/macintosh/adb.c b/drivers/macintosh/adb.c index d2ead1776c1..34fcabac5fd 100644 --- a/drivers/macintosh/adb.c +++ b/drivers/macintosh/adb.c @@ -80,7 +80,7 @@ static struct adb_driver *adb_driver_list[] = { static struct class *adb_dev_class; struct adb_driver *adb_controller; -struct notifier_block *adb_client_list = NULL; +BLOCKING_NOTIFIER_HEAD(adb_client_list); static int adb_got_sleep; static int adb_inited; static pid_t adb_probe_task_pid; @@ -354,7 +354,8 @@ adb_notify_sleep(struct pmu_sleep_notifier *self, int when) /* Stop autopoll */ if (adb_controller->autopoll) adb_controller->autopoll(0); - ret = notifier_call_chain(&adb_client_list, ADB_MSG_POWERDOWN, NULL); + ret = blocking_notifier_call_chain(&adb_client_list, + ADB_MSG_POWERDOWN, NULL); if (ret & NOTIFY_STOP_MASK) { up(&adb_probe_mutex); return PBOOK_SLEEP_REFUSE; @@ -391,7 +392,8 @@ do_adb_reset_bus(void) if (adb_controller->autopoll) adb_controller->autopoll(0); - nret = notifier_call_chain(&adb_client_list, ADB_MSG_PRE_RESET, NULL); + nret = blocking_notifier_call_chain(&adb_client_list, + ADB_MSG_PRE_RESET, NULL); if (nret & NOTIFY_STOP_MASK) { if (adb_controller->autopoll) adb_controller->autopoll(autopoll_devs); @@ -426,7 +428,8 @@ do_adb_reset_bus(void) } up(&adb_handler_sem); - nret = notifier_call_chain(&adb_client_list, ADB_MSG_POST_RESET, NULL); + nret = blocking_notifier_call_chain(&adb_client_list, + ADB_MSG_POST_RESET, NULL); if (nret & NOTIFY_STOP_MASK) return -EBUSY; diff --git a/drivers/macintosh/adbhid.c b/drivers/macintosh/adbhid.c index c0b46bceb5d..f5779a73184 100644 --- a/drivers/macintosh/adbhid.c +++ b/drivers/macintosh/adbhid.c @@ -1214,7 +1214,8 @@ static int __init adbhid_init(void) adbhid_probe(); - notifier_chain_register(&adb_client_list, &adbhid_adb_notifier); + blocking_notifier_chain_register(&adb_client_list, + &adbhid_adb_notifier); return 0; } diff --git a/drivers/macintosh/via-pmu.c b/drivers/macintosh/via-pmu.c index 4f5f3abc9cb..0b5ff553e39 100644 --- a/drivers/macintosh/via-pmu.c +++ b/drivers/macintosh/via-pmu.c @@ -187,7 +187,7 @@ extern int disable_kernel_backlight; int __fake_sleep; int asleep; -struct notifier_block *sleep_notifier_list; +BLOCKING_NOTIFIER_HEAD(sleep_notifier_list); #ifdef CONFIG_ADB static int adb_dev_map = 0; diff --git a/drivers/macintosh/via-pmu68k.c b/drivers/macintosh/via-pmu68k.c index f08e52f2107..35b70323e7e 100644 --- a/drivers/macintosh/via-pmu68k.c +++ b/drivers/macintosh/via-pmu68k.c @@ -102,7 +102,7 @@ static int pmu_kind = PMU_UNKNOWN; static int pmu_fully_inited = 0; int asleep; -struct notifier_block *sleep_notifier_list; +BLOCKING_NOTIFIER_HEAD(sleep_notifier_list); static int pmu_probe(void); static int pmu_init(void); @@ -913,7 +913,8 @@ int powerbook_sleep(void) struct adb_request sleep_req; /* Notify device drivers */ - ret = notifier_call_chain(&sleep_notifier_list, PBOOK_SLEEP, NULL); + ret = blocking_notifier_call_chain(&sleep_notifier_list, + PBOOK_SLEEP, NULL); if (ret & NOTIFY_STOP_MASK) return -EBUSY; @@ -984,7 +985,7 @@ int powerbook_sleep(void) enable_irq(i); /* Notify drivers */ - notifier_call_chain(&sleep_notifier_list, PBOOK_WAKE, NULL); + blocking_notifier_call_chain(&sleep_notifier_list, PBOOK_WAKE, NULL); /* reenable ADB autopoll */ pmu_adb_autopoll(adb_dev_map); diff --git a/drivers/macintosh/windfarm_core.c b/drivers/macintosh/windfarm_core.c index 6c0ba04bc57..ab3faa702d5 100644 --- a/drivers/macintosh/windfarm_core.c +++ b/drivers/macintosh/windfarm_core.c @@ -52,7 +52,7 @@ static LIST_HEAD(wf_controls); static LIST_HEAD(wf_sensors); static DEFINE_MUTEX(wf_lock); -static struct notifier_block *wf_client_list; +static BLOCKING_NOTIFIER_HEAD(wf_client_list); static int wf_client_count; static unsigned int wf_overtemp; static unsigned int wf_overtemp_counter; @@ -68,7 +68,7 @@ static struct platform_device wf_platform_device = { static inline void wf_notify(int event, void *param) { - notifier_call_chain(&wf_client_list, event, param); + blocking_notifier_call_chain(&wf_client_list, event, param); } int wf_critical_overtemp(void) @@ -398,7 +398,7 @@ int wf_register_client(struct notifier_block *nb) struct wf_sensor *sr; mutex_lock(&wf_lock); - rc = notifier_chain_register(&wf_client_list, nb); + rc = blocking_notifier_chain_register(&wf_client_list, nb); if (rc != 0) goto bail; wf_client_count++; @@ -417,7 +417,7 @@ EXPORT_SYMBOL_GPL(wf_register_client); int wf_unregister_client(struct notifier_block *nb) { mutex_lock(&wf_lock); - notifier_chain_unregister(&wf_client_list, nb); + blocking_notifier_chain_unregister(&wf_client_list, nb); wf_client_count++; if (wf_client_count == 0) wf_stop_thread(); diff --git a/drivers/misc/ibmasm/heartbeat.c b/drivers/misc/ibmasm/heartbeat.c index f295401fac2..7fd7a43e38d 100644 --- a/drivers/misc/ibmasm/heartbeat.c +++ b/drivers/misc/ibmasm/heartbeat.c @@ -52,12 +52,13 @@ static struct notifier_block panic_notifier = { panic_happened, NULL, 1 }; void ibmasm_register_panic_notifier(void) { - notifier_chain_register(&panic_notifier_list, &panic_notifier); + atomic_notifier_chain_register(&panic_notifier_list, &panic_notifier); } void ibmasm_unregister_panic_notifier(void) { - notifier_chain_unregister(&panic_notifier_list, &panic_notifier); + atomic_notifier_chain_unregister(&panic_notifier_list, + &panic_notifier); } diff --git a/drivers/net/bonding/bond_main.c b/drivers/net/bonding/bond_main.c index 2d0ac169a86..f13a539dc16 100644 --- a/drivers/net/bonding/bond_main.c +++ b/drivers/net/bonding/bond_main.c @@ -3159,7 +3159,7 @@ static int bond_slave_netdev_event(unsigned long event, struct net_device *slave * bond_netdev_event: handle netdev notifier chain events. * * This function receives events for the netdev chain. The caller (an - * ioctl handler calling notifier_call_chain) holds the necessary + * ioctl handler calling blocking_notifier_call_chain) holds the necessary * locks for us to safely manipulate the slave devices (RTNL lock, * dev_probe_lock). */ diff --git a/drivers/parisc/led.c b/drivers/parisc/led.c index 3627a2d7f79..298f2ddb2c1 100644 --- a/drivers/parisc/led.c +++ b/drivers/parisc/led.c @@ -499,11 +499,16 @@ static int led_halt(struct notifier_block *, unsigned long, void *); static struct notifier_block led_notifier = { .notifier_call = led_halt, }; +static int notifier_disabled = 0; static int led_halt(struct notifier_block *nb, unsigned long event, void *buf) { char *txt; - + + if (notifier_disabled) + return NOTIFY_OK; + + notifier_disabled = 1; switch (event) { case SYS_RESTART: txt = "SYSTEM RESTART"; break; @@ -527,7 +532,6 @@ static int led_halt(struct notifier_block *nb, unsigned long event, void *buf) if (led_func_ptr) led_func_ptr(0xff); /* turn all LEDs ON */ - unregister_reboot_notifier(&led_notifier); return NOTIFY_OK; } @@ -758,6 +762,12 @@ not_found: return 1; } +static void __exit led_exit(void) +{ + unregister_reboot_notifier(&led_notifier); + return; +} + #ifdef CONFIG_PROC_FS module_init(led_create_procfs) #endif diff --git a/drivers/parisc/power.c b/drivers/parisc/power.c index 54b2b7f20b9..0bcab83b408 100644 --- a/drivers/parisc/power.c +++ b/drivers/parisc/power.c @@ -251,7 +251,8 @@ static int __init power_init(void) } /* Register a call for panic conditions. */ - notifier_chain_register(&panic_notifier_list, &parisc_panic_block); + atomic_notifier_chain_register(&panic_notifier_list, + &parisc_panic_block); tasklet_enable(&power_tasklet); @@ -264,7 +265,8 @@ static void __exit power_exit(void) return; tasklet_disable(&power_tasklet); - notifier_chain_unregister(&panic_notifier_list, &parisc_panic_block); + atomic_notifier_chain_unregister(&panic_notifier_list, + &parisc_panic_block); power_tasklet.func = NULL; pdc_soft_power_button(0); } diff --git a/drivers/scsi/gdth.c b/drivers/scsi/gdth.c index 62e3cda859a..7f7013e80a8 100644 --- a/drivers/scsi/gdth.c +++ b/drivers/scsi/gdth.c @@ -671,7 +671,7 @@ static struct file_operations gdth_fops = { static struct notifier_block gdth_notifier = { gdth_halt, NULL, 0 }; - +static int notifier_disabled = 0; static void gdth_delay(int milliseconds) { @@ -4595,13 +4595,13 @@ static int __init gdth_detect(struct scsi_host_template *shtp) add_timer(&gdth_timer); #endif major = register_chrdev(0,"gdth",&gdth_fops); + notifier_disabled = 0; register_reboot_notifier(&gdth_notifier); } gdth_polling = FALSE; return gdth_ctr_vcount; } - static int gdth_release(struct Scsi_Host *shp) { int hanum; @@ -5632,10 +5632,14 @@ static int gdth_halt(struct notifier_block *nb, ulong event, void *buf) char cmnd[MAX_COMMAND_SIZE]; #endif + if (notifier_disabled) + return NOTIFY_OK; + TRACE2(("gdth_halt() event %d\n",(int)event)); if (event != SYS_RESTART && event != SYS_HALT && event != SYS_POWER_OFF) return NOTIFY_DONE; + notifier_disabled = 1; printk("GDT-HA: Flushing all host drives .. "); for (hanum = 0; hanum < gdth_ctr_count; ++hanum) { gdth_flush(hanum); @@ -5679,7 +5683,6 @@ static int gdth_halt(struct notifier_block *nb, ulong event, void *buf) #ifdef GDTH_STATISTICS del_timer(&gdth_timer); #endif - unregister_reboot_notifier(&gdth_notifier); return NOTIFY_OK; } diff --git a/drivers/usb/core/notify.c b/drivers/usb/core/notify.c index 4b55285de9a..fe0ed54fa0a 100644 --- a/drivers/usb/core/notify.c +++ b/drivers/usb/core/notify.c @@ -16,57 +16,7 @@ #include #include "usb.h" - -static struct notifier_block *usb_notifier_list; -static DEFINE_MUTEX(usb_notifier_lock); - -static void usb_notifier_chain_register(struct notifier_block **list, - struct notifier_block *n) -{ - mutex_lock(&usb_notifier_lock); - while (*list) { - if (n->priority > (*list)->priority) - break; - list = &((*list)->next); - } - n->next = *list; - *list = n; - mutex_unlock(&usb_notifier_lock); -} - -static void usb_notifier_chain_unregister(struct notifier_block **nl, - struct notifier_block *n) -{ - mutex_lock(&usb_notifier_lock); - while ((*nl)!=NULL) { - if ((*nl)==n) { - *nl = n->next; - goto exit; - } - nl=&((*nl)->next); - } -exit: - mutex_unlock(&usb_notifier_lock); -} - -static int usb_notifier_call_chain(struct notifier_block **n, - unsigned long val, void *v) -{ - int ret=NOTIFY_DONE; - struct notifier_block *nb = *n; - - mutex_lock(&usb_notifier_lock); - while (nb) { - ret = nb->notifier_call(nb,val,v); - if (ret&NOTIFY_STOP_MASK) { - goto exit; - } - nb = nb->next; - } -exit: - mutex_unlock(&usb_notifier_lock); - return ret; -} +static BLOCKING_NOTIFIER_HEAD(usb_notifier_list); /** * usb_register_notify - register a notifier callback whenever a usb change happens @@ -76,7 +26,7 @@ exit: */ void usb_register_notify(struct notifier_block *nb) { - usb_notifier_chain_register(&usb_notifier_list, nb); + blocking_notifier_chain_register(&usb_notifier_list, nb); } EXPORT_SYMBOL_GPL(usb_register_notify); @@ -89,27 +39,28 @@ EXPORT_SYMBOL_GPL(usb_register_notify); */ void usb_unregister_notify(struct notifier_block *nb) { - usb_notifier_chain_unregister(&usb_notifier_list, nb); + blocking_notifier_chain_unregister(&usb_notifier_list, nb); } EXPORT_SYMBOL_GPL(usb_unregister_notify); void usb_notify_add_device(struct usb_device *udev) { - usb_notifier_call_chain(&usb_notifier_list, USB_DEVICE_ADD, udev); + blocking_notifier_call_chain(&usb_notifier_list, USB_DEVICE_ADD, udev); } void usb_notify_remove_device(struct usb_device *udev) { - usb_notifier_call_chain(&usb_notifier_list, USB_DEVICE_REMOVE, udev); + blocking_notifier_call_chain(&usb_notifier_list, + USB_DEVICE_REMOVE, udev); } void usb_notify_add_bus(struct usb_bus *ubus) { - usb_notifier_call_chain(&usb_notifier_list, USB_BUS_ADD, ubus); + blocking_notifier_call_chain(&usb_notifier_list, USB_BUS_ADD, ubus); } void usb_notify_remove_bus(struct usb_bus *ubus) { - usb_notifier_call_chain(&usb_notifier_list, USB_BUS_REMOVE, ubus); + blocking_notifier_call_chain(&usb_notifier_list, USB_BUS_REMOVE, ubus); } diff --git a/drivers/video/fbmem.c b/drivers/video/fbmem.c index 07d882b1439..b1a8dca7643 100644 --- a/drivers/video/fbmem.c +++ b/drivers/video/fbmem.c @@ -55,7 +55,7 @@ #define FBPIXMAPSIZE (1024 * 8) -static struct notifier_block *fb_notifier_list; +static BLOCKING_NOTIFIER_HEAD(fb_notifier_list); struct fb_info *registered_fb[FB_MAX]; int num_registered_fb; @@ -784,7 +784,7 @@ fb_set_var(struct fb_info *info, struct fb_var_screeninfo *var) event.info = info; event.data = &mode1; - ret = notifier_call_chain(&fb_notifier_list, + ret = blocking_notifier_call_chain(&fb_notifier_list, FB_EVENT_MODE_DELETE, &event); } @@ -830,8 +830,8 @@ fb_set_var(struct fb_info *info, struct fb_var_screeninfo *var) info->flags &= ~FBINFO_MISC_USEREVENT; event.info = info; - notifier_call_chain(&fb_notifier_list, evnt, - &event); + blocking_notifier_call_chain(&fb_notifier_list, + evnt, &event); } } } @@ -854,7 +854,8 @@ fb_blank(struct fb_info *info, int blank) event.info = info; event.data = ␣ - notifier_call_chain(&fb_notifier_list, FB_EVENT_BLANK, &event); + blocking_notifier_call_chain(&fb_notifier_list, + FB_EVENT_BLANK, &event); } return ret; @@ -925,7 +926,7 @@ fb_ioctl(struct inode *inode, struct file *file, unsigned int cmd, con2fb.framebuffer = -1; event.info = info; event.data = &con2fb; - notifier_call_chain(&fb_notifier_list, + blocking_notifier_call_chain(&fb_notifier_list, FB_EVENT_GET_CONSOLE_MAP, &event); return copy_to_user(argp, &con2fb, sizeof(con2fb)) ? -EFAULT : 0; @@ -944,7 +945,7 @@ fb_ioctl(struct inode *inode, struct file *file, unsigned int cmd, return -EINVAL; event.info = info; event.data = &con2fb; - return notifier_call_chain(&fb_notifier_list, + return blocking_notifier_call_chain(&fb_notifier_list, FB_EVENT_SET_CONSOLE_MAP, &event); case FBIOBLANK: @@ -1324,7 +1325,7 @@ register_framebuffer(struct fb_info *fb_info) devfs_mk_cdev(MKDEV(FB_MAJOR, i), S_IFCHR | S_IRUGO | S_IWUGO, "fb/%d", i); event.info = fb_info; - notifier_call_chain(&fb_notifier_list, + blocking_notifier_call_chain(&fb_notifier_list, FB_EVENT_FB_REGISTERED, &event); return 0; } @@ -1366,7 +1367,7 @@ unregister_framebuffer(struct fb_info *fb_info) */ int fb_register_client(struct notifier_block *nb) { - return notifier_chain_register(&fb_notifier_list, nb); + return blocking_notifier_chain_register(&fb_notifier_list, nb); } /** @@ -1375,7 +1376,7 @@ int fb_register_client(struct notifier_block *nb) */ int fb_unregister_client(struct notifier_block *nb) { - return notifier_chain_unregister(&fb_notifier_list, nb); + return blocking_notifier_chain_unregister(&fb_notifier_list, nb); } /** @@ -1393,11 +1394,13 @@ void fb_set_suspend(struct fb_info *info, int state) event.info = info; if (state) { - notifier_call_chain(&fb_notifier_list, FB_EVENT_SUSPEND, &event); + blocking_notifier_call_chain(&fb_notifier_list, + FB_EVENT_SUSPEND, &event); info->state = FBINFO_STATE_SUSPENDED; } else { info->state = FBINFO_STATE_RUNNING; - notifier_call_chain(&fb_notifier_list, FB_EVENT_RESUME, &event); + blocking_notifier_call_chain(&fb_notifier_list, + FB_EVENT_RESUME, &event); } } @@ -1469,7 +1472,7 @@ int fb_new_modelist(struct fb_info *info) if (!list_empty(&info->modelist)) { event.info = info; - err = notifier_call_chain(&fb_notifier_list, + err = blocking_notifier_call_chain(&fb_notifier_list, FB_EVENT_NEW_MODELIST, &event); } @@ -1495,7 +1498,7 @@ int fb_con_duit(struct fb_info *info, int event, void *data) evnt.info = info; evnt.data = data; - return notifier_call_chain(&fb_notifier_list, event, &evnt); + return blocking_notifier_call_chain(&fb_notifier_list, event, &evnt); } EXPORT_SYMBOL(fb_con_duit); diff --git a/include/asm-i386/kdebug.h b/include/asm-i386/kdebug.h index 316138e8991..96d0828ce09 100644 --- a/include/asm-i386/kdebug.h +++ b/include/asm-i386/kdebug.h @@ -17,11 +17,9 @@ struct die_args { int signr; }; -/* Note - you should never unregister because that can race with NMIs. - If you really want to do it first unregister - then synchronize_sched - then free. - */ -int register_die_notifier(struct notifier_block *nb); -extern struct notifier_block *i386die_chain; +extern int register_die_notifier(struct notifier_block *); +extern int unregister_die_notifier(struct notifier_block *); +extern struct atomic_notifier_head i386die_chain; /* Grossly misnamed. */ @@ -51,7 +49,7 @@ static inline int notify_die(enum die_val val, const char *str, .trapnr = trap, .signr = sig }; - return notifier_call_chain(&i386die_chain, val, &args); + return atomic_notifier_call_chain(&i386die_chain, val, &args); } #endif diff --git a/include/asm-ia64/kdebug.h b/include/asm-ia64/kdebug.h index 8b01a083dde..218c458ab60 100644 --- a/include/asm-ia64/kdebug.h +++ b/include/asm-ia64/kdebug.h @@ -40,7 +40,7 @@ struct die_args { extern int register_die_notifier(struct notifier_block *); extern int unregister_die_notifier(struct notifier_block *); -extern struct notifier_block *ia64die_chain; +extern struct atomic_notifier_head ia64die_chain; enum die_val { DIE_BREAK = 1, @@ -81,7 +81,7 @@ static inline int notify_die(enum die_val val, char *str, struct pt_regs *regs, .signr = sig }; - return notifier_call_chain(&ia64die_chain, val, &args); + return atomic_notifier_call_chain(&ia64die_chain, val, &args); } #endif diff --git a/include/asm-powerpc/kdebug.h b/include/asm-powerpc/kdebug.h index 7c16265568e..c01786ab5fa 100644 --- a/include/asm-powerpc/kdebug.h +++ b/include/asm-powerpc/kdebug.h @@ -16,13 +16,9 @@ struct die_args { int signr; }; -/* - Note - you should never unregister because that can race with NMIs. - If you really want to do it first unregister - then synchronize_sched - - then free. - */ -int register_die_notifier(struct notifier_block *nb); -extern struct notifier_block *powerpc_die_chain; +extern int register_die_notifier(struct notifier_block *); +extern int unregister_die_notifier(struct notifier_block *); +extern struct atomic_notifier_head powerpc_die_chain; /* Grossly misnamed. */ enum die_val { @@ -37,7 +33,7 @@ enum die_val { static inline int notify_die(enum die_val val,char *str,struct pt_regs *regs,long err,int trap, int sig) { struct die_args args = { .regs=regs, .str=str, .err=err, .trapnr=trap,.signr=sig }; - return notifier_call_chain(&powerpc_die_chain, val, &args); + return atomic_notifier_call_chain(&powerpc_die_chain, val, &args); } #endif /* __KERNEL__ */ diff --git a/include/asm-sparc64/kdebug.h b/include/asm-sparc64/kdebug.h index 6321f5a0198..4040d127ac3 100644 --- a/include/asm-sparc64/kdebug.h +++ b/include/asm-sparc64/kdebug.h @@ -15,12 +15,9 @@ struct die_args { int signr; }; -/* Note - you should never unregister because that can race with NMIs. - * If you really want to do it first unregister - then synchronize_sched - * - then free. - */ -int register_die_notifier(struct notifier_block *nb); -extern struct notifier_block *sparc64die_chain; +extern int register_die_notifier(struct notifier_block *); +extern int unregister_die_notifier(struct notifier_block *); +extern struct atomic_notifier_head sparc64die_chain; extern void bad_trap(struct pt_regs *, long); @@ -46,7 +43,7 @@ static inline int notify_die(enum die_val val,char *str, struct pt_regs *regs, .trapnr = trap, .signr = sig }; - return notifier_call_chain(&sparc64die_chain, val, &args); + return atomic_notifier_call_chain(&sparc64die_chain, val, &args); } #endif diff --git a/include/asm-x86_64/kdebug.h b/include/asm-x86_64/kdebug.h index b9ed4c0c878..cf795631d9b 100644 --- a/include/asm-x86_64/kdebug.h +++ b/include/asm-x86_64/kdebug.h @@ -5,21 +5,20 @@ struct pt_regs; -struct die_args { +struct die_args { struct pt_regs *regs; const char *str; - long err; + long err; int trapnr; int signr; -}; +}; + +extern int register_die_notifier(struct notifier_block *); +extern int unregister_die_notifier(struct notifier_block *); +extern struct atomic_notifier_head die_chain; -/* Note - you should never unregister because that can race with NMIs. - If you really want to do it first unregister - then synchronize_sched - then free. - */ -int register_die_notifier(struct notifier_block *nb); -extern struct notifier_block *die_chain; /* Grossly misnamed. */ -enum die_val { +enum die_val { DIE_OOPS = 1, DIE_INT3, DIE_DEBUG, @@ -33,8 +32,8 @@ enum die_val { DIE_CALL, DIE_NMI_IPI, DIE_PAGE_FAULT, -}; - +}; + static inline int notify_die(enum die_val val, const char *str, struct pt_regs *regs, long err, int trap, int sig) { @@ -45,7 +44,7 @@ static inline int notify_die(enum die_val val, const char *str, .trapnr = trap, .signr = sig }; - return notifier_call_chain(&die_chain, val, &args); + return atomic_notifier_call_chain(&die_chain, val, &args); } extern int printk_address(unsigned long address); diff --git a/include/linux/adb.h b/include/linux/adb.h index e9fdc63483c..b7305b17827 100644 --- a/include/linux/adb.h +++ b/include/linux/adb.h @@ -85,7 +85,7 @@ enum adb_message { ADB_MSG_POST_RESET /* Called after resetting the bus (re-do init & register) */ }; extern struct adb_driver *adb_controller; -extern struct notifier_block *adb_client_list; +extern struct blocking_notifier_head adb_client_list; int adb_request(struct adb_request *req, void (*done)(struct adb_request *), int flags, int nbytes, ...); diff --git a/include/linux/kernel.h b/include/linux/kernel.h index 03d6cfaa5b8..a3720f973ea 100644 --- a/include/linux/kernel.h +++ b/include/linux/kernel.h @@ -87,7 +87,7 @@ extern int cond_resched(void); (__x < 0) ? -__x : __x; \ }) -extern struct notifier_block *panic_notifier_list; +extern struct atomic_notifier_head panic_notifier_list; extern long (*panic_blink)(long time); NORET_TYPE void panic(const char * fmt, ...) __attribute__ ((NORET_AND format (printf, 1, 2))); diff --git a/include/linux/memory.h b/include/linux/memory.h index e251dc43d0f..8f04143ca36 100644 --- a/include/linux/memory.h +++ b/include/linux/memory.h @@ -77,7 +77,6 @@ extern int remove_memory_block(unsigned long, struct mem_section *, int); #define CONFIG_MEM_BLOCK_SIZE (PAGES_PER_SECTION< +#include +#include -struct notifier_block -{ - int (*notifier_call)(struct notifier_block *self, unsigned long, void *); +/* + * Notifier chains are of three types: + * + * Atomic notifier chains: Chain callbacks run in interrupt/atomic + * context. Callouts are not allowed to block. + * Blocking notifier chains: Chain callbacks run in process context. + * Callouts are allowed to block. + * Raw notifier chains: There are no restrictions on callbacks, + * registration, or unregistration. All locking and protection + * must be provided by the caller. + * + * atomic_notifier_chain_register() may be called from an atomic context, + * but blocking_notifier_chain_register() must be called from a process + * context. Ditto for the corresponding _unregister() routines. + * + * atomic_notifier_chain_unregister() and blocking_notifier_chain_unregister() + * _must not_ be called from within the call chain. + */ + +struct notifier_block { + int (*notifier_call)(struct notifier_block *, unsigned long, void *); struct notifier_block *next; int priority; }; +struct atomic_notifier_head { + spinlock_t lock; + struct notifier_block *head; +}; + +struct blocking_notifier_head { + struct rw_semaphore rwsem; + struct notifier_block *head; +}; + +struct raw_notifier_head { + struct notifier_block *head; +}; + +#define ATOMIC_INIT_NOTIFIER_HEAD(name) do { \ + spin_lock_init(&(name)->lock); \ + (name)->head = NULL; \ + } while (0) +#define BLOCKING_INIT_NOTIFIER_HEAD(name) do { \ + init_rwsem(&(name)->rwsem); \ + (name)->head = NULL; \ + } while (0) +#define RAW_INIT_NOTIFIER_HEAD(name) do { \ + (name)->head = NULL; \ + } while (0) + +#define ATOMIC_NOTIFIER_INIT(name) { \ + .lock = SPIN_LOCK_UNLOCKED, \ + .head = NULL } +#define BLOCKING_NOTIFIER_INIT(name) { \ + .rwsem = __RWSEM_INITIALIZER((name).rwsem), \ + .head = NULL } +#define RAW_NOTIFIER_INIT(name) { \ + .head = NULL } + +#define ATOMIC_NOTIFIER_HEAD(name) \ + struct atomic_notifier_head name = \ + ATOMIC_NOTIFIER_INIT(name) +#define BLOCKING_NOTIFIER_HEAD(name) \ + struct blocking_notifier_head name = \ + BLOCKING_NOTIFIER_INIT(name) +#define RAW_NOTIFIER_HEAD(name) \ + struct raw_notifier_head name = \ + RAW_NOTIFIER_INIT(name) #ifdef __KERNEL__ -extern int notifier_chain_register(struct notifier_block **list, struct notifier_block *n); -extern int notifier_chain_unregister(struct notifier_block **nl, struct notifier_block *n); -extern int notifier_call_chain(struct notifier_block **n, unsigned long val, void *v); +extern int atomic_notifier_chain_register(struct atomic_notifier_head *, + struct notifier_block *); +extern int blocking_notifier_chain_register(struct blocking_notifier_head *, + struct notifier_block *); +extern int raw_notifier_chain_register(struct raw_notifier_head *, + struct notifier_block *); + +extern int atomic_notifier_chain_unregister(struct atomic_notifier_head *, + struct notifier_block *); +extern int blocking_notifier_chain_unregister(struct blocking_notifier_head *, + struct notifier_block *); +extern int raw_notifier_chain_unregister(struct raw_notifier_head *, + struct notifier_block *); + +extern int atomic_notifier_call_chain(struct atomic_notifier_head *, + unsigned long val, void *v); +extern int blocking_notifier_call_chain(struct blocking_notifier_head *, + unsigned long val, void *v); +extern int raw_notifier_call_chain(struct raw_notifier_head *, + unsigned long val, void *v); #define NOTIFY_DONE 0x0000 /* Don't care */ #define NOTIFY_OK 0x0001 /* Suits me */ #define NOTIFY_STOP_MASK 0x8000 /* Don't call further */ -#define NOTIFY_BAD (NOTIFY_STOP_MASK|0x0002) /* Bad/Veto action */ +#define NOTIFY_BAD (NOTIFY_STOP_MASK|0x0002) + /* Bad/Veto action */ /* * Clean way to return from the notifier and stop further calls. */ diff --git a/include/net/netfilter/nf_conntrack.h b/include/net/netfilter/nf_conntrack.h index b6f0905a4ee..916013ca4a5 100644 --- a/include/net/netfilter/nf_conntrack.h +++ b/include/net/netfilter/nf_conntrack.h @@ -300,29 +300,30 @@ DECLARE_PER_CPU(struct nf_conntrack_ecache, nf_conntrack_ecache); #define CONNTRACK_ECACHE(x) (__get_cpu_var(nf_conntrack_ecache).x) -extern struct notifier_block *nf_conntrack_chain; -extern struct notifier_block *nf_conntrack_expect_chain; +extern struct atomic_notifier_head nf_conntrack_chain; +extern struct atomic_notifier_head nf_conntrack_expect_chain; static inline int nf_conntrack_register_notifier(struct notifier_block *nb) { - return notifier_chain_register(&nf_conntrack_chain, nb); + return atomic_notifier_chain_register(&nf_conntrack_chain, nb); } static inline int nf_conntrack_unregister_notifier(struct notifier_block *nb) { - return notifier_chain_unregister(&nf_conntrack_chain, nb); + return atomic_notifier_chain_unregister(&nf_conntrack_chain, nb); } static inline int nf_conntrack_expect_register_notifier(struct notifier_block *nb) { - return notifier_chain_register(&nf_conntrack_expect_chain, nb); + return atomic_notifier_chain_register(&nf_conntrack_expect_chain, nb); } static inline int nf_conntrack_expect_unregister_notifier(struct notifier_block *nb) { - return notifier_chain_unregister(&nf_conntrack_expect_chain, nb); + return atomic_notifier_chain_unregister(&nf_conntrack_expect_chain, + nb); } extern void nf_ct_deliver_cached_events(const struct nf_conn *ct); @@ -347,14 +348,14 @@ static inline void nf_conntrack_event(enum ip_conntrack_events event, struct nf_conn *ct) { if (nf_ct_is_confirmed(ct) && !nf_ct_is_dying(ct)) - notifier_call_chain(&nf_conntrack_chain, event, ct); + atomic_notifier_call_chain(&nf_conntrack_chain, event, ct); } static inline void nf_conntrack_expect_event(enum ip_conntrack_expect_events event, struct nf_conntrack_expect *exp) { - notifier_call_chain(&nf_conntrack_expect_chain, event, exp); + atomic_notifier_call_chain(&nf_conntrack_expect_chain, event, exp); } #else /* CONFIG_NF_CONNTRACK_EVENTS */ static inline void nf_conntrack_event_cache(enum ip_conntrack_events event, diff --git a/kernel/cpu.c b/kernel/cpu.c index 8be22bd8093..fe2b8d0bfe4 100644 --- a/kernel/cpu.c +++ b/kernel/cpu.c @@ -18,7 +18,7 @@ /* This protects CPUs going up and down... */ static DECLARE_MUTEX(cpucontrol); -static struct notifier_block *cpu_chain; +static BLOCKING_NOTIFIER_HEAD(cpu_chain); #ifdef CONFIG_HOTPLUG_CPU static struct task_struct *lock_cpu_hotplug_owner; @@ -71,21 +71,13 @@ EXPORT_SYMBOL_GPL(lock_cpu_hotplug_interruptible); /* Need to know about CPUs going up/down? */ int register_cpu_notifier(struct notifier_block *nb) { - int ret; - - if ((ret = lock_cpu_hotplug_interruptible()) != 0) - return ret; - ret = notifier_chain_register(&cpu_chain, nb); - unlock_cpu_hotplug(); - return ret; + return blocking_notifier_chain_register(&cpu_chain, nb); } EXPORT_SYMBOL(register_cpu_notifier); void unregister_cpu_notifier(struct notifier_block *nb) { - lock_cpu_hotplug(); - notifier_chain_unregister(&cpu_chain, nb); - unlock_cpu_hotplug(); + blocking_notifier_chain_unregister(&cpu_chain, nb); } EXPORT_SYMBOL(unregister_cpu_notifier); @@ -141,7 +133,7 @@ int cpu_down(unsigned int cpu) goto out; } - err = notifier_call_chain(&cpu_chain, CPU_DOWN_PREPARE, + err = blocking_notifier_call_chain(&cpu_chain, CPU_DOWN_PREPARE, (void *)(long)cpu); if (err == NOTIFY_BAD) { printk("%s: attempt to take down CPU %u failed\n", @@ -159,7 +151,7 @@ int cpu_down(unsigned int cpu) p = __stop_machine_run(take_cpu_down, NULL, cpu); if (IS_ERR(p)) { /* CPU didn't die: tell everyone. Can't complain. */ - if (notifier_call_chain(&cpu_chain, CPU_DOWN_FAILED, + if (blocking_notifier_call_chain(&cpu_chain, CPU_DOWN_FAILED, (void *)(long)cpu) == NOTIFY_BAD) BUG(); @@ -182,8 +174,8 @@ int cpu_down(unsigned int cpu) put_cpu(); /* CPU is completely dead: tell everyone. Too late to complain. */ - if (notifier_call_chain(&cpu_chain, CPU_DEAD, (void *)(long)cpu) - == NOTIFY_BAD) + if (blocking_notifier_call_chain(&cpu_chain, CPU_DEAD, + (void *)(long)cpu) == NOTIFY_BAD) BUG(); check_for_tasks(cpu); @@ -211,7 +203,7 @@ int __devinit cpu_up(unsigned int cpu) goto out; } - ret = notifier_call_chain(&cpu_chain, CPU_UP_PREPARE, hcpu); + ret = blocking_notifier_call_chain(&cpu_chain, CPU_UP_PREPARE, hcpu); if (ret == NOTIFY_BAD) { printk("%s: attempt to bring up CPU %u failed\n", __FUNCTION__, cpu); @@ -226,11 +218,12 @@ int __devinit cpu_up(unsigned int cpu) BUG_ON(!cpu_online(cpu)); /* Now call notifier in preparation. */ - notifier_call_chain(&cpu_chain, CPU_ONLINE, hcpu); + blocking_notifier_call_chain(&cpu_chain, CPU_ONLINE, hcpu); out_notify: if (ret != 0) - notifier_call_chain(&cpu_chain, CPU_UP_CANCELED, hcpu); + blocking_notifier_call_chain(&cpu_chain, + CPU_UP_CANCELED, hcpu); out: unlock_cpu_hotplug(); return ret; diff --git a/kernel/module.c b/kernel/module.c index ddfe45ac2fd..4fafd58038a 100644 --- a/kernel/module.c +++ b/kernel/module.c @@ -64,26 +64,17 @@ static DEFINE_SPINLOCK(modlist_lock); static DEFINE_MUTEX(module_mutex); static LIST_HEAD(modules); -static DEFINE_MUTEX(notify_mutex); -static struct notifier_block * module_notify_list; +static BLOCKING_NOTIFIER_HEAD(module_notify_list); int register_module_notifier(struct notifier_block * nb) { - int err; - mutex_lock(¬ify_mutex); - err = notifier_chain_register(&module_notify_list, nb); - mutex_unlock(¬ify_mutex); - return err; + return blocking_notifier_chain_register(&module_notify_list, nb); } EXPORT_SYMBOL(register_module_notifier); int unregister_module_notifier(struct notifier_block * nb) { - int err; - mutex_lock(¬ify_mutex); - err = notifier_chain_unregister(&module_notify_list, nb); - mutex_unlock(¬ify_mutex); - return err; + return blocking_notifier_chain_unregister(&module_notify_list, nb); } EXPORT_SYMBOL(unregister_module_notifier); @@ -1816,9 +1807,8 @@ sys_init_module(void __user *umod, /* Drop lock so they can recurse */ mutex_unlock(&module_mutex); - mutex_lock(¬ify_mutex); - notifier_call_chain(&module_notify_list, MODULE_STATE_COMING, mod); - mutex_unlock(¬ify_mutex); + blocking_notifier_call_chain(&module_notify_list, + MODULE_STATE_COMING, mod); /* Start the module */ if (mod->init != NULL) diff --git a/kernel/panic.c b/kernel/panic.c index acd95adddb9..f895c7c01d5 100644 --- a/kernel/panic.c +++ b/kernel/panic.c @@ -29,7 +29,7 @@ static DEFINE_SPINLOCK(pause_on_oops_lock); int panic_timeout; EXPORT_SYMBOL(panic_timeout); -struct notifier_block *panic_notifier_list; +ATOMIC_NOTIFIER_HEAD(panic_notifier_list); EXPORT_SYMBOL(panic_notifier_list); @@ -97,7 +97,7 @@ NORET_TYPE void panic(const char * fmt, ...) smp_send_stop(); #endif - notifier_call_chain(&panic_notifier_list, 0, buf); + atomic_notifier_call_chain(&panic_notifier_list, 0, buf); if (!panic_blink) panic_blink = no_blink; diff --git a/kernel/profile.c b/kernel/profile.c index ad81f799a9b..5a730fdb1a2 100644 --- a/kernel/profile.c +++ b/kernel/profile.c @@ -87,72 +87,52 @@ void __init profile_init(void) #ifdef CONFIG_PROFILING -static DECLARE_RWSEM(profile_rwsem); -static DEFINE_RWLOCK(handoff_lock); -static struct notifier_block * task_exit_notifier; -static struct notifier_block * task_free_notifier; -static struct notifier_block * munmap_notifier; +static BLOCKING_NOTIFIER_HEAD(task_exit_notifier); +static ATOMIC_NOTIFIER_HEAD(task_free_notifier); +static BLOCKING_NOTIFIER_HEAD(munmap_notifier); void profile_task_exit(struct task_struct * task) { - down_read(&profile_rwsem); - notifier_call_chain(&task_exit_notifier, 0, task); - up_read(&profile_rwsem); + blocking_notifier_call_chain(&task_exit_notifier, 0, task); } int profile_handoff_task(struct task_struct * task) { int ret; - read_lock(&handoff_lock); - ret = notifier_call_chain(&task_free_notifier, 0, task); - read_unlock(&handoff_lock); + ret = atomic_notifier_call_chain(&task_free_notifier, 0, task); return (ret == NOTIFY_OK) ? 1 : 0; } void profile_munmap(unsigned long addr) { - down_read(&profile_rwsem); - notifier_call_chain(&munmap_notifier, 0, (void *)addr); - up_read(&profile_rwsem); + blocking_notifier_call_chain(&munmap_notifier, 0, (void *)addr); } int task_handoff_register(struct notifier_block * n) { - int err = -EINVAL; - - write_lock(&handoff_lock); - err = notifier_chain_register(&task_free_notifier, n); - write_unlock(&handoff_lock); - return err; + return atomic_notifier_chain_register(&task_free_notifier, n); } int task_handoff_unregister(struct notifier_block * n) { - int err = -EINVAL; - - write_lock(&handoff_lock); - err = notifier_chain_unregister(&task_free_notifier, n); - write_unlock(&handoff_lock); - return err; + return atomic_notifier_chain_unregister(&task_free_notifier, n); } int profile_event_register(enum profile_type type, struct notifier_block * n) { int err = -EINVAL; - down_write(&profile_rwsem); - switch (type) { case PROFILE_TASK_EXIT: - err = notifier_chain_register(&task_exit_notifier, n); + err = blocking_notifier_chain_register( + &task_exit_notifier, n); break; case PROFILE_MUNMAP: - err = notifier_chain_register(&munmap_notifier, n); + err = blocking_notifier_chain_register( + &munmap_notifier, n); break; } - up_write(&profile_rwsem); - return err; } @@ -161,18 +141,17 @@ int profile_event_unregister(enum profile_type type, struct notifier_block * n) { int err = -EINVAL; - down_write(&profile_rwsem); - switch (type) { case PROFILE_TASK_EXIT: - err = notifier_chain_unregister(&task_exit_notifier, n); + err = blocking_notifier_chain_unregister( + &task_exit_notifier, n); break; case PROFILE_MUNMAP: - err = notifier_chain_unregister(&munmap_notifier, n); + err = blocking_notifier_chain_unregister( + &munmap_notifier, n); break; } - up_write(&profile_rwsem); return err; } diff --git a/kernel/softlockup.c b/kernel/softlockup.c index d9b3d5847ed..ced91e1ff56 100644 --- a/kernel/softlockup.c +++ b/kernel/softlockup.c @@ -152,5 +152,5 @@ __init void spawn_softlockup_task(void) cpu_callback(&cpu_nfb, CPU_ONLINE, cpu); register_cpu_notifier(&cpu_nfb); - notifier_chain_register(&panic_notifier_list, &panic_block); + atomic_notifier_chain_register(&panic_notifier_list, &panic_block); } diff --git a/kernel/sys.c b/kernel/sys.c index 38bc73ede2b..c93d37f71ae 100644 --- a/kernel/sys.c +++ b/kernel/sys.c @@ -95,99 +95,304 @@ int cad_pid = 1; * and the like. */ -static struct notifier_block *reboot_notifier_list; -static DEFINE_RWLOCK(notifier_lock); +static BLOCKING_NOTIFIER_HEAD(reboot_notifier_list); + +/* + * Notifier chain core routines. The exported routines below + * are layered on top of these, with appropriate locking added. + */ + +static int notifier_chain_register(struct notifier_block **nl, + struct notifier_block *n) +{ + while ((*nl) != NULL) { + if (n->priority > (*nl)->priority) + break; + nl = &((*nl)->next); + } + n->next = *nl; + rcu_assign_pointer(*nl, n); + return 0; +} + +static int notifier_chain_unregister(struct notifier_block **nl, + struct notifier_block *n) +{ + while ((*nl) != NULL) { + if ((*nl) == n) { + rcu_assign_pointer(*nl, n->next); + return 0; + } + nl = &((*nl)->next); + } + return -ENOENT; +} + +static int __kprobes notifier_call_chain(struct notifier_block **nl, + unsigned long val, void *v) +{ + int ret = NOTIFY_DONE; + struct notifier_block *nb; + + nb = rcu_dereference(*nl); + while (nb) { + ret = nb->notifier_call(nb, val, v); + if ((ret & NOTIFY_STOP_MASK) == NOTIFY_STOP_MASK) + break; + nb = rcu_dereference(nb->next); + } + return ret; +} + +/* + * Atomic notifier chain routines. Registration and unregistration + * use a mutex, and call_chain is synchronized by RCU (no locks). + */ /** - * notifier_chain_register - Add notifier to a notifier chain - * @list: Pointer to root list pointer + * atomic_notifier_chain_register - Add notifier to an atomic notifier chain + * @nh: Pointer to head of the atomic notifier chain * @n: New entry in notifier chain * - * Adds a notifier to a notifier chain. + * Adds a notifier to an atomic notifier chain. * * Currently always returns zero. */ + +int atomic_notifier_chain_register(struct atomic_notifier_head *nh, + struct notifier_block *n) +{ + unsigned long flags; + int ret; + + spin_lock_irqsave(&nh->lock, flags); + ret = notifier_chain_register(&nh->head, n); + spin_unlock_irqrestore(&nh->lock, flags); + return ret; +} + +EXPORT_SYMBOL_GPL(atomic_notifier_chain_register); + +/** + * atomic_notifier_chain_unregister - Remove notifier from an atomic notifier chain + * @nh: Pointer to head of the atomic notifier chain + * @n: Entry to remove from notifier chain + * + * Removes a notifier from an atomic notifier chain. + * + * Returns zero on success or %-ENOENT on failure. + */ +int atomic_notifier_chain_unregister(struct atomic_notifier_head *nh, + struct notifier_block *n) +{ + unsigned long flags; + int ret; + + spin_lock_irqsave(&nh->lock, flags); + ret = notifier_chain_unregister(&nh->head, n); + spin_unlock_irqrestore(&nh->lock, flags); + synchronize_rcu(); + return ret; +} + +EXPORT_SYMBOL_GPL(atomic_notifier_chain_unregister); + +/** + * atomic_notifier_call_chain - Call functions in an atomic notifier chain + * @nh: Pointer to head of the atomic notifier chain + * @val: Value passed unmodified to notifier function + * @v: Pointer passed unmodified to notifier function + * + * Calls each function in a notifier chain in turn. The functions + * run in an atomic context, so they must not block. + * This routine uses RCU to synchronize with changes to the chain. + * + * If the return value of the notifier can be and'ed + * with %NOTIFY_STOP_MASK then atomic_notifier_call_chain + * will return immediately, with the return value of + * the notifier function which halted execution. + * Otherwise the return value is the return value + * of the last notifier function called. + */ -int notifier_chain_register(struct notifier_block **list, struct notifier_block *n) +int atomic_notifier_call_chain(struct atomic_notifier_head *nh, + unsigned long val, void *v) { - write_lock(¬ifier_lock); - while(*list) - { - if(n->priority > (*list)->priority) - break; - list= &((*list)->next); - } - n->next = *list; - *list=n; - write_unlock(¬ifier_lock); - return 0; + int ret; + + rcu_read_lock(); + ret = notifier_call_chain(&nh->head, val, v); + rcu_read_unlock(); + return ret; } -EXPORT_SYMBOL(notifier_chain_register); +EXPORT_SYMBOL_GPL(atomic_notifier_call_chain); + +/* + * Blocking notifier chain routines. All access to the chain is + * synchronized by an rwsem. + */ /** - * notifier_chain_unregister - Remove notifier from a notifier chain - * @nl: Pointer to root list pointer + * blocking_notifier_chain_register - Add notifier to a blocking notifier chain + * @nh: Pointer to head of the blocking notifier chain * @n: New entry in notifier chain * - * Removes a notifier from a notifier chain. + * Adds a notifier to a blocking notifier chain. + * Must be called in process context. * - * Returns zero on success, or %-ENOENT on failure. + * Currently always returns zero. */ -int notifier_chain_unregister(struct notifier_block **nl, struct notifier_block *n) +int blocking_notifier_chain_register(struct blocking_notifier_head *nh, + struct notifier_block *n) { - write_lock(¬ifier_lock); - while((*nl)!=NULL) - { - if((*nl)==n) - { - *nl=n->next; - write_unlock(¬ifier_lock); - return 0; - } - nl=&((*nl)->next); - } - write_unlock(¬ifier_lock); - return -ENOENT; + int ret; + + /* + * This code gets used during boot-up, when task switching is + * not yet working and interrupts must remain disabled. At + * such times we must not call down_write(). + */ + if (unlikely(system_state == SYSTEM_BOOTING)) + return notifier_chain_register(&nh->head, n); + + down_write(&nh->rwsem); + ret = notifier_chain_register(&nh->head, n); + up_write(&nh->rwsem); + return ret; } -EXPORT_SYMBOL(notifier_chain_unregister); +EXPORT_SYMBOL_GPL(blocking_notifier_chain_register); /** - * notifier_call_chain - Call functions in a notifier chain - * @n: Pointer to root pointer of notifier chain + * blocking_notifier_chain_unregister - Remove notifier from a blocking notifier chain + * @nh: Pointer to head of the blocking notifier chain + * @n: Entry to remove from notifier chain + * + * Removes a notifier from a blocking notifier chain. + * Must be called from process context. + * + * Returns zero on success or %-ENOENT on failure. + */ +int blocking_notifier_chain_unregister(struct blocking_notifier_head *nh, + struct notifier_block *n) +{ + int ret; + + /* + * This code gets used during boot-up, when task switching is + * not yet working and interrupts must remain disabled. At + * such times we must not call down_write(). + */ + if (unlikely(system_state == SYSTEM_BOOTING)) + return notifier_chain_unregister(&nh->head, n); + + down_write(&nh->rwsem); + ret = notifier_chain_unregister(&nh->head, n); + up_write(&nh->rwsem); + return ret; +} + +EXPORT_SYMBOL_GPL(blocking_notifier_chain_unregister); + +/** + * blocking_notifier_call_chain - Call functions in a blocking notifier chain + * @nh: Pointer to head of the blocking notifier chain * @val: Value passed unmodified to notifier function * @v: Pointer passed unmodified to notifier function * - * Calls each function in a notifier chain in turn. + * Calls each function in a notifier chain in turn. The functions + * run in a process context, so they are allowed to block. * - * If the return value of the notifier can be and'd - * with %NOTIFY_STOP_MASK, then notifier_call_chain + * If the return value of the notifier can be and'ed + * with %NOTIFY_STOP_MASK then blocking_notifier_call_chain * will return immediately, with the return value of * the notifier function which halted execution. - * Otherwise, the return value is the return value + * Otherwise the return value is the return value * of the last notifier function called. */ -int __kprobes notifier_call_chain(struct notifier_block **n, unsigned long val, void *v) +int blocking_notifier_call_chain(struct blocking_notifier_head *nh, + unsigned long val, void *v) { - int ret=NOTIFY_DONE; - struct notifier_block *nb = *n; + int ret; - while(nb) - { - ret=nb->notifier_call(nb,val,v); - if(ret&NOTIFY_STOP_MASK) - { - return ret; - } - nb=nb->next; - } + down_read(&nh->rwsem); + ret = notifier_call_chain(&nh->head, val, v); + up_read(&nh->rwsem); return ret; } -EXPORT_SYMBOL(notifier_call_chain); +EXPORT_SYMBOL_GPL(blocking_notifier_call_chain); + +/* + * Raw notifier chain routines. There is no protection; + * the caller must provide it. Use at your own risk! + */ + +/** + * raw_notifier_chain_register - Add notifier to a raw notifier chain + * @nh: Pointer to head of the raw notifier chain + * @n: New entry in notifier chain + * + * Adds a notifier to a raw notifier chain. + * All locking must be provided by the caller. + * + * Currently always returns zero. + */ + +int raw_notifier_chain_register(struct raw_notifier_head *nh, + struct notifier_block *n) +{ + return notifier_chain_register(&nh->head, n); +} + +EXPORT_SYMBOL_GPL(raw_notifier_chain_register); + +/** + * raw_notifier_chain_unregister - Remove notifier from a raw notifier chain + * @nh: Pointer to head of the raw notifier chain + * @n: Entry to remove from notifier chain + * + * Removes a notifier from a raw notifier chain. + * All locking must be provided by the caller. + * + * Returns zero on success or %-ENOENT on failure. + */ +int raw_notifier_chain_unregister(struct raw_notifier_head *nh, + struct notifier_block *n) +{ + return notifier_chain_unregister(&nh->head, n); +} + +EXPORT_SYMBOL_GPL(raw_notifier_chain_unregister); + +/** + * raw_notifier_call_chain - Call functions in a raw notifier chain + * @nh: Pointer to head of the raw notifier chain + * @val: Value passed unmodified to notifier function + * @v: Pointer passed unmodified to notifier function + * + * Calls each function in a notifier chain in turn. The functions + * run in an undefined context. + * All locking must be provided by the caller. + * + * If the return value of the notifier can be and'ed + * with %NOTIFY_STOP_MASK then raw_notifier_call_chain + * will return immediately, with the return value of + * the notifier function which halted execution. + * Otherwise the return value is the return value + * of the last notifier function called. + */ + +int raw_notifier_call_chain(struct raw_notifier_head *nh, + unsigned long val, void *v) +{ + return notifier_call_chain(&nh->head, val, v); +} + +EXPORT_SYMBOL_GPL(raw_notifier_call_chain); /** * register_reboot_notifier - Register function to be called at reboot time @@ -196,13 +401,13 @@ EXPORT_SYMBOL(notifier_call_chain); * Registers a function with the list of functions * to be called at reboot time. * - * Currently always returns zero, as notifier_chain_register + * Currently always returns zero, as blocking_notifier_chain_register * always returns zero. */ int register_reboot_notifier(struct notifier_block * nb) { - return notifier_chain_register(&reboot_notifier_list, nb); + return blocking_notifier_chain_register(&reboot_notifier_list, nb); } EXPORT_SYMBOL(register_reboot_notifier); @@ -219,7 +424,7 @@ EXPORT_SYMBOL(register_reboot_notifier); int unregister_reboot_notifier(struct notifier_block * nb) { - return notifier_chain_unregister(&reboot_notifier_list, nb); + return blocking_notifier_chain_unregister(&reboot_notifier_list, nb); } EXPORT_SYMBOL(unregister_reboot_notifier); @@ -380,7 +585,7 @@ EXPORT_SYMBOL_GPL(emergency_restart); void kernel_restart_prepare(char *cmd) { - notifier_call_chain(&reboot_notifier_list, SYS_RESTART, cmd); + blocking_notifier_call_chain(&reboot_notifier_list, SYS_RESTART, cmd); system_state = SYSTEM_RESTART; device_shutdown(); } @@ -430,7 +635,7 @@ EXPORT_SYMBOL_GPL(kernel_kexec); void kernel_shutdown_prepare(enum system_states state) { - notifier_call_chain(&reboot_notifier_list, + blocking_notifier_call_chain(&reboot_notifier_list, (state == SYSTEM_HALT)?SYS_HALT:SYS_POWER_OFF, NULL); system_state = state; device_shutdown(); diff --git a/net/bluetooth/hci_core.c b/net/bluetooth/hci_core.c index 9106354c781..a49a6975092 100644 --- a/net/bluetooth/hci_core.c +++ b/net/bluetooth/hci_core.c @@ -73,23 +73,23 @@ DEFINE_RWLOCK(hci_cb_list_lock); struct hci_proto *hci_proto[HCI_MAX_PROTO]; /* HCI notifiers list */ -static struct notifier_block *hci_notifier; +static ATOMIC_NOTIFIER_HEAD(hci_notifier); /* ---- HCI notifications ---- */ int hci_register_notifier(struct notifier_block *nb) { - return notifier_chain_register(&hci_notifier, nb); + return atomic_notifier_chain_register(&hci_notifier, nb); } int hci_unregister_notifier(struct notifier_block *nb) { - return notifier_chain_unregister(&hci_notifier, nb); + return atomic_notifier_chain_unregister(&hci_notifier, nb); } static void hci_notify(struct hci_dev *hdev, int event) { - notifier_call_chain(&hci_notifier, event, hdev); + atomic_notifier_call_chain(&hci_notifier, event, hdev); } /* ---- HCI requests ---- */ diff --git a/net/core/dev.c b/net/core/dev.c index 8e1dc305122..a3ab11f3415 100644 --- a/net/core/dev.c +++ b/net/core/dev.c @@ -193,7 +193,7 @@ static inline struct hlist_head *dev_index_hash(int ifindex) * Our notifier list */ -static struct notifier_block *netdev_chain; +static BLOCKING_NOTIFIER_HEAD(netdev_chain); /* * Device drivers call our routines to queue packets here. We empty the @@ -736,7 +736,8 @@ int dev_change_name(struct net_device *dev, char *newname) if (!err) { hlist_del(&dev->name_hlist); hlist_add_head(&dev->name_hlist, dev_name_hash(dev->name)); - notifier_call_chain(&netdev_chain, NETDEV_CHANGENAME, dev); + blocking_notifier_call_chain(&netdev_chain, + NETDEV_CHANGENAME, dev); } return err; @@ -750,7 +751,7 @@ int dev_change_name(struct net_device *dev, char *newname) */ void netdev_features_change(struct net_device *dev) { - notifier_call_chain(&netdev_chain, NETDEV_FEAT_CHANGE, dev); + blocking_notifier_call_chain(&netdev_chain, NETDEV_FEAT_CHANGE, dev); } EXPORT_SYMBOL(netdev_features_change); @@ -765,7 +766,8 @@ EXPORT_SYMBOL(netdev_features_change); void netdev_state_change(struct net_device *dev) { if (dev->flags & IFF_UP) { - notifier_call_chain(&netdev_chain, NETDEV_CHANGE, dev); + blocking_notifier_call_chain(&netdev_chain, + NETDEV_CHANGE, dev); rtmsg_ifinfo(RTM_NEWLINK, dev, 0); } } @@ -862,7 +864,7 @@ int dev_open(struct net_device *dev) /* * ... and announce new interface. */ - notifier_call_chain(&netdev_chain, NETDEV_UP, dev); + blocking_notifier_call_chain(&netdev_chain, NETDEV_UP, dev); } return ret; } @@ -885,7 +887,7 @@ int dev_close(struct net_device *dev) * Tell people we are going down, so that they can * prepare to death, when device is still operating. */ - notifier_call_chain(&netdev_chain, NETDEV_GOING_DOWN, dev); + blocking_notifier_call_chain(&netdev_chain, NETDEV_GOING_DOWN, dev); dev_deactivate(dev); @@ -922,7 +924,7 @@ int dev_close(struct net_device *dev) /* * Tell people we are down */ - notifier_call_chain(&netdev_chain, NETDEV_DOWN, dev); + blocking_notifier_call_chain(&netdev_chain, NETDEV_DOWN, dev); return 0; } @@ -953,7 +955,7 @@ int register_netdevice_notifier(struct notifier_block *nb) int err; rtnl_lock(); - err = notifier_chain_register(&netdev_chain, nb); + err = blocking_notifier_chain_register(&netdev_chain, nb); if (!err) { for (dev = dev_base; dev; dev = dev->next) { nb->notifier_call(nb, NETDEV_REGISTER, dev); @@ -981,7 +983,7 @@ int unregister_netdevice_notifier(struct notifier_block *nb) int err; rtnl_lock(); - err = notifier_chain_unregister(&netdev_chain, nb); + err = blocking_notifier_chain_unregister(&netdev_chain, nb); rtnl_unlock(); return err; } @@ -992,12 +994,12 @@ int unregister_netdevice_notifier(struct notifier_block *nb) * @v: pointer passed unmodified to notifier function * * Call all network notifier blocks. Parameters and return value - * are as for notifier_call_chain(). + * are as for blocking_notifier_call_chain(). */ int call_netdevice_notifiers(unsigned long val, void *v) { - return notifier_call_chain(&netdev_chain, val, v); + return blocking_notifier_call_chain(&netdev_chain, val, v); } /* When > 0 there are consumers of rx skb time stamps */ @@ -2242,7 +2244,8 @@ int dev_change_flags(struct net_device *dev, unsigned flags) if (dev->flags & IFF_UP && ((old_flags ^ dev->flags) &~ (IFF_UP | IFF_PROMISC | IFF_ALLMULTI | IFF_VOLATILE))) - notifier_call_chain(&netdev_chain, NETDEV_CHANGE, dev); + blocking_notifier_call_chain(&netdev_chain, + NETDEV_CHANGE, dev); if ((flags ^ dev->gflags) & IFF_PROMISC) { int inc = (flags & IFF_PROMISC) ? +1 : -1; @@ -2286,8 +2289,8 @@ int dev_set_mtu(struct net_device *dev, int new_mtu) else dev->mtu = new_mtu; if (!err && dev->flags & IFF_UP) - notifier_call_chain(&netdev_chain, - NETDEV_CHANGEMTU, dev); + blocking_notifier_call_chain(&netdev_chain, + NETDEV_CHANGEMTU, dev); return err; } @@ -2303,7 +2306,8 @@ int dev_set_mac_address(struct net_device *dev, struct sockaddr *sa) return -ENODEV; err = dev->set_mac_address(dev, sa); if (!err) - notifier_call_chain(&netdev_chain, NETDEV_CHANGEADDR, dev); + blocking_notifier_call_chain(&netdev_chain, + NETDEV_CHANGEADDR, dev); return err; } @@ -2359,7 +2363,7 @@ static int dev_ifsioc(struct ifreq *ifr, unsigned int cmd) return -EINVAL; memcpy(dev->broadcast, ifr->ifr_hwaddr.sa_data, min(sizeof ifr->ifr_hwaddr.sa_data, (size_t) dev->addr_len)); - notifier_call_chain(&netdev_chain, + blocking_notifier_call_chain(&netdev_chain, NETDEV_CHANGEADDR, dev); return 0; @@ -2813,7 +2817,7 @@ int register_netdevice(struct net_device *dev) write_unlock_bh(&dev_base_lock); /* Notify protocols, that a new device appeared. */ - notifier_call_chain(&netdev_chain, NETDEV_REGISTER, dev); + blocking_notifier_call_chain(&netdev_chain, NETDEV_REGISTER, dev); /* Finish registration after unlock */ net_set_todo(dev); @@ -2892,7 +2896,7 @@ static void netdev_wait_allrefs(struct net_device *dev) rtnl_lock(); /* Rebroadcast unregister notification */ - notifier_call_chain(&netdev_chain, + blocking_notifier_call_chain(&netdev_chain, NETDEV_UNREGISTER, dev); if (test_bit(__LINK_STATE_LINKWATCH_PENDING, @@ -3148,7 +3152,7 @@ int unregister_netdevice(struct net_device *dev) /* Notify protocols, that we are about to destroy this device. They should clean all the things. */ - notifier_call_chain(&netdev_chain, NETDEV_UNREGISTER, dev); + blocking_notifier_call_chain(&netdev_chain, NETDEV_UNREGISTER, dev); /* * Flush the multicast chain diff --git a/net/decnet/dn_dev.c b/net/decnet/dn_dev.c index cc7b9d9255e..d2ae9893ca1 100644 --- a/net/decnet/dn_dev.c +++ b/net/decnet/dn_dev.c @@ -68,7 +68,7 @@ __le16 decnet_address = 0; static DEFINE_RWLOCK(dndev_lock); static struct net_device *decnet_default_device; -static struct notifier_block *dnaddr_chain; +static BLOCKING_NOTIFIER_HEAD(dnaddr_chain); static struct dn_dev *dn_dev_create(struct net_device *dev, int *err); static void dn_dev_delete(struct net_device *dev); @@ -446,7 +446,7 @@ static void dn_dev_del_ifa(struct dn_dev *dn_db, struct dn_ifaddr **ifap, int de } rtmsg_ifa(RTM_DELADDR, ifa1); - notifier_call_chain(&dnaddr_chain, NETDEV_DOWN, ifa1); + blocking_notifier_call_chain(&dnaddr_chain, NETDEV_DOWN, ifa1); if (destroy) { dn_dev_free_ifa(ifa1); @@ -481,7 +481,7 @@ static int dn_dev_insert_ifa(struct dn_dev *dn_db, struct dn_ifaddr *ifa) dn_db->ifa_list = ifa; rtmsg_ifa(RTM_NEWADDR, ifa); - notifier_call_chain(&dnaddr_chain, NETDEV_UP, ifa); + blocking_notifier_call_chain(&dnaddr_chain, NETDEV_UP, ifa); return 0; } @@ -1285,12 +1285,12 @@ void dn_dev_devices_on(void) int register_dnaddr_notifier(struct notifier_block *nb) { - return notifier_chain_register(&dnaddr_chain, nb); + return blocking_notifier_chain_register(&dnaddr_chain, nb); } int unregister_dnaddr_notifier(struct notifier_block *nb) { - return notifier_chain_unregister(&dnaddr_chain, nb); + return blocking_notifier_chain_unregister(&dnaddr_chain, nb); } #ifdef CONFIG_PROC_FS diff --git a/net/ipv4/devinet.c b/net/ipv4/devinet.c index 44fdf1413e2..81c2f788529 100644 --- a/net/ipv4/devinet.c +++ b/net/ipv4/devinet.c @@ -81,7 +81,7 @@ static struct ipv4_devconf ipv4_devconf_dflt = { static void rtmsg_ifa(int event, struct in_ifaddr *); -static struct notifier_block *inetaddr_chain; +static BLOCKING_NOTIFIER_HEAD(inetaddr_chain); static void inet_del_ifa(struct in_device *in_dev, struct in_ifaddr **ifap, int destroy); #ifdef CONFIG_SYSCTL @@ -267,7 +267,8 @@ static void inet_del_ifa(struct in_device *in_dev, struct in_ifaddr **ifap, *ifap1 = ifa->ifa_next; rtmsg_ifa(RTM_DELADDR, ifa); - notifier_call_chain(&inetaddr_chain, NETDEV_DOWN, ifa); + blocking_notifier_call_chain(&inetaddr_chain, + NETDEV_DOWN, ifa); inet_free_ifa(ifa); } else { promote = ifa; @@ -291,7 +292,7 @@ static void inet_del_ifa(struct in_device *in_dev, struct in_ifaddr **ifap, So that, this order is correct. */ rtmsg_ifa(RTM_DELADDR, ifa1); - notifier_call_chain(&inetaddr_chain, NETDEV_DOWN, ifa1); + blocking_notifier_call_chain(&inetaddr_chain, NETDEV_DOWN, ifa1); if (promote) { @@ -303,7 +304,8 @@ static void inet_del_ifa(struct in_device *in_dev, struct in_ifaddr **ifap, promote->ifa_flags &= ~IFA_F_SECONDARY; rtmsg_ifa(RTM_NEWADDR, promote); - notifier_call_chain(&inetaddr_chain, NETDEV_UP, promote); + blocking_notifier_call_chain(&inetaddr_chain, + NETDEV_UP, promote); for (ifa = promote->ifa_next; ifa; ifa = ifa->ifa_next) { if (ifa1->ifa_mask != ifa->ifa_mask || !inet_ifa_match(ifa1->ifa_address, ifa)) @@ -366,7 +368,7 @@ static int inet_insert_ifa(struct in_ifaddr *ifa) Notifier will trigger FIB update, so that listeners of netlink will know about new ifaddr */ rtmsg_ifa(RTM_NEWADDR, ifa); - notifier_call_chain(&inetaddr_chain, NETDEV_UP, ifa); + blocking_notifier_call_chain(&inetaddr_chain, NETDEV_UP, ifa); return 0; } @@ -938,12 +940,12 @@ u32 inet_confirm_addr(const struct net_device *dev, u32 dst, u32 local, int scop int register_inetaddr_notifier(struct notifier_block *nb) { - return notifier_chain_register(&inetaddr_chain, nb); + return blocking_notifier_chain_register(&inetaddr_chain, nb); } int unregister_inetaddr_notifier(struct notifier_block *nb) { - return notifier_chain_unregister(&inetaddr_chain, nb); + return blocking_notifier_chain_unregister(&inetaddr_chain, nb); } /* Rename ifa_labels for a device name change. Make some effort to preserve existing diff --git a/net/ipv4/netfilter/ip_conntrack_core.c b/net/ipv4/netfilter/ip_conntrack_core.c index 9e34034729a..ceaabc18202 100644 --- a/net/ipv4/netfilter/ip_conntrack_core.c +++ b/net/ipv4/netfilter/ip_conntrack_core.c @@ -80,8 +80,8 @@ static int ip_conntrack_vmalloc; static unsigned int ip_conntrack_next_id; static unsigned int ip_conntrack_expect_next_id; #ifdef CONFIG_IP_NF_CONNTRACK_EVENTS -struct notifier_block *ip_conntrack_chain; -struct notifier_block *ip_conntrack_expect_chain; +ATOMIC_NOTIFIER_HEAD(ip_conntrack_chain); +ATOMIC_NOTIFIER_HEAD(ip_conntrack_expect_chain); DEFINE_PER_CPU(struct ip_conntrack_ecache, ip_conntrack_ecache); @@ -92,7 +92,7 @@ __ip_ct_deliver_cached_events(struct ip_conntrack_ecache *ecache) { DEBUGP("ecache: delivering events for %p\n", ecache->ct); if (is_confirmed(ecache->ct) && !is_dying(ecache->ct) && ecache->events) - notifier_call_chain(&ip_conntrack_chain, ecache->events, + atomic_notifier_call_chain(&ip_conntrack_chain, ecache->events, ecache->ct); ecache->events = 0; ip_conntrack_put(ecache->ct); diff --git a/net/ipv6/addrconf.c b/net/ipv6/addrconf.c index 01c62a0d374..445006ee452 100644 --- a/net/ipv6/addrconf.c +++ b/net/ipv6/addrconf.c @@ -143,7 +143,7 @@ static void inet6_prefix_notify(int event, struct inet6_dev *idev, struct prefix_info *pinfo); static int ipv6_chk_same_addr(const struct in6_addr *addr, struct net_device *dev); -static struct notifier_block *inet6addr_chain; +static ATOMIC_NOTIFIER_HEAD(inet6addr_chain); struct ipv6_devconf ipv6_devconf = { .forwarding = 0, @@ -593,7 +593,7 @@ out2: read_unlock_bh(&addrconf_lock); if (likely(err == 0)) - notifier_call_chain(&inet6addr_chain, NETDEV_UP, ifa); + atomic_notifier_call_chain(&inet6addr_chain, NETDEV_UP, ifa); else { kfree(ifa); ifa = ERR_PTR(err); @@ -688,7 +688,7 @@ static void ipv6_del_addr(struct inet6_ifaddr *ifp) ipv6_ifa_notify(RTM_DELADDR, ifp); - notifier_call_chain(&inet6addr_chain,NETDEV_DOWN,ifp); + atomic_notifier_call_chain(&inet6addr_chain, NETDEV_DOWN, ifp); addrconf_del_timer(ifp); @@ -3767,12 +3767,12 @@ static void addrconf_sysctl_unregister(struct ipv6_devconf *p) int register_inet6addr_notifier(struct notifier_block *nb) { - return notifier_chain_register(&inet6addr_chain, nb); + return atomic_notifier_chain_register(&inet6addr_chain, nb); } int unregister_inet6addr_notifier(struct notifier_block *nb) { - return notifier_chain_unregister(&inet6addr_chain,nb); + return atomic_notifier_chain_unregister(&inet6addr_chain,nb); } /* diff --git a/net/netfilter/nf_conntrack_core.c b/net/netfilter/nf_conntrack_core.c index 0ae281d9bfc..56389c83557 100644 --- a/net/netfilter/nf_conntrack_core.c +++ b/net/netfilter/nf_conntrack_core.c @@ -90,8 +90,8 @@ static int nf_conntrack_vmalloc; static unsigned int nf_conntrack_next_id; static unsigned int nf_conntrack_expect_next_id; #ifdef CONFIG_NF_CONNTRACK_EVENTS -struct notifier_block *nf_conntrack_chain; -struct notifier_block *nf_conntrack_expect_chain; +ATOMIC_NOTIFIER_HEAD(nf_conntrack_chain); +ATOMIC_NOTIFIER_HEAD(nf_conntrack_expect_chain); DEFINE_PER_CPU(struct nf_conntrack_ecache, nf_conntrack_ecache); @@ -103,7 +103,7 @@ __nf_ct_deliver_cached_events(struct nf_conntrack_ecache *ecache) DEBUGP("ecache: delivering events for %p\n", ecache->ct); if (nf_ct_is_confirmed(ecache->ct) && !nf_ct_is_dying(ecache->ct) && ecache->events) - notifier_call_chain(&nf_conntrack_chain, ecache->events, + atomic_notifier_call_chain(&nf_conntrack_chain, ecache->events, ecache->ct); ecache->events = 0; diff --git a/net/netlink/af_netlink.c b/net/netlink/af_netlink.c index d00a9034cb5..2a233ffcf61 100644 --- a/net/netlink/af_netlink.c +++ b/net/netlink/af_netlink.c @@ -123,7 +123,7 @@ static void netlink_destroy_callback(struct netlink_callback *cb); static DEFINE_RWLOCK(nl_table_lock); static atomic_t nl_table_users = ATOMIC_INIT(0); -static struct notifier_block *netlink_chain; +static ATOMIC_NOTIFIER_HEAD(netlink_chain); static u32 netlink_group_mask(u32 group) { @@ -469,7 +469,8 @@ static int netlink_release(struct socket *sock) .protocol = sk->sk_protocol, .pid = nlk->pid, }; - notifier_call_chain(&netlink_chain, NETLINK_URELEASE, &n); + atomic_notifier_call_chain(&netlink_chain, + NETLINK_URELEASE, &n); } if (nlk->module) @@ -1695,12 +1696,12 @@ static struct file_operations netlink_seq_fops = { int netlink_register_notifier(struct notifier_block *nb) { - return notifier_chain_register(&netlink_chain, nb); + return atomic_notifier_chain_register(&netlink_chain, nb); } int netlink_unregister_notifier(struct notifier_block *nb) { - return notifier_chain_unregister(&netlink_chain, nb); + return atomic_notifier_chain_unregister(&netlink_chain, nb); } static const struct proto_ops netlink_ops = { -- cgit v1.2.3-70-g09d2