On Mon, Dec 28, 2020 at 06:49:52PM -0500, Douglas Gilbert wrote:
diff --git a/lib/scatterlist.c b/lib/scatterlist.c
index a59778946404..4986545beef9 100644
+++ b/lib/scatterlist.c
@@ -554,13 +554,15 @@ EXPORT_SYMBOL(sg_alloc_table_from_pages);
#ifdef CONFIG_SGL_ALLOC
/**
- * sgl_alloc_order - allocate a scatterlist and its pages
+ * sgl_alloc_order - allocate a scatterlist with equally sized elements
* @length: Length in bytes of the scatterlist. Must be at least one
- * @order: Second argument for alloc_pages()
+ * @order: Second argument for alloc_pages(). Each sgl element size will
+ * be (PAGE_SIZE*2^order) bytes
* @chainable: Whether or not to allocate an extra element in the scatterlist
- * for scatterlist chaining purposes
+ * for scatterlist chaining purposes
* @gfp: Memory allocation flags
- * @nent_p: [out] Number of entries in the scatterlist that have pages
+ * @nent_p: [out] Number of entries in the scatterlist that have pages.
+ * Ignored if NULL is given.
*
* Returns: A pointer to an initialized scatterlist or %NULL upon failure.
*/
@@ -574,8 +576,8 @@ struct scatterlist *sgl_alloc_order(unsigned long long length,
u32 elem_len;
nent = round_up(length, PAGE_SIZE << order) >> (PAGE_SHIFT + order);
- /* Check for integer overflow */
- if (length > (nent << (PAGE_SHIFT + order)))
+ /* Integer overflow if: length > nent*2^(PAGE_SHIFT+order) */
+ if (ilog2(length) > ilog2(nent) + PAGE_SHIFT + order)
return NULL;
nalloc = nent;
if (chainable) {
This is a little bit too tortured now, how about this:
if (length >> (PAGE_SHIFT + order) >= UINT_MAX)
return NULL;
nent = length >> (PAGE_SHIFT + order);
if (length & ((1ULL << (PAGE_SHIFT + order)) - 1))
nent++;
if (chainable) {
if (check_add_overflow(nent, 1, &nalloc))
return NULL;
}
else
nalloc = nent;