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