bioqdisksort - fixes to avoid starvation
authorMatthew Dillon <dillon@apollo.backplane.com>
Sat, 8 Aug 2009 22:07:40 +0000 (15:07 -0700)
committerMatthew Dillon <dillon@apollo.backplane.com>
Sat, 8 Aug 2009 22:07:40 +0000 (15:07 -0700)
Long chains of pipelined write I/O were being sorted in front of other
requests.  Due to the pipelining these other requests would wind up
getting starved virtually permanently.

Prevent starvation by forcing one out of every 16 BIOs to be ordered.

This fixes issues with HAMMER which tends to have more of an absolute
ordering of meta data verses data then UFS.

sys/kern/subr_disk.c
sys/sys/buf.h
sys/sys/buf2.h

index d256b86..2481381 100644 (file)
@@ -160,7 +160,7 @@ disk_probe_slice(struct disk *dp, cdev_t dev, int slice, int reprobe)
        const char *msg;
        cdev_t ndev;
        int sno;
-       unsigned long i;
+       u_int i;
 
        sno = slice ? slice - 1 : 0;
 
@@ -898,6 +898,18 @@ bioqdisksort(struct bio_queue_head *bioq, struct bio *bio)
                bioq_insert_tail(bioq, bio);
                return;
        }
+
+       /*
+        * Avoid permanent request starvation by forcing the request to
+        * be ordered every 16 requests.  Without this long sequential
+        * write pipelines can prevent requests later in the queue from
+        * getting serviced for many seconds.
+        */
+       if ((++bioq->order_count & 15) == 0) {
+               bioq_insert_tail_order(bioq, bio, 1);
+               return;
+       }
+
        if (bioq->insert_point != NULL) {
                /*
                 * A certain portion of the list is
index 44039b6..1a6668d 100644 (file)
@@ -330,6 +330,7 @@ extern char *buf_wmesg;                     /* Default buffer lock message */
 struct bio_queue_head {
        TAILQ_HEAD(bio_queue, bio) queue;
        off_t   last_offset;
+       int     order_count;
        struct  bio *insert_point;
        struct  bio *switch_point;
 };
index cfc0487..5cf56e6 100644 (file)
@@ -149,20 +149,29 @@ bioq_init(struct bio_queue_head *head)
 {
        TAILQ_INIT(&head->queue);
        head->last_offset = 0;
+       head->order_count = 0;
        head->insert_point = NULL;
        head->switch_point = NULL;
 }
 
 static __inline void
-bioq_insert_tail(struct bio_queue_head *head, struct bio *bio)
+bioq_insert_tail_order(struct bio_queue_head *head, struct bio *bio, int order)
 {
-       if ((bio->bio_buf->b_flags & B_ORDERED) != 0) {
+       if (order) {
                head->insert_point = bio;
                head->switch_point = NULL;
+               head->order_count = 0;
        }
        TAILQ_INSERT_TAIL(&head->queue, bio, bio_act);
 }
 
+static __inline void
+bioq_insert_tail(struct bio_queue_head *head, struct bio *bio)
+{
+       bioq_insert_tail_order(head, bio, bio->bio_buf->b_flags & B_ORDERED);
+}
+
+
 static __inline void
 bioq_remove(struct bio_queue_head *head, struct bio *bio)
 {