Merge tag 'urgent/nolibc.2023.10.16a' of git://git.kernel.org/pub/scm/linux/kernel...
[platform/kernel/linux-rpi.git] / io_uring / kbuf.c
index 556f4df..9123138 100644 (file)
@@ -477,7 +477,7 @@ static int io_pin_pbuf_ring(struct io_uring_buf_reg *reg,
 {
        struct io_uring_buf_ring *br;
        struct page **pages;
-       int nr_pages;
+       int i, nr_pages;
 
        pages = io_pin_pages(reg->ring_addr,
                             flex_array_size(br, bufs, reg->ring_entries),
@@ -485,6 +485,17 @@ static int io_pin_pbuf_ring(struct io_uring_buf_reg *reg,
        if (IS_ERR(pages))
                return PTR_ERR(pages);
 
+       /*
+        * Apparently some 32-bit boxes (ARM) will return highmem pages,
+        * which then need to be mapped. We could support that, but it'd
+        * complicate the code and slowdown the common cases quite a bit.
+        * So just error out, returning -EINVAL just like we did on kernels
+        * that didn't support mapped buffer rings.
+        */
+       for (i = 0; i < nr_pages; i++)
+               if (PageHighMem(pages[i]))
+                       goto error_unpin;
+
        br = page_address(pages[0]);
 #ifdef SHM_COLOUR
        /*
@@ -496,13 +507,8 @@ static int io_pin_pbuf_ring(struct io_uring_buf_reg *reg,
         * should use IOU_PBUF_RING_MMAP instead, and liburing will handle
         * this transparently.
         */
-       if ((reg->ring_addr | (unsigned long) br) & (SHM_COLOUR - 1)) {
-               int i;
-
-               for (i = 0; i < nr_pages; i++)
-                       unpin_user_page(pages[i]);
-               return -EINVAL;
-       }
+       if ((reg->ring_addr | (unsigned long) br) & (SHM_COLOUR - 1))
+               goto error_unpin;
 #endif
        bl->buf_pages = pages;
        bl->buf_nr_pages = nr_pages;
@@ -510,6 +516,11 @@ static int io_pin_pbuf_ring(struct io_uring_buf_reg *reg,
        bl->is_mapped = 1;
        bl->is_mmap = 0;
        return 0;
+error_unpin:
+       for (i = 0; i < nr_pages; i++)
+               unpin_user_page(pages[i]);
+       kvfree(pages);
+       return -EINVAL;
 }
 
 static int io_alloc_pbuf_ring(struct io_uring_buf_reg *reg,