From d7de93ba19cd086a180887a42c094aa32e3885c5 Mon Sep 17 00:00:00 2001 From: Vladislav Bolkhovitin Date: Thu, 16 Apr 2015 04:06:37 +0000 Subject: [PATCH 1/6] qla2x00t: Kernel 3.19 build fix Signed-off-by: Bart Van Assche git-svn-id: http://svn.code.sf.net/p/scst/svn/trunk@6183 d57e44dd-8a1f-0410-8b47-8ef2f437770f --- qla2x00t/qla_iocb.c | 23 +++++++++++++++++++++++ qla2x00t/qla_os.c | 16 ++++++++++++++-- 2 files changed, 37 insertions(+), 2 deletions(-) diff --git a/qla2x00t/qla_iocb.c b/qla2x00t/qla_iocb.c index d975f194a..58465ee07 100644 --- a/qla2x00t/qla_iocb.c +++ b/qla2x00t/qla_iocb.c @@ -328,7 +328,9 @@ qla2x00_start_scsi(srb_t *sp) struct qla_hw_data *ha; struct req_que *req; struct rsp_que *rsp; +#if LINUX_VERSION_CODE < KERNEL_VERSION(3, 19, 0) char tag[2]; +#endif /* Setup device pointers. */ ret = 0; @@ -409,6 +411,7 @@ qla2x00_start_scsi(srb_t *sp) cmd_pkt->lun = cpu_to_le16(cmd->device->lun); /* Update tagged queuing modifier */ +#if LINUX_VERSION_CODE < KERNEL_VERSION(3, 19, 0) if (scsi_populate_tag_msg(cmd, tag)) { switch (tag[0]) { case HEAD_OF_QUEUE_TAG: @@ -425,6 +428,10 @@ qla2x00_start_scsi(srb_t *sp) break; } } +#else + if (cmd->flags & SCMD_TAGGED) + cmd_pkt->control_flags = cpu_to_le16(CF_SIMPLE_TAG); +#endif /* Load SCSI command packet. */ memcpy(cmd_pkt->scsi_cdb, cmd->cmnd, cmd->cmd_len); @@ -1302,7 +1309,9 @@ qla24xx_build_scsi_crc_2_iocbs(srb_t *sp, struct cmd_type_crc_2 *cmd_pkt, uint16_t fcp_cmnd_len; struct fcp_cmnd *fcp_cmnd; dma_addr_t crc_ctx_dma; +#if LINUX_VERSION_CODE < KERNEL_VERSION(3, 19, 0) char tag[2]; +#endif cmd = GET_CMD_SP(sp); @@ -1398,6 +1407,7 @@ qla24xx_build_scsi_crc_2_iocbs(srb_t *sp, struct cmd_type_crc_2 *cmd_pkt, /* * Update tagged queuing modifier if using command tag queuing */ +#if LINUX_VERSION_CODE < KERNEL_VERSION(3, 19, 0) if (scsi_populate_tag_msg(cmd, tag)) { switch (tag[0]) { case HEAD_OF_QUEUE_TAG: @@ -1413,6 +1423,9 @@ qla24xx_build_scsi_crc_2_iocbs(srb_t *sp, struct cmd_type_crc_2 *cmd_pkt, } else { fcp_cmnd->task_attribute = 0; } +#else + fcp_cmnd->task_attribute = 0; +#endif cmd_pkt->fcp_rsp_dseg_len = 0; /* Let response come in status iocb */ @@ -1523,7 +1536,9 @@ qla24xx_start_scsi(srb_t *sp) struct scsi_cmnd *cmd = GET_CMD_SP(sp); struct scsi_qla_host *vha = sp->fcport->vha; struct qla_hw_data *ha = vha->hw; +#if LINUX_VERSION_CODE < KERNEL_VERSION(3, 19, 0) char tag[2]; +#endif /* Setup device pointers. */ ret = 0; @@ -1607,6 +1622,7 @@ qla24xx_start_scsi(srb_t *sp) int_to_scsilun(cmd->device->lun, &cmd_pkt->lun); host_to_fcp_swap((uint8_t *)&cmd_pkt->lun, sizeof(cmd_pkt->lun)); +#if LINUX_VERSION_CODE < KERNEL_VERSION(3, 19, 0) /* Update tagged queuing modifier -- default is TSK_SIMPLE (0). */ if (scsi_populate_tag_msg(cmd, tag)) { switch (tag[0]) { @@ -1618,6 +1634,7 @@ qla24xx_start_scsi(srb_t *sp) break; } } +#endif /* Load SCSI command packet. */ memcpy(cmd_pkt->fcp_cdb, cmd->cmnd, cmd->cmd_len); @@ -2315,7 +2332,9 @@ qla82xx_start_scsi(srb_t *sp) struct qla_hw_data *ha = vha->hw; struct req_que *req = NULL; struct rsp_que *rsp = NULL; +#if LINUX_VERSION_CODE < KERNEL_VERSION(3, 19, 0) char tag[2]; +#endif /* Setup device pointers. */ ret = 0; @@ -2494,6 +2513,7 @@ sufficient_dsds: else if (cmd->sc_data_direction == DMA_FROM_DEVICE) ctx->fcp_cmnd->additional_cdb_len |= 2; +#if LINUX_VERSION_CODE < KERNEL_VERSION(3, 19, 0) /* * Update tagged queuing modifier -- default is TSK_SIMPLE (0). */ @@ -2509,6 +2529,7 @@ sufficient_dsds: break; } } +#endif /* Populate the FCP_PRIO. */ if (ha->flags.fcp_prio_enabled) @@ -2570,6 +2591,7 @@ sufficient_dsds: host_to_fcp_swap((uint8_t *)&cmd_pkt->lun, sizeof(cmd_pkt->lun)); +#if LINUX_VERSION_CODE < KERNEL_VERSION(3, 19, 0) /* * Update tagged queuing modifier -- default is TSK_SIMPLE (0). */ @@ -2583,6 +2605,7 @@ sufficient_dsds: break; } } +#endif /* Populate the FCP_PRIO. */ if (ha->flags.fcp_prio_enabled) diff --git a/qla2x00t/qla_os.c b/qla2x00t/qla_os.c index b80bcc586..6772523be 100644 --- a/qla2x00t/qla_os.c +++ b/qla2x00t/qla_os.c @@ -264,7 +264,8 @@ static int qla2xxx_eh_target_reset(struct scsi_cmnd *); static int qla2xxx_eh_bus_reset(struct scsi_cmnd *); static int qla2xxx_eh_host_reset(struct scsi_cmnd *); -#if LINUX_VERSION_CODE < KERNEL_VERSION(2, 6, 33) && \ +#if LINUX_VERSION_CODE >= KERNEL_VERSION(3, 19, 0) +#elif LINUX_VERSION_CODE < KERNEL_VERSION(2, 6, 33) && \ !defined(CONFIG_SUSE_KERNEL) && \ (!defined(RHEL_RELEASE_CODE) || \ RHEL_RELEASE_CODE -0 < RHEL_RELEASE_VERSION(6, 1)) @@ -272,7 +273,9 @@ static int qla2x00_change_queue_depth(struct scsi_device *, int); #else static int qla2x00_change_queue_depth(struct scsi_device *, int, int); #endif +#if LINUX_VERSION_CODE < KERNEL_VERSION(3, 19, 0) static int qla2x00_change_queue_type(struct scsi_device *, int); +#endif struct scsi_host_template qla2xxx_driver_template = { .module = THIS_MODULE, @@ -295,8 +298,10 @@ struct scsi_host_template qla2xxx_driver_template = { .slave_destroy = qla2xxx_slave_destroy, .scan_finished = qla2xxx_scan_finished, .scan_start = qla2xxx_scan_start, +#if LINUX_VERSION_CODE < KERNEL_VERSION(3, 19, 0) .change_queue_depth = qla2x00_change_queue_depth, .change_queue_type = qla2x00_change_queue_type, +#endif .this_id = -1, .cmd_per_lun = 3, .use_clustering = ENABLE_CLUSTERING, @@ -1452,10 +1457,14 @@ qla2xxx_slave_configure(struct scsi_device *sdev) struct fc_rport *rport = starget_to_rport(sdev->sdev_target); struct req_que *req = vha->req; +#if LINUX_VERSION_CODE < KERNEL_VERSION(3, 19, 0) if (sdev->tagged_supported) scsi_activate_tcq(sdev, req->max_q_depth); else scsi_deactivate_tcq(sdev, req->max_q_depth); +#else + scsi_change_queue_depth(sdev, req->max_q_depth); +#endif rport->dev_loss_tmo = ha->port_down_retry_count; @@ -1468,7 +1477,8 @@ qla2xxx_slave_destroy(struct scsi_device *sdev) sdev->hostdata = NULL; } -#if LINUX_VERSION_CODE < KERNEL_VERSION(2, 6, 33) && \ +#if LINUX_VERSION_CODE >= KERNEL_VERSION(3, 19, 0) +#elif LINUX_VERSION_CODE < KERNEL_VERSION(2, 6, 33) && \ !defined(CONFIG_SUSE_KERNEL) && \ (!defined(RHEL_RELEASE_CODE) || \ RHEL_RELEASE_CODE -0 < RHEL_RELEASE_VERSION(6, 1)) @@ -1539,6 +1549,7 @@ qla2x00_change_queue_depth(struct scsi_device *sdev, int qdepth, int reason) #endif /* LINUX_VERSION_CODE < KERNEL_VERSION(2, 6, 33) && !defined(CONFIG_SUSE_KERNEL) && (!defined(RHEL_RELEASE_CODE) || RHEL_RELEASE_CODE -0 < RHEL_RELEASE_VERSION(6, 1)) */ +#if LINUX_VERSION_CODE < KERNEL_VERSION(3, 19, 0) static int qla2x00_change_queue_type(struct scsi_device *sdev, int tag_type) { @@ -1553,6 +1564,7 @@ qla2x00_change_queue_type(struct scsi_device *sdev, int tag_type) return tag_type; } +#endif /** * qla2x00_config_dma_addressing() - Configure OS DMA addressing method. From 918ac631205fab8d8ecbfa4f5045386c35eb9623 Mon Sep 17 00:00:00 2001 From: Vladislav Bolkhovitin Date: Thu, 16 Apr 2015 04:08:45 +0000 Subject: [PATCH 2/6] iscsi-scst: Add put_page_callback patch for kernel 3.19 Tested against the virtio_net network driver. Signed-off-by: Bart Van Assche git-svn-id: http://svn.code.sf.net/p/scst/svn/trunk@6184 d57e44dd-8a1f-0410-8b47-8ef2f437770f --- .../patches/put_page_callback-3.19.patch | 387 ++++++++++++++++++ 1 file changed, 387 insertions(+) create mode 100644 iscsi-scst/kernel/patches/put_page_callback-3.19.patch diff --git a/iscsi-scst/kernel/patches/put_page_callback-3.19.patch b/iscsi-scst/kernel/patches/put_page_callback-3.19.patch new file mode 100644 index 000000000..406350c0d --- /dev/null +++ b/iscsi-scst/kernel/patches/put_page_callback-3.19.patch @@ -0,0 +1,387 @@ +Subject: [PATCH] put_page_callback + +--- + drivers/block/drbd/drbd_receiver.c | 2 +- + include/linux/mm_types.h | 11 +++++++++ + include/linux/net.h | 40 ++++++++++++++++++++++++++++++ + include/linux/skbuff.h | 4 +-- + net/Kconfig | 12 +++++++++ + net/ceph/pagevec.c | 2 +- + net/core/skbuff.c | 14 +++++------ + net/core/sock.c | 4 +-- + net/ipv4/Makefile | 1 + + net/ipv4/ip_output.c | 4 +-- + net/ipv4/tcp.c | 4 +-- + net/ipv4/tcp_zero_copy.c | 50 ++++++++++++++++++++++++++++++++++++++ + net/ipv6/ip6_output.c | 2 +- + 13 files changed, 132 insertions(+), 18 deletions(-) + create mode 100644 net/ipv4/tcp_zero_copy.c + +diff --git a/drivers/block/drbd/drbd_receiver.c b/drivers/block/drbd/drbd_receiver.c +index d169b4a..ec913c2 100644 +--- a/drivers/block/drbd/drbd_receiver.c ++++ b/drivers/block/drbd/drbd_receiver.c +@@ -132,7 +132,7 @@ static int page_chain_free(struct page *page) + struct page *tmp; + int i = 0; + page_chain_for_each_safe(page, tmp) { +- put_page(page); ++ net_put_page(page); + ++i; + } + return i; +diff --git a/include/linux/mm_types.h b/include/linux/mm_types.h +index 6d34aa2..a536ed7 100644 +--- a/include/linux/mm_types.h ++++ b/include/linux/mm_types.h +@@ -197,6 +197,17 @@ struct page { + #ifdef LAST_CPUPID_NOT_IN_PAGE_FLAGS + int _last_cpupid; + #endif ++ ++#if defined(CONFIG_TCP_ZERO_COPY_TRANSFER_COMPLETION_NOTIFICATION) ++ /* ++ * Used to implement support for notification on zero-copy TCP transfer ++ * completion. It might look as not good to have this field here and ++ * it's better to have it in struct sk_buff, but it would make the code ++ * much more complicated and fragile, since all skb then would have to ++ * contain only pages with the same value in this field. ++ */ ++ void *net_priv; ++#endif + } + /* + * The struct page can be forced to be double word aligned so that atomic ops +diff --git a/include/linux/net.h b/include/linux/net.h +index 17d8339..f784384 100644 +--- a/include/linux/net.h ++++ b/include/linux/net.h +@@ -19,6 +19,7 @@ + #define _LINUX_NET_H + + #include ++#include + #include + #include + #include /* For O_CLOEXEC and O_NONBLOCK */ +@@ -285,6 +286,45 @@ int kernel_sendpage(struct socket *sock, struct page *page, int offset, + int kernel_sock_ioctl(struct socket *sock, int cmd, unsigned long arg); + int kernel_sock_shutdown(struct socket *sock, enum sock_shutdown_cmd how); + ++#if defined(CONFIG_TCP_ZERO_COPY_TRANSFER_COMPLETION_NOTIFICATION) ++/* Support for notification on zero-copy TCP transfer completion */ ++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); ++ ++/* ++ * See comment for net_set_get_put_page_callbacks() why those functions ++ * don't need any protection. ++ */ ++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); ++} ++#else ++static inline void net_get_page(struct page *page) ++{ ++ get_page(page); ++} ++static inline void net_put_page(struct page *page) ++{ ++ put_page(page); ++} ++#endif /* CONFIG_TCP_ZERO_COPY_TRANSFER_COMPLETION_NOTIFICATION */ ++ + #define MODULE_ALIAS_NETPROTO(proto) \ + MODULE_ALIAS("net-pf-" __stringify(proto)) + +diff --git a/include/linux/skbuff.h b/include/linux/skbuff.h +index 85ab7d7..fb82e86 100644 +--- a/include/linux/skbuff.h ++++ b/include/linux/skbuff.h +@@ -2254,7 +2254,7 @@ static inline struct page *skb_frag_page(const skb_frag_t *frag) + */ + static inline void __skb_frag_ref(skb_frag_t *frag) + { +- get_page(skb_frag_page(frag)); ++ net_get_page(skb_frag_page(frag)); + } + + /** +@@ -2277,7 +2277,7 @@ static inline void skb_frag_ref(struct sk_buff *skb, int f) + */ + static inline void __skb_frag_unref(skb_frag_t *frag) + { +- put_page(skb_frag_page(frag)); ++ net_put_page(skb_frag_page(frag)); + } + + /** +diff --git a/net/Kconfig b/net/Kconfig +index ff9ffc1..a270579 100644 +--- a/net/Kconfig ++++ b/net/Kconfig +@@ -76,6 +76,18 @@ config INET + + Short answer: say Y. + ++config TCP_ZERO_COPY_TRANSFER_COMPLETION_NOTIFICATION ++ bool "TCP/IP zero-copy transfer completion notification" ++ depends on INET ++ default SCST_ISCSI ++ ---help--- ++ Adds support for sending a notification upon completion of a ++ zero-copy TCP/IP transfer. This can speed up certain TCP/IP ++ software. Currently this is only used by the iSCSI target driver ++ iSCSI-SCST. ++ ++ If unsure, say N. ++ + if INET + source "net/ipv4/Kconfig" + source "net/ipv6/Kconfig" +diff --git a/net/ceph/pagevec.c b/net/ceph/pagevec.c +index 5550130..993f710 100644 +--- a/net/ceph/pagevec.c ++++ b/net/ceph/pagevec.c +@@ -51,7 +51,7 @@ void ceph_put_page_vector(struct page **pages, int num_pages, bool dirty) + for (i = 0; i < num_pages; i++) { + if (dirty) + set_page_dirty_lock(pages[i]); +- put_page(pages[i]); ++ net_put_page(pages[i]); + } + if (is_vmalloc_addr(pages)) + vfree(pages); +diff --git a/net/core/skbuff.c b/net/core/skbuff.c +index 62c67be..35074d3 100644 +--- a/net/core/skbuff.c ++++ b/net/core/skbuff.c +@@ -479,7 +479,7 @@ static struct sk_buff *__alloc_rx_skb(unsigned int length, gfp_t gfp_mask, + if (likely(data)) { + skb = build_skb(data, fragsz); + if (unlikely(!skb)) +- put_page(virt_to_head_page(data)); ++ net_put_page(virt_to_head_page(data)); + } + } else { + skb = __alloc_skb(length, gfp_mask, +@@ -592,7 +592,7 @@ static void skb_clone_fraglist(struct sk_buff *skb) + static void skb_free_head(struct sk_buff *skb) + { + if (skb->head_frag) +- put_page(virt_to_head_page(skb->head)); ++ net_put_page(virt_to_head_page(skb->head)); + else + kfree(skb->head); + } +@@ -920,7 +920,7 @@ int skb_copy_ubufs(struct sk_buff *skb, gfp_t gfp_mask) + if (!page) { + while (head) { + struct page *next = (struct page *)page_private(head); +- put_page(head); ++ net_put_page(head); + head = next; + } + return -ENOMEM; +@@ -1767,7 +1767,7 @@ EXPORT_SYMBOL(skb_copy_bits); + */ + static void sock_spd_release(struct splice_pipe_desc *spd, unsigned int i) + { +- put_page(spd->pages[i]); ++ net_put_page(spd->pages[i]); + } + + static struct page *linear_to_page(struct page *page, unsigned int *len, +@@ -1820,7 +1820,7 @@ static bool spd_fill_page(struct splice_pipe_desc *spd, + spd->partial[spd->nr_pages - 1].len += *len; + return false; + } +- get_page(page); ++ net_get_page(page); + spd->pages[spd->nr_pages] = page; + spd->partial[spd->nr_pages].len = *len; + spd->partial[spd->nr_pages].offset = offset; +@@ -2279,7 +2279,7 @@ skb_zerocopy(struct sk_buff *to, struct sk_buff *from, int len, int hlen) + page = virt_to_head_page(from->head); + offset = from->data - (unsigned char *)page_address(page); + __skb_fill_page_desc(to, 0, page, offset, plen); +- get_page(page); ++ net_get_page(page); + j = 1; + len -= plen; + } +@@ -2933,7 +2933,7 @@ int skb_append_datato_frags(struct sock *sk, struct sk_buff *skb, + copy); + frg_cnt++; + pfrag->offset += copy; +- get_page(pfrag->page); ++ net_get_page(pfrag->page); + + skb->truesize += copy; + atomic_add(copy, &sk->sk_wmem_alloc); +diff --git a/net/core/sock.c b/net/core/sock.c +index 1c7a33d..ec95185 100644 +--- a/net/core/sock.c ++++ b/net/core/sock.c +@@ -1864,7 +1864,7 @@ bool skb_page_frag_refill(unsigned int sz, struct page_frag *pfrag, gfp_t gfp) + } + if (pfrag->offset + sz <= pfrag->size) + return true; +- put_page(pfrag->page); ++ net_put_page(pfrag->page); + } + + pfrag->offset = 0; +@@ -2615,7 +2615,7 @@ void sk_common_release(struct sock *sk) + sk_refcnt_debug_release(sk); + + if (sk->sk_frag.page) { +- put_page(sk->sk_frag.page); ++ net_put_page(sk->sk_frag.page); + sk->sk_frag.page = NULL; + } + +diff --git a/net/ipv4/Makefile b/net/ipv4/Makefile +index 518c04e..4072a87 100644 +--- a/net/ipv4/Makefile ++++ b/net/ipv4/Makefile +@@ -57,6 +57,7 @@ obj-$(CONFIG_TCP_CONG_ILLINOIS) += tcp_illinois.o + obj-$(CONFIG_MEMCG_KMEM) += tcp_memcontrol.o + obj-$(CONFIG_NETLABEL) += cipso_ipv4.o + obj-$(CONFIG_GENEVE) += geneve.o ++obj-$(CONFIG_TCP_ZERO_COPY_TRANSFER_COMPLETION_NOTIFICATION) += tcp_zero_copy.o + + obj-$(CONFIG_XFRM) += xfrm4_policy.o xfrm4_state.o xfrm4_input.o \ + xfrm4_output.o xfrm4_protocol.o +diff --git a/net/ipv4/ip_output.c b/net/ipv4/ip_output.c +index 2e2f687..87f5bff 100644 +--- a/net/ipv4/ip_output.c ++++ b/net/ipv4/ip_output.c +@@ -1052,7 +1052,7 @@ alloc_new_skb: + __skb_fill_page_desc(skb, i, pfrag->page, + pfrag->offset, 0); + skb_shinfo(skb)->nr_frags = ++i; +- get_page(pfrag->page); ++ net_get_page(pfrag->page); + } + copy = min_t(int, copy, pfrag->size - pfrag->offset); + if (getfrag(from, +@@ -1277,7 +1277,7 @@ ssize_t ip_append_page(struct sock *sk, struct flowi4 *fl4, struct page *page, + if (skb_can_coalesce(skb, i, page, offset)) { + skb_frag_size_add(&skb_shinfo(skb)->frags[i-1], 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 --git a/net/ipv4/tcp.c b/net/ipv4/tcp.c +index 3075723..396b887 100644 +--- a/net/ipv4/tcp.c ++++ b/net/ipv4/tcp.c +@@ -931,7 +931,7 @@ new_segment: + if (can_coalesce) { + skb_frag_size_add(&skb_shinfo(skb)->frags[i - 1], copy); + } else { +- get_page(page); ++ net_get_page(page); + skb_fill_page_desc(skb, i, page, offset, copy); + } + skb_shinfo(skb)->tx_flags |= SKBTX_SHARED_FRAG; +@@ -1232,7 +1232,7 @@ new_segment: + } else { + skb_fill_page_desc(skb, i, pfrag->page, + pfrag->offset, copy); +- get_page(pfrag->page); ++ net_get_page(pfrag->page); + } + pfrag->offset += copy; + } +diff --git a/net/ipv4/tcp_zero_copy.c b/net/ipv4/tcp_zero_copy.c +new file mode 100644 +index 0000000..430147e +--- /dev/null ++++ b/net/ipv4/tcp_zero_copy.c +@@ -0,0 +1,50 @@ ++/* ++ * Support routines for TCP zero copy transmit ++ * ++ * Created by Vladislav Bolkhovitin ++ * ++ * This program is free software; you can redistribute it and/or ++ * modify it under the terms of the GNU General Public License ++ * version 2 as published by the Free Software Foundation. ++ */ ++ ++#include ++#include ++ ++net_get_page_callback_t net_get_page_callback __read_mostly; ++EXPORT_SYMBOL_GPL(net_get_page_callback); ++ ++net_put_page_callback_t net_put_page_callback __read_mostly; ++EXPORT_SYMBOL_GPL(net_put_page_callback); ++ ++/* ++ * Caller of this function must ensure that at the moment when it's called ++ * there are no pages in the system with net_priv field set to non-zero ++ * value. Hence, this function, as well as net_get_page() and net_put_page(), ++ * don't need any protection. ++ */ ++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_GPL(net_set_get_put_page_callbacks); +diff --git a/net/ipv6/ip6_output.c b/net/ipv6/ip6_output.c +index 3f5aa99..777f267 100644 +--- a/net/ipv6/ip6_output.c ++++ b/net/ipv6/ip6_output.c +@@ -1460,7 +1460,7 @@ alloc_new_skb: + __skb_fill_page_desc(skb, i, pfrag->page, + pfrag->offset, 0); + skb_shinfo(skb)->nr_frags = ++i; +- get_page(pfrag->page); ++ net_get_page(pfrag->page); + } + copy = min_t(int, copy, pfrag->size - pfrag->offset); + if (getfrag(from, +-- +1.9.1 + From b8fe3c6962c366192c46c9ad6d739bfcd34f0ec5 Mon Sep 17 00:00:00 2001 From: Vladislav Bolkhovitin Date: Fri, 24 Apr 2015 00:20:59 +0000 Subject: [PATCH 3/6] Emulex target driver web update from Emulex git-svn-id: http://svn.code.sf.net/p/scst/svn/trunk@6185 d57e44dd-8a1f-0410-8b47-8ef2f437770f --- www/images/LPe16002.jpg | Bin 0 -> 13644 bytes www/target_emulex.html | 26 +++++++++----------------- 2 files changed, 9 insertions(+), 17 deletions(-) create mode 100644 www/images/LPe16002.jpg diff --git a/www/images/LPe16002.jpg b/www/images/LPe16002.jpg new file mode 100644 index 0000000000000000000000000000000000000000..ce16b045bd84511f0f6ca6fcb9ee41c7bff41aef GIT binary patch literal 13644 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 Rgc=_R$j2;&vq5-W_

Target driver for Emulex FC/FCoE adapters

-

SCST Emulex +

SCST Emulex -

The ocs_fc_scst target driver for Emulex FC/FCoE adapters is developed by the Emulex team - and is available at the Emulex OneCore SDK - developer site. Register for free at the Developer Portal Access - page to get the source code and documentation. The Emulex OneCore SDK is built around the Emulex SLI-4 - (Service Level Interface) API and is compatible with Emulex 16 Gb/s Fibre Channel HBAs (LPe16000 series) - and Ethernet based target mode FCoE UCNAs (OCe11102-F series).

+

The Emulex OneCore Storage FC/FCoE driver (ocs_fc_scst) is developed and maintained by Emulex. It is available on the emulex.com download page under OneCore Storage Drivers. + The Emulex OneCore driver supports the Service Level Interface 4 (SLI-4) API and is compatible with the latest generation of Emulex 8 and 16 Gb/s Fibre Channel HBAs (LPe15000 and LPe16000 series), + as well as the latest generation of 10 and 40 Gb/s FCoE UCNAs (OCe14000-series).

-

The ocs_fc_scst driver allows for Emulex adapters to be placed in initiator and/or target mode. - The driver effectively maps SCST to the Emulex SLI-4 interface allowing a simple transition to Emulex 16Gb/s - fibre channel technology for existing or new SCST users. NPIV is also supported, allowing virtual - ports to be created with individual SCST target instances bound to them. +

The ocs_fc_scst driver has been tested with SCST version 3.0.1, as well as SCST version 2.2.0. The driver supports both target and initiator mode of operation and a number of + advanced features: NPIV, T10-PI, etc. Please refer to the Emulex download page for more information. -

Documented for use with RHEL/Centos 6.x based distributions, ocs_fc_scst works with the stable SCST 2.2.1 - as well as the development versions of 2.2.x and 3.0.x.

- -

Please note that the drivers on SourceForge Emulex Drivers - are now very old, not maintained and so are not recommended for new designs.

+

Note: The drivers on SourceForge Emulex Drivers + are now very old, not maintained and not recommended for new designs.



 
From 6572bedcb82687ddccd0252410b7ec60e40fcd90 Mon Sep 17 00:00:00 2001 From: Vladislav Bolkhovitin Date: Fri, 24 Apr 2015 02:04:58 +0000 Subject: [PATCH 4/6] iscsid: Logically and negative conditions instead of or-ing these Logically and negative allowed_portal conditions instead of or-ing these. This was proposed by Sergej Roytman . Signed-off-by: Bart Van Assche git-svn-id: http://svn.code.sf.net/p/scst/svn/trunk@6186 d57e44dd-8a1f-0410-8b47-8ef2f437770f --- iscsi-scst/usr/target.c | 22 ++++++++++++++++++---- 1 file changed, 18 insertions(+), 4 deletions(-) diff --git a/iscsi-scst/usr/target.c b/iscsi-scst/usr/target.c index 1bb5a2a72..cfab907a6 100644 --- a/iscsi-scst/usr/target.c +++ b/iscsi-scst/usr/target.c @@ -127,6 +127,15 @@ static int wildcmp(const char *wild, const char *string) return __wildcmp(wild, string, 0); } +/* + * Evaluate the list with wildcard patterns as follows: + * - If only positive wildcard patterns have been specified, it is sufficient + * that one wildcard pattern matches (logical or). + * - If only negative wildcard patterns have been specified, none of these + * patterns must match (logical and). + * - If positive and negative wildcard patterns have been specified, one of + * the positive patterns must match and none of the negative. + */ int target_portal_allowed(struct target *target, const char *target_portal, const char *initiator_name) { @@ -135,14 +144,19 @@ int target_portal_allowed(struct target *target, if (!list_empty(&target->allowed_portals)) { struct iscsi_attr *attr; + bool any_pos_cond = false, pos_match = false, neg_match = true; - res = 0; list_for_each_entry(attr, &target->allowed_portals, ulist) { - if (wildcmp(attr->attr_key, target_portal)) { - res = 1; - break; + bool match = wildcmp(attr->attr_key, target_portal); + + if (attr->attr_key[0] != '!') { + any_pos_cond = true; + pos_match = pos_match || match; + } else { + neg_match = neg_match && match; } } + res = (!any_pos_cond || pos_match) && neg_match; if (res == 0) goto out; } From 1e781269620dc0bb49582b053dcb2c453389f050 Mon Sep 17 00:00:00 2001 From: Vladislav Bolkhovitin Date: Fri, 24 Apr 2015 02:54:52 +0000 Subject: [PATCH 5/6] iscsi-scst: update for 3.19 kernels Signed-off-by: Bart Van Assche with some improvements git-svn-id: http://svn.code.sf.net/p/scst/svn/trunk@6187 d57e44dd-8a1f-0410-8b47-8ef2f437770f --- iscsi-scst/kernel/conn.c | 2 +- iscsi-scst/kernel/iscsi.c | 60 ++++++++++++++++++----------- iscsi-scst/kernel/iscsi.h | 6 ++- iscsi-scst/kernel/nthread.c | 77 +++++++++++++++++++++++-------------- 4 files changed, 92 insertions(+), 53 deletions(-) diff --git a/iscsi-scst/kernel/conn.c b/iscsi-scst/kernel/conn.c index e8e690fbb..2a0c31596 100644 --- a/iscsi-scst/kernel/conn.c +++ b/iscsi-scst/kernel/conn.c @@ -895,7 +895,7 @@ static int iscsi_conn_alloc(struct iscsi_session *session, (unsigned long long int)session->sid, info->cid); /* Changing it, change ISCSI_CONN_IOV_MAX as well !! */ - conn->read_iov = (struct iovec *)get_zeroed_page(GFP_KERNEL); + conn->read_iov = (void *)get_zeroed_page(GFP_KERNEL); if (conn->read_iov == NULL) { res = -ENOMEM; goto out_err_free_conn; diff --git a/iscsi-scst/kernel/iscsi.c b/iscsi-scst/kernel/iscsi.c index e77b72c08..512ab9aad 100644 --- a/iscsi-scst/kernel/iscsi.c +++ b/iscsi-scst/kernel/iscsi.c @@ -1407,7 +1407,7 @@ static void cmnd_prepare_get_rejected_immed_data(struct iscsi_cmnd *cmnd) struct iscsi_conn *conn = cmnd->conn; struct scatterlist *sg = cmnd->sg; char *addr; - u32 size; + u32 size, s, e; unsigned int i; TRACE_ENTRY(); @@ -1441,17 +1441,21 @@ static void cmnd_prepare_get_rejected_immed_data(struct iscsi_cmnd *cmnd) } addr = page_address(sg_page(&sg[0])); - conn->read_size = size; - for (i = 0; size > PAGE_SIZE; i++, size -= PAGE_SIZE) { + for (s = size, i = 0; s > 0; i++, s -= e) { /* We already checked pdu.datasize in check_segment_length() */ sBUG_ON(i >= ISCSI_CONN_IOV_MAX); - conn->read_iov[i].iov_base = (void __force __user *)addr; - conn->read_iov[i].iov_len = PAGE_SIZE; + conn->read_iov[i].iov_base = addr; + e = min_t(u32, s, PAGE_SIZE); + conn->read_iov[i].iov_len = e; } - conn->read_iov[i].iov_base = (void __force __user *)addr; - conn->read_iov[i].iov_len = size; +#if LINUX_VERSION_CODE >= KERNEL_VERSION(3, 19, 0) + iov_iter_kvec(&conn->read_msg.msg_iter, READ | ITER_KVEC, + conn->read_iov, i, size); +#else conn->read_msg.msg_iov = conn->read_iov; - conn->read_msg.msg_iovlen = ++i; + conn->read_msg.msg_iovlen = i; + conn->read_size = size; +#endif out: TRACE_EXIT(); @@ -1532,6 +1536,7 @@ static int cmnd_prepare_recv_pdu(struct iscsi_conn *conn, struct scatterlist *sg = cmd->sg; unsigned int bufflen = cmd->bufflen; unsigned int idx, i, buff_offs; + const u32 read_size = size; int res = 0; TRACE_ENTRY(); @@ -1546,9 +1551,6 @@ static int cmnd_prepare_recv_pdu(struct iscsi_conn *conn, idx = offset >> PAGE_SHIFT; offset &= ~PAGE_MASK; - conn->read_msg.msg_iov = conn->read_iov; - conn->read_size = size; - i = 0; while (1) { unsigned int sg_len; @@ -1566,13 +1568,12 @@ static int cmnd_prepare_recv_pdu(struct iscsi_conn *conn, EXTRACHECKS_BUG_ON(addr == NULL); sg_len = sg[idx].offset + sg[idx].length - offset; - conn->read_iov[i].iov_base = (void __force __user *)addr + offset; + conn->read_iov[i].iov_base = addr + offset; if (size <= sg_len) { TRACE_DBG("idx=%d, i=%d, offset=%u, size=%d, addr=%p", idx, i, offset, size, addr); conn->read_iov[i].iov_len = size; - conn->read_msg.msg_iovlen = i+1; break; } conn->read_iov[i].iov_len = sg_len; @@ -1591,16 +1592,26 @@ static int cmnd_prepare_recv_pdu(struct iscsi_conn *conn, size); mark_conn_closed(conn); res = -EINVAL; - break; + goto out; } idx++; offset = 0; } - TRACE_DBG("msg_iov=%p, msg_iovlen=%zd", - conn->read_msg.msg_iov, conn->read_msg.msg_iovlen); + i++; +#if LINUX_VERSION_CODE >= KERNEL_VERSION(3, 19, 0) + iov_iter_kvec(&conn->read_msg.msg_iter, READ | ITER_KVEC, + conn->read_iov, i, read_size); +#else + conn->read_msg.msg_iov = conn->read_iov; + conn->read_msg.msg_iovlen = i; + conn->read_size = read_size; +#endif + TRACE_DBG("msg_iov=%p, msg_iovlen=%u", conn->read_iov, i); + +out: TRACE_EXIT_RES(res); return res; } @@ -1740,7 +1751,6 @@ static int nop_out_start(struct iscsi_cmnd *cmnd) size = cmnd->pdu.datasize; if (size) { - conn->read_msg.msg_iov = conn->read_iov; if (cmnd->pdu.bhs.itt != ISCSI_RESERVED_TAG) { struct scatterlist *sg; @@ -1761,10 +1771,9 @@ static int nop_out_start(struct iscsi_cmnd *cmnd) for (i = 0; i < cmnd->sg_cnt; i++) { conn->read_iov[i].iov_base = - (void __force __user *)(page_address(sg_page(&sg[i]))); + page_address(sg_page(&sg[i])); tmp = min_t(u32, size, PAGE_SIZE); conn->read_iov[i].iov_len = tmp; - conn->read_size += tmp; size -= tmp; } sBUG_ON(size != 0); @@ -1776,10 +1785,9 @@ static int nop_out_start(struct iscsi_cmnd *cmnd) */ for (i = 0; i < (signed)ISCSI_CONN_IOV_MAX; i++) { conn->read_iov[i].iov_base = - (void __force __user *)(page_address(dummy_page)); + page_address(dummy_page); tmp = min_t(u32, size, PAGE_SIZE); conn->read_iov[i].iov_len = tmp; - conn->read_size += tmp; size -= tmp; } @@ -1787,9 +1795,15 @@ static int nop_out_start(struct iscsi_cmnd *cmnd) sBUG_ON(size != 0); } +#if LINUX_VERSION_CODE >= KERNEL_VERSION(3, 19, 0) + iov_iter_kvec(&conn->read_msg.msg_iter, READ | ITER_KVEC, + conn->read_iov, i, cmnd->pdu.datasize); +#else + conn->read_msg.msg_iov = conn->read_iov; conn->read_msg.msg_iovlen = i; - TRACE_DBG("msg_iov=%p, msg_iovlen=%zd", conn->read_msg.msg_iov, - conn->read_msg.msg_iovlen); + conn->read_size = cmnd->pdu.datasize; +#endif + TRACE_DBG("msg_iov=%p, msg_iovlen=%d", conn->read_iov, i); } out: diff --git a/iscsi-scst/kernel/iscsi.h b/iscsi-scst/kernel/iscsi.h index 47b474502..7f29fb8cd 100644 --- a/iscsi-scst/kernel/iscsi.h +++ b/iscsi-scst/kernel/iscsi.h @@ -285,9 +285,13 @@ struct iscsi_conn { */ struct iscsi_cmnd *read_cmnd; struct msghdr read_msg; - u32 read_size; int read_state; +#if LINUX_VERSION_CODE >= KERNEL_VERSION(3, 19, 0) + struct kvec *read_iov; +#else + u32 read_size; struct iovec *read_iov; +#endif struct task_struct *rx_task; uint32_t rpadding; diff --git a/iscsi-scst/kernel/nthread.c b/iscsi-scst/kernel/nthread.c index f7fea7522..44ec3986f 100644 --- a/iscsi-scst/kernel/nthread.c +++ b/iscsi-scst/kernel/nthread.c @@ -615,11 +615,16 @@ static void start_close_conn(struct iscsi_conn *conn) static inline void iscsi_conn_init_read(struct iscsi_conn *conn, void *data, size_t len) { - conn->read_iov[0].iov_base = (void __force __user *)data; + conn->read_iov[0].iov_base = data; conn->read_iov[0].iov_len = len; +#if LINUX_VERSION_CODE >= KERNEL_VERSION(3, 19, 0) + iov_iter_kvec(&conn->read_msg.msg_iter, READ | ITER_KVEC, + conn->read_iov, 1, len); +#else conn->read_msg.msg_iov = conn->read_iov; conn->read_msg.msg_iovlen = 1; conn->read_size = len; +#endif return; } @@ -680,8 +685,12 @@ static int do_recv(struct iscsi_conn *conn) { int res; mm_segment_t oldfs; - struct msghdr msg; + struct msghdr *msg; + int read_size; +#if LINUX_VERSION_CODE < KERNEL_VERSION(3, 19, 0) + struct iovec *first_iov; int first_len; +#endif EXTRACHECKS_BUG_ON(conn->read_cmnd == NULL); @@ -697,45 +706,48 @@ static int do_recv(struct iscsi_conn *conn) */ restart: - memset(&msg, 0, sizeof(msg)); - msg.msg_iov = conn->read_msg.msg_iov; - msg.msg_iovlen = conn->read_msg.msg_iovlen; - first_len = msg.msg_iov->iov_len; + msg = &conn->read_msg; +#if LINUX_VERSION_CODE >= KERNEL_VERSION(3, 19, 0) + read_size = msg->msg_iter.count; +#else + read_size = conn->read_size; + first_iov = msg->msg_iov; + first_len = first_iov->iov_len; +#endif oldfs = get_fs(); set_fs(get_ds()); - res = sock_recvmsg(conn->sock, &msg, conn->read_size, + res = sock_recvmsg(conn->sock, msg, read_size, MSG_DONTWAIT | MSG_NOSIGNAL); set_fs(oldfs); - TRACE_DBG("msg_iovlen %zd, first_len %d, read_size %d, res %d", - msg.msg_iovlen, first_len, conn->read_size, res); +#if LINUX_VERSION_CODE >= KERNEL_VERSION(3, 19, 0) + TRACE_DBG("nr_segs %zd, bytes_left %zd, res %d", + msg->msg_iter.nr_segs, msg->msg_iter.count, res); +#else + TRACE_DBG("msg_iovlen %zd, read_size %d, res %d", msg->msg_iovlen, + read_size, res); +#endif if (res > 0) { /* - * To save some considerable effort and CPU power we - * suppose that TCP functions adjust - * conn->read_msg.msg_iov and conn->read_msg.msg_iovlen - * on amount of copied data. This BUG_ON is intended - * to catch if it is changed in the future. + * To save CPU cycles we suppose that sock_recvmsg() adjusts + * msg->msg_iov and msg->msg_iovlen. The BUG_ON() statements + * below verifies this. */ - sBUG_ON((res >= first_len) && - (conn->read_msg.msg_iov->iov_len != 0)); +#if LINUX_VERSION_CODE >= KERNEL_VERSION(3, 19, 0) + sBUG_ON(msg->msg_iter.count + res != read_size); + res = msg->msg_iter.count; +#else + sBUG_ON((res >= first_len) && (first_iov->iov_len != 0)); conn->read_size -= res; - if (conn->read_size != 0) { - if (res >= first_len) { - int done = 1 + ((res - first_len) >> PAGE_SHIFT); - TRACE_DBG("done %d", done); - conn->read_msg.msg_iov += done; - conn->read_msg.msg_iovlen -= done; - } - } res = conn->read_size; +#endif } else { switch (res) { case -EAGAIN: TRACE_DBG("EAGAIN received for conn %p", conn); - res = conn->read_size; + res = read_size; break; case -ERESTARTSYS: TRACE_DBG("ERESTARTSYS received for conn %p", conn); @@ -821,7 +833,7 @@ static int iscsi_rx_check_ddigest(struct iscsi_conn *conn) static int process_read_io(struct iscsi_conn *conn, int *closed) { struct iscsi_cmnd *cmnd = conn->read_cmnd; - int res; + int bytes_left, res; TRACE_ENTRY(); @@ -909,10 +921,15 @@ static int process_read_io(struct iscsi_conn *conn, int *closed) break; case RX_END: - if (unlikely(conn->read_size != 0)) { +#if LINUX_VERSION_CODE >= KERNEL_VERSION(3, 19, 0) + bytes_left = conn->read_msg.msg_iter.count; +#else + bytes_left = conn->read_size; +#endif + if (unlikely(bytes_left != 0)) { PRINT_CRIT_ERROR("conn read_size !=0 on RX_END " "(conn %p, op %x, read_size %d)", conn, - cmnd_opcode(cmnd), conn->read_size); + cmnd_opcode(cmnd), bytes_left); sBUG(); } conn->read_cmnd = NULL; @@ -920,7 +937,11 @@ static int process_read_io(struct iscsi_conn *conn, int *closed) cmnd_rx_end(cmnd); +#if LINUX_VERSION_CODE >= KERNEL_VERSION(3, 19, 0) + EXTRACHECKS_BUG_ON(conn->read_msg.msg_iter.count != 0); +#else EXTRACHECKS_BUG_ON(conn->read_size != 0); +#endif /* * To maintain fairness. Res must be 0 here anyway, the From 0b4fe40d3e68dbdd1c2dabe77fcfdce575c520c7 Mon Sep 17 00:00:00 2001 From: Vladislav Bolkhovitin Date: Fri, 1 May 2015 02:04:39 +0000 Subject: [PATCH 6/6] scst_lib: Improve WRITE SAME performance Some storage devices have a block size of 512 bytes and a minimum I/O size and/or optimal I/O size of 4096 bytes. Improve WRITE SAME performance for such devices by increasing the I/O granularity from 512 bytes to 4096 bytes. Based on a patch written by Vishal Tripathi and Sushil Sharma . Signed-off-by: Bart Van Assche + with some minor changes git-svn-id: http://svn.code.sf.net/p/scst/svn/trunk@6189 d57e44dd-8a1f-0410-8b47-8ef2f437770f --- scst/include/scst.h | 4 ++ scst/src/scst_lib.c | 123 ++++++++++++++++++++++++++++++++++++++++---- 2 files changed, 116 insertions(+), 11 deletions(-) diff --git a/scst/include/scst.h b/scst/include/scst.h index 20e2c6685..4045f041b 100644 --- a/scst/include/scst.h +++ b/scst/include/scst.h @@ -4080,6 +4080,10 @@ static inline void *sg_virt(struct scatterlist *sg) return page_address(sg_page(sg)) + sg->offset; } +static inline void sg_mark_end(struct scatterlist *sg) +{ +} + #ifndef __BACKPORT_LINUX_SCATTERLIST_H_TO_2_6_23__ static inline void sg_init_table(struct scatterlist *sgl, unsigned int nents) diff --git a/scst/src/scst_lib.c b/scst/src/scst_lib.c index 669cafdb7..ca608d657 100644 --- a/scst/src/scst_lib.c +++ b/scst/src/scst_lib.c @@ -5165,6 +5165,20 @@ struct scst_write_same_priv { struct scatterlist *ws_sg; }; +#ifdef CONFIG_SCST_EXTRACHECKS +static u64 sg_data_length(struct scatterlist *sgl, int nr) +{ + struct scatterlist *sg; + u64 len = 0; + int i; + + for_each_sg(sgl, sg, nr, i) + len += sg->length; + + return len; +} +#endif + /* ws_mutex suppose to be locked */ static int scst_ws_push_single_write(struct scst_write_same_priv *wsp, int64_t lba, int blocks) @@ -5178,7 +5192,7 @@ static int scst_ws_push_single_write(struct scst_write_same_priv *wsp, TRACE_ENTRY(); - EXTRACHECKS_BUG_ON(blocks > wsp->ws_sg_cnt); + EXTRACHECKS_BUG_ON(len != sg_data_length(wsp->ws_sg, wsp->ws_sg_cnt)); if (unlikely(test_bit(SCST_CMD_ABORTED, &ws_cmd->cmd_flags)) || unlikely(ws_cmd->completed)) { @@ -5208,7 +5222,7 @@ static int scst_ws_push_single_write(struct scst_write_same_priv *wsp, cmd->tgt_i_priv = wsp; cmd->tgt_i_sg = ws_sg; - cmd->tgt_i_sg_cnt = blocks; + cmd->tgt_i_sg_cnt = wsp->ws_sg_cnt; cmd->tgt_i_data_buf_alloced = 1; wsp->ws_cur_lba += blocks; @@ -5241,6 +5255,8 @@ static void scst_ws_finished(struct scst_write_same_priv *wsp) sBUG_ON(wsp->ws_cur_in_flight != 0); + if (sg_page(&wsp->ws_sg[0]) != sg_page(ws_cmd->sg)) + __free_page(sg_page(&wsp->ws_sg[0])); kfree(wsp->ws_sg); kfree(wsp); @@ -5251,6 +5267,51 @@ static void scst_ws_finished(struct scst_write_same_priv *wsp) return; } +/* + * If there is a tail with fewer segments than ws_max_each, adjust the SG + * vector and submit a WRITE command for the tail after all other in-flight + * commands have finished. + */ +static void scst_ws_process_tail(struct scst_write_same_priv *wsp) +{ + struct scst_cmd *ws_cmd = wsp->ws_orig_cmd; + struct scatterlist *sg; + unsigned left; + int i; + + TRACE_ENTRY(); + + lockdep_assert_held(&wsp->ws_mutex); + EXTRACHECKS_BUG_ON(wsp->ws_cur_in_flight > 0); + EXTRACHECKS_BUG_ON(wsp->ws_left_to_send >= wsp->ws_max_each); + + wsp->ws_max_each = wsp->ws_left_to_send; + left = wsp->ws_left_to_send << ws_cmd->dev->block_shift; + for_each_sg(wsp->ws_sg, sg, wsp->ws_sg_cnt, i) { + u32 len = min(left, sg->length); + + if (sg->length > len) { + TRACE_DBG("Processing WS tail of %d << %d = %d bytes - adjusted length of element %d from %d to %d", + wsp->ws_left_to_send, + ws_cmd->dev->block_shift, + wsp->ws_left_to_send << ws_cmd->dev->block_shift, + i, sg->length, len); + sg->length = len; + sg_mark_end(sg); +#if LINUX_VERSION_CODE < KERNEL_VERSION(3, 0, 0) + /* Old versions of sg_mark_end() clear page_link. */ + BUG_ON(sg_page(sg) == NULL); +#endif + wsp->ws_sg_cnt = i + 1; + break; + } + left -= len; + } + + TRACE_EXIT(); + return; +} + /* Must be called in a thread context and no locks */ static void scst_ws_write_cmd_finished(struct scst_cmd *cmd) { @@ -5292,6 +5353,13 @@ static void scst_ws_write_cmd_finished(struct scst_cmd *cmd) if (wsp->ws_left_to_send == 0) goto out_check_finish; + if (wsp->ws_left_to_send < wsp->ws_max_each) { + if (wsp->ws_cur_in_flight > 0) + goto out_check_finish; + else + scst_ws_process_tail(wsp); + } + blocks = min_t(int, wsp->ws_left_to_send, wsp->ws_max_each); rc = scst_ws_push_single_write(wsp, wsp->ws_cur_lba, blocks); @@ -5326,13 +5394,15 @@ static void scst_ws_gen_writes(struct scst_write_same_priv *wsp) mutex_lock(&wsp->ws_mutex); - while ((wsp->ws_left_to_send > 0) && - (wsp->ws_cur_in_flight < SCST_MAX_IN_FLIGHT_INTERNAL_COMMANDS)) { - int rc, blocks; + if (wsp->ws_left_to_send < wsp->ws_max_each) + scst_ws_process_tail(wsp); - blocks = min_t(int, wsp->ws_left_to_send, wsp->ws_max_each); + while (wsp->ws_left_to_send >= wsp->ws_max_each && + wsp->ws_cur_in_flight < SCST_MAX_IN_FLIGHT_INTERNAL_COMMANDS) { + int rc; - rc = scst_ws_push_single_write(wsp, wsp->ws_cur_lba, blocks); + rc = scst_ws_push_single_write(wsp, wsp->ws_cur_lba, + wsp->ws_max_each); if (rc != 0) goto out_err; @@ -5366,6 +5436,9 @@ out_err: void scst_write_same(struct scst_cmd *cmd) { struct scst_write_same_priv *wsp; + struct page *pg = NULL; + struct scatterlist *sg; + unsigned int offset, length, mult, ws_sg_blocks, left; int i; TRACE_ENTRY(); @@ -5413,18 +5486,44 @@ void scst_write_same(struct scst_cmd *cmd) wsp->ws_left_to_send = cmd->data_len >> cmd->dev->block_shift; wsp->ws_max_each = SCST_MAX_EACH_INTERNAL_IO_SIZE >> cmd->dev->block_shift; - wsp->ws_sg_cnt = min_t(int, wsp->ws_left_to_send, wsp->ws_max_each); + if (cmd->bufflen <= PAGE_SIZE / 2) + pg = alloc_page(GFP_KERNEL); + if (pg) { + void *src, *dst; + int k; + + mult = 0; + src = kmap(sg_page(cmd->sg)); + dst = kmap(pg); + for (k = 0; k < PAGE_SIZE; k += cmd->bufflen, mult++) + memcpy(dst + k, src + cmd->sg->offset, cmd->bufflen); + kunmap(pg); + kunmap(src); + offset = 0; + length = k; + } else { + pg = sg_page(cmd->sg); + offset = cmd->sg->offset; + length = cmd->sg->length; + mult = 1; + } + + ws_sg_blocks = min_t(int, wsp->ws_left_to_send, wsp->ws_max_each); + wsp->ws_sg_cnt = (ws_sg_blocks + mult - 1) / mult; wsp->ws_sg = kmalloc(wsp->ws_sg_cnt * sizeof(*wsp->ws_sg), GFP_KERNEL); if (wsp->ws_sg == NULL) { PRINT_ERROR("Unable to alloc sg for %d entries", wsp->ws_sg_cnt); goto out_free; } sg_init_table(wsp->ws_sg, wsp->ws_sg_cnt); + left = ws_sg_blocks << cmd->dev->block_shift; + for_each_sg(wsp->ws_sg, sg, wsp->ws_sg_cnt, i) { + u32 len = min(left, length); - for (i = 0; i < wsp->ws_sg_cnt; i++) { - sg_set_page(&wsp->ws_sg[i], sg_page(cmd->sg), - cmd->sg->length, cmd->sg->offset); + sg_set_page(sg, pg, len, offset); + left -= len; } + sBUG_ON(left != 0); /* crash here to avoid data corruption */ scst_ws_gen_writes(wsp); @@ -5433,6 +5532,8 @@ out: return; out_free: + if (pg && pg != sg_page(cmd->sg)) + __free_page(pg); kfree(wsp); out_busy: