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 13 void ceph_release_page_vector(struct page **pages, int num_pages) 14 { 15 int i; 16 17 for (i = 0; i < num_pages; i++) 18 __free_pages(pages[i], 0); 19 kfree(pages); 20 } 21 EXPORT_SYMBOL(ceph_release_page_vector); 22 23 /* 24 * allocate a vector new pages 25 */ 26 struct page **ceph_alloc_page_vector(int num_pages, gfp_t flags) 27 { 28 struct page **pages; 29 int i; 30 31 pages = kmalloc_objs(*pages, num_pages, flags); 32 if (!pages) 33 return ERR_PTR(-ENOMEM); 34 for (i = 0; i < num_pages; i++) { 35 pages[i] = __page_cache_alloc(flags); 36 if (pages[i] == NULL) { 37 ceph_release_page_vector(pages, i); 38 return ERR_PTR(-ENOMEM); 39 } 40 } 41 return pages; 42 } 43 EXPORT_SYMBOL(ceph_alloc_page_vector); 44 45 void ceph_copy_from_page_vector(struct page **pages, 46 void *data, 47 loff_t off, size_t len) 48 { 49 int i = 0; 50 size_t po = off & ~PAGE_MASK; 51 size_t left = len; 52 53 while (left > 0) { 54 size_t l = min_t(size_t, PAGE_SIZE-po, left); 55 56 memcpy(data, page_address(pages[i]) + po, l); 57 data += l; 58 left -= l; 59 po += l; 60 if (po == PAGE_SIZE) { 61 po = 0; 62 i++; 63 } 64 } 65 } 66 EXPORT_SYMBOL(ceph_copy_from_page_vector); 67 68 /* 69 * Zero an extent within a page vector. Offset is relative to the 70 * start of the first page. 71 */ 72 void ceph_zero_page_vector_range(int off, int len, struct page **pages) 73 { 74 int i = off >> PAGE_SHIFT; 75 76 off &= ~PAGE_MASK; 77 78 dout("zero_page_vector_page %u~%u\n", off, len); 79 80 /* leading partial page? */ 81 if (off) { 82 int end = min((int)PAGE_SIZE, off + len); 83 dout("zeroing %d %p head from %d\n", i, pages[i], 84 (int)off); 85 zero_user_segment(pages[i], off, end); 86 len -= (end - off); 87 i++; 88 } 89 while (len >= PAGE_SIZE) { 90 dout("zeroing %d %p len=%d\n", i, pages[i], len); 91 zero_user_segment(pages[i], 0, PAGE_SIZE); 92 len -= PAGE_SIZE; 93 i++; 94 } 95 /* trailing partial page? */ 96 if (len) { 97 dout("zeroing %d %p tail to %d\n", i, pages[i], (int)len); 98 zero_user_segment(pages[i], 0, len); 99 } 100 } 101 EXPORT_SYMBOL(ceph_zero_page_vector_range); 102