diff options
author | Jeff Dike <jdike@addtoit.com> | 2007-02-10 04:44:16 -0500 |
---|---|---|
committer | Linus Torvalds <torvalds@woody.linux-foundation.org> | 2007-02-11 13:51:23 -0500 |
commit | 62f96cb01e8de7a5daee472e540f726db2801499 (patch) | |
tree | 0ad14b68eeb8170669e8072e9e09782fc8dd4b79 /arch/um | |
parent | 92b4202f38cf630350a9e1eb0ab23ca4fc5b687b (diff) |
[PATCH] uml: add per-device queues and locks to ubd driver
Replace global queue and lock with per-device queues and locks. Mostly a
straightforward replacement of ubd_io_lock with dev->lock and ubd_queue with
dev->queue.
Complications -
There was no way to get a request struct (and queue) from the
structure sent to the io_thread, so a pointer to the request was
added. This is needed in ubd_handler in order to kick do_ubd_request
to process another request.
Queue initialization is moved from ubd_init to ubd_add.
Signed-off-by: Jeff Dike <jdike@addtoit.com>
Cc: Paolo 'Blaisorblade' Giarrusso <blaisorblade@yahoo.it>
Cc: Jens Axboe <axboe@kernel.dk>
Signed-off-by: Andrew Morton <akpm@linux-foundation.org>
Signed-off-by: Linus Torvalds <torvalds@linux-foundation.org>
Diffstat (limited to 'arch/um')
-rw-r--r-- | arch/um/drivers/ubd_kern.c | 70 |
1 files changed, 40 insertions, 30 deletions
diff --git a/arch/um/drivers/ubd_kern.c b/arch/um/drivers/ubd_kern.c index c1d40fb738e6..d863482cdd27 100644 --- a/arch/um/drivers/ubd_kern.c +++ b/arch/um/drivers/ubd_kern.c | |||
@@ -56,6 +56,7 @@ | |||
56 | enum ubd_req { UBD_READ, UBD_WRITE }; | 56 | enum ubd_req { UBD_READ, UBD_WRITE }; |
57 | 57 | ||
58 | struct io_thread_req { | 58 | struct io_thread_req { |
59 | struct request *req; | ||
59 | enum ubd_req op; | 60 | enum ubd_req op; |
60 | int fds[2]; | 61 | int fds[2]; |
61 | unsigned long offsets[2]; | 62 | unsigned long offsets[2]; |
@@ -106,10 +107,6 @@ static inline void ubd_set_bit(__u64 bit, unsigned char *data) | |||
106 | 107 | ||
107 | #define DRIVER_NAME "uml-blkdev" | 108 | #define DRIVER_NAME "uml-blkdev" |
108 | 109 | ||
109 | /* Can be taken in interrupt context, and is passed to the block layer to lock | ||
110 | * the request queue. Kernel side code knows that. */ | ||
111 | static DEFINE_SPINLOCK(ubd_io_lock); | ||
112 | |||
113 | static DEFINE_MUTEX(ubd_lock); | 110 | static DEFINE_MUTEX(ubd_lock); |
114 | 111 | ||
115 | /* XXX - this made sense in 2.4 days, now it's only used as a boolean, and | 112 | /* XXX - this made sense in 2.4 days, now it's only used as a boolean, and |
@@ -132,9 +129,6 @@ static struct block_device_operations ubd_blops = { | |||
132 | .getgeo = ubd_getgeo, | 129 | .getgeo = ubd_getgeo, |
133 | }; | 130 | }; |
134 | 131 | ||
135 | /* Protected by the queue_lock */ | ||
136 | static request_queue_t *ubd_queue; | ||
137 | |||
138 | /* Protected by ubd_lock */ | 132 | /* Protected by ubd_lock */ |
139 | static int fake_major = MAJOR_NR; | 133 | static int fake_major = MAJOR_NR; |
140 | 134 | ||
@@ -178,6 +172,8 @@ struct ubd { | |||
178 | unsigned no_cow:1; | 172 | unsigned no_cow:1; |
179 | struct cow cow; | 173 | struct cow cow; |
180 | struct platform_device pdev; | 174 | struct platform_device pdev; |
175 | struct request_queue *queue; | ||
176 | spinlock_t lock; | ||
181 | }; | 177 | }; |
182 | 178 | ||
183 | #define DEFAULT_COW { \ | 179 | #define DEFAULT_COW { \ |
@@ -198,6 +194,7 @@ struct ubd { | |||
198 | .no_cow = 0, \ | 194 | .no_cow = 0, \ |
199 | .shared = 0, \ | 195 | .shared = 0, \ |
200 | .cow = DEFAULT_COW, \ | 196 | .cow = DEFAULT_COW, \ |
197 | .lock = SPIN_LOCK_UNLOCKED, \ | ||
201 | } | 198 | } |
202 | 199 | ||
203 | struct ubd ubd_devs[MAX_DEV] = { [ 0 ... MAX_DEV - 1 ] = DEFAULT_UBD }; | 200 | struct ubd ubd_devs[MAX_DEV] = { [ 0 ... MAX_DEV - 1 ] = DEFAULT_UBD }; |
@@ -504,17 +501,20 @@ static void __ubd_finish(struct request *req, int error) | |||
504 | * spin_lock_irq()/spin_lock_irqsave() */ | 501 | * spin_lock_irq()/spin_lock_irqsave() */ |
505 | static inline void ubd_finish(struct request *req, int error) | 502 | static inline void ubd_finish(struct request *req, int error) |
506 | { | 503 | { |
507 | spin_lock(&ubd_io_lock); | 504 | struct ubd *dev = req->rq_disk->private_data; |
505 | |||
506 | spin_lock(&dev->lock); | ||
508 | __ubd_finish(req, error); | 507 | __ubd_finish(req, error); |
509 | spin_unlock(&ubd_io_lock); | 508 | spin_unlock(&dev->lock); |
510 | } | 509 | } |
511 | 510 | ||
512 | /* XXX - move this inside ubd_intr. */ | 511 | /* XXX - move this inside ubd_intr. */ |
513 | /* Called without ubd_io_lock held, and only in interrupt context. */ | 512 | /* Called without dev->lock held, and only in interrupt context. */ |
514 | static void ubd_handler(void) | 513 | static void ubd_handler(void) |
515 | { | 514 | { |
516 | struct io_thread_req req; | 515 | struct io_thread_req req; |
517 | struct request *rq = elv_next_request(ubd_queue); | 516 | struct request *rq; |
517 | struct ubd *dev; | ||
518 | int n; | 518 | int n; |
519 | 519 | ||
520 | do_ubd = 0; | 520 | do_ubd = 0; |
@@ -523,17 +523,17 @@ static void ubd_handler(void) | |||
523 | if(n != sizeof(req)){ | 523 | if(n != sizeof(req)){ |
524 | printk(KERN_ERR "Pid %d - spurious interrupt in ubd_handler, " | 524 | printk(KERN_ERR "Pid %d - spurious interrupt in ubd_handler, " |
525 | "err = %d\n", os_getpid(), -n); | 525 | "err = %d\n", os_getpid(), -n); |
526 | spin_lock(&ubd_io_lock); | ||
527 | end_request(rq, 0); | ||
528 | spin_unlock(&ubd_io_lock); | ||
529 | return; | 526 | return; |
530 | } | 527 | } |
531 | 528 | ||
529 | rq = req.req; | ||
530 | dev = rq->rq_disk->private_data; | ||
531 | |||
532 | ubd_finish(rq, req.error); | 532 | ubd_finish(rq, req.error); |
533 | reactivate_fd(thread_fd, UBD_IRQ); | 533 | reactivate_fd(thread_fd, UBD_IRQ); |
534 | spin_lock(&ubd_io_lock); | 534 | spin_lock(&dev->lock); |
535 | do_ubd_request(ubd_queue); | 535 | do_ubd_request(dev->queue); |
536 | spin_unlock(&ubd_io_lock); | 536 | spin_unlock(&dev->lock); |
537 | } | 537 | } |
538 | 538 | ||
539 | static irqreturn_t ubd_intr(int irq, void *dev) | 539 | static irqreturn_t ubd_intr(int irq, void *dev) |
@@ -664,7 +664,7 @@ static int ubd_disk_register(int major, u64 size, int unit, | |||
664 | } | 664 | } |
665 | 665 | ||
666 | disk->private_data = &ubd_devs[unit]; | 666 | disk->private_data = &ubd_devs[unit]; |
667 | disk->queue = ubd_queue; | 667 | disk->queue = ubd_devs[unit].queue; |
668 | add_disk(disk); | 668 | add_disk(disk); |
669 | 669 | ||
670 | *disk_out = disk; | 670 | *disk_out = disk; |
@@ -689,13 +689,23 @@ static int ubd_add(int n, char **error_out) | |||
689 | 689 | ||
690 | ubd_dev->size = ROUND_BLOCK(ubd_dev->size); | 690 | ubd_dev->size = ROUND_BLOCK(ubd_dev->size); |
691 | 691 | ||
692 | err = ubd_disk_register(MAJOR_NR, ubd_dev->size, n, &ubd_gendisk[n]); | 692 | err = -ENOMEM; |
693 | if(err) | 693 | ubd_dev->queue = blk_init_queue(do_ubd_request, &ubd_dev->lock); |
694 | if (ubd_dev->queue == NULL) { | ||
695 | *error_out = "Failed to initialize device queue"; | ||
694 | goto out; | 696 | goto out; |
697 | } | ||
698 | ubd_dev->queue->queuedata = ubd_dev; | ||
699 | |||
700 | err = ubd_disk_register(MAJOR_NR, ubd_dev->size, n, &ubd_gendisk[n]); | ||
701 | if(err){ | ||
702 | *error_out = "Failed to register device"; | ||
703 | goto out_cleanup; | ||
704 | } | ||
695 | 705 | ||
696 | if(fake_major != MAJOR_NR) | 706 | if(fake_major != MAJOR_NR) |
697 | ubd_disk_register(fake_major, ubd_dev->size, n, | 707 | ubd_disk_register(fake_major, ubd_dev->size, n, |
698 | &fake_gendisk[n]); | 708 | &fake_gendisk[n]); |
699 | 709 | ||
700 | /* perhaps this should also be under the "if (fake_major)" above */ | 710 | /* perhaps this should also be under the "if (fake_major)" above */ |
701 | /* using the fake_disk->disk_name and also the fakehd_set name */ | 711 | /* using the fake_disk->disk_name and also the fakehd_set name */ |
@@ -705,6 +715,10 @@ static int ubd_add(int n, char **error_out) | |||
705 | err = 0; | 715 | err = 0; |
706 | out: | 716 | out: |
707 | return err; | 717 | return err; |
718 | |||
719 | out_cleanup: | ||
720 | blk_cleanup_queue(ubd_dev->queue); | ||
721 | goto out; | ||
708 | } | 722 | } |
709 | 723 | ||
710 | static int ubd_config(char *str, char **error_out) | 724 | static int ubd_config(char *str, char **error_out) |
@@ -816,6 +830,7 @@ static int ubd_remove(int n, char **error_out) | |||
816 | fake_gendisk[n] = NULL; | 830 | fake_gendisk[n] = NULL; |
817 | } | 831 | } |
818 | 832 | ||
833 | blk_cleanup_queue(ubd_dev->queue); | ||
819 | platform_device_unregister(&ubd_dev->pdev); | 834 | platform_device_unregister(&ubd_dev->pdev); |
820 | *ubd_dev = ((struct ubd) DEFAULT_UBD); | 835 | *ubd_dev = ((struct ubd) DEFAULT_UBD); |
821 | err = 0; | 836 | err = 0; |
@@ -869,12 +884,6 @@ static int __init ubd_init(void) | |||
869 | if (register_blkdev(MAJOR_NR, "ubd")) | 884 | if (register_blkdev(MAJOR_NR, "ubd")) |
870 | return -1; | 885 | return -1; |
871 | 886 | ||
872 | ubd_queue = blk_init_queue(do_ubd_request, &ubd_io_lock); | ||
873 | if (!ubd_queue) { | ||
874 | unregister_blkdev(MAJOR_NR, "ubd"); | ||
875 | return -1; | ||
876 | } | ||
877 | |||
878 | if (fake_major != MAJOR_NR) { | 887 | if (fake_major != MAJOR_NR) { |
879 | char name[sizeof("ubd_nnn\0")]; | 888 | char name[sizeof("ubd_nnn\0")]; |
880 | 889 | ||
@@ -1020,7 +1029,7 @@ static void cowify_req(struct io_thread_req *req, unsigned long *bitmap, | |||
1020 | req->bitmap_words, bitmap_len); | 1029 | req->bitmap_words, bitmap_len); |
1021 | } | 1030 | } |
1022 | 1031 | ||
1023 | /* Called with ubd_io_lock held */ | 1032 | /* Called with dev->lock held */ |
1024 | static int prepare_request(struct request *req, struct io_thread_req *io_req) | 1033 | static int prepare_request(struct request *req, struct io_thread_req *io_req) |
1025 | { | 1034 | { |
1026 | struct gendisk *disk = req->rq_disk; | 1035 | struct gendisk *disk = req->rq_disk; |
@@ -1039,6 +1048,7 @@ static int prepare_request(struct request *req, struct io_thread_req *io_req) | |||
1039 | offset = ((__u64) req->sector) << 9; | 1048 | offset = ((__u64) req->sector) << 9; |
1040 | len = req->current_nr_sectors << 9; | 1049 | len = req->current_nr_sectors << 9; |
1041 | 1050 | ||
1051 | io_req->req = req; | ||
1042 | io_req->fds[0] = (ubd_dev->cow.file != NULL) ? ubd_dev->cow.fd : ubd_dev->fd; | 1052 | io_req->fds[0] = (ubd_dev->cow.file != NULL) ? ubd_dev->cow.fd : ubd_dev->fd; |
1043 | io_req->fds[1] = ubd_dev->fd; | 1053 | io_req->fds[1] = ubd_dev->fd; |
1044 | io_req->cow_offset = -1; | 1054 | io_req->cow_offset = -1; |
@@ -1060,7 +1070,7 @@ static int prepare_request(struct request *req, struct io_thread_req *io_req) | |||
1060 | return(0); | 1070 | return(0); |
1061 | } | 1071 | } |
1062 | 1072 | ||
1063 | /* Called with ubd_io_lock held */ | 1073 | /* Called with dev->lock held */ |
1064 | static void do_ubd_request(request_queue_t *q) | 1074 | static void do_ubd_request(request_queue_t *q) |
1065 | { | 1075 | { |
1066 | struct io_thread_req io_req; | 1076 | struct io_thread_req io_req; |