Skip to contentSkip to conversation

block: add dma alignment and padding support to blk_rq_map_kern

PATCH In review FUJITA Tomonori 2 participants 3 messages Apr 19, 2008 – Apr 23, 2008

Subsystems (3)
lore
Share & tools
lore
#0 lore raw

PATCH 1/1 block: add dma alignment and padding support to blk_rq_map_kern

blk_rq_map_kern ignores dma alignment and padding. Is it problematic to libata?

This is against Jens' for-2.6.26 branch.

==
From: FUJITA Tomonori <[email protected]>
Subject: [PATCH] block: add dma alignment and padding support to blk_rq_map_kern

This patch adds bio_copy_kern similar to bio_copy_user. blk_rq_map_kern uses bio_copy_kern instead of bio_map_kern if necessary.

bio_copy_kern uses temporary pages and the bi_end_io callback frees these pages. bio_copy_kern saves the original kernel buffer at bio->bi_private it doesn't use something like struct bio_map_data to store the information about the caller.

---
 block/blk-map.c     |   21 +++++++++++-
 fs/bio.c            |   90 +++++++++++++++++++++++++++++++++++++++++++++++++++
 include/linux/bio.h |    2 +
 3 files changed, 112 insertions(+), 1 deletions(-)
block/blk-map.c +20 -1
index 3c942bd..0b1af5a 100644
@@ -255,10 +255,18 @@ EXPORT_SYMBOL(blk_rq_unmap_user);
  * @kbuf:	the kernel buffer
  * @len:	length of user data
  * @gfp_mask:	memory allocation flags
+ *
+ * Description:
+ *    Data will be mapped directly if possible. Otherwise a bounce
+ *    buffer is used.
  */
 int blk_rq_map_kern(struct request_queue *q, struct request *rq, void *kbuf,
 		    unsigned int len, gfp_t gfp_mask)
 {
+	unsigned long kaddr;
+	unsigned int alignment;
+	int reading = rq_data_dir(rq) == READ;
+	int do_copy = 0;
 	struct bio *bio;
 
 	if (len > (q->max_hw_sectors << 9))
@@ -266,13 +274,24 @@ int blk_rq_map_kern(struct request_queue *q, struct request *rq, void *kbuf,
 	if (!len || !kbuf)
 		return -EINVAL;
 
-	bio = bio_map_kern(q, kbuf, len, gfp_mask);
+	kaddr = (unsigned long)kbuf;
+	alignment = queue_dma_alignment(q) | q->dma_pad_mask;
+	do_copy = ((kaddr & alignment) || (len & alignment));
+
+	if (do_copy)
+		bio = bio_copy_kern(q, kbuf, len, gfp_mask, reading);
+	else
+		bio = bio_map_kern(q, kbuf, len, gfp_mask);
+
 	if (IS_ERR(bio))
 		return PTR_ERR(bio);
 
 	if (rq_data_dir(rq) == WRITE)
 		bio->bi_rw |= (1 << BIO_RW);
 
+	if (do_copy)
+		rq->cmd_flags |= REQ_COPY_USER;
+
 	blk_rq_bio_prep(q, rq, bio);
 	blk_queue_bounce(q, &rq->bio);
 	rq->buffer = rq->data = NULL;
fs/bio.c +90 -0

102 lines not on this page · raw message

include/linux/bio.h +2 -0
index d259690..61c15ea 100644
@@ -324,6 +324,8 @@ extern struct bio *bio_map_user_iov(struct request_queue *,
 extern void bio_unmap_user(struct bio *);
 extern struct bio *bio_map_kern(struct request_queue *, void *, unsigned int,
 				gfp_t);
+extern struct bio *bio_copy_kern(struct request_queue *, void *, unsigned int,
+				 gfp_t, int);
 extern void bio_set_pages_dirty(struct bio *bio);
 extern void bio_check_pages_dirty(struct bio *bio);
 extern struct bio *bio_copy_user(struct request_queue *, unsigned long, unsigned int, int);
Signature · 1 line
1.5.3.4
#1 lore raw
Quoted 2 lines · FUJITA Tomonori

blk_rq_map_kern ignores dma alignment and padding. Is it problematic to libata?

Till now we've been depending for the issuer to get this right but it's definitely worth fixing. Thanks.

Signature · 1 line
tejun
#2 lore raw
Quoted 6 lines · On Wed, 23 Apr 2008 15:32:25 +0900 Tejun Heo <[email protected]> wrote:
Quoted 2 lines · FUJITA Tomonori

blk_rq_map_kern ignores dma alignment and padding. Is it problematic to libata?

Till now we've been depending for the issuer to get this right but it's definitely worth fixing. Thanks.

Surely, some callers don't give 512-byte aligned buffer, which libata wants.