summaryrefslogtreecommitdiffstats
path: root/drivers/md/dm-snap.c
diff options
context:
space:
mode:
Diffstat (limited to 'drivers/md/dm-snap.c')
-rw-r--r--drivers/md/dm-snap.c18
1 files changed, 15 insertions, 3 deletions
diff --git a/drivers/md/dm-snap.c b/drivers/md/dm-snap.c
index 220a06bfe91b..e5a84c890e8f 100644
--- a/drivers/md/dm-snap.c
+++ b/drivers/md/dm-snap.c
@@ -2143,6 +2143,7 @@ static int origin_write_extent(struct dm_snapshot *merging_snap,
struct dm_origin {
struct dm_dev *dev;
+ unsigned split_boundary;
};
/*
@@ -2194,13 +2195,24 @@ static void origin_dtr(struct dm_target *ti)
static int origin_map(struct dm_target *ti, struct bio *bio)
{
struct dm_origin *o = ti->private;
+ unsigned available_sectors;
+
bio->bi_bdev = o->dev->bdev;
- if (bio->bi_rw & REQ_FLUSH)
+ if (unlikely(bio->bi_rw & REQ_FLUSH))
+ return DM_MAPIO_REMAPPED;
+
+ if (bio_rw(bio) != WRITE)
return DM_MAPIO_REMAPPED;
+ available_sectors = o->split_boundary -
+ ((unsigned)bio->bi_iter.bi_sector & (o->split_boundary - 1));
+
+ if (bio_sectors(bio) > available_sectors)
+ dm_accept_partial_bio(bio, available_sectors);
+
/* Only tell snapshots if this is a write */
- return (bio_rw(bio) == WRITE) ? do_origin(o->dev, bio) : DM_MAPIO_REMAPPED;
+ return do_origin(o->dev, bio);
}
/*
@@ -2211,7 +2223,7 @@ static void origin_resume(struct dm_target *ti)
{
struct dm_origin *o = ti->private;
- ti->max_io_len = get_origin_minimum_chunksize(o->dev->bdev);
+ o->split_boundary = get_origin_minimum_chunksize(o->dev->bdev);
}
static void origin_status(struct dm_target *ti, status_type_t type,