Whamcloud - gitweb
LU-8057 ko2iblnd: Replace sg++ with sg = sg_next(sg) 42/19342/12
authorAmitoj Kaur Chawla <amitoj1606@gmail.com>
Wed, 1 Jun 2016 13:16:25 +0000 (09:16 -0400)
committerOleg Drokin <oleg.drokin@intel.com>
Tue, 14 Jun 2016 03:45:38 +0000 (03:45 +0000)
With scatterlist chaining, simply incrementing the array does not
work. sg_next macro was thus introduced to follow the chain links
when necessary. So replace sg++ with sg_next.

This change was made with the help of the following Coccinelle
semantic patch:
//<smpl>
@@
 struct scatterlist *sg;
@@
 -sg++
 +sg = sg_next(sg)
//</smpl>

In my test of the upstream client this change exposed a long
standing issues where we have a offset that is not page aligned
would cause us to access memory beyond the scatter gather list
which was causing memory corruption when all 256 fragments were
in use.

Signed-off-by: James Simmons <uja.ornl@yahoo.com>
Change-Id: I5bc140645b841aa2a92da434ffa65795112c6cec
Signed-off-by: Amitoj Kaur Chawla <amitoj1606@gmail.com>
Signed-off-by: Greg Kroah-Hartman <gregkh@linuxfoundation.org>
Reviewed-on: http://review.whamcloud.com/19342
Tested-by: Jenkins
Reviewed-by: Andreas Dilger <andreas.dilger@intel.com>
Reviewed-by: Doug Oucharek <doug.s.oucharek@intel.com>
Tested-by: Maloo <hpdd-maloo@intel.com>
Reviewed-by: Oleg Drokin <oleg.drokin@intel.com>
lnet/klnds/o2iblnd/o2iblnd.c
lnet/klnds/o2iblnd/o2iblnd_cb.c

index 92254b8..09d4f56 100644 (file)
@@ -2216,8 +2216,8 @@ kiblnd_destroy_tx_pool(kib_pool_t *pool)
                                     sizeof(*tx->tx_pages));
                 if (tx->tx_frags != NULL)
                         LIBCFS_FREE(tx->tx_frags,
                                     sizeof(*tx->tx_pages));
                 if (tx->tx_frags != NULL)
                         LIBCFS_FREE(tx->tx_frags,
-                                    IBLND_MAX_RDMA_FRAGS *
-                                            sizeof(*tx->tx_frags));
+                                   (1 + IBLND_MAX_RDMA_FRAGS) *
+                                   sizeof(*tx->tx_frags));
                 if (tx->tx_wrq != NULL)
                         LIBCFS_FREE(tx->tx_wrq,
                                     (1 + IBLND_MAX_RDMA_FRAGS) *
                 if (tx->tx_wrq != NULL)
                         LIBCFS_FREE(tx->tx_wrq,
                                     (1 + IBLND_MAX_RDMA_FRAGS) *
@@ -2295,11 +2295,12 @@ kiblnd_create_tx_pool(kib_poolset_t *ps, int size, kib_pool_t **pp_po)
                }
 
                LIBCFS_CPT_ALLOC(tx->tx_frags, lnet_cpt_table(), ps->ps_cpt,
                }
 
                LIBCFS_CPT_ALLOC(tx->tx_frags, lnet_cpt_table(), ps->ps_cpt,
-                                IBLND_MAX_RDMA_FRAGS * sizeof(*tx->tx_frags));
+                                (1 + IBLND_MAX_RDMA_FRAGS) *
+                                sizeof(*tx->tx_frags));
                if (tx->tx_frags == NULL)
                        break;
 
                if (tx->tx_frags == NULL)
                        break;
 
-               sg_init_table(tx->tx_frags, IBLND_MAX_RDMA_FRAGS);
+               sg_init_table(tx->tx_frags, IBLND_MAX_RDMA_FRAGS + 1);
 
                LIBCFS_CPT_ALLOC(tx->tx_wrq, lnet_cpt_table(), ps->ps_cpt,
                                 (1 + IBLND_MAX_RDMA_FRAGS) *
 
                LIBCFS_CPT_ALLOC(tx->tx_wrq, lnet_cpt_table(), ps->ps_cpt,
                                 (1 + IBLND_MAX_RDMA_FRAGS) *
index 4ff2e98..6b4bd30 100644 (file)
@@ -688,7 +688,11 @@ kiblnd_setup_rd_iov(lnet_ni_t *ni, kib_tx_t *tx, kib_rdma_desc_t *rd,
                 fragnob = min(fragnob, (int)PAGE_SIZE - page_offset);
 
                 sg_set_page(sg, page, fragnob, page_offset);
                 fragnob = min(fragnob, (int)PAGE_SIZE - page_offset);
 
                 sg_set_page(sg, page, fragnob, page_offset);
-                sg++;
+               sg = sg_next(sg);
+               if (!sg) {
+                       CERROR("lacking enough sg entries to map tx\n");
+                       return -EFAULT;
+               }
 
                 if (offset + fragnob < iov->iov_len) {
                         offset += fragnob;
 
                 if (offset + fragnob < iov->iov_len) {
                         offset += fragnob;
@@ -730,9 +734,13 @@ kiblnd_setup_rd_kiov (lnet_ni_t *ni, kib_tx_t *tx, kib_rdma_desc_t *rd,
 
                 fragnob = min((int)(kiov->kiov_len - offset), nob);
 
 
                 fragnob = min((int)(kiov->kiov_len - offset), nob);
 
-                sg_set_page(sg, kiov->kiov_page, fragnob,
-                            kiov->kiov_offset + offset);
-                sg++;
+               sg_set_page(sg, kiov->kiov_page, fragnob,
+                           kiov->kiov_offset + offset);
+               sg = sg_next(sg);
+               if (!sg) {
+                       CERROR("lacking enough sg entries to map tx\n");
+                       return -EFAULT;
+               }
 
                 offset = 0;
                 kiov++;
 
                 offset = 0;
                 kiov++;