include/asm-x86/thread_info_32.h: checkpatch cleanups - formatting only
[sfrench/cifs-2.6.git] / block / blk-map.c
index 916cfc96ffa0de2ee8b92c63273b71daaef7db1b..c07d9c8317f4c055d3821302c22df20cf2627195 100644 (file)
@@ -43,6 +43,7 @@ static int __blk_rq_map_user(struct request_queue *q, struct request *rq,
                             void __user *ubuf, unsigned int len)
 {
        unsigned long uaddr;
+       unsigned int alignment;
        struct bio *bio, *orig_bio;
        int reading, ret;
 
@@ -53,7 +54,8 @@ static int __blk_rq_map_user(struct request_queue *q, struct request *rq,
         * 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);
@@ -138,13 +140,33 @@ int blk_rq_map_user(struct request_queue *q, struct request *rq,
                ubuf += ret;
        }
 
+       /*
+        * __blk_rq_map_user() copies the buffers if starting address
+        * or length isn't aligned to dma_pad_mask.  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 & q->dma_pad_mask) {
+               unsigned int pad_len = (q->dma_pad_mask & ~len) + 1;
+               struct bio *tail = rq->biotail;
+
+               tail->bi_io_vec[tail->bi_vcnt - 1].bv_len += pad_len;
+               tail->bi_size += pad_len;
+
+               rq->extra_len += pad_len;
+       }
+
        rq->buffer = rq->data = NULL;
        return 0;
 unmap_rq:
        blk_rq_unmap_user(bio);
+       rq->bio = NULL;
        return ret;
 }
-
 EXPORT_SYMBOL(blk_rq_map_user);
 
 /**
@@ -179,7 +201,8 @@ int blk_rq_map_user_iov(struct request_queue *q, struct request *rq,
        /* 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);
+       bio = bio_map_user_iov(q, NULL, iov, iov_count,
+                               rq_data_dir(rq) == READ);
        if (IS_ERR(bio))
                return PTR_ERR(bio);
 
@@ -195,8 +218,6 @@ int blk_rq_map_user_iov(struct request_queue *q, struct request *rq,
        return 0;
 }
 
-EXPORT_SYMBOL(blk_rq_map_user_iov);
-
 /**
  * blk_rq_unmap_user - unmap a request with user data
  * @bio:              start of bio list
@@ -227,7 +248,6 @@ int blk_rq_unmap_user(struct bio *bio)
 
        return ret;
 }
-
 EXPORT_SYMBOL(blk_rq_unmap_user);
 
 /**
@@ -260,5 +280,4 @@ int blk_rq_map_kern(struct request_queue *q, struct request *rq, void *kbuf,
        rq->buffer = rq->data = NULL;
        return 0;
 }
-
 EXPORT_SYMBOL(blk_rq_map_kern);