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 index 000000000..01a1c7e4a --- /dev/null +++ b/iscsi-scst/kernel/patches/rhel/put_page_callback-rhel5.patch @@ -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 ++#include + + #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 + #include + #include ++#include + + #include + #include + #include + ++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; inr_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]; + } diff --git a/iscsi-scst/kernel/target.c b/iscsi-scst/kernel/target.c index 585b467e0..483ef65b6 100644 --- a/iscsi-scst/kernel/target.c +++ b/iscsi-scst/kernel/target.c @@ -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 index 000000000..5fcf7b220 --- /dev/null +++ b/scst/kernel/rhel/scst_exec_req_fifo-rhel5.patch @@ -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) + {