]>
Commit | Line | Data |
---|---|---|
924f98e8 DM |
1 | From a265a27f75e6ab35d0289f11337eaab8cb80906c Mon Sep 17 00:00:00 2001 |
2 | From: Dietmar Maurer <dietmar@proxmox.com> | |
3 | Date: Sun, 9 Aug 2015 17:19:35 +0200 | |
4 | Subject: [PATCH] Revert "block: loop: switch to VFS ITER_BVEC" | |
5 | ||
6 | This reverts commit aa4d86163e4e91a1ac560954a554bab417e338f4. | |
7 | ||
8 | Conflicts: | |
9 | drivers/block/loop.c | |
10 | --- | |
11 | drivers/block/loop.c | 293 ++++++++++++++++++++++++++++++--------------------- | |
12 | 1 file changed, 173 insertions(+), 120 deletions(-) | |
13 | ||
14 | diff --git a/drivers/block/loop.c b/drivers/block/loop.c | |
15 | index 866f8e2..7fad961 100644 | |
16 | --- a/drivers/block/loop.c | |
17 | +++ b/drivers/block/loop.c | |
18 | @@ -88,6 +88,28 @@ static int part_shift; | |
19 | ||
20 | static struct workqueue_struct *loop_wq; | |
21 | ||
22 | +/* | |
23 | + * Transfer functions | |
24 | + */ | |
25 | +static int transfer_none(struct loop_device *lo, int cmd, | |
26 | + struct page *raw_page, unsigned raw_off, | |
27 | + struct page *loop_page, unsigned loop_off, | |
28 | + int size, sector_t real_block) | |
29 | +{ | |
30 | + char *raw_buf = kmap_atomic(raw_page) + raw_off; | |
31 | + char *loop_buf = kmap_atomic(loop_page) + loop_off; | |
32 | + | |
33 | + if (cmd == READ) | |
34 | + memcpy(loop_buf, raw_buf, size); | |
35 | + else | |
36 | + memcpy(raw_buf, loop_buf, size); | |
37 | + | |
38 | + kunmap_atomic(loop_buf); | |
39 | + kunmap_atomic(raw_buf); | |
40 | + cond_resched(); | |
41 | + return 0; | |
42 | +} | |
43 | + | |
44 | static int transfer_xor(struct loop_device *lo, int cmd, | |
45 | struct page *raw_page, unsigned raw_off, | |
46 | struct page *loop_page, unsigned loop_off, | |
47 | @@ -126,13 +148,14 @@ static int xor_init(struct loop_device *lo, const struct loop_info64 *info) | |
48 | ||
49 | static struct loop_func_table none_funcs = { | |
50 | .number = LO_CRYPT_NONE, | |
51 | -}; | |
52 | + .transfer = transfer_none, | |
53 | +}; | |
54 | ||
55 | static struct loop_func_table xor_funcs = { | |
56 | .number = LO_CRYPT_XOR, | |
57 | .transfer = transfer_xor, | |
58 | .init = xor_init | |
59 | -}; | |
60 | +}; | |
61 | ||
62 | /* xfer_funcs[0] is special - its release function is never called */ | |
63 | static struct loop_func_table *xfer_funcs[MAX_LO_CRYPT] = { | |
64 | @@ -192,169 +215,207 @@ lo_do_transfer(struct loop_device *lo, int cmd, | |
65 | struct page *lpage, unsigned loffs, | |
66 | int size, sector_t rblock) | |
67 | { | |
68 | - int ret; | |
69 | - | |
70 | - ret = lo->transfer(lo, cmd, rpage, roffs, lpage, loffs, size, rblock); | |
71 | - if (likely(!ret)) | |
72 | + if (unlikely(!lo->transfer)) | |
73 | return 0; | |
74 | ||
75 | - printk_ratelimited(KERN_ERR | |
76 | - "loop: Transfer error at byte offset %llu, length %i.\n", | |
77 | - (unsigned long long)rblock << 9, size); | |
78 | - return ret; | |
79 | + return lo->transfer(lo, cmd, rpage, roffs, lpage, loffs, size, rblock); | |
80 | } | |
81 | ||
82 | -static int lo_write_bvec(struct file *file, struct bio_vec *bvec, loff_t *ppos) | |
83 | +/** | |
84 | + * __do_lo_send_write - helper for writing data to a loop device | |
85 | + * | |
86 | + * This helper just factors out common code between do_lo_send_direct_write() | |
87 | + * and do_lo_send_write(). | |
88 | + */ | |
89 | +static int __do_lo_send_write(struct file *file, | |
90 | + u8 *buf, const int len, loff_t pos) | |
91 | { | |
92 | - struct iov_iter i; | |
93 | + struct kvec kvec = {.iov_base = buf, .iov_len = len}; | |
94 | + struct iov_iter from; | |
95 | ssize_t bw; | |
96 | ||
97 | - iov_iter_bvec(&i, ITER_BVEC, bvec, 1, bvec->bv_len); | |
98 | + iov_iter_kvec(&from, ITER_KVEC | WRITE, &kvec, 1, len); | |
99 | ||
100 | file_start_write(file); | |
101 | - bw = vfs_iter_write(file, &i, ppos); | |
102 | + bw = vfs_iter_write(file, &from, &pos); | |
103 | file_end_write(file); | |
104 | - | |
105 | - if (likely(bw == bvec->bv_len)) | |
106 | + if (likely(bw == len)) | |
107 | return 0; | |
108 | - | |
109 | - printk_ratelimited(KERN_ERR | |
110 | - "loop: Write error at byte offset %llu, length %i.\n", | |
111 | - (unsigned long long)*ppos, bvec->bv_len); | |
112 | + printk_ratelimited(KERN_ERR "loop: Write error at byte offset %llu, length %i.\n", | |
113 | + (unsigned long long)pos, len); | |
114 | if (bw >= 0) | |
115 | bw = -EIO; | |
116 | return bw; | |
117 | } | |
118 | ||
119 | -static int lo_write_simple(struct loop_device *lo, struct request *rq, | |
120 | - loff_t pos) | |
121 | +/** | |
122 | + * do_lo_send_direct_write - helper for writing data to a loop device | |
123 | + * | |
124 | + * This is the fast, non-transforming version that does not need double | |
125 | + * buffering. | |
126 | + */ | |
127 | +static int do_lo_send_direct_write(struct loop_device *lo, | |
128 | + struct bio_vec *bvec, loff_t pos, struct page *page) | |
129 | { | |
130 | - struct bio_vec bvec; | |
131 | - struct req_iterator iter; | |
132 | - int ret = 0; | |
133 | - | |
134 | - rq_for_each_segment(bvec, rq, iter) { | |
135 | - ret = lo_write_bvec(lo->lo_backing_file, &bvec, &pos); | |
136 | - if (ret < 0) | |
137 | - break; | |
138 | - cond_resched(); | |
139 | - } | |
140 | - | |
141 | - return ret; | |
142 | + ssize_t bw = __do_lo_send_write(lo->lo_backing_file, | |
143 | + kmap(bvec->bv_page) + bvec->bv_offset, | |
144 | + bvec->bv_len, pos); | |
145 | + kunmap(bvec->bv_page); | |
146 | + cond_resched(); | |
147 | + return bw; | |
148 | } | |
149 | ||
150 | -/* | |
151 | +/** | |
152 | + * do_lo_send_write - helper for writing data to a loop device | |
153 | + * | |
154 | * This is the slow, transforming version that needs to double buffer the | |
155 | * data as it cannot do the transformations in place without having direct | |
156 | * access to the destination pages of the backing file. | |
157 | */ | |
158 | -static int lo_write_transfer(struct loop_device *lo, struct request *rq, | |
159 | - loff_t pos) | |
160 | +static int do_lo_send_write(struct loop_device *lo, struct bio_vec *bvec, | |
161 | + loff_t pos, struct page *page) | |
162 | { | |
163 | - struct bio_vec bvec, b; | |
164 | + int ret = lo_do_transfer(lo, WRITE, page, 0, bvec->bv_page, | |
165 | + bvec->bv_offset, bvec->bv_len, pos >> 9); | |
166 | + if (likely(!ret)) | |
167 | + return __do_lo_send_write(lo->lo_backing_file, | |
168 | + page_address(page), bvec->bv_len, | |
169 | + pos); | |
170 | + printk_ratelimited(KERN_ERR "loop: Transfer error at byte offset %llu, " | |
171 | + "length %i.\n", (unsigned long long)pos, bvec->bv_len); | |
172 | + if (ret > 0) | |
173 | + ret = -EIO; | |
174 | + return ret; | |
175 | +} | |
176 | + | |
177 | +static int lo_send(struct loop_device *lo, struct request *rq, loff_t pos) | |
178 | +{ | |
179 | + int (*do_lo_send)(struct loop_device *, struct bio_vec *, loff_t, | |
180 | + struct page *page); | |
181 | + struct bio_vec bvec; | |
182 | struct req_iterator iter; | |
183 | - struct page *page; | |
184 | + struct page *page = NULL; | |
185 | int ret = 0; | |
186 | ||
187 | - page = alloc_page(GFP_NOIO); | |
188 | - if (unlikely(!page)) | |
189 | - return -ENOMEM; | |
190 | + if (lo->transfer != transfer_none) { | |
191 | + page = alloc_page(GFP_NOIO | __GFP_HIGHMEM); | |
192 | + if (unlikely(!page)) | |
193 | + goto fail; | |
194 | + kmap(page); | |
195 | + do_lo_send = do_lo_send_write; | |
196 | + } else { | |
197 | + do_lo_send = do_lo_send_direct_write; | |
198 | + } | |
199 | ||
200 | rq_for_each_segment(bvec, rq, iter) { | |
201 | - ret = lo_do_transfer(lo, WRITE, page, 0, bvec.bv_page, | |
202 | - bvec.bv_offset, bvec.bv_len, pos >> 9); | |
203 | - if (unlikely(ret)) | |
204 | - break; | |
205 | - | |
206 | - b.bv_page = page; | |
207 | - b.bv_offset = 0; | |
208 | - b.bv_len = bvec.bv_len; | |
209 | - ret = lo_write_bvec(lo->lo_backing_file, &b, &pos); | |
210 | + ret = do_lo_send(lo, &bvec, pos, page); | |
211 | if (ret < 0) | |
212 | break; | |
213 | + pos += bvec.bv_len; | |
214 | } | |
215 | - | |
216 | - __free_page(page); | |
217 | + if (page) { | |
218 | + kunmap(page); | |
219 | + __free_page(page); | |
220 | + } | |
221 | +out: | |
222 | return ret; | |
223 | +fail: | |
224 | + printk_ratelimited(KERN_ERR "loop: Failed to allocate temporary page for write.\n"); | |
225 | + ret = -ENOMEM; | |
226 | + goto out; | |
227 | } | |
228 | ||
229 | -static int lo_read_simple(struct loop_device *lo, struct request *rq, | |
230 | - loff_t pos) | |
231 | -{ | |
232 | - struct bio_vec bvec; | |
233 | - struct req_iterator iter; | |
234 | - struct iov_iter i; | |
235 | - ssize_t len; | |
236 | +struct lo_read_data { | |
237 | + struct loop_device *lo; | |
238 | + struct page *page; | |
239 | + unsigned offset; | |
240 | + int bsize; | |
241 | +}; | |
242 | ||
243 | - rq_for_each_segment(bvec, rq, iter) { | |
244 | - iov_iter_bvec(&i, ITER_BVEC, &bvec, 1, bvec.bv_len); | |
245 | - len = vfs_iter_read(lo->lo_backing_file, &i, &pos); | |
246 | - if (len < 0) | |
247 | - return len; | |
248 | +static int | |
249 | +lo_splice_actor(struct pipe_inode_info *pipe, struct pipe_buffer *buf, | |
250 | + struct splice_desc *sd) | |
251 | +{ | |
252 | + struct lo_read_data *p = sd->u.data; | |
253 | + struct loop_device *lo = p->lo; | |
254 | + struct page *page = buf->page; | |
255 | + sector_t IV; | |
256 | + int size; | |
257 | + | |
258 | + IV = ((sector_t) page->index << (PAGE_CACHE_SHIFT - 9)) + | |
259 | + (buf->offset >> 9); | |
260 | + size = sd->len; | |
261 | + if (size > p->bsize) | |
262 | + size = p->bsize; | |
263 | + | |
264 | + if (lo_do_transfer(lo, READ, page, buf->offset, p->page, p->offset, size, IV)) { | |
265 | + printk_ratelimited(KERN_ERR "loop: transfer error block %ld\n", | |
266 | + page->index); | |
267 | + size = -EINVAL; | |
268 | + } | |
269 | ||
270 | - flush_dcache_page(bvec.bv_page); | |
271 | + flush_dcache_page(p->page); | |
272 | ||
273 | - if (len != bvec.bv_len) { | |
274 | - struct bio *bio; | |
275 | + if (size > 0) | |
276 | + p->offset += size; | |
277 | ||
278 | - __rq_for_each_bio(bio, rq) | |
279 | - zero_fill_bio(bio); | |
280 | - break; | |
281 | - } | |
282 | - cond_resched(); | |
283 | - } | |
284 | + return size; | |
285 | +} | |
286 | ||
287 | - return 0; | |
288 | +static int | |
289 | +lo_direct_splice_actor(struct pipe_inode_info *pipe, struct splice_desc *sd) | |
290 | +{ | |
291 | + return __splice_from_pipe(pipe, sd, lo_splice_actor); | |
292 | } | |
293 | ||
294 | -static int lo_read_transfer(struct loop_device *lo, struct request *rq, | |
295 | - loff_t pos) | |
296 | +static ssize_t | |
297 | +do_lo_receive(struct loop_device *lo, | |
298 | + struct bio_vec *bvec, int bsize, loff_t pos) | |
299 | { | |
300 | - struct bio_vec bvec, b; | |
301 | - struct req_iterator iter; | |
302 | - struct iov_iter i; | |
303 | - struct page *page; | |
304 | - ssize_t len; | |
305 | - int ret = 0; | |
306 | + struct lo_read_data cookie; | |
307 | + struct splice_desc sd; | |
308 | + struct file *file; | |
309 | + ssize_t retval; | |
310 | ||
311 | - page = alloc_page(GFP_NOIO); | |
312 | - if (unlikely(!page)) | |
313 | - return -ENOMEM; | |
314 | + cookie.lo = lo; | |
315 | + cookie.page = bvec->bv_page; | |
316 | + cookie.offset = bvec->bv_offset; | |
317 | + cookie.bsize = bsize; | |
318 | ||
319 | - rq_for_each_segment(bvec, rq, iter) { | |
320 | - loff_t offset = pos; | |
321 | + sd.len = 0; | |
322 | + sd.total_len = bvec->bv_len; | |
323 | + sd.flags = 0; | |
324 | + sd.pos = pos; | |
325 | + sd.u.data = &cookie; | |
326 | ||
327 | - b.bv_page = page; | |
328 | - b.bv_offset = 0; | |
329 | - b.bv_len = bvec.bv_len; | |
330 | + file = lo->lo_backing_file; | |
331 | + retval = splice_direct_to_actor(file, &sd, lo_direct_splice_actor); | |
332 | ||
333 | - iov_iter_bvec(&i, ITER_BVEC, &b, 1, b.bv_len); | |
334 | - len = vfs_iter_read(lo->lo_backing_file, &i, &pos); | |
335 | - if (len < 0) { | |
336 | - ret = len; | |
337 | - goto out_free_page; | |
338 | - } | |
339 | + return retval; | |
340 | +} | |
341 | ||
342 | - ret = lo_do_transfer(lo, READ, page, 0, bvec.bv_page, | |
343 | - bvec.bv_offset, len, offset >> 9); | |
344 | - if (ret) | |
345 | - goto out_free_page; | |
346 | +static int | |
347 | +lo_receive(struct loop_device *lo, struct request *rq, int bsize, loff_t pos) | |
348 | +{ | |
349 | + struct bio_vec bvec; | |
350 | + struct req_iterator iter; | |
351 | + ssize_t s; | |
352 | ||
353 | - flush_dcache_page(bvec.bv_page); | |
354 | + rq_for_each_segment(bvec, rq, iter) { | |
355 | + s = do_lo_receive(lo, &bvec, bsize, pos); | |
356 | + if (s < 0) | |
357 | + return s; | |
358 | ||
359 | - if (len != bvec.bv_len) { | |
360 | + if (s != bvec.bv_len) { | |
361 | struct bio *bio; | |
362 | ||
363 | __rq_for_each_bio(bio, rq) | |
364 | zero_fill_bio(bio); | |
365 | break; | |
366 | } | |
367 | + pos += bvec.bv_len; | |
368 | } | |
369 | - | |
370 | - ret = 0; | |
371 | -out_free_page: | |
372 | - __free_page(page); | |
373 | - return ret; | |
374 | + return 0; | |
375 | } | |
376 | ||
377 | static int lo_discard(struct loop_device *lo, struct request *rq, loff_t pos) | |
378 | @@ -403,17 +464,10 @@ static int do_req_filebacked(struct loop_device *lo, struct request *rq) | |
379 | ret = lo_req_flush(lo, rq); | |
380 | else if (rq->cmd_flags & REQ_DISCARD) | |
381 | ret = lo_discard(lo, rq, pos); | |
382 | - else if (lo->transfer) | |
383 | - ret = lo_write_transfer(lo, rq, pos); | |
384 | else | |
385 | - ret = lo_write_simple(lo, rq, pos); | |
386 | - | |
387 | - } else { | |
388 | - if (lo->transfer) | |
389 | - ret = lo_read_transfer(lo, rq, pos); | |
390 | - else | |
391 | - ret = lo_read_simple(lo, rq, pos); | |
392 | - } | |
393 | + ret = lo_send(lo, rq, pos); | |
394 | + } else | |
395 | + ret = lo_receive(lo, rq, lo->lo_blocksize, pos); | |
396 | ||
397 | return ret; | |
398 | } | |
399 | @@ -783,7 +837,6 @@ static int loop_set_fd(struct loop_device *lo, fmode_t mode, | |
400 | lo->lo_flags = lo_flags; | |
401 | lo->lo_backing_file = file; | |
402 | lo->lo_backing_virt_file = virt_file; | |
403 | - lo->transfer = NULL; | |
404 | lo->ioctl = NULL; | |
405 | lo->lo_sizelimit = 0; | |
406 | lo->old_gfp_mask = mapping_gfp_mask(mapping); | |
407 | @@ -1008,7 +1061,7 @@ loop_set_status(struct loop_device *lo, const struct loop_info64 *info) | |
408 | memcpy(lo->lo_encrypt_key, info->lo_encrypt_key, | |
409 | info->lo_encrypt_key_size); | |
410 | lo->lo_key_owner = uid; | |
411 | - } | |
412 | + } | |
413 | ||
414 | return 0; | |
415 | } | |
416 | -- | |
417 | 2.1.4 | |
418 |