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 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, 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 39 fail: 40 ceph_put_page_vector(pages, got, false); 41 return ERR_PTR(rc); 42 } 43 EXPORT_SYMBOL(ceph_get_direct_page_vector); 44 45 void 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 } 56 EXPORT_SYMBOL(ceph_put_page_vector); 57 58 void 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 } 66 EXPORT_SYMBOL(ceph_release_page_vector); 67 68 /* 69 * allocate a vector new pages 70 */ 71 struct 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 } 88 EXPORT_SYMBOL(ceph_alloc_page_vector); 89 90 /* 91 * copy user data into a page vector 92 */ 93 int 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 } 117 EXPORT_SYMBOL(ceph_copy_user_to_page_vector); 118 119 void 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 } 140 EXPORT_SYMBOL(ceph_copy_to_page_vector); 141 142 void 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 } 163 EXPORT_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 */ 169 void 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 } 198 EXPORT_SYMBOL(ceph_zero_page_vector_range); 199 200