Donate to e Foundation | Murena handsets with /e/OS | Own a part of Murena! Learn more

Commit 8814c4b5 authored by YOSHIFUJI Hideaki's avatar YOSHIFUJI Hideaki Committed by David S. Miller
Browse files

[IPV6] ADDRCONF: Convert addrconf_lock to RCU.

parent fbea49e1
Loading
Loading
Loading
Loading
+4 −6
Original line number Diff line number Diff line
@@ -133,20 +133,18 @@ extern int unregister_inet6addr_notifier(struct notifier_block *nb);
static inline struct inet6_dev *
__in6_dev_get(struct net_device *dev)
{
	return (struct inet6_dev *)dev->ip6_ptr;
	return rcu_dereference(dev->ip6_ptr);
}

extern rwlock_t addrconf_lock;

static inline struct inet6_dev *
in6_dev_get(struct net_device *dev)
{
	struct inet6_dev *idev = NULL;
	read_lock(&addrconf_lock);
	idev = dev->ip6_ptr;
	rcu_read_lock();
	idev = __in6_dev_get(dev);
	if (idev)
		atomic_inc(&idev->refcnt);
	read_unlock(&addrconf_lock);
	rcu_read_unlock();
	return idev;
}

+1 −0
Original line number Diff line number Diff line
@@ -189,6 +189,7 @@ struct inet6_dev
	struct ipv6_devconf	cnf;
	struct ipv6_devstat	stats;
	unsigned long		tstamp; /* ipv6InterfaceTable update timestamp */
	struct rcu_head		rcu;
};

extern struct ipv6_devconf ipv6_devconf;
+2 −2
Original line number Diff line number Diff line
@@ -1786,7 +1786,7 @@ static void pktgen_setup_inject(struct pktgen_dev *pkt_dev)
			 * use ipv6_get_lladdr if/when it's get exported
			 */

			read_lock(&addrconf_lock);
			rcu_read_lock();
			if ((idev = __in6_dev_get(pkt_dev->odev)) != NULL) {
				struct inet6_ifaddr *ifp;

@@ -1805,7 +1805,7 @@ static void pktgen_setup_inject(struct pktgen_dev *pkt_dev)
				}
				read_unlock_bh(&idev->lock);
			}
			read_unlock(&addrconf_lock);
			rcu_read_unlock();
			if (err)
				printk("pktgen: ERROR: IPv6 link address not availble.\n");
		}
+24 −22
Original line number Diff line number Diff line
@@ -119,9 +119,6 @@ static int ipv6_count_addresses(struct inet6_dev *idev);
static struct inet6_ifaddr		*inet6_addr_lst[IN6_ADDR_HSIZE];
static DEFINE_RWLOCK(addrconf_hash_lock);

/* Protects inet6 devices */
DEFINE_RWLOCK(addrconf_lock);

static void addrconf_verify(unsigned long);

static DEFINE_TIMER(addr_chk_timer, addrconf_verify, 0, 0);
@@ -318,6 +315,12 @@ static void addrconf_mod_timer(struct inet6_ifaddr *ifp,

/* Nobody refers to this device, we may destroy it. */

static void in6_dev_finish_destroy_rcu(struct rcu_head *head)
{
	struct inet6_dev *idev = container_of(head, struct inet6_dev, rcu);
	kfree(idev);
}

void in6_dev_finish_destroy(struct inet6_dev *idev)
{
	struct net_device *dev = idev->dev;
@@ -332,7 +335,7 @@ void in6_dev_finish_destroy(struct inet6_dev *idev)
		return;
	}
	snmp6_free_dev(idev);
	kfree(idev);
	call_rcu(&idev->rcu, in6_dev_finish_destroy_rcu);
}

static struct inet6_dev * ipv6_add_dev(struct net_device *dev)
@@ -408,9 +411,8 @@ static struct inet6_dev * ipv6_add_dev(struct net_device *dev)
	if (netif_carrier_ok(dev))
		ndev->if_flags |= IF_READY;

	write_lock_bh(&addrconf_lock);
	dev->ip6_ptr = ndev;
	write_unlock_bh(&addrconf_lock);
	/* protected by rtnl_lock */
	rcu_assign_pointer(dev->ip6_ptr, ndev);

	ipv6_mc_init_dev(ndev);
	ndev->tstamp = jiffies;
@@ -474,7 +476,7 @@ static void addrconf_forward_change(void)

	read_lock(&dev_base_lock);
	for (dev=dev_base; dev; dev=dev->next) {
		read_lock(&addrconf_lock);
		rcu_read_lock();
		idev = __in6_dev_get(dev);
		if (idev) {
			int changed = (!idev->cnf.forwarding) ^ (!ipv6_devconf.forwarding);
@@ -482,7 +484,7 @@ static void addrconf_forward_change(void)
			if (changed)
				dev_forward_change(idev);
		}
		read_unlock(&addrconf_lock);
		rcu_read_unlock();
	}
	read_unlock(&dev_base_lock);
}
@@ -543,7 +545,7 @@ ipv6_add_addr(struct inet6_dev *idev, const struct in6_addr *addr, int pfxlen,
	int hash;
	int err = 0;

	read_lock_bh(&addrconf_lock);
	rcu_read_lock_bh();
	if (idev->dead) {
		err = -ENODEV;			/*XXX*/
		goto out2;
@@ -612,7 +614,7 @@ ipv6_add_addr(struct inet6_dev *idev, const struct in6_addr *addr, int pfxlen,
	in6_ifa_hold(ifa);
	write_unlock(&idev->lock);
out2:
	read_unlock_bh(&addrconf_lock);
	rcu_read_unlock_bh();

	if (likely(err == 0))
		atomic_notifier_call_chain(&inet6addr_chain, NETDEV_UP, ifa);
@@ -915,7 +917,7 @@ int ipv6_dev_get_saddr(struct net_device *daddr_dev,
	memset(&hiscore, 0, sizeof(hiscore));

	read_lock(&dev_base_lock);
	read_lock(&addrconf_lock);
	rcu_read_lock();

	for (dev = dev_base; dev; dev=dev->next) {
		struct inet6_dev *idev;
@@ -1127,7 +1129,7 @@ int ipv6_dev_get_saddr(struct net_device *daddr_dev,
		}
		read_unlock_bh(&idev->lock);
	}
	read_unlock(&addrconf_lock);
	rcu_read_unlock();
	read_unlock(&dev_base_lock);

	if (!ifa_result)
@@ -1151,7 +1153,7 @@ int ipv6_get_lladdr(struct net_device *dev, struct in6_addr *addr)
	struct inet6_dev *idev;
	int err = -EADDRNOTAVAIL;

	read_lock(&addrconf_lock);
	rcu_read_lock();
	if ((idev = __in6_dev_get(dev)) != NULL) {
		struct inet6_ifaddr *ifp;

@@ -1165,7 +1167,7 @@ int ipv6_get_lladdr(struct net_device *dev, struct in6_addr *addr)
		}
		read_unlock_bh(&idev->lock);
	}
	read_unlock(&addrconf_lock);
	rcu_read_unlock();
	return err;
}

@@ -1466,7 +1468,7 @@ static void ipv6_regen_rndid(unsigned long data)
	struct inet6_dev *idev = (struct inet6_dev *) data;
	unsigned long expires;

	read_lock_bh(&addrconf_lock);
	rcu_read_lock_bh();
	write_lock_bh(&idev->lock);

	if (idev->dead)
@@ -1490,7 +1492,7 @@ static void ipv6_regen_rndid(unsigned long data)

out:
	write_unlock_bh(&idev->lock);
	read_unlock_bh(&addrconf_lock);
	rcu_read_unlock_bh();
	in6_dev_put(idev);
}

@@ -2342,10 +2344,10 @@ static int addrconf_ifdown(struct net_device *dev, int how)
	           Do not dev_put!
	 */
	if (how == 1) {
		write_lock_bh(&addrconf_lock);
		dev->ip6_ptr = NULL;
		idev->dead = 1;
		write_unlock_bh(&addrconf_lock);

		/* protected by rtnl_lock */
		rcu_assign_pointer(dev->ip6_ptr, NULL);

		/* Step 1.5: remove snmp6 entry */
		snmp6_unregister_dev(idev);
@@ -3573,10 +3575,10 @@ static void __ipv6_ifa_notify(int event, struct inet6_ifaddr *ifp)

static void ipv6_ifa_notify(int event, struct inet6_ifaddr *ifp)
{
	read_lock_bh(&addrconf_lock);
	rcu_read_lock_bh();
	if (likely(ifp->idev->dead == 0))
		__ipv6_ifa_notify(event, ifp);
	read_unlock_bh(&addrconf_lock);
	rcu_read_unlock_bh();
}

#ifdef CONFIG_SYSCTL
+2 −2
Original line number Diff line number Diff line
@@ -56,7 +56,7 @@ ip6_onlink(struct in6_addr *addr, struct net_device *dev)
	int	onlink;

	onlink = 0;
	read_lock(&addrconf_lock);
	rcu_read_lock();
	idev = __in6_dev_get(dev);
	if (idev) {
		read_lock_bh(&idev->lock);
@@ -68,7 +68,7 @@ ip6_onlink(struct in6_addr *addr, struct net_device *dev)
		}
		read_unlock_bh(&idev->lock);
	}
	read_unlock(&addrconf_lock);
	rcu_read_unlock();
	return onlink;
}

Loading