Commit 62f96cb0 authored by Jeff Dike's avatar Jeff Dike Committed by Linus Torvalds

[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: default avatarJeff Dike <jdike@addtoit.com>
Cc: Paolo 'Blaisorblade' Giarrusso <blaisorblade@yahoo.it>
Cc: Jens Axboe <axboe@kernel.dk>
Signed-off-by: default avatarAndrew Morton <akpm@linux-foundation.org>
Signed-off-by: default avatarLinus Torvalds <torvalds@linux-foundation.org>
parent 92b4202f
...@@ -56,6 +56,7 @@ ...@@ -56,6 +56,7 @@
enum ubd_req { UBD_READ, UBD_WRITE }; enum ubd_req { UBD_READ, UBD_WRITE };
struct io_thread_req { struct io_thread_req {
struct request *req;
enum ubd_req op; enum ubd_req op;
int fds[2]; int fds[2];
unsigned long offsets[2]; unsigned long offsets[2];
...@@ -106,10 +107,6 @@ static inline void ubd_set_bit(__u64 bit, unsigned char *data) ...@@ -106,10 +107,6 @@ static inline void ubd_set_bit(__u64 bit, unsigned char *data)
#define DRIVER_NAME "uml-blkdev" #define DRIVER_NAME "uml-blkdev"
/* Can be taken in interrupt context, and is passed to the block layer to lock
* the request queue. Kernel side code knows that. */
static DEFINE_SPINLOCK(ubd_io_lock);
static DEFINE_MUTEX(ubd_lock); static DEFINE_MUTEX(ubd_lock);
/* XXX - this made sense in 2.4 days, now it's only used as a boolean, and /* 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,9 +129,6 @@ static struct block_device_operations ubd_blops = {
.getgeo = ubd_getgeo, .getgeo = ubd_getgeo,
}; };
/* Protected by the queue_lock */
static request_queue_t *ubd_queue;
/* Protected by ubd_lock */ /* Protected by ubd_lock */
static int fake_major = MAJOR_NR; static int fake_major = MAJOR_NR;
...@@ -178,6 +172,8 @@ struct ubd { ...@@ -178,6 +172,8 @@ struct ubd {
unsigned no_cow:1; unsigned no_cow:1;
struct cow cow; struct cow cow;
struct platform_device pdev; struct platform_device pdev;
struct request_queue *queue;
spinlock_t lock;
}; };
#define DEFAULT_COW { \ #define DEFAULT_COW { \
...@@ -198,6 +194,7 @@ struct ubd { ...@@ -198,6 +194,7 @@ struct ubd {
.no_cow = 0, \ .no_cow = 0, \
.shared = 0, \ .shared = 0, \
.cow = DEFAULT_COW, \ .cow = DEFAULT_COW, \
.lock = SPIN_LOCK_UNLOCKED, \
} }
struct ubd ubd_devs[MAX_DEV] = { [ 0 ... MAX_DEV - 1 ] = DEFAULT_UBD }; 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,17 +501,20 @@ static void __ubd_finish(struct request *req, int error)
* spin_lock_irq()/spin_lock_irqsave() */ * spin_lock_irq()/spin_lock_irqsave() */
static inline void ubd_finish(struct request *req, int error) static inline void ubd_finish(struct request *req, int error)
{ {
spin_lock(&ubd_io_lock); struct ubd *dev = req->rq_disk->private_data;
spin_lock(&dev->lock);
__ubd_finish(req, error); __ubd_finish(req, error);
spin_unlock(&ubd_io_lock); spin_unlock(&dev->lock);
} }
/* XXX - move this inside ubd_intr. */ /* XXX - move this inside ubd_intr. */
/* Called without ubd_io_lock held, and only in interrupt context. */ /* Called without dev->lock held, and only in interrupt context. */
static void ubd_handler(void) static void ubd_handler(void)
{ {
struct io_thread_req req; struct io_thread_req req;
struct request *rq = elv_next_request(ubd_queue); struct request *rq;
struct ubd *dev;
int n; int n;
do_ubd = 0; do_ubd = 0;
...@@ -523,17 +523,17 @@ static void ubd_handler(void) ...@@ -523,17 +523,17 @@ static void ubd_handler(void)
if(n != sizeof(req)){ if(n != sizeof(req)){
printk(KERN_ERR "Pid %d - spurious interrupt in ubd_handler, " printk(KERN_ERR "Pid %d - spurious interrupt in ubd_handler, "
"err = %d\n", os_getpid(), -n); "err = %d\n", os_getpid(), -n);
spin_lock(&ubd_io_lock);
end_request(rq, 0);
spin_unlock(&ubd_io_lock);
return; return;
} }
rq = req.req;
dev = rq->rq_disk->private_data;
ubd_finish(rq, req.error); ubd_finish(rq, req.error);
reactivate_fd(thread_fd, UBD_IRQ); reactivate_fd(thread_fd, UBD_IRQ);
spin_lock(&ubd_io_lock); spin_lock(&dev->lock);
do_ubd_request(ubd_queue); do_ubd_request(dev->queue);
spin_unlock(&ubd_io_lock); spin_unlock(&dev->lock);
} }
static irqreturn_t ubd_intr(int irq, void *dev) 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,7 +664,7 @@ static int ubd_disk_register(int major, u64 size, int unit,
} }
disk->private_data = &ubd_devs[unit]; disk->private_data = &ubd_devs[unit];
disk->queue = ubd_queue; disk->queue = ubd_devs[unit].queue;
add_disk(disk); add_disk(disk);
*disk_out = disk; *disk_out = disk;
...@@ -689,13 +689,23 @@ static int ubd_add(int n, char **error_out) ...@@ -689,13 +689,23 @@ static int ubd_add(int n, char **error_out)
ubd_dev->size = ROUND_BLOCK(ubd_dev->size); ubd_dev->size = ROUND_BLOCK(ubd_dev->size);
err = ubd_disk_register(MAJOR_NR, ubd_dev->size, n, &ubd_gendisk[n]); err = -ENOMEM;
if(err) ubd_dev->queue = blk_init_queue(do_ubd_request, &ubd_dev->lock);
if (ubd_dev->queue == NULL) {
*error_out = "Failed to initialize device queue";
goto out; goto out;
}
ubd_dev->queue->queuedata = ubd_dev;
err = ubd_disk_register(MAJOR_NR, ubd_dev->size, n, &ubd_gendisk[n]);
if(err){
*error_out = "Failed to register device";
goto out_cleanup;
}
if(fake_major != MAJOR_NR) if(fake_major != MAJOR_NR)
ubd_disk_register(fake_major, ubd_dev->size, n, ubd_disk_register(fake_major, ubd_dev->size, n,
&fake_gendisk[n]); &fake_gendisk[n]);
/* perhaps this should also be under the "if (fake_major)" above */ /* perhaps this should also be under the "if (fake_major)" above */
/* using the fake_disk->disk_name and also the fakehd_set name */ /* 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,6 +715,10 @@ static int ubd_add(int n, char **error_out)
err = 0; err = 0;
out: out:
return err; return err;
out_cleanup:
blk_cleanup_queue(ubd_dev->queue);
goto out;
} }
static int ubd_config(char *str, char **error_out) static int ubd_config(char *str, char **error_out)
...@@ -816,6 +830,7 @@ static int ubd_remove(int n, char **error_out) ...@@ -816,6 +830,7 @@ static int ubd_remove(int n, char **error_out)
fake_gendisk[n] = NULL; fake_gendisk[n] = NULL;
} }
blk_cleanup_queue(ubd_dev->queue);
platform_device_unregister(&ubd_dev->pdev); platform_device_unregister(&ubd_dev->pdev);
*ubd_dev = ((struct ubd) DEFAULT_UBD); *ubd_dev = ((struct ubd) DEFAULT_UBD);
err = 0; err = 0;
...@@ -869,12 +884,6 @@ static int __init ubd_init(void) ...@@ -869,12 +884,6 @@ static int __init ubd_init(void)
if (register_blkdev(MAJOR_NR, "ubd")) if (register_blkdev(MAJOR_NR, "ubd"))
return -1; return -1;
ubd_queue = blk_init_queue(do_ubd_request, &ubd_io_lock);
if (!ubd_queue) {
unregister_blkdev(MAJOR_NR, "ubd");
return -1;
}
if (fake_major != MAJOR_NR) { if (fake_major != MAJOR_NR) {
char name[sizeof("ubd_nnn\0")]; char name[sizeof("ubd_nnn\0")];
...@@ -1020,7 +1029,7 @@ static void cowify_req(struct io_thread_req *req, unsigned long *bitmap, ...@@ -1020,7 +1029,7 @@ static void cowify_req(struct io_thread_req *req, unsigned long *bitmap,
req->bitmap_words, bitmap_len); req->bitmap_words, bitmap_len);
} }
/* Called with ubd_io_lock held */ /* Called with dev->lock held */
static int prepare_request(struct request *req, struct io_thread_req *io_req) static int prepare_request(struct request *req, struct io_thread_req *io_req)
{ {
struct gendisk *disk = req->rq_disk; struct gendisk *disk = req->rq_disk;
...@@ -1039,6 +1048,7 @@ static int prepare_request(struct request *req, struct io_thread_req *io_req) ...@@ -1039,6 +1048,7 @@ static int prepare_request(struct request *req, struct io_thread_req *io_req)
offset = ((__u64) req->sector) << 9; offset = ((__u64) req->sector) << 9;
len = req->current_nr_sectors << 9; len = req->current_nr_sectors << 9;
io_req->req = req;
io_req->fds[0] = (ubd_dev->cow.file != NULL) ? ubd_dev->cow.fd : ubd_dev->fd; io_req->fds[0] = (ubd_dev->cow.file != NULL) ? ubd_dev->cow.fd : ubd_dev->fd;
io_req->fds[1] = ubd_dev->fd; io_req->fds[1] = ubd_dev->fd;
io_req->cow_offset = -1; io_req->cow_offset = -1;
...@@ -1060,7 +1070,7 @@ static int prepare_request(struct request *req, struct io_thread_req *io_req) ...@@ -1060,7 +1070,7 @@ static int prepare_request(struct request *req, struct io_thread_req *io_req)
return(0); return(0);
} }
/* Called with ubd_io_lock held */ /* Called with dev->lock held */
static void do_ubd_request(request_queue_t *q) static void do_ubd_request(request_queue_t *q)
{ {
struct io_thread_req io_req; struct io_thread_req io_req;
......
Markdown is supported
0%
or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment