diff options
Diffstat (limited to 'arch/um/drivers/ubd_kern.c')
-rw-r--r-- | arch/um/drivers/ubd_kern.c | 570 |
1 files changed, 255 insertions, 315 deletions
diff --git a/arch/um/drivers/ubd_kern.c b/arch/um/drivers/ubd_kern.c index 344b24d09a7c..e77a38da4350 100644 --- a/arch/um/drivers/ubd_kern.c +++ b/arch/um/drivers/ubd_kern.c | |||
@@ -35,6 +35,7 @@ | |||
35 | #include "linux/blkpg.h" | 35 | #include "linux/blkpg.h" |
36 | #include "linux/genhd.h" | 36 | #include "linux/genhd.h" |
37 | #include "linux/spinlock.h" | 37 | #include "linux/spinlock.h" |
38 | #include "asm/atomic.h" | ||
38 | #include "asm/segment.h" | 39 | #include "asm/segment.h" |
39 | #include "asm/uaccess.h" | 40 | #include "asm/uaccess.h" |
40 | #include "asm/irq.h" | 41 | #include "asm/irq.h" |
@@ -53,20 +54,21 @@ | |||
53 | #include "mem.h" | 54 | #include "mem.h" |
54 | #include "mem_kern.h" | 55 | #include "mem_kern.h" |
55 | #include "cow.h" | 56 | #include "cow.h" |
57 | #include "aio.h" | ||
56 | 58 | ||
57 | enum ubd_req { UBD_READ, UBD_WRITE }; | 59 | enum ubd_req { UBD_READ, UBD_WRITE }; |
58 | 60 | ||
59 | struct io_thread_req { | 61 | struct io_thread_req { |
60 | enum ubd_req op; | 62 | enum aio_type op; |
61 | int fds[2]; | 63 | int fds[2]; |
62 | unsigned long offsets[2]; | 64 | unsigned long offsets[2]; |
63 | unsigned long long offset; | 65 | unsigned long long offset; |
64 | unsigned long length; | 66 | unsigned long length; |
65 | char *buffer; | 67 | char *buffer; |
66 | int sectorsize; | 68 | int sectorsize; |
67 | unsigned long sector_mask; | 69 | int bitmap_offset; |
68 | unsigned long long cow_offset; | 70 | long bitmap_start; |
69 | unsigned long bitmap_words[2]; | 71 | long bitmap_end; |
70 | int error; | 72 | int error; |
71 | }; | 73 | }; |
72 | 74 | ||
@@ -80,28 +82,31 @@ extern int create_cow_file(char *cow_file, char *backing_file, | |||
80 | unsigned long *bitmap_len_out, | 82 | unsigned long *bitmap_len_out, |
81 | int *data_offset_out); | 83 | int *data_offset_out); |
82 | extern int read_cow_bitmap(int fd, void *buf, int offset, int len); | 84 | extern int read_cow_bitmap(int fd, void *buf, int offset, int len); |
83 | extern void do_io(struct io_thread_req *req); | 85 | extern void do_io(struct io_thread_req *req, struct request *r, |
86 | unsigned long *bitmap); | ||
84 | 87 | ||
85 | static inline int ubd_test_bit(__u64 bit, unsigned char *data) | 88 | static inline int ubd_test_bit(__u64 bit, void *data) |
86 | { | 89 | { |
90 | unsigned char *buffer = data; | ||
87 | __u64 n; | 91 | __u64 n; |
88 | int bits, off; | 92 | int bits, off; |
89 | 93 | ||
90 | bits = sizeof(data[0]) * 8; | 94 | bits = sizeof(buffer[0]) * 8; |
91 | n = bit / bits; | 95 | n = bit / bits; |
92 | off = bit % bits; | 96 | off = bit % bits; |
93 | return((data[n] & (1 << off)) != 0); | 97 | return((buffer[n] & (1 << off)) != 0); |
94 | } | 98 | } |
95 | 99 | ||
96 | static inline void ubd_set_bit(__u64 bit, unsigned char *data) | 100 | static inline void ubd_set_bit(__u64 bit, void *data) |
97 | { | 101 | { |
102 | unsigned char *buffer = data; | ||
98 | __u64 n; | 103 | __u64 n; |
99 | int bits, off; | 104 | int bits, off; |
100 | 105 | ||
101 | bits = sizeof(data[0]) * 8; | 106 | bits = sizeof(buffer[0]) * 8; |
102 | n = bit / bits; | 107 | n = bit / bits; |
103 | off = bit % bits; | 108 | off = bit % bits; |
104 | data[n] |= (1 << off); | 109 | buffer[n] |= (1 << off); |
105 | } | 110 | } |
106 | /*End stuff from ubd_user.h*/ | 111 | /*End stuff from ubd_user.h*/ |
107 | 112 | ||
@@ -110,8 +115,6 @@ static inline void ubd_set_bit(__u64 bit, unsigned char *data) | |||
110 | static DEFINE_SPINLOCK(ubd_io_lock); | 115 | static DEFINE_SPINLOCK(ubd_io_lock); |
111 | static DEFINE_SPINLOCK(ubd_lock); | 116 | static DEFINE_SPINLOCK(ubd_lock); |
112 | 117 | ||
113 | static void (*do_ubd)(void); | ||
114 | |||
115 | static int ubd_open(struct inode * inode, struct file * filp); | 118 | static int ubd_open(struct inode * inode, struct file * filp); |
116 | static int ubd_release(struct inode * inode, struct file * file); | 119 | static int ubd_release(struct inode * inode, struct file * file); |
117 | static int ubd_ioctl(struct inode * inode, struct file * file, | 120 | static int ubd_ioctl(struct inode * inode, struct file * file, |
@@ -158,6 +161,8 @@ struct cow { | |||
158 | int data_offset; | 161 | int data_offset; |
159 | }; | 162 | }; |
160 | 163 | ||
164 | #define MAX_SG 64 | ||
165 | |||
161 | struct ubd { | 166 | struct ubd { |
162 | char *file; | 167 | char *file; |
163 | int count; | 168 | int count; |
@@ -168,6 +173,7 @@ struct ubd { | |||
168 | int no_cow; | 173 | int no_cow; |
169 | struct cow cow; | 174 | struct cow cow; |
170 | struct platform_device pdev; | 175 | struct platform_device pdev; |
176 | struct scatterlist sg[MAX_SG]; | ||
171 | }; | 177 | }; |
172 | 178 | ||
173 | #define DEFAULT_COW { \ | 179 | #define DEFAULT_COW { \ |
@@ -460,80 +466,113 @@ __uml_help(fakehd, | |||
460 | ); | 466 | ); |
461 | 467 | ||
462 | static void do_ubd_request(request_queue_t * q); | 468 | static void do_ubd_request(request_queue_t * q); |
463 | 469 | static int in_ubd; | |
464 | /* Only changed by ubd_init, which is an initcall. */ | ||
465 | int thread_fd = -1; | ||
466 | 470 | ||
467 | /* Changed by ubd_handler, which is serialized because interrupts only | 471 | /* Changed by ubd_handler, which is serialized because interrupts only |
468 | * happen on CPU 0. | 472 | * happen on CPU 0. |
469 | */ | 473 | */ |
470 | int intr_count = 0; | 474 | int intr_count = 0; |
471 | 475 | ||
472 | /* call ubd_finish if you need to serialize */ | 476 | static void ubd_end_request(struct request *req, int bytes, int uptodate) |
473 | static void __ubd_finish(struct request *req, int error) | ||
474 | { | 477 | { |
475 | int nsect; | 478 | if (!end_that_request_first(req, uptodate, bytes >> 9)) { |
476 | 479 | add_disk_randomness(req->rq_disk); | |
477 | if(error){ | 480 | end_that_request_last(req); |
478 | end_request(req, 0); | ||
479 | return; | ||
480 | } | 481 | } |
481 | nsect = req->current_nr_sectors; | ||
482 | req->sector += nsect; | ||
483 | req->buffer += nsect << 9; | ||
484 | req->errors = 0; | ||
485 | req->nr_sectors -= nsect; | ||
486 | req->current_nr_sectors = 0; | ||
487 | end_request(req, 1); | ||
488 | } | 482 | } |
489 | 483 | ||
490 | static inline void ubd_finish(struct request *req, int error) | 484 | /* call ubd_finish if you need to serialize */ |
485 | static void __ubd_finish(struct request *req, int bytes) | ||
491 | { | 486 | { |
492 | spin_lock(&ubd_io_lock); | 487 | if(bytes < 0){ |
493 | __ubd_finish(req, error); | 488 | ubd_end_request(req, 0, 0); |
494 | spin_unlock(&ubd_io_lock); | 489 | return; |
490 | } | ||
491 | |||
492 | ubd_end_request(req, bytes, 1); | ||
495 | } | 493 | } |
496 | 494 | ||
497 | /* Called without ubd_io_lock held */ | 495 | static inline void ubd_finish(struct request *req, int bytes) |
498 | static void ubd_handler(void) | ||
499 | { | 496 | { |
500 | struct io_thread_req req; | 497 | spin_lock(&ubd_io_lock); |
501 | struct request *rq = elv_next_request(ubd_queue); | 498 | __ubd_finish(req, bytes); |
502 | int n; | 499 | spin_unlock(&ubd_io_lock); |
503 | |||
504 | do_ubd = NULL; | ||
505 | intr_count++; | ||
506 | n = os_read_file(thread_fd, &req, sizeof(req)); | ||
507 | if(n != sizeof(req)){ | ||
508 | printk(KERN_ERR "Pid %d - spurious interrupt in ubd_handler, " | ||
509 | "err = %d\n", os_getpid(), -n); | ||
510 | spin_lock(&ubd_io_lock); | ||
511 | end_request(rq, 0); | ||
512 | spin_unlock(&ubd_io_lock); | ||
513 | return; | ||
514 | } | ||
515 | |||
516 | ubd_finish(rq, req.error); | ||
517 | reactivate_fd(thread_fd, UBD_IRQ); | ||
518 | do_ubd_request(ubd_queue); | ||
519 | } | 500 | } |
520 | 501 | ||
502 | struct bitmap_io { | ||
503 | atomic_t count; | ||
504 | struct aio_context aio; | ||
505 | }; | ||
506 | |||
507 | struct ubd_aio { | ||
508 | struct aio_context aio; | ||
509 | struct request *req; | ||
510 | int len; | ||
511 | struct bitmap_io *bitmap; | ||
512 | void *bitmap_buf; | ||
513 | }; | ||
514 | |||
515 | static int ubd_reply_fd = -1; | ||
516 | |||
521 | static irqreturn_t ubd_intr(int irq, void *dev, struct pt_regs *unused) | 517 | static irqreturn_t ubd_intr(int irq, void *dev, struct pt_regs *unused) |
522 | { | 518 | { |
523 | ubd_handler(); | 519 | struct aio_thread_reply reply; |
524 | return(IRQ_HANDLED); | 520 | struct ubd_aio *aio; |
525 | } | 521 | struct request *req; |
522 | int err, n, fd = (int) (long) dev; | ||
523 | |||
524 | while(1){ | ||
525 | err = os_read_file(fd, &reply, sizeof(reply)); | ||
526 | if(err == -EAGAIN) | ||
527 | break; | ||
528 | if(err < 0){ | ||
529 | printk("ubd_aio_handler - read returned err %d\n", | ||
530 | -err); | ||
531 | break; | ||
532 | } | ||
526 | 533 | ||
527 | /* Only changed by ubd_init, which is an initcall. */ | 534 | aio = container_of(reply.data, struct ubd_aio, aio); |
528 | static int io_pid = -1; | 535 | n = reply.err; |
529 | 536 | ||
530 | void kill_io_thread(void) | 537 | if(n == 0){ |
531 | { | 538 | req = aio->req; |
532 | if(io_pid != -1) | 539 | req->nr_sectors -= aio->len >> 9; |
533 | os_kill_process(io_pid, 1); | 540 | |
534 | } | 541 | if((aio->bitmap != NULL) && |
542 | (atomic_dec_and_test(&aio->bitmap->count))){ | ||
543 | aio->aio = aio->bitmap->aio; | ||
544 | aio->len = 0; | ||
545 | kfree(aio->bitmap); | ||
546 | aio->bitmap = NULL; | ||
547 | submit_aio(&aio->aio); | ||
548 | } | ||
549 | else { | ||
550 | if((req->nr_sectors == 0) && | ||
551 | (aio->bitmap == NULL)){ | ||
552 | int len = req->hard_nr_sectors << 9; | ||
553 | ubd_finish(req, len); | ||
554 | } | ||
555 | |||
556 | if(aio->bitmap_buf != NULL) | ||
557 | kfree(aio->bitmap_buf); | ||
558 | kfree(aio); | ||
559 | } | ||
560 | } | ||
561 | else if(n < 0){ | ||
562 | ubd_finish(aio->req, n); | ||
563 | if(aio->bitmap != NULL) | ||
564 | kfree(aio->bitmap); | ||
565 | if(aio->bitmap_buf != NULL) | ||
566 | kfree(aio->bitmap_buf); | ||
567 | kfree(aio); | ||
568 | } | ||
569 | } | ||
570 | reactivate_fd(fd, UBD_IRQ); | ||
535 | 571 | ||
536 | __uml_exitcall(kill_io_thread); | 572 | do_ubd_request(ubd_queue); |
573 | |||
574 | return(IRQ_HANDLED); | ||
575 | } | ||
537 | 576 | ||
538 | static int ubd_file_size(struct ubd *dev, __u64 *size_out) | 577 | static int ubd_file_size(struct ubd *dev, __u64 *size_out) |
539 | { | 578 | { |
@@ -569,7 +608,7 @@ static int ubd_open_dev(struct ubd *dev) | |||
569 | &dev->cow.data_offset, create_ptr); | 608 | &dev->cow.data_offset, create_ptr); |
570 | 609 | ||
571 | if((dev->fd == -ENOENT) && create_cow){ | 610 | if((dev->fd == -ENOENT) && create_cow){ |
572 | dev->fd = create_cow_file(dev->file, dev->cow.file, | 611 | dev->fd = create_cow_file(dev->file, dev->cow.file, |
573 | dev->openflags, 1 << 9, PAGE_SIZE, | 612 | dev->openflags, 1 << 9, PAGE_SIZE, |
574 | &dev->cow.bitmap_offset, | 613 | &dev->cow.bitmap_offset, |
575 | &dev->cow.bitmap_len, | 614 | &dev->cow.bitmap_len, |
@@ -668,21 +707,22 @@ static int ubd_add(int n) | |||
668 | struct ubd *dev = &ubd_dev[n]; | 707 | struct ubd *dev = &ubd_dev[n]; |
669 | int err; | 708 | int err; |
670 | 709 | ||
710 | err = -ENODEV; | ||
671 | if(dev->file == NULL) | 711 | if(dev->file == NULL) |
672 | return(-ENODEV); | 712 | goto out; |
673 | 713 | ||
674 | if (ubd_open_dev(dev)) | 714 | if (ubd_open_dev(dev)) |
675 | return(-ENODEV); | 715 | goto out; |
676 | 716 | ||
677 | err = ubd_file_size(dev, &dev->size); | 717 | err = ubd_file_size(dev, &dev->size); |
678 | if(err < 0) | 718 | if(err < 0) |
679 | return(err); | 719 | goto out_close; |
680 | 720 | ||
681 | dev->size = ROUND_BLOCK(dev->size); | 721 | dev->size = ROUND_BLOCK(dev->size); |
682 | 722 | ||
683 | err = ubd_new_disk(MAJOR_NR, dev->size, n, &ubd_gendisk[n]); | 723 | err = ubd_new_disk(MAJOR_NR, dev->size, n, &ubd_gendisk[n]); |
684 | if(err) | 724 | if(err) |
685 | return(err); | 725 | goto out_close; |
686 | 726 | ||
687 | if(fake_major != MAJOR_NR) | 727 | if(fake_major != MAJOR_NR) |
688 | ubd_new_disk(fake_major, dev->size, n, | 728 | ubd_new_disk(fake_major, dev->size, n, |
@@ -693,8 +733,11 @@ static int ubd_add(int n) | |||
693 | if (fake_ide) | 733 | if (fake_ide) |
694 | make_ide_entries(ubd_gendisk[n]->disk_name); | 734 | make_ide_entries(ubd_gendisk[n]->disk_name); |
695 | 735 | ||
736 | err = 0; | ||
737 | out_close: | ||
696 | ubd_close(dev); | 738 | ubd_close(dev); |
697 | return 0; | 739 | out: |
740 | return err; | ||
698 | } | 741 | } |
699 | 742 | ||
700 | static int ubd_config(char *str) | 743 | static int ubd_config(char *str) |
@@ -827,6 +870,10 @@ int ubd_init(void) | |||
827 | { | 870 | { |
828 | int i; | 871 | int i; |
829 | 872 | ||
873 | ubd_reply_fd = init_aio_irq(UBD_IRQ, "ubd", ubd_intr); | ||
874 | if(ubd_reply_fd < 0) | ||
875 | printk("Setting up ubd AIO failed, err = %d\n", ubd_reply_fd); | ||
876 | |||
830 | devfs_mk_dir("ubd"); | 877 | devfs_mk_dir("ubd"); |
831 | if (register_blkdev(MAJOR_NR, "ubd")) | 878 | if (register_blkdev(MAJOR_NR, "ubd")) |
832 | return -1; | 879 | return -1; |
@@ -837,6 +884,7 @@ int ubd_init(void) | |||
837 | return -1; | 884 | return -1; |
838 | } | 885 | } |
839 | 886 | ||
887 | blk_queue_max_hw_segments(ubd_queue, MAX_SG); | ||
840 | if (fake_major != MAJOR_NR) { | 888 | if (fake_major != MAJOR_NR) { |
841 | char name[sizeof("ubd_nnn\0")]; | 889 | char name[sizeof("ubd_nnn\0")]; |
842 | 890 | ||
@@ -848,40 +896,12 @@ int ubd_init(void) | |||
848 | driver_register(&ubd_driver); | 896 | driver_register(&ubd_driver); |
849 | for (i = 0; i < MAX_DEV; i++) | 897 | for (i = 0; i < MAX_DEV; i++) |
850 | ubd_add(i); | 898 | ubd_add(i); |
899 | |||
851 | return 0; | 900 | return 0; |
852 | } | 901 | } |
853 | 902 | ||
854 | late_initcall(ubd_init); | 903 | late_initcall(ubd_init); |
855 | 904 | ||
856 | int ubd_driver_init(void){ | ||
857 | unsigned long stack; | ||
858 | int err; | ||
859 | |||
860 | /* Set by CONFIG_BLK_DEV_UBD_SYNC or ubd=sync.*/ | ||
861 | if(global_openflags.s){ | ||
862 | printk(KERN_INFO "ubd: Synchronous mode\n"); | ||
863 | /* Letting ubd=sync be like using ubd#s= instead of ubd#= is | ||
864 | * enough. So use anyway the io thread. */ | ||
865 | } | ||
866 | stack = alloc_stack(0, 0); | ||
867 | io_pid = start_io_thread(stack + PAGE_SIZE - sizeof(void *), | ||
868 | &thread_fd); | ||
869 | if(io_pid < 0){ | ||
870 | printk(KERN_ERR | ||
871 | "ubd : Failed to start I/O thread (errno = %d) - " | ||
872 | "falling back to synchronous I/O\n", -io_pid); | ||
873 | io_pid = -1; | ||
874 | return(0); | ||
875 | } | ||
876 | err = um_request_irq(UBD_IRQ, thread_fd, IRQ_READ, ubd_intr, | ||
877 | SA_INTERRUPT, "ubd", ubd_dev); | ||
878 | if(err != 0) | ||
879 | printk(KERN_ERR "um_request_irq failed - errno = %d\n", -err); | ||
880 | return(err); | ||
881 | } | ||
882 | |||
883 | device_initcall(ubd_driver_init); | ||
884 | |||
885 | static int ubd_open(struct inode *inode, struct file *filp) | 905 | static int ubd_open(struct inode *inode, struct file *filp) |
886 | { | 906 | { |
887 | struct gendisk *disk = inode->i_bdev->bd_disk; | 907 | struct gendisk *disk = inode->i_bdev->bd_disk; |
@@ -919,105 +939,55 @@ static int ubd_release(struct inode * inode, struct file * file) | |||
919 | return(0); | 939 | return(0); |
920 | } | 940 | } |
921 | 941 | ||
922 | static void cowify_bitmap(__u64 io_offset, int length, unsigned long *cow_mask, | 942 | static void cowify_bitmap(struct io_thread_req *req, unsigned long *bitmap) |
923 | __u64 *cow_offset, unsigned long *bitmap, | ||
924 | __u64 bitmap_offset, unsigned long *bitmap_words, | ||
925 | __u64 bitmap_len) | ||
926 | { | 943 | { |
927 | __u64 sector = io_offset >> 9; | 944 | __u64 sector = req->offset / req->sectorsize; |
928 | int i, update_bitmap = 0; | 945 | int i; |
929 | |||
930 | for(i = 0; i < length >> 9; i++){ | ||
931 | if(cow_mask != NULL) | ||
932 | ubd_set_bit(i, (unsigned char *) cow_mask); | ||
933 | if(ubd_test_bit(sector + i, (unsigned char *) bitmap)) | ||
934 | continue; | ||
935 | |||
936 | update_bitmap = 1; | ||
937 | ubd_set_bit(sector + i, (unsigned char *) bitmap); | ||
938 | } | ||
939 | |||
940 | if(!update_bitmap) | ||
941 | return; | ||
942 | |||
943 | *cow_offset = sector / (sizeof(unsigned long) * 8); | ||
944 | |||
945 | /* This takes care of the case where we're exactly at the end of the | ||
946 | * device, and *cow_offset + 1 is off the end. So, just back it up | ||
947 | * by one word. Thanks to Lynn Kerby for the fix and James McMechan | ||
948 | * for the original diagnosis. | ||
949 | */ | ||
950 | if(*cow_offset == ((bitmap_len + sizeof(unsigned long) - 1) / | ||
951 | sizeof(unsigned long) - 1)) | ||
952 | (*cow_offset)--; | ||
953 | |||
954 | bitmap_words[0] = bitmap[*cow_offset]; | ||
955 | bitmap_words[1] = bitmap[*cow_offset + 1]; | ||
956 | |||
957 | *cow_offset *= sizeof(unsigned long); | ||
958 | *cow_offset += bitmap_offset; | ||
959 | } | ||
960 | 946 | ||
961 | static void cowify_req(struct io_thread_req *req, unsigned long *bitmap, | 947 | for(i = 0; i < req->length / req->sectorsize; i++){ |
962 | __u64 bitmap_offset, __u64 bitmap_len) | 948 | if(ubd_test_bit(sector + i, bitmap)) |
963 | { | 949 | continue; |
964 | __u64 sector = req->offset >> 9; | ||
965 | int i; | ||
966 | 950 | ||
967 | if(req->length > (sizeof(req->sector_mask) * 8) << 9) | 951 | if(req->bitmap_start == -1) |
968 | panic("Operation too long"); | 952 | req->bitmap_start = sector + i; |
953 | req->bitmap_end = sector + i + 1; | ||
969 | 954 | ||
970 | if(req->op == UBD_READ) { | 955 | ubd_set_bit(sector + i, bitmap); |
971 | for(i = 0; i < req->length >> 9; i++){ | 956 | } |
972 | if(ubd_test_bit(sector + i, (unsigned char *) bitmap)) | ||
973 | ubd_set_bit(i, (unsigned char *) | ||
974 | &req->sector_mask); | ||
975 | } | ||
976 | } | ||
977 | else cowify_bitmap(req->offset, req->length, &req->sector_mask, | ||
978 | &req->cow_offset, bitmap, bitmap_offset, | ||
979 | req->bitmap_words, bitmap_len); | ||
980 | } | 957 | } |
981 | 958 | ||
982 | /* Called with ubd_io_lock held */ | 959 | /* Called with ubd_io_lock held */ |
983 | static int prepare_request(struct request *req, struct io_thread_req *io_req) | 960 | static int prepare_request(struct request *req, struct io_thread_req *io_req, |
961 | unsigned long long offset, int page_offset, | ||
962 | int len, struct page *page) | ||
984 | { | 963 | { |
985 | struct gendisk *disk = req->rq_disk; | 964 | struct gendisk *disk = req->rq_disk; |
986 | struct ubd *dev = disk->private_data; | 965 | struct ubd *dev = disk->private_data; |
987 | __u64 offset; | ||
988 | int len; | ||
989 | |||
990 | if(req->rq_status == RQ_INACTIVE) return(1); | ||
991 | 966 | ||
992 | /* This should be impossible now */ | 967 | /* This should be impossible now */ |
993 | if((rq_data_dir(req) == WRITE) && !dev->openflags.w){ | 968 | if((rq_data_dir(req) == WRITE) && !dev->openflags.w){ |
994 | printk("Write attempted on readonly ubd device %s\n", | 969 | printk("Write attempted on readonly ubd device %s\n", |
995 | disk->disk_name); | 970 | disk->disk_name); |
996 | end_request(req, 0); | 971 | ubd_end_request(req, 0, 0); |
997 | return(1); | 972 | return(1); |
998 | } | 973 | } |
999 | 974 | ||
1000 | offset = ((__u64) req->sector) << 9; | ||
1001 | len = req->current_nr_sectors << 9; | ||
1002 | |||
1003 | io_req->fds[0] = (dev->cow.file != NULL) ? dev->cow.fd : dev->fd; | 975 | io_req->fds[0] = (dev->cow.file != NULL) ? dev->cow.fd : dev->fd; |
1004 | io_req->fds[1] = dev->fd; | 976 | io_req->fds[1] = dev->fd; |
1005 | io_req->cow_offset = -1; | ||
1006 | io_req->offset = offset; | 977 | io_req->offset = offset; |
1007 | io_req->length = len; | 978 | io_req->length = len; |
1008 | io_req->error = 0; | 979 | io_req->error = 0; |
1009 | io_req->sector_mask = 0; | 980 | io_req->op = (rq_data_dir(req) == READ) ? AIO_READ : AIO_WRITE; |
1010 | |||
1011 | io_req->op = (rq_data_dir(req) == READ) ? UBD_READ : UBD_WRITE; | ||
1012 | io_req->offsets[0] = 0; | 981 | io_req->offsets[0] = 0; |
1013 | io_req->offsets[1] = dev->cow.data_offset; | 982 | io_req->offsets[1] = dev->cow.data_offset; |
1014 | io_req->buffer = req->buffer; | 983 | io_req->buffer = page_address(page) + page_offset; |
1015 | io_req->sectorsize = 1 << 9; | 984 | io_req->sectorsize = 1 << 9; |
985 | io_req->bitmap_offset = dev->cow.bitmap_offset; | ||
986 | io_req->bitmap_start = -1; | ||
987 | io_req->bitmap_end = -1; | ||
1016 | 988 | ||
1017 | if(dev->cow.file != NULL) | 989 | if((dev->cow.file != NULL) && (io_req->op == UBD_WRITE)) |
1018 | cowify_req(io_req, dev->cow.bitmap, dev->cow.bitmap_offset, | 990 | cowify_bitmap(io_req, dev->cow.bitmap); |
1019 | dev->cow.bitmap_len); | ||
1020 | |||
1021 | return(0); | 991 | return(0); |
1022 | } | 992 | } |
1023 | 993 | ||
@@ -1026,30 +996,36 @@ static void do_ubd_request(request_queue_t *q) | |||
1026 | { | 996 | { |
1027 | struct io_thread_req io_req; | 997 | struct io_thread_req io_req; |
1028 | struct request *req; | 998 | struct request *req; |
1029 | int err, n; | 999 | __u64 sector; |
1030 | 1000 | int err; | |
1031 | if(thread_fd == -1){ | 1001 | |
1032 | while((req = elv_next_request(q)) != NULL){ | 1002 | if(in_ubd) |
1033 | err = prepare_request(req, &io_req); | 1003 | return; |
1034 | if(!err){ | 1004 | in_ubd = 1; |
1035 | do_io(&io_req); | 1005 | while((req = elv_next_request(q)) != NULL){ |
1036 | __ubd_finish(req, io_req.error); | 1006 | struct gendisk *disk = req->rq_disk; |
1037 | } | 1007 | struct ubd *dev = disk->private_data; |
1038 | } | 1008 | int n, i; |
1039 | } | 1009 | |
1040 | else { | 1010 | blkdev_dequeue_request(req); |
1041 | if(do_ubd || (req = elv_next_request(q)) == NULL) | 1011 | |
1042 | return; | 1012 | sector = req->sector; |
1043 | err = prepare_request(req, &io_req); | 1013 | n = blk_rq_map_sg(q, req, dev->sg); |
1044 | if(!err){ | 1014 | |
1045 | do_ubd = ubd_handler; | 1015 | for(i = 0; i < n; i++){ |
1046 | n = os_write_file(thread_fd, (char *) &io_req, | 1016 | struct scatterlist *sg = &dev->sg[i]; |
1047 | sizeof(io_req)); | 1017 | |
1048 | if(n != sizeof(io_req)) | 1018 | err = prepare_request(req, &io_req, sector << 9, |
1049 | printk("write to io thread failed, " | 1019 | sg->offset, sg->length, |
1050 | "errno = %d\n", -n); | 1020 | sg->page); |
1021 | if(err) | ||
1022 | continue; | ||
1023 | |||
1024 | sector += sg->length >> 9; | ||
1025 | do_io(&io_req, req, dev->cow.bitmap); | ||
1051 | } | 1026 | } |
1052 | } | 1027 | } |
1028 | in_ubd = 0; | ||
1053 | } | 1029 | } |
1054 | 1030 | ||
1055 | static int ubd_ioctl(struct inode * inode, struct file * file, | 1031 | static int ubd_ioctl(struct inode * inode, struct file * file, |
@@ -1265,131 +1241,95 @@ int create_cow_file(char *cow_file, char *backing_file, struct openflags flags, | |||
1265 | return(err); | 1241 | return(err); |
1266 | } | 1242 | } |
1267 | 1243 | ||
1268 | static int update_bitmap(struct io_thread_req *req) | 1244 | void do_io(struct io_thread_req *req, struct request *r, unsigned long *bitmap) |
1269 | { | ||
1270 | int n; | ||
1271 | |||
1272 | if(req->cow_offset == -1) | ||
1273 | return(0); | ||
1274 | |||
1275 | n = os_seek_file(req->fds[1], req->cow_offset); | ||
1276 | if(n < 0){ | ||
1277 | printk("do_io - bitmap lseek failed : err = %d\n", -n); | ||
1278 | return(1); | ||
1279 | } | ||
1280 | |||
1281 | n = os_write_file(req->fds[1], &req->bitmap_words, | ||
1282 | sizeof(req->bitmap_words)); | ||
1283 | if(n != sizeof(req->bitmap_words)){ | ||
1284 | printk("do_io - bitmap update failed, err = %d fd = %d\n", -n, | ||
1285 | req->fds[1]); | ||
1286 | return(1); | ||
1287 | } | ||
1288 | |||
1289 | return(0); | ||
1290 | } | ||
1291 | |||
1292 | void do_io(struct io_thread_req *req) | ||
1293 | { | 1245 | { |
1294 | char *buf; | 1246 | struct ubd_aio *aio; |
1295 | unsigned long len; | 1247 | struct bitmap_io *bitmap_io = NULL; |
1296 | int n, nsectors, start, end, bit; | 1248 | char *buf; |
1297 | int err; | 1249 | void *bitmap_buf = NULL; |
1298 | __u64 off; | 1250 | unsigned long len, sector; |
1299 | 1251 | int nsectors, start, end, bit, err; | |
1300 | nsectors = req->length / req->sectorsize; | 1252 | __u64 off; |
1301 | start = 0; | 1253 | |
1302 | do { | 1254 | if(req->bitmap_start != -1){ |
1303 | bit = ubd_test_bit(start, (unsigned char *) &req->sector_mask); | 1255 | /* Round up to the nearest word */ |
1304 | end = start; | 1256 | int round = sizeof(unsigned long); |
1305 | while((end < nsectors) && | 1257 | len = (req->bitmap_end - req->bitmap_start + |
1306 | (ubd_test_bit(end, (unsigned char *) | 1258 | round * 8 - 1) / (round * 8); |
1307 | &req->sector_mask) == bit)) | 1259 | len *= round; |
1308 | end++; | 1260 | |
1309 | 1261 | off = req->bitmap_start / (8 * round); | |
1310 | off = req->offset + req->offsets[bit] + | 1262 | off *= round; |
1311 | start * req->sectorsize; | 1263 | |
1312 | len = (end - start) * req->sectorsize; | 1264 | bitmap_io = kmalloc(sizeof(*bitmap_io), GFP_KERNEL); |
1313 | buf = &req->buffer[start * req->sectorsize]; | 1265 | if(bitmap_io == NULL){ |
1314 | 1266 | printk("Failed to kmalloc bitmap IO\n"); | |
1315 | err = os_seek_file(req->fds[bit], off); | 1267 | req->error = 1; |
1316 | if(err < 0){ | 1268 | return; |
1317 | printk("do_io - lseek failed : err = %d\n", -err); | 1269 | } |
1318 | req->error = 1; | ||
1319 | return; | ||
1320 | } | ||
1321 | if(req->op == UBD_READ){ | ||
1322 | n = 0; | ||
1323 | do { | ||
1324 | buf = &buf[n]; | ||
1325 | len -= n; | ||
1326 | n = os_read_file(req->fds[bit], buf, len); | ||
1327 | if (n < 0) { | ||
1328 | printk("do_io - read failed, err = %d " | ||
1329 | "fd = %d\n", -n, req->fds[bit]); | ||
1330 | req->error = 1; | ||
1331 | return; | ||
1332 | } | ||
1333 | } while((n < len) && (n != 0)); | ||
1334 | if (n < len) memset(&buf[n], 0, len - n); | ||
1335 | } else { | ||
1336 | n = os_write_file(req->fds[bit], buf, len); | ||
1337 | if(n != len){ | ||
1338 | printk("do_io - write failed err = %d " | ||
1339 | "fd = %d\n", -n, req->fds[bit]); | ||
1340 | req->error = 1; | ||
1341 | return; | ||
1342 | } | ||
1343 | } | ||
1344 | 1270 | ||
1345 | start = end; | 1271 | bitmap_buf = kmalloc(len, GFP_KERNEL); |
1346 | } while(start < nsectors); | 1272 | if(bitmap_buf == NULL){ |
1273 | printk("do_io : kmalloc of bitmap chunk " | ||
1274 | "failed\n"); | ||
1275 | kfree(bitmap_io); | ||
1276 | req->error = 1; | ||
1277 | return; | ||
1278 | } | ||
1279 | memcpy(bitmap_buf, &bitmap[off / sizeof(bitmap[0])], len); | ||
1280 | |||
1281 | *bitmap_io = ((struct bitmap_io) | ||
1282 | { .count = ATOMIC_INIT(0), | ||
1283 | .aio = INIT_AIO(AIO_WRITE, req->fds[1], | ||
1284 | bitmap_buf, len, | ||
1285 | req->bitmap_offset + off, | ||
1286 | ubd_reply_fd) } ); | ||
1287 | } | ||
1347 | 1288 | ||
1348 | req->error = update_bitmap(req); | 1289 | nsectors = req->length / req->sectorsize; |
1349 | } | 1290 | start = 0; |
1291 | end = nsectors; | ||
1292 | bit = 0; | ||
1293 | do { | ||
1294 | if(bitmap != NULL){ | ||
1295 | sector = req->offset / req->sectorsize; | ||
1296 | bit = ubd_test_bit(sector + start, bitmap); | ||
1297 | end = start; | ||
1298 | while((end < nsectors) && | ||
1299 | (ubd_test_bit(sector + end, bitmap) == bit)) | ||
1300 | end++; | ||
1301 | } | ||
1350 | 1302 | ||
1351 | /* Changed in start_io_thread, which is serialized by being called only | 1303 | off = req->offsets[bit] + req->offset + |
1352 | * from ubd_init, which is an initcall. | 1304 | start * req->sectorsize; |
1353 | */ | 1305 | len = (end - start) * req->sectorsize; |
1354 | int kernel_fd = -1; | 1306 | buf = &req->buffer[start * req->sectorsize]; |
1355 | 1307 | ||
1356 | /* Only changed by the io thread */ | 1308 | aio = kmalloc(sizeof(*aio), GFP_KERNEL); |
1357 | int io_count = 0; | 1309 | if(aio == NULL){ |
1310 | req->error = 1; | ||
1311 | return; | ||
1312 | } | ||
1358 | 1313 | ||
1359 | int io_thread(void *arg) | 1314 | *aio = ((struct ubd_aio) |
1360 | { | 1315 | { .aio = INIT_AIO(req->op, req->fds[bit], buf, |
1361 | struct io_thread_req req; | 1316 | len, off, ubd_reply_fd), |
1362 | int n; | 1317 | .len = len, |
1318 | .req = r, | ||
1319 | .bitmap = bitmap_io, | ||
1320 | .bitmap_buf = bitmap_buf }); | ||
1321 | |||
1322 | if(aio->bitmap != NULL) | ||
1323 | atomic_inc(&aio->bitmap->count); | ||
1324 | |||
1325 | err = submit_aio(&aio->aio); | ||
1326 | if(err){ | ||
1327 | printk("do_io - submit_aio failed, " | ||
1328 | "err = %d\n", err); | ||
1329 | req->error = 1; | ||
1330 | return; | ||
1331 | } | ||
1363 | 1332 | ||
1364 | ignore_sigwinch_sig(); | 1333 | start = end; |
1365 | while(1){ | 1334 | } while(start < nsectors); |
1366 | n = os_read_file(kernel_fd, &req, sizeof(req)); | ||
1367 | if(n != sizeof(req)){ | ||
1368 | if(n < 0) | ||
1369 | printk("io_thread - read failed, fd = %d, " | ||
1370 | "err = %d\n", kernel_fd, -n); | ||
1371 | else { | ||
1372 | printk("io_thread - short read, fd = %d, " | ||
1373 | "length = %d\n", kernel_fd, n); | ||
1374 | } | ||
1375 | continue; | ||
1376 | } | ||
1377 | io_count++; | ||
1378 | do_io(&req); | ||
1379 | n = os_write_file(kernel_fd, &req, sizeof(req)); | ||
1380 | if(n != sizeof(req)) | ||
1381 | printk("io_thread - write failed, fd = %d, err = %d\n", | ||
1382 | kernel_fd, -n); | ||
1383 | } | ||
1384 | } | 1335 | } |
1385 | |||
1386 | /* | ||
1387 | * Overrides for Emacs so that we follow Linus's tabbing style. | ||
1388 | * Emacs will notice this stuff at the end of the file and automatically | ||
1389 | * adjust the settings for this buffer only. This must remain at the end | ||
1390 | * of the file. | ||
1391 | * --------------------------------------------------------------------------- | ||
1392 | * Local variables: | ||
1393 | * c-file-style: "linux" | ||
1394 | * End: | ||
1395 | */ | ||