]> Pileus Git - ~andy/linux/blobdiff - include/linux/scatterlist.h
lib/scatterlist: use page iterator in the mapping iterator
[~andy/linux] / include / linux / scatterlist.h
index 4bd6c06eb28edb13cc8a47698fd2b1df94d72f65..2d8bdaef96116517cb8c6c1862a3cb82a3a863db 100644 (file)
@@ -231,6 +231,41 @@ size_t sg_copy_to_buffer(struct scatterlist *sgl, unsigned int nents,
  */
 #define SG_MAX_SINGLE_ALLOC            (PAGE_SIZE / sizeof(struct scatterlist))
 
+/*
+ * sg page iterator
+ *
+ * Iterates over sg entries page-by-page.  On each successful iteration,
+ * @piter->page points to the current page, @piter->sg to the sg holding this
+ * page and @piter->sg_pgoffset to the page's page offset within the sg. The
+ * iteration will stop either when a maximum number of sg entries was reached
+ * or a terminating sg (sg_last(sg) == true) was reached.
+ */
+struct sg_page_iter {
+       struct page             *page;          /* current page */
+       struct scatterlist      *sg;            /* sg holding the page */
+       unsigned int            sg_pgoffset;    /* page offset within the sg */
+
+       /* these are internal states, keep away */
+       unsigned int            __nents;        /* remaining sg entries */
+       int                     __pg_advance;   /* nr pages to advance at the
+                                                * next step */
+};
+
+bool __sg_page_iter_next(struct sg_page_iter *piter);
+void __sg_page_iter_start(struct sg_page_iter *piter,
+                         struct scatterlist *sglist, unsigned int nents,
+                         unsigned long pgoffset);
+
+/**
+ * for_each_sg_page - iterate over the pages of the given sg list
+ * @sglist:    sglist to iterate over
+ * @piter:     page iterator to hold current page, sg, sg_pgoffset
+ * @nents:     maximum number of sg entries to iterate over
+ * @pgoffset:  starting page offset
+ */
+#define for_each_sg_page(sglist, piter, nents, pgoffset)                  \
+       for (__sg_page_iter_start((piter), (sglist), (nents), (pgoffset)); \
+            __sg_page_iter_next(piter);)
 
 /*
  * Mapping sg iterator
@@ -258,11 +293,11 @@ struct sg_mapping_iter {
        void                    *addr;          /* pointer to the mapped area */
        size_t                  length;         /* length of the mapped area */
        size_t                  consumed;       /* number of consumed bytes */
+       struct sg_page_iter     piter;          /* page iterator */
 
        /* these are internal states, keep away */
-       struct scatterlist      *__sg;          /* current entry */
-       unsigned int            __nents;        /* nr of remaining entries */
-       unsigned int            __offset;       /* offset within sg */
+       unsigned int            __offset;       /* offset within page */
+       unsigned int            __remaining;    /* remaining bytes on page */
        unsigned int            __flags;
 };