diff options
Diffstat (limited to 'drivers/block')
-rw-r--r-- | drivers/block/loop.c | 64 |
1 files changed, 44 insertions, 20 deletions
diff --git a/drivers/block/loop.c b/drivers/block/loop.c index 0ed5470d2533..87d84e7d5432 100644 --- a/drivers/block/loop.c +++ b/drivers/block/loop.c | |||
@@ -74,6 +74,7 @@ | |||
74 | #include <linux/highmem.h> | 74 | #include <linux/highmem.h> |
75 | #include <linux/gfp.h> | 75 | #include <linux/gfp.h> |
76 | #include <linux/kthread.h> | 76 | #include <linux/kthread.h> |
77 | #include <linux/pipe_fs_i.h> | ||
77 | 78 | ||
78 | #include <asm/uaccess.h> | 79 | #include <asm/uaccess.h> |
79 | 80 | ||
@@ -401,50 +402,73 @@ struct lo_read_data { | |||
401 | }; | 402 | }; |
402 | 403 | ||
403 | static int | 404 | static int |
404 | lo_read_actor(read_descriptor_t *desc, struct page *page, | 405 | lo_splice_actor(struct pipe_inode_info *pipe, struct pipe_buffer *buf, |
405 | unsigned long offset, unsigned long size) | 406 | struct splice_desc *sd) |
406 | { | 407 | { |
407 | unsigned long count = desc->count; | 408 | struct lo_read_data *p = sd->u.data; |
408 | struct lo_read_data *p = desc->arg.data; | ||
409 | struct loop_device *lo = p->lo; | 409 | struct loop_device *lo = p->lo; |
410 | struct page *page = buf->page; | ||
410 | sector_t IV; | 411 | sector_t IV; |
412 | size_t size; | ||
413 | int ret; | ||
411 | 414 | ||
412 | IV = ((sector_t) page->index << (PAGE_CACHE_SHIFT - 9))+(offset >> 9); | 415 | ret = buf->ops->pin(pipe, buf); |
416 | if (unlikely(ret)) | ||
417 | return ret; | ||
413 | 418 | ||
414 | if (size > count) | 419 | IV = ((sector_t) page->index << (PAGE_CACHE_SHIFT - 9)) + |
415 | size = count; | 420 | (buf->offset >> 9); |
421 | size = sd->len; | ||
422 | if (size > p->bsize) | ||
423 | size = p->bsize; | ||
416 | 424 | ||
417 | if (lo_do_transfer(lo, READ, page, offset, p->page, p->offset, size, IV)) { | 425 | if (lo_do_transfer(lo, READ, page, buf->offset, p->page, p->offset, size, IV)) { |
418 | size = 0; | ||
419 | printk(KERN_ERR "loop: transfer error block %ld\n", | 426 | printk(KERN_ERR "loop: transfer error block %ld\n", |
420 | page->index); | 427 | page->index); |
421 | desc->error = -EINVAL; | 428 | size = -EINVAL; |
422 | } | 429 | } |
423 | 430 | ||
424 | flush_dcache_page(p->page); | 431 | flush_dcache_page(p->page); |
425 | 432 | ||
426 | desc->count = count - size; | 433 | if (size > 0) |
427 | desc->written += size; | 434 | p->offset += size; |
428 | p->offset += size; | 435 | |
429 | return size; | 436 | return size; |
430 | } | 437 | } |
431 | 438 | ||
432 | static int | 439 | static int |
440 | lo_direct_splice_actor(struct pipe_inode_info *pipe, struct splice_desc *sd) | ||
441 | { | ||
442 | return __splice_from_pipe(pipe, sd, lo_splice_actor); | ||
443 | } | ||
444 | |||
445 | static int | ||
433 | do_lo_receive(struct loop_device *lo, | 446 | do_lo_receive(struct loop_device *lo, |
434 | struct bio_vec *bvec, int bsize, loff_t pos) | 447 | struct bio_vec *bvec, int bsize, loff_t pos) |
435 | { | 448 | { |
436 | struct lo_read_data cookie; | 449 | struct lo_read_data cookie; |
450 | struct splice_desc sd; | ||
437 | struct file *file; | 451 | struct file *file; |
438 | int retval; | 452 | long retval; |
439 | 453 | ||
440 | cookie.lo = lo; | 454 | cookie.lo = lo; |
441 | cookie.page = bvec->bv_page; | 455 | cookie.page = bvec->bv_page; |
442 | cookie.offset = bvec->bv_offset; | 456 | cookie.offset = bvec->bv_offset; |
443 | cookie.bsize = bsize; | 457 | cookie.bsize = bsize; |
458 | |||
459 | sd.len = 0; | ||
460 | sd.total_len = bvec->bv_len; | ||
461 | sd.flags = 0; | ||
462 | sd.pos = pos; | ||
463 | sd.u.data = &cookie; | ||
464 | |||
444 | file = lo->lo_backing_file; | 465 | file = lo->lo_backing_file; |
445 | retval = file->f_op->sendfile(file, &pos, bvec->bv_len, | 466 | retval = splice_direct_to_actor(file, &sd, lo_direct_splice_actor); |
446 | lo_read_actor, &cookie); | 467 | |
447 | return (retval < 0)? retval: 0; | 468 | if (retval < 0) |
469 | return retval; | ||
470 | |||
471 | return 0; | ||
448 | } | 472 | } |
449 | 473 | ||
450 | static int | 474 | static int |
@@ -679,8 +703,8 @@ static int loop_change_fd(struct loop_device *lo, struct file *lo_file, | |||
679 | if (!S_ISREG(inode->i_mode) && !S_ISBLK(inode->i_mode)) | 703 | if (!S_ISREG(inode->i_mode) && !S_ISBLK(inode->i_mode)) |
680 | goto out_putf; | 704 | goto out_putf; |
681 | 705 | ||
682 | /* new backing store needs to support loop (eg sendfile) */ | 706 | /* new backing store needs to support loop (eg splice_read) */ |
683 | if (!inode->i_fop->sendfile) | 707 | if (!inode->i_fop->splice_read) |
684 | goto out_putf; | 708 | goto out_putf; |
685 | 709 | ||
686 | /* size of the new backing store needs to be the same */ | 710 | /* size of the new backing store needs to be the same */ |
@@ -760,7 +784,7 @@ static int loop_set_fd(struct loop_device *lo, struct file *lo_file, | |||
760 | * If we can't read - sorry. If we only can't write - well, | 784 | * If we can't read - sorry. If we only can't write - well, |
761 | * it's going to be read-only. | 785 | * it's going to be read-only. |
762 | */ | 786 | */ |
763 | if (!file->f_op->sendfile) | 787 | if (!file->f_op->splice_read) |
764 | goto out_putf; | 788 | goto out_putf; |
765 | if (aops->prepare_write && aops->commit_write) | 789 | if (aops->prepare_write && aops->commit_write) |
766 | lo_flags |= LO_FLAGS_USE_AOPS; | 790 | lo_flags |= LO_FLAGS_USE_AOPS; |