[Date Prev][Date Next][Thread Prev][Thread Next][Date Index][Thread Index]

[Xen-changelog] Support CFQ scheduling of guest block requests by creating



# HG changeset patch
# User kaf24@xxxxxxxxxxxxxxxxxxxx
# Node ID 6f62ad959f6b6d7fd98b2adfb3f07a9a15613e07
# Parent  c9772105fead52abf64213aa1eda6419871acf94
Support CFQ scheduling of guest block requests by creating
a kernel thread per blkif connection. General cleanup work
in blkback driver.

Signed-off-by: Gerd Knorr <kraxel@xxxxxxx>

diff -r c9772105fead -r 6f62ad959f6b 
linux-2.6-xen-sparse/drivers/xen/blkback/blkback.c
--- a/linux-2.6-xen-sparse/drivers/xen/blkback/blkback.c        Thu Dec  8 
15:04:41 2005
+++ b/linux-2.6-xen-sparse/drivers/xen/blkback/blkback.c        Thu Dec  8 
15:53:53 2005
@@ -12,6 +12,8 @@
  */
 
 #include <linux/spinlock.h>
+#include <linux/kthread.h>
+#include <linux/list.h>
 #include <asm-xen/balloon.h>
 #include <asm/hypervisor.h>
 #include "common.h"
@@ -21,26 +23,26 @@
  * pulled from a communication ring are quite likely to end up being part of
  * the same scatter/gather request at the disc.
  * 
- * ** TRY INCREASING 'MAX_PENDING_REQS' IF WRITE SPEEDS SEEM TOO LOW **
+ * ** TRY INCREASING 'blkif_reqs' IF WRITE SPEEDS SEEM TOO LOW **
+ * 
  * This will increase the chances of being able to write whole tracks.
  * 64 should be enough to keep us competitive with Linux.
  */
-#define MAX_PENDING_REQS 64
-#define BATCH_PER_DOMAIN 16
-
-static unsigned long mmap_vstart;
-#define MMAP_PAGES                                             \
-       (MAX_PENDING_REQS * BLKIF_MAX_SEGMENTS_PER_REQUEST)
-#ifdef __ia64__
-static void *pending_vaddrs[MMAP_PAGES];
-#define MMAP_VADDR(_idx, _i) \
-       (unsigned long)(pending_vaddrs[((_idx) * 
BLKIF_MAX_SEGMENTS_PER_REQUEST) + (_i)])
-#else
-#define MMAP_VADDR(_req,_seg)                                          \
-       (mmap_vstart +                                                  \
-        ((_req) * BLKIF_MAX_SEGMENTS_PER_REQUEST * PAGE_SIZE) +        \
-        ((_seg) * PAGE_SIZE))
-#endif
+static int blkif_reqs = 64;
+static int mmap_pages;
+
+static int __init set_blkif_reqs(char *str)
+{
+       get_option(&str, &blkif_reqs);
+       return 1;
+}
+__setup("blkif_reqs=", set_blkif_reqs);
+
+/* Run-time switchable: /sys/module/blkback/parameters/ */
+static unsigned int log_stats = 0;
+static unsigned int debug_lvl = 0;
+module_param(log_stats, int, 0644);
+module_param(debug_lvl, int, 0644);
 
 /*
  * Each outstanding request that we've passed to the lower device layers has a 
@@ -55,43 +57,33 @@
        atomic_t       pendcnt;
        unsigned short operation;
        int            status;
+       struct list_head free_list;
 } pending_req_t;
 
-/*
- * We can't allocate pending_req's in order, since they may complete out of 
- * order. We therefore maintain an allocation ring. This ring also indicates 
- * when enough work has been passed down -- at that point the allocation ring 
- * will be empty.
- */
-static pending_req_t pending_reqs[MAX_PENDING_REQS];
-static unsigned char pending_ring[MAX_PENDING_REQS];
-static spinlock_t pend_prod_lock = SPIN_LOCK_UNLOCKED;
-/* NB. We use a different index type to differentiate from shared blk rings. */
-typedef unsigned int PEND_RING_IDX;
-#define MASK_PEND_IDX(_i) ((_i)&(MAX_PENDING_REQS-1))
-static PEND_RING_IDX pending_prod, pending_cons;
-#define NR_PENDING_REQS (MAX_PENDING_REQS - pending_prod + pending_cons)
-
-static request_queue_t *plugged_queue;
-static inline void flush_plugged_queue(void)
-{
-       request_queue_t *q = plugged_queue;
-       if (q != NULL) {
-               if ( q->unplug_fn != NULL )
-                       q->unplug_fn(q);
-               blk_put_queue(q);
-               plugged_queue = NULL;
-       }
-}
-
-/* When using grant tables to map a frame for device access then the
- * handle returned must be used to unmap the frame. This is needed to
- * drop the ref count on the frame.
- */
-static grant_handle_t pending_grant_handles[MMAP_PAGES];
-#define pending_handle(_idx, _i) \
-    (pending_grant_handles[((_idx) * BLKIF_MAX_SEGMENTS_PER_REQUEST) + (_i)])
+static pending_req_t *pending_reqs;
+static struct list_head pending_free;
+static spinlock_t pending_free_lock = SPIN_LOCK_UNLOCKED;
+static DECLARE_WAIT_QUEUE_HEAD(pending_free_wq);
+
 #define BLKBACK_INVALID_HANDLE (~0)
+
+static unsigned long mmap_vstart;
+static unsigned long *pending_vaddrs;
+static grant_handle_t *pending_grant_handles;
+
+static inline int vaddr_pagenr(pending_req_t *req, int seg)
+{
+       return (req - pending_reqs) * BLKIF_MAX_SEGMENTS_PER_REQUEST + seg;
+}
+
+static inline unsigned long vaddr(pending_req_t *req, int seg)
+{
+       return pending_vaddrs[vaddr_pagenr(req, seg)];
+}
+
+#define pending_handle(_req, _seg) \
+       (pending_grant_handles[vaddr_pagenr(_req, _seg)])
+
 
 #ifdef CONFIG_XEN_BLKDEV_TAP_BE
 /*
@@ -105,26 +97,79 @@
 static inline domid_t ID_TO_DOM(unsigned long id) { return (id >> 16); }
 #endif
 
-static int do_block_io_op(blkif_t *blkif, int max_to_do);
-static void dispatch_rw_block_io(blkif_t *blkif, blkif_request_t *req);
+static int do_block_io_op(blkif_t *blkif);
+static void dispatch_rw_block_io(blkif_t *blkif,
+                                blkif_request_t *req,
+                                pending_req_t *pending_req);
 static void make_response(blkif_t *blkif, unsigned long id, 
                           unsigned short op, int st);
 
-static void fast_flush_area(int idx, int nr_pages)
+/******************************************************************
+ * misc small helpers
+ */
+static pending_req_t* alloc_req(void)
+{
+       pending_req_t *req = NULL;
+       unsigned long flags;
+
+       spin_lock_irqsave(&pending_free_lock, flags);
+       if (!list_empty(&pending_free)) {
+               req = list_entry(pending_free.next, pending_req_t, free_list);
+               list_del(&req->free_list);
+       }
+       spin_unlock_irqrestore(&pending_free_lock, flags);
+       return req;
+}
+
+static void free_req(pending_req_t *req)
+{
+       unsigned long flags;
+       int was_empty;
+
+       spin_lock_irqsave(&pending_free_lock, flags);
+       was_empty = list_empty(&pending_free);
+       list_add(&req->free_list, &pending_free);
+       spin_unlock_irqrestore(&pending_free_lock, flags);
+       if (was_empty)
+               wake_up(&pending_free_wq);
+}
+
+static void unplug_queue(blkif_t *blkif)
+{
+       if (blkif->plug == NULL)
+               return;
+       if (blkif->plug->unplug_fn)
+               blkif->plug->unplug_fn(blkif->plug);
+       blk_put_queue(blkif->plug);
+       blkif->plug = NULL;
+}
+
+static void plug_queue(blkif_t *blkif, struct bio *bio)
+{
+       request_queue_t *q = bdev_get_queue(bio->bi_bdev);
+
+       if (q == blkif->plug)
+               return;
+       unplug_queue(blkif);
+       blk_get_queue(q);
+       blkif->plug = q;
+}
+
+static void fast_flush_area(pending_req_t *req)
 {
        struct gnttab_unmap_grant_ref unmap[BLKIF_MAX_SEGMENTS_PER_REQUEST];
        unsigned int i, invcount = 0;
        grant_handle_t handle;
        int ret;
 
-       for (i = 0; i < nr_pages; i++) {
-               handle = pending_handle(idx, i);
+       for (i = 0; i < req->nr_pages; i++) {
+               handle = pending_handle(req, i);
                if (handle == BLKBACK_INVALID_HANDLE)
                        continue;
-               unmap[invcount].host_addr    = MMAP_VADDR(idx, i);
+               unmap[invcount].host_addr    = vaddr(req, i);
                unmap[invcount].dev_bus_addr = 0;
                unmap[invcount].handle       = handle;
-               pending_handle(idx, i) = BLKBACK_INVALID_HANDLE;
+               pending_handle(req, i) = BLKBACK_INVALID_HANDLE;
                invcount++;
        }
 
@@ -133,109 +178,83 @@
        BUG_ON(ret);
 }
 
-
-/******************************************************************
- * BLOCK-DEVICE SCHEDULER LIST MAINTENANCE
- */
-
-static struct list_head blkio_schedule_list;
-static spinlock_t blkio_schedule_list_lock;
-
-static int __on_blkdev_list(blkif_t *blkif)
-{
-       return blkif->blkdev_list.next != NULL;
-}
-
-static void remove_from_blkdev_list(blkif_t *blkif)
-{
-       unsigned long flags;
-
-       if (!__on_blkdev_list(blkif))
-               return;
-
-       spin_lock_irqsave(&blkio_schedule_list_lock, flags);
-       if (__on_blkdev_list(blkif)) {
-               list_del(&blkif->blkdev_list);
-               blkif->blkdev_list.next = NULL;
-               blkif_put(blkif);
-       }
-       spin_unlock_irqrestore(&blkio_schedule_list_lock, flags);
-}
-
-static void add_to_blkdev_list_tail(blkif_t *blkif)
-{
-       unsigned long flags;
-
-       if (__on_blkdev_list(blkif))
-               return;
-
-       spin_lock_irqsave(&blkio_schedule_list_lock, flags);
-       if (!__on_blkdev_list(blkif) && (blkif->status == CONNECTED)) {
-               list_add_tail(&blkif->blkdev_list, &blkio_schedule_list);
-               blkif_get(blkif);
-       }
-       spin_unlock_irqrestore(&blkio_schedule_list_lock, flags);
-}
-
-
 /******************************************************************
  * SCHEDULER FUNCTIONS
  */
 
-static DECLARE_WAIT_QUEUE_HEAD(blkio_schedule_wait);
-
-static int blkio_schedule(void *arg)
-{
-       DECLARE_WAITQUEUE(wq, current);
-
-       blkif_t          *blkif;
-       struct list_head *ent;
-
-       daemonize("xenblkd");
-
+static void print_stats(blkif_t *blkif)
+{
+       printk(KERN_DEBUG "%s: oo %3d  |  rd %4d  |  wr %4d\n",
+              current->comm, blkif->st_oo_req,
+              blkif->st_rd_req, blkif->st_wr_req);
+       blkif->st_print = jiffies + msecs_to_jiffies(10 * 1000);
+       blkif->st_rd_req = 0;
+       blkif->st_wr_req = 0;
+       blkif->st_oo_req = 0;
+}
+
+int blkif_schedule(void *arg)
+{
+       blkif_t          *blkif = arg;
+
+       blkif_get(blkif);
+       if (debug_lvl)
+               printk(KERN_DEBUG "%s: started\n", current->comm);
        for (;;) {
-               /* Wait for work to do. */
-               add_wait_queue(&blkio_schedule_wait, &wq);
-               set_current_state(TASK_INTERRUPTIBLE);
-               if ( (NR_PENDING_REQS == MAX_PENDING_REQS) || 
-                    list_empty(&blkio_schedule_list) )
-                       schedule();
-               __set_current_state(TASK_RUNNING);
-               remove_wait_queue(&blkio_schedule_wait, &wq);
-
-               /* Queue up a batch of requests. */
-               while ((NR_PENDING_REQS < MAX_PENDING_REQS) &&
-                      !list_empty(&blkio_schedule_list)) {
-                       ent = blkio_schedule_list.next;
-                       blkif = list_entry(ent, blkif_t, blkdev_list);
-                       blkif_get(blkif);
-                       remove_from_blkdev_list(blkif);
-                       if (do_block_io_op(blkif, BATCH_PER_DOMAIN))
-                               add_to_blkdev_list_tail(blkif);
-                       blkif_put(blkif);
-               }
-
-               /* Push the batch through to disc. */
-               flush_plugged_queue();
-       }
-}
-
-static void maybe_trigger_blkio_schedule(void)
-{
-       /*
-        * Needed so that two processes, which together make the following
-        * predicate true, don't both read stale values and evaluate the
-        * predicate incorrectly. Incredibly unlikely to stall the scheduler
-        * on x86, but...
-        */
-       smp_mb();
-
-       if ((NR_PENDING_REQS < (MAX_PENDING_REQS/2)) &&
-           !list_empty(&blkio_schedule_list))
-               wake_up(&blkio_schedule_wait);
-}
-
-
+               if (kthread_should_stop()) {
+                       /* asked to quit? */
+                       if (!atomic_read(&blkif->io_pending))
+                               break;
+                       if (debug_lvl)
+                               printk(KERN_DEBUG "%s: I/O pending, "
+                                      "delaying exit\n", current->comm);
+               }
+
+               if (!atomic_read(&blkif->io_pending)) {
+                       /* Wait for work to do. */
+                       wait_event_interruptible(
+                               blkif->wq,
+                               (atomic_read(&blkif->io_pending) ||
+                                kthread_should_stop()));
+               } else if (list_empty(&pending_free)) {
+                       /* Wait for pending_req becoming available. */
+                       wait_event_interruptible(
+                               pending_free_wq,
+                               !list_empty(&pending_free));
+               }
+
+               if (blkif->status != CONNECTED) {
+                       /* make sure we are connected */
+                       if (debug_lvl)
+                               printk(KERN_DEBUG "%s: not connected "
+                                      "(%d pending)\n",
+                                      current->comm,
+                                      atomic_read(&blkif->io_pending));
+                       wait_event_interruptible(
+                               blkif->wq,
+                               (blkif->status == CONNECTED ||
+                                kthread_should_stop()));
+                       continue;
+               }
+
+               /* Schedule I/O */
+               atomic_set(&blkif->io_pending, 0);
+               if (do_block_io_op(blkif))
+                       atomic_inc(&blkif->io_pending);
+               unplug_queue(blkif);
+
+               if (log_stats && time_after(jiffies, blkif->st_print))
+                       print_stats(blkif);
+       }
+
+       if (log_stats)
+               print_stats(blkif);
+       if (debug_lvl)
+               printk(KERN_DEBUG "%s: exiting\n", current->comm);
+       blkif->xenblkd = NULL;
+       blkif_put(blkif);
+       return 0;
+}
 
 /******************************************************************
  * COMPLETION CALLBACK -- Called as bh->b_end_io()
@@ -243,8 +262,6 @@
 
 static void __end_block_io_op(pending_req_t *pending_req, int uptodate)
 {
-       unsigned long flags;
-
        /* An error fails the entire request. */
        if (!uptodate) {
                DPRINTK("Buffer not up-to-date at end of operation\n");
@@ -252,15 +269,11 @@
        }
 
        if (atomic_dec_and_test(&pending_req->pendcnt)) {
-               int pending_idx = pending_req - pending_reqs;
-               fast_flush_area(pending_idx, pending_req->nr_pages);
+               fast_flush_area(pending_req);
                make_response(pending_req->blkif, pending_req->id,
                              pending_req->operation, pending_req->status);
                blkif_put(pending_req->blkif);
-               spin_lock_irqsave(&pend_prod_lock, flags);
-               pending_ring[MASK_PEND_IDX(pending_prod++)] = pending_idx;
-               spin_unlock_irqrestore(&pend_prod_lock, flags);
-               maybe_trigger_blkio_schedule();
+               free_req(pending_req);
        }
 }
 
@@ -281,8 +294,9 @@
 irqreturn_t blkif_be_int(int irq, void *dev_id, struct pt_regs *regs)
 {
        blkif_t *blkif = dev_id;
-       add_to_blkdev_list_tail(blkif);
-       maybe_trigger_blkio_schedule();
+
+       atomic_inc(&blkif->io_pending);
+       wake_up(&blkif->wq);
        return IRQ_HANDLED;
 }
 
@@ -292,10 +306,11 @@
  * DOWNWARD CALLS -- These interface with the block-device layer proper.
  */
 
-static int do_block_io_op(blkif_t *blkif, int max_to_do)
+static int do_block_io_op(blkif_t *blkif)
 {
        blkif_back_ring_t *blk_ring = &blkif->blk_ring;
        blkif_request_t *req;
+       pending_req_t *pending_req;
        RING_IDX rc, rp;
        int more_to_do = 0;
 
@@ -304,8 +319,10 @@
        rmb(); /* Ensure we see queued requests up to 'rp'. */
 
        while ((rc != rp) && !RING_REQUEST_CONS_OVERFLOW(blk_ring, rc)) {
-               if ((max_to_do-- == 0) ||
-                   (NR_PENDING_REQS == MAX_PENDING_REQS)) {
+
+               pending_req = alloc_req();
+               if (NULL == pending_req) {
+                       blkif->st_oo_req++;
                        more_to_do = 1;
                        break;
                }
@@ -315,28 +332,31 @@
 
                switch (req->operation) {
                case BLKIF_OP_READ:
+                       blkif->st_rd_req++;
+                       dispatch_rw_block_io(blkif, req, pending_req);
+                       break;
                case BLKIF_OP_WRITE:
-                       dispatch_rw_block_io(blkif, req);
+                       blkif->st_wr_req++;
+                       dispatch_rw_block_io(blkif, req, pending_req);
                        break;
-
                default:
                        DPRINTK("error: unknown block io operation [%d]\n",
                                req->operation);
                        make_response(blkif, req->id, req->operation,
                                      BLKIF_RSP_ERROR);
+                       free_req(pending_req);
                        break;
                }
        }
-
        return more_to_do;
 }
 
-static void dispatch_rw_block_io(blkif_t *blkif, blkif_request_t *req)
+static void dispatch_rw_block_io(blkif_t *blkif,
+                                blkif_request_t *req,
+                                pending_req_t *pending_req)
 {
        extern void ll_rw_block(int rw, int nr, struct buffer_head * bhs[]); 
        int operation = (req->operation == BLKIF_OP_WRITE) ? WRITE : READ;
-       int i, pending_idx = pending_ring[MASK_PEND_IDX(pending_cons)];
-       pending_req_t *pending_req;
        struct gnttab_map_grant_ref map[BLKIF_MAX_SEGMENTS_PER_REQUEST];
        struct phys_req preq;
        struct { 
@@ -344,32 +364,36 @@
        } seg[BLKIF_MAX_SEGMENTS_PER_REQUEST];
        unsigned int nseg;
        struct bio *bio = NULL, *biolist[BLKIF_MAX_SEGMENTS_PER_REQUEST];
-       int nbio = 0;
-       request_queue_t *q;
-       int ret, errors = 0;
+       int ret, i, nbio = 0;
 
        /* Check that number of segments is sane. */
        nseg = req->nr_segments;
        if (unlikely(nseg == 0) || 
            unlikely(nseg > BLKIF_MAX_SEGMENTS_PER_REQUEST)) {
                DPRINTK("Bad number of segments in request (%d)\n", nseg);
-               goto bad_descriptor;
+               goto fail_response;
        }
 
        preq.dev           = req->handle;
        preq.sector_number = req->sector_number;
        preq.nr_sects      = 0;
 
+       pending_req->blkif     = blkif;
+       pending_req->id        = req->id;
+       pending_req->operation = operation;
+       pending_req->status    = BLKIF_RSP_OKAY;
+       pending_req->nr_pages  = nseg;
+
        for (i = 0; i < nseg; i++) {
                seg[i].nsec = req->seg[i].last_sect -
                        req->seg[i].first_sect + 1;
 
                if ((req->seg[i].last_sect >= (PAGE_SIZE >> 9)) ||
                    (seg[i].nsec <= 0))
-                       goto bad_descriptor;
+                       goto fail_response;
                preq.nr_sects += seg[i].nsec;
 
-               map[i].host_addr = MMAP_VADDR(pending_idx, i);
+               map[i].host_addr = vaddr(pending_req, i);
                map[i].dom = blkif->domid;
                map[i].ref = req->seg[i].gref;
                map[i].flags = GNTMAP_host_map;
@@ -381,26 +405,22 @@
        BUG_ON(ret);
 
        for (i = 0; i < nseg; i++) {
-               if (likely(map[i].status == 0)) {
-                       pending_handle(pending_idx, i) = map[i].handle;
+               if (unlikely(map[i].status != 0)) {
+                       DPRINTK("invalid buffer -- could not remap it\n");
+                       goto fail_flush;
+               }
+
+               pending_handle(pending_req, i) = map[i].handle;
 #ifdef __ia64__
-                       MMAP_VADDR(pending_idx,i) = gnttab_map_vaddr(map[i]);
+               pending_vaddrs[vaddr_pagenr(req, seg)] =
+                       = gnttab_map_vaddr(map[i]);
 #else
-                       set_phys_to_machine(__pa(MMAP_VADDR(
-                               pending_idx, i)) >> PAGE_SHIFT,
-                               FOREIGN_FRAME(map[i].dev_bus_addr>>PAGE_SHIFT));
+               set_phys_to_machine(__pa(vaddr(
+                       pending_req, i)) >> PAGE_SHIFT,
+                       FOREIGN_FRAME(map[i].dev_bus_addr >> PAGE_SHIFT));
 #endif
-                       seg[i].buf = map[i].dev_bus_addr |
-                               (req->seg[i].first_sect << 9);
-               } else {
-                       errors++;
-               }
-       }
-
-       if (errors) {
-               DPRINTK("invalid buffer -- could not remap it\n");
-               fast_flush_area(pending_idx, nseg);
-               goto bad_descriptor;
+               seg[i].buf  = map[i].dev_bus_addr | 
+                       (req->seg[i].first_sect << 9);
        }
 
        if (vbd_translate(&preq, blkif, operation) != 0) {
@@ -408,37 +428,25 @@
                        operation == READ ? "read" : "write",
                        preq.sector_number,
                        preq.sector_number + preq.nr_sects, preq.dev); 
-               goto bad_descriptor;
-       }
-
-       pending_req = &pending_reqs[pending_idx];
-       pending_req->blkif     = blkif;
-       pending_req->id        = req->id;
-       pending_req->operation = operation;
-       pending_req->status    = BLKIF_RSP_OKAY;
-       pending_req->nr_pages  = nseg;
+               goto fail_flush;
+       }
 
        for (i = 0; i < nseg; i++) {
                if (((int)preq.sector_number|(int)seg[i].nsec) &
                    ((bdev_hardsect_size(preq.bdev) >> 9) - 1)) {
                        DPRINTK("Misaligned I/O request from domain %d",
                                blkif->domid);
-                       goto cleanup_and_fail;
+                       goto fail_put_bio;
                }
 
                while ((bio == NULL) ||
                       (bio_add_page(bio,
-                                    virt_to_page(MMAP_VADDR(pending_idx, i)),
+                                    virt_to_page(vaddr(pending_req, i)),
                                     seg[i].nsec << 9,
                                     seg[i].buf & ~PAGE_MASK) == 0)) {
                        bio = biolist[nbio++] = bio_alloc(GFP_KERNEL, nseg-i);
-                       if (unlikely(bio == NULL)) {
-                       cleanup_and_fail:
-                               for (i = 0; i < (nbio-1); i++)
-                                       bio_put(biolist[i]);
-                               fast_flush_area(pending_idx, nseg);
-                               goto bad_descriptor;
-                       }
+                       if (unlikely(bio == NULL))
+                               goto fail_put_bio;
                 
                        bio->bi_bdev    = preq.bdev;
                        bio->bi_private = pending_req;
@@ -449,14 +457,8 @@
                preq.sector_number += seg[i].nsec;
        }
 
-       if ((q = bdev_get_queue(bio->bi_bdev)) != plugged_queue) {
-               flush_plugged_queue();
-               blk_get_queue(q);
-               plugged_queue = q;
-       }
-
+       plug_queue(blkif, bio);
        atomic_set(&pending_req->pendcnt, nbio);
-       pending_cons++;
        blkif_get(blkif);
 
        for (i = 0; i < nbio; i++)
@@ -464,8 +466,14 @@
 
        return;
 
- bad_descriptor:
+ fail_put_bio:
+       for (i = 0; i < (nbio-1); i++)
+               bio_put(biolist[i]);
+ fail_flush:
+       fast_flush_area(pending_req);
+ fail_response:
        make_response(blkif, req->id, req->operation, BLKIF_RSP_ERROR);
+       free_req(pending_req);
 } 
 
 
@@ -481,6 +489,7 @@
        blkif_response_t *resp;
        unsigned long     flags;
        blkif_back_ring_t *blk_ring = &blkif->blk_ring;
+       int more_to_do = 0;
        int notify;
 
        spin_lock_irqsave(&blkif->blk_ring_lock, flags);
@@ -499,76 +508,69 @@
                 * notifications if requests are already in flight (lower
                 * overheads and promotes batching).
                 */
-               int more_to_do;
                RING_FINAL_CHECK_FOR_REQUESTS(blk_ring, more_to_do);
-               if (more_to_do) {
-                       add_to_blkdev_list_tail(blkif);
-                       maybe_trigger_blkio_schedule();
-               }
-       }
-       else if (!__on_blkdev_list(blkif)
-                && RING_HAS_UNCONSUMED_REQUESTS(blk_ring)) {
-               /* Keep pulling requests as they become available... */
-               add_to_blkdev_list_tail(blkif);
-               maybe_trigger_blkio_schedule();
-       }
-
+
+       } else if (RING_HAS_UNCONSUMED_REQUESTS(blk_ring)) {
+               more_to_do = 1;
+
+       }
        spin_unlock_irqrestore(&blkif->blk_ring_lock, flags);
 
+       if (more_to_do) {
+               atomic_inc(&blkif->io_pending);
+               wake_up(&blkif->wq);
+       }
        if (notify)
                notify_remote_via_irq(blkif->irq);
 }
 
-void blkif_deschedule(blkif_t *blkif)
-{
-       remove_from_blkdev_list(blkif);
-}
-
 static int __init blkif_init(void)
 {
+       struct page *page;
        int i;
-       struct page *page;
-       int ret;
-
-       for (i = 0; i < MMAP_PAGES; i++)
-               pending_grant_handles[i] = BLKBACK_INVALID_HANDLE;
 
        if (xen_init() < 0)
                return -ENODEV;
 
+       mmap_pages            = blkif_reqs * BLKIF_MAX_SEGMENTS_PER_REQUEST;
+       pending_reqs          = kmalloc(sizeof(pending_reqs[0]) *
+                                       blkif_reqs, GFP_KERNEL);
+       pending_grant_handles = kmalloc(sizeof(pending_grant_handles[0]) *
+                                       mmap_pages, GFP_KERNEL);
+       pending_vaddrs        = kmalloc(sizeof(pending_vaddrs[0]) *
+                                       mmap_pages, GFP_KERNEL);
+       if (!pending_reqs || !pending_grant_handles || !pending_vaddrs) {
+               printk("%s: out of memory\n", __FUNCTION__);
+               return -1;
+       }
+
        blkif_interface_init();
-
+       
 #ifdef __ia64__
-    {
-       extern unsigned long alloc_empty_foreign_map_page_range(unsigned long 
pages);
-       int i;
-
-       mmap_vstart =  alloc_empty_foreign_map_page_range(MMAP_PAGES);
-       printk("Allocated mmap_vstart: 0x%lx\n", mmap_vstart);
-       for(i = 0; i < MMAP_PAGES; i++)
-           pending_vaddrs[i] = mmap_vstart + (i << PAGE_SHIFT);
-       BUG_ON(mmap_vstart == NULL);
-    }
-#else
-       page = balloon_alloc_empty_page_range(MMAP_PAGES);
+       extern unsigned long alloc_empty_foreign_map_page_range(
+               unsigned long pages);
+       mmap_vstart = (unsigned long)
+               alloc_empty_foreign_map_page_range(mmap_pages);
+#else /* ! ia64 */
+       page = balloon_alloc_empty_page_range(mmap_pages);
        BUG_ON(page == NULL);
        mmap_vstart = (unsigned long)pfn_to_kaddr(page_to_pfn(page));
 #endif
-
-       pending_cons = 0;
-       pending_prod = MAX_PENDING_REQS;
+       printk("%s: reqs=%d, pages=%d, mmap_vstart=0x%lx\n",
+              __FUNCTION__, blkif_reqs, mmap_pages, mmap_vstart);
+       BUG_ON(mmap_vstart == 0);
+       for (i = 0; i < mmap_pages; i++) {
+               pending_vaddrs[i] = mmap_vstart + (i << PAGE_SHIFT);
+               pending_grant_handles[i] = BLKBACK_INVALID_HANDLE;
+       }
+
        memset(pending_reqs, 0, sizeof(pending_reqs));
-       for (i = 0; i < MAX_PENDING_REQS; i++)
-               pending_ring[i] = i;
+       INIT_LIST_HEAD(&pending_free);
+
+       for (i = 0; i < blkif_reqs; i++)
+               list_add_tail(&pending_reqs[i].free_list, &pending_free);
     
-       spin_lock_init(&blkio_schedule_list_lock);
-       INIT_LIST_HEAD(&blkio_schedule_list);
-
-       ret = kernel_thread(blkio_schedule, NULL, CLONE_FS | CLONE_FILES);
-       BUG_ON(ret < 0);
-
        blkif_xenbus_init();
-
        return 0;
 }
 
diff -r c9772105fead -r 6f62ad959f6b 
linux-2.6-xen-sparse/drivers/xen/blkback/common.h
--- a/linux-2.6-xen-sparse/drivers/xen/blkback/common.h Thu Dec  8 15:04:41 2005
+++ b/linux-2.6-xen-sparse/drivers/xen/blkback/common.h Thu Dec  8 15:53:53 2005
@@ -60,9 +60,19 @@
        /* Is this a blktap frontend */
        unsigned int     is_blktap;
 #endif
-       struct list_head blkdev_list;
        spinlock_t       blk_ring_lock;
        atomic_t         refcnt;
+
+       wait_queue_head_t   wq;
+       struct task_struct  *xenblkd;
+       atomic_t            io_pending;
+       request_queue_t     *plug;
+
+       /* statistics */
+       unsigned long       st_print;
+       int                 st_rd_req;
+       int                 st_wr_req;
+       int                 st_oo_req;
 
        struct work_struct free_work;
 
@@ -101,11 +111,10 @@
 
 void blkif_interface_init(void);
 
-void blkif_deschedule(blkif_t *blkif);
-
 void blkif_xenbus_init(void);
 
 irqreturn_t blkif_be_int(int irq, void *dev_id, struct pt_regs *regs);
+int blkif_schedule(void *arg);
 
 void update_blkif_status(blkif_t *blkif); 
 
diff -r c9772105fead -r 6f62ad959f6b 
linux-2.6-xen-sparse/drivers/xen/blkback/interface.c
--- a/linux-2.6-xen-sparse/drivers/xen/blkback/interface.c      Thu Dec  8 
15:04:41 2005
+++ b/linux-2.6-xen-sparse/drivers/xen/blkback/interface.c      Thu Dec  8 
15:53:53 2005
@@ -24,6 +24,8 @@
        blkif->status = DISCONNECTED;
        spin_lock_init(&blkif->blk_ring_lock);
        atomic_set(&blkif->refcnt, 1);
+       init_waitqueue_head(&blkif->wq);
+       blkif->st_print = jiffies;
 
        return blkif;
 }
diff -r c9772105fead -r 6f62ad959f6b 
linux-2.6-xen-sparse/drivers/xen/blkback/xenbus.c
--- a/linux-2.6-xen-sparse/drivers/xen/blkback/xenbus.c Thu Dec  8 15:04:41 2005
+++ b/linux-2.6-xen-sparse/drivers/xen/blkback/xenbus.c Thu Dec  8 15:53:53 2005
@@ -20,6 +20,7 @@
 
 #include <stdarg.h>
 #include <linux/module.h>
+#include <linux/kthread.h>
 #include <asm-xen/xenbus.h>
 #include "common.h"
 
@@ -92,6 +93,8 @@
        }
        if (be->blkif) {
                be->blkif->status = DISCONNECTED; 
+               if (be->blkif->xenblkd)
+                       kthread_stop(be->blkif->xenblkd);
                blkif_put(be->blkif);
                be->blkif = NULL;
        }
@@ -217,6 +220,17 @@
                        be->major = 0;
                        be->minor = 0;
                        xenbus_dev_fatal(dev, err, "creating vbd structure");
+                       return;
+               }
+
+               be->blkif->xenblkd = kthread_run(blkif_schedule, be->blkif,
+                                                "xvd %d %02x:%02x",
+                                                be->blkif->domid,
+                                                be->major, be->minor);
+               if (IS_ERR(be->blkif->xenblkd)) {
+                       err = PTR_ERR(be->blkif->xenblkd);
+                       be->blkif->xenblkd = NULL;
+                       xenbus_dev_error(dev, err, "start xenblkd");
                        return;
                }
 

_______________________________________________
Xen-changelog mailing list
Xen-changelog@xxxxxxxxxxxxxxxxxxx
http://lists.xensource.com/xen-changelog


 


Rackspace

Lists.xenproject.org is hosted with RackSpace, monitoring our
servers 24x7x365 and backed by RackSpace's Fanatical Support®.