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