diff --git a/CHANGELOG.md b/CHANGELOG.md index c4434fc..75a3a64 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -14,6 +14,17 @@ and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0 - Global constants fully shared among components through `sflc_constants.h`. +## [0.5.1] - 2024-10-13 + +### Refactored + + - Reorganized interface between dispatcher and dm-legacy through pointers to functions. + +### Fixed + + - Fixed debug error message when reading unallocated slices on dm-legacy. + + ## [0.5.0] - 2024-09-01 ### Added @@ -37,6 +48,7 @@ and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0 - Changed all occurrences of "Shufflecake Old" to "Shufflecake Legacy", including code paths and variables. - Reordered entries in CHANGELOG.md with sections following the order Added -> Changed -> Fixed -> Refactored -> Removed. + ## [0.4.5] - 2024-06-03 ### Changed diff --git a/README.md b/README.md index beee2f9..863150c 100644 --- a/README.md +++ b/README.md @@ -1,5 +1,5 @@ [![Status](resources/images/badges/badge_status_active.png)](https://codeberg.org/shufflecake/shufflecake-c)  -[![Version](resources/images/badges/badge_version_0.5.0.png)](https://codeberg.org/shufflecake/shufflecake-c/releases/tag/v0.5.0)  +[![Version](resources/images/badges/badge_version_0.5.1.png)](https://codeberg.org/shufflecake/shufflecake-c/releases/tag/v0.5.1)  [![License](resources/images/badges/badge_license_gplv2plus.png)](https://www.gnu.org/licenses/old-licenses/gpl-2.0.en.html)  [![Docs researchpaper](resources/images/badges/badge_docs_researchpaper.png)](https://eprint.iacr.org/2023/1529)  [![Website](resources/images/badges/badge_web_shufflecakedotnet.png)](https://shufflecake.net/)  @@ -12,7 +12,7 @@ -# Shufflecake - Full C Implementation - v0.5.0 +# Shufflecake - Full C Implementation - v0.5.1 _Shufflecake_ is a plausible deniability (hidden storage) layer for Linux. You can consider Shufflecake a spiritual successor of tools like TrueCrypt and VeraCrypt, but vastly improved, both in terms of security and functionality. Official website: . @@ -265,6 +265,11 @@ Both methods works with the `init` action, and we do not have current plans to c Please see the file `CHANGELOG.md` for a detailed history of changes. +### [0.5.1] - 2024-10-13 + + - Reorganized interface between dispatcher and dm-legacy through pointers to functions. + - Fixed debug error message when reading unallocated slices on dm-legacy. + ### [0.5.0] - 2024-09-01 - BREAKING CHANGE: major rewrite, bugfixes, introduced Shufflecake "Lite" as a default mode of operation. @@ -273,34 +278,6 @@ Please see the file `CHANGELOG.md` for a detailed history of changes. - Fixed a compile error on some versions of LTS kernels. - Fixed segmentation fault when opening an already opened device. - -### [0.4.4] - 2023-12-31 - - - Fixed a memory allocation error on large devices. - -### [0.4.3] - 2023-11-29 - - - Fixed compile error on recent kernel versions. - -### [0.4.2] - 2023-11-28 - - - Fixed persistent slice allocation ambiguity after a volume corruption by allocating fresh slices for the corrupted volume. This is done in order to help external recovery tools (e.g. RAID). - - Various bugfixes. - -### [0.4.1] - 2023-07-30 - - - Fixed and improved benchmark scripts. - - Fixed mistake in drawing of header layout in `doc`. - -### [0.4.0] - 2023-07-24 - -- BREAKING CHANGE: slightly modified header field format, removing redundant data and making it adherent to documentation. -- Implemented reference slice allocation algorithm with much faster performance. -- Added actions `checkpwd` and `changepwd`. -- Password is now read in a secure shell during `open`. -- Added benchmark suite. -- Fixed bugs in action `close` and option `--skip-randfill`. -- Added `doc` (currently includes figure of Shufflecake headers structure). diff --git a/dm-sflc/bin/sflc_types.h b/dm-sflc/bin/sflc_types.h new file mode 120000 index 0000000..d320fe2 --- /dev/null +++ b/dm-sflc/bin/sflc_types.h @@ -0,0 +1 @@ +../src/sflc_types.h \ No newline at end of file diff --git a/dm-sflc/src/dev_vol.c b/dm-sflc/src/dev_vol.c index 6c454b9..5bc3473 100644 --- a/dm-sflc/src/dev_vol.c +++ b/dm-sflc/src/dev_vol.c @@ -27,183 +27,67 @@ #include "legacy/sflc_legacy.h" -/* Create a sflc_device containing the appropriate mode-specific struct */ -struct sflc_device *sflc_dev_create(struct dm_target *ti, int argc, char **argv) +/* Init a sflc_device_base */ +int sflc_dev_base_init(struct sflc_device_base *sd_base, struct dm_target *ti, + int argc, char **argv) { - struct sflc_device *sdev; u32 dev_id; dev_t devt; - int mode; int err; - sdev = kzalloc(sizeof(*sdev), GFP_KERNEL); - if (!sdev) { - DMERR("Could not allocate device"); - return ERR_PTR(-ENOMEM); - } - /* Parse arguments */ - if (sscanf(argv[0], "%d", &mode) != 1) { - err = -EINVAL; - goto bad_parse; - } sscanf(argv[1], "%u", &dev_id); err = lookup_bdev(argv[2], &devt); - if (err) { - DMERR("Could not look up block device"); - goto bad_parse; - } + if (err) + return err; /* Assign fields */ - sdev->dev_id = dev_id; - sdev->nr_volumes = 0; - sdev->mode = mode; - format_dev_t(sdev->name, devt); + sd_base->dev_id = dev_id; + sd_base->nr_volumes = 0; + format_dev_t(sd_base->name, devt); + /* Fields `mode` and `ops` will be set by the derived constructor */ /* Register with sysfs */ - err = sflc_sysfs_register_device(sdev); + err = sflc_sysfs_register_device_base(sd_base); if (err) - goto bad_sysfs; + return err; - /* Instantiate inner device. Sysfs has to be inited by now */ - switch (mode) - { - case SFLC_MODE_LEGACY: - sdev->sflegc_dev = sflegc_dev_create(ti, argc, argv, &sdev->kobj); - if (IS_ERR(sdev->sflegc_dev)) { - err = PTR_ERR(sdev->sflegc_dev); - goto bad_inner; - } - break; - case SFLC_MODE_LITE: - sdev->sflite_dev = sflite_dev_create(ti, argc, argv, &sdev->kobj); - if (IS_ERR(sdev->sflite_dev)) { - err = PTR_ERR(sdev->sflite_dev); - goto bad_inner; - } - break; - default: - DMERR("Invalid Shufflecake mode %d", mode); - err = -EINVAL; - goto bad_mode; - } - - return sdev; - - -bad_mode: -bad_inner: - sflc_sysfs_unregister_device(sdev); -bad_sysfs: -bad_parse: - kfree(sdev); - return ERR_PTR(err); + return 0; } -void sflc_dev_destroy(struct sflc_device *sdev) +void sflc_dev_base_exit(struct sflc_device_base *sd_base) { - switch (sdev->mode) - { - case SFLC_MODE_LEGACY: - sflegc_dev_destroy(sdev->sflegc_dev); - break; - case SFLC_MODE_LITE: - sflite_dev_destroy(sdev->sflite_dev); - break; - default: - DMCRIT("Destroying device with invalid Shufflecake mode %d", sdev->mode); - return; - } - - sflc_sysfs_unregister_device(sdev); - kfree(sdev); + sflc_sysfs_unregister_device_base(sd_base); } -/* Create a sflc_volume containing the appropriate mode-specific struct */ -struct sflc_volume *sflc_vol_create(struct sflc_device *sdev, struct dm_target *ti, - int argc, char **argv) +/* Init a sflc_volume_base */ +int sflc_vol_base_init(struct sflc_volume_base *sv_base, + struct sflc_device_base *sd_base, struct dm_target *ti, + int argc, char **argv) { - struct sflc_volume *svol; u32 vol_idx; - int mode; int err; - svol = kzalloc(sizeof(*svol), GFP_KERNEL); - if (!svol) { - DMERR("Could not allocate volume"); - return ERR_PTR(-ENOMEM); - } - /* Parse arguments */ - if (sscanf(argv[0], "%d", &mode) != 1) { - err = -EINVAL; - goto bad_parse; - } sscanf(argv[3], "%u", &vol_idx); /* Assign fields */ - svol->mode = mode; - sprintf(svol->name, "sflc_%u_%u", sdev->dev_id, vol_idx); - svol->sdev = sdev; + sv_base->vol_idx = vol_idx; + sprintf(sv_base->name, "sflc_%u_%u", sd_base->dev_id, vol_idx); + sv_base->sd_base = sd_base; + /* Field `ops` will be set by the derived constructor */ /* Register with sysfs */ - err = sflc_sysfs_register_volume(svol); + err = sflc_sysfs_register_volume_base(sv_base); if (err) - goto bad_sysfs; + return err; - /* Instantiate inner volume. Sysfs has to be inited by now */ - switch (mode) - { - case SFLC_MODE_LEGACY: - svol->sflegc_vol = sflegc_vol_create(ti, sdev->sflegc_dev, argc, argv, &svol->kobj); - if (IS_ERR(svol->sflegc_vol)) { - err = PTR_ERR(svol->sflegc_vol); - goto bad_inner; - } - svol->tt = &sflegc_target_type; - break; - case SFLC_MODE_LITE: - svol->sflite_vol = sflite_vol_create(ti, sdev->sflite_dev, argc, argv, &svol->kobj); - if (IS_ERR(svol->sflite_vol)) { - err = PTR_ERR(svol->sflite_vol); - goto bad_inner; - } - svol->tt = &sflite_target_type; - break; - default: - DMERR("Invalid Shufflecake mode %d", mode); - err = -EINVAL; - goto bad_mode; - } - - return svol; - - -bad_mode: -bad_inner: - sflc_sysfs_unregister_volume(svol); -bad_sysfs: -bad_parse: - kfree(svol); - return ERR_PTR(err); + return 0; } -void sflc_vol_destroy(struct sflc_volume *svol) +void sflc_vol_base_exit(struct sflc_volume_base *sv_base) { - switch (svol->mode) - { - case SFLC_MODE_LEGACY: - sflegc_vol_destroy(svol->sflegc_vol); - break; - case SFLC_MODE_LITE: - sflite_vol_destroy(svol->sflite_vol); - break; - default: - DMCRIT("Destroying volume with invalid Shufflecake mode %d", svol->mode); - return; - } - - sflc_sysfs_unregister_volume(svol); - kfree(svol); + sflc_sysfs_unregister_volume_base(sv_base); } + diff --git a/dm-sflc/src/legacy/device/device.c b/dm-sflc/src/legacy/device/device.c index 1725d65..e64b613 100644 --- a/dm-sflc/src/legacy/device/device.c +++ b/dm-sflc/src/legacy/device/device.c @@ -33,6 +33,7 @@ #include "legacy/device/device.h" #include "legacy/utils/vector.h" #include "legacy/log/log.h" +#include "sflc.h" #include @@ -63,11 +64,10 @@ static int sflegc_dev_initAndShufflePsiArray(u32 *psi_array, u32 len); * argv[4]: number of 1 MB slices in the underlying device * argv[5]: 32-byte encryption key (hex-encoded) */ -sflegc_Device *sflegc_dev_create(struct dm_target *ti, int argc, char **argv, struct kobject *kobj) +struct sflc_device_base *sflegc_dev_ctr(struct dm_target *ti, int argc, char **argv) { sflegc_Device * dev; u32 tot_slices; - u32 dev_id; int err; int i; @@ -79,25 +79,25 @@ sflegc_Device *sflegc_dev_create(struct dm_target *ti, int argc, char **argv, st goto err_alloc_dev; } + /* Init base part */ + err = sflc_dev_base_init(&dev->sd_base, ti, argc, argv); + if (err) + goto bad_base; + dev->sd_base.mode = SFLC_MODE_LEGACY; + dev->sd_base.ops = &sflc_legacy_ops; + /* Parse args */ if (argc != 6) { pr_err("Wrong argument count"); err = -EINVAL; goto err_parse; } - sscanf(argv[1], "%u", &dev_id); if (sscanf(argv[4], "%u", &tot_slices) != 1) { pr_err("Could not decode tot_slices\n"); err = -EINVAL; goto err_parse; } - /* Init list node here, so it's always safe to list_del() */ - INIT_LIST_HEAD(&dev->list_node); - - /* Set device ID */ - dev->dev_id = dev_id; - /* Set backing real device */ err = dm_get_device(ti, argv[2], dm_table_get_mode(ti->table), &dev->bdev); if (err) { @@ -105,14 +105,6 @@ sflegc_Device *sflegc_dev_create(struct dm_target *ti, int argc, char **argv, st goto err_dm_get_dev; } dev->ti = ti; - /* And its path */ - dev->bdev_path = kmalloc(strlen(argv[2]) + 1, GFP_KERNEL); - if (!dev->bdev_path) { - pr_err("Could not allocate %lu bytes for dev->real_dev_path\n", strlen(argv[2]) + 1); - err = -ENOMEM; - goto err_alloc_real_dev_path; - } - strcpy(dev->bdev_path, argv[2]); /* Init volumes */ for (i = 0; i < SFLEGC_DEV_MAX_VOLUMES; ++i) { @@ -173,14 +165,13 @@ sflegc_Device *sflegc_dev_create(struct dm_target *ti, int argc, char **argv, st INIT_LIST_HEAD(&dev->iv_lru_list); /* Add to sysfs */ - dev->kobj_parent = kobj; err = sflegc_sysfs_add_device(dev); if (err) { pr_err("Could not add device to sysfs; error %d\n", err); goto err_sysfs; } - return dev; + return &dev->sd_base; err_sysfs: @@ -191,35 +182,33 @@ err_initshuffle_psi_array: err_alloc_psi_array: vfree(dev->rmap); err_alloc_rmap: - kfree(dev->bdev_path); -err_alloc_real_dev_path: dm_put_device(ti, dev->bdev); err_dm_get_dev: err_parse: + sflc_dev_base_exit(&dev->sd_base); +bad_base: kfree(dev); err_alloc_dev: return ERR_PTR(err); } -/* Returns false if still busy (not all volumes have been removed). Frees the Device. */ -bool sflegc_dev_destroy(sflegc_Device * dev) +void sflegc_dev_dtr(struct sflc_device_base *sd_base) { + sflegc_Device *dev = container_of(sd_base, sflegc_Device, sd_base); + /* Check if we actually have to put this device */ if (!dev) { - return false; + return; } if (dev->vol_cnt > 0) { pr_warn("Called while still holding %d volumes\n", dev->vol_cnt); - return false; + return; } /* Flush all IVs */ sflegc_dev_flushIvs(dev); - /* List */ - list_del(&dev->list_node); - /* Sysfs */ sflegc_sysfs_remove_device(dev); @@ -234,12 +223,14 @@ bool sflegc_dev_destroy(sflegc_Device * dev) /* Backing device */ dm_put_device(dev->ti, dev->bdev); - kfree(dev->bdev_path); + + /* Base part */ + sflc_dev_base_exit(&dev->sd_base); /* Free the device itself */ kfree(dev); - return true; + return; } diff --git a/dm-sflc/src/legacy/device/device.h b/dm-sflc/src/legacy/device/device.h index a6109e7..63430d6 100644 --- a/dm-sflc/src/legacy/device/device.h +++ b/dm-sflc/src/legacy/device/device.h @@ -50,6 +50,7 @@ typedef struct sflegc_dev_iv_cache_entry_s sflegc_dev_IvCacheEntry; #include +#include "sflc_types.h" #include "legacy/sflc_legacy.h" #include "legacy/volume/volume.h" #include "legacy/crypto/symkey/symkey.h" @@ -101,13 +102,13 @@ struct sflegc_dev_iv_cache_entry_s struct sflegc_device_s { + /* Base device object */ + struct sflc_device_base sd_base; + /* Underlying block device */ struct dm_dev * bdev; - char * bdev_path; /* Target instance that owns the bdev reference */ struct dm_target *ti; - /* Shufflecake-unique numeric ID of this device */ - u32 dev_id; /* All volumes linked to this device */ sflegc_Volume * vol[SFLEGC_DEV_MAX_VOLUMES]; @@ -130,18 +131,12 @@ struct sflegc_device_s u32 vol_header_size; u32 dev_header_size; - /* Parent sysfs directory */ - struct kobject *kobj_parent; - /* LRU cache of IV blocks */ struct mutex iv_cache_lock; wait_queue_head_t iv_cache_waitqueue; sflegc_dev_IvCacheEntry ** iv_cache; u32 iv_cache_nr_entries; struct list_head iv_lru_list; - - /* We keep all devices in a list */ - struct list_head list_node; }; @@ -149,17 +144,9 @@ struct sflegc_device_s * PUBLIC FUNCTIONS PROTOTYPES * *****************************************************/ -/* - * None of these functions acquire the big device lock: it must be held - * by the caller. - */ - -/* Creates Device and adds it to the list. Returns an ERR_PTR() if unsuccessful. */ -sflegc_Device * sflegc_dev_create(struct dm_target *ti, int argc, char **argv, struct kobject *kobj); - -/* Returns false if still busy (not all volumes have been removed) Frees the Device. */ -bool sflegc_dev_destroy(sflegc_Device * dev); +struct sflc_device_base *sflegc_dev_ctr(struct dm_target *ti, int argc, char **argv); +void sflegc_dev_dtr(struct sflc_device_base *sd_base); /* Returns false if volume index was already occupied. */ bool sflegc_dev_addVolume(sflegc_Device * dev, sflegc_Volume * vol, int vol_idx); diff --git a/dm-sflc/src/legacy/sflc_legacy.h b/dm-sflc/src/legacy/sflc_legacy.h index 70f0a95..2a3824f 100644 --- a/dm-sflc/src/legacy/sflc_legacy.h +++ b/dm-sflc/src/legacy/sflc_legacy.h @@ -31,7 +31,7 @@ #include "legacy/volume/volume.h" -extern struct target_type sflegc_target_type; +extern struct sflc_mode_ops sflc_legacy_ops; int sflegc_init(void); diff --git a/dm-sflc/src/legacy/sysfs.c b/dm-sflc/src/legacy/sysfs.c index df6615e..7d567ec 100644 --- a/dm-sflc/src/legacy/sysfs.c +++ b/dm-sflc/src/legacy/sysfs.c @@ -43,13 +43,10 @@ /* Show the total number of slices in a device */ static ssize_t tot_slices_show(struct kobject *kobj, struct kobj_attribute *kattr, char *buf) { - struct sflc_device *top_dev; - sflegc_Device * dev; + struct sflc_device_base *sd_base = container_of(kobj, struct sflc_device_base, kobj); + sflegc_Device * dev = container_of(sd_base, sflegc_Device, sd_base); ssize_t ret; - top_dev = container_of(kobj, struct sflc_device, kobj); - dev = top_dev->sflegc_dev; - /* Write the tot_slices */ ret = sysfs_emit(buf, "%u\n", dev->tot_slices); @@ -59,13 +56,10 @@ static ssize_t tot_slices_show(struct kobject *kobj, struct kobj_attribute *katt /* Show the number of free slices in a device */ static ssize_t free_slices_show(struct kobject *kobj, struct kobj_attribute *kattr, char *buf) { - struct sflc_device *top_dev; - sflegc_Device * dev; + struct sflc_device_base *sd_base = container_of(kobj, struct sflc_device_base, kobj); + sflegc_Device * dev = container_of(sd_base, sflegc_Device, sd_base); ssize_t ret; - top_dev = container_of(kobj, struct sflc_device, kobj); - dev = top_dev->sflegc_dev; - /* Write the free_slices */ if (mutex_lock_interruptible(&dev->slices_lock)) return -ERESTARTSYS; @@ -88,12 +82,12 @@ static const struct attribute_group sflegc_device_attr_group = { int sflegc_sysfs_add_device(sflegc_Device *dev) { - return sysfs_create_group(dev->kobj_parent, &sflegc_device_attr_group); + return sysfs_create_group(&dev->sd_base.kobj, &sflegc_device_attr_group); } void sflegc_sysfs_remove_device(sflegc_Device *dev) { - sysfs_remove_group(dev->kobj_parent, &sflegc_device_attr_group); + sysfs_remove_group(&dev->sd_base.kobj, &sflegc_device_attr_group); } @@ -106,13 +100,10 @@ void sflegc_sysfs_remove_device(sflegc_Device *dev) /* Show the number of mapped slices in a volume */ static ssize_t mapped_slices_show(struct kobject *kobj, struct kobj_attribute *kattr, char *buf) { - struct sflc_volume *top_vol; - sflegc_Volume * vol; + struct sflc_volume_base *sv_base = container_of(kobj, struct sflc_volume_base, kobj); + sflegc_Volume * vol = container_of(sv_base, sflegc_Volume, sv_base); ssize_t ret; - top_vol = container_of(kobj, struct sflc_volume, kobj); - vol = top_vol->sflegc_vol; - /* Write the free_slices */ if (mutex_lock_interruptible(&vol->fmap_lock)) return -ERESTARTSYS; @@ -133,10 +124,10 @@ static const struct attribute_group sflegc_volume_attr_group = { int sflegc_sysfs_add_volume(sflegc_Volume *vol) { - return sysfs_create_group(vol->kobj_parent, &sflegc_volume_attr_group); + return sysfs_create_group(&vol->sv_base.kobj, &sflegc_volume_attr_group); } void sflegc_sysfs_remove_volume(sflegc_Volume *vol) { - sysfs_remove_group(vol->kobj_parent, &sflegc_volume_attr_group); + sysfs_remove_group(&vol->sv_base.kobj, &sflegc_volume_attr_group); } diff --git a/dm-sflc/src/legacy/target.c b/dm-sflc/src/legacy/target.c index 08a0d40..52970b4 100644 --- a/dm-sflc/src/legacy/target.c +++ b/dm-sflc/src/legacy/target.c @@ -55,10 +55,14 @@ static int sflegc_tgt_iterateDevices(struct dm_target *ti, iterate_devices_callo * PUBLIC VARIABLES DEFINITIONS * *****************************************************/ -struct target_type sflegc_target_type = { - .map = sflegc_tgt_map, - .io_hints = sflegc_tgt_ioHints, - .iterate_devices = sflegc_tgt_iterateDevices, +struct sflc_mode_ops sflc_legacy_ops = { + .dev_ctr = sflegc_dev_ctr, + .dev_dtr = sflegc_dev_dtr, + .vol_ctr = sflegc_vol_ctr, + .vol_dtr = sflegc_vol_dtr, + .map = sflegc_tgt_map, + .io_hints = sflegc_tgt_ioHints, + .iterate_devices = sflegc_tgt_iterateDevices, }; /***************************************************** @@ -70,20 +74,22 @@ struct target_type sflegc_target_type = { static int sflegc_tgt_map(struct dm_target *ti, struct bio *bio) { int err; - struct sflc_volume *top_vol = ti->private; - sflegc_Volume *vol = top_vol->sflegc_vol; + struct sflc_volume_base *sv_base = ti->private; + sflegc_Volume *vol = container_of(sv_base, sflegc_Volume, sv_base); - /* If no data, just quickly remap the sector and the block device (no crypto) */ - /* TODO: this is dangerous for deniability, will need more filtering */ - if (unlikely(!bio_has_data(bio))) { - pr_debug("No-data bio: bio_op = %d", bio_op(bio)); - err = sflegc_vol_remapBioFast(vol, bio); - if (err) { - pr_err("Could not remap bio; error %d\n", err); + /* Copied from sflc_lite */ + if (unlikely(bio->bi_opf & REQ_PREFLUSH)) { + /* Has to be empty though */ + if (bio_sectors(bio)) { + DMWARN("Non-empty flush request!"); + //msleep(3000); return DM_MAPIO_KILL; } - return DM_MAPIO_REMAPPED; - } +// DMWARN("REQ_PREFLUSH empty (phew), sector: %llu", bio->bi_iter.bi_sector); +// msleep(100); + bio_set_dev(bio, vol->dev->bdev->bdev); + return DM_MAPIO_REMAPPED; + } /* At this point, the bio has data. Do a few sanity checks */ /* TODO: I think we can get rid of all of them */ @@ -117,11 +123,6 @@ static int sflegc_tgt_map(struct dm_target *ti, struct bio *bio) /* Callback executed to inform the DM about our 4096-byte sector size */ static void sflegc_tgt_ioHints(struct dm_target *ti, struct queue_limits *limits) { - struct sflc_volume *top_vol = ti->private; - sflegc_Volume *vol = top_vol->sflegc_vol; - - pr_info("Called io_hints on volume \"%s\"\n", vol->vol_name); - limits->logical_block_size = SFLEGC_DEV_SECTOR_SIZE; limits->physical_block_size = SFLEGC_DEV_SECTOR_SIZE; @@ -135,11 +136,10 @@ static void sflegc_tgt_ioHints(struct dm_target *ti, struct queue_limits *limits static int sflegc_tgt_iterateDevices(struct dm_target *ti, iterate_devices_callout_fn fn, void *data) { - struct sflc_volume *top_vol = ti->private; - sflegc_Volume *vol = top_vol->sflegc_vol; + struct sflc_volume_base *sv_base = ti->private; + sflegc_Volume *vol = container_of(sv_base, sflegc_Volume, sv_base); sflegc_Device * dev = vol->dev; - pr_debug("Called iterate_devices on volume \"%s\"\n", vol->vol_name); if (!fn) { return -EINVAL; diff --git a/dm-sflc/src/legacy/volume/fmap.c b/dm-sflc/src/legacy/volume/fmap.c index c0ca78c..7f924ae 100644 --- a/dm-sflc/src/legacy/volume/fmap.c +++ b/dm-sflc/src/legacy/volume/fmap.c @@ -137,7 +137,7 @@ int sflegc_vol_loadFmap(sflegc_Volume * vol) } /* Starting block of the position map (skip the DMB, the previous volume headers, and the VMB) */ - sector = 1 + (vol->vol_idx * dev->vol_header_size) + 1; + sector = 1 + (vol->sv_base.vol_idx * dev->vol_header_size) + 1; /* Starting LSI in the fmap */ lsi = 0; @@ -182,7 +182,7 @@ int sflegc_vol_loadFmap(sflegc_Volume * vol) vol->fmap[lsi] = psi; /* Also add it to the device's rmap and to the count, if LSI is actually mapped */ if (psi != SFLEGC_VOL_FMAP_INVALID_PSI) { - sflegc_dev_markPsiTaken(dev, psi, vol->vol_idx); + sflegc_dev_markPsiTaken(dev, psi, vol->sv_base.vol_idx); vol->mapped_slices += 1; } @@ -247,7 +247,7 @@ int sflegc_vol_storeFmap(sflegc_Volume * vol) } /* Starting block of the position map (skip the DMB, the previous volume headers, and the VMB) */ - sector = 1 + (vol->vol_idx * dev->vol_header_size) + 1; + sector = 1 + (vol->sv_base.vol_idx * dev->vol_header_size) + 1; /* Starting LSI in the fmap */ lsi = 0; @@ -366,7 +366,7 @@ static s32 sflegc_vol_mapSlice(sflegc_Volume * vol, u32 lsi, int op) vol->fmap[lsi] = psi; vol->mapped_slices += 1; /* And in the device's rmap */ - sflegc_dev_markPsiTaken(dev, psi, vol->vol_idx); + sflegc_dev_markPsiTaken(dev, psi, vol->sv_base.vol_idx); /* Unlock both maps */ mutex_unlock(&dev->slices_lock); diff --git a/dm-sflc/src/legacy/volume/volume.c b/dm-sflc/src/legacy/volume/volume.c index e229312..f37623d 100644 --- a/dm-sflc/src/legacy/volume/volume.c +++ b/dm-sflc/src/legacy/volume/volume.c @@ -32,6 +32,7 @@ #include "legacy/volume/volume.h" #include "legacy/utils/string.h" #include "legacy/log/log.h" +#include "sflc.h" #include @@ -50,11 +51,12 @@ * argv[4]: number of 1 MB slices in the underlying device * argv[5]: 32-byte encryption key (hex-encoded) */ -sflegc_Volume * sflegc_vol_create(struct dm_target * ti, sflegc_Device* dev, - int argc, char **argv, struct kobject *kobj) +struct sflc_volume_base *sflegc_vol_ctr(struct sflc_device_base *sd_base, + struct dm_target *ti, + int argc, char **argv) { sflegc_Volume * vol; - int vol_idx; + sflegc_Device *dev = container_of(sd_base, sflegc_Device, sd_base); u8 enckey[SFLEGC_SK_KEY_LEN]; int err; @@ -66,17 +68,18 @@ sflegc_Volume * sflegc_vol_create(struct dm_target * ti, sflegc_Device* dev, goto err_alloc_vol; } + /* Init base part */ + err = sflc_vol_base_init(&vol->sv_base, sd_base, ti, argc, argv); + if (err) + goto bad_base; + vol->sv_base.ops = &sflc_legacy_ops; + /* Parse args */ if (argc != 6) { pr_err("Wrong argument count"); err = -EINVAL; goto err_parse; } - if (sscanf(argv[3], "%u", &vol_idx) != 1) { - pr_err("Could not decode tot_slices\n"); - err = -EINVAL; - goto err_parse; - } /* Decode the encryption key */ if (strlen(argv[5]) != 2 * SFLEGC_SK_KEY_LEN) { pr_err("Hexadecimal key (length %lu): %s\n", strlen(argv[5]), argv[5]); @@ -90,11 +93,7 @@ sflegc_Volume * sflegc_vol_create(struct dm_target * ti, sflegc_Device* dev, goto err_parse; } - /* Set volume name */ - sprintf(vol->vol_name, "sflc_%u_%d", dev->dev_id, vol_idx); - /* Sysfs stuff */ - vol->kobj_parent = kobj; err = sflegc_sysfs_add_volume(vol); if (err) { pr_err("Could not add volume to sysfs; error %d\n", err); @@ -102,13 +101,12 @@ sflegc_Volume * sflegc_vol_create(struct dm_target * ti, sflegc_Device* dev, } /* Backing device */ - if (!sflegc_dev_addVolume(dev, vol, vol_idx)) { + if (!sflegc_dev_addVolume(dev, vol, vol->sv_base.vol_idx)) { pr_err("Could not add volume to device\n"); err = -EINVAL; goto err_add_to_dev; } vol->dev = dev; - vol->vol_idx = vol_idx; /* Crypto */ vol->skctx = sflegc_sk_createContext(enckey); @@ -131,13 +129,11 @@ sflegc_Volume * sflegc_vol_create(struct dm_target * ti, sflegc_Device* dev, vol->mapped_slices = 0; /* Initialise fmap */ - pr_notice("Volume opening for volume %s: loading fmap from header\n", vol->vol_name); err = sflegc_vol_loadFmap(vol); if (err) { pr_err("Could not load position map; error %d\n", err); goto err_load_fmap; } - pr_debug("Successfully loaded position map for volume %s\n", vol->vol_name); /* Tell DM we want one SFLC sector at a time */ @@ -152,7 +148,7 @@ sflegc_Volume * sflegc_vol_create(struct dm_target * ti, sflegc_Device* dev, TODO: will need to support them to release slice mappings */ ti->num_discard_bios = 0; - return vol; + return &vol->sv_base; err_load_fmap: @@ -160,28 +156,29 @@ err_load_fmap: err_alloc_fmap: sflegc_sk_destroyContext(vol->skctx); err_create_skctx: - sflegc_dev_removeVolume(vol->dev, vol->vol_idx); + sflegc_dev_removeVolume(vol->dev, vol->sv_base.vol_idx); err_add_to_dev: sflegc_sysfs_remove_volume(vol); err_sysfs: err_parse: + sflc_vol_base_exit(&vol->sv_base); +bad_base: kfree(vol); err_alloc_vol: return ERR_PTR(err); } /* Removes the volume from the device and frees it. */ -void sflegc_vol_destroy(sflegc_Volume * vol) +void sflegc_vol_dtr(struct sflc_volume_base *sv_base) { + sflegc_Volume *vol = container_of(sv_base, sflegc_Volume, sv_base); int err; /* Store fmap */ - pr_notice("Going to store position map of volume %s\n", vol->vol_name); err = sflegc_vol_storeFmap(vol); if (err) { pr_err("Could not store position map; error %d\n", err); } - pr_debug("Successfully stored position map of volume %s\n", vol->vol_name); /* Free it */ vfree(vol->fmap); @@ -189,11 +186,14 @@ void sflegc_vol_destroy(sflegc_Volume * vol) sflegc_sk_destroyContext(vol->skctx); /* Remove from device */ - sflegc_dev_removeVolume(vol->dev, vol->vol_idx); + sflegc_dev_removeVolume(vol->dev, vol->sv_base.vol_idx); /* Destroy sysfs entries */ sflegc_sysfs_remove_volume(vol); + /* Base part */ + sflc_vol_base_exit(&vol->sv_base); + /* Free volume structure */ kfree(vol); diff --git a/dm-sflc/src/legacy/volume/volume.h b/dm-sflc/src/legacy/volume/volume.h index 3222433..c61de66 100644 --- a/dm-sflc/src/legacy/volume/volume.h +++ b/dm-sflc/src/legacy/volume/volume.h @@ -47,6 +47,7 @@ typedef struct sflegc_volume_s sflegc_Volume; #include +#include "sflc_types.h" #include "legacy/sflc_legacy.h" #include "legacy/device/device.h" #include "legacy/crypto/symkey/symkey.h" @@ -103,13 +104,11 @@ struct sflegc_vol_decrypt_work_s struct sflegc_volume_s { - /* Name of the volume, sflc__*/ - char vol_name[SFLEGC_VOL_NAME_MAX_LEN + 1]; + /* Base volume object */ + struct sflc_volume_base sv_base; /* Backing device */ sflegc_Device * dev; - /* Index of this volume within the device's volume array */ - u32 vol_idx; /* Forward position map */ struct mutex fmap_lock; @@ -117,8 +116,6 @@ struct sflegc_volume_s /* Stats on the fmap */ u32 mapped_slices; - /* Parent sysfs directory */ - struct kobject *kobj_parent; /* Crypto */ sflegc_sk_Context * skctx; @@ -129,11 +126,10 @@ struct sflegc_volume_s * PUBLIC FUNCTIONS PROTOTYPES * *****************************************************/ -/* Creates volume and adds it to the device. Returns an ERR_PTR() if unsuccessful */ -sflegc_Volume * sflegc_vol_create(struct dm_target * ti, sflegc_Device* dev, - int argc, char **argv, struct kobject *kobj); -/* Removes the volume from the device and frees it. */ -void sflegc_vol_destroy(sflegc_Volume * vol); +struct sflc_volume_base *sflegc_vol_ctr(struct sflc_device_base *sd_base, + struct dm_target *ti, + int argc, char **argv); +void sflegc_vol_dtr(struct sflc_volume_base *sv_base); /* Remaps the underlying block device and the sector number */ int sflegc_vol_remapBioFast(sflegc_Volume * vol, struct bio * bio); diff --git a/dm-sflc/src/lite/device.c b/dm-sflc/src/lite/device.c index e62aa54..cd10ef0 100644 --- a/dm-sflc/src/lite/device.c +++ b/dm-sflc/src/lite/device.c @@ -26,6 +26,7 @@ #include #include #include "sflc_lite.h" +#include "sflc.h" @@ -55,11 +56,9 @@ static void fisheryates_u32(u32 *v, u32 len) * argv[4]: number of 1 MB slices in the underlying device * argv[5]: 64-byte encryption key (hex-encoded) */ -struct sflite_device *sflite_dev_create(struct dm_target *ti, int argc, char **argv, struct kobject *kobj) +struct sflc_device_base *sflite_dev_ctr(struct dm_target *ti, int argc, char **argv) { struct sflite_device *sdev; - dev_t devt; - u32 dev_id; u32 tot_slices; int i; int err; @@ -70,29 +69,25 @@ struct sflite_device *sflite_dev_create(struct dm_target *ti, int argc, char **a return ERR_PTR(-ENOMEM); } + /* Init base part */ + err = sflc_dev_base_init(&sdev->sd_base, ti, argc, argv); + if (err) + goto bad_base; + sdev->sd_base.mode = SFLC_MODE_LITE; + sdev->sd_base.ops = &sflc_lite_ops; + /* Parse args */ if (argc != 6) { - pr_err("Wrong argument count"); + DMERR("Wrong argument count"); err = -EINVAL; goto bad_parse; } - sscanf(argv[1], "%u", &dev_id); if (sscanf(argv[4], "%u", &tot_slices) != 1) { - pr_err("Could not decode tot_slices\n"); + DMERR("Could not decode tot_slices"); err = -EINVAL; goto bad_parse; } - sdev->dev_id = dev_id; - - /* Look up block device and set name */ - err = lookup_bdev(argv[2], &devt); - if (err) { - DMERR("Could not look up block device"); - goto bad_lookup; - } - format_dev_t(sdev->name, devt); - /* Compute sizes */ sdev->tot_slices = tot_slices; sdev->nr_free_slices = tot_slices; @@ -143,7 +138,7 @@ struct sflite_device *sflite_dev_create(struct dm_target *ti, int argc, char **a /* I/O workqueue */ sdev->io_queue = alloc_workqueue("sflite_%s_io", WQ_MEM_RECLAIM | WQ_CPU_INTENSIVE, - 0, sdev->name); + 0, sdev->sd_base.name); if (!sdev->io_queue) { err = -ENOMEM; DMERR("Could not allocate I/O workqueue"); @@ -152,7 +147,7 @@ struct sflite_device *sflite_dev_create(struct dm_target *ti, int argc, char **a /* Decryption workqueue */ sdev->crypt_queue = alloc_workqueue("sflite_%s_crypt", WQ_MEM_RECLAIM | WQ_CPU_INTENSIVE, - 0, sdev->name); + 0, sdev->sd_base.name); if (!sdev->crypt_queue) { err = -ENOMEM; DMERR("Could not allocate decryption workqueue"); @@ -160,12 +155,11 @@ struct sflite_device *sflite_dev_create(struct dm_target *ti, int argc, char **a } /* Add to sysfs, once initialised */ - sdev->kobj_parent = kobj; err = sflite_sysfs_add_device(sdev); if (err) goto bad_sysfs; - return sdev; + return &sdev->sd_base; bad_sysfs: @@ -181,15 +175,18 @@ bad_bioset: bad_prmslices: vfree(sdev->slices_ofld); bad_ofld: -bad_lookup: bad_parse: + sflc_dev_base_exit(&sdev->sd_base); +bad_base: kfree(sdev); return ERR_PTR(err); } -void sflite_dev_destroy(struct sflite_device *sdev) +void sflite_dev_dtr(struct sflc_device_base *sd_base) { + struct sflite_device *sdev = container_of(sd_base, struct sflite_device, sd_base); + sflite_sysfs_remove_device(sdev); destroy_workqueue(sdev->crypt_queue); destroy_workqueue(sdev->io_queue); @@ -197,6 +194,7 @@ void sflite_dev_destroy(struct sflite_device *sdev) bioset_exit(&sdev->bioset); vfree(sdev->prmslices); vfree(sdev->slices_ofld); + sflc_dev_base_exit(&sdev->sd_base); kfree(sdev); return; diff --git a/dm-sflc/src/lite/posmap.c b/dm-sflc/src/lite/posmap.c index 3ee2551..8a2e412 100644 --- a/dm-sflc/src/lite/posmap.c +++ b/dm-sflc/src/lite/posmap.c @@ -311,7 +311,7 @@ static int _deserialise_and_sanitise_posmap(struct sflite_volume *svol) /* If PSI already taken, sample a new one */ if (sdev->slices_ofld[psi]) { DMWARN("Corruption of volume %u: LSI %u was evicted from PSI %u", - svol->vol_idx, lsi, psi); + svol->sv_base.vol_idx, lsi, psi); err = peek_next_free_psi(sdev, &psi); if (err) return err; diff --git a/dm-sflc/src/lite/sflc_lite.c b/dm-sflc/src/lite/sflc_lite.c index edc245f..f17adf7 100644 --- a/dm-sflc/src/lite/sflc_lite.c +++ b/dm-sflc/src/lite/sflc_lite.c @@ -41,9 +41,9 @@ static int sflite_map(struct dm_target *ti, struct bio *bio) { + struct sflc_volume_base *sv_base = ti->private; + struct sflite_volume *svol = container_of(sv_base, struct sflite_volume, sv_base); struct sflite_io *sio = dm_per_bio_data(bio, sizeof(struct sflite_io)); - struct sflc_volume *top_vol = ti->private; - struct sflite_volume *svol = top_vol->sflite_vol; sector_t lblk_num = bio->bi_iter.bi_sector >> SFLITE_BLOCK_SHIFT; if (unlikely(!bio_has_data(bio))) { @@ -116,8 +116,8 @@ static void sflite_io_hints(struct dm_target *ti, struct queue_limits *limits) static int sflite_iterate_devices(struct dm_target *ti, iterate_devices_callout_fn fn, void *data) { - struct sflc_volume *top_vol = ti->private; - struct sflite_volume *svol = top_vol->sflite_vol; + struct sflc_volume_base *sv_base = ti->private; + struct sflite_volume *svol = container_of(sv_base, struct sflite_volume, sv_base); struct sflite_device *sdev = svol->sdev; if (!fn) { @@ -129,7 +129,11 @@ static int sflite_iterate_devices(struct dm_target *ti, iterate_devices_callout_ } -struct target_type sflite_target_type = { +struct sflc_mode_ops sflc_lite_ops = { + .dev_ctr = sflite_dev_ctr, + .dev_dtr = sflite_dev_dtr, + .vol_ctr = sflite_vol_ctr, + .vol_dtr = sflite_vol_dtr, .map = sflite_map, .io_hints = sflite_io_hints, .iterate_devices = sflite_iterate_devices, diff --git a/dm-sflc/src/lite/sflc_lite.h b/dm-sflc/src/lite/sflc_lite.h index 1c2e5a7..59becb7 100644 --- a/dm-sflc/src/lite/sflc_lite.h +++ b/dm-sflc/src/lite/sflc_lite.h @@ -29,6 +29,7 @@ #include #include #include "sflite_constants.h" +#include "sflc_types.h" #include "sflc_constants.h" @@ -40,10 +41,8 @@ struct sflite_device { - /* Shufflecake-unique device ID */ - u32 dev_id; - /* : */ - char name[16]; + /* Base device object */ + struct sflc_device_base sd_base; /* Logical size of each volume */ u32 tot_slices; @@ -58,9 +57,6 @@ struct sflite_device bool *slices_ofld; u32 nr_free_slices; - /* Parent sysfs directory */ - struct kobject *kobj_parent; - /* Resource sharing */ struct bio_set bioset; struct dm_io_client *io_client; @@ -70,6 +66,9 @@ struct sflite_device struct sflite_volume { + /* Base volume object */ + struct sflc_volume_base sv_base; + /* Backing device */ struct sflite_device *sdev; @@ -78,24 +77,17 @@ struct sflite_volume struct dm_dev *dm_dev; struct dm_target *ti; - /* Volume index within the device */ - u32 vol_idx; - /* Volume name: sflite__ */ - char name[32]; - /* Position map */ struct mutex posmap_lock; u32 *posmap; u32 nr_mapped_slices; - /* Parent sysfs directory */ - struct kobject *kobj_parent; - /* Crypto */ u8 enckey[SFLITE_XTS_KEYLEN]; struct crypto_skcipher *tfm; }; +/* Per-bio data */ struct sflite_io { struct sflite_volume *svol; @@ -119,7 +111,7 @@ struct sflite_io /* Starting sector of position map */ #define SFLITE_POSMAP_START_SECTOR(svol) \ (SFLITE_BLOCK_SCALE * (1 + SFLITE_DEV_MAX_VOLUMES) + \ - (svol)->vol_idx * (svol)->sdev->posmap_size_sectors) + (svol)->sv_base.vol_idx * (svol)->sdev->posmap_size_sectors) /* Physical sector of a remapped bio */ @@ -136,7 +128,7 @@ struct sflite_io *---------------------------- */ -extern struct target_type sflite_target_type; +extern struct sflc_mode_ops sflc_lite_ops; /* @@ -150,13 +142,14 @@ int sflite_init(void); void sflite_exit(void); /* Device */ -struct sflite_device *sflite_dev_create(struct dm_target *ti, int argc, char **argv, struct kobject *kobj); -void sflite_dev_destroy(struct sflite_device *sdev); +struct sflc_device_base *sflite_dev_ctr(struct dm_target *ti, int argc, char **argv); +void sflite_dev_dtr(struct sflc_device_base *sd_base); /* Volume */ -struct sflite_volume *sflite_vol_create(struct dm_target *ti, struct sflite_device *sdev, - int argc, char **argv, struct kobject *kobj); -void sflite_vol_destroy(struct sflite_volume *svol); +struct sflc_volume_base *sflite_vol_ctr(struct sflc_device_base *sd_base, + struct dm_target *ti, + int argc, char **argv); +void sflite_vol_dtr(struct sflc_volume_base *sv_base); /* Sysfs */ int sflite_sysfs_add_device(struct sflite_device *sdev); diff --git a/dm-sflc/src/lite/sysfs.c b/dm-sflc/src/lite/sysfs.c index 88e2d06..6c15b66 100644 --- a/dm-sflc/src/lite/sysfs.c +++ b/dm-sflc/src/lite/sysfs.c @@ -34,16 +34,16 @@ static ssize_t tot_slices_show(struct kobject *kobj, struct kobj_attribute *kattr, char *buf) { - struct sflc_device *top_dev = container_of(kobj, struct sflc_device, kobj); - struct sflite_device *sdev = top_dev->sflite_dev; + struct sflc_device_base *sd_base = container_of(kobj, struct sflc_device_base, kobj); + struct sflite_device *sdev = container_of(sd_base, struct sflite_device, sd_base); return sysfs_emit(buf, "%u\n", sdev->tot_slices); } static ssize_t free_slices_show(struct kobject *kobj, struct kobj_attribute *kattr, char *buf) { - struct sflc_device *top_dev = container_of(kobj, struct sflc_device, kobj); - struct sflite_device *sdev = top_dev->sflite_dev; + struct sflc_device_base *sd_base = container_of(kobj, struct sflc_device_base, kobj); + struct sflite_device *sdev = container_of(sd_base, struct sflite_device, sd_base); int ret; if (mutex_lock_interruptible(&sdev->slices_lock)) @@ -67,12 +67,12 @@ static const struct attribute_group sflite_device_attr_group = { int sflite_sysfs_add_device(struct sflite_device *sdev) { - return sysfs_create_group(sdev->kobj_parent, &sflite_device_attr_group); + return sysfs_create_group(&sdev->sd_base.kobj, &sflite_device_attr_group); } void sflite_sysfs_remove_device(struct sflite_device *sdev) { - sysfs_remove_group(sdev->kobj_parent, &sflite_device_attr_group); + sysfs_remove_group(&sdev->sd_base.kobj, &sflite_device_attr_group); } @@ -84,8 +84,8 @@ void sflite_sysfs_remove_device(struct sflite_device *sdev) static ssize_t mapped_slices_show(struct kobject *kobj, struct kobj_attribute *kattr, char *buf) { - struct sflc_volume *top_vol = container_of(kobj, struct sflc_volume, kobj); - struct sflite_volume *svol = top_vol->sflite_vol; + struct sflc_volume_base *sv_base = container_of(kobj, struct sflc_volume_base, kobj); + struct sflite_volume *svol = container_of(sv_base, struct sflite_volume, sv_base); int ret; if (mutex_lock_interruptible(&svol->posmap_lock)) @@ -107,10 +107,10 @@ static const struct attribute_group sflite_volume_attr_group = { int sflite_sysfs_add_volume(struct sflite_volume *svol) { - return sysfs_create_group(svol->kobj_parent, &sflite_volume_attr_group); + return sysfs_create_group(&svol->sv_base.kobj, &sflite_volume_attr_group); } void sflite_sysfs_remove_volume(struct sflite_volume *svol) { - sysfs_remove_group(svol->kobj_parent, &sflite_volume_attr_group); + sysfs_remove_group(&svol->sv_base.kobj, &sflite_volume_attr_group); } diff --git a/dm-sflc/src/lite/volume.c b/dm-sflc/src/lite/volume.c index e37d9c1..26717b9 100644 --- a/dm-sflc/src/lite/volume.c +++ b/dm-sflc/src/lite/volume.c @@ -23,6 +23,7 @@ #include #include "sflc_lite.h" +#include "sflc.h" /** @@ -34,11 +35,12 @@ * argv[4]: number of 1 MB slices in the underlying device * argv[5]: 64-byte encryption key (hex-encoded) */ -struct sflite_volume *sflite_vol_create(struct dm_target *ti, struct sflite_device* sdev, - int argc, char **argv, struct kobject *kobj) +struct sflc_volume_base *sflite_vol_ctr(struct sflc_device_base *sd_base, + struct dm_target *ti, + int argc, char **argv) { struct sflite_volume *svol; - u32 vol_idx; + struct sflite_device *sdev = container_of(sd_base, struct sflite_device, sd_base); int err; svol = kzalloc(sizeof(*svol), GFP_KERNEL); @@ -47,17 +49,18 @@ struct sflite_volume *sflite_vol_create(struct dm_target *ti, struct sflite_devi return ERR_PTR(-ENOMEM); } + /* Init base part */ + err = sflc_vol_base_init(&svol->sv_base, sd_base, ti, argc, argv); + if (err) + goto bad_base; + svol->sv_base.ops = &sflc_lite_ops; + /* Parse arguments */ if (argc != 6) { DMERR("Wrong argument count"); err = -EINVAL; goto bad_parse; } - if (sscanf(argv[3], "%u", &vol_idx) != 1) { - DMERR("Could not decode tot_slices\n"); - err = -EINVAL; - goto bad_parse; - } /* Decode the encryption key */ if (strlen(argv[5]) != 2 * SFLITE_XTS_KEYLEN) { DMERR("Invalid key length"); @@ -72,11 +75,9 @@ struct sflite_volume *sflite_vol_create(struct dm_target *ti, struct sflite_devi } svol->sdev = sdev; - svol->vol_idx = vol_idx; - sprintf(svol->name, "sflc_%u_%u", sdev->dev_id, vol_idx); svol->ti = ti; - err = dm_get_device(ti, sdev->name, + err = dm_get_device(ti, sdev->sd_base.name, dm_table_get_mode(ti->table), &svol->dm_dev); if (err) { ti->error = "Device lookup failed"; @@ -114,7 +115,6 @@ struct sflite_volume *sflite_vol_create(struct dm_target *ti, struct sflite_devi } /* Add to sysfs, once initialised */ - svol->kobj_parent = kobj; err = sflite_sysfs_add_volume(svol); if (err) { DMERR("Could not register volume with sysfs; error %d", err); @@ -133,7 +133,7 @@ struct sflite_volume *sflite_vol_create(struct dm_target *ti, struct sflite_devi ti->per_io_data_size = sizeof(struct sflite_io); ti->private = svol; - return svol; + return &svol->sv_base; bad_sysfs: @@ -146,17 +146,22 @@ bad_tfm_alloc: dm_put_device(ti, svol->dm_dev); bad_dm_dev: bad_parse: + sflc_vol_base_exit(&svol->sv_base); +bad_base: kfree(svol); return ERR_PTR(err); } -void sflite_vol_destroy(struct sflite_volume *svol) +void sflite_vol_dtr(struct sflc_volume_base *sv_base) { + struct sflite_volume *svol = container_of(sv_base, struct sflite_volume, sv_base); + sflite_sysfs_remove_volume(svol); vfree(svol->posmap); crypto_free_skcipher(svol->tfm); dm_put_device(svol->ti, svol->dm_dev); + sflc_vol_base_exit(&svol->sv_base); kfree(svol); return; diff --git a/dm-sflc/src/sflc.c b/dm-sflc/src/sflc.c index 1a7e802..76b0f0e 100644 --- a/dm-sflc/src/sflc.c +++ b/dm-sflc/src/sflc.c @@ -32,14 +32,22 @@ #include -// Global variables +/* Global variables */ + +// A set of algorithms for each Shufflecake mode, in the same order as the modes. +struct sflc_mode_ops *sflc_all_mode_ops[SFLC_NR_MODES] = { + &sflc_legacy_ops, + &sflc_lite_ops +}; + +// Global array of base device objects DEFINE_MUTEX(sflc_alldevs_lock); -struct sflc_device **sflc_alldevs = NULL; +struct sflc_device_base **sflc_alldevs = NULL; u32 sflc_free_devid = 0; /* The lowest free devID */ /* Add a device to the global array, and advance next_dev_id */ -static int sflc_add_device_global(u32 dev_id, struct sflc_device *sdev) +static int sflc_add_device_global(u32 dev_id, struct sflc_device_base *sd_base) { int i; @@ -54,7 +62,7 @@ static int sflc_add_device_global(u32 dev_id, struct sflc_device *sdev) return -EINVAL; } // Add to the global array, and advance free_devid - sflc_alldevs[dev_id] = sdev; + sflc_alldevs[dev_id] = sd_base; for (i = sflc_free_devid; i < SFLC_MAX_DEVS && sflc_alldevs[i]; i++); sflc_free_devid = i; @@ -86,10 +94,12 @@ static void sflc_remove_device_global(u32 dev_id) */ static int sflc_ctr(struct dm_target *ti, unsigned int argc, char **argv) { + u32 mode; + struct sflc_mode_ops *mode_ops; u32 dev_id; u32 vol_idx; - struct sflc_device *sdev; - struct sflc_volume *svol; + struct sflc_device_base *sd_base; + struct sflc_volume_base *sv_base; int err; /* Parse arguments */ @@ -97,6 +107,10 @@ static int sflc_ctr(struct dm_target *ti, unsigned int argc, char **argv) ti->error = "Invalid argument count"; return -EINVAL; } + if (sscanf(argv[0], "%u", &mode) != 1) { + ti->error = "Could not decode mode"; + return -EINVAL; + } if (sscanf(argv[1], "%u", &dev_id) != 1) { ti->error = "Could not decode device ID"; return -EINVAL; @@ -106,6 +120,10 @@ static int sflc_ctr(struct dm_target *ti, unsigned int argc, char **argv) return -EINVAL; } /* Sanity checks */ + if (mode >= SFLC_NR_MODES) { + ti->error = "Mode out of bounds"; + return -EINVAL; + } if (dev_id >= SFLC_MAX_DEVS) { ti->error = "Device ID out of bounds"; return -EINVAL; @@ -114,16 +132,18 @@ static int sflc_ctr(struct dm_target *ti, unsigned int argc, char **argv) ti->error = "Volume index out of bounds"; return -EINVAL; } + /* Grab the correct mode */ + mode_ops = sflc_all_mode_ops[mode]; /* Create device, if this is the first volume, otherwise retrieve it */ if (vol_idx == 0) { - sdev = sflc_dev_create(ti, argc, argv); - if (IS_ERR(sdev)) { + sd_base = mode_ops->dev_ctr(ti, argc, argv); + if (IS_ERR(sd_base)) { ti->error = "Could not instantiate device"; - return PTR_ERR(sdev); + return PTR_ERR(sd_base); } /* Insert in global array */ - err = sflc_add_device_global(dev_id, sdev); + err = sflc_add_device_global(dev_id, sd_base); if (err) { ti->error = "Could not add device to global array"; goto bad_dev_global; @@ -131,26 +151,26 @@ static int sflc_ctr(struct dm_target *ti, unsigned int argc, char **argv) } else { if (mutex_lock_interruptible(&sflc_alldevs_lock)) return -ERESTARTSYS; - sdev = sflc_alldevs[dev_id]; + sd_base = sflc_alldevs[dev_id]; mutex_unlock(&sflc_alldevs_lock); - if (!sdev) { + if (!sd_base) { ti->error = "Could not find device with specified ID"; return -EINVAL; } } /* Create volume */ - svol = sflc_vol_create(sdev, ti, argc, argv); - if (IS_ERR(svol)) { + sv_base = mode_ops->vol_ctr(sd_base, ti, argc, argv); + if (IS_ERR(sv_base)) { ti->error = "Could not instantiate volume"; - err = PTR_ERR(svol); + err = PTR_ERR(sv_base); goto bad_vol_create; } /* We expect ->ctr() calls to be strictly sequential, so we don't need locking */ - sdev->nr_volumes++; + sd_base->nr_volumes++; - ti->private = svol; + ti->private = sv_base; return 0; @@ -159,7 +179,7 @@ bad_vol_create: if (vol_idx == 0) { sflc_remove_device_global(dev_id); bad_dev_global: - sflc_dev_destroy(sdev); + mode_ops->dev_dtr(sd_base); } return err; } @@ -168,16 +188,16 @@ bad_dev_global: /* Destroy volume and, if needed, the underlying device */ static void sflc_dtr(struct dm_target *ti) { - struct sflc_volume *svol = ti->private; - struct sflc_device *sdev = svol->sdev; + struct sflc_volume_base *sv_base = ti->private; + struct sflc_device_base *sd_base = sv_base->sd_base; - sflc_vol_destroy(svol); + sv_base->ops->vol_dtr(sv_base); /* We expect ->dtr() calls to be strictly sequential, so we don't need locking */ - sdev->nr_volumes--; + sd_base->nr_volumes--; - if (sdev->nr_volumes == 0) { - sflc_remove_device_global(sdev->dev_id); - sflc_dev_destroy(sdev); + if (sd_base->nr_volumes == 0) { + sflc_remove_device_global(sd_base->dev_id); + sd_base->ops->dev_dtr(sd_base); } return; @@ -186,21 +206,21 @@ static void sflc_dtr(struct dm_target *ti) static int sflc_map(struct dm_target *ti, struct bio *bio) { - struct sflc_volume *svol = ti->private; - return svol->tt->map(ti, bio); + struct sflc_volume_base *sv_base = ti->private; + return sv_base->ops->map(ti, bio); } static void sflc_io_hints(struct dm_target *ti, struct queue_limits *limits) { - struct sflc_volume *svol = ti->private; - svol->tt->io_hints(ti, limits); + struct sflc_volume_base *sv_base = ti->private; + return sv_base->ops->io_hints(ti, limits); return; } static int sflc_iterate_devices(struct dm_target *ti, iterate_devices_callout_fn fn, void *data) { - struct sflc_volume *svol = ti->private; - return svol->tt->iterate_devices(ti, fn, data); + struct sflc_volume_base *sv_base = ti->private; + return sv_base->ops->iterate_devices(ti, fn, data); } diff --git a/dm-sflc/src/sflc.h b/dm-sflc/src/sflc.h index 1ff8499..a3459ca 100644 --- a/dm-sflc/src/sflc.h +++ b/dm-sflc/src/sflc.h @@ -27,58 +27,8 @@ #include +#include "sflc_types.h" #include "sflc_constants.h" -#include "legacy/sflc_legacy.h" -#include "lite/sflc_lite.h" - - -/* - *---------------------------- - * Structs - *---------------------------- - */ - -struct sflc_device -{ - /* Shufflecake-unique device ID */ - u32 dev_id; - /* : */ - char name[16]; - /* Number of volumes */ - u32 nr_volumes; - - /* Mode-specific device struct */ - int mode; - union { - sflegc_Device *sflegc_dev; - struct sflite_device *sflite_dev; - }; - - /* Sysfs */ - struct kobject kobj; - struct completion kobj_released; -}; - -struct sflc_volume -{ - /* Backing device */ - struct sflc_device *sdev; - /* Volume name: sflc__ */ - char name[32]; - - /* Mode-specific volume struct */ - int mode; - union { - sflegc_Volume *sflegc_vol; - struct sflite_volume *sflite_vol; - }; - /* Pointers to concrete, mode-specific callbacks */ - struct target_type *tt; - - /* Sysfs */ - struct kobject kobj; - struct completion kobj_released; -}; /* @@ -87,8 +37,12 @@ struct sflc_volume *---------------------------- */ +/* Every mode provides a full set of algorithms */ +extern struct sflc_mode_ops *sflc_all_mode_ops[SFLC_NR_MODES]; + +/* Array of all open devices */ extern struct mutex sflc_alldevs_lock; -extern struct sflc_device **sflc_alldevs; +extern struct sflc_device_base **sflc_alldevs; /* Next free device id */ extern u32 sflc_free_devid; /* The lowest free devID */ @@ -99,22 +53,24 @@ extern u32 sflc_free_devid; /* The lowest free devID */ *---------------------------- */ -/* Device */ -struct sflc_device *sflc_dev_create(struct dm_target *ti, int argc, char **argv); -void sflc_dev_destroy(struct sflc_device *sdev); +/* Device base */ +int sflc_dev_base_init(struct sflc_device_base *sd_base, struct dm_target *ti, + int argc, char **argv); +void sflc_dev_base_exit(struct sflc_device_base *sd_base); -/* Volume */ -struct sflc_volume *sflc_vol_create(struct sflc_device *sdev, struct dm_target *ti, - int argc, char **argv); -void sflc_vol_destroy(struct sflc_volume *svol); +/* Volume base */ +int sflc_vol_base_init(struct sflc_volume_base *sv_base, + struct sflc_device_base *sd_base, struct dm_target *ti, + int argc, char **argv); +void sflc_vol_base_exit(struct sflc_volume_base *sv_base); /* Sysfs */ int sflc_sysfs_init(void); void sflc_sysfs_exit(void); -int sflc_sysfs_register_device(struct sflc_device *sdev); -void sflc_sysfs_unregister_device(struct sflc_device *sdev); -int sflc_sysfs_register_volume(struct sflc_volume *svol); -void sflc_sysfs_unregister_volume(struct sflc_volume *svol); +int sflc_sysfs_register_device_base(struct sflc_device_base *sd_base); +void sflc_sysfs_unregister_device_base(struct sflc_device_base *sd_base); +int sflc_sysfs_register_volume_base(struct sflc_volume_base *sv_base); +void sflc_sysfs_unregister_volume_base(struct sflc_volume_base *sv_base); #endif /* _SFLC_H */ diff --git a/dm-sflc/src/sflc_constants.h b/dm-sflc/src/sflc_constants.h index c978796..e02d71d 100644 --- a/dm-sflc/src/sflc_constants.h +++ b/dm-sflc/src/sflc_constants.h @@ -33,8 +33,8 @@ #define SFLC_VER_MAJOR 0 #define SFLC_VER_MINOR 5 -#define SFLC_VER_REVISION 0 -#define SFLC_VER_SPECIAL "rc1" +#define SFLC_VER_REVISION 1 +#define SFLC_VER_SPECIAL "" #define STRINGIFY0(s) # s #define STRINGIFY(s) STRINGIFY0(s) @@ -45,6 +45,7 @@ /* Each device can be formatted and used with a mode of choice, irrespective of the other devices */ #define SFLC_MODE_LEGACY 0 #define SFLC_MODE_LITE 1 +#define SFLC_NR_MODES 2 /* Max number of volumes per device */ diff --git a/dm-sflc/src/sflc_types.h b/dm-sflc/src/sflc_types.h new file mode 100644 index 0000000..d2927cd --- /dev/null +++ b/dm-sflc/src/sflc_types.h @@ -0,0 +1,155 @@ +/* + * Copyright The Shufflecake Project Authors (2022) + * Copyright The Shufflecake Project Contributors (2022) + * Copyright Contributors to the The Shufflecake Project. + * + * See the AUTHORS file at the top-level directory of this distribution and at + * + * + * This file is part of the program shufflecake-c, which is part of the + * Shufflecake Project. Shufflecake is a plausible deniability (hidden storage) + * layer for Linux. See . + * + * This program is free software: you can redistribute it and/or modify it + * under the terms of the GNU General Public License as published by the Free + * Software Foundation, either version 2 of the License, or (at your option) + * any later version. This program is distributed in the hope that it will be + * useful, but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General + * Public License for more details. You should have received a copy of the + * GNU General Public License along with this program. + * If not, see . + */ + +/** + * This kernel module implements Shufflecake as an in-kernel device driver, + * built on top of the device-mapper framework. + * Shufflecake supports several "modes" (currently Legacy and Lite). Each mode + * is a distinct set of algorithms which implements a specific flavour of the + * Shufflecake scheme; they are very different and largely incompatible with + * each other. For this reason, each mode has its own independent, complete + * implementation - located in a subdirectory of the root - and exposes a + * standardised interface to the top-level "dispatcher", which only takes care + * of the few bookkeeping tasks which are common to all modes, and displays a + * unified view to user space through the sysfs. + * + * In order to achieve an intuitive and maintainable separation between the + * dispatcher and the modes, a "lightweight" OOP-style coding convention is + * followed: not fully general, but just enough to allow for one-level class + * inheritance and type-checked method polymorphism. + * Base "classes" exist to represent devices and volumes (see Shufflecake docs + * to learn what these terms mean): they are structs containing the fields + * needed by the dispatcher for its bookkeeping. Derived "classes" exist to + * represent mode-specific devices and volumes: they are structs embedding a + * base-class struct "by-value", plus their own specific fields. + * Type-checked polymorphism is achieved by having device and volume methods + * take as argument a pointer to a base-class struct, instead of an opaque void + * pointer. The pointer is then "down-cast" in the mode-specific method. + */ + +#ifndef _SFLC_TYPES_H +#define _SFLC_TYPES_H + + +#include + +#include "sflc_constants.h" + + +/* + *---------------------------- + * Structs + *---------------------------- + */ + +/** + * The virtual table. + * Contains all the concrete method pointers provided by a Shufflecake mode + * (devices + volumes + devmapper). + * It is a field in the base class, but will be set by the constructor of the + * derived class. + */ +struct sflc_mode_ops; + +/** + * Base class for devices. + * It is inherited by derived classes for mode-specific devices. + */ +struct sflc_device_base +{ + /* Shufflecake-unique device ID */ + u32 dev_id; + /* : */ + char name[16]; + /* Shufflecake mode: legacy/lite */ + u32 mode; + /* Number of (open) volumes */ + u32 nr_volumes; + + /* Sysfs */ + struct kobject kobj; + struct completion kobj_released; + + /* Virtual table */ + struct sflc_mode_ops *ops; +}; + +/** + * Base class for volumes. + * It is inherited by derived classes for mode-specific volumes. + */ +struct sflc_volume_base +{ + /* Backing device */ + struct sflc_device_base *sd_base; + + /* Volume index within the device */ + u32 vol_idx; + /* Volume name: sflc__ */ + char name[32]; + + /* Sysfs */ + struct kobject kobj; + struct completion kobj_released; + + /* Virtual table */ + struct sflc_mode_ops *ops; +}; + + +/* + *---------------------------- + * Methods + *---------------------------- + */ + +/* Device constructor */ +typedef struct sflc_device_base* (*sflc_mode_dev_ctr_fn) ( + struct dm_target *ti, int argc, char **argv); +/* Device destructor */ +typedef void (*sflc_mode_dev_dtr_fn) (struct sflc_device_base* sd_base); + +/* Volume constructor */ +typedef struct sflc_volume_base* (*sflc_mode_vol_ctr_fn) ( + struct sflc_device_base *sd_base, struct dm_target *ti, + int argc, char **argv); +/* Volume destructor */ +typedef void (*sflc_mode_vol_dtr_fn) (struct sflc_volume_base* sv_base); + +/** + * A Shufflecake mode must provide ctr() and dtr() for devices and volumes, + * as well as devmapper-related methods. + */ +struct sflc_mode_ops +{ + sflc_mode_dev_ctr_fn dev_ctr; + sflc_mode_dev_dtr_fn dev_dtr; + sflc_mode_vol_ctr_fn vol_ctr; + sflc_mode_vol_dtr_fn vol_dtr; + dm_map_fn map; + dm_io_hints_fn io_hints; + dm_iterate_devices_fn iterate_devices; +}; + + +#endif /* _SFLC_TYPES_H */ diff --git a/dm-sflc/src/sysfs.c b/dm-sflc/src/sysfs.c index 2ef402d..9782ca8 100644 --- a/dm-sflc/src/sysfs.c +++ b/dm-sflc/src/sysfs.c @@ -87,16 +87,16 @@ void sflc_sysfs_exit() static ssize_t dev_id_show(struct kobject *kobj, struct kobj_attribute *kattr, char *buf) { - struct sflc_device *sdev = container_of(kobj, struct sflc_device, kobj); + struct sflc_device_base *sd_base = container_of(kobj, struct sflc_device_base, kobj); - return sysfs_emit(buf, "%u\n", sdev->dev_id); + return sysfs_emit(buf, "%u\n", sd_base->dev_id); } static ssize_t volumes_show(struct kobject *kobj, struct kobj_attribute *kattr, char *buf) { - struct sflc_device *sdev = container_of(kobj, struct sflc_device, kobj); + struct sflc_device_base *sd_base = container_of(kobj, struct sflc_device_base, kobj); - return sysfs_emit(buf, "%u\n", sdev->nr_volumes); + return sysfs_emit(buf, "%u\n", sd_base->nr_volumes); } @@ -109,47 +109,47 @@ static struct attribute *sflc_device_default_attrs[] = { }; ATTRIBUTE_GROUPS(sflc_device_default); -static void sflc_device_kobj_release(struct kobject *kobj) +static void sflc_device_base_kobj_release(struct kobject *kobj) { - struct sflc_device *sdev = container_of(kobj, struct sflc_device, kobj); - complete(&sdev->kobj_released); + struct sflc_device_base *sd_base = container_of(kobj, struct sflc_device_base, kobj); + complete(&sd_base->kobj_released); } -static struct kobj_type sflc_device_ktype = { - .release = sflc_device_kobj_release, +static struct kobj_type sflc_device_base_ktype = { + .release = sflc_device_base_kobj_release, .sysfs_ops = &kobj_sysfs_ops, .default_groups = sflc_device_default_groups }; -int sflc_sysfs_register_device(struct sflc_device *sdev) +int sflc_sysfs_register_device_base(struct sflc_device_base *sd_base) { int err; /* Completion */ - init_completion(&sdev->kobj_released); + init_completion(&sd_base->kobj_released); /* Register directory :/ under bdevs/ */ - sdev->kobj.kset = bdevs_kset; - err = kobject_init_and_add(&sdev->kobj, &sflc_device_ktype, NULL, - "%s", sdev->name); + sd_base->kobj.kset = bdevs_kset; + err = kobject_init_and_add(&sd_base->kobj, &sflc_device_base_ktype, NULL, + "%s", sd_base->name); if (err) goto bad; /* Emit uevent */ - kobject_uevent(&sdev->kobj, KOBJ_ADD); + kobject_uevent(&sd_base->kobj, KOBJ_ADD); return 0; bad: - kobject_put(&sdev->kobj); - wait_for_completion(&sdev->kobj_released); + kobject_put(&sd_base->kobj); + wait_for_completion(&sd_base->kobj_released); return err; } -void sflc_sysfs_unregister_device(struct sflc_device *sdev) +void sflc_sysfs_unregister_device_base(struct sflc_device_base *sd_base) { - kobject_put(&sdev->kobj); - wait_for_completion(&sdev->kobj_released); + kobject_put(&sd_base->kobj); + wait_for_completion(&sd_base->kobj_released); } @@ -159,45 +159,47 @@ void sflc_sysfs_unregister_device(struct sflc_device *sdev) *---------------------------- */ -static void sflc_volume_kobj_release(struct kobject *kobj) +static void sflc_volume_base_kobj_release(struct kobject *kobj) { - struct sflc_volume *svol = container_of(kobj, struct sflc_volume, kobj); + struct sflc_volume_base *sv_base = container_of(kobj, struct sflc_volume_base, kobj); - complete(&svol->kobj_released); + complete(&sv_base->kobj_released); } -static struct kobj_type sflc_volume_ktype = { - .release = sflc_volume_kobj_release, +static struct kobj_type sflc_volume_base_ktype = { + .release = sflc_volume_base_kobj_release, .sysfs_ops = &kobj_sysfs_ops, }; -int sflc_sysfs_register_volume(struct sflc_volume *svol) +int sflc_sysfs_register_volume_base(struct sflc_volume_base *sv_base) { int err; /* Completion */ - init_completion(&svol->kobj_released); + init_completion(&sv_base->kobj_released); /* Register directory name>/ under device directory */ - err = kobject_init_and_add(&svol->kobj, &sflc_volume_ktype, &svol->sdev->kobj, - "%s", svol->name); + err = kobject_init_and_add(&sv_base->kobj, &sflc_volume_base_ktype, + &sv_base->sd_base->kobj, + "%s", sv_base->name); if (err) goto bad; /* Emit uevent */ - kobject_uevent(&svol->kobj, KOBJ_ADD); + kobject_uevent(&sv_base->kobj, KOBJ_ADD); return 0; bad: - kobject_put(&svol->kobj); - wait_for_completion(&svol->kobj_released); + kobject_put(&sv_base->kobj); + wait_for_completion(&sv_base->kobj_released); return err; } -void sflc_sysfs_unregister_volume(struct sflc_volume *svol) +void sflc_sysfs_unregister_volume_base(struct sflc_volume_base *sv_base) { - kobject_put(&svol->kobj); - wait_for_completion(&svol->kobj_released); + kobject_put(&sv_base->kobj); + wait_for_completion(&sv_base->kobj_released); } + diff --git a/resources/images/badges/badge_version_0.5.0.png b/resources/images/badges/badge_version_0.5.0.png deleted file mode 100644 index 869a324..0000000 Binary files a/resources/images/badges/badge_version_0.5.0.png and /dev/null differ diff --git a/resources/images/badges/badge_version_0.5.1.png b/resources/images/badges/badge_version_0.5.1.png new file mode 100644 index 0000000..63b0346 Binary files /dev/null and b/resources/images/badges/badge_version_0.5.1.png differ diff --git a/resources/images/badges/badges.svg b/resources/images/badges/badges.svg index 254bb97..32b9e6a 100644 --- a/resources/images/badges/badges.svg +++ b/resources/images/badges/badges.svg @@ -29,8 +29,8 @@ inkscape:document-units="mm" showgrid="false" inkscape:zoom="2.7438272" - inkscape:cx="234.16198" - inkscape:cy="198.26321" + inkscape:cx="234.52643" + inkscape:cy="227.41957" inkscape:window-width="1920" inkscape:window-height="975" inkscape:window-x="0" @@ -333,7 +333,7 @@ height="5.2916675" x="61.548569" y="79.569435" - inkscape:export-filename="badge_version_0.5.0.png" + inkscape:export-filename="badge_version_0.5.1.png" inkscape:export-xdpi="96" inkscape:export-ydpi="96" /> 0.5.0 + y="83.4077">0.5.1