Set the ti->split_io field for the snapshot to its chunk-size. Set the ti->split_io field for the origin to the smallest chunk-size of its snapshots. This is done each time the origin is resumed, since new snapshots (with smaller chunk-sizes) could have been added. --- a/drivers/md/dm-snapshot.c 2003-10-20 12:21:30.000000000 -0500 +++ b/drivers/md/dm-snapshot.c 2003-10-20 12:10:36.000000000 -0500 @@ -527,6 +527,8 @@ } ti->private = s; + ti->split_io = chunk_size; + return 0; bad6: @@ -1136,6 +1138,33 @@ return (bio_rw(bio) == WRITE) ? do_origin(dev, bio) : 1; } +#define min_not_zero(l, r) (l == 0) ? r : ((r == 0) ? l : min(l, r)) + +/* + * Set the target "split_io" field to the minimum of all the snapshots' + * chunk sizes. + */ +static void origin_resume(struct dm_target *ti) +{ + struct dm_dev *dev = (struct dm_dev *) ti->private; + struct dm_snapshot *snap; + struct origin *o; + struct list_head *sl; + chunk_t chunk_size = 0; + + down_read(&_origins_lock); + o = __lookup_origin(dev->bdev); + if (o) { + list_for_each(sl, &o->snapshots) { + snap = list_entry(sl, struct dm_snapshot, list); + chunk_size = min_not_zero(chunk_size, snap->chunk_size); + } + } + up_read(&_origins_lock); + + ti->split_io = chunk_size; +} + static int origin_status(struct dm_target *ti, status_type_t type, char *result, unsigned int maxlen) { @@ -1162,6 +1191,7 @@ ctr: origin_ctr, dtr: origin_dtr, map: origin_map, + resume: origin_resume, status: origin_status, };