From: Joe Thornber <joe@fib011235813.fsnet.co.uk>
To: Joe Thornber <joe@fib011235813.fsnet.co.uk>
Cc: Linus Torvalds <torvalds@transmeta.com>,
Kernel Mailing List <linux-kernel@vger.kernel.org>
Subject: 18/19
Date: Mon, 16 Dec 2002 10:18:30 +0000 [thread overview]
Message-ID: <20021216101830.GS7407@reti> (raw)
In-Reply-To: <20021216100457.GA7407@reti>
The block layer does not honour bio->bi_size when issuing io, instead
it performs io to the complete bvecs. This means we have to change
the bio splitting code slightly.
Given a bio we repeatedly apply one of the following three operations
until there is no more io left in the bio:
1) The remaining io does not cross an io/target boundary, so just
create a clone and issue all of the io.
2) There are some bvecs at the start of the bio that are not split by
a target boundary. Create a clone for these bvecs only.
3) The first bvec needs splitting, use bio_alloc() to create *two*
bios, one for the first half of the bvec, the other for the second
half. A bvec can never contain more than one boundary.
--- diff/drivers/md/dm.c 2002-12-16 09:41:39.000000000 +0000
+++ source/drivers/md/dm.c 2002-12-16 09:42:31.000000000 +0000
@@ -228,6 +228,15 @@
* interests of getting something for people to use I give
* you this clearly demarcated crap.
*---------------------------------------------------------------*/
+static inline sector_t to_sector(unsigned int bytes)
+{
+ return bytes >> SECTOR_SHIFT;
+}
+
+static inline unsigned int to_bytes(sector_t sector)
+{
+ return sector << SECTOR_SHIFT;
+}
/*
* Decrements the number of outstanding ios that a bio has been
@@ -270,16 +279,17 @@
static sector_t max_io_len(struct mapped_device *md,
sector_t sector, struct dm_target *ti)
{
- sector_t len = ti->len;
+ sector_t offset = sector - ti->begin;
+ sector_t len = ti->len - offset;
/* FIXME: obey io_restrictions ! */
+
/*
* Does the target need to split even further ?
*/
if (ti->split_io) {
sector_t boundary;
- sector_t offset = sector - ti->begin;
boundary = dm_round_up(offset + 1, ti->split_io) - offset;
if (len > boundary)
@@ -289,16 +299,17 @@
return len;
}
-static void __map_bio(struct dm_target *ti, struct bio *clone)
+static void __map_bio(struct dm_target *ti, struct bio *clone, struct dm_io *io)
{
- struct dm_io *io = clone->bi_private;
int r;
/*
* Sanity checks.
*/
- if (!clone->bi_size)
- BUG();
+ BUG_ON(!clone->bi_size);
+
+ clone->bi_end_io = clone_endio;
+ clone->bi_private = io;
/*
* Map the clone. If r == 0 we don't need to do
@@ -326,77 +337,125 @@
};
/*
- * Issues a little bio that just does the back end of a split page.
+ * Creates a little bio that is just does part of a bvec.
*/
-static void __split_page(struct clone_info *ci, unsigned int len)
+static struct bio *split_bvec(struct bio *bio, sector_t sector,
+ unsigned short idx, unsigned int offset,
+ unsigned int len)
{
- struct dm_target *ti = dm_table_find_target(ci->md->map, ci->sector);
- struct bio *clone, *bio = ci->bio;
- struct bio_vec *bv = bio->bi_io_vec + ci->idx;
-
- if (len > ci->sector_count)
- len = ci->sector_count;
+ struct bio *clone;
+ struct bio_vec *bv = bio->bi_io_vec + idx;
clone = bio_alloc(GFP_NOIO, 1);
- memcpy(clone->bi_io_vec, bv, sizeof(*bv));
- clone->bi_sector = ci->sector;
- clone->bi_bdev = bio->bi_bdev;
- clone->bi_rw = bio->bi_rw;
- clone->bi_vcnt = 1;
- clone->bi_size = len << SECTOR_SHIFT;
- clone->bi_end_io = clone_endio;
- clone->bi_private = ci->io;
- clone->bi_io_vec->bv_offset = bv->bv_len - clone->bi_size;
- clone->bi_io_vec->bv_len = clone->bi_size;
+ if (clone) {
+ memcpy(clone->bi_io_vec, bv, sizeof(*bv));
- ci->sector += len;
- ci->sector_count -= len;
+ clone->bi_sector = sector;
+ clone->bi_bdev = bio->bi_bdev;
+ clone->bi_rw = bio->bi_rw;
+ clone->bi_vcnt = 1;
+ clone->bi_size = to_bytes(len);
+ clone->bi_io_vec->bv_offset = offset;
+ clone->bi_io_vec->bv_len = clone->bi_size;
+ }
- __map_bio(ti, clone);
+ return clone;
+}
+
+/*
+ * Creates a bio that consists of range of complete bvecs.
+ */
+static struct bio *clone_bio(struct bio *bio, sector_t sector,
+ unsigned short idx, unsigned short bv_count,
+ unsigned int len)
+{
+ struct bio *clone;
+
+ clone = bio_clone(bio, GFP_NOIO);
+ clone->bi_sector = sector;
+ clone->bi_idx = idx;
+ clone->bi_vcnt = idx + bv_count;
+ clone->bi_size = to_bytes(len);
+
+ return clone;
}
static void __clone_and_map(struct clone_info *ci)
{
struct bio *clone, *bio = ci->bio;
struct dm_target *ti = dm_table_find_target(ci->md->map, ci->sector);
- sector_t len = max_io_len(ci->md, bio->bi_sector, ti);
+ sector_t len = 0, max = max_io_len(ci->md, ci->sector, ti);
- /* shorter than current target ? */
- if (ci->sector_count < len)
- len = ci->sector_count;
+ if (ci->sector_count <= max) {
+ /*
+ * Optimise for the simple case where we can do all of
+ * the remaining io with a single clone.
+ */
+ clone = clone_bio(bio, ci->sector, ci->idx,
+ bio->bi_vcnt - ci->idx, ci->sector_count);
+ __map_bio(ti, clone, ci->io);
+ ci->sector_count = 0;
- /* create the clone */
- clone = bio_clone(ci->bio, GFP_NOIO);
- clone->bi_sector = ci->sector;
- clone->bi_idx = ci->idx;
- clone->bi_size = len << SECTOR_SHIFT;
- clone->bi_end_io = clone_endio;
- clone->bi_private = ci->io;
+ } else if (to_sector(bio->bi_io_vec[ci->idx].bv_len) <= max) {
+ /*
+ * There are some bvecs that don't span targets.
+ * Do as many of these as possible.
+ */
+ int i;
+ sector_t remaining = max;
+ sector_t bv_len;
- /* adjust the remaining io */
- ci->sector += len;
- ci->sector_count -= len;
- __map_bio(ti, clone);
+ for (i = ci->idx; remaining && (i < bio->bi_vcnt); i++) {
+ bv_len = to_sector(bio->bi_io_vec[i].bv_len);
- /*
- * If we are not performing all remaining io in this
- * clone then we need to calculate ci->idx for the next
- * time round.
- */
- if (ci->sector_count) {
- while (len) {
- struct bio_vec *bv = clone->bi_io_vec + ci->idx;
- sector_t bv_len = bv->bv_len >> SECTOR_SHIFT;
- if (bv_len <= len)
- len -= bv_len;
+ if (bv_len > remaining)
+ break;
- else {
- __split_page(ci, bv_len - len);
- len = 0;
- }
- ci->idx++;
+ remaining -= bv_len;
+ len += bv_len;
}
+
+ clone = clone_bio(bio, ci->sector, ci->idx, i - ci->idx, len);
+ __map_bio(ti, clone, ci->io);
+
+ ci->sector += len;
+ ci->sector_count -= len;
+ ci->idx = i;
+
+ } else {
+ /*
+ * Create two copy bios to deal with io that has
+ * been split across a target.
+ */
+ struct bio_vec *bv = bio->bi_io_vec + ci->idx;
+
+ clone = split_bvec(bio, ci->sector, ci->idx,
+ bv->bv_offset, max);
+ if (!clone) {
+ dec_pending(ci->io, -ENOMEM);
+ return;
+ }
+
+ __map_bio(ti, clone, ci->io);
+
+ ci->sector += max;
+ ci->sector_count -= max;
+ ti = dm_table_find_target(ci->md->map, ci->sector);
+
+ len = to_sector(bv->bv_len) - max;
+ clone = split_bvec(bio, ci->sector, ci->idx,
+ bv->bv_offset + to_bytes(max), len);
+ if (!clone) {
+ dec_pending(ci->io, -ENOMEM);
+ return;
+ }
+
+ __map_bio(ti, clone, ci->io);
+
+ ci->sector += len;
+ ci->sector_count -= len;
+ ci->idx++;
}
}
next prev parent reply other threads:[~2002-12-16 10:12 UTC|newest]
Thread overview: 42+ messages / expand[flat|nested] mbox.gz Atom feed top
2002-12-10 22:03 [PATCH] dm.c - device-mapper I/O path fixes Kevin Corry
2002-12-11 12:17 ` Joe Thornber
2002-12-11 12:19 ` Joe Thornber
2002-12-11 18:19 ` Denis Vlasenko
2002-12-11 13:16 ` Kevin Corry
2002-12-11 14:18 ` Joe Thornber
2002-12-11 19:24 ` Denis Vlasenko
2002-12-11 14:06 ` Kevin Corry
2002-12-11 21:12 ` Paul Mackerras
2002-12-12 12:30 ` Kevin Corry
2002-12-11 19:19 ` Denis Vlasenko
2002-12-11 14:02 ` Kevin Corry
2002-12-11 15:12 ` [lvm-devel] " Joe Thornber
2002-12-11 14:58 ` Joe Thornber
2002-12-11 12:19 ` Joe Thornber
2002-12-11 12:20 ` Joe Thornber
2002-12-11 12:21 ` Joe Thornber
2002-12-11 12:52 ` [lvm-devel] " Kevin Corry
2002-12-16 0:50 ` Linus Torvalds
2002-12-16 10:04 ` Joe Thornber
2002-12-16 10:06 ` 1/19 Joe Thornber
2002-12-16 17:07 ` 1/19 Linus Torvalds
2002-12-16 10:06 ` 2/19 Joe Thornber
2002-12-16 10:07 ` 3/19 Joe Thornber
2002-12-16 10:08 ` 4/19 Joe Thornber
2002-12-16 10:09 ` 5/19 Joe Thornber
2002-12-16 10:09 ` 6/19 Joe Thornber
2002-12-16 10:35 ` 6/19 Tomas Szepe
2002-12-16 10:38 ` 6/19 Tomas Szepe
2002-12-16 10:10 ` 7/19 Joe Thornber
2002-12-16 10:11 ` 8/19 Joe Thornber
2002-12-16 10:11 ` 9/19 Joe Thornber
2002-12-16 10:12 ` 10/19 Joe Thornber
2002-12-16 10:13 ` 11/19 Joe Thornber
2002-12-16 10:14 ` 12/19 Joe Thornber
2002-12-16 10:14 ` 13/19 Joe Thornber
2002-12-16 10:15 ` 14/19 Joe Thornber
2002-12-16 10:16 ` 15/19 Joe Thornber
2002-12-16 10:16 ` 16/19 Joe Thornber
2002-12-16 10:17 ` 17/19 Joe Thornber
2002-12-16 10:18 ` Joe Thornber [this message]
2002-12-16 10:19 ` 19/19 Joe Thornber
Reply instructions:
You may reply publicly to this message via plain-text email
using any one of the following methods:
* Save the following mbox file, import it into your mail client,
and reply-to-all from there: mbox
Avoid top-posting and favor interleaved quoting:
https://en.wikipedia.org/wiki/Posting_style#Interleaved_style
* Reply using the --to, --cc, and --in-reply-to
switches of git-send-email(1):
git send-email \
--in-reply-to=20021216101830.GS7407@reti \
--to=joe@fib011235813.fsnet.co.uk \
--cc=linux-kernel@vger.kernel.org \
--cc=torvalds@transmeta.com \
/path/to/YOUR_REPLY
https://kernel.org/pub/software/scm/git/docs/git-send-email.html
* If your mail client supports setting the In-Reply-To header
via mailto: links, try the mailto: link
Be sure your reply has a Subject: header at the top and a blank line
before the message body.
This is a public inbox, see mirroring instructions
for how to clone and mirror all data and code used for this inbox