From: Boaz Harrosh <bharrosh@panasas.com>
To: Boaz Harrosh <bharrosh@panasas.com>,
Jens Axboe <jens.axboe@oracle.com>,
James Bottomley <James.Bottomley@SteelEye.com>,
Andrew Morton <akpm@osdl.org>,
Mike Christie <michaelc@cs.wisc.edu>,
Christoph Hellwig <hch@infradead.org>
Cc: linux-scsi <linux-scsi@vger.kernel.org>,
Linux-ide <linux-ide@vger.kernel.org>,
Benny Halevy <bhalevy@panasas.com>,
osd-dev@open-osd.org
Subject: [PATCH 4/4] bidi support: bidirectional request
Date: Sun, 15 Apr 2007 20:33:28 +0300 [thread overview]
Message-ID: <462261E8.5090005@panasas.com> (raw)
In-Reply-To: <46225E18.7070404@panasas.com>
- Instantiate another request_io_part in struct request for bidi_read.
- Define & Implement new API for accessing bidi parts.
- API to Build bidi requests and map to sglists.
- Define new end_that_request_block() function to end a complete request.
Signed-off-by: Boaz Harrosh <bharrosh@panasas.com>
Signed-off-by: Benny Halevy <bhalevy@panasas.com>
---
block/elevator.c | 7 +--
block/ll_rw_blk.c | 120 ++++++++++++++++++++++++++++++++++++++++-------
drivers/scsi/scsi_lib.c | 2 +-
include/linux/blkdev.h | 56 +++++++++++++++++++++-
4 files changed, 160 insertions(+), 25 deletions(-)
diff --git a/block/elevator.c b/block/elevator.c
index 237f15c..e39ef57 100644
--- a/block/elevator.c
+++ b/block/elevator.c
@@ -757,14 +757,9 @@ struct request *elv_next_request(request_queue_t *q)
rq = NULL;
break;
} else if (ret == BLKPREP_KILL) {
- int nr_bytes = rq_uni(rq)->hard_nr_sectors << 9;
-
- if (!nr_bytes)
- nr_bytes = rq_uni(rq)->data_len;
-
blkdev_dequeue_request(rq);
rq->cmd_flags |= REQ_QUIET;
- end_that_request_chunk(rq, 0, nr_bytes);
+ end_that_request_block(rq, 0);
end_that_request_last(rq, 0);
} else {
printk(KERN_ERR "%s: bad return=%d\n", __FUNCTION__,
diff --git a/block/ll_rw_blk.c b/block/ll_rw_blk.c
index c8ed8a9..21fdbc2 100644
--- a/block/ll_rw_blk.c
+++ b/block/ll_rw_blk.c
@@ -261,6 +261,7 @@ static void rq_init(request_queue_t *q, struct request *rq)
rq->end_io_data = NULL;
rq->completion_data = NULL;
rq_init_io_part(&rq->uni);
+ rq_init_io_part(&rq->bidi_read);
}
/**
@@ -1312,14 +1313,16 @@ static int blk_hw_contig_segment(request_queue_t *q, struct bio *bio,
}
/*
- * map a request to scatterlist, return number of sg entries setup. Caller
- * must make sure sg can hold rq->nr_phys_segments entries
+ * map a request_io_part to scatterlist, return number of sg entries setup.
+ * Caller must make sure sg can hold rq_io(rq, dir)->nr_phys_segments entries
*/
-int blk_rq_map_sg(request_queue_t *q, struct request *rq, struct scatterlist *sg)
+int blk_rq_map_sg_bidi(request_queue_t *q, struct request *rq,
+ struct scatterlist *sg, enum dma_data_direction dir)
{
struct bio_vec *bvec, *bvprv;
struct bio *bio;
int nsegs, i, cluster;
+ struct request_io_part* req_io = rq_io(rq, dir);
nsegs = 0;
cluster = q->queue_flags & (1 << QUEUE_FLAG_CLUSTER);
@@ -1328,7 +1331,7 @@ int blk_rq_map_sg(request_queue_t *q, struct request *rq, struct scatterlist *sg
* for each bio in rq
*/
bvprv = NULL;
- rq_for_each_bio(bio, rq) {
+ for (bio = req_io->bio; bio; bio = bio->bi_next) {
/*
* for each segment in bio
*/
@@ -1360,7 +1363,17 @@ new_segment:
return nsegs;
}
+EXPORT_SYMBOL(blk_rq_map_sg_bidi);
+/*
+ * map a request to scatterlist, return number of sg entries setup. Caller
+ * must make sure sg can hold rq->nr_phys_segments entries
+ */
+int blk_rq_map_sg(request_queue_t *q, struct request *rq,
+ struct scatterlist *sg)
+{
+ return blk_rq_map_sg_bidi(q, rq, sg, rq->data_dir);
+}
EXPORT_SYMBOL(blk_rq_map_sg);
/*
@@ -1415,11 +1428,12 @@ static inline int ll_new_hw_segment(request_queue_t *q,
return 1;
}
-int ll_back_merge_fn(request_queue_t *q, struct request *req, struct bio *bio)
+int ll_back_merge_fn(request_queue_t *q, struct request *req, struct bio *bio,
+ enum dma_data_direction dir)
{
unsigned short max_sectors;
int len;
- struct request_io_part* req_io = rq_uni(req);
+ struct request_io_part* req_io = rq_io(req, dir);
if (unlikely(blk_pc_request(req)))
max_sectors = q->max_hw_sectors;
@@ -2404,7 +2418,7 @@ static int __blk_rq_map_user(request_queue_t *q, struct request *rq,
req_io = rq_uni(rq);
if (!req_io->bio)
blk_rq_bio_prep(q, rq, bio);
- else if (!ll_back_merge_fn(q, rq, bio)) {
+ else if (!ll_back_merge_fn(q, rq, bio, rq->data_dir)) {
ret = -EINVAL;
goto unmap_bio;
} else {
@@ -2574,15 +2588,18 @@ int blk_rq_unmap_user(struct bio *bio)
EXPORT_SYMBOL(blk_rq_unmap_user);
/**
- * blk_rq_map_kern - map kernel data to a request, for REQ_BLOCK_PC usage
+ * blk_rq_map_kern_bidi - maps kernel data to a request_io_part, for BIDI usage
* @q: request queue where request should be inserted
* @rq: request to fill
* @kbuf: the kernel buffer
* @len: length of user data
* @gfp_mask: memory allocation flags
+ * @dir: if it is a BIDIRECTIONAL request than DMA_TO_DEVICE to prepare
+ * the bidi_write side or DMA_FROM_DEVICE to prepare the bidi_read
+ * side, else it should be same as req->data_dir
*/
-int blk_rq_map_kern(request_queue_t *q, struct request *rq, void *kbuf,
- unsigned int len, gfp_t gfp_mask)
+int blk_rq_map_kern_bidi(request_queue_t *q, struct request *rq, void *kbuf,
+ unsigned int len, gfp_t gfp_mask, enum dma_data_direction dir)
{
struct bio *bio;
@@ -2595,14 +2612,29 @@ int blk_rq_map_kern(request_queue_t *q, struct request *rq, void *kbuf,
if (IS_ERR(bio))
return PTR_ERR(bio);
- if (dma_write_dir(rq->data_dir))
+ if (dma_write_dir(dir))
bio->bi_rw |= (1 << BIO_RW);
- blk_rq_bio_prep(q, rq, bio);
+ blk_rq_bio_prep_bidi(q, rq, bio ,dir);
rq->buffer = rq->data = NULL;
return 0;
}
+EXPORT_SYMBOL(blk_rq_map_kern_bidi);
+
+/**
+ * blk_rq_map_kern - map kernel data to a request, for REQ_BLOCK_PC usage
+ * @q: request queue where request should be inserted
+ * @rq: request to fill
+ * @kbuf: the kernel buffer
+ * @len: length of user data
+ * @gfp_mask: memory allocation flags
+ */
+int blk_rq_map_kern(request_queue_t *q, struct request *rq, void *kbuf,
+ unsigned int len, gfp_t gfp_mask)
+{
+ return blk_rq_map_kern_bidi( q, rq, kbuf, len, gfp_mask, rq->data_dir);
+}
EXPORT_SYMBOL(blk_rq_map_kern);
/**
@@ -2988,7 +3020,7 @@ static int __make_request(request_queue_t *q, struct bio *bio)
case ELEVATOR_BACK_MERGE:
BUG_ON(!rq_mergeable(req));
- if (!ll_back_merge_fn(q, req, bio))
+ if (!ll_back_merge_fn(q, req, bio, req->data_dir))
break;
blk_add_trace_bio(q, bio, BLK_TA_BACKMERGE);
@@ -3375,11 +3407,11 @@ static void blk_recalc_rq_sectors(struct request *rq, int nsect)
}
static int __end_that_request_first(struct request *req, int uptodate,
- int nr_bytes)
+ int nr_bytes, enum dma_data_direction dir)
{
int total_bytes, bio_nbytes, error, next_idx = 0;
struct bio *bio;
- struct request_io_part* req_io = rq_uni(req);
+ struct request_io_part* req_io = rq_io(req, dir);
blk_add_trace_rq(req->q, req, BLK_TA_COMPLETE);
@@ -3469,6 +3501,8 @@ static int __end_that_request_first(struct request *req, int uptodate,
if (!req_io->bio)
return 0;
+ WARN_ON(rq_bidi_dir(req));
+
/*
* if the request wasn't completed, update state
*/
@@ -3501,7 +3535,7 @@ static int __end_that_request_first(struct request *req, int uptodate,
**/
int end_that_request_first(struct request *req, int uptodate, int nr_sectors)
{
- return __end_that_request_first(req, uptodate, nr_sectors << 9);
+ return end_that_request_chunk(req, uptodate, nr_sectors << 9);
}
EXPORT_SYMBOL(end_that_request_first);
@@ -3523,11 +3557,55 @@ EXPORT_SYMBOL(end_that_request_first);
**/
int end_that_request_chunk(struct request *req, int uptodate, int nr_bytes)
{
- return __end_that_request_first(req, uptodate, nr_bytes);
+ WARN_ON_BIDI_FLAG(req);
+ WARN_ON(!rq_uni_dir(req));
+ return __end_that_request_first(req, uptodate, nr_bytes,
+ rq_uni_dir(req) ? rq_dma_dir(req) : DMA_TO_DEVICE);
}
EXPORT_SYMBOL(end_that_request_chunk);
+static void __end_req_io_block(struct request_io_part *req_io, int error)
+{
+ struct bio *next, *bio = req_io->bio;
+ req_io->bio = NULL;
+
+ for (; bio; bio = next) {
+ next = bio->bi_next;
+ bio_endio(bio, bio->bi_size, error);
+ }
+}
+
+/**
+ * end_that_request_block - end ALL I/O on a request in one "shloop",
+ * including the bidi part.
+ * @req: the request being processed
+ * @uptodate: 1 for success, 0 for I/O error, < 0 for specific error
+ *
+ * Description:
+ * Ends ALL I/O on @req, both read/write or bidi. frees all bio resources.
+ **/
+void end_that_request_block(struct request *req, int uptodate)
+{
+ if (blk_pc_request(req)) {
+ int error = 0;
+ if (end_io_error(uptodate))
+ error = !uptodate ? -EIO : uptodate;
+ blk_add_trace_rq(req->q, req, BLK_TA_COMPLETE);
+
+ __end_req_io_block(&req->uni, error);
+ if (rq_bidi_dir(req))
+ __end_req_io_block(&req->bidi_read, 0);
+ } else { /* needs elevator bookeeping */
+ int nr_bytes = req->uni.hard_nr_sectors << 9;
+ if (!nr_bytes)
+ nr_bytes = req->uni.data_len;
+ end_that_request_chunk(req, uptodate, nr_bytes);
+ }
+}
+
+EXPORT_SYMBOL(end_that_request_block);
+
/*
* splice the completion data to a local structure and hand off to
* process_completion_queue() to complete the requests
@@ -3656,6 +3734,14 @@ void end_request(struct request *req, int uptodate)
EXPORT_SYMBOL(end_request);
+void blk_rq_bio_prep_bidi(request_queue_t *q, struct request *rq,
+ struct bio *bio, enum dma_data_direction dir)
+{
+ init_req_io_part_from_bio(q, rq_io(rq, dir), bio);
+ rq->buffer = NULL;
+}
+EXPORT_SYMBOL(blk_rq_bio_prep_bidi);
+
void blk_rq_bio_prep(request_queue_t *q, struct request *rq, struct bio *bio)
{
rq->data_dir = bio_data_dir(bio) ? DMA_TO_DEVICE : DMA_FROM_DEVICE;
diff --git a/drivers/scsi/scsi_lib.c b/drivers/scsi/scsi_lib.c
index 5863827..42aefd4 100644
--- a/drivers/scsi/scsi_lib.c
+++ b/drivers/scsi/scsi_lib.c
@@ -268,7 +268,7 @@ static int scsi_merge_bio(struct request *rq, struct bio *bio)
if (!req_io->bio)
blk_rq_bio_prep(q, rq, bio);
- else if (!ll_back_merge_fn(q, rq, bio))
+ else if (!ll_back_merge_fn(q, rq, bio, rq_dma_dir(rq)))
return -EINVAL;
else {
req_io->biotail->bi_next = bio;
diff --git a/include/linux/blkdev.h b/include/linux/blkdev.h
index 645d24b..16a02ee 100644
--- a/include/linux/blkdev.h
+++ b/include/linux/blkdev.h
@@ -322,6 +322,7 @@ struct request {
void *end_io_data;
struct request_io_part uni;
+ struct request_io_part bidi_read;
};
/*
@@ -600,6 +601,34 @@ static inline struct request_io_part* rq_uni(struct request* req)
return &req->uni;
}
+static inline struct request_io_part* rq_out(struct request* req)
+{
+ WARN_ON_BIDI_FLAG(req);
+ return &req->uni;
+}
+
+static inline struct request_io_part* rq_in(struct request* req)
+{
+ WARN_ON_BIDI_FLAG(req);
+ if (likely(rq_dma_dir(req) != DMA_BIDIRECTIONAL))
+ return &req->uni;
+
+ if (likely(req->cmd_flags & REQ_BIDI))
+ return &req->bidi_read;
+
+ return &req->uni;
+}
+
+static inline struct request_io_part* rq_io(struct request* req,
+ enum dma_data_direction dir)
+{
+ if (dir == DMA_FROM_DEVICE)
+ return rq_in(req);
+
+ WARN_ON( (dir != DMA_TO_DEVICE) && (dir != DMA_NONE) );
+ return &req->uni;
+}
+
/*
* We regard a request as sync, if it's a READ or a SYNC write.
*/
@@ -700,7 +729,8 @@ extern int sg_scsi_ioctl(struct file *, struct request_queue *,
/*
* Temporary export, until SCSI gets fixed up.
*/
-extern int ll_back_merge_fn(request_queue_t *, struct request *, struct bio *);
+extern int ll_back_merge_fn(request_queue_t *, struct request *, struct bio *,
+ enum dma_data_direction);
/*
* A queue has just exitted congestion. Note this in the global counter of
@@ -771,6 +801,15 @@ extern void end_request(struct request *req, int uptodate);
extern void blk_complete_request(struct request *);
/*
+ * end_request_block will complete and free all bio resources held
+ * by the request in one call. User will still need to call
+ * end_that_request_last(..).
+ * It is the only one that can deal with BIDI.
+ * can be called for parial bidi allocation and cleanup.
+ */
+extern void end_that_request_block(struct request *req, int uptodate);
+
+/*
* end_that_request_first/chunk() takes an uptodate argument. we account
* any value <= as an io error. 0 means -EIO for compatability reasons,
* any other < 0 value is the direct error type. An uptodate value of
@@ -849,6 +888,21 @@ static inline struct request *blk_map_queue_find_tag(struct blk_queue_tag *bqt,
extern void blk_rq_bio_prep(request_queue_t *, struct request *, struct bio *);
extern int blkdev_issue_flush(struct block_device *, sector_t *);
+/* BIDI API
+ * build a request. for bidi requests must be called twice to map/prepare
+ * the data-in and data-out buffers, one at a time according to
+ * the given dma_data_direction.
+ */
+extern void blk_rq_bio_prep_bidi(request_queue_t *, struct request *,
+ struct bio *, enum dma_data_direction);
+extern int blk_rq_map_kern_bidi(request_queue_t *, struct request *,
+ void *, unsigned int, gfp_t, enum dma_data_direction);
+/* retrieve the mapped pages for bidi according to
+ * the given dma_data_direction
+ */
+extern int blk_rq_map_sg_bidi(request_queue_t *, struct request *,
+ struct scatterlist *, enum dma_data_direction);
+
#define MAX_PHYS_SEGMENTS 128
#define MAX_HW_SEGMENTS 128
#define SAFE_MAX_SECTORS 255
--
1.5.0.4.402.g8035
next prev parent reply other threads:[~2007-04-15 17:33 UTC|newest]
Thread overview: 25+ messages / expand[flat|nested] mbox.gz Atom feed top
2007-04-15 17:17 [PATCH 0/4] bidi support: block layer bidirectional io Boaz Harrosh
2007-04-15 17:25 ` [PATCH 1/4] bidi support: request dma_data_direction Boaz Harrosh
2007-04-15 17:31 ` [PATCH 2/4] bidi support: fix req->cmd == INT cases Boaz Harrosh
2007-04-15 17:32 ` [PATCH 3/4] bidi support: request_io_part Boaz Harrosh
2007-04-29 15:49 ` Boaz Harrosh
2007-04-15 17:33 ` Boaz Harrosh [this message]
2007-04-28 19:48 ` [PATCH 4/4] bidi support: bidirectional request FUJITA Tomonori
2007-04-29 15:48 ` Boaz Harrosh
2007-04-29 18:49 ` James Bottomley
2007-04-30 11:11 ` Jens Axboe
2007-04-30 11:53 ` Benny Halevy
2007-04-30 11:59 ` Jens Axboe
2007-04-30 14:52 ` Douglas Gilbert
2007-04-30 14:51 ` Jens Axboe
2007-04-30 15:12 ` Benny Halevy
2007-05-01 18:22 ` Boaz Harrosh
2007-05-01 18:57 ` Jens Axboe
2007-05-01 19:01 ` FUJITA Tomonori
2007-04-30 13:05 ` Mark Lord
2007-04-30 13:07 ` Jens Axboe
2007-05-01 19:50 ` FUJITA Tomonori
2007-05-03 17:42 ` Boaz Harrosh
2007-05-04 13:55 ` FUJITA Tomonori
2007-04-16 18:03 ` [PATCH 0/4] bidi support: block layer bidirectional io Douglas Gilbert
2007-04-17 9:32 ` Boaz Harrosh
Reply instructions:
You may reply publicly to this message via plain-text email
using any one of the following methods:
* Save the following mbox file, import it into your mail client,
and reply-to-all from there: mbox
Avoid top-posting and favor interleaved quoting:
https://en.wikipedia.org/wiki/Posting_style#Interleaved_style
* Reply using the --to, --cc, and --in-reply-to
switches of git-send-email(1):
git send-email \
--in-reply-to=462261E8.5090005@panasas.com \
--to=bharrosh@panasas.com \
--cc=James.Bottomley@SteelEye.com \
--cc=akpm@osdl.org \
--cc=bhalevy@panasas.com \
--cc=hch@infradead.org \
--cc=jens.axboe@oracle.com \
--cc=linux-ide@vger.kernel.org \
--cc=linux-scsi@vger.kernel.org \
--cc=michaelc@cs.wisc.edu \
--cc=osd-dev@open-osd.org \
/path/to/YOUR_REPLY
https://kernel.org/pub/software/scm/git/docs/git-send-email.html
* If your mail client supports setting the In-Reply-To header
via mailto: links, try the mailto: link
Be sure your reply has a Subject: header at the top and a blank line
before the message body.
This is an external index of several public inboxes,
see mirroring instructions on how to clone and mirror
all data and code used by this external index.