#include #include #include #include #include #include #define DM_MSG_PREFIX "poc" struct poc_c { struct dm_dev *dev; int chunk_size_in_pages; atomic_t nr_pending; struct bio *pending_bio; }; static void endio(struct bio *bio, int error) { struct poc_c *pc = bio->bi_private; bio_put(bio); if (atomic_dec_and_test(&pc->nr_pending)) bio_endio(pc->pending_bio, error); } static struct bio *clone_bio(struct poc_c *pc, struct bio *bio, int idx, int nr_pages) { struct bio *clone = bio_clone(bio, GFP_NOIO); if (!clone) return NULL; clone->bi_sector = bio->bi_sector + (idx * 8); /* 8 sectors per page. */ clone->bi_idx = idx; clone->bi_vcnt = idx + nr_pages; clone->bi_size = nr_pages * PAGE_SIZE; clone->bi_end_io = endio; clone->bi_bdev = pc->dev->bdev; clone->bi_private = pc; atomic_inc(&pc->nr_pending); return clone; } static int poc_map(struct dm_target *ti, struct bio *bio) { struct poc_c *pc = ti->private; struct bio *clone1, *clone2; int nr_pages1 = pc->chunk_size_in_pages; int nr_pages2 = bio_segments(bio) - nr_pages1; if (bio_data_dir(bio) == WRITE || nr_pages2 <= 0) { bio_endio(bio, 0); return DM_MAPIO_SUBMITTED; } clone1 = clone_bio(pc, bio, 0, nr_pages1); clone2 = clone_bio(pc, bio, nr_pages1, nr_pages2); if (!clone1 || !clone2) { printk(KERN_ERR "Failed to clone bio.\n"); return -EIO; } pc->pending_bio = bio; generic_make_request(clone1); generic_make_request(clone2); return DM_MAPIO_SUBMITTED; } static int poc_ctr(struct dm_target *ti, unsigned int argc, char **argv) { struct poc_c *pc; unsigned long long tmp; char dummy; if (argc != 2) { ti->error = "Invalid argument count"; return -EINVAL; } pc = kzalloc(sizeof(*pc), GFP_KERNEL); if (pc == NULL) { ti->error = "dm-poc: Cannot allocate poc context"; return -ENOMEM; } if (sscanf(argv[1], "%llu%c", &tmp, &dummy) != 1) { ti->error = "dm-poc: Invalid chunk size"; goto bad; } pc->chunk_size_in_pages = tmp; atomic_set(&pc->nr_pending, 0); if (dm_get_device(ti, argv[0], dm_table_get_mode(ti->table), &pc->dev)) { printk(KERN_ERR "device is %s", argv[0]); ti->error = "dm-poc: Device lookup failed"; goto bad; } ti->private = pc; return 0; bad: kfree(pc); return -EINVAL; } static void poc_dtr(struct dm_target *ti) { struct poc_c *pc = (struct poc_c *) ti->private; dm_put_device(ti, pc->dev); kfree(pc); } static struct target_type poc_target = { .name = "poc", .version = {1, 0, 0}, .module = THIS_MODULE, .ctr = poc_ctr, .dtr = poc_dtr, .map = poc_map, }; int __init dm_poc_init(void) { int r = dm_register_target(&poc_target); if (r < 0) DMERR("register failed %d", r); return r; } void dm_poc_exit(void) { dm_unregister_target(&poc_target); } module_init(dm_poc_init); module_exit(dm_poc_exit); MODULE_LICENSE("GPL");