Gitweb:     
http://git.kernel.org/git/?p=linux/kernel/git/torvalds/linux-2.6.git;a=commit;h=91e106259214b40e992a58fb9417da46868e19b2
Commit:     91e106259214b40e992a58fb9417da46868e19b2
Parent:     91212507f93778c09d4c1335207b6f4b995f5ad1
Author:     Milan Broz <[EMAIL PROTECTED]>
AuthorDate: Thu Dec 13 14:16:10 2007 +0000
Committer:  Alasdair G Kergon <[EMAIL PROTECTED]>
CommitDate: Thu Dec 20 17:32:13 2007 +0000

    dm crypt: use bio_add_page
    
    Fix possible max_phys_segments violation in cloned dm-crypt bio.
    
    In write operation dm-crypt needs to allocate new bio request
    and run crypto operation on this clone. Cloned request has always
    the same size, but number of physical segments can be increased
    and violate max_phys_segments restriction.
    
    This can lead to data corruption and serious hardware malfunction.
    This was observed when using XFS over dm-crypt and at least
    two HBA controller drivers (arcmsr, cciss) recently.
    
    Fix it by using bio_add_page() call (which tests for other
    restrictions too) instead of constructing own biovec.
    
    All versions of dm-crypt are affected by this bug.
    
    Cc: [EMAIL PROTECTED]
    Cc:  [EMAIL PROTECTED]
    Signed-off-by: Milan Broz <[EMAIL PROTECTED]>
    Signed-off-by: Alasdair G Kergon <[EMAIL PROTECTED]>
---
 drivers/md/dm-crypt.c |   24 +++++++++++-------------
 1 files changed, 11 insertions(+), 13 deletions(-)

diff --git a/drivers/md/dm-crypt.c b/drivers/md/dm-crypt.c
index 30d51a0..6b66ee4 100644
--- a/drivers/md/dm-crypt.c
+++ b/drivers/md/dm-crypt.c
@@ -398,7 +398,8 @@ static struct bio *crypt_alloc_buffer(struct dm_crypt_io 
*io, unsigned size)
        struct bio *clone;
        unsigned int nr_iovecs = (size + PAGE_SIZE - 1) >> PAGE_SHIFT;
        gfp_t gfp_mask = GFP_NOIO | __GFP_HIGHMEM;
-       unsigned int i;
+       unsigned i, len;
+       struct page *page;
 
        clone = bio_alloc_bioset(GFP_NOIO, nr_iovecs, cc->bs);
        if (!clone)
@@ -407,10 +408,8 @@ static struct bio *crypt_alloc_buffer(struct dm_crypt_io 
*io, unsigned size)
        clone_init(io, clone);
 
        for (i = 0; i < nr_iovecs; i++) {
-               struct bio_vec *bv = bio_iovec_idx(clone, i);
-
-               bv->bv_page = mempool_alloc(cc->page_pool, gfp_mask);
-               if (!bv->bv_page)
+               page = mempool_alloc(cc->page_pool, gfp_mask);
+               if (!page)
                        break;
 
                /*
@@ -421,15 +420,14 @@ static struct bio *crypt_alloc_buffer(struct dm_crypt_io 
*io, unsigned size)
                if (i == (MIN_BIO_PAGES - 1))
                        gfp_mask = (gfp_mask | __GFP_NOWARN) & ~__GFP_WAIT;
 
-               bv->bv_offset = 0;
-               if (size > PAGE_SIZE)
-                       bv->bv_len = PAGE_SIZE;
-               else
-                       bv->bv_len = size;
+               len = (size > PAGE_SIZE) ? PAGE_SIZE : size;
+
+               if (!bio_add_page(clone, page, len, 0)) {
+                       mempool_free(page, cc->page_pool);
+                       break;
+               }
 
-               clone->bi_size += bv->bv_len;
-               clone->bi_vcnt++;
-               size -= bv->bv_len;
+               size -= len;
        }
 
        if (!clone->bi_size) {
-
To unsubscribe from this list: send the line "unsubscribe git-commits-head" in
the body of a message to [EMAIL PROTECTED]
More majordomo info at  http://vger.kernel.org/majordomo-info.html

Reply via email to