diff options
author | FUJITA Tomonori <fujita.tomonori@lab.ntt.co.jp> | 2008-04-11 06:56:51 -0400 |
---|---|---|
committer | Jens Axboe <jens.axboe@oracle.com> | 2008-04-21 03:50:08 -0400 |
commit | afdc1a780ef84a54b613dae6f971407748aab61c (patch) | |
tree | 67f120001c9a0a3f95fbb3ee2dc545f0886440c0 | |
parent | c5dec1c3034f1ae3503efbf641ff3b0273b64797 (diff) |
block: add bio_copy_user_iov support to blk_rq_map_user_iov
With this patch, blk_rq_map_user_iov uses bio_copy_user_iov when a low
level driver needs padding or a buffer in sg_iovec isn't aligned. That
is, it uses temporary kernel buffers instead of mapping user pages
directly.
When a LLD needs padding, later blk_rq_map_sg needs to extend the last
entry of a scatter list. bio_copy_user_iov guarantees that there is
enough space for padding by using temporary kernel buffers instead of
user pages.
blk_rq_map_user_iov needs buffers in sg_iovec to be aligned. The
comment in blk_rq_map_user_iov indicates that drivers/scsi/sg.c also
needs buffers in sg_iovec to be aligned. Actually, drivers/scsi/sg.c
works with unaligned buffers in sg_iovec (it always uses temporary
kernel buffers).
Signed-off-by: FUJITA Tomonori <fujita.tomonori@lab.ntt.co.jp>
Cc: Tejun Heo <htejun@gmail.com>
Cc: Mike Christie <michaelc@cs.wisc.edu>
Cc: James Bottomley <James.Bottomley@HansenPartnership.com>
Signed-off-by: Jens Axboe <jens.axboe@oracle.com>
-rw-r--r-- | block/blk-map.c | 22 |
1 files changed, 17 insertions, 5 deletions
diff --git a/block/blk-map.c b/block/blk-map.c index c07d9c8317f4..ab43533ba641 100644 --- a/block/blk-map.c +++ b/block/blk-map.c | |||
@@ -5,6 +5,7 @@ | |||
5 | #include <linux/module.h> | 5 | #include <linux/module.h> |
6 | #include <linux/bio.h> | 6 | #include <linux/bio.h> |
7 | #include <linux/blkdev.h> | 7 | #include <linux/blkdev.h> |
8 | #include <scsi/sg.h> /* for struct sg_iovec */ | ||
8 | 9 | ||
9 | #include "blk.h" | 10 | #include "blk.h" |
10 | 11 | ||
@@ -194,15 +195,26 @@ int blk_rq_map_user_iov(struct request_queue *q, struct request *rq, | |||
194 | struct sg_iovec *iov, int iov_count, unsigned int len) | 195 | struct sg_iovec *iov, int iov_count, unsigned int len) |
195 | { | 196 | { |
196 | struct bio *bio; | 197 | struct bio *bio; |
198 | int i, read = rq_data_dir(rq) == READ; | ||
199 | int unaligned = 0; | ||
197 | 200 | ||
198 | if (!iov || iov_count <= 0) | 201 | if (!iov || iov_count <= 0) |
199 | return -EINVAL; | 202 | return -EINVAL; |
200 | 203 | ||
201 | /* we don't allow misaligned data like bio_map_user() does. If the | 204 | for (i = 0; i < iov_count; i++) { |
202 | * user is using sg, they're expected to know the alignment constraints | 205 | unsigned long uaddr = (unsigned long)iov[i].iov_base; |
203 | * and respect them accordingly */ | 206 | |
204 | bio = bio_map_user_iov(q, NULL, iov, iov_count, | 207 | if (uaddr & queue_dma_alignment(q)) { |
205 | rq_data_dir(rq) == READ); | 208 | unaligned = 1; |
209 | break; | ||
210 | } | ||
211 | } | ||
212 | |||
213 | if (unaligned || (q->dma_pad_mask & len)) | ||
214 | bio = bio_copy_user_iov(q, iov, iov_count, read); | ||
215 | else | ||
216 | bio = bio_map_user_iov(q, NULL, iov, iov_count, read); | ||
217 | |||
206 | if (IS_ERR(bio)) | 218 | if (IS_ERR(bio)) |
207 | return PTR_ERR(bio); | 219 | return PTR_ERR(bio); |
208 | 220 | ||