mirror of
https://github.com/SCST-project/scst.git
synced 2026-09-26 01:44:54 +00:00
source tree: - Support for zero-copy TCP transfer completion. - An implementation of scsi_execute_async_fifo(). Except for the hunk headers, these patches are identical to similarly named patches already present in the SCST source tree. Additionally, implementations of seq_list_start() and seq_list_next() are provided for those kernel versions that do not define these functions. The patch below has been tested by verifying that iSCSI data transfer still works OK on CentOS 5.2 (x86_64). Signed-off-by: Bart Van Assche <bart.vanassche@gmail.com> git-svn-id: http://svn.code.sf.net/p/scst/svn/trunk@657 d57e44dd-8a1f-0410-8b47-8ef2f437770f
258 lines
8.6 KiB
Diff
258 lines
8.6 KiB
Diff
diff -upr linux-2.6.18/include/linux/mm.h linux-2.6.18/include/linux/mm.h
|
|
--- linux-2.6.18/include/linux/mm.h 2006-09-20 07:42:06.000000000 +0400
|
|
+++ linux-2.6.18/include/linux/mm.h 2007-08-07 19:35:51.000000000 +0400
|
|
@@ -277,6 +277,15 @@ struct page {
|
|
void *virtual; /* Kernel virtual address (NULL if
|
|
not kmapped, ie. highmem) */
|
|
#endif /* WANT_PAGE_VIRTUAL */
|
|
+ /*
|
|
+ * Used to implement support for notification on zero-copy TCP transfer
|
|
+ * completion. Not good to have this field here, it's better to have
|
|
+ * it in struct sk_buff, but it would make the code much more
|
|
+ * complicated and fragile, if maintained as a separate patch, since all
|
|
+ * skb then would have to contain only pages with the same value in this
|
|
+ * field.
|
|
+ */
|
|
+ void *net_priv;
|
|
};
|
|
|
|
#define page_private(page) ((page)->private)
|
|
diff -upr linux-2.6.18/include/linux/net.h linux-2.6.18/include/linux/net.h
|
|
--- linux-2.6.18/include/linux/net.h 2006-09-20 07:42:06.000000000 +0400
|
|
+++ linux-2.6.18/include/linux/net.h 2007-08-29 18:28:21.000000000 +0400
|
|
@@ -56,6 +56,7 @@ typedef enum {
|
|
|
|
#ifdef __KERNEL__
|
|
#include <linux/stringify.h>
|
|
+#include <linux/mm.h>
|
|
|
|
#define SOCK_ASYNC_NOSPACE 0
|
|
#define SOCK_ASYNC_WAITDATA 1
|
|
@@ -324,5 +325,30 @@ extern int net_msg_cost;
|
|
extern int net_msg_burst;
|
|
#endif
|
|
|
|
+/* Support for notification on zero-copy TCP transfer completion */
|
|
+#define CONFIG_TCP_ZERO_COPY_TRANSFER_COMPLETION_NOTIFICATION
|
|
+typedef void (*net_get_page_callback_t)(struct page *page);
|
|
+typedef void (*net_put_page_callback_t)(struct page *page);
|
|
+
|
|
+extern net_get_page_callback_t net_get_page_callback;
|
|
+extern net_put_page_callback_t net_put_page_callback;
|
|
+
|
|
+extern int net_set_get_put_page_callbacks(
|
|
+ net_get_page_callback_t get_callback,
|
|
+ net_put_page_callback_t put_callback);
|
|
+
|
|
+static inline void net_get_page(struct page *page)
|
|
+{
|
|
+ if (page->net_priv != 0)
|
|
+ net_get_page_callback(page);
|
|
+ get_page(page);
|
|
+}
|
|
+static inline void net_put_page(struct page *page)
|
|
+{
|
|
+ if (page->net_priv != 0)
|
|
+ net_put_page_callback(page);
|
|
+ put_page(page);
|
|
+}
|
|
+
|
|
#endif /* __KERNEL__ */
|
|
#endif /* _LINUX_NET_H */
|
|
diff -upr linux-2.6.18/net/core/skbuff.c linux-2.6.18/net/core/skbuff.c
|
|
--- linux-2.6.18/net/core/skbuff.c 2006-09-20 07:42:06.000000000 +0400
|
|
+++ linux-2.6.18/net/core/skbuff.c 2007-08-07 19:35:51.000000000 +0400
|
|
@@ -324,7 +324,7 @@ static void skb_release_data(struct sk_b
|
|
if (skb_shinfo(skb)->nr_frags) {
|
|
int i;
|
|
for (i = 0; i < skb_shinfo(skb)->nr_frags; i++)
|
|
- put_page(skb_shinfo(skb)->frags[i].page);
|
|
+ net_put_page(skb_shinfo(skb)->frags[i].page);
|
|
}
|
|
|
|
if (skb_shinfo(skb)->frag_list)
|
|
@@ -666,7 +666,7 @@ struct sk_buff *pskb_copy(struct sk_buff
|
|
|
|
for (i = 0; i < skb_shinfo(skb)->nr_frags; i++) {
|
|
skb_shinfo(n)->frags[i] = skb_shinfo(skb)->frags[i];
|
|
- get_page(skb_shinfo(n)->frags[i].page);
|
|
+ net_get_page(skb_shinfo(n)->frags[i].page);
|
|
}
|
|
skb_shinfo(n)->nr_frags = i;
|
|
}
|
|
@@ -720,7 +720,7 @@ int pskb_expand_head(struct sk_buff *skb
|
|
memcpy(data + size, skb->end, sizeof(struct skb_shared_info));
|
|
|
|
for (i = 0; i < skb_shinfo(skb)->nr_frags; i++)
|
|
- get_page(skb_shinfo(skb)->frags[i].page);
|
|
+ net_get_page(skb_shinfo(skb)->frags[i].page);
|
|
|
|
if (skb_shinfo(skb)->frag_list)
|
|
skb_clone_fraglist(skb);
|
|
@@ -902,7 +902,7 @@ drop_pages:
|
|
skb_shinfo(skb)->nr_frags = i;
|
|
|
|
for (; i < nfrags; i++)
|
|
- put_page(skb_shinfo(skb)->frags[i].page);
|
|
+ net_put_page(skb_shinfo(skb)->frags[i].page);
|
|
|
|
if (skb_shinfo(skb)->frag_list)
|
|
skb_drop_fraglist(skb);
|
|
@@ -1071,7 +1071,7 @@ pull_pages:
|
|
k = 0;
|
|
for (i = 0; i < skb_shinfo(skb)->nr_frags; i++) {
|
|
if (skb_shinfo(skb)->frags[i].size <= eat) {
|
|
- put_page(skb_shinfo(skb)->frags[i].page);
|
|
+ net_put_page(skb_shinfo(skb)->frags[i].page);
|
|
eat -= skb_shinfo(skb)->frags[i].size;
|
|
} else {
|
|
skb_shinfo(skb)->frags[k] = skb_shinfo(skb)->frags[i];
|
|
@@ -1653,7 +1653,7 @@ static inline void skb_split_no_header(s
|
|
* where splitting is expensive.
|
|
* 2. Split is accurately. We make this.
|
|
*/
|
|
- get_page(skb_shinfo(skb)->frags[i].page);
|
|
+ net_get_page(skb_shinfo(skb)->frags[i].page);
|
|
skb_shinfo(skb1)->frags[0].page_offset += len - pos;
|
|
skb_shinfo(skb1)->frags[0].size -= len - pos;
|
|
skb_shinfo(skb)->frags[i].size = len - pos;
|
|
@@ -2021,7 +2021,7 @@ struct sk_buff *skb_segment(struct sk_bu
|
|
BUG_ON(i >= nfrags);
|
|
|
|
*frag = skb_shinfo(skb)->frags[i];
|
|
- get_page(frag->page);
|
|
+ net_get_page(frag->page);
|
|
size = frag->size;
|
|
|
|
if (pos < offset) {
|
|
diff -upr linux-2.6.18/net/core/utils.c linux-2.6.18/net/core/utils.c
|
|
--- linux-2.6.18/net/core/utils.c 2006-09-20 07:42:06.000000000 +0400
|
|
+++ linux-2.6.18/net/core/utils.c 2007-08-23 19:49:40.000000000 +0400
|
|
@@ -24,11 +24,15 @@
|
|
#include <linux/random.h>
|
|
#include <linux/percpu.h>
|
|
#include <linux/init.h>
|
|
+#include <linux/skbuff.h>
|
|
|
|
#include <asm/byteorder.h>
|
|
#include <asm/system.h>
|
|
#include <asm/uaccess.h>
|
|
|
|
+net_get_page_callback_t net_get_page_callback __read_mostly;
|
|
+net_put_page_callback_t net_put_page_callback __read_mostly;
|
|
+
|
|
/*
|
|
This is a maximally equidistributed combined Tausworthe generator
|
|
based on code from GNU Scientific Library 1.5 (30 Jun 2004)
|
|
@@ -203,3 +203,32 @@ __be32 in_aton(const char *str)
|
|
}
|
|
|
|
EXPORT_SYMBOL(in_aton);
|
|
+
|
|
+int net_set_get_put_page_callbacks(
|
|
+ net_get_page_callback_t get_callback,
|
|
+ net_put_page_callback_t put_callback)
|
|
+{
|
|
+ int res = 0;
|
|
+
|
|
+ if ((net_get_page_callback != NULL) && (get_callback != NULL) &&
|
|
+ (net_get_page_callback != get_callback)) {
|
|
+ res = -EBUSY;
|
|
+ goto out;
|
|
+ }
|
|
+
|
|
+ if ((net_put_page_callback != NULL) && (put_callback != NULL) &&
|
|
+ (net_put_page_callback != put_callback)) {
|
|
+ res = -EBUSY;
|
|
+ goto out;
|
|
+ }
|
|
+
|
|
+ net_get_page_callback = get_callback;
|
|
+ net_put_page_callback = put_callback;
|
|
+
|
|
+out:
|
|
+ return res;
|
|
+}
|
|
+EXPORT_SYMBOL(net_set_get_put_page_callbacks);
|
|
+
|
|
+EXPORT_SYMBOL(net_get_page_callback);
|
|
+EXPORT_SYMBOL(net_put_page_callback);
|
|
diff -upr linux-2.6.18/net/ipv4/ip_output.c linux-2.6.18/net/ipv4/ip_output.c
|
|
--- linux-2.6.18/net/ipv4/ip_output.c 2006-09-20 07:42:06.000000000 +0400
|
|
+++ linux-2.6.18/net/ipv4/ip_output.c 2007-08-07 19:37:24.000000000 +0400
|
|
@@ -1006,7 +1006,7 @@ alloc_new_skb:
|
|
err = -EMSGSIZE;
|
|
goto error;
|
|
}
|
|
- get_page(page);
|
|
+ net_get_page(page);
|
|
skb_fill_page_desc(skb, i, page, sk->sk_sndmsg_off, 0);
|
|
frag = &skb_shinfo(skb)->frags[i];
|
|
}
|
|
@@ -1166,7 +1166,7 @@ ssize_t ip_append_page(struct sock *sk,
|
|
if (skb_can_coalesce(skb, i, page, offset)) {
|
|
skb_shinfo(skb)->frags[i-1].size += len;
|
|
} else if (i < MAX_SKB_FRAGS) {
|
|
- get_page(page);
|
|
+ net_get_page(page);
|
|
skb_fill_page_desc(skb, i, page, offset, len);
|
|
} else {
|
|
err = -EMSGSIZE;
|
|
diff -upr linux-2.6.18/net/ipv4/tcp.c linux-2.6.18/net/ipv4/tcp.c
|
|
--- linux-2.6.18/net/ipv4/tcp.c 2006-09-20 07:42:06.000000000 +0400
|
|
+++ linux-2.6.18/net/ipv4/tcp.c 2007-08-07 19:35:51.000000000 +0400
|
|
@@ -560,7 +560,7 @@ new_segment:
|
|
if (can_coalesce) {
|
|
skb_shinfo(skb)->frags[i - 1].size += copy;
|
|
} else {
|
|
- get_page(page);
|
|
+ net_get_page(page);
|
|
skb_fill_page_desc(skb, i, page, offset, copy);
|
|
}
|
|
|
|
@@ -763,7 +763,7 @@ new_segment:
|
|
goto new_segment;
|
|
} else if (page) {
|
|
if (off == PAGE_SIZE) {
|
|
- put_page(page);
|
|
+ net_put_page(page);
|
|
TCP_PAGE(sk) = page = NULL;
|
|
off = 0;
|
|
}
|
|
@@ -804,9 +804,9 @@ new_segment:
|
|
} else {
|
|
skb_fill_page_desc(skb, i, page, off, copy);
|
|
if (TCP_PAGE(sk)) {
|
|
- get_page(page);
|
|
+ net_get_page(page);
|
|
} else if (off + copy < PAGE_SIZE) {
|
|
- get_page(page);
|
|
+ net_get_page(page);
|
|
TCP_PAGE(sk) = page;
|
|
}
|
|
}
|
|
diff -upr linux-2.6.18/net/ipv4/tcp_output.c linux-2.6.18/net/ipv4/tcp_output.c
|
|
--- linux-2.6.18/net/ipv4/tcp_output.c 2006-09-20 07:42:06.000000000 +0400
|
|
+++ linux-2.6.18/net/ipv4/tcp_output.c 2007-08-07 19:35:51.000000000 +0400
|
|
@@ -659,7 +659,7 @@ static void __pskb_trim_head(struct sk_b
|
|
k = 0;
|
|
for (i=0; i<skb_shinfo(skb)->nr_frags; i++) {
|
|
if (skb_shinfo(skb)->frags[i].size <= eat) {
|
|
- put_page(skb_shinfo(skb)->frags[i].page);
|
|
+ net_put_page(skb_shinfo(skb)->frags[i].page);
|
|
eat -= skb_shinfo(skb)->frags[i].size;
|
|
} else {
|
|
skb_shinfo(skb)->frags[k] = skb_shinfo(skb)->frags[i];
|
|
diff -upr linux-2.6.18/net/ipv6/ip6_output.c linux-2.6.18/net/ipv6/ip6_output.c
|
|
--- linux-2.6.18/net/ipv6/ip6_output.c 2006-09-20 07:42:06.000000000 +0400
|
|
+++ linux-2.6.18/net/ipv6/ip6_output.c 2007-08-07 19:35:51.000000000 +0400
|
|
@@ -1212,7 +1212,7 @@ alloc_new_skb:
|
|
err = -EMSGSIZE;
|
|
goto error;
|
|
}
|
|
- get_page(page);
|
|
+ net_get_page(page);
|
|
skb_fill_page_desc(skb, i, page, sk->sk_sndmsg_off, 0);
|
|
frag = &skb_shinfo(skb)->frags[i];
|
|
}
|