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 an external index of several public inboxes,
see mirroring instructions on how to clone and mirror
all data and code used by this external index.