From 68f2d02669f7102be80aae47155f45e18950d223 Mon Sep 17 00:00:00 2001
From: Jouni Malinen <jouni.malinen@atheros.com>
Date: Thu, 11 Jun 2009 18:19:45 +0300
Subject: mac80211: Do not try to associate with an empty SSID

It looks like some programs (e.g., NM) are setting an empty SSID with
SIOCSIWESSID in some cases. This seems to trigger mac80211 to try to
associate with an invalid configuration (wildcard SSID) which will
result in failing associations (or odd issues, potentially including
kernel panic with some drivers) if the AP were to actually accept this
anyway).

Only start association process if the SSID is actually set. This
speeds up connection with NM in number of cases and avoids sending out
broken association request frames.

Signed-off-by: Jouni Malinen <jouni.malinen@atheros.com>
Signed-off-by: John W. Linville <linville@tuxdriver.com>
---
 net/mac80211/mlme.c | 8 ++++++++
 1 file changed, 8 insertions(+)

(limited to 'net')

diff --git a/net/mac80211/mlme.c b/net/mac80211/mlme.c
index d779c57a8220..e5de9cea0034 100644
--- a/net/mac80211/mlme.c
+++ b/net/mac80211/mlme.c
@@ -2445,6 +2445,14 @@ void ieee80211_sta_req_auth(struct ieee80211_sub_if_data *sdata)
 			ieee80211_set_disassoc(sdata, true, true,
 					       WLAN_REASON_DEAUTH_LEAVING);
 
+		if (ifmgd->ssid_len == 0) {
+			/*
+			 * Only allow association to be started if a valid SSID
+			 * is configured.
+			 */
+			return;
+		}
+
 		if (!(ifmgd->flags & IEEE80211_STA_EXT_SME) ||
 		    ifmgd->state != IEEE80211_STA_MLME_ASSOCIATE)
 			set_bit(IEEE80211_STA_REQ_AUTH, &ifmgd->request);
-- 
cgit v1.2.2


From db2e6bd4e966a36c6b2f1921feb3537e8254415c Mon Sep 17 00:00:00 2001
From: Johannes Berg <johannes@sipsolutions.net>
Date: Sun, 14 Jun 2009 17:37:39 +0200
Subject: mac80211: add queue debugfs file

I suspect that some driver bugs can cause queues to be
stopped while they shouldn't be, but it's hard to find
out whether that is the case or not without having any
visible information about the queues. This adds a file
to debugfs that allows us to see the queues' statuses.

Signed-off-by: Johannes Berg <johannes@sipsolutions.net>
Signed-off-by: John W. Linville <linville@tuxdriver.com>
---
 net/mac80211/debugfs.c     | 25 +++++++++++++++++++++++++
 net/mac80211/ieee80211_i.h |  1 +
 2 files changed, 26 insertions(+)

(limited to 'net')

diff --git a/net/mac80211/debugfs.c b/net/mac80211/debugfs.c
index 11c72311f35b..6c439cd5ccea 100644
--- a/net/mac80211/debugfs.c
+++ b/net/mac80211/debugfs.c
@@ -163,6 +163,29 @@ static const struct file_operations noack_ops = {
 	.open = mac80211_open_file_generic
 };
 
+static ssize_t queues_read(struct file *file, char __user *user_buf,
+			   size_t count, loff_t *ppos)
+{
+	struct ieee80211_local *local = file->private_data;
+	unsigned long flags;
+	char buf[IEEE80211_MAX_QUEUES * 20];
+	int q, res = 0;
+
+	spin_lock_irqsave(&local->queue_stop_reason_lock, flags);
+	for (q = 0; q < local->hw.queues; q++)
+		res += sprintf(buf + res, "%02d: %#.8lx/%d\n", q,
+				local->queue_stop_reasons[q],
+				__netif_subqueue_stopped(local->mdev, q));
+	spin_unlock_irqrestore(&local->queue_stop_reason_lock, flags);
+
+	return simple_read_from_buffer(user_buf, count, ppos, buf, res);
+}
+
+static const struct file_operations queues_ops = {
+	.read = queues_read,
+	.open = mac80211_open_file_generic
+};
+
 /* statistics stuff */
 
 #define DEBUGFS_STATS_FILE(name, buflen, fmt, value...)			\
@@ -298,6 +321,7 @@ void debugfs_hw_add(struct ieee80211_local *local)
 	DEBUGFS_ADD(total_ps_buffered);
 	DEBUGFS_ADD(wep_iv);
 	DEBUGFS_ADD(tsf);
+	DEBUGFS_ADD(queues);
 	DEBUGFS_ADD_MODE(reset, 0200);
 	DEBUGFS_ADD(noack);
 
@@ -350,6 +374,7 @@ void debugfs_hw_del(struct ieee80211_local *local)
 	DEBUGFS_DEL(total_ps_buffered);
 	DEBUGFS_DEL(wep_iv);
 	DEBUGFS_DEL(tsf);
+	DEBUGFS_DEL(queues);
 	DEBUGFS_DEL(reset);
 	DEBUGFS_DEL(noack);
 
diff --git a/net/mac80211/ieee80211_i.h b/net/mac80211/ieee80211_i.h
index 4dbc28964196..f41fe1f1430c 100644
--- a/net/mac80211/ieee80211_i.h
+++ b/net/mac80211/ieee80211_i.h
@@ -783,6 +783,7 @@ struct ieee80211_local {
 		struct dentry *total_ps_buffered;
 		struct dentry *wep_iv;
 		struct dentry *tsf;
+		struct dentry *queues;
 		struct dentry *reset;
 		struct dentry *noack;
 		struct dentry *statistics;
-- 
cgit v1.2.2


From 7e9debe9789456426ec8574ead879e33da19ee57 Mon Sep 17 00:00:00 2001
From: Johannes Berg <johannes@sipsolutions.net>
Date: Mon, 15 Jun 2009 13:42:25 +0200
Subject: mac80211: disconnect when user changes channel

If we do not disconnect when a channel switch is requested,
we end up eventually detection beacon loss from the AP and
then disconnecting, without ever really telling the AP, so
we might just as well disconnect right away.

Additionally, this fixes a problem with iwlwifi where the
driver will clear some internal state on channel changes
like this and then get confused when we actually go clear
that state from mac80211.

It may look like this patch drops the no-IBSS check, but
that is already handled by cfg80211 in the wext handler it
provides for IBSS (cfg80211_ibss_wext_siwfreq).

Signed-off-by: Johannes Berg <johannes@sipsolutions.net>
Signed-off-by: John W. Linville <linville@tuxdriver.com>
---
 net/mac80211/ieee80211_i.h |  1 -
 net/mac80211/mlme.c        |  5 ++++-
 net/mac80211/util.c        | 25 -------------------------
 net/mac80211/wext.c        | 31 +++++++++++++++++++++++++++----
 4 files changed, 31 insertions(+), 31 deletions(-)

(limited to 'net')

diff --git a/net/mac80211/ieee80211_i.h b/net/mac80211/ieee80211_i.h
index f41fe1f1430c..68eb5052179a 100644
--- a/net/mac80211/ieee80211_i.h
+++ b/net/mac80211/ieee80211_i.h
@@ -1101,7 +1101,6 @@ void ieee802_11_parse_elems(u8 *start, size_t len,
 u32 ieee802_11_parse_elems_crc(u8 *start, size_t len,
 			       struct ieee802_11_elems *elems,
 			       u64 filter, u32 crc);
-int ieee80211_set_freq(struct ieee80211_sub_if_data *sdata, int freq);
 u32 ieee80211_mandatory_rates(struct ieee80211_local *local,
 			      enum ieee80211_band band);
 
diff --git a/net/mac80211/mlme.c b/net/mac80211/mlme.c
index e5de9cea0034..84e59b9b493a 100644
--- a/net/mac80211/mlme.c
+++ b/net/mac80211/mlme.c
@@ -2223,7 +2223,10 @@ static int ieee80211_sta_config_auth(struct ieee80211_sub_if_data *sdata)
 				       capa_mask, capa_val);
 
 	if (bss) {
-		ieee80211_set_freq(sdata, bss->cbss.channel->center_freq);
+		local->oper_channel = bss->cbss.channel;
+		local->oper_channel_type = NL80211_CHAN_NO_HT;
+		ieee80211_hw_config(local, 0);
+
 		if (!(ifmgd->flags & IEEE80211_STA_SSID_SET))
 			ieee80211_sta_set_ssid(sdata, bss->ssid,
 					       bss->ssid_len);
diff --git a/net/mac80211/util.c b/net/mac80211/util.c
index 66ce96a69f31..915e77769312 100644
--- a/net/mac80211/util.c
+++ b/net/mac80211/util.c
@@ -774,31 +774,6 @@ void ieee80211_tx_skb(struct ieee80211_sub_if_data *sdata, struct sk_buff *skb,
 	dev_queue_xmit(skb);
 }
 
-int ieee80211_set_freq(struct ieee80211_sub_if_data *sdata, int freqMHz)
-{
-	int ret = -EINVAL;
-	struct ieee80211_channel *chan;
-	struct ieee80211_local *local = sdata->local;
-
-	chan = ieee80211_get_channel(local->hw.wiphy, freqMHz);
-
-	if (chan && !(chan->flags & IEEE80211_CHAN_DISABLED)) {
-		if (sdata->vif.type == NL80211_IFTYPE_ADHOC &&
-		    chan->flags & IEEE80211_CHAN_NO_IBSS)
-			return ret;
-		local->oper_channel = chan;
-		local->oper_channel_type = NL80211_CHAN_NO_HT;
-
-		if (local->sw_scanning || local->hw_scanning)
-			ret = 0;
-		else
-			ret = ieee80211_hw_config(
-				local, IEEE80211_CONF_CHANGE_CHANNEL);
-	}
-
-	return ret;
-}
-
 u32 ieee80211_mandatory_rates(struct ieee80211_local *local,
 			      enum ieee80211_band band)
 {
diff --git a/net/mac80211/wext.c b/net/mac80211/wext.c
index d2d81b103341..1da81f456744 100644
--- a/net/mac80211/wext.c
+++ b/net/mac80211/wext.c
@@ -55,6 +55,8 @@ static int ieee80211_ioctl_siwfreq(struct net_device *dev,
 				   struct iw_freq *freq, char *extra)
 {
 	struct ieee80211_sub_if_data *sdata = IEEE80211_DEV_TO_SUB_IF(dev);
+	struct ieee80211_local *local = sdata->local;
+	struct ieee80211_channel *chan;
 
 	if (sdata->vif.type == NL80211_IFTYPE_ADHOC)
 		return cfg80211_ibss_wext_siwfreq(dev, info, freq, extra);
@@ -69,17 +71,38 @@ static int ieee80211_ioctl_siwfreq(struct net_device *dev,
 					IEEE80211_STA_AUTO_CHANNEL_SEL;
 			return 0;
 		} else
-			return ieee80211_set_freq(sdata,
+			chan = ieee80211_get_channel(local->hw.wiphy,
 				ieee80211_channel_to_frequency(freq->m));
 	} else {
 		int i, div = 1000000;
 		for (i = 0; i < freq->e; i++)
 			div /= 10;
-		if (div > 0)
-			return ieee80211_set_freq(sdata, freq->m / div);
-		else
+		if (div <= 0)
 			return -EINVAL;
+		chan = ieee80211_get_channel(local->hw.wiphy, freq->m / div);
 	}
+
+	if (!chan)
+		return -EINVAL;
+
+	if (chan->flags & IEEE80211_CHAN_DISABLED)
+		return -EINVAL;
+
+	/*
+	 * no change except maybe auto -> fixed, ignore the HT
+	 * setting so you can fix a channel you're on already
+	 */
+	if (local->oper_channel == chan)
+		return 0;
+
+	if (sdata->vif.type == NL80211_IFTYPE_STATION)
+		ieee80211_sta_req_auth(sdata);
+
+	local->oper_channel = chan;
+	local->oper_channel_type = NL80211_CHAN_NO_HT;
+	ieee80211_hw_config(local, 0);
+
+	return 0;
 }
 
 
-- 
cgit v1.2.2


From 1fa6f4af9f55bc1b753af04276984429d6b5a613 Mon Sep 17 00:00:00 2001
From: Johannes Berg <johannes@sipsolutions.net>
Date: Mon, 15 Jun 2009 18:13:58 +0200
Subject: mac80211: fix wext bssid/ssid setting

When changing to a new BSSID or SSID, the code in
ieee80211_set_disassoc() needs to have the old data
still valid to be able to disconnect and clean up
properly. Currently, however, the old data is thrown
away before ieee80211_set_disassoc() is ever called,
so fix that by calling the function _before_ the old
data is overwritten.

This is (one of) the issue(s) causing mac80211 to hold
cfg80211's BSS structs forever, and them thus being
returned in scan results after they're long gone.

http://www.intellinuxwireless.org/bugzilla/show_bug.cgi?id=2015

Signed-off-by: Johannes Berg <johannes@sipsolutions.net>
Signed-off-by: John W. Linville <linville@tuxdriver.com>
---
 net/mac80211/mlme.c | 25 ++++++++++++++-----------
 1 file changed, 14 insertions(+), 11 deletions(-)

(limited to 'net')

diff --git a/net/mac80211/mlme.c b/net/mac80211/mlme.c
index 84e59b9b493a..aca22b00b6a3 100644
--- a/net/mac80211/mlme.c
+++ b/net/mac80211/mlme.c
@@ -1102,14 +1102,6 @@ static void ieee80211_set_disassoc(struct ieee80211_sub_if_data *sdata,
 	struct sta_info *sta;
 	u32 changed = 0, config_changed = 0;
 
-	rcu_read_lock();
-
-	sta = sta_info_get(local, ifmgd->bssid);
-	if (!sta) {
-		rcu_read_unlock();
-		return;
-	}
-
 	if (deauth) {
 		ifmgd->direct_probe_tries = 0;
 		ifmgd->auth_tries = 0;
@@ -1120,7 +1112,11 @@ static void ieee80211_set_disassoc(struct ieee80211_sub_if_data *sdata,
 	netif_tx_stop_all_queues(sdata->dev);
 	netif_carrier_off(sdata->dev);
 
-	ieee80211_sta_tear_down_BA_sessions(sta);
+	rcu_read_lock();
+	sta = sta_info_get(local, ifmgd->bssid);
+	if (sta)
+		ieee80211_sta_tear_down_BA_sessions(sta);
+	rcu_read_unlock();
 
 	bss = ieee80211_rx_bss_get(local, ifmgd->bssid,
 				   conf->channel->center_freq,
@@ -1156,8 +1152,6 @@ static void ieee80211_set_disassoc(struct ieee80211_sub_if_data *sdata,
 				ifmgd->ssid, ifmgd->ssid_len);
 	}
 
-	rcu_read_unlock();
-
 	ieee80211_set_wmm_default(sdata);
 
 	ieee80211_recalc_idle(local);
@@ -2487,6 +2481,10 @@ int ieee80211_sta_set_ssid(struct ieee80211_sub_if_data *sdata, char *ssid, size
 	ifmgd = &sdata->u.mgd;
 
 	if (ifmgd->ssid_len != len || memcmp(ifmgd->ssid, ssid, len) != 0) {
+		if (ifmgd->state == IEEE80211_STA_MLME_ASSOCIATED)
+			ieee80211_set_disassoc(sdata, true, true,
+					       WLAN_REASON_DEAUTH_LEAVING);
+
 		/*
 		 * Do not use reassociation if SSID is changed (different ESS).
 		 */
@@ -2511,6 +2509,11 @@ int ieee80211_sta_set_bssid(struct ieee80211_sub_if_data *sdata, u8 *bssid)
 {
 	struct ieee80211_if_managed *ifmgd = &sdata->u.mgd;
 
+	if (compare_ether_addr(bssid, ifmgd->bssid) != 0 &&
+	    ifmgd->state == IEEE80211_STA_MLME_ASSOCIATED)
+		ieee80211_set_disassoc(sdata, true, true,
+				       WLAN_REASON_DEAUTH_LEAVING);
+
 	if (is_valid_ether_addr(bssid)) {
 		memcpy(ifmgd->bssid, bssid, ETH_ALEN);
 		ifmgd->flags |= IEEE80211_STA_BSSID_SET;
-- 
cgit v1.2.2


From 14ebaf81e13ce66bff275380b246796fd16cbfa1 Mon Sep 17 00:00:00 2001
From: "David S. Miller" <davem@davemloft.net>
Date: Tue, 16 Jun 2009 05:40:30 -0700
Subject: x25: Fix sleep from timer on socket destroy.

If socket destuction gets delayed to a timer, we try to
lock_sock() from that timer which won't work.

Use bh_lock_sock() in that case.

Signed-off-by: David S. Miller <davem@davemloft.net>
Tested-by: Ingo Molnar <mingo@elte.hu>
---
 net/x25/af_x25.c    | 23 ++++++++++++++++++-----
 net/x25/x25_timer.c |  2 +-
 2 files changed, 19 insertions(+), 6 deletions(-)

(limited to 'net')

diff --git a/net/x25/af_x25.c b/net/x25/af_x25.c
index ed80af8ca5fb..c51f3095739c 100644
--- a/net/x25/af_x25.c
+++ b/net/x25/af_x25.c
@@ -332,14 +332,14 @@ static unsigned int x25_new_lci(struct x25_neigh *nb)
 /*
  *	Deferred destroy.
  */
-void x25_destroy_socket(struct sock *);
+static void __x25_destroy_socket(struct sock *);
 
 /*
  *	handler for deferred kills.
  */
 static void x25_destroy_timer(unsigned long data)
 {
-	x25_destroy_socket((struct sock *)data);
+	x25_destroy_socket_from_timer((struct sock *)data);
 }
 
 /*
@@ -349,12 +349,10 @@ static void x25_destroy_timer(unsigned long data)
  *	will touch it and we are (fairly 8-) ) safe.
  *	Not static as it's used by the timer
  */
-void x25_destroy_socket(struct sock *sk)
+static void __x25_destroy_socket(struct sock *sk)
 {
 	struct sk_buff *skb;
 
-	sock_hold(sk);
-	lock_sock(sk);
 	x25_stop_heartbeat(sk);
 	x25_stop_timer(sk);
 
@@ -385,7 +383,22 @@ void x25_destroy_socket(struct sock *sk)
 		/* drop last reference so sock_put will free */
 		__sock_put(sk);
 	}
+}
 
+void x25_destroy_socket_from_timer(struct sock *sk)
+{
+	sock_hold(sk);
+	bh_lock_sock(sk);
+	__x25_destroy_socket(sk);
+	bh_unlock_sock(sk);
+	sock_put(sk);
+}
+
+static void x25_destroy_socket(struct sock *sk)
+{
+	sock_hold(sk);
+	lock_sock(sk);
+	__x25_destroy_socket(sk);
 	release_sock(sk);
 	sock_put(sk);
 }
diff --git a/net/x25/x25_timer.c b/net/x25/x25_timer.c
index d3e3e54db936..5c5db1a36399 100644
--- a/net/x25/x25_timer.c
+++ b/net/x25/x25_timer.c
@@ -113,7 +113,7 @@ static void x25_heartbeat_expiry(unsigned long param)
 			    (sk->sk_state == TCP_LISTEN &&
 			     sock_flag(sk, SOCK_DEAD))) {
 				bh_unlock_sock(sk);
-				x25_destroy_socket(sk);
+				x25_destroy_socket_from_timer(sk);
 				return;
 			}
 			break;
-- 
cgit v1.2.2


From c564039fd83ea16a86a96d52632794b24849e507 Mon Sep 17 00:00:00 2001
From: Eric Dumazet <eric.dumazet@gmail.com>
Date: Tue, 16 Jun 2009 10:12:03 +0000
Subject: net: sk_wmem_alloc has initial value of one, not zero

commit 2b85a34e911bf483c27cfdd124aeb1605145dc80
(net: No more expensive sock_hold()/sock_put() on each tx)
changed initial sk_wmem_alloc value.

Some protocols check sk_wmem_alloc value to determine if a timer
must delay socket deallocation. We must take care of the sk_wmem_alloc
value being one instead of zero when no write allocations are pending.

Reported by Ingo Molnar, and full diagnostic from David Miller.

This patch introduces three helpers to get read/write allocations
and a followup patch will use these helpers to report correct
write allocations to user.

Reported-by: Ingo Molnar <mingo@elte.hu>
Signed-off-by: Eric Dumazet <eric.dumazet@gmail.com>
Signed-off-by: David S. Miller <davem@davemloft.net>
---
 net/appletalk/ddp.c    | 6 ++----
 net/ax25/af_ax25.c     | 3 +--
 net/econet/af_econet.c | 6 ++----
 net/netrom/af_netrom.c | 3 +--
 net/rose/af_rose.c     | 3 +--
 net/x25/af_x25.c       | 3 +--
 6 files changed, 8 insertions(+), 16 deletions(-)

(limited to 'net')

diff --git a/net/appletalk/ddp.c b/net/appletalk/ddp.c
index b603cbacdc58..f7a53b219ef0 100644
--- a/net/appletalk/ddp.c
+++ b/net/appletalk/ddp.c
@@ -162,8 +162,7 @@ static void atalk_destroy_timer(unsigned long data)
 {
 	struct sock *sk = (struct sock *)data;
 
-	if (atomic_read(&sk->sk_wmem_alloc) ||
-	    atomic_read(&sk->sk_rmem_alloc)) {
+	if (sk_has_allocations(sk)) {
 		sk->sk_timer.expires = jiffies + SOCK_DESTROY_TIME;
 		add_timer(&sk->sk_timer);
 	} else
@@ -175,8 +174,7 @@ static inline void atalk_destroy_socket(struct sock *sk)
 	atalk_remove_socket(sk);
 	skb_queue_purge(&sk->sk_receive_queue);
 
-	if (atomic_read(&sk->sk_wmem_alloc) ||
-	    atomic_read(&sk->sk_rmem_alloc)) {
+	if (sk_has_allocations(sk)) {
 		setup_timer(&sk->sk_timer, atalk_destroy_timer,
 				(unsigned long)sk);
 		sk->sk_timer.expires	= jiffies + SOCK_DESTROY_TIME;
diff --git a/net/ax25/af_ax25.c b/net/ax25/af_ax25.c
index fd9d06f291dc..61b35b955490 100644
--- a/net/ax25/af_ax25.c
+++ b/net/ax25/af_ax25.c
@@ -330,8 +330,7 @@ void ax25_destroy_socket(ax25_cb *ax25)
 	}
 
 	if (ax25->sk != NULL) {
-		if (atomic_read(&ax25->sk->sk_wmem_alloc) ||
-		    atomic_read(&ax25->sk->sk_rmem_alloc)) {
+		if (sk_has_allocations(ax25->sk)) {
 			/* Defer: outstanding buffers */
 			setup_timer(&ax25->dtimer, ax25_destroy_timer,
 					(unsigned long)ax25);
diff --git a/net/econet/af_econet.c b/net/econet/af_econet.c
index 8121bf0029e3..2e1f836d4240 100644
--- a/net/econet/af_econet.c
+++ b/net/econet/af_econet.c
@@ -540,8 +540,7 @@ static void econet_destroy_timer(unsigned long data)
 {
 	struct sock *sk=(struct sock *)data;
 
-	if (!atomic_read(&sk->sk_wmem_alloc) &&
-	    !atomic_read(&sk->sk_rmem_alloc)) {
+	if (!sk_has_allocations(sk)) {
 		sk_free(sk);
 		return;
 	}
@@ -579,8 +578,7 @@ static int econet_release(struct socket *sock)
 
 	skb_queue_purge(&sk->sk_receive_queue);
 
-	if (atomic_read(&sk->sk_rmem_alloc) ||
-	    atomic_read(&sk->sk_wmem_alloc)) {
+	if (sk_has_allocations(sk)) {
 		sk->sk_timer.data     = (unsigned long)sk;
 		sk->sk_timer.expires  = jiffies + HZ;
 		sk->sk_timer.function = econet_destroy_timer;
diff --git a/net/netrom/af_netrom.c b/net/netrom/af_netrom.c
index 3be0e016ab7d..cd911904cbe1 100644
--- a/net/netrom/af_netrom.c
+++ b/net/netrom/af_netrom.c
@@ -286,8 +286,7 @@ void nr_destroy_socket(struct sock *sk)
 		kfree_skb(skb);
 	}
 
-	if (atomic_read(&sk->sk_wmem_alloc) ||
-	    atomic_read(&sk->sk_rmem_alloc)) {
+	if (sk_has_allocations(sk)) {
 		/* Defer: outstanding buffers */
 		sk->sk_timer.function = nr_destroy_timer;
 		sk->sk_timer.expires  = jiffies + 2 * HZ;
diff --git a/net/rose/af_rose.c b/net/rose/af_rose.c
index 877a7f65f707..4dd9a7d18945 100644
--- a/net/rose/af_rose.c
+++ b/net/rose/af_rose.c
@@ -356,8 +356,7 @@ void rose_destroy_socket(struct sock *sk)
 		kfree_skb(skb);
 	}
 
-	if (atomic_read(&sk->sk_wmem_alloc) ||
-	    atomic_read(&sk->sk_rmem_alloc)) {
+	if (sk_has_allocations(sk)) {
 		/* Defer: outstanding buffers */
 		setup_timer(&sk->sk_timer, rose_destroy_timer,
 				(unsigned long)sk);
diff --git a/net/x25/af_x25.c b/net/x25/af_x25.c
index c51f3095739c..8cd2390b0d45 100644
--- a/net/x25/af_x25.c
+++ b/net/x25/af_x25.c
@@ -372,8 +372,7 @@ static void __x25_destroy_socket(struct sock *sk)
 		kfree_skb(skb);
 	}
 
-	if (atomic_read(&sk->sk_wmem_alloc) ||
-	    atomic_read(&sk->sk_rmem_alloc)) {
+	if (sk_has_allocations(sk)) {
 		/* Defer: outstanding buffers */
 		sk->sk_timer.expires  = jiffies + 10 * HZ;
 		sk->sk_timer.function = x25_destroy_timer;
-- 
cgit v1.2.2


From 19633e129c65e5bb62b1af545c5479afcdb01fc4 Mon Sep 17 00:00:00 2001
From: Stephen Hemminger <shemminger@vyatta.com>
Date: Wed, 17 Jun 2009 05:23:27 +0000
Subject: skbuff: skb_mac_header_was_set is always true on >32 bit

Looking at the crash in log_martians(), one suspect is that the check for
mac header being set is not correct.  The value of mac_header defaults to
0 on allocation, therefore skb_mac_header_was_set will always be true on
platforms using NET_SKBUFF_USES_OFFSET.

Signed-off-by: Stephen Hemminger <shemminger@vyatta.com>
Acked-by: Arnaldo Carvalho de Melo <acme@redhat.com>
Signed-off-by: David S. Miller <davem@davemloft.net>
---
 net/core/skbuff.c | 4 ++++
 1 file changed, 4 insertions(+)

(limited to 'net')

diff --git a/net/core/skbuff.c b/net/core/skbuff.c
index 1a94a3037370..436695d8deb8 100644
--- a/net/core/skbuff.c
+++ b/net/core/skbuff.c
@@ -201,6 +201,10 @@ struct sk_buff *__alloc_skb(unsigned int size, gfp_t gfp_mask,
 	skb->data = data;
 	skb_reset_tail_pointer(skb);
 	skb->end = skb->tail + size;
+#ifdef NET_SKBUFF_DATA_USES_OFFSET
+	skb->mac_header = ~0U;
+#endif
+
 	/* make sure we initialize shinfo sequentially */
 	shinfo = skb_shinfo(skb);
 	atomic_set(&shinfo->dataref, 1);
-- 
cgit v1.2.2


From 603a8bbe62e54108055fca46ecdd611c10c6cd0a Mon Sep 17 00:00:00 2001
From: Stephen Hemminger <shemminger@vyatta.com>
Date: Wed, 17 Jun 2009 12:17:34 +0000
Subject: skbuff: don't corrupt mac_header on skb expansion

The skb mac_header field is sometimes NULL (or ~0u) as a sentinel
value. The places where skb is expanded add an offset which would
change this flag into an invalid pointer (or offset).

Signed-off-by: Stephen Hemminger <shemminger@vyatta.com>
Signed-off-by: David S. Miller <davem@davemloft.net>
---
 net/core/skbuff.c | 9 ++++++---
 1 file changed, 6 insertions(+), 3 deletions(-)

(limited to 'net')

diff --git a/net/core/skbuff.c b/net/core/skbuff.c
index 436695d8deb8..a4c01f5c6585 100644
--- a/net/core/skbuff.c
+++ b/net/core/skbuff.c
@@ -661,7 +661,8 @@ static void copy_skb_header(struct sk_buff *new, const struct sk_buff *old)
 	/* {transport,network,mac}_header are relative to skb->head */
 	new->transport_header += offset;
 	new->network_header   += offset;
-	new->mac_header	      += offset;
+	if (skb_mac_header_was_set(new))
+		new->mac_header	      += offset;
 #endif
 	skb_shinfo(new)->gso_size = skb_shinfo(old)->gso_size;
 	skb_shinfo(new)->gso_segs = skb_shinfo(old)->gso_segs;
@@ -843,7 +844,8 @@ int pskb_expand_head(struct sk_buff *skb, int nhead, int ntail,
 	skb->tail	      += off;
 	skb->transport_header += off;
 	skb->network_header   += off;
-	skb->mac_header	      += off;
+	if (skb_mac_header_was_set(skb))
+		skb->mac_header += off;
 	skb->csum_start       += nhead;
 	skb->cloned   = 0;
 	skb->hdr_len  = 0;
@@ -935,7 +937,8 @@ struct sk_buff *skb_copy_expand(const struct sk_buff *skb,
 #ifdef NET_SKBUFF_DATA_USES_OFFSET
 	n->transport_header += off;
 	n->network_header   += off;
-	n->mac_header	    += off;
+	if (skb_mac_header_was_set(skb))
+		n->mac_header += off;
 #endif
 
 	return n;
-- 
cgit v1.2.2


From b964758050f856e44f5fe645d03bea8a1b0b66bd Mon Sep 17 00:00:00 2001
From: Jarek Poplawski <jarkao2@gmail.com>
Date: Tue, 16 Jun 2009 08:33:55 +0000
Subject: pkt_sched: Update drops stats in act_police

Action police statistics could be misleading because drops are not
shown when expected.

With feedback from: Jamal Hadi Salim <hadi@cyberus.ca>

Reported-by: Pawel Staszewski <pstaszewski@itcare.pl>
Signed-off-by: Jarek Poplawski <jarkao2@gmail.com>
Acked-by: Jamal Hadi Salim <hadi@cyberus.ca>
Signed-off-by: David S. Miller <davem@davemloft.net>
---
 net/sched/act_police.c | 4 ++++
 1 file changed, 4 insertions(+)

(limited to 'net')

diff --git a/net/sched/act_police.c b/net/sched/act_police.c
index f8f047b61245..723964c3ee4f 100644
--- a/net/sched/act_police.c
+++ b/net/sched/act_police.c
@@ -294,6 +294,8 @@ static int tcf_act_police(struct sk_buff *skb, struct tc_action *a,
 	if (police->tcfp_ewma_rate &&
 	    police->tcf_rate_est.bps >= police->tcfp_ewma_rate) {
 		police->tcf_qstats.overlimits++;
+		if (police->tcf_action == TC_ACT_SHOT)
+			police->tcf_qstats.drops++;
 		spin_unlock(&police->tcf_lock);
 		return police->tcf_action;
 	}
@@ -327,6 +329,8 @@ static int tcf_act_police(struct sk_buff *skb, struct tc_action *a,
 	}
 
 	police->tcf_qstats.overlimits++;
+	if (police->tcf_action == TC_ACT_SHOT)
+		police->tcf_qstats.drops++;
 	spin_unlock(&police->tcf_lock);
 	return police->tcf_action;
 }
-- 
cgit v1.2.2


From 7b85576d15bf2574b0a451108f59f9ad4170dd3f Mon Sep 17 00:00:00 2001
From: Jarek Poplawski <jarkao2@gmail.com>
Date: Thu, 18 Jun 2009 00:28:51 -0700
Subject: ipv4: Fix fib_trie rebalancing, part 2

My previous patch, which explicitly delays freeing of tnodes by adding
them to the list to flush them after the update is finished, isn't
strict enough. It treats exceptionally tnodes without parent, assuming
they are newly created, so "invisible" for the read side yet.

But the top tnode doesn't have parent as well, so we have to exclude
all exceptions (at least until a better way is found). Additionally we
need to move rcu assignment of this node before flushing, so the
return type of the trie_rebalance() function is changed.

Reported-by: Yan Zheng <zheng.yan@oracle.com>
Signed-off-by: Jarek Poplawski <jarkao2@gmail.com>
Signed-off-by: David S. Miller <davem@davemloft.net>
---
 net/ipv4/fib_trie.c | 24 ++++++++++--------------
 1 file changed, 10 insertions(+), 14 deletions(-)

(limited to 'net')

diff --git a/net/ipv4/fib_trie.c b/net/ipv4/fib_trie.c
index d1a39b1277d6..012cf5a68581 100644
--- a/net/ipv4/fib_trie.c
+++ b/net/ipv4/fib_trie.c
@@ -391,13 +391,8 @@ static inline void tnode_free(struct tnode *tn)
 static void tnode_free_safe(struct tnode *tn)
 {
 	BUG_ON(IS_LEAF(tn));
-
-	if (node_parent((struct node *) tn)) {
-		tn->tnode_free = tnode_free_head;
-		tnode_free_head = tn;
-	} else {
-		tnode_free(tn);
-	}
+	tn->tnode_free = tnode_free_head;
+	tnode_free_head = tn;
 }
 
 static void tnode_free_flush(void)
@@ -1009,7 +1004,7 @@ fib_find_node(struct trie *t, u32 key)
 	return NULL;
 }
 
-static struct node *trie_rebalance(struct trie *t, struct tnode *tn)
+static void trie_rebalance(struct trie *t, struct tnode *tn)
 {
 	int wasfull;
 	t_key cindex, key;
@@ -1033,12 +1028,13 @@ static struct node *trie_rebalance(struct trie *t, struct tnode *tn)
 	}
 
 	/* Handle last (top) tnode */
-	if (IS_TNODE(tn)) {
+	if (IS_TNODE(tn))
 		tn = (struct tnode *)resize(t, (struct tnode *)tn);
-		tnode_free_flush();
-	}
 
-	return (struct node *)tn;
+	rcu_assign_pointer(t->trie, (struct node *)tn);
+	tnode_free_flush();
+
+	return;
 }
 
 /* only used from updater-side */
@@ -1186,7 +1182,7 @@ static struct list_head *fib_insert_node(struct trie *t, u32 key, int plen)
 
 	/* Rebalance the trie */
 
-	rcu_assign_pointer(t->trie, trie_rebalance(t, tp));
+	trie_rebalance(t, tp);
 done:
 	return fa_head;
 }
@@ -1605,7 +1601,7 @@ static void trie_leaf_remove(struct trie *t, struct leaf *l)
 	if (tp) {
 		t_key cindex = tkey_extract_bits(l->key, tp->pos, tp->bits);
 		put_child(t, (struct tnode *)tp, cindex, NULL);
-		rcu_assign_pointer(t->trie, trie_rebalance(t, tp));
+		trie_rebalance(t, tp);
 	} else
 		rcu_assign_pointer(t->trie, NULL);
 
-- 
cgit v1.2.2


From 31278e71471399beaff9280737e52b47db4dc345 Mon Sep 17 00:00:00 2001
From: Jiri Pirko <jpirko@redhat.com>
Date: Wed, 17 Jun 2009 01:12:19 +0000
Subject: net: group address list and its count

This patch is inspired by patch recently posted by Johannes Berg. Basically what
my patch does is to group list and a count of addresses into newly introduced
structure netdev_hw_addr_list. This brings us two benefits:
1) struct net_device becames a bit nicer.
2) in the future there will be a possibility to operate with lists independently
   on netdevices (with exporting right functions).
I wanted to introduce this patch before I'll post a multicast lists conversion.

Signed-off-by: Jiri Pirko <jpirko@redhat.com>

 drivers/net/bnx2.c              |    4 +-
 drivers/net/e1000/e1000_main.c  |    4 +-
 drivers/net/ixgbe/ixgbe_main.c  |    6 +-
 drivers/net/mv643xx_eth.c       |    2 +-
 drivers/net/niu.c               |    4 +-
 drivers/net/virtio_net.c        |   10 ++--
 drivers/s390/net/qeth_l2_main.c |    2 +-
 include/linux/netdevice.h       |   17 +++--
 net/core/dev.c                  |  130 ++++++++++++++++++--------------------
 9 files changed, 89 insertions(+), 90 deletions(-)
Signed-off-by: David S. Miller <davem@davemloft.net>
---
 net/core/dev.c | 130 +++++++++++++++++++++++++++------------------------------
 1 file changed, 62 insertions(+), 68 deletions(-)

(limited to 'net')

diff --git a/net/core/dev.c b/net/core/dev.c
index 576a61574a93..baf2dc13a34a 100644
--- a/net/core/dev.c
+++ b/net/core/dev.c
@@ -3461,10 +3461,10 @@ void __dev_set_rx_mode(struct net_device *dev)
 		/* Unicast addresses changes may only happen under the rtnl,
 		 * therefore calling __dev_set_promiscuity here is safe.
 		 */
-		if (dev->uc_count > 0 && !dev->uc_promisc) {
+		if (dev->uc.count > 0 && !dev->uc_promisc) {
 			__dev_set_promiscuity(dev, 1);
 			dev->uc_promisc = 1;
-		} else if (dev->uc_count == 0 && dev->uc_promisc) {
+		} else if (dev->uc.count == 0 && dev->uc_promisc) {
 			__dev_set_promiscuity(dev, -1);
 			dev->uc_promisc = 0;
 		}
@@ -3483,9 +3483,8 @@ void dev_set_rx_mode(struct net_device *dev)
 
 /* hw addresses list handling functions */
 
-static int __hw_addr_add(struct list_head *list, int *delta,
-			 unsigned char *addr, int addr_len,
-			 unsigned char addr_type)
+static int __hw_addr_add(struct netdev_hw_addr_list *list, unsigned char *addr,
+			 int addr_len, unsigned char addr_type)
 {
 	struct netdev_hw_addr *ha;
 	int alloc_size;
@@ -3493,7 +3492,7 @@ static int __hw_addr_add(struct list_head *list, int *delta,
 	if (addr_len > MAX_ADDR_LEN)
 		return -EINVAL;
 
-	list_for_each_entry(ha, list, list) {
+	list_for_each_entry(ha, &list->list, list) {
 		if (!memcmp(ha->addr, addr, addr_len) &&
 		    ha->type == addr_type) {
 			ha->refcount++;
@@ -3512,9 +3511,8 @@ static int __hw_addr_add(struct list_head *list, int *delta,
 	ha->type = addr_type;
 	ha->refcount = 1;
 	ha->synced = false;
-	list_add_tail_rcu(&ha->list, list);
-	if (delta)
-		(*delta)++;
+	list_add_tail_rcu(&ha->list, &list->list);
+	list->count++;
 	return 0;
 }
 
@@ -3526,120 +3524,121 @@ static void ha_rcu_free(struct rcu_head *head)
 	kfree(ha);
 }
 
-static int __hw_addr_del(struct list_head *list, int *delta,
-			 unsigned char *addr, int addr_len,
-			 unsigned char addr_type)
+static int __hw_addr_del(struct netdev_hw_addr_list *list, unsigned char *addr,
+			 int addr_len, unsigned char addr_type)
 {
 	struct netdev_hw_addr *ha;
 
-	list_for_each_entry(ha, list, list) {
+	list_for_each_entry(ha, &list->list, list) {
 		if (!memcmp(ha->addr, addr, addr_len) &&
 		    (ha->type == addr_type || !addr_type)) {
 			if (--ha->refcount)
 				return 0;
 			list_del_rcu(&ha->list);
 			call_rcu(&ha->rcu_head, ha_rcu_free);
-			if (delta)
-				(*delta)--;
+			list->count--;
 			return 0;
 		}
 	}
 	return -ENOENT;
 }
 
-static int __hw_addr_add_multiple(struct list_head *to_list, int *to_delta,
-				  struct list_head *from_list, int addr_len,
+static int __hw_addr_add_multiple(struct netdev_hw_addr_list *to_list,
+				  struct netdev_hw_addr_list *from_list,
+				  int addr_len,
 				  unsigned char addr_type)
 {
 	int err;
 	struct netdev_hw_addr *ha, *ha2;
 	unsigned char type;
 
-	list_for_each_entry(ha, from_list, list) {
+	list_for_each_entry(ha, &from_list->list, list) {
 		type = addr_type ? addr_type : ha->type;
-		err = __hw_addr_add(to_list, to_delta, ha->addr,
-				    addr_len, type);
+		err = __hw_addr_add(to_list, ha->addr, addr_len, type);
 		if (err)
 			goto unroll;
 	}
 	return 0;
 
 unroll:
-	list_for_each_entry(ha2, from_list, list) {
+	list_for_each_entry(ha2, &from_list->list, list) {
 		if (ha2 == ha)
 			break;
 		type = addr_type ? addr_type : ha2->type;
-		__hw_addr_del(to_list, to_delta, ha2->addr,
-			      addr_len, type);
+		__hw_addr_del(to_list, ha2->addr, addr_len, type);
 	}
 	return err;
 }
 
-static void __hw_addr_del_multiple(struct list_head *to_list, int *to_delta,
-				   struct list_head *from_list, int addr_len,
+static void __hw_addr_del_multiple(struct netdev_hw_addr_list *to_list,
+				   struct netdev_hw_addr_list *from_list,
+				   int addr_len,
 				   unsigned char addr_type)
 {
 	struct netdev_hw_addr *ha;
 	unsigned char type;
 
-	list_for_each_entry(ha, from_list, list) {
+	list_for_each_entry(ha, &from_list->list, list) {
 		type = addr_type ? addr_type : ha->type;
-		__hw_addr_del(to_list, to_delta, ha->addr,
-			      addr_len, addr_type);
+		__hw_addr_del(to_list, ha->addr, addr_len, addr_type);
 	}
 }
 
-static int __hw_addr_sync(struct list_head *to_list, int *to_delta,
-			  struct list_head *from_list, int *from_delta,
+static int __hw_addr_sync(struct netdev_hw_addr_list *to_list,
+			  struct netdev_hw_addr_list *from_list,
 			  int addr_len)
 {
 	int err = 0;
 	struct netdev_hw_addr *ha, *tmp;
 
-	list_for_each_entry_safe(ha, tmp, from_list, list) {
+	list_for_each_entry_safe(ha, tmp, &from_list->list, list) {
 		if (!ha->synced) {
-			err = __hw_addr_add(to_list, to_delta, ha->addr,
+			err = __hw_addr_add(to_list, ha->addr,
 					    addr_len, ha->type);
 			if (err)
 				break;
 			ha->synced = true;
 			ha->refcount++;
 		} else if (ha->refcount == 1) {
-			__hw_addr_del(to_list, to_delta, ha->addr,
-				      addr_len, ha->type);
-			__hw_addr_del(from_list, from_delta, ha->addr,
-				      addr_len, ha->type);
+			__hw_addr_del(to_list, ha->addr, addr_len, ha->type);
+			__hw_addr_del(from_list, ha->addr, addr_len, ha->type);
 		}
 	}
 	return err;
 }
 
-static void __hw_addr_unsync(struct list_head *to_list, int *to_delta,
-			     struct list_head *from_list, int *from_delta,
+static void __hw_addr_unsync(struct netdev_hw_addr_list *to_list,
+			     struct netdev_hw_addr_list *from_list,
 			     int addr_len)
 {
 	struct netdev_hw_addr *ha, *tmp;
 
-	list_for_each_entry_safe(ha, tmp, from_list, list) {
+	list_for_each_entry_safe(ha, tmp, &from_list->list, list) {
 		if (ha->synced) {
-			__hw_addr_del(to_list, to_delta, ha->addr,
+			__hw_addr_del(to_list, ha->addr,
 				      addr_len, ha->type);
 			ha->synced = false;
-			__hw_addr_del(from_list, from_delta, ha->addr,
+			__hw_addr_del(from_list, ha->addr,
 				      addr_len, ha->type);
 		}
 	}
 }
 
-
-static void __hw_addr_flush(struct list_head *list)
+static void __hw_addr_flush(struct netdev_hw_addr_list *list)
 {
 	struct netdev_hw_addr *ha, *tmp;
 
-	list_for_each_entry_safe(ha, tmp, list, list) {
+	list_for_each_entry_safe(ha, tmp, &list->list, list) {
 		list_del_rcu(&ha->list);
 		call_rcu(&ha->rcu_head, ha_rcu_free);
 	}
+	list->count = 0;
+}
+
+static void __hw_addr_init(struct netdev_hw_addr_list *list)
+{
+	INIT_LIST_HEAD(&list->list);
+	list->count = 0;
 }
 
 /* Device addresses handling functions */
@@ -3648,7 +3647,7 @@ static void dev_addr_flush(struct net_device *dev)
 {
 	/* rtnl_mutex must be held here */
 
-	__hw_addr_flush(&dev->dev_addr_list);
+	__hw_addr_flush(&dev->dev_addrs);
 	dev->dev_addr = NULL;
 }
 
@@ -3660,16 +3659,16 @@ static int dev_addr_init(struct net_device *dev)
 
 	/* rtnl_mutex must be held here */
 
-	INIT_LIST_HEAD(&dev->dev_addr_list);
+	__hw_addr_init(&dev->dev_addrs);
 	memset(addr, 0, sizeof(addr));
-	err = __hw_addr_add(&dev->dev_addr_list, NULL, addr, sizeof(addr),
+	err = __hw_addr_add(&dev->dev_addrs, addr, sizeof(addr),
 			    NETDEV_HW_ADDR_T_LAN);
 	if (!err) {
 		/*
 		 * Get the first (previously created) address from the list
 		 * and set dev_addr pointer to this location.
 		 */
-		ha = list_first_entry(&dev->dev_addr_list,
+		ha = list_first_entry(&dev->dev_addrs.list,
 				      struct netdev_hw_addr, list);
 		dev->dev_addr = ha->addr;
 	}
@@ -3694,8 +3693,7 @@ int dev_addr_add(struct net_device *dev, unsigned char *addr,
 
 	ASSERT_RTNL();
 
-	err = __hw_addr_add(&dev->dev_addr_list, NULL, addr, dev->addr_len,
-			    addr_type);
+	err = __hw_addr_add(&dev->dev_addrs, addr, dev->addr_len, addr_type);
 	if (!err)
 		call_netdevice_notifiers(NETDEV_CHANGEADDR, dev);
 	return err;
@@ -3725,11 +3723,12 @@ int dev_addr_del(struct net_device *dev, unsigned char *addr,
 	 * We can not remove the first address from the list because
 	 * dev->dev_addr points to that.
 	 */
-	ha = list_first_entry(&dev->dev_addr_list, struct netdev_hw_addr, list);
+	ha = list_first_entry(&dev->dev_addrs.list,
+			      struct netdev_hw_addr, list);
 	if (ha->addr == dev->dev_addr && ha->refcount == 1)
 		return -ENOENT;
 
-	err = __hw_addr_del(&dev->dev_addr_list, NULL, addr, dev->addr_len,
+	err = __hw_addr_del(&dev->dev_addrs, addr, dev->addr_len,
 			    addr_type);
 	if (!err)
 		call_netdevice_notifiers(NETDEV_CHANGEADDR, dev);
@@ -3757,8 +3756,7 @@ int dev_addr_add_multiple(struct net_device *to_dev,
 
 	if (from_dev->addr_len != to_dev->addr_len)
 		return -EINVAL;
-	err = __hw_addr_add_multiple(&to_dev->dev_addr_list, NULL,
-				     &from_dev->dev_addr_list,
+	err = __hw_addr_add_multiple(&to_dev->dev_addrs, &from_dev->dev_addrs,
 				     to_dev->addr_len, addr_type);
 	if (!err)
 		call_netdevice_notifiers(NETDEV_CHANGEADDR, to_dev);
@@ -3784,15 +3782,14 @@ int dev_addr_del_multiple(struct net_device *to_dev,
 
 	if (from_dev->addr_len != to_dev->addr_len)
 		return -EINVAL;
-	__hw_addr_del_multiple(&to_dev->dev_addr_list, NULL,
-			       &from_dev->dev_addr_list,
+	__hw_addr_del_multiple(&to_dev->dev_addrs, &from_dev->dev_addrs,
 			       to_dev->addr_len, addr_type);
 	call_netdevice_notifiers(NETDEV_CHANGEADDR, to_dev);
 	return 0;
 }
 EXPORT_SYMBOL(dev_addr_del_multiple);
 
-/* unicast and multicast addresses handling functions */
+/* multicast addresses handling functions */
 
 int __dev_addr_delete(struct dev_addr_list **list, int *count,
 		      void *addr, int alen, int glbl)
@@ -3868,8 +3865,8 @@ int dev_unicast_delete(struct net_device *dev, void *addr)
 
 	ASSERT_RTNL();
 
-	err = __hw_addr_del(&dev->uc_list, &dev->uc_count, addr,
-			    dev->addr_len, NETDEV_HW_ADDR_T_UNICAST);
+	err = __hw_addr_del(&dev->uc, addr, dev->addr_len,
+			    NETDEV_HW_ADDR_T_UNICAST);
 	if (!err)
 		__dev_set_rx_mode(dev);
 	return err;
@@ -3892,8 +3889,8 @@ int dev_unicast_add(struct net_device *dev, void *addr)
 
 	ASSERT_RTNL();
 
-	err = __hw_addr_add(&dev->uc_list, &dev->uc_count, addr,
-			    dev->addr_len, NETDEV_HW_ADDR_T_UNICAST);
+	err = __hw_addr_add(&dev->uc, addr, dev->addr_len,
+			    NETDEV_HW_ADDR_T_UNICAST);
 	if (!err)
 		__dev_set_rx_mode(dev);
 	return err;
@@ -3966,8 +3963,7 @@ int dev_unicast_sync(struct net_device *to, struct net_device *from)
 	if (to->addr_len != from->addr_len)
 		return -EINVAL;
 
-	err = __hw_addr_sync(&to->uc_list, &to->uc_count,
-			     &from->uc_list, &from->uc_count, to->addr_len);
+	err = __hw_addr_sync(&to->uc, &from->uc, to->addr_len);
 	if (!err)
 		__dev_set_rx_mode(to);
 	return err;
@@ -3990,8 +3986,7 @@ void dev_unicast_unsync(struct net_device *to, struct net_device *from)
 	if (to->addr_len != from->addr_len)
 		return;
 
-	__hw_addr_unsync(&to->uc_list, &to->uc_count,
-			 &from->uc_list, &from->uc_count, to->addr_len);
+	__hw_addr_unsync(&to->uc, &from->uc, to->addr_len);
 	__dev_set_rx_mode(to);
 }
 EXPORT_SYMBOL(dev_unicast_unsync);
@@ -4000,15 +3995,14 @@ static void dev_unicast_flush(struct net_device *dev)
 {
 	/* rtnl_mutex must be held here */
 
-	__hw_addr_flush(&dev->uc_list);
-	dev->uc_count = 0;
+	__hw_addr_flush(&dev->uc);
 }
 
 static void dev_unicast_init(struct net_device *dev)
 {
 	/* rtnl_mutex must be held here */
 
-	INIT_LIST_HEAD(&dev->uc_list);
+	__hw_addr_init(&dev->uc);
 }
 
 
-- 
cgit v1.2.2


From 31e6d363abcd0d05766c82f1a9c905a4c974a199 Mon Sep 17 00:00:00 2001
From: Eric Dumazet <eric.dumazet@gmail.com>
Date: Wed, 17 Jun 2009 19:05:41 -0700
Subject: net: correct off-by-one write allocations reports

commit 2b85a34e911bf483c27cfdd124aeb1605145dc80
(net: No more expensive sock_hold()/sock_put() on each tx)
changed initial sk_wmem_alloc value.

We need to take into account this offset when reporting
sk_wmem_alloc to user, in PROC_FS files or various
ioctls (SIOCOUTQ/TIOCOUTQ)

Signed-off-by: Eric Dumazet <eric.dumazet@gmail.com>
Signed-off-by: David S. Miller <davem@davemloft.net>
---
 net/appletalk/atalk_proc.c   |  4 ++--
 net/appletalk/ddp.c          |  3 +--
 net/ax25/af_ax25.c           | 11 ++++++-----
 net/bluetooth/af_bluetooth.c |  2 +-
 net/decnet/af_decnet.c       |  2 +-
 net/ieee802154/dgram.c       |  3 ++-
 net/ipv4/inet_diag.c         |  4 ++--
 net/ipv4/raw.c               |  7 ++++---
 net/ipv4/udp.c               |  7 ++++---
 net/ipv6/raw.c               |  7 ++++---
 net/ipv6/udp.c               |  4 ++--
 net/ipx/af_ipx.c             |  2 +-
 net/ipx/ipx_proc.c           |  4 ++--
 net/irda/af_irda.c           |  3 ++-
 net/key/af_key.c             |  4 ++--
 net/llc/llc_proc.c           |  4 ++--
 net/netlink/af_netlink.c     |  4 ++--
 net/netrom/af_netrom.c       |  6 +++---
 net/packet/af_packet.c       |  3 ++-
 net/rose/af_rose.c           |  7 ++++---
 net/sched/em_meta.c          |  4 ++--
 net/sctp/socket.c            |  4 ++--
 net/unix/af_unix.c           |  2 +-
 net/x25/af_x25.c             |  4 ++--
 net/x25/x25_proc.c           |  4 ++--
 25 files changed, 58 insertions(+), 51 deletions(-)

(limited to 'net')

diff --git a/net/appletalk/atalk_proc.c b/net/appletalk/atalk_proc.c
index fd8e0847b254..80caad1a31a5 100644
--- a/net/appletalk/atalk_proc.c
+++ b/net/appletalk/atalk_proc.c
@@ -204,8 +204,8 @@ static int atalk_seq_socket_show(struct seq_file *seq, void *v)
 			"%02X %d\n",
 		   s->sk_type, ntohs(at->src_net), at->src_node, at->src_port,
 		   ntohs(at->dest_net), at->dest_node, at->dest_port,
-		   atomic_read(&s->sk_wmem_alloc),
-		   atomic_read(&s->sk_rmem_alloc),
+		   sk_wmem_alloc_get(s),
+		   sk_rmem_alloc_get(s),
 		   s->sk_state, SOCK_INODE(s->sk_socket)->i_uid);
 out:
 	return 0;
diff --git a/net/appletalk/ddp.c b/net/appletalk/ddp.c
index f7a53b219ef0..590b83963622 100644
--- a/net/appletalk/ddp.c
+++ b/net/appletalk/ddp.c
@@ -1748,8 +1748,7 @@ static int atalk_ioctl(struct socket *sock, unsigned int cmd, unsigned long arg)
 	switch (cmd) {
 		/* Protocol layer */
 		case TIOCOUTQ: {
-			long amount = sk->sk_sndbuf -
-				      atomic_read(&sk->sk_wmem_alloc);
+			long amount = sk->sk_sndbuf - sk_wmem_alloc_get(sk);
 
 			if (amount < 0)
 				amount = 0;
diff --git a/net/ax25/af_ax25.c b/net/ax25/af_ax25.c
index 61b35b955490..da0f64f82b57 100644
--- a/net/ax25/af_ax25.c
+++ b/net/ax25/af_ax25.c
@@ -1690,7 +1690,8 @@ static int ax25_ioctl(struct socket *sock, unsigned int cmd, unsigned long arg)
 	switch (cmd) {
 	case TIOCOUTQ: {
 		long amount;
-		amount = sk->sk_sndbuf - atomic_read(&sk->sk_wmem_alloc);
+
+		amount = sk->sk_sndbuf - sk_wmem_alloc_get(sk);
 		if (amount < 0)
 			amount = 0;
 		res = put_user(amount, (int __user *)argp);
@@ -1780,8 +1781,8 @@ static int ax25_ioctl(struct socket *sock, unsigned int cmd, unsigned long arg)
 		ax25_info.idletimer = ax25_display_timer(&ax25->idletimer) / (60 * HZ);
 		ax25_info.n2count   = ax25->n2count;
 		ax25_info.state     = ax25->state;
-		ax25_info.rcv_q     = atomic_read(&sk->sk_rmem_alloc);
-		ax25_info.snd_q     = atomic_read(&sk->sk_wmem_alloc);
+		ax25_info.rcv_q     = sk_wmem_alloc_get(sk);
+		ax25_info.snd_q     = sk_rmem_alloc_get(sk);
 		ax25_info.vs        = ax25->vs;
 		ax25_info.vr        = ax25->vr;
 		ax25_info.va        = ax25->va;
@@ -1921,8 +1922,8 @@ static int ax25_info_show(struct seq_file *seq, void *v)
 
 	if (ax25->sk != NULL) {
 		seq_printf(seq, " %d %d %lu\n",
-			   atomic_read(&ax25->sk->sk_wmem_alloc),
-			   atomic_read(&ax25->sk->sk_rmem_alloc),
+			   sk_wmem_alloc_get(ax25->sk),
+			   sk_rmem_alloc_get(ax25->sk),
 			   sock_i_ino(ax25->sk));
 	} else {
 		seq_puts(seq, " * * *\n");
diff --git a/net/bluetooth/af_bluetooth.c b/net/bluetooth/af_bluetooth.c
index 02b9baa1930b..0250e0600150 100644
--- a/net/bluetooth/af_bluetooth.c
+++ b/net/bluetooth/af_bluetooth.c
@@ -337,7 +337,7 @@ int bt_sock_ioctl(struct socket *sock, unsigned int cmd, unsigned long arg)
 		if (sk->sk_state == BT_LISTEN)
 			return -EINVAL;
 
-		amount = sk->sk_sndbuf - atomic_read(&sk->sk_wmem_alloc);
+		amount = sk->sk_sndbuf - sk_wmem_alloc_get(sk);
 		if (amount < 0)
 			amount = 0;
 		err = put_user(amount, (int __user *) arg);
diff --git a/net/decnet/af_decnet.c b/net/decnet/af_decnet.c
index a5e3a593e472..d351b8db0df5 100644
--- a/net/decnet/af_decnet.c
+++ b/net/decnet/af_decnet.c
@@ -1240,7 +1240,7 @@ static int dn_ioctl(struct socket *sock, unsigned int cmd, unsigned long arg)
 		return val;
 
 	case TIOCOUTQ:
-		amount = sk->sk_sndbuf - atomic_read(&sk->sk_wmem_alloc);
+		amount = sk->sk_sndbuf - sk_wmem_alloc_get(sk);
 		if (amount < 0)
 			amount = 0;
 		err = put_user(amount, (int __user *)arg);
diff --git a/net/ieee802154/dgram.c b/net/ieee802154/dgram.c
index 1779677aed46..14d39840dd62 100644
--- a/net/ieee802154/dgram.c
+++ b/net/ieee802154/dgram.c
@@ -126,7 +126,8 @@ static int dgram_ioctl(struct sock *sk, int cmd, unsigned long arg)
 	switch (cmd) {
 	case SIOCOUTQ:
 	{
-		int amount = atomic_read(&sk->sk_wmem_alloc);
+		int amount = sk_wmem_alloc_get(sk);
+
 		return put_user(amount, (int __user *)arg);
 	}
 
diff --git a/net/ipv4/inet_diag.c b/net/ipv4/inet_diag.c
index b0b273503e2a..a706a47f4dbb 100644
--- a/net/ipv4/inet_diag.c
+++ b/net/ipv4/inet_diag.c
@@ -156,10 +156,10 @@ static int inet_csk_diag_fill(struct sock *sk,
 	r->idiag_inode = sock_i_ino(sk);
 
 	if (minfo) {
-		minfo->idiag_rmem = atomic_read(&sk->sk_rmem_alloc);
+		minfo->idiag_rmem = sk_rmem_alloc_get(sk);
 		minfo->idiag_wmem = sk->sk_wmem_queued;
 		minfo->idiag_fmem = sk->sk_forward_alloc;
-		minfo->idiag_tmem = atomic_read(&sk->sk_wmem_alloc);
+		minfo->idiag_tmem = sk_wmem_alloc_get(sk);
 	}
 
 	handler->idiag_get_info(sk, r, info);
diff --git a/net/ipv4/raw.c b/net/ipv4/raw.c
index 3dc9171a272f..2979f14bb188 100644
--- a/net/ipv4/raw.c
+++ b/net/ipv4/raw.c
@@ -799,7 +799,8 @@ static int raw_ioctl(struct sock *sk, int cmd, unsigned long arg)
 {
 	switch (cmd) {
 		case SIOCOUTQ: {
-			int amount = atomic_read(&sk->sk_wmem_alloc);
+			int amount = sk_wmem_alloc_get(sk);
+
 			return put_user(amount, (int __user *)arg);
 		}
 		case SIOCINQ: {
@@ -935,8 +936,8 @@ static void raw_sock_seq_show(struct seq_file *seq, struct sock *sp, int i)
 	seq_printf(seq, "%4d: %08X:%04X %08X:%04X"
 		" %02X %08X:%08X %02X:%08lX %08X %5d %8d %lu %d %p %d\n",
 		i, src, srcp, dest, destp, sp->sk_state,
-		atomic_read(&sp->sk_wmem_alloc),
-		atomic_read(&sp->sk_rmem_alloc),
+		sk_wmem_alloc_get(sp),
+		sk_rmem_alloc_get(sp),
 		0, 0L, 0, sock_i_uid(sp), 0, sock_i_ino(sp),
 		atomic_read(&sp->sk_refcnt), sp, atomic_read(&sp->sk_drops));
 }
diff --git a/net/ipv4/udp.c b/net/ipv4/udp.c
index 8f4158d7c9a6..80e3812837ad 100644
--- a/net/ipv4/udp.c
+++ b/net/ipv4/udp.c
@@ -840,7 +840,8 @@ int udp_ioctl(struct sock *sk, int cmd, unsigned long arg)
 	switch (cmd) {
 	case SIOCOUTQ:
 	{
-		int amount = atomic_read(&sk->sk_wmem_alloc);
+		int amount = sk_wmem_alloc_get(sk);
+
 		return put_user(amount, (int __user *)arg);
 	}
 
@@ -1721,8 +1722,8 @@ static void udp4_format_sock(struct sock *sp, struct seq_file *f,
 	seq_printf(f, "%4d: %08X:%04X %08X:%04X"
 		" %02X %08X:%08X %02X:%08lX %08X %5d %8d %lu %d %p %d%n",
 		bucket, src, srcp, dest, destp, sp->sk_state,
-		atomic_read(&sp->sk_wmem_alloc),
-		atomic_read(&sp->sk_rmem_alloc),
+		sk_wmem_alloc_get(sp),
+		sk_rmem_alloc_get(sp),
 		0, 0L, 0, sock_i_uid(sp), 0, sock_i_ino(sp),
 		atomic_read(&sp->sk_refcnt), sp,
 		atomic_read(&sp->sk_drops), len);
diff --git a/net/ipv6/raw.c b/net/ipv6/raw.c
index 36a090d87a3d..8b0b6f948063 100644
--- a/net/ipv6/raw.c
+++ b/net/ipv6/raw.c
@@ -1130,7 +1130,8 @@ static int rawv6_ioctl(struct sock *sk, int cmd, unsigned long arg)
 	switch(cmd) {
 		case SIOCOUTQ:
 		{
-			int amount = atomic_read(&sk->sk_wmem_alloc);
+			int amount = sk_wmem_alloc_get(sk);
+
 			return put_user(amount, (int __user *)arg);
 		}
 		case SIOCINQ:
@@ -1236,8 +1237,8 @@ static void raw6_sock_seq_show(struct seq_file *seq, struct sock *sp, int i)
 		   dest->s6_addr32[0], dest->s6_addr32[1],
 		   dest->s6_addr32[2], dest->s6_addr32[3], destp,
 		   sp->sk_state,
-		   atomic_read(&sp->sk_wmem_alloc),
-		   atomic_read(&sp->sk_rmem_alloc),
+		   sk_wmem_alloc_get(sp),
+		   sk_rmem_alloc_get(sp),
 		   0, 0L, 0,
 		   sock_i_uid(sp), 0,
 		   sock_i_ino(sp),
diff --git a/net/ipv6/udp.c b/net/ipv6/udp.c
index fc333d854728..023beda6b224 100644
--- a/net/ipv6/udp.c
+++ b/net/ipv6/udp.c
@@ -1061,8 +1061,8 @@ static void udp6_sock_seq_show(struct seq_file *seq, struct sock *sp, int bucket
 		   dest->s6_addr32[0], dest->s6_addr32[1],
 		   dest->s6_addr32[2], dest->s6_addr32[3], destp,
 		   sp->sk_state,
-		   atomic_read(&sp->sk_wmem_alloc),
-		   atomic_read(&sp->sk_rmem_alloc),
+		   sk_wmem_alloc_get(sp),
+		   sk_rmem_alloc_get(sp),
 		   0, 0L, 0,
 		   sock_i_uid(sp), 0,
 		   sock_i_ino(sp),
diff --git a/net/ipx/af_ipx.c b/net/ipx/af_ipx.c
index 1627050e29fd..417b0e309495 100644
--- a/net/ipx/af_ipx.c
+++ b/net/ipx/af_ipx.c
@@ -1835,7 +1835,7 @@ static int ipx_ioctl(struct socket *sock, unsigned int cmd, unsigned long arg)
 
 	switch (cmd) {
 	case TIOCOUTQ:
-		amount = sk->sk_sndbuf - atomic_read(&sk->sk_wmem_alloc);
+		amount = sk->sk_sndbuf - sk_wmem_alloc_get(sk);
 		if (amount < 0)
 			amount = 0;
 		rc = put_user(amount, (int __user *)argp);
diff --git a/net/ipx/ipx_proc.c b/net/ipx/ipx_proc.c
index 5ed97ad0e2e3..576178482f89 100644
--- a/net/ipx/ipx_proc.c
+++ b/net/ipx/ipx_proc.c
@@ -280,8 +280,8 @@ static int ipx_seq_socket_show(struct seq_file *seq, void *v)
 	}
 
 	seq_printf(seq, "%08X  %08X  %02X     %03d\n",
-		   atomic_read(&s->sk_wmem_alloc),
-		   atomic_read(&s->sk_rmem_alloc),
+		   sk_wmem_alloc_get(s),
+		   sk_rmem_alloc_get(s),
 		   s->sk_state, SOCK_INODE(s->sk_socket)->i_uid);
 out:
 	return 0;
diff --git a/net/irda/af_irda.c b/net/irda/af_irda.c
index 3eb5bcc75f99..5922febe25c4 100644
--- a/net/irda/af_irda.c
+++ b/net/irda/af_irda.c
@@ -1762,7 +1762,8 @@ static int irda_ioctl(struct socket *sock, unsigned int cmd, unsigned long arg)
 	switch (cmd) {
 	case TIOCOUTQ: {
 		long amount;
-		amount = sk->sk_sndbuf - atomic_read(&sk->sk_wmem_alloc);
+
+		amount = sk->sk_sndbuf - sk_wmem_alloc_get(sk);
 		if (amount < 0)
 			amount = 0;
 		if (put_user(amount, (unsigned int __user *)arg))
diff --git a/net/key/af_key.c b/net/key/af_key.c
index 643c1be2d02e..dba9abd27f90 100644
--- a/net/key/af_key.c
+++ b/net/key/af_key.c
@@ -3662,8 +3662,8 @@ static int pfkey_seq_show(struct seq_file *f, void *v)
 		seq_printf(f ,"%p %-6d %-6u %-6u %-6u %-6lu\n",
 			       s,
 			       atomic_read(&s->sk_refcnt),
-			       atomic_read(&s->sk_rmem_alloc),
-			       atomic_read(&s->sk_wmem_alloc),
+			       sk_rmem_alloc_get(s),
+			       sk_wmem_alloc_get(s),
 			       sock_i_uid(s),
 			       sock_i_ino(s)
 			       );
diff --git a/net/llc/llc_proc.c b/net/llc/llc_proc.c
index d208b3396d94..f97be471fe2e 100644
--- a/net/llc/llc_proc.c
+++ b/net/llc/llc_proc.c
@@ -134,8 +134,8 @@ static int llc_seq_socket_show(struct seq_file *seq, void *v)
 	seq_printf(seq, "@%02X ", llc->sap->laddr.lsap);
 	llc_ui_format_mac(seq, llc->daddr.mac);
 	seq_printf(seq, "@%02X %8d %8d %2d %3d %4d\n", llc->daddr.lsap,
-		   atomic_read(&sk->sk_wmem_alloc),
-		   atomic_read(&sk->sk_rmem_alloc) - llc->copied_seq,
+		   sk_wmem_alloc_get(sk),
+		   sk_rmem_alloc_get(sk) - llc->copied_seq,
 		   sk->sk_state,
 		   sk->sk_socket ? SOCK_INODE(sk->sk_socket)->i_uid : -1,
 		   llc->link);
diff --git a/net/netlink/af_netlink.c b/net/netlink/af_netlink.c
index 8b6bbb3032b0..2936fa3b6dc8 100644
--- a/net/netlink/af_netlink.c
+++ b/net/netlink/af_netlink.c
@@ -1914,8 +1914,8 @@ static int netlink_seq_show(struct seq_file *seq, void *v)
 			   s->sk_protocol,
 			   nlk->pid,
 			   nlk->groups ? (u32)nlk->groups[0] : 0,
-			   atomic_read(&s->sk_rmem_alloc),
-			   atomic_read(&s->sk_wmem_alloc),
+			   sk_rmem_alloc_get(s),
+			   sk_wmem_alloc_get(s),
 			   nlk->cb,
 			   atomic_read(&s->sk_refcnt),
 			   atomic_read(&s->sk_drops)
diff --git a/net/netrom/af_netrom.c b/net/netrom/af_netrom.c
index cd911904cbe1..ce51ce012cda 100644
--- a/net/netrom/af_netrom.c
+++ b/net/netrom/af_netrom.c
@@ -1205,7 +1205,7 @@ static int nr_ioctl(struct socket *sock, unsigned int cmd, unsigned long arg)
 		long amount;
 
 		lock_sock(sk);
-		amount = sk->sk_sndbuf - atomic_read(&sk->sk_wmem_alloc);
+		amount = sk->sk_sndbuf - sk_wmem_alloc_get(sk);
 		if (amount < 0)
 			amount = 0;
 		release_sock(sk);
@@ -1341,8 +1341,8 @@ static int nr_info_show(struct seq_file *seq, void *v)
 			nr->n2count,
 			nr->n2,
 			nr->window,
-			atomic_read(&s->sk_wmem_alloc),
-			atomic_read(&s->sk_rmem_alloc),
+			sk_wmem_alloc_get(s),
+			sk_rmem_alloc_get(s),
 			s->sk_socket ? SOCK_INODE(s->sk_socket)->i_ino : 0L);
 
 		bh_unlock_sock(s);
diff --git a/net/packet/af_packet.c b/net/packet/af_packet.c
index 4f76e5552d8e..ebe5718baa31 100644
--- a/net/packet/af_packet.c
+++ b/net/packet/af_packet.c
@@ -1987,7 +1987,8 @@ static int packet_ioctl(struct socket *sock, unsigned int cmd,
 	switch (cmd) {
 		case SIOCOUTQ:
 		{
-			int amount = atomic_read(&sk->sk_wmem_alloc);
+			int amount = sk_wmem_alloc_get(sk);
+
 			return put_user(amount, (int __user *)arg);
 		}
 		case SIOCINQ:
diff --git a/net/rose/af_rose.c b/net/rose/af_rose.c
index 4dd9a7d18945..6bd8e93869ed 100644
--- a/net/rose/af_rose.c
+++ b/net/rose/af_rose.c
@@ -1309,7 +1309,8 @@ static int rose_ioctl(struct socket *sock, unsigned int cmd, unsigned long arg)
 	switch (cmd) {
 	case TIOCOUTQ: {
 		long amount;
-		amount = sk->sk_sndbuf - atomic_read(&sk->sk_wmem_alloc);
+
+		amount = sk->sk_sndbuf - sk_wmem_alloc_get(sk);
 		if (amount < 0)
 			amount = 0;
 		return put_user(amount, (unsigned int __user *) argp);
@@ -1480,8 +1481,8 @@ static int rose_info_show(struct seq_file *seq, void *v)
 			rose->hb / HZ,
 			ax25_display_timer(&rose->idletimer) / (60 * HZ),
 			rose->idle / (60 * HZ),
-			atomic_read(&s->sk_wmem_alloc),
-			atomic_read(&s->sk_rmem_alloc),
+			sk_wmem_alloc_get(s),
+			sk_rmem_alloc_get(s),
 			s->sk_socket ? SOCK_INODE(s->sk_socket)->i_ino : 0L);
 	}
 
diff --git a/net/sched/em_meta.c b/net/sched/em_meta.c
index 266151ae85a3..18d85d259104 100644
--- a/net/sched/em_meta.c
+++ b/net/sched/em_meta.c
@@ -349,13 +349,13 @@ META_COLLECTOR(int_sk_type)
 META_COLLECTOR(int_sk_rmem_alloc)
 {
 	SKIP_NONLOCAL(skb);
-	dst->value = atomic_read(&skb->sk->sk_rmem_alloc);
+	dst->value = sk_rmem_alloc_get(skb->sk);
 }
 
 META_COLLECTOR(int_sk_wmem_alloc)
 {
 	SKIP_NONLOCAL(skb);
-	dst->value = atomic_read(&skb->sk->sk_wmem_alloc);
+	dst->value = sk_wmem_alloc_get(skb->sk);
 }
 
 META_COLLECTOR(int_sk_omem_alloc)
diff --git a/net/sctp/socket.c b/net/sctp/socket.c
index 0f01e5d8a24f..35ba035970a2 100644
--- a/net/sctp/socket.c
+++ b/net/sctp/socket.c
@@ -130,7 +130,7 @@ static inline int sctp_wspace(struct sctp_association *asoc)
 	if (asoc->ep->sndbuf_policy)
 		amt = asoc->sndbuf_used;
 	else
-		amt = atomic_read(&asoc->base.sk->sk_wmem_alloc);
+		amt = sk_wmem_alloc_get(asoc->base.sk);
 
 	if (amt >= asoc->base.sk->sk_sndbuf) {
 		if (asoc->base.sk->sk_userlocks & SOCK_SNDBUF_LOCK)
@@ -6523,7 +6523,7 @@ static int sctp_writeable(struct sock *sk)
 {
 	int amt = 0;
 
-	amt = sk->sk_sndbuf - atomic_read(&sk->sk_wmem_alloc);
+	amt = sk->sk_sndbuf - sk_wmem_alloc_get(sk);
 	if (amt < 0)
 		amt = 0;
 	return amt;
diff --git a/net/unix/af_unix.c b/net/unix/af_unix.c
index 9dcc6e7f96ec..36d4e44d6233 100644
--- a/net/unix/af_unix.c
+++ b/net/unix/af_unix.c
@@ -1946,7 +1946,7 @@ static int unix_ioctl(struct socket *sock, unsigned int cmd, unsigned long arg)
 
 	switch (cmd) {
 	case SIOCOUTQ:
-		amount = atomic_read(&sk->sk_wmem_alloc);
+		amount = sk_wmem_alloc_get(sk);
 		err = put_user(amount, (int __user *)arg);
 		break;
 	case SIOCINQ:
diff --git a/net/x25/af_x25.c b/net/x25/af_x25.c
index 8cd2390b0d45..21cdc872004e 100644
--- a/net/x25/af_x25.c
+++ b/net/x25/af_x25.c
@@ -1271,8 +1271,8 @@ static int x25_ioctl(struct socket *sock, unsigned int cmd, unsigned long arg)
 
 	switch (cmd) {
 		case TIOCOUTQ: {
-			int amount = sk->sk_sndbuf -
-				     atomic_read(&sk->sk_wmem_alloc);
+			int amount = sk->sk_sndbuf - sk_wmem_alloc_get(sk);
+
 			if (amount < 0)
 				amount = 0;
 			rc = put_user(amount, (unsigned int __user *)argp);
diff --git a/net/x25/x25_proc.c b/net/x25/x25_proc.c
index 1afa44d25beb..0a04e62e0e18 100644
--- a/net/x25/x25_proc.c
+++ b/net/x25/x25_proc.c
@@ -163,8 +163,8 @@ static int x25_seq_socket_show(struct seq_file *seq, void *v)
 		   devname, x25->lci & 0x0FFF, x25->state, x25->vs, x25->vr,
 		   x25->va, x25_display_timer(s) / HZ, x25->t2  / HZ,
 		   x25->t21 / HZ, x25->t22 / HZ, x25->t23 / HZ,
-		   atomic_read(&s->sk_wmem_alloc),
-		   atomic_read(&s->sk_rmem_alloc),
+		   sk_wmem_alloc_get(s),
+		   sk_rmem_alloc_get(s),
 		   s->sk_socket ? SOCK_INODE(s->sk_socket)->i_ino : 0L);
 out:
 	return 0;
-- 
cgit v1.2.2


From 81e2a3d5b75cbf0b42428b9d5a7cc7c85be9e7a7 Mon Sep 17 00:00:00 2001
From: Eric Dumazet <eric.dumazet@gmail.com>
Date: Wed, 17 Jun 2009 19:06:12 -0700
Subject: atm: sk_wmem_alloc initial value is one

commit 2b85a34e911bf483c27cfdd124aeb1605145dc80
(net: No more expensive sock_hold()/sock_put() on each tx)
changed initial sk_wmem_alloc value.

This broke net/atm since this protocol assumed a null
initial value. This patch makes necessary changes.

Signed-off-by: Eric Dumazet <eric.dumazet@gmail.com>
Signed-off-by: David S. Miller <davem@davemloft.net>
---
 net/atm/common.c | 12 ++++++------
 net/atm/ioctl.c  |  3 +--
 net/atm/proc.c   |  4 ++--
 net/atm/raw.c    |  2 +-
 4 files changed, 10 insertions(+), 11 deletions(-)

(limited to 'net')

diff --git a/net/atm/common.c b/net/atm/common.c
index d34edbe754c8..c1c97936192c 100644
--- a/net/atm/common.c
+++ b/net/atm/common.c
@@ -62,15 +62,15 @@ static struct sk_buff *alloc_tx(struct atm_vcc *vcc,unsigned int size)
 	struct sk_buff *skb;
 	struct sock *sk = sk_atm(vcc);
 
-	if (atomic_read(&sk->sk_wmem_alloc) && !atm_may_send(vcc, size)) {
+	if (sk_wmem_alloc_get(sk) && !atm_may_send(vcc, size)) {
 		pr_debug("Sorry: wmem_alloc = %d, size = %d, sndbuf = %d\n",
-			atomic_read(&sk->sk_wmem_alloc), size,
+			sk_wmem_alloc_get(sk), size,
 			sk->sk_sndbuf);
 		return NULL;
 	}
-	while (!(skb = alloc_skb(size,GFP_KERNEL))) schedule();
-	pr_debug("AlTx %d += %d\n", atomic_read(&sk->sk_wmem_alloc),
-		skb->truesize);
+	while (!(skb = alloc_skb(size, GFP_KERNEL)))
+		schedule();
+	pr_debug("AlTx %d += %d\n", sk_wmem_alloc_get(sk), skb->truesize);
 	atomic_add(skb->truesize, &sk->sk_wmem_alloc);
 	return skb;
 }
@@ -145,7 +145,7 @@ int vcc_create(struct net *net, struct socket *sock, int protocol, int family)
 	memset(&vcc->local,0,sizeof(struct sockaddr_atmsvc));
 	memset(&vcc->remote,0,sizeof(struct sockaddr_atmsvc));
 	vcc->qos.txtp.max_sdu = 1 << 16; /* for meta VCs */
-	atomic_set(&sk->sk_wmem_alloc, 0);
+	atomic_set(&sk->sk_wmem_alloc, 1);
 	atomic_set(&sk->sk_rmem_alloc, 0);
 	vcc->push = NULL;
 	vcc->pop = NULL;
diff --git a/net/atm/ioctl.c b/net/atm/ioctl.c
index 76ed3c8d26e6..4da8892ced5f 100644
--- a/net/atm/ioctl.c
+++ b/net/atm/ioctl.c
@@ -63,8 +63,7 @@ static int do_vcc_ioctl(struct socket *sock, unsigned int cmd, unsigned long arg
 				error =  -EINVAL;
 				goto done;
 			}
-			error = put_user(sk->sk_sndbuf -
-					 atomic_read(&sk->sk_wmem_alloc),
+			error = put_user(sk->sk_sndbuf - sk_wmem_alloc_get(sk),
 					 (int __user *) argp) ? -EFAULT : 0;
 			goto done;
 		case SIOCINQ:
diff --git a/net/atm/proc.c b/net/atm/proc.c
index e7b3b273907d..38de5ff61ecd 100644
--- a/net/atm/proc.c
+++ b/net/atm/proc.c
@@ -204,8 +204,8 @@ static void vcc_info(struct seq_file *seq, struct atm_vcc *vcc)
 			seq_printf(seq, "%3d", sk->sk_family);
 	}
 	seq_printf(seq, " %04lx  %5d %7d/%7d %7d/%7d [%d]\n", vcc->flags, sk->sk_err,
-		  atomic_read(&sk->sk_wmem_alloc), sk->sk_sndbuf,
-		  atomic_read(&sk->sk_rmem_alloc), sk->sk_rcvbuf,
+		  sk_wmem_alloc_get(sk), sk->sk_sndbuf,
+		  sk_rmem_alloc_get(sk), sk->sk_rcvbuf,
 		  atomic_read(&sk->sk_refcnt));
 }
 
diff --git a/net/atm/raw.c b/net/atm/raw.c
index b0a2d8cb6744..cbfcc71a17b1 100644
--- a/net/atm/raw.c
+++ b/net/atm/raw.c
@@ -33,7 +33,7 @@ static void atm_pop_raw(struct atm_vcc *vcc,struct sk_buff *skb)
 	struct sock *sk = sk_atm(vcc);
 
 	pr_debug("APopR (%d) %d -= %d\n", vcc->vci,
-		atomic_read(&sk->sk_wmem_alloc), skb->truesize);
+		sk_wmem_alloc_get(sk), skb->truesize);
 	atomic_sub(skb->truesize, &sk->sk_wmem_alloc);
 	dev_kfree_skb_any(skb);
 	sk->sk_write_space(sk);
-- 
cgit v1.2.2