Back to home page

OSCL-LXR

 
 

    


0001 /*
0002  * Copyright (C) 2017 Intel Corporation.
0003  *
0004  * This file is released under the GPL.
0005  */
0006 
0007 #include "dm.h"
0008 
0009 #include <linux/module.h>
0010 
0011 struct unstripe_c {
0012     struct dm_dev *dev;
0013     sector_t physical_start;
0014 
0015     uint32_t stripes;
0016 
0017     uint32_t unstripe;
0018     sector_t unstripe_width;
0019     sector_t unstripe_offset;
0020 
0021     uint32_t chunk_size;
0022     u8 chunk_shift;
0023 };
0024 
0025 #define DM_MSG_PREFIX "unstriped"
0026 
0027 static void cleanup_unstripe(struct unstripe_c *uc, struct dm_target *ti)
0028 {
0029     if (uc->dev)
0030         dm_put_device(ti, uc->dev);
0031     kfree(uc);
0032 }
0033 
0034 /*
0035  * Contruct an unstriped mapping.
0036  * <number of stripes> <chunk size> <stripe #> <dev_path> <offset>
0037  */
0038 static int unstripe_ctr(struct dm_target *ti, unsigned int argc, char **argv)
0039 {
0040     struct unstripe_c *uc;
0041     sector_t tmp_len;
0042     unsigned long long start;
0043     char dummy;
0044 
0045     if (argc != 5) {
0046         ti->error = "Invalid number of arguments";
0047         return -EINVAL;
0048     }
0049 
0050     uc = kzalloc(sizeof(*uc), GFP_KERNEL);
0051     if (!uc) {
0052         ti->error = "Memory allocation for unstriped context failed";
0053         return -ENOMEM;
0054     }
0055 
0056     if (kstrtouint(argv[0], 10, &uc->stripes) || !uc->stripes) {
0057         ti->error = "Invalid stripe count";
0058         goto err;
0059     }
0060 
0061     if (kstrtouint(argv[1], 10, &uc->chunk_size) || !uc->chunk_size) {
0062         ti->error = "Invalid chunk_size";
0063         goto err;
0064     }
0065 
0066     if (kstrtouint(argv[2], 10, &uc->unstripe)) {
0067         ti->error = "Invalid stripe number";
0068         goto err;
0069     }
0070 
0071     if (uc->unstripe > uc->stripes && uc->stripes > 1) {
0072         ti->error = "Please provide stripe between [0, # of stripes]";
0073         goto err;
0074     }
0075 
0076     if (dm_get_device(ti, argv[3], dm_table_get_mode(ti->table), &uc->dev)) {
0077         ti->error = "Couldn't get striped device";
0078         goto err;
0079     }
0080 
0081     if (sscanf(argv[4], "%llu%c", &start, &dummy) != 1 || start != (sector_t)start) {
0082         ti->error = "Invalid striped device offset";
0083         goto err;
0084     }
0085     uc->physical_start = start;
0086 
0087     uc->unstripe_offset = uc->unstripe * uc->chunk_size;
0088     uc->unstripe_width = (uc->stripes - 1) * uc->chunk_size;
0089     uc->chunk_shift = is_power_of_2(uc->chunk_size) ? fls(uc->chunk_size) - 1 : 0;
0090 
0091     tmp_len = ti->len;
0092     if (sector_div(tmp_len, uc->chunk_size)) {
0093         ti->error = "Target length not divisible by chunk size";
0094         goto err;
0095     }
0096 
0097     if (dm_set_target_max_io_len(ti, uc->chunk_size)) {
0098         ti->error = "Failed to set max io len";
0099         goto err;
0100     }
0101 
0102     ti->private = uc;
0103     return 0;
0104 err:
0105     cleanup_unstripe(uc, ti);
0106     return -EINVAL;
0107 }
0108 
0109 static void unstripe_dtr(struct dm_target *ti)
0110 {
0111     struct unstripe_c *uc = ti->private;
0112 
0113     cleanup_unstripe(uc, ti);
0114 }
0115 
0116 static sector_t map_to_core(struct dm_target *ti, struct bio *bio)
0117 {
0118     struct unstripe_c *uc = ti->private;
0119     sector_t sector = bio->bi_iter.bi_sector;
0120     sector_t tmp_sector = sector;
0121 
0122     /* Shift us up to the right "row" on the stripe */
0123     if (uc->chunk_shift)
0124         tmp_sector >>= uc->chunk_shift;
0125     else
0126         sector_div(tmp_sector, uc->chunk_size);
0127 
0128     sector += uc->unstripe_width * tmp_sector;
0129 
0130     /* Account for what stripe we're operating on */
0131     return sector + uc->unstripe_offset;
0132 }
0133 
0134 static int unstripe_map(struct dm_target *ti, struct bio *bio)
0135 {
0136     struct unstripe_c *uc = ti->private;
0137 
0138     bio_set_dev(bio, uc->dev->bdev);
0139     bio->bi_iter.bi_sector = map_to_core(ti, bio) + uc->physical_start;
0140 
0141     return DM_MAPIO_REMAPPED;
0142 }
0143 
0144 static void unstripe_status(struct dm_target *ti, status_type_t type,
0145                 unsigned int status_flags, char *result, unsigned int maxlen)
0146 {
0147     struct unstripe_c *uc = ti->private;
0148     unsigned int sz = 0;
0149 
0150     switch (type) {
0151     case STATUSTYPE_INFO:
0152         break;
0153 
0154     case STATUSTYPE_TABLE:
0155         DMEMIT("%d %llu %d %s %llu",
0156                uc->stripes, (unsigned long long)uc->chunk_size, uc->unstripe,
0157                uc->dev->name, (unsigned long long)uc->physical_start);
0158         break;
0159 
0160     case STATUSTYPE_IMA:
0161         *result = '\0';
0162         break;
0163     }
0164 }
0165 
0166 static int unstripe_iterate_devices(struct dm_target *ti,
0167                     iterate_devices_callout_fn fn, void *data)
0168 {
0169     struct unstripe_c *uc = ti->private;
0170 
0171     return fn(ti, uc->dev, uc->physical_start, ti->len, data);
0172 }
0173 
0174 static void unstripe_io_hints(struct dm_target *ti,
0175                    struct queue_limits *limits)
0176 {
0177     struct unstripe_c *uc = ti->private;
0178 
0179     limits->chunk_sectors = uc->chunk_size;
0180 }
0181 
0182 static struct target_type unstripe_target = {
0183     .name = "unstriped",
0184     .version = {1, 1, 0},
0185     .features = DM_TARGET_NOWAIT,
0186     .module = THIS_MODULE,
0187     .ctr = unstripe_ctr,
0188     .dtr = unstripe_dtr,
0189     .map = unstripe_map,
0190     .status = unstripe_status,
0191     .iterate_devices = unstripe_iterate_devices,
0192     .io_hints = unstripe_io_hints,
0193 };
0194 
0195 static int __init dm_unstripe_init(void)
0196 {
0197     return dm_register_target(&unstripe_target);
0198 }
0199 
0200 static void __exit dm_unstripe_exit(void)
0201 {
0202     dm_unregister_target(&unstripe_target);
0203 }
0204 
0205 module_init(dm_unstripe_init);
0206 module_exit(dm_unstripe_exit);
0207 
0208 MODULE_DESCRIPTION(DM_NAME " unstriped target");
0209 MODULE_ALIAS("dm-unstriped");
0210 MODULE_AUTHOR("Scott Bauer <scott.bauer@intel.com>");
0211 MODULE_LICENSE("GPL");