linux/net/ceph/pagevec.c
<<
>>
Prefs
   1// SPDX-License-Identifier: GPL-2.0
   2#include <linux/ceph/ceph_debug.h>
   3
   4#include <linux/module.h>
   5#include <linux/sched.h>
   6#include <linux/slab.h>
   7#include <linux/file.h>
   8#include <linux/namei.h>
   9#include <linux/writeback.h>
  10
  11#include <linux/ceph/libceph.h>
  12
  13void ceph_put_page_vector(struct page **pages, int num_pages, bool dirty)
  14{
  15        int i;
  16
  17        for (i = 0; i < num_pages; i++) {
  18                if (dirty)
  19                        set_page_dirty_lock(pages[i]);
  20                put_page(pages[i]);
  21        }
  22        kvfree(pages);
  23}
  24EXPORT_SYMBOL(ceph_put_page_vector);
  25
  26void ceph_release_page_vector(struct page **pages, int num_pages)
  27{
  28        int i;
  29
  30        for (i = 0; i < num_pages; i++)
  31                __free_pages(pages[i], 0);
  32        kfree(pages);
  33}
  34EXPORT_SYMBOL(ceph_release_page_vector);
  35
  36/*
  37 * allocate a vector new pages
  38 */
  39struct page **ceph_alloc_page_vector(int num_pages, gfp_t flags)
  40{
  41        struct page **pages;
  42        int i;
  43
  44        pages = kmalloc_array(num_pages, sizeof(*pages), flags);
  45        if (!pages)
  46                return ERR_PTR(-ENOMEM);
  47        for (i = 0; i < num_pages; i++) {
  48                pages[i] = __page_cache_alloc(flags);
  49                if (pages[i] == NULL) {
  50                        ceph_release_page_vector(pages, i);
  51                        return ERR_PTR(-ENOMEM);
  52                }
  53        }
  54        return pages;
  55}
  56EXPORT_SYMBOL(ceph_alloc_page_vector);
  57
  58/*
  59 * copy user data into a page vector
  60 */
  61int ceph_copy_user_to_page_vector(struct page **pages,
  62                                         const void __user *data,
  63                                         loff_t off, size_t len)
  64{
  65        int i = 0;
  66        int po = off & ~PAGE_MASK;
  67        int left = len;
  68        int l, bad;
  69
  70        while (left > 0) {
  71                l = min_t(int, PAGE_SIZE-po, left);
  72                bad = copy_from_user(page_address(pages[i]) + po, data, l);
  73                if (bad == l)
  74                        return -EFAULT;
  75                data += l - bad;
  76                left -= l - bad;
  77                po += l - bad;
  78                if (po == PAGE_SIZE) {
  79                        po = 0;
  80                        i++;
  81                }
  82        }
  83        return len;
  84}
  85EXPORT_SYMBOL(ceph_copy_user_to_page_vector);
  86
  87void ceph_copy_to_page_vector(struct page **pages,
  88                                    const void *data,
  89                                    loff_t off, size_t len)
  90{
  91        int i = 0;
  92        size_t po = off & ~PAGE_MASK;
  93        size_t left = len;
  94
  95        while (left > 0) {
  96                size_t l = min_t(size_t, PAGE_SIZE-po, left);
  97
  98                memcpy(page_address(pages[i]) + po, data, l);
  99                data += l;
 100                left -= l;
 101                po += l;
 102                if (po == PAGE_SIZE) {
 103                        po = 0;
 104                        i++;
 105                }
 106        }
 107}
 108EXPORT_SYMBOL(ceph_copy_to_page_vector);
 109
 110void ceph_copy_from_page_vector(struct page **pages,
 111                                    void *data,
 112                                    loff_t off, size_t len)
 113{
 114        int i = 0;
 115        size_t po = off & ~PAGE_MASK;
 116        size_t left = len;
 117
 118        while (left > 0) {
 119                size_t l = min_t(size_t, PAGE_SIZE-po, left);
 120
 121                memcpy(data, page_address(pages[i]) + po, l);
 122                data += l;
 123                left -= l;
 124                po += l;
 125                if (po == PAGE_SIZE) {
 126                        po = 0;
 127                        i++;
 128                }
 129        }
 130}
 131EXPORT_SYMBOL(ceph_copy_from_page_vector);
 132
 133/*
 134 * Zero an extent within a page vector.  Offset is relative to the
 135 * start of the first page.
 136 */
 137void ceph_zero_page_vector_range(int off, int len, struct page **pages)
 138{
 139        int i = off >> PAGE_SHIFT;
 140
 141        off &= ~PAGE_MASK;
 142
 143        dout("zero_page_vector_page %u~%u\n", off, len);
 144
 145        /* leading partial page? */
 146        if (off) {
 147                int end = min((int)PAGE_SIZE, off + len);
 148                dout("zeroing %d %p head from %d\n", i, pages[i],
 149                     (int)off);
 150                zero_user_segment(pages[i], off, end);
 151                len -= (end - off);
 152                i++;
 153        }
 154        while (len >= PAGE_SIZE) {
 155                dout("zeroing %d %p len=%d\n", i, pages[i], len);
 156                zero_user_segment(pages[i], 0, PAGE_SIZE);
 157                len -= PAGE_SIZE;
 158                i++;
 159        }
 160        /* trailing partial page? */
 161        if (len) {
 162                dout("zeroing %d %p tail to %d\n", i, pages[i], (int)len);
 163                zero_user_segment(pages[i], 0, len);
 164        }
 165}
 166EXPORT_SYMBOL(ceph_zero_page_vector_range);
 167