]> asedeno.scripts.mit.edu Git - linux.git/blobdiff - lib/scatterlist.c
m68k: defconfig: Update defconfigs for v5.5-rc3
[linux.git] / lib / scatterlist.c
index 2882d9ba6607a71490f994518d16bae4e59a16e5..c2cf2c311b7dba0b055da1bca59bbca20d340420 100644 (file)
@@ -179,7 +179,8 @@ static void sg_kfree(struct scatterlist *sg, unsigned int nents)
  * __sg_free_table - Free a previously mapped sg table
  * @table:     The sg table header to use
  * @max_ents:  The maximum number of entries per single scatterlist
- * @skip_first_chunk: don't free the (preallocated) first scatterlist chunk
+ * @nents_first_chunk: Number of entries int the (preallocated) first
+ *     scatterlist chunk, 0 means no such preallocated first chunk
  * @free_fn:   Free function
  *
  *  Description:
@@ -189,9 +190,10 @@ static void sg_kfree(struct scatterlist *sg, unsigned int nents)
  *
  **/
 void __sg_free_table(struct sg_table *table, unsigned int max_ents,
-                    bool skip_first_chunk, sg_free_fn *free_fn)
+                    unsigned int nents_first_chunk, sg_free_fn *free_fn)
 {
        struct scatterlist *sgl, *next;
+       unsigned curr_max_ents = nents_first_chunk ?: max_ents;
 
        if (unlikely(!table->sgl))
                return;
@@ -207,9 +209,9 @@ void __sg_free_table(struct sg_table *table, unsigned int max_ents,
                 * sg_size is then one less than alloc size, since the last
                 * element is the chain pointer.
                 */
-               if (alloc_size > max_ents) {
-                       next = sg_chain_ptr(&sgl[max_ents - 1]);
-                       alloc_size = max_ents;
+               if (alloc_size > curr_max_ents) {
+                       next = sg_chain_ptr(&sgl[curr_max_ents - 1]);
+                       alloc_size = curr_max_ents;
                        sg_size = alloc_size - 1;
                } else {
                        sg_size = alloc_size;
@@ -217,11 +219,12 @@ void __sg_free_table(struct sg_table *table, unsigned int max_ents,
                }
 
                table->orig_nents -= sg_size;
-               if (skip_first_chunk)
-                       skip_first_chunk = false;
+               if (nents_first_chunk)
+                       nents_first_chunk = 0;
                else
                        free_fn(sgl, alloc_size);
                sgl = next;
+               curr_max_ents = max_ents;
        }
 
        table->sgl = NULL;
@@ -244,6 +247,8 @@ EXPORT_SYMBOL(sg_free_table);
  * @table:     The sg table header to use
  * @nents:     Number of entries in sg list
  * @max_ents:  The maximum number of entries the allocator returns per call
+ * @nents_first_chunk: Number of entries int the (preallocated) first
+ *     scatterlist chunk, 0 means no such preallocated chunk provided by user
  * @gfp_mask:  GFP allocation mask
  * @alloc_fn:  Allocator to use
  *
@@ -260,10 +265,13 @@ EXPORT_SYMBOL(sg_free_table);
  **/
 int __sg_alloc_table(struct sg_table *table, unsigned int nents,
                     unsigned int max_ents, struct scatterlist *first_chunk,
-                    gfp_t gfp_mask, sg_alloc_fn *alloc_fn)
+                    unsigned int nents_first_chunk, gfp_t gfp_mask,
+                    sg_alloc_fn *alloc_fn)
 {
        struct scatterlist *sg, *prv;
        unsigned int left;
+       unsigned curr_max_ents = nents_first_chunk ?: max_ents;
+       unsigned prv_max_ents;
 
        memset(table, 0, sizeof(*table));
 
@@ -279,8 +287,8 @@ int __sg_alloc_table(struct sg_table *table, unsigned int nents,
        do {
                unsigned int sg_size, alloc_size = left;
 
-               if (alloc_size > max_ents) {
-                       alloc_size = max_ents;
+               if (alloc_size > curr_max_ents) {
+                       alloc_size = curr_max_ents;
                        sg_size = alloc_size - 1;
                } else
                        sg_size = alloc_size;
@@ -314,7 +322,7 @@ int __sg_alloc_table(struct sg_table *table, unsigned int nents,
                 * If this is not the first mapping, chain previous part.
                 */
                if (prv)
-                       sg_chain(prv, max_ents, sg);
+                       sg_chain(prv, prv_max_ents, sg);
                else
                        table->sgl = sg;
 
@@ -325,6 +333,8 @@ int __sg_alloc_table(struct sg_table *table, unsigned int nents,
                        sg_mark_end(&sg[sg_size - 1]);
 
                prv = sg;
+               prv_max_ents = curr_max_ents;
+               curr_max_ents = max_ents;
        } while (left);
 
        return 0;
@@ -347,9 +357,9 @@ int sg_alloc_table(struct sg_table *table, unsigned int nents, gfp_t gfp_mask)
        int ret;
 
        ret = __sg_alloc_table(table, nents, SG_MAX_SINGLE_ALLOC,
-                              NULL, gfp_mask, sg_kmalloc);
+                              NULL, 0, gfp_mask, sg_kmalloc);
        if (unlikely(ret))
-               __sg_free_table(table, SG_MAX_SINGLE_ALLOC, false, sg_kfree);
+               __sg_free_table(table, SG_MAX_SINGLE_ALLOC, 0, sg_kfree);
 
        return ret;
 }
@@ -676,17 +686,18 @@ static bool sg_miter_get_next_page(struct sg_mapping_iter *miter)
 {
        if (!miter->__remaining) {
                struct scatterlist *sg;
-               unsigned long pgoffset;
 
                if (!__sg_page_iter_next(&miter->piter))
                        return false;
 
                sg = miter->piter.sg;
-               pgoffset = miter->piter.sg_pgoffset;
 
-               miter->__offset = pgoffset ? 0 : sg->offset;
+               miter->__offset = miter->piter.sg_pgoffset ? 0 : sg->offset;
+               miter->piter.sg_pgoffset += miter->__offset >> PAGE_SHIFT;
+               miter->__offset &= PAGE_SIZE - 1;
                miter->__remaining = sg->offset + sg->length -
-                               (pgoffset << PAGE_SHIFT) - miter->__offset;
+                                    (miter->piter.sg_pgoffset << PAGE_SHIFT) -
+                                    miter->__offset;
                miter->__remaining = min_t(unsigned long, miter->__remaining,
                                           PAGE_SIZE - miter->__offset);
        }