- pass gfp_flags to get_io_context(): not all callers are forced to use
  GFP_ATOMIC().

- fix locking in get_io_context(): bump the refcount whilein the exclusive
  region.

- don't go oops in get_io_context() if the kmalloc failed.

- in as_get_io_context(): fail the whole thing if we were unable to
  allocate the AS-specific part.

- as_remove_queued_request() cleanup


 drivers/block/as-iosched.c |   50 +++++++++++++++++++++------------------------
 drivers/block/ll_rw_blk.c  |    9 ++++----
 include/linux/blkdev.h     |    2 -
 3 files changed, 30 insertions(+), 31 deletions(-)

diff -puN drivers/block/ll_rw_blk.c~get_io_context-fix drivers/block/ll_rw_blk.c
--- 25/drivers/block/ll_rw_blk.c~get_io_context-fix	2003-06-16 00:22:41.000000000 -0700
+++ 25-akpm/drivers/block/ll_rw_blk.c	2003-06-16 00:22:41.000000000 -0700
@@ -1350,7 +1350,7 @@ static struct request *get_request(reque
 {
 	struct request *rq = NULL;
 	struct request_list *rl = &q->rq;
-	struct io_context *ioc = get_io_context();
+	struct io_context *ioc = get_io_context(gfp_mask);
 
 	spin_lock_irq(q->queue_lock);
 	if (rl->count[rw]+1 >= q->nr_requests) {
@@ -1437,7 +1437,7 @@ static struct request *get_request_wait(
 			struct io_context *ioc;
 
 			io_schedule();
-			ioc = get_io_context();
+			ioc = get_io_context(GFP_NOIO);
 			ioc_set_batching(ioc);
 			put_io_context(ioc);
 		}
@@ -2474,7 +2474,7 @@ void exit_io_context(void)
  * But weird things happen, so we disable local interrupts to ensure exclusive
  * access to *current.
  */
-struct io_context *get_io_context(void)
+struct io_context *get_io_context(int gfp_flags)
 {
 	struct task_struct *tsk = current;
 	unsigned long flags;
@@ -2494,8 +2494,9 @@ struct io_context *get_io_context(void)
 			tsk->io_context = ret;
 		}
 	}
+	if (ret)
+		atomic_inc(&ret->refcount);
 	local_irq_restore(flags);
-	atomic_inc(&ret->refcount);
 	return ret;
 }
 
diff -puN drivers/block/as-iosched.c~get_io_context-fix drivers/block/as-iosched.c
--- 25/drivers/block/as-iosched.c~get_io_context-fix	2003-06-16 00:22:46.000000000 -0700
+++ 25-akpm/drivers/block/as-iosched.c	2003-06-16 00:33:36.000000000 -0700
@@ -219,13 +219,17 @@ static struct as_io_context *alloc_as_io
  */
 static struct io_context *as_get_io_context(void)
 {
-	struct io_context *ioc = get_io_context();
-	if (ioc && !ioc->aic)
+	struct io_context *ioc = get_io_context(GFP_ATOMIC);
+	if (ioc && !ioc->aic) {
 		ioc->aic = alloc_as_io_context();
+		if (!ioc->aic) {
+			put_io_context(ioc);
+			ioc = NULL;
+		}
+	}
 	return ioc;
 }
 
-
 /*
  * the back merge hash support functions
  */
@@ -971,32 +975,26 @@ static void as_completed_request(request
 static void as_remove_queued_request(request_queue_t *q, struct request *rq)
 {
 	struct as_rq *arq = RQ_DATA(rq);
+	const int data_dir = arq->is_sync;
+	struct as_data *ad = q->elevator.elevator_data;
 
-	if (!arq)
-		BUG();
-	else {
-		const int data_dir = arq->is_sync;
-		struct as_data *ad = q->elevator.elevator_data;
-
-		WARN_ON(arq->state != AS_RQ_QUEUED);
-
-		if (arq->io_context && arq->io_context->aic) {
-			BUG_ON(!atomic_read(&arq->io_context->aic->nr_queued));
-			atomic_dec(&arq->io_context->aic->nr_queued);
-		}
+	WARN_ON(arq->state != AS_RQ_QUEUED);
 
-		/*
-		 * Update the "next_arq" cache if we are about to remove its
-		 * entry
-		 */
-		if (ad->next_arq[data_dir] == arq)
-			ad->next_arq[data_dir] = as_find_next_arq(ad, arq);
-		
-		list_del_init(&arq->fifo);
-		as_remove_merge_hints(q, arq);
-		as_del_arq_rb(ad, arq);
+	if (arq->io_context && arq->io_context->aic) {
+		BUG_ON(!atomic_read(&arq->io_context->aic->nr_queued));
+		atomic_dec(&arq->io_context->aic->nr_queued);
 	}
 
+	/*
+	 * Update the "next_arq" cache if we are about to remove its
+	 * entry
+	 */
+	if (ad->next_arq[data_dir] == arq)
+		ad->next_arq[data_dir] = as_find_next_arq(ad, arq);
+		
+	list_del_init(&arq->fifo);
+	as_remove_merge_hints(q, arq);
+	as_del_arq_rb(ad, arq);
 }
 
 /*
@@ -1292,7 +1290,7 @@ static void as_add_request(struct as_dat
 
 	arq->io_context = as_get_io_context();
 
-	if (arq->io_context && arq->io_context->aic) {
+	if (arq->io_context) {
 		atomic_inc(&arq->io_context->aic->nr_queued);
 		as_update_iohist(arq->io_context->aic, arq->request);
 	}
diff -puN include/linux/blkdev.h~get_io_context-fix include/linux/blkdev.h
--- 25/include/linux/blkdev.h~get_io_context-fix	2003-06-16 00:24:51.000000000 -0700
+++ 25-akpm/include/linux/blkdev.h	2003-06-16 00:25:03.000000000 -0700
@@ -70,7 +70,7 @@ struct io_context {
 
 void put_io_context(struct io_context *ioc);
 void exit_io_context(void);
-struct io_context *get_io_context(void);
+struct io_context *get_io_context(int gfp_flags);
 void copy_io_context(struct io_context **pdst, struct io_context **psrc);
 void swap_io_context(struct io_context **ioc1, struct io_context **ioc2);
 

_