The patch below adds the following two RHEL 5 / CentOS 5 patches to the SCST
authorvlnb <vlnb@d57e44dd-8a1f-0410-8b47-8ef2f437770f>
Mon, 2 Feb 2009 11:36:53 +0000 (11:36 +0000)
committervlnb <vlnb@d57e44dd-8a1f-0410-8b47-8ef2f437770f>
Mon, 2 Feb 2009 11:36:53 +0000 (11:36 +0000)
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: https://scst.svn.sourceforge.net/svnroot/scst/trunk@657 d57e44dd-8a1f-0410-8b47-8ef2f437770f

iscsi-scst/kernel/patches/rhel/put_page_callback-rhel5.patch [new file with mode: 0644]
iscsi-scst/kernel/target.c
scst/kernel/rhel/scst_exec_req_fifo-rhel5.patch [new file with mode: 0644]

diff --git a/iscsi-scst/kernel/patches/rhel/put_page_callback-rhel5.patch b/iscsi-scst/kernel/patches/rhel/put_page_callback-rhel5.patch
new file mode 100644 (file)
index 0000000..01a1c7e
--- /dev/null
@@ -0,0 +1,257 @@
+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];
+                               }
index 585b467..483ef65 100644 (file)
@@ -299,6 +299,29 @@ void target_del_all(void)
        return;
 }
 
+#if LINUX_VERSION_CODE < KERNEL_VERSION(2, 6, 19)
+static struct list_head *seq_list_start(struct list_head *head, loff_t pos)
+{
+       struct list_head *lh;
+
+       list_for_each(lh, head)
+               if (pos-- == 0)
+                       return lh;
+
+       return NULL;
+}
+
+static struct list_head *seq_list_next(void *v, struct list_head *head,
+                                      loff_t *ppos)
+{
+       struct list_head *lh;
+
+       lh = ((struct list_head *)v)->next;
+       ++*ppos;
+       return lh == head ? NULL : lh;
+}
+#endif
+
 static void *iscsi_seq_start(struct seq_file *m, loff_t *pos)
 {
        int err;
diff --git a/scst/kernel/rhel/scst_exec_req_fifo-rhel5.patch b/scst/kernel/rhel/scst_exec_req_fifo-rhel5.patch
new file mode 100644 (file)
index 0000000..5fcf7b2
--- /dev/null
@@ -0,0 +1,109 @@
+diff -upr linux-2.6.18/drivers/scsi/scsi_lib.c linux-2.6.18/drivers/scsi/scsi_lib.c
+--- linux-2.6.18/drivers/scsi/scsi_lib.c       2006-09-20 07:42:06.000000000 +0400
++++ linux-2.6.18/drivers/scsi/scsi_lib.c       2007-07-04 21:15:32.000000000 +0400
+@@ -367,7 +367,7 @@ free_bios:
+ }
+ /**
+- * scsi_execute_async - insert request
++ * __scsi_execute_async - insert request
+  * @sdev:     scsi device
+  * @cmd:      scsi command
+  * @cmd_len:  length of scsi cdb
+@@ -378,11 +378,14 @@ free_bios:
+  * @timeout:  request timeout in seconds
+  * @retries:  number of times to retry request
+  * @flags:    or into request flags
++ * @at_head:  insert request at head or tail of queue
+  **/
+-int scsi_execute_async(struct scsi_device *sdev, const unsigned char *cmd,
++static inline int __scsi_execute_async(struct scsi_device *sdev,
++                     const unsigned char *cmd,
+                      int cmd_len, int data_direction, void *buffer, unsigned bufflen,
+                      int use_sg, int timeout, int retries, void *privdata,
+-                     void (*done)(void *, char *, int, int), gfp_t gfp)
++                     void (*done)(void *, char *, int, int), gfp_t gfp,
++                     int at_head)
+ {
+       struct request *req;
+       struct scsi_io_context *sioc;
+@@ -418,7 +421,7 @@ int scsi_execute_async(struct scsi_devic
+       sioc->data = privdata;
+       sioc->done = done;
+-      blk_execute_rq_nowait(req->q, NULL, req, 1, scsi_end_async);
++      blk_execute_rq_nowait(req->q, NULL, req, at_head, scsi_end_async);
+       return 0;
+ free_req:
+@@ -427,8 +430,53 @@ free_sense:
+       kfree(sioc);
+       return DRIVER_ERROR << 24;
+ }
++
++/**
++ * scsi_execute_async - insert request
++ * @sdev:     scsi device
++ * @cmd:      scsi command
++ * @cmd_len:  length of scsi cdb
++ * @data_direction: data direction
++ * @buffer:   data buffer (this can be a kernel buffer or scatterlist)
++ * @bufflen:  len of buffer
++ * @use_sg:   if buffer is a scatterlist this is the number of elements
++ * @timeout:  request timeout in seconds
++ * @retries:  number of times to retry request
++ * @flags:    or into request flags
++ **/
++int scsi_execute_async(struct scsi_device *sdev, const unsigned char *cmd,
++                     int cmd_len, int data_direction, void *buffer, unsigned bufflen,
++                     int use_sg, int timeout, int retries, void *privdata,
++                     void (*done)(void *, char *, int, int), gfp_t gfp)
++{
++      return __scsi_execute_async(sdev, cmd, cmd_len, data_direction, buffer,
++              bufflen, use_sg, timeout, retries, privdata, done, gfp, 1);
++}
+ EXPORT_SYMBOL_GPL(scsi_execute_async);
++/**
++ * scsi_execute_async_fifo - insert request at tail, in FIFO order
++ * @sdev:     scsi device
++ * @cmd:      scsi command
++ * @cmd_len:  length of scsi cdb
++ * @data_direction: data direction
++ * @buffer:   data buffer (this can be a kernel buffer or scatterlist)
++ * @bufflen:  len of buffer
++ * @use_sg:   if buffer is a scatterlist this is the number of elements
++ * @timeout:  request timeout in seconds
++ * @retries:  number of times to retry request
++ * @flags:    or into request flags
++ **/
++int scsi_execute_async_fifo(struct scsi_device *sdev, const unsigned char *cmd,
++                     int cmd_len, int data_direction, void *buffer, unsigned bufflen,
++                     int use_sg, int timeout, int retries, void *privdata,
++                     void (*done)(void *, char *, int, int), gfp_t gfp)
++{
++      return __scsi_execute_async(sdev, cmd, cmd_len, data_direction, buffer,
++              bufflen, use_sg, timeout, retries, privdata, done, gfp, 0);
++}
++EXPORT_SYMBOL_GPL(scsi_execute_async_fifo);
++
+ /*
+  * Function:    scsi_init_cmd_errh()
+  *
+diff -upr linux-2.6.18/include/scsi/scsi_device.h linux-2.6.18/include/scsi/scsi_device.h
+--- linux-2.6.18/include/scsi/scsi_device.h    2006-09-20 07:42:06.000000000 +0400
++++ linux-2.6.18/include/scsi/scsi_device.h    2007-07-04 21:15:32.000000000 +0400
+@@ -335,6 +335,13 @@ extern int scsi_execute_async(struct scs
+                             int timeout, int retries, void *privdata,
+                             void (*done)(void *, char *, int, int),
+                             gfp_t gfp);
++#define SCSI_EXEC_REQ_FIFO_DEFINED
++extern int scsi_execute_async_fifo(struct scsi_device *sdev,
++                            const unsigned char *cmd, int cmd_len, int data_direction,
++                            void *buffer, unsigned bufflen, int use_sg,
++                            int timeout, int retries, void *privdata,
++                            void (*done)(void *, char *, int, int),
++                            gfp_t gfp);
+ static inline void scsi_device_reprobe(struct scsi_device *sdev)
+ {