Linux Headquarters
[ Register ]
[ About us ] [ Home Page ]

Advertisement
[ Kernel ] [ Documentation ] [ Links ] [ Books ]

Advertisement

Kernel v2.6.26-rc1 /block/blk-map.c

Filename:/block/blk-map.c
Lines Added:42
Lines Deleted:25
Also changed in: (Previous) 2.6.25-git20  2.6.25-git19  2.6.25-git18  2.6.25-git17  2.6.25-git16  2.6.25-git15 
(Following) 2.6.26-rc2  2.6.26-rc3  2.6.26-rc4  2.6.26-rc5  2.6.26-rc6  2.6.26-rc7 

Location
[  2.6.26-rc1
  [  block
     o  blk-map.c

Patch

diff --git a/block/blk-map.c b/block/blk-map.c
index c07d9c8..0b1af5a 100644
--- a/block/blk-map.c
+++ b/block/blk-map.c
@@ -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"
 
@@ -140,25 +141,8 @@ 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;
-   }
+   if (!bio_flagged(bio, BIO_USER_MAPPED))
+      rq->cmd_flags |= REQ_COPY_USER;
 
    rq->buffer = rq->data = NULL;
    return 0;
@@ -194,15 +178,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);
 
@@ -212,6 +207,9 @@ int blk_rq_map_user_iov(struct request_queue *q, struct request *rq,
       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;
@@ -257,10 +255,18 @@ EXPORT_SYMBOL(blk_rq_unmap_user);
  * @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))
@@ -268,13 +274,24 @@ int blk_rq_map_kern(struct request_queue *q, struct request *rq, void *kbuf,
    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;


Comments: webmaster (at) linuxhq.com.
Advertising: banners (at) linuxhq.com.
Compilation ©1998-2008 Linux Headquarters, Inc.