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(current, current->mm, 28 (unsigned long)data + ((unsigned long)got * PAGE_SIZE), 29 num_pages - got, write_page, 0, pages + got); 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 if (is_vmalloc_addr(pages)) 55 vfree(pages); 56 else 57 kfree(pages); 58} 59EXPORT_SYMBOL(ceph_put_page_vector); 60 61void ceph_release_page_vector(struct page **pages, int num_pages) 62{ 63 int i; 64 65 for (i = 0; i < num_pages; i++) 66 __free_pages(pages[i], 0); 67 kfree(pages); 68} 69EXPORT_SYMBOL(ceph_release_page_vector); 70 71/* 72 * allocate a vector new pages 73 */ 74struct page **ceph_alloc_page_vector(int num_pages, gfp_t flags) 75{ 76 struct page **pages; 77 int i; 78 79 pages = kmalloc(sizeof(*pages) * num_pages, flags); 80 if (!pages) 81 return ERR_PTR(-ENOMEM); 82 for (i = 0; i < num_pages; i++) { 83 pages[i] = __page_cache_alloc(flags); 84 if (pages[i] == NULL) { 85 ceph_release_page_vector(pages, i); 86 return ERR_PTR(-ENOMEM); 87 } 88 } 89 return pages; 90} 91EXPORT_SYMBOL(ceph_alloc_page_vector); 92 93/* 94 * copy user data into a page vector 95 */ 96int ceph_copy_user_to_page_vector(struct page **pages, 97 const void __user *data, 98 loff_t off, size_t len) 99{ 100 int i = 0; 101 int po = off & ~PAGE_CACHE_MASK; 102 int left = len; 103 int l, bad; 104 105 while (left > 0) { 106 l = min_t(int, PAGE_CACHE_SIZE-po, left); 107 bad = copy_from_user(page_address(pages[i]) + po, data, l); 108 if (bad == l) 109 return -EFAULT; 110 data += l - bad; 111 left -= l - bad; 112 po += l - bad; 113 if (po == PAGE_CACHE_SIZE) { 114 po = 0; 115 i++; 116 } 117 } 118 return len; 119} 120EXPORT_SYMBOL(ceph_copy_user_to_page_vector); 121 122void ceph_copy_to_page_vector(struct page **pages, 123 const void *data, 124 loff_t off, size_t len) 125{ 126 int i = 0; 127 size_t po = off & ~PAGE_CACHE_MASK; 128 size_t left = len; 129 130 while (left > 0) { 131 size_t l = min_t(size_t, PAGE_CACHE_SIZE-po, left); 132 133 memcpy(page_address(pages[i]) + po, data, l); 134 data += l; 135 left -= l; 136 po += l; 137 if (po == PAGE_CACHE_SIZE) { 138 po = 0; 139 i++; 140 } 141 } 142} 143EXPORT_SYMBOL(ceph_copy_to_page_vector); 144 145void ceph_copy_from_page_vector(struct page **pages, 146 void *data, 147 loff_t off, size_t len) 148{ 149 int i = 0; 150 size_t po = off & ~PAGE_CACHE_MASK; 151 size_t left = len; 152 153 while (left > 0) { 154 size_t l = min_t(size_t, PAGE_CACHE_SIZE-po, left); 155 156 memcpy(data, page_address(pages[i]) + po, l); 157 data += l; 158 left -= l; 159 po += l; 160 if (po == PAGE_CACHE_SIZE) { 161 po = 0; 162 i++; 163 } 164 } 165} 166EXPORT_SYMBOL(ceph_copy_from_page_vector); 167 168/* 169 * Zero an extent within a page vector. Offset is relative to the 170 * start of the first page. 171 */ 172void ceph_zero_page_vector_range(int off, int len, struct page **pages) 173{ 174 int i = off >> PAGE_CACHE_SHIFT; 175 176 off &= ~PAGE_CACHE_MASK; 177 178 dout("zero_page_vector_page %u~%u\n", off, len); 179 180 /* leading partial page? */ 181 if (off) { 182 int end = min((int)PAGE_CACHE_SIZE, off + len); 183 dout("zeroing %d %p head from %d\n", i, pages[i], 184 (int)off); 185 zero_user_segment(pages[i], off, end); 186 len -= (end - off); 187 i++; 188 } 189 while (len >= PAGE_CACHE_SIZE) { 190 dout("zeroing %d %p len=%d\n", i, pages[i], len); 191 zero_user_segment(pages[i], 0, PAGE_CACHE_SIZE); 192 len -= PAGE_CACHE_SIZE; 193 i++; 194 } 195 /* trailing partial page? */ 196 if (len) { 197 dout("zeroing %d %p tail to %d\n", i, pages[i], (int)len); 198 zero_user_segment(pages[i], 0, len); 199 } 200} 201EXPORT_SYMBOL(ceph_zero_page_vector_range); 202 203