mirror of
https://git.kernel.org/pub/scm/linux/kernel/git/stable/linux.git
synced 2024-12-29 17:25:38 +00:00
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>
This commit is contained in:
parent
c5dec1c303
commit
afdc1a780e
@ -5,6 +5,7 @@
|
||||
#include <linux/module.h>
|
||||
#include <linux/bio.h>
|
||||
#include <linux/blkdev.h>
|
||||
#include <scsi/sg.h> /* for struct sg_iovec */
|
||||
|
||||
#include "blk.h"
|
||||
|
||||
@ -194,15 +195,26 @@ int blk_rq_map_user_iov(struct request_queue *q, struct request *rq,
|
||||
struct sg_iovec *iov, int iov_count, unsigned int len)
|
||||
{
|
||||
struct bio *bio;
|
||||
int i, read = rq_data_dir(rq) == READ;
|
||||
int unaligned = 0;
|
||||
|
||||
if (!iov || iov_count <= 0)
|
||||
return -EINVAL;
|
||||
|
||||
/* we don't allow misaligned data like bio_map_user() does. If the
|
||||
* user is using sg, they're expected to know the alignment constraints
|
||||
* and respect them accordingly */
|
||||
bio = bio_map_user_iov(q, NULL, iov, iov_count,
|
||||
rq_data_dir(rq) == READ);
|
||||
for (i = 0; i < iov_count; i++) {
|
||||
unsigned long uaddr = (unsigned long)iov[i].iov_base;
|
||||
|
||||
if (uaddr & queue_dma_alignment(q)) {
|
||||
unaligned = 1;
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
if (unaligned || (q->dma_pad_mask & len))
|
||||
bio = bio_copy_user_iov(q, iov, iov_count, read);
|
||||
else
|
||||
bio = bio_map_user_iov(q, NULL, iov, iov_count, read);
|
||||
|
||||
if (IS_ERR(bio))
|
||||
return PTR_ERR(bio);
|
||||
|
||||
|
Loading…
Reference in New Issue
Block a user