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;
}
--
Linux-cachefs mailing list
Linux-cachefs@redhat.com
https://listman.redhat.com/mailman/listinfo/linux-cachefs

Reply via email to