Back to home page

OSCL-LXR

 
 

    


0001 /*
0002  * Copyright (C) 2001-2003 Sistina Software (UK) Limited.
0003  *
0004  * This file is released under the GPL.
0005  */
0006 
0007 #include "dm.h"
0008 #include <linux/module.h>
0009 #include <linux/init.h>
0010 #include <linux/blkdev.h>
0011 #include <linux/bio.h>
0012 #include <linux/dax.h>
0013 #include <linux/slab.h>
0014 #include <linux/device-mapper.h>
0015 
0016 #define DM_MSG_PREFIX "linear"
0017 
0018 /*
0019  * Linear: maps a linear range of a device.
0020  */
0021 struct linear_c {
0022     struct dm_dev *dev;
0023     sector_t start;
0024 };
0025 
0026 /*
0027  * Construct a linear mapping: <dev_path> <offset>
0028  */
0029 static int linear_ctr(struct dm_target *ti, unsigned int argc, char **argv)
0030 {
0031     struct linear_c *lc;
0032     unsigned long long tmp;
0033     char dummy;
0034     int ret;
0035 
0036     if (argc != 2) {
0037         ti->error = "Invalid argument count";
0038         return -EINVAL;
0039     }
0040 
0041     lc = kmalloc(sizeof(*lc), GFP_KERNEL);
0042     if (lc == NULL) {
0043         ti->error = "Cannot allocate linear context";
0044         return -ENOMEM;
0045     }
0046 
0047     ret = -EINVAL;
0048     if (sscanf(argv[1], "%llu%c", &tmp, &dummy) != 1 || tmp != (sector_t)tmp) {
0049         ti->error = "Invalid device sector";
0050         goto bad;
0051     }
0052     lc->start = tmp;
0053 
0054     ret = dm_get_device(ti, argv[0], dm_table_get_mode(ti->table), &lc->dev);
0055     if (ret) {
0056         ti->error = "Device lookup failed";
0057         goto bad;
0058     }
0059 
0060     ti->num_flush_bios = 1;
0061     ti->num_discard_bios = 1;
0062     ti->num_secure_erase_bios = 1;
0063     ti->num_write_zeroes_bios = 1;
0064     ti->private = lc;
0065     return 0;
0066 
0067       bad:
0068     kfree(lc);
0069     return ret;
0070 }
0071 
0072 static void linear_dtr(struct dm_target *ti)
0073 {
0074     struct linear_c *lc = (struct linear_c *) ti->private;
0075 
0076     dm_put_device(ti, lc->dev);
0077     kfree(lc);
0078 }
0079 
0080 static sector_t linear_map_sector(struct dm_target *ti, sector_t bi_sector)
0081 {
0082     struct linear_c *lc = ti->private;
0083 
0084     return lc->start + dm_target_offset(ti, bi_sector);
0085 }
0086 
0087 static int linear_map(struct dm_target *ti, struct bio *bio)
0088 {
0089     struct linear_c *lc = ti->private;
0090 
0091     bio_set_dev(bio, lc->dev->bdev);
0092     bio->bi_iter.bi_sector = linear_map_sector(ti, bio->bi_iter.bi_sector);
0093 
0094     return DM_MAPIO_REMAPPED;
0095 }
0096 
0097 static void linear_status(struct dm_target *ti, status_type_t type,
0098               unsigned status_flags, char *result, unsigned maxlen)
0099 {
0100     struct linear_c *lc = (struct linear_c *) ti->private;
0101     size_t sz = 0;
0102 
0103     switch (type) {
0104     case STATUSTYPE_INFO:
0105         result[0] = '\0';
0106         break;
0107 
0108     case STATUSTYPE_TABLE:
0109         DMEMIT("%s %llu", lc->dev->name, (unsigned long long)lc->start);
0110         break;
0111 
0112     case STATUSTYPE_IMA:
0113         DMEMIT_TARGET_NAME_VERSION(ti->type);
0114         DMEMIT(",device_name=%s,start=%llu;", lc->dev->name,
0115                (unsigned long long)lc->start);
0116         break;
0117     }
0118 }
0119 
0120 static int linear_prepare_ioctl(struct dm_target *ti, struct block_device **bdev)
0121 {
0122     struct linear_c *lc = (struct linear_c *) ti->private;
0123     struct dm_dev *dev = lc->dev;
0124 
0125     *bdev = dev->bdev;
0126 
0127     /*
0128      * Only pass ioctls through if the device sizes match exactly.
0129      */
0130     if (lc->start || ti->len != bdev_nr_sectors(dev->bdev))
0131         return 1;
0132     return 0;
0133 }
0134 
0135 #ifdef CONFIG_BLK_DEV_ZONED
0136 static int linear_report_zones(struct dm_target *ti,
0137         struct dm_report_zones_args *args, unsigned int nr_zones)
0138 {
0139     struct linear_c *lc = ti->private;
0140 
0141     return dm_report_zones(lc->dev->bdev, lc->start,
0142                    linear_map_sector(ti, args->next_sector),
0143                    args, nr_zones);
0144 }
0145 #else
0146 #define linear_report_zones NULL
0147 #endif
0148 
0149 static int linear_iterate_devices(struct dm_target *ti,
0150                   iterate_devices_callout_fn fn, void *data)
0151 {
0152     struct linear_c *lc = ti->private;
0153 
0154     return fn(ti, lc->dev, lc->start, ti->len, data);
0155 }
0156 
0157 #if IS_ENABLED(CONFIG_FS_DAX)
0158 static struct dax_device *linear_dax_pgoff(struct dm_target *ti, pgoff_t *pgoff)
0159 {
0160     struct linear_c *lc = ti->private;
0161     sector_t sector = linear_map_sector(ti, *pgoff << PAGE_SECTORS_SHIFT);
0162 
0163     *pgoff = (get_start_sect(lc->dev->bdev) + sector) >> PAGE_SECTORS_SHIFT;
0164     return lc->dev->dax_dev;
0165 }
0166 
0167 static long linear_dax_direct_access(struct dm_target *ti, pgoff_t pgoff,
0168         long nr_pages, enum dax_access_mode mode, void **kaddr,
0169         pfn_t *pfn)
0170 {
0171     struct dax_device *dax_dev = linear_dax_pgoff(ti, &pgoff);
0172 
0173     return dax_direct_access(dax_dev, pgoff, nr_pages, mode, kaddr, pfn);
0174 }
0175 
0176 static int linear_dax_zero_page_range(struct dm_target *ti, pgoff_t pgoff,
0177                       size_t nr_pages)
0178 {
0179     struct dax_device *dax_dev = linear_dax_pgoff(ti, &pgoff);
0180 
0181     return dax_zero_page_range(dax_dev, pgoff, nr_pages);
0182 }
0183 
0184 static size_t linear_dax_recovery_write(struct dm_target *ti, pgoff_t pgoff,
0185         void *addr, size_t bytes, struct iov_iter *i)
0186 {
0187     struct dax_device *dax_dev = linear_dax_pgoff(ti, &pgoff);
0188 
0189     return dax_recovery_write(dax_dev, pgoff, addr, bytes, i);
0190 }
0191 
0192 #else
0193 #define linear_dax_direct_access NULL
0194 #define linear_dax_zero_page_range NULL
0195 #define linear_dax_recovery_write NULL
0196 #endif
0197 
0198 static struct target_type linear_target = {
0199     .name   = "linear",
0200     .version = {1, 4, 0},
0201     .features = DM_TARGET_PASSES_INTEGRITY | DM_TARGET_NOWAIT |
0202             DM_TARGET_ZONED_HM | DM_TARGET_PASSES_CRYPTO,
0203     .report_zones = linear_report_zones,
0204     .module = THIS_MODULE,
0205     .ctr    = linear_ctr,
0206     .dtr    = linear_dtr,
0207     .map    = linear_map,
0208     .status = linear_status,
0209     .prepare_ioctl = linear_prepare_ioctl,
0210     .iterate_devices = linear_iterate_devices,
0211     .direct_access = linear_dax_direct_access,
0212     .dax_zero_page_range = linear_dax_zero_page_range,
0213     .dax_recovery_write = linear_dax_recovery_write,
0214 };
0215 
0216 int __init dm_linear_init(void)
0217 {
0218     int r = dm_register_target(&linear_target);
0219 
0220     if (r < 0)
0221         DMERR("register failed %d", r);
0222 
0223     return r;
0224 }
0225 
0226 void dm_linear_exit(void)
0227 {
0228     dm_unregister_target(&linear_target);
0229 }