summaryrefslogtreecommitdiff
path: root/net/core
diff options
context:
space:
mode:
authorLinus Torvalds <torvalds@g5.osdl.org>2005-09-29 08:56:47 -0700
committerLinus Torvalds <torvalds@g5.osdl.org>2005-09-29 08:56:47 -0700
commiteb693d2994eb762b2201aead31066265ab0be20b (patch)
tree424e1e7f3d272d0fd5888435176b386594ce121f /net/core
parent6dec3cf5cdb600f39b9eac3349f6bf50eab87731 (diff)
parent01d40f28b125e0a9aa0ec24642be67fc4c5dfaff (diff)
Merge master.kernel.org:/pub/scm/linux/kernel/git/davem/net-2.6
Diffstat (limited to 'net/core')
-rw-r--r--net/core/datagram.c81
-rw-r--r--net/core/dev.c2
-rw-r--r--net/core/sock.c20
3 files changed, 40 insertions, 63 deletions
diff --git a/net/core/datagram.c b/net/core/datagram.c
index da9bf71421a7..81987df536eb 100644
--- a/net/core/datagram.c
+++ b/net/core/datagram.c
@@ -211,74 +211,45 @@ void skb_free_datagram(struct sock *sk, struct sk_buff *skb)
int skb_copy_datagram_iovec(const struct sk_buff *skb, int offset,
struct iovec *to, int len)
{
- int start = skb_headlen(skb);
- int i, copy = start - offset;
-
- /* Copy header. */
- if (copy > 0) {
- if (copy > len)
- copy = len;
- if (memcpy_toiovec(to, skb->data + offset, copy))
- goto fault;
- if ((len -= copy) == 0)
- return 0;
- offset += copy;
- }
+ int i, err, fraglen, end = 0;
+ struct sk_buff *next = skb_shinfo(skb)->frag_list;
+next_skb:
+ fraglen = skb_headlen(skb);
+ i = -1;
- /* Copy paged appendix. Hmm... why does this look so complicated? */
- for (i = 0; i < skb_shinfo(skb)->nr_frags; i++) {
- int end;
-
- BUG_TRAP(start <= offset + len);
+ while (1) {
+ int start = end;
- end = start + skb_shinfo(skb)->frags[i].size;
- if ((copy = end - offset) > 0) {
- int err;
- u8 *vaddr;
- skb_frag_t *frag = &skb_shinfo(skb)->frags[i];
- struct page *page = frag->page;
+ if ((end += fraglen) > offset) {
+ int copy = end - offset, o = offset - start;
if (copy > len)
copy = len;
- vaddr = kmap(page);
- err = memcpy_toiovec(to, vaddr + frag->page_offset +
- offset - start, copy);
- kunmap(page);
+ if (i == -1)
+ err = memcpy_toiovec(to, skb->data + o, copy);
+ else {
+ skb_frag_t *frag = &skb_shinfo(skb)->frags[i];
+ struct page *page = frag->page;
+ void *p = kmap(page) + frag->page_offset + o;
+ err = memcpy_toiovec(to, p, copy);
+ kunmap(page);
+ }
if (err)
goto fault;
if (!(len -= copy))
return 0;
offset += copy;
}
- start = end;
+ if (++i >= skb_shinfo(skb)->nr_frags)
+ break;
+ fraglen = skb_shinfo(skb)->frags[i].size;
}
-
- if (skb_shinfo(skb)->frag_list) {
- struct sk_buff *list = skb_shinfo(skb)->frag_list;
-
- for (; list; list = list->next) {
- int end;
-
- BUG_TRAP(start <= offset + len);
-
- end = start + list->len;
- if ((copy = end - offset) > 0) {
- if (copy > len)
- copy = len;
- if (skb_copy_datagram_iovec(list,
- offset - start,
- to, copy))
- goto fault;
- if ((len -= copy) == 0)
- return 0;
- offset += copy;
- }
- start = end;
- }
+ if (next) {
+ skb = next;
+ BUG_ON(skb_shinfo(skb)->frag_list);
+ next = skb->next;
+ goto next_skb;
}
- if (!len)
- return 0;
-
fault:
return -EFAULT;
}
diff --git a/net/core/dev.c b/net/core/dev.c
index 37c881070963..9066c874e273 100644
--- a/net/core/dev.c
+++ b/net/core/dev.c
@@ -1259,6 +1259,8 @@ int dev_queue_xmit(struct sk_buff *skb)
if (skb_checksum_help(skb, 0))
goto out_kfree_skb;
+ spin_lock_prefetch(&dev->queue_lock);
+
/* Disable soft irqs for various locks below. Also
* stops preemption for RCU.
*/
diff --git a/net/core/sock.c b/net/core/sock.c
index ac63b56e23b2..928d2a1d6d8e 100644
--- a/net/core/sock.c
+++ b/net/core/sock.c
@@ -660,16 +660,20 @@ struct sock *sk_alloc(int family, unsigned int __nocast priority,
sock_lock_init(sk);
}
- if (security_sk_alloc(sk, family, priority)) {
- if (slab != NULL)
- kmem_cache_free(slab, sk);
- else
- kfree(sk);
- sk = NULL;
- } else
- __module_get(prot->owner);
+ if (security_sk_alloc(sk, family, priority))
+ goto out_free;
+
+ if (!try_module_get(prot->owner))
+ goto out_free;
}
return sk;
+
+out_free:
+ if (slab != NULL)
+ kmem_cache_free(slab, sk);
+ else
+ kfree(sk);
+ return NULL;
}
void sk_free(struct sock *sk)