Return-Path: Received: (majordomo@vger.kernel.org) by vger.kernel.org via listexpand id S964976AbXAWTec (ORCPT ); Tue, 23 Jan 2007 14:34:32 -0500 Received: (majordomo@vger.kernel.org) by vger.kernel.org id S964851AbXAWTeZ (ORCPT ); Tue, 23 Jan 2007 14:34:25 -0500 Received: from saraswathi.solana.com ([198.99.130.12]:33079 "EHLO saraswathi.solana.com" rhost-flags-OK-OK-OK-OK) by vger.kernel.org with ESMTP id S933141AbXAWTeX (ORCPT ); Tue, 23 Jan 2007 14:34:23 -0500 Message-Id: <200701231927.l0NJRdFx005338@ccure.user-mode-linux.org> X-Mailer: exmh version 2.7.2 01/07/2005 with nmh-1.0.4 To: akpm@osdl.org cc: linux-kernel@vger.kernel.org, user-mode-linux-devel@lists.sourceforge.net Subject: [PATCH 1/7] UML - Add per-device queues and locks to ubd driver Mime-Version: 1.0 Content-Type: text/plain; charset=us-ascii Date: Tue, 23 Jan 2007 14:27:39 -0500 From: Jeff Dike Sender: linux-kernel-owner@vger.kernel.org X-Mailing-List: linux-kernel@vger.kernel.org Content-Length: 6424 Lines: 216 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 -- arch/um/drivers/ubd_kern.c | 70 +++++++++++++++++++++++++-------------------- 1 file changed, 40 insertions(+), 30 deletions(-) Index: linux-2.6.18-mm/arch/um/drivers/ubd_kern.c =================================================================== --- linux-2.6.18-mm.orig/arch/um/drivers/ubd_kern.c 2007-01-17 12:46:25.000000000 +1100 +++ linux-2.6.18-mm/arch/um/drivers/ubd_kern.c 2007-01-17 12:46:28.000000000 +1100 @@ -56,6 +56,7 @@ enum ubd_req { UBD_READ, UBD_WRITE }; struct io_thread_req { + struct request *req; enum ubd_req op; int fds[2]; unsigned long offsets[2]; @@ -106,10 +107,6 @@ static inline void ubd_set_bit(__u64 bit #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); /* XXX - this made sense in 2.4 days, now it's only used as a boolean, and @@ -132,9 +129,6 @@ static const struct block_device_operati .getgeo = ubd_getgeo, }; -/* Protected by the queue_lock */ -static request_queue_t *ubd_queue; - /* Protected by ubd_lock */ static int fake_major = MAJOR_NR; @@ -178,6 +172,8 @@ struct ubd { unsigned no_cow:1; struct cow cow; struct platform_device pdev; + struct request_queue *queue; + spinlock_t lock; }; #define DEFAULT_COW { \ @@ -198,6 +194,7 @@ struct ubd { .no_cow = 0, \ .shared = 0, \ .cow = DEFAULT_COW, \ + .lock = SPIN_LOCK_UNLOCKED, \ } struct ubd ubd_devs[MAX_DEV] = { [ 0 ... MAX_DEV - 1 ] = DEFAULT_UBD }; @@ -503,17 +500,20 @@ static void __ubd_finish(struct request * spin_lock_irq()/spin_lock_irqsave() */ 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); - spin_unlock(&ubd_io_lock); + spin_unlock(&dev->lock); } /* 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) { struct io_thread_req req; - struct request *rq = elv_next_request(ubd_queue); + struct request *rq; + struct ubd *dev; int n; do_ubd = 0; @@ -522,17 +522,17 @@ static void ubd_handler(void) if(n != sizeof(req)){ printk(KERN_ERR "Pid %d - spurious interrupt in ubd_handler, " "err = %d\n", os_getpid(), -n); - spin_lock(&ubd_io_lock); - end_request(rq, 0); - spin_unlock(&ubd_io_lock); return; } + rq = req.req; + dev = rq->rq_disk->private_data; + ubd_finish(rq, req.error); - reactivate_fd(thread_fd, UBD_IRQ); - spin_lock(&ubd_io_lock); - do_ubd_request(ubd_queue); - spin_unlock(&ubd_io_lock); + reactivate_fd(thread_fd, UBD_IRQ); + spin_lock(&dev->lock); + do_ubd_request(dev->queue); + spin_unlock(&dev->lock); } static irqreturn_t ubd_intr(int irq, void *dev) @@ -663,7 +663,7 @@ static int ubd_disk_register(int major, } disk->private_data = &ubd_devs[unit]; - disk->queue = ubd_queue; + disk->queue = ubd_devs[unit].queue; add_disk(disk); *disk_out = disk; @@ -688,13 +688,23 @@ static int ubd_add(int n, char **error_o ubd_dev->size = ROUND_BLOCK(ubd_dev->size); - err = ubd_disk_register(MAJOR_NR, ubd_dev->size, n, &ubd_gendisk[n]); - if(err) + err = -ENOMEM; + 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; + } + 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) 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 */ /* using the fake_disk->disk_name and also the fakehd_set name */ @@ -704,6 +714,10 @@ static int ubd_add(int n, char **error_o err = 0; out: return err; + +out_cleanup: + blk_cleanup_queue(ubd_dev->queue); + goto out; } static int ubd_config(char *str, char **error_out) @@ -815,6 +829,7 @@ static int ubd_remove(int n, char **erro fake_gendisk[n] = NULL; } + blk_cleanup_queue(ubd_dev->queue); platform_device_unregister(&ubd_dev->pdev); *ubd_dev = ((struct ubd) DEFAULT_UBD); err = 0; @@ -868,12 +883,6 @@ static int __init ubd_init(void) if (register_blkdev(MAJOR_NR, "ubd")) 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) { char name[sizeof("ubd_nnn\0")]; @@ -1019,7 +1028,7 @@ static void cowify_req(struct io_thread_ 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) { struct gendisk *disk = req->rq_disk; @@ -1038,6 +1047,7 @@ static int prepare_request(struct reques offset = ((__u64) req->sector) << 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[1] = ubd_dev->fd; io_req->cow_offset = -1; @@ -1059,7 +1069,7 @@ static int prepare_request(struct reques return(0); } -/* Called with ubd_io_lock held */ +/* Called with dev->lock held */ static void do_ubd_request(request_queue_t *q) { struct io_thread_req io_req; - To unsubscribe from this list: send the line "unsubscribe linux-kernel" in the body of a message to majordomo@vger.kernel.org More majordomo info at http://vger.kernel.org/majordomo-info.html Please read the FAQ at http://www.tux.org/lkml/