summaryrefslogtreecommitdiff
path: root/net/core/skbuff.c
diff options
context:
space:
mode:
authorLinus Torvalds <torvalds@linux-foundation.org>2010-06-01 08:13:20 -0700
committerLinus Torvalds <torvalds@linux-foundation.org>2010-06-01 08:13:20 -0700
commit076dab234d29d1c0d60e26a5fa48aabb7fa58f79 (patch)
tree4dbd92007635b59830e1a73bb355f74b4b2d79f0 /net/core/skbuff.c
parente30c7c3b306312c157d67eedd6a01920518b756c (diff)
parentb42d9165e1e3d92e4e3318642463dbe592a12568 (diff)
Merge git://git.kernel.org/pub/scm/linux/kernel/git/davem/net-2.6
* git://git.kernel.org/pub/scm/linux/kernel/git/davem/net-2.6: (28 commits) drivers/isdn/hardware/mISDN: Use GFP_ATOMIC when a lock is held ksz884x: Add missing validate_addr hook ksz884x: convert to netdev_tx_t virtio-net: pass gfp to add_buf be2net: convert hdr.timeout in be_cmd_loopback_test() to le32 can: mpc5xxx_can.c: Fix build failure net/ipv4/tcp_input.c: fix compilation breakage when FASTRETRANS_DEBUG > 1 net: sock_queue_err_skb() dont mess with sk_forward_alloc netfilter: xtables: stackptr should be percpu netfilter: don't xt_jumpstack_alloc twice in xt_register_table greth: Fix build after OF device conversions. net: fix sk_forward_alloc corruptions Phonet: listening socket lock protects the connected socket list caif: unlock on error path in cfserl_receive() be2net: remove superfluous externs be2net: add unlock on error path net/rds: Add missing mutex_unlock drivers/isdn/hardware/mISDN: Add missing spin_unlock fs_enet: Adjust BDs after tx error skb: make skb_recycle_check() return a bool value ...
Diffstat (limited to 'net/core/skbuff.c')
-rw-r--r--net/core/skbuff.c42
1 files changed, 36 insertions, 6 deletions
diff --git a/net/core/skbuff.c b/net/core/skbuff.c
index f8abf68e3988..9f07e749d7b1 100644
--- a/net/core/skbuff.c
+++ b/net/core/skbuff.c
@@ -482,22 +482,22 @@ EXPORT_SYMBOL(consume_skb);
* reference count dropping and cleans up the skbuff as if it
* just came from __alloc_skb().
*/
-int skb_recycle_check(struct sk_buff *skb, int skb_size)
+bool skb_recycle_check(struct sk_buff *skb, int skb_size)
{
struct skb_shared_info *shinfo;
if (irqs_disabled())
- return 0;
+ return false;
if (skb_is_nonlinear(skb) || skb->fclone != SKB_FCLONE_UNAVAILABLE)
- return 0;
+ return false;
skb_size = SKB_DATA_ALIGN(skb_size + NET_SKB_PAD);
if (skb_end_pointer(skb) - skb->head < skb_size)
- return 0;
+ return false;
if (skb_shared(skb) || skb_cloned(skb))
- return 0;
+ return false;
skb_release_head_state(skb);
@@ -509,7 +509,7 @@ int skb_recycle_check(struct sk_buff *skb, int skb_size)
skb->data = skb->head + NET_SKB_PAD;
skb_reset_tail_pointer(skb);
- return 1;
+ return true;
}
EXPORT_SYMBOL(skb_recycle_check);
@@ -2965,6 +2965,34 @@ int skb_cow_data(struct sk_buff *skb, int tailbits, struct sk_buff **trailer)
}
EXPORT_SYMBOL_GPL(skb_cow_data);
+static void sock_rmem_free(struct sk_buff *skb)
+{
+ struct sock *sk = skb->sk;
+
+ atomic_sub(skb->truesize, &sk->sk_rmem_alloc);
+}
+
+/*
+ * Note: We dont mem charge error packets (no sk_forward_alloc changes)
+ */
+int sock_queue_err_skb(struct sock *sk, struct sk_buff *skb)
+{
+ if (atomic_read(&sk->sk_rmem_alloc) + skb->truesize >=
+ (unsigned)sk->sk_rcvbuf)
+ return -ENOMEM;
+
+ skb_orphan(skb);
+ skb->sk = sk;
+ skb->destructor = sock_rmem_free;
+ atomic_add(skb->truesize, &sk->sk_rmem_alloc);
+
+ skb_queue_tail(&sk->sk_error_queue, skb);
+ if (!sock_flag(sk, SOCK_DEAD))
+ sk->sk_data_ready(sk, skb->len);
+ return 0;
+}
+EXPORT_SYMBOL(sock_queue_err_skb);
+
void skb_tstamp_tx(struct sk_buff *orig_skb,
struct skb_shared_hwtstamps *hwtstamps)
{
@@ -2996,7 +3024,9 @@ void skb_tstamp_tx(struct sk_buff *orig_skb,
memset(serr, 0, sizeof(*serr));
serr->ee.ee_errno = ENOMSG;
serr->ee.ee_origin = SO_EE_ORIGIN_TIMESTAMPING;
+
err = sock_queue_err_skb(sk, skb);
+
if (err)
kfree_skb(skb);
}