Jens, Some storage devices have a mode where they require a special command be sent inorder to perform failover. IBM's fastt is one of these devices we are trying to add support for using the dm-multipath framework. The problem is that dm works at the bio level and we need to send down something like a block pc or special request. So from dm multipath we could have a thread and do a blk_execute_rq, or if we had some sort of end_request function similar to the bio's and bh's endio function we could send the failover command asynchronously. The attached patch adds an end_request fn to the request structure for this purpose. Maybe the fact that I have to ask for such a change should indidcate that I am doing something brain dead, in which case please be gentle in your review of my patch :) -- Mike Christie mikenc@xxxxxxxxxx
diff -aurp linux-2.6.6/drivers/block/ll_rw_blk.c linux-2.6.6-work/drivers/block/ll_rw_blk.c --- linux-2.6.6/drivers/block/ll_rw_blk.c 2004-05-09 19:32:00.000000000 -0700 +++ linux-2.6.6-work/drivers/block/ll_rw_blk.c 2004-05-22 15:26:37.000000000 -0700 @@ -1599,6 +1599,7 @@ static struct request *get_request(reque rq->ref_count = 1; rq->q = q; rq->rl = rl; + rq->end_request = NULL; rq->waiting = NULL; rq->special = NULL; rq->data_len = 0; @@ -1842,6 +1843,21 @@ int blk_rq_unmap_user(struct request *rq EXPORT_SYMBOL(blk_rq_unmap_user); /** + * blk_end_sync_rq - executes a completion event on a request + * when it has completed. + * @rq: request to complete. + */ +void blk_end_sync_rq(struct request *rq) +{ + struct completion *waiting = rq->waiting; + + rq->waiting = NULL; + complete(waiting); +} + +EXPORT_SYMBOL(blk_end_sync_rq); + +/** * blk_execute_rq - insert a request into queue for execution * @q: queue to insert the request in * @bd_disk: matching gendisk @@ -1874,6 +1890,7 @@ int blk_execute_rq(request_queue_t *q, s rq->flags |= REQ_NOMERGE; rq->waiting = &wait; + rq->end_request = blk_end_sync_rq; elv_add_request(q, rq, ELEVATOR_INSERT_BACK, 1); generic_unplug_device(q); wait_for_completion(&wait); @@ -2731,7 +2748,7 @@ EXPORT_SYMBOL(end_that_request_chunk); void end_that_request_last(struct request *req) { struct gendisk *disk = req->rq_disk; - struct completion *waiting = req->waiting; + end_request_fn *end_fn = req->end_request; if (unlikely(laptop_mode) && blk_fs_request(req)) laptop_io_completion(); @@ -2752,9 +2769,16 @@ void end_that_request_last(struct reques disk->in_flight--; } __blk_put_request(req->q, req); - /* Do this LAST! The structure may be freed immediately afterwards */ - if (waiting) - complete(waiting); + + /* + * If you are allocating reqs from the block layer you + * should get a handle to the req and release it after + * your end_request_fn is run. + */ + if (end_fn) { + req->end_request = NULL; + end_fn(req); + } } EXPORT_SYMBOL(end_that_request_last); diff -aurp linux-2.6.6/drivers/block/paride/pd.c linux-2.6.6-work/drivers/block/paride/pd.c --- linux-2.6.6/drivers/block/paride/pd.c 2004-05-09 19:33:13.000000000 -0700 +++ linux-2.6.6-work/drivers/block/paride/pd.c 2004-05-22 15:17:05.000000000 -0700 @@ -743,6 +743,7 @@ static int pd_special_command(struct pd_ rq.rq_disk = disk->gd; rq.ref_count = 1; rq.waiting = &wait; + rq.end_request = blk_end_sync_rq; blk_insert_request(disk->gd->queue, &rq, 0, func, 0); wait_for_completion(&wait); rq.waiting = NULL; diff -aurp linux-2.6.6/drivers/ide/ide-cd.c linux-2.6.6-work/drivers/ide/ide-cd.c --- linux-2.6.6/drivers/ide/ide-cd.c 2004-05-09 19:32:29.000000000 -0700 +++ linux-2.6.6-work/drivers/ide/ide-cd.c 2004-05-22 15:17:05.000000000 -0700 @@ -555,6 +555,8 @@ static void cdrom_queue_request_sense(id rq->flags = REQ_SENSE; rq->waiting = wait; + if (wait) + rq->end_request = blk_end_sync_rq; /* NOTE! Save the failed command in "rq->buffer" */ rq->buffer = (void *) failed_command; @@ -719,6 +721,7 @@ static int cdrom_decode_status(ide_drive if ((stat & ERR_STAT) != 0) { wait = rq->waiting; rq->waiting = NULL; + rq->end_request = NULL; if ((rq->flags & REQ_BLOCK_PC) != 0) { cdrom_queue_request_sense(drive, wait, rq->sense, rq); diff -aurp linux-2.6.6/drivers/ide/ide-io.c linux-2.6.6-work/drivers/ide/ide-io.c --- linux-2.6.6/drivers/ide/ide-io.c 2004-05-09 19:33:13.000000000 -0700 +++ linux-2.6.6-work/drivers/ide/ide-io.c 2004-05-22 15:17:05.000000000 -0700 @@ -1372,6 +1372,7 @@ int ide_do_drive_cmd (ide_drive_t *drive if (must_wait) { rq->ref_count++; rq->waiting = &wait; + rq->end_request = blk_end_sync_rq; } spin_lock_irqsave(&ide_lock, flags); diff -aurp linux-2.6.6/drivers/ide/ide-tape.c linux-2.6.6-work/drivers/ide/ide-tape.c --- linux-2.6.6/drivers/ide/ide-tape.c 2004-05-09 19:32:27.000000000 -0700 +++ linux-2.6.6-work/drivers/ide/ide-tape.c 2004-05-22 15:17:06.000000000 -0700 @@ -2798,6 +2798,7 @@ static void idetape_wait_for_request (id } #endif /* IDETAPE_DEBUG_BUGS */ rq->waiting = &wait; + rq->end_request = blk_end_sync_rq; spin_unlock_irq(&tape->spinlock); wait_for_completion(&wait); /* The stage and its struct request have been deallocated */ diff -aurp linux-2.6.6/include/linux/blkdev.h linux-2.6.6-work/include/linux/blkdev.h --- linux-2.6.6/include/linux/blkdev.h 2004-05-09 19:32:26.000000000 -0700 +++ linux-2.6.6-work/include/linux/blkdev.h 2004-05-22 15:17:06.000000000 -0700 @@ -17,6 +17,7 @@ #include <asm/scatterlist.h> +struct request; struct request_queue; typedef struct request_queue request_queue_t; struct elevator_s; @@ -84,6 +85,8 @@ struct request_list { #define BLK_MAX_CDB 16 +typedef void end_request_fn(struct request *rq); + /* * try to put the fields that are referenced together in the same cacheline */ @@ -144,6 +147,7 @@ struct request { struct completion *waiting; void *special; + end_request_fn *end_request; /* * when request is used as a packet command carrier @@ -503,6 +507,7 @@ extern int blk_register_queue(struct gen extern void blk_unregister_queue(struct gendisk *disk); extern void register_disk(struct gendisk *dev); extern void generic_make_request(struct bio *bio); +extern void blk_end_sync_rq(struct request *rq); extern void blk_put_request(struct request *); extern void blk_attempt_remerge(request_queue_t *, struct request *); extern void __blk_attempt_remerge(request_queue_t *, struct request *);