]> err.no Git - linux-2.6/blobdiff - block/blk-map.c
[NETNS][IPV6] fib6 rule - dynamic allocation of the rules struct ops
[linux-2.6] / block / blk-map.c
index 916cfc96ffa0de2ee8b92c63273b71daaef7db1b..09f7fd0bcb73000d4899f2b96dc088d852d41aab 100644 (file)
@@ -19,6 +19,7 @@ int blk_rq_append_bio(struct request_queue *q, struct request *rq,
                rq->biotail->bi_next = bio;
                rq->biotail = bio;
 
+               rq->raw_data_len += bio->bi_size;
                rq->data_len += bio->bi_size;
        }
        return 0;
@@ -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)))
+       if (!(uaddr & queue_dma_alignment(q)) &&
+           !(len & queue_dma_alignment(q)))
                bio = bio_map_user(q, NULL, uaddr, len, reading);
        else
                bio = bio_copy_user(q, uaddr, len, reading);
@@ -138,13 +140,31 @@ 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.  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;
+       }
+
        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 +199,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);
 
@@ -194,7 +215,6 @@ int blk_rq_map_user_iov(struct request_queue *q, struct request *rq,
        rq->buffer = rq->data = NULL;
        return 0;
 }
-
 EXPORT_SYMBOL(blk_rq_map_user_iov);
 
 /**
@@ -227,7 +247,6 @@ int blk_rq_unmap_user(struct bio *bio)
 
        return ret;
 }
-
 EXPORT_SYMBOL(blk_rq_unmap_user);
 
 /**
@@ -260,5 +279,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);