Sophie

Sophie

distrib > Scientific%20Linux > 5x > x86_64 > by-pkgid > 27922b4260f65d317aabda37e42bbbff > files > 1729

kernel-2.6.18-238.el5.src.rpm

From: Milan Broz <mbroz@redhat.com>
Date: Thu, 13 Dec 2007 19:03:43 +0100
Subject: [md] dm-crypt: possible max_phys_segments violation
Message-id: 476173FF.5020104@redhat.com
O-Subject: [RHEL 5.2 PATCH] dm-crypt: fix possible max_phys_segments violation
Bugzilla: 421441

RHEL5.2 dm: Fix possible max_phys_segments violation in dm-crypt
Resolves: rhbz#421441
Patch is in -mm queued for upstream 2.6.24-rc

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.

Fix it by using bio_add_page() call (which tests for other
restrictions too) instead of constructing own biovec.

Kernel with patch compiled and tested.

Acked-by: Alasdair G Kergon <agk@redhat.com>

diff --git a/drivers/md/dm-crypt.c b/drivers/md/dm-crypt.c
index 40f9e59..0c7f22e 100644
--- a/drivers/md/dm-crypt.c
+++ b/drivers/md/dm-crypt.c
@@ -329,7 +329,8 @@ static struct bio *crypt_alloc_buffer(struct crypt_io *io, unsigned int 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)
@@ -338,10 +339,8 @@ static struct bio *crypt_alloc_buffer(struct crypt_io *io, unsigned int 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;
 
 		/*
@@ -352,15 +351,14 @@ static struct bio *crypt_alloc_buffer(struct crypt_io *io, unsigned int 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) {