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 */ 15 struct page **ceph_get_direct_page_vector(const char __user *data, 16 int num_pages) 17 { 18 struct page **pages; 19 int rc; 20 21 pages = kmalloc(sizeof(*pages) * num_pages, GFP_NOFS); 22 if (!pages) 23 return ERR_PTR(-ENOMEM); 24 25 down_read(¤t->mm->mmap_sem); 26 rc = get_user_pages(current, current->mm, (unsigned long)data, 27 num_pages, 0, 0, pages, NULL); 28 up_read(¤t->mm->mmap_sem); 29 if (rc < 0) 30 goto fail; 31 return pages; 32 33 fail: 34 kfree(pages); 35 return ERR_PTR(rc); 36 } 37 EXPORT_SYMBOL(ceph_get_direct_page_vector); 38 39 void ceph_put_page_vector(struct page **pages, int num_pages) 40 { 41 int i; 42 43 for (i = 0; i < num_pages; i++) 44 put_page(pages[i]); 45 kfree(pages); 46 } 47 EXPORT_SYMBOL(ceph_put_page_vector); 48 49 void ceph_release_page_vector(struct page **pages, int num_pages) 50 { 51 int i; 52 53 for (i = 0; i < num_pages; i++) 54 __free_pages(pages[i], 0); 55 kfree(pages); 56 } 57 EXPORT_SYMBOL(ceph_release_page_vector); 58 59 /* 60 * allocate a vector new pages 61 */ 62 struct page **ceph_alloc_page_vector(int num_pages, gfp_t flags) 63 { 64 struct page **pages; 65 int i; 66 67 pages = kmalloc(sizeof(*pages) * num_pages, flags); 68 if (!pages) 69 return ERR_PTR(-ENOMEM); 70 for (i = 0; i < num_pages; i++) { 71 pages[i] = __page_cache_alloc(flags); 72 if (pages[i] == NULL) { 73 ceph_release_page_vector(pages, i); 74 return ERR_PTR(-ENOMEM); 75 } 76 } 77 return pages; 78 } 79 EXPORT_SYMBOL(ceph_alloc_page_vector); 80 81 /* 82 * copy user data into a page vector 83 */ 84 int ceph_copy_user_to_page_vector(struct page **pages, 85 const char __user *data, 86 loff_t off, size_t len) 87 { 88 int i = 0; 89 int po = off & ~PAGE_CACHE_MASK; 90 int left = len; 91 int l, bad; 92 93 while (left > 0) { 94 l = min_t(int, PAGE_CACHE_SIZE-po, left); 95 bad = copy_from_user(page_address(pages[i]) + po, data, l); 96 if (bad == l) 97 return -EFAULT; 98 data += l - bad; 99 left -= l - bad; 100 po += l - bad; 101 if (po == PAGE_CACHE_SIZE) { 102 po = 0; 103 i++; 104 } 105 } 106 return len; 107 } 108 EXPORT_SYMBOL(ceph_copy_user_to_page_vector); 109 110 int ceph_copy_to_page_vector(struct page **pages, 111 const char *data, 112 loff_t off, size_t len) 113 { 114 int i = 0; 115 size_t po = off & ~PAGE_CACHE_MASK; 116 size_t left = len; 117 size_t l; 118 119 while (left > 0) { 120 l = min_t(size_t, PAGE_CACHE_SIZE-po, left); 121 memcpy(page_address(pages[i]) + po, data, l); 122 data += l; 123 left -= l; 124 po += l; 125 if (po == PAGE_CACHE_SIZE) { 126 po = 0; 127 i++; 128 } 129 } 130 return len; 131 } 132 EXPORT_SYMBOL(ceph_copy_to_page_vector); 133 134 int ceph_copy_from_page_vector(struct page **pages, 135 char *data, 136 loff_t off, size_t len) 137 { 138 int i = 0; 139 size_t po = off & ~PAGE_CACHE_MASK; 140 size_t left = len; 141 size_t l; 142 143 while (left > 0) { 144 l = min_t(size_t, PAGE_CACHE_SIZE-po, left); 145 memcpy(data, page_address(pages[i]) + po, l); 146 data += l; 147 left -= l; 148 po += l; 149 if (po == PAGE_CACHE_SIZE) { 150 po = 0; 151 i++; 152 } 153 } 154 return len; 155 } 156 EXPORT_SYMBOL(ceph_copy_from_page_vector); 157 158 /* 159 * copy user data from a page vector into a user pointer 160 */ 161 int ceph_copy_page_vector_to_user(struct page **pages, 162 char __user *data, 163 loff_t off, size_t len) 164 { 165 int i = 0; 166 int po = off & ~PAGE_CACHE_MASK; 167 int left = len; 168 int l, bad; 169 170 while (left > 0) { 171 l = min_t(int, left, PAGE_CACHE_SIZE-po); 172 bad = copy_to_user(data, page_address(pages[i]) + po, l); 173 if (bad == l) 174 return -EFAULT; 175 data += l - bad; 176 left -= l - bad; 177 if (po) { 178 po += l - bad; 179 if (po == PAGE_CACHE_SIZE) 180 po = 0; 181 } 182 i++; 183 } 184 return len; 185 } 186 EXPORT_SYMBOL(ceph_copy_page_vector_to_user); 187 188 /* 189 * Zero an extent within a page vector. Offset is relative to the 190 * start of the first page. 191 */ 192 void ceph_zero_page_vector_range(int off, int len, struct page **pages) 193 { 194 int i = off >> PAGE_CACHE_SHIFT; 195 196 off &= ~PAGE_CACHE_MASK; 197 198 dout("zero_page_vector_page %u~%u\n", off, len); 199 200 /* leading partial page? */ 201 if (off) { 202 int end = min((int)PAGE_CACHE_SIZE, off + len); 203 dout("zeroing %d %p head from %d\n", i, pages[i], 204 (int)off); 205 zero_user_segment(pages[i], off, end); 206 len -= (end - off); 207 i++; 208 } 209 while (len >= PAGE_CACHE_SIZE) { 210 dout("zeroing %d %p len=%d\n", i, pages[i], len); 211 zero_user_segment(pages[i], 0, PAGE_CACHE_SIZE); 212 len -= PAGE_CACHE_SIZE; 213 i++; 214 } 215 /* trailing partial page? */ 216 if (len) { 217 dout("zeroing %d %p tail to %d\n", i, pages[i], (int)len); 218 zero_user_segment(pages[i], 0, len); 219 } 220 } 221 EXPORT_SYMBOL(ceph_zero_page_vector_range); 222 223