- 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); _