aboutsummaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorFUJITA Tomonori2008-04-11 05:56:51 -0500
committerJens Axboe2008-04-21 02:50:08 -0500
commitafdc1a780ef84a54b613dae6f971407748aab61c (patch)
tree67f120001c9a0a3f95fbb3ee2dc545f0886440c0 /block/blk-map.c
parentc5dec1c3034f1ae3503efbf641ff3b0273b64797 (diff)
downloadkernel-common-afdc1a780ef84a54b613dae6f971407748aab61c.tar.gz
kernel-common-afdc1a780ef84a54b613dae6f971407748aab61c.tar.xz
kernel-common-afdc1a780ef84a54b613dae6f971407748aab61c.zip
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>
Diffstat (limited to 'block/blk-map.c')
-rw-r--r--block/blk-map.c22
1 files changed, 17 insertions, 5 deletions
diff --git a/block/blk-map.c b/block/blk-map.c
index c07d9c8317f..ab43533ba64 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