*/
 #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
 
 }
 EXPORT_SYMBOL(sg_alloc_table_from_pages);
 
+void __sg_page_iter_start(struct sg_page_iter *piter,
+                         struct scatterlist *sglist, unsigned int nents,
+                         unsigned long pgoffset)
+{
+       piter->__pg_advance = 0;
+       piter->__nents = nents;
+
+       piter->page = NULL;
+       piter->sg = sglist;
+       piter->sg_pgoffset = pgoffset;
+}
+EXPORT_SYMBOL(__sg_page_iter_start);
+
+static int sg_page_count(struct scatterlist *sg)
+{
+       return PAGE_ALIGN(sg->offset + sg->length) >> PAGE_SHIFT;
+}
+
+bool __sg_page_iter_next(struct sg_page_iter *piter)
+{
+       if (!piter->__nents || !piter->sg)
+               return false;
+
+       piter->sg_pgoffset += piter->__pg_advance;
+       piter->__pg_advance = 1;
+
+       while (piter->sg_pgoffset >= sg_page_count(piter->sg)) {
+               piter->sg_pgoffset -= sg_page_count(piter->sg);
+               piter->sg = sg_next(piter->sg);
+               if (!--piter->__nents || !piter->sg)
+                       return false;
+       }
+       piter->page = nth_page(sg_page(piter->sg), piter->sg_pgoffset);
+
+       return true;
+}
+EXPORT_SYMBOL(__sg_page_iter_next);
+
 /**
  * sg_miter_start - start mapping iteration over a sg list
  * @miter: sg mapping iter to be started