From: Jens Axboe <axboe@suse.de>

This is needed for several things, one in-tree user which I will introduce
after this patch.

This adds a ->end_io callback to struct request, so it can be used with
async io of any sort.  Right now users have to wait for completion in a
blocking manner.  In the next iteration, ->waiting can be folded into
->end_io_data since it is just a special case of that use.

From: Peter Osterlund <petero2@telia.com>

The problem is that the add-struct-request-end_io-callback patch forgot to
update pktcdvd.c.  This patch fixes it.

Signed-off-by: Jens Axboe <axboe@suse.de>
Signed-off-by: Peter Osterlund <petero2@telia.com>
Signed-off-by: Andrew Morton <akpm@osdl.org>
---

 25-akpm/drivers/block/ll_rw_blk.c |   36 ++++++++++++++++++++++++++++--------
 25-akpm/drivers/block/paride/pd.c |    1 +
 25-akpm/drivers/block/pktcdvd.c   |    1 +
 25-akpm/drivers/ide/ide-io.c      |    1 +
 25-akpm/drivers/ide/ide-tape.c    |    1 +
 25-akpm/include/linux/blkdev.h    |   11 ++++++++++-
 6 files changed, 42 insertions(+), 9 deletions(-)

diff -puN drivers/block/ll_rw_blk.c~add-struct-request-end_io-callback drivers/block/ll_rw_blk.c
--- 25/drivers/block/ll_rw_blk.c~add-struct-request-end_io-callback	2005-02-23 02:11:18.000000000 -0800
+++ 25-akpm/drivers/block/ll_rw_blk.c	2005-02-23 02:11:18.000000000 -0800
@@ -1753,6 +1753,8 @@ rq_starved:
 	rq->data_len = 0;
 	rq->data = NULL;
 	rq->sense = NULL;
+	rq->end_io = NULL;
+	rq->end_io_data = NULL;
 
 out:
 	put_io_context(ioc);
@@ -2018,8 +2020,8 @@ int blk_execute_rq(request_queue_t *q, s
 	}
 
 	rq->flags |= REQ_NOMERGE;
-	if (!rq->waiting)
-		rq->waiting = &wait;
+	rq->waiting = &wait;
+	rq->end_io = blk_end_sync_rq;
 	elv_add_request(q, rq, ELEVATOR_INSERT_BACK, 1);
 	generic_unplug_device(q);
 	wait_for_completion(rq->waiting);
@@ -2171,7 +2173,7 @@ void disk_round_stats(struct gendisk *di
 /*
  * queue lock must be held
  */
-void __blk_put_request(request_queue_t *q, struct request *req)
+static void __blk_put_request(request_queue_t *q, struct request *req)
 {
 	struct request_list *rl = req->rl;
 
@@ -2219,6 +2221,25 @@ void blk_put_request(struct request *req
 EXPORT_SYMBOL(blk_put_request);
 
 /**
+ * blk_end_sync_rq - executes a completion event on a request
+ * @rq: request to complete
+ */
+void blk_end_sync_rq(struct request *rq)
+{
+	struct completion *waiting = rq->waiting;
+
+	rq->waiting = NULL;
+	__blk_put_request(rq->q, rq);
+
+	/*
+	 * complete last, if this is a stack request the process (and thus
+	 * the rq pointer) could be invalid right after this complete()
+	 */
+	complete(waiting);
+}
+EXPORT_SYMBOL(blk_end_sync_rq);
+
+/**
  * blk_congestion_wait - wait for a queue to become uncongested
  * @rw: READ or WRITE
  * @timeout: timeout in jiffies
@@ -2978,7 +2999,6 @@ 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;
 
 	if (unlikely(laptop_mode) && blk_fs_request(req))
 		laptop_io_completion();
@@ -2998,10 +3018,10 @@ void end_that_request_last(struct reques
 		disk_round_stats(disk);
 		disk->in_flight--;
 	}
-	__blk_put_request(req->q, req);
-	/* Do this LAST! The structure may be freed immediately afterwards */
-	if (waiting)
-		complete(waiting);
+	if (req->end_io)
+		req->end_io(req);
+	else
+		__blk_put_request(req->q, req);
 }
 
 EXPORT_SYMBOL(end_that_request_last);
diff -puN drivers/block/paride/pd.c~add-struct-request-end_io-callback drivers/block/paride/pd.c
--- 25/drivers/block/paride/pd.c~add-struct-request-end_io-callback	2005-02-23 02:11:18.000000000 -0800
+++ 25-akpm/drivers/block/paride/pd.c	2005-02-23 02:11:18.000000000 -0800
@@ -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_io = blk_end_sync_rq;
 	blk_insert_request(disk->gd->queue, &rq, 0, func, 0);
 	wait_for_completion(&wait);
 	rq.waiting = NULL;
diff -puN drivers/ide/ide-io.c~add-struct-request-end_io-callback drivers/ide/ide-io.c
--- 25/drivers/ide/ide-io.c~add-struct-request-end_io-callback	2005-02-23 02:11:18.000000000 -0800
+++ 25-akpm/drivers/ide/ide-io.c	2005-02-23 02:11:18.000000000 -0800
@@ -1835,6 +1835,7 @@ int ide_do_drive_cmd (ide_drive_t *drive
 	if (must_wait) {
 		rq->ref_count++;
 		rq->waiting = &wait;
+		rq->end_io = blk_end_sync_rq;
 	}
 
 	spin_lock_irqsave(&ide_lock, flags);
diff -puN drivers/ide/ide-tape.c~add-struct-request-end_io-callback drivers/ide/ide-tape.c
--- 25/drivers/ide/ide-tape.c~add-struct-request-end_io-callback	2005-02-23 02:11:18.000000000 -0800
+++ 25-akpm/drivers/ide/ide-tape.c	2005-02-23 02:11:18.000000000 -0800
@@ -2766,6 +2766,7 @@ static void idetape_wait_for_request (id
 	}
 #endif /* IDETAPE_DEBUG_BUGS */
 	rq->waiting = &wait;
+	rq->end_io = blk_end_sync_rq;
 	spin_unlock_irq(&tape->spinlock);
 	wait_for_completion(&wait);
 	/* The stage and its struct request have been deallocated */
diff -puN include/linux/blkdev.h~add-struct-request-end_io-callback include/linux/blkdev.h
--- 25/include/linux/blkdev.h~add-struct-request-end_io-callback	2005-02-23 02:11:18.000000000 -0800
+++ 25-akpm/include/linux/blkdev.h	2005-02-23 02:11:18.000000000 -0800
@@ -93,6 +93,9 @@ struct io_context *get_io_context(int gf
 void copy_io_context(struct io_context **pdst, struct io_context **psrc);
 void swap_io_context(struct io_context **ioc1, struct io_context **ioc2);
 
+struct request;
+typedef void (rq_end_io_fn)(struct request *);
+
 struct request_list {
 	int count[2];
 	int starved[2];
@@ -176,6 +179,12 @@ struct request {
 	 * For Power Management requests
 	 */
 	struct request_pm_state *pm;
+
+	/*
+	 * completion callback. end_io_data should be folded in with waiting
+	 */
+	rq_end_io_fn *end_io;
+	void *end_io_data;
 };
 
 /*
@@ -509,10 +518,10 @@ extern void blk_unregister_queue(struct 
 extern void register_disk(struct gendisk *dev);
 extern void generic_make_request(struct bio *bio);
 extern void blk_put_request(struct request *);
+extern void blk_end_sync_rq(struct request *rq);
 extern void blk_attempt_remerge(request_queue_t *, struct request *);
 extern void __blk_attempt_remerge(request_queue_t *, struct request *);
 extern struct request *blk_get_request(request_queue_t *, int, int);
-extern void blk_put_request(struct request *);
 extern void blk_insert_request(request_queue_t *, struct request *, int, void *, int);
 extern void blk_requeue_request(request_queue_t *, struct request *);
 extern void blk_plug_device(request_queue_t *);
diff -puN drivers/block/pktcdvd.c~add-struct-request-end_io-callback drivers/block/pktcdvd.c
--- 25/drivers/block/pktcdvd.c~add-struct-request-end_io-callback	2005-02-23 02:11:20.000000000 -0800
+++ 25-akpm/drivers/block/pktcdvd.c	2005-02-23 02:11:20.000000000 -0800
@@ -375,6 +375,7 @@ static int pkt_generic_packet(struct pkt
 	rq->ref_count++;
 	rq->flags |= REQ_NOMERGE;
 	rq->waiting = &wait;
+	rq->end_io = blk_end_sync_rq;
 	elv_add_request(q, rq, ELEVATOR_INSERT_BACK, 1);
 	generic_unplug_device(q);
 	wait_for_completion(&wait);
_