Here's a program that can be used to exercise the iter_xarray_get_pages() function in userspace. In the main() function, there are various parameters that can be adjusted, such as the starting offset (iter.xarray_start), the size of the content (iter.count), the maximum number of pages to be extracted (maxpages) and the maximum size to be extracted (maxsize). David --- /* SPDX-License-Identifier: GPL-2.0 */ #include <stdbool.h> #include <stdlib.h> #include <stdio.h> #include <string.h> typedef unsigned long pgoff_t; #define PAGE_SHIFT 12 #define PAGE_SIZE ((unsigned long)1 << PAGE_SHIFT) #define PAGE_MASK (~(PAGE_SIZE - 1)) struct page; struct xarray; struct iov_iter { size_t iov_offset; size_t count; loff_t xarray_start; }; #define __is_constexpr(x) \ (sizeof(int) == sizeof(*(8 ? ((void *)((long)(x) * 0l)) : (int *)8))) #define __typecheck(x, y) \ (!!(sizeof((typeof(x) *)1 == (typeof(y) *)1))) #define __no_side_effects(x, y) \ (__is_constexpr(x) && __is_constexpr(y)) #define __safe_cmp(x, y) \ (__typecheck(x, y) && __no_side_effects(x, y)) #define __cmp(x, y, op) ((x) op (y) ? (x) : (y)) #define __cmp_once(x, y, unique_x, unique_y, op) ({ \ typeof(x) unique_x = (x); \ typeof(y) unique_y = (y); \ __cmp(unique_x, unique_y, op); }) #define __careful_cmp(x, y, op) \ __builtin_choose_expr(__safe_cmp(x, y), \ __cmp(x, y, op), \ __cmp_once(x, y, __x, __y, op)) #define min(x, y) __careful_cmp(x, y, <) #define min_t(type, x, y) __careful_cmp((type)(x), (type)(y), <) static int apply_fix; static ssize_t iter_xarray_populate_pages(pgoff_t index, unsigned int nr_pages) { return nr_pages; } static ssize_t iter_xarray_get_pages(struct iov_iter *i, size_t maxsize, unsigned maxpages, size_t *_start_offset) { unsigned nr, offset; pgoff_t index, count; size_t size = maxsize, head_size, tail_size; loff_t pos; if (!size || !maxpages) return 0; pos = i->xarray_start + i->iov_offset; index = pos >> PAGE_SHIFT; offset = pos & ~PAGE_MASK; *_start_offset = offset; count = 1; tail_size = head_size = PAGE_SIZE - offset; if (maxsize > head_size) { size -= head_size; count += size >> PAGE_SHIFT; tail_size = size & ~PAGE_MASK; if (tail_size) count++; } if (count > maxpages) count = maxpages; printf(" %6lx %6lu %6zx |", index, count, tail_size); nr = iter_xarray_populate_pages(index, count); if (nr == 0) return 0; if (!apply_fix) { size_t actual = PAGE_SIZE * nr; actual -= offset; if (nr == count && size > 0) { unsigned last_offset = (nr > 1) ? 0 : offset; actual -= PAGE_SIZE - (last_offset + size); } return actual; } else { return min(nr * PAGE_SIZE - offset, maxsize); } } ssize_t iov_iter_get_pages(struct iov_iter *i, size_t maxsize, unsigned maxpages, size_t *start) { if (maxsize > i->count) maxsize = i->count; if (!maxsize) return 0; return iter_xarray_get_pages(i, maxsize, maxpages, start); } int main() { struct iov_iter iter; ssize_t size; size_t i, maxpages, maxsize, offset; memset(&iter, 0, sizeof(iter)); /* Adjustable parameters */ iter.xarray_start = 0x11000; iter.count = PAGE_SIZE * 16; maxpages = 15; maxsize = maxpages * PAGE_SIZE; printf("X-STRT X-OFFS X-CNT | INDEX COUNT T-SIZE | OFFSET SIZE\n"); printf("====== ====== ====== | ====== ====== ====== | ====== ======\n"); for (apply_fix = 0; apply_fix < 2; apply_fix++) { i = 0; for (;;) { iter.iov_offset = i; printf("%6lx %6zx %6zx |", iter.xarray_start, iter.iov_offset, iter.count); size = iov_iter_get_pages(&iter, maxsize, maxpages, &offset); printf(" %6zx %6zx", offset, size); if (offset + size > maxsize) printf(" ** BIG"); if (offset + size > iter.iov_offset + iter.count) printf(" ** OVER"); printf("\n"); if (i > PAGE_SIZE) break; i += 0x111; } } return 0; }