From: Nick Piggin <piggin@cyberone.com.au>

I have tested this on my disks and cdroms, but they don't represent
what all drivers might do. I have asked Jarkko Lehti with his dvd writing
problem to try it...



 drivers/block/as-iosched.c |  101 +++++++++++++++++++++++++++++++--------------
 1 files changed, 70 insertions(+), 31 deletions(-)

diff -puN drivers/block/as-iosched.c~as-request-poisoning drivers/block/as-iosched.c
--- 25/drivers/block/as-iosched.c~as-request-poisoning	2003-11-09 16:39:52.000000000 -0800
+++ 25-akpm/drivers/block/as-iosched.c	2003-11-09 16:39:52.000000000 -0800
@@ -136,6 +136,10 @@ enum arq_state {
 				   scheduler */
 	AS_RQ_DISPATCHED,	/* On the dispatch list. It belongs to the
 				   driver now */
+	AS_RQ_PRESCHED,		/* Debug poisoning for requests being used */
+	AS_RQ_REMOVED,
+	AS_RQ_MERGED,
+	AS_RQ_POSTSCHED,	/* when they shouldn't be */
 };
 
 struct as_rq {
@@ -893,12 +897,22 @@ static void as_completed_request(request
 {
 	struct as_data *ad = q->elevator.elevator_data;
 	struct as_rq *arq = RQ_DATA(rq);
-	struct as_io_context *aic;
 
 	WARN_ON(!list_empty(&rq->queuelist));
 
-	if (unlikely(arq->state != AS_RQ_DISPATCHED))
-		return;
+	if (arq->state == AS_RQ_PRESCHED) {
+		WARN_ON(arq->io_context);
+		goto out;
+	}
+
+	if (arq->state == AS_RQ_MERGED)
+		goto out_ioc;
+
+	if (arq->state != AS_RQ_REMOVED) {
+		printk("arq->state %d\n", arq->state);
+		WARN_ON(1);
+		goto out;
+	}
 
 	if (!blk_fs_request(rq))
 		return;
@@ -925,10 +939,7 @@ static void as_completed_request(request
 		ad->new_batch = 0;
 	}
 
-	if (!arq->io_context)
-		return;
-
-	if (ad->io_context == arq->io_context) {
+	if (ad->io_context == arq->io_context && ad->io_context) {
 		ad->antic_start = jiffies;
 		ad->ioc_finished = 1;
 		if (ad->antic_status == ANTIC_WAIT_REQ) {
@@ -940,18 +951,23 @@ static void as_completed_request(request
 		}
 	}
 
-	aic = arq->io_context->aic;
-	if (!aic)
-		return;
+out_ioc:
+	if (!arq->io_context)
+		goto out;
 
-	spin_lock(&aic->lock);
 	if (arq->is_sync == REQ_SYNC) {
-		set_bit(AS_TASK_IORUNNING, &aic->state);
-		aic->last_end_request = jiffies;
+		struct as_io_context *aic = arq->io_context->aic;
+		if (aic) {
+			spin_lock(&aic->lock);
+			set_bit(AS_TASK_IORUNNING, &aic->state);
+			aic->last_end_request = jiffies;
+			spin_unlock(&aic->lock);
+		}
 	}
-	spin_unlock(&aic->lock);
 
 	put_io_context(arq->io_context);
+out:
+	arq->state = AS_RQ_POSTSCHED;
 }
 
 /*
@@ -1020,14 +1036,14 @@ static void as_remove_request(request_qu
 	struct as_rq *arq = RQ_DATA(rq);
 
 	if (unlikely(arq->state == AS_RQ_NEW))
-		return;
-
-	if (!arq) {
-		WARN_ON(1);
-		return;
-	}
+		goto out;
 
 	if (ON_RB(&arq->rb_node)) {
+		if (arq->state != AS_RQ_QUEUED) {
+			printk("arq->state %d\n", arq->state);
+			WARN_ON(1);
+			goto out;
+		}
 		/*
 		 * We'll lose the aliased request(s) here. I don't think this
 		 * will ever happen, but if it does, hopefully someone will
@@ -1035,8 +1051,16 @@ static void as_remove_request(request_qu
 		 */
 		WARN_ON(!list_empty(&rq->queuelist));
 		as_remove_queued_request(q, rq);
-	} else
+	} else {
+		if (arq->state != AS_RQ_DISPATCHED) {
+			printk("arq->state %d\n", arq->state);
+			WARN_ON(1);
+			goto out;
+		}
 		as_remove_dispatched_request(q, rq);
+	}
+out:
+	arq->state = AS_RQ_REMOVED;
 }
 
 /*
@@ -1214,9 +1238,9 @@ static int as_dispatch_request(struct as
 			 */
 			goto dispatch_writes;
 
- 		if (ad->batch_data_dir == REQ_ASYNC) {
+		if (ad->batch_data_dir == REQ_ASYNC) {
 			WARN_ON(ad->new_batch);
- 			ad->changed_batch = 1;
+			ad->changed_batch = 1;
 		}
 		ad->batch_data_dir = REQ_SYNC;
 		arq = list_entry_fifo(ad->fifo_list[ad->batch_data_dir].next);
@@ -1232,8 +1256,8 @@ static int as_dispatch_request(struct as
 dispatch_writes:
 		BUG_ON(RB_EMPTY(&ad->sort_list[REQ_ASYNC]));
 
- 		if (ad->batch_data_dir == REQ_SYNC) {
- 			ad->changed_batch = 1;
+		if (ad->batch_data_dir == REQ_SYNC) {
+			ad->changed_batch = 1;
 
 			/*
 			 * new_batch might be 1 when the queue runs out of
@@ -1276,8 +1300,6 @@ fifo_expired:
 			ad->new_batch = 1;
 
 		ad->changed_batch = 0;
-
-//		arq->request->flags |= REQ_SOFTBARRIER;
 	}
 
 	/*
@@ -1402,6 +1424,11 @@ static void as_requeue_request(request_q
 	struct as_rq *arq = RQ_DATA(rq);
 
 	if (arq) {
+		if (arq->state != AS_RQ_REMOVED) {
+			printk("arq->state %d\n", arq->state);
+			WARN_ON(1);
+		}
+
 		arq->state = AS_RQ_DISPATCHED;
 		if (arq->io_context && arq->io_context->aic)
 			atomic_inc(&arq->io_context->aic->nr_dispatched);
@@ -1421,12 +1448,18 @@ as_insert_request(request_queue_t *q, st
 	struct as_data *ad = q->elevator.elevator_data;
 	struct as_rq *arq = RQ_DATA(rq);
 
-#if 0
+	if (arq) {
+		if (arq->state != AS_RQ_PRESCHED) {
+			printk("arq->state: %d\n", arq->state);
+			WARN_ON(1);
+		}
+		arq->state = AS_RQ_NEW;
+	}
+
 	/* barriers must flush the reorder queue */
 	if (unlikely(rq->flags & (REQ_SOFTBARRIER | REQ_HARDBARRIER)
 			&& where == ELEVATOR_INSERT_SORT))
 		where = ELEVATOR_INSERT_BACK;
-#endif
 
 	switch (where) {
 		case ELEVATOR_INSERT_BACK:
@@ -1661,7 +1694,8 @@ as_merged_requests(request_queue_t *q, s
 	 * kill knowledge of next, this one is a goner
 	 */
 	as_remove_queued_request(q, next);
-	put_io_context(anext->io_context);
+
+	anext->state = AS_RQ_MERGED;
 }
 
 /*
@@ -1694,6 +1728,11 @@ static void as_put_request(request_queue
 		return;
 	}
 
+	if (arq->state != AS_RQ_POSTSCHED) {
+		printk("arq->state %d\n", arq->state);
+		WARN_ON(1);
+	}
+
 	mempool_free(arq, ad->arq_pool);
 	rq->elevator_private = NULL;
 }
@@ -1707,7 +1746,7 @@ static int as_set_request(request_queue_
 		memset(arq, 0, sizeof(*arq));
 		RB_CLEAR(&arq->rb_node);
 		arq->request = rq;
-		arq->state = AS_RQ_NEW;
+		arq->state = AS_RQ_PRESCHED;
 		arq->io_context = NULL;
 		INIT_LIST_HEAD(&arq->hash);
 		arq->on_hash = 0;

_