#include <linux/module.h>
#include <linux/bio.h>
#include <linux/blkdev.h>
+#include <scsi/sg.h> /* for struct sg_iovec */
#include "blk.h"
rq->biotail->bi_next = bio;
rq->biotail = bio;
- rq->raw_data_len += bio->bi_size;
rq->data_len += bio->bi_size;
}
return 0;
void __user *ubuf, unsigned int len)
{
unsigned long uaddr;
+ unsigned int alignment;
struct bio *bio, *orig_bio;
int reading, ret;
* direct dma. else, set up kernel bounce buffers
*/
uaddr = (unsigned long) ubuf;
- if (!(uaddr & queue_dma_alignment(q)) &&
- !(len & queue_dma_alignment(q)))
+ alignment = queue_dma_alignment(q) | q->dma_pad_mask;
+ if (!(uaddr & alignment) && !(len & alignment))
bio = bio_map_user(q, NULL, uaddr, len, reading);
else
bio = bio_copy_user(q, uaddr, len, reading);
ubuf += ret;
}
- /*
- * __blk_rq_map_user() copies the buffers if starting address
- * or length isn't aligned. As the copied buffer is always
- * page aligned, we know that there's enough room for padding.
- * Extend the last bio and update rq->data_len accordingly.
- *
- * On unmap, bio_uncopy_user() will use unmodified
- * bio_map_data pointed to by bio->bi_private.
- */
- if (len & queue_dma_alignment(q)) {
- unsigned int pad_len = (queue_dma_alignment(q) & ~len) + 1;
- struct bio *bio = rq->biotail;
-
- bio->bi_io_vec[bio->bi_vcnt - 1].bv_len += pad_len;
- bio->bi_size += pad_len;
- rq->data_len += pad_len;
- }
+ if (!bio_flagged(bio, BIO_USER_MAPPED))
+ rq->cmd_flags |= REQ_COPY_USER;
rq->buffer = rq->data = NULL;
return 0;
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);
return -EINVAL;
}
+ if (!bio_flagged(bio, BIO_USER_MAPPED))
+ rq->cmd_flags |= REQ_COPY_USER;
+
bio_get(bio);
blk_rq_bio_prep(q, rq, bio);
rq->buffer = rq->data = NULL;
return 0;
}
-EXPORT_SYMBOL(blk_rq_map_user_iov);
/**
* blk_rq_unmap_user - unmap a request with user data
* @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))
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;