kernel/kfifo.c: add handling of chained scatterlists
Stefani Seibold [Wed, 11 Aug 2010 21:17:27 +0000 (14:17 -0700)]
The current kfifo scatterlist implementation will not work with chained
scatterlists.  It assumes that struct scatterlist arrays are allocated
contiguously, which is not the case when chained scatterlists (struct
sg_table) are in use.

Signed-off-by: Stefani Seibold <stefani@seibold.net>
Signed-off-by: Andrew Morton <akpm@linux-foundation.org>
Signed-off-by: Linus Torvalds <torvalds@linux-foundation.org>

kernel/kfifo.c

index 02192dd..4502604 100644 (file)
@@ -10,7 +10,7 @@
  *
  * This program is distributed in the hope that it will be useful,
  * but WITHOUT ANY WARRANTY; without even the implied warranty of
- * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
  * GNU General Public License for more details.
  *
  * You should have received a copy of the GNU General Public License
@@ -333,17 +333,16 @@ static int setup_sgl_buf(struct scatterlist *sgl, void *buf,
                buf += PAGE_SIZE;
                npage = virt_to_page(buf);
                if (page_to_phys(page) != page_to_phys(npage) - l) {
-                       sgl->page_link = 0;
-                       sg_set_page(sgl++, page, l - off, off);
-                       if (++n == nents)
+                       sg_set_page(sgl, page, l - off, off);
+                       sgl = sg_next(sgl);
+                       if (++n == nents || sgl == NULL)
                                return n;
                        page = npage;
                        len -= l - off;
                        l = off = 0;
                }
        }
-       sgl->page_link = 0;
-       sg_set_page(sgl++, page, len, off);
+       sg_set_page(sgl, page, len, off);
        return n + 1;
 }
 
@@ -363,7 +362,7 @@ static unsigned int setup_sgl(struct __kfifo *fifo, struct scatterlist *sgl,
        }
        l = min(len, size - off);
 
-       n  = setup_sgl_buf(sgl, fifo->data + off, nents, l);
+       n = setup_sgl_buf(sgl, fifo->data + off, nents, l);
        n += setup_sgl_buf(sgl + n, fifo->data, nents - n, len - l);
 
        if (n)