diff --git a/dist/dattobd.spec b/dist/dattobd.spec index c10b4d7a..f1c2dfc8 100644 --- a/dist/dattobd.spec +++ b/dist/dattobd.spec @@ -117,7 +117,7 @@ Name: dattobd -Version: 0.11.9 +Version: 0.11.10 Release: 1%{?dist} Summary: Kernel module and utilities for enabling low-level live backups Vendor: Datto, Inc. @@ -320,6 +320,13 @@ sed -e "s:@prefix@:%{_prefix}:g" \ # Generate symbols for library package (Debian/Ubuntu only) %if "%{_vendor}" == "debbuild" mkdir -p %{buildroot}/%{libname}/DEBIAN + +# Ubuntu 24.04 LTS have broken dpkg-gensymbols usage without debian/control file. So, let us emulate it. +%if 0%{?ubuntu} && 0%{?ubuntu} >= 2404 +mkdir debian +touch debian/control +%endif + dpkg-gensymbols -P%{buildroot} -p%{libname} -v%{version}-%{release} -e%{buildroot}%{_libdir}/%{libprefix}.so.%{?!libsover:0}%{?libsover} -e%{buildroot}%{_libdir}/%{libprefix}.so.%{?!libsover:0}%{?libsover}.* -O%{buildroot}/%{libname}/DEBIAN/symbols %endif @@ -425,6 +432,10 @@ if [ "$1" -ge "1" ]; then if [ -f /usr/lib/dkms/common.postinst ]; then /usr/lib/dkms/common.postinst %{name} %{version} exit $? + else + dkms add -m %{name} -v %{version} %{?rpm_dkms_opt:--rpm_safe_upgrade} + dkms install -m %{name} -v %{version} --force + exit $? fi fi diff --git a/src/bdev_state_handler.c b/src/bdev_state_handler.c index 8e582e2c..0bb13bb2 100644 --- a/src/bdev_state_handler.c +++ b/src/bdev_state_handler.c @@ -65,7 +65,7 @@ int __handle_bdev_mount_nowrite(const struct vfsmount *mnt, { if (!dev || !test_bit(ACTIVE, &dev->sd_state) || tracer_read_fail_state(dev) || - dev->sd_base_dev != mnt->mnt_sb->s_bdev) + dev->sd_base_dev->bdev != mnt->mnt_sb->s_bdev) continue; if (mnt == dev->sd_cow->dfilp->mnt) { @@ -105,7 +105,7 @@ int __handle_bdev_mount_writable(const char *dir_name, int ret; unsigned int i; struct snap_device *dev; - struct block_device *cur_bdev; + struct bdev_wrapper *cur_bdev; LOG_DEBUG("ENTER %s", __func__); tracer_for_each(dev, i) @@ -121,7 +121,7 @@ int __handle_bdev_mount_writable(const char *dir_name, if (test_bit(UNVERIFIED, &dev->sd_state)) { // get the block device for the unverified tracer we are // looking into - cur_bdev = dattodb_blkdev_by_path(dev->sd_bdev_path, + cur_bdev = dattobd_blkdev_by_path(dev->sd_bdev_path, FMODE_READ, NULL); if (IS_ERR(cur_bdev)) { cur_bdev = NULL; @@ -130,7 +130,7 @@ int __handle_bdev_mount_writable(const char *dir_name, // if the tracer's block device exists and matches the // one being mounted perform transition - if (cur_bdev == bdev) { + if (cur_bdev->bdev == bdev) { LOG_DEBUG("block device mount detected for " "unverified device %d", i); @@ -144,7 +144,7 @@ int __handle_bdev_mount_writable(const char *dir_name, // put the block device dattobd_blkdev_put(cur_bdev); - } else if (dev->sd_base_dev == bdev) { + } else if (dev->sd_base_dev->bdev == bdev) { LOG_DEBUG( "block device mount detected for dormant device %d", i); @@ -259,15 +259,15 @@ void post_umount_check(int dormant_ret, int umount_ret, unsigned int idx, // if we successfully went dormant, but the umount call failed, // reactivate if (umount_ret) { - struct block_device *bdev; - bdev = dattodb_blkdev_by_path(dev->sd_bdev_path, FMODE_READ, NULL); - if (!bdev || IS_ERR(bdev)) { + struct bdev_wrapper *bdev_w; + bdev_w = dattobd_blkdev_by_path(dev->sd_bdev_path, FMODE_READ, NULL); + if (IS_ERR_OR_NULL(bdev_w)) { LOG_DEBUG("device gone, moving to error state"); tracer_set_fail_state(dev, -ENODEV); return; } - dattobd_blkdev_put(bdev); + dattobd_blkdev_put(bdev_w); LOG_DEBUG("umount call failed, reactivating tracer %u", idx); auto_transition_active(idx, dir_name); @@ -279,7 +279,7 @@ void post_umount_check(int dormant_ret, int umount_ret, unsigned int idx, // if we went dormant, but the block device is still mounted somewhere, // goto fail state - sb = dattobd_get_super(dev->sd_base_dev); + sb = dattobd_get_super(dev->sd_base_dev->bdev); if (sb) { if (!(sb->s_flags & MS_RDONLY)) { LOG_ERROR( diff --git a/src/blkdev.c b/src/blkdev.c index 8a0fa6eb..29ed5624 100644 --- a/src/blkdev.c +++ b/src/blkdev.c @@ -6,8 +6,9 @@ #include "blkdev.h" #include "logging.h" +#include -#if !defined HAVE_BLKDEV_GET_BY_PATH && !defined HAVE_BLKDEV_GET_BY_PATH_4 +#if !defined HAVE_BLKDEV_GET_BY_PATH && !defined HAVE_BLKDEV_GET_BY_PATH_4 && !defined HAVE_BDEV_OPEN_BY_PATH && !defined HAVE_BDEV_FILE_OPEN_BY_PATH /** * dattobd_lookup_bdev() - Looks up the inode associated with the path, verifies @@ -91,30 +92,44 @@ static struct block_device *_blkdev_get_by_path(const char *pathname, fmode_t mo #endif /** - * dattodb_blkdev_by_path() - Fetches the @block_device struct associated with the + * dattobd_blkdev_by_path() - Fetches the @block_device struct associated with the * @path. This function uses different methods based on available kernel functions - * to retrieve the block device. + * to retrieve the block device. Returns @bdev_handle struct which contains + * information about @block_device and @holder. Made to be in compliance with kernel + * version 6.8+ standard. * * @path: the path name of a block special file. * @mode: The mode used to open the block special file, likely just FMODE_READ. * @holder: unused. * * Return: - * On success the @block_device structure otherwise an error created via + * On success the @bdev_handle structure otherwise an error created via * ERR_PTR(). */ -struct block_device *dattodb_blkdev_by_path(const char *path, fmode_t mode, +struct bdev_wrapper *dattobd_blkdev_by_path(const char *path, fmode_t mode, void *holder) { -#if defined HAVE_BLKDEV_GET_BY_PATH_4 - return blkdev_get_by_path(path, mode, holder, NULL); + struct bdev_wrapper *bw = kmalloc(sizeof(struct bdev_wrapper), GFP_KERNEL); -#elif defined HAVE_BLKDEV_GET_BY_PATH - return blkdev_get_by_path(path, mode, holder); + if(IS_ERR_OR_NULL(bw)){ + return ERR_PTR(-ENOMEM); + } +#if defined HAVE_BDEV_OPEN_BY_PATH + bw->_internal.handle = bdev_open_by_path(path, mode, holder, NULL); + bw->bdev = bw->_internal.handle->bdev; +#elif defined HAVE_BLKDEV_GET_BY_PATH_4 + bw->bdev = blkdev_get_by_path(path, mode, holder, NULL); +#elif defined HAVE_BLKDEV_GET_BY_PATH + bw->bdev = blkdev_get_by_path(path, mode, holder); +#elif defined HAVE_BDEV_FILE_OPEN_BY_PATH + bw->_internal.file = bdev_file_open_by_path(path, mode, holder, NULL); + bw->bdev = file_bdev(bw->_internal.file); #else - return _blkdev_get_by_path(path, mode, holder); + bw->bdev = _blkdev_get_by_path(path, mode, holder); #endif + + return bw; } /** @@ -131,13 +146,15 @@ struct super_block *dattobd_get_super(struct block_device * bd) { #if defined HAVE_BD_SUPER return (bd != NULL) ? bd->bd_super : NULL; - #elif defined HAVE_GET_SUPER return get_super(bdev); - -#else +#elif LINUX_VERSION_CODE >= KERNEL_VERSION(6,6,0) + return (struct super_block*)(bd -> bd_holder); +#elif GET_ACTIVE_SUPER_ADDR != 0 struct super_block* (*get_active_superblock)(struct block_device*)= (GET_ACTIVE_SUPER_ADDR != 0) ? (struct super_block* (*)(struct block_device*))(GET_ACTIVE_SUPER_ADDR +(long long)(((void*)kfree)-(void*)KFREE_ADDR)):NULL; return get_active_superblock(bd); +#else + #error "Could not determine super block of block device" #endif } @@ -155,12 +172,14 @@ void dattobd_drop_super(struct super_block *sb) { #if defined HAVE_BD_SUPER return; - #elif defined HAVE_GET_SUPER return drop_super(sb); - -#else +#elif LINUX_VERSION_CODE >= KERNEL_VERSION(6,6,0) + return; +#elif GET_ACTIVE_SUPER_ADDR != 0 return; +#else + #error "Could not determine super block of block device" #endif } @@ -169,22 +188,30 @@ void dattobd_drop_super(struct super_block *sb) * This function performs the appropriate action based on the available * kernel functions to release block device. * - * @bd: block device structure pointer to be released. + * @bh: bdev_handle structure pointer to be released. * * Return: * void. */ -void dattobd_blkdev_put(struct block_device *bd) +void dattobd_blkdev_put(struct bdev_wrapper *bw) { -#if defined HAVE_BLKDEV_PUT_1 - return blkdev_put(bd); - + if(unlikely(IS_ERR_OR_NULL(bw))) + return; + +#ifdef USE_BDEV_AS_FILE + if(bw->_internal.file) + bdev_fput(bw->_internal.file); +#elif defined HAVE_BDEV_RELEASE + if(bw->_internal.handle) + bdev_release(bw->_internal.handle); +#elif defined HAVE_BLKDEV_PUT_1 + blkdev_put(bw->bdev); #elif defined HAVE_BLKDEV_PUT_2 - return blkdev_put(bd,NULL); - + blkdev_put(bw->bdev, NULL); #else - return blkdev_put(bd, FMODE_READ); + blkdev_put(bw->bdev, FMODE_READ); #endif + kfree(bw); } /** @@ -219,7 +246,7 @@ int dattobd_get_start_sect_by_gendisk_for_bio(struct gendisk* gd, u8 partno, sec LOG_ERROR(-1, "Unreachable code."); return -1; #else - #error Could not determine starting sector of partition by gendisk and partition number + #error "Could not determine starting sector of partition by gendisk and partition number" #endif } diff --git a/src/blkdev.h b/src/blkdev.h index f1b7fe14..62838c7d 100644 --- a/src/blkdev.h +++ b/src/blkdev.h @@ -7,6 +7,7 @@ #ifndef BLKDEV_H_ #define BLKDEV_H_ +#include "config.h" #include "includes.h" struct block_device; @@ -16,6 +17,21 @@ struct block_device; #define bdev_whole(bdev) ((bdev)->bd_contains) #endif +struct bdev_wrapper{ + struct block_device* bdev; + + union { +#ifdef HAVE_BDEV_HANDLE + struct bdev_handle* handle; +#endif +// Kernel 6.9+ manages block_device with struct file and file_bdev has to be used to find block_device from file. +// For us, file_bdev function is marker to check if we have to use +#ifdef USE_BDEV_AS_FILE + struct file* file; +#endif + } _internal; +}; + #ifndef HAVE_HD_STRUCT //#if LINUX_VERSION_CODE < KERNEL_VERSION(5,11,0) #define dattobd_bdev_size(bdev) (bdev_nr_sectors(bdev)) @@ -27,14 +43,14 @@ struct block_device; #endif -struct block_device *dattodb_blkdev_by_path(const char *path, fmode_t mode, +struct bdev_wrapper *dattobd_blkdev_by_path(const char *path, fmode_t mode, void *holder); struct super_block *dattobd_get_super(struct block_device * bd); void dattobd_drop_super(struct super_block *sb); -void dattobd_blkdev_put(struct block_device *bd); +void dattobd_blkdev_put(struct bdev_wrapper *bd); int dattobd_get_start_sect_by_gendisk_for_bio(struct gendisk* gd, u8 partno, sector_t* result); diff --git a/src/config.h b/src/config.h new file mode 100644 index 00000000..5bbaa749 --- /dev/null +++ b/src/config.h @@ -0,0 +1,5 @@ +#if defined HAVE_BDEV_FILE_OPEN_BY_PATH && defined HAVE_FILE_BDEV + +#define USE_BDEV_AS_FILE + +#endif \ No newline at end of file diff --git a/src/configure-tests/feature-tests/bdev_file_open_by_path.c b/src/configure-tests/feature-tests/bdev_file_open_by_path.c new file mode 100644 index 00000000..0f89e5a4 --- /dev/null +++ b/src/configure-tests/feature-tests/bdev_file_open_by_path.c @@ -0,0 +1,19 @@ +// SPDX-License-Identifier: GPL-2.0-only + +/* + * Copyright (C) 2024 Datto Inc. + */ + +#include "includes.h" + +MODULE_LICENSE("GPL"); + +static inline void dummy(void){ + struct file *file __attribute__ ((unused)) = NULL; + const char *path = ""; + fmode_t mode = 0; + void *holder = NULL; + struct blk_holder_ops h; + + file = bdev_file_open_by_path(path, mode, holder, &h); +} diff --git a/src/configure-tests/feature-tests/bdev_freeze.c b/src/configure-tests/feature-tests/bdev_freeze.c new file mode 100644 index 00000000..5ad78b0d --- /dev/null +++ b/src/configure-tests/feature-tests/bdev_freeze.c @@ -0,0 +1,15 @@ +// SPDX-License-Identifier: GPL-2.0-only + +/* + * Copyright (C) 2024 Datto Inc. + */ + +#include "includes.h" + +MODULE_LICENSE("GPL"); + +static inline void dummy(void){ + struct block_device bh; + + bdev_freeze(&bh); +} diff --git a/src/configure-tests/feature-tests/bdev_handle.c b/src/configure-tests/feature-tests/bdev_handle.c new file mode 100644 index 00000000..33deaf72 --- /dev/null +++ b/src/configure-tests/feature-tests/bdev_handle.c @@ -0,0 +1,19 @@ +// SPDX-License-Identifier: GPL-2.0-only + +/* + * Copyright (C) 2024 Datto Inc. + */ + +#include "includes.h" + +MODULE_LICENSE("GPL"); + +static inline void dummy(void){ + struct bdev_handle bh; + + struct block_device bd; + int holder; + + bh.bdev = &bd; + bh.holder = (void*)&holder; +} diff --git a/src/configure-tests/feature-tests/bdev_open_by_path.c b/src/configure-tests/feature-tests/bdev_open_by_path.c new file mode 100644 index 00000000..01ad9e2e --- /dev/null +++ b/src/configure-tests/feature-tests/bdev_open_by_path.c @@ -0,0 +1,20 @@ +// SPDX-License-Identifier: GPL-2.0-only + +/* + * Copyright (C) 2024 Datto Inc. + */ + +#include "includes.h" + +MODULE_LICENSE("GPL"); + +static inline void dummy(void){ + struct bdev_handle* bh; + + const char *path; + blk_mode_t mode; + int holder; + const struct blk_holder_ops bho; + + bh = bdev_open_by_path(path, mode, (void*)&holder, &bho); +} diff --git a/src/configure-tests/feature-tests/bdev_release.c b/src/configure-tests/feature-tests/bdev_release.c new file mode 100644 index 00000000..875d9afc --- /dev/null +++ b/src/configure-tests/feature-tests/bdev_release.c @@ -0,0 +1,15 @@ +// SPDX-License-Identifier: GPL-2.0-only + +/* + * Copyright (C) 2024 Datto Inc. + */ + +#include "includes.h" + +MODULE_LICENSE("GPL"); + +static inline void dummy(void){ + struct bdev_handle bh; + + bdev_release(&bh); +} diff --git a/src/configure-tests/feature-tests/bdev_thaw.c b/src/configure-tests/feature-tests/bdev_thaw.c new file mode 100644 index 00000000..cba21b44 --- /dev/null +++ b/src/configure-tests/feature-tests/bdev_thaw.c @@ -0,0 +1,15 @@ +// SPDX-License-Identifier: GPL-2.0-only + +/* + * Copyright (C) 2024 Datto Inc. + */ + +#include "includes.h" + +MODULE_LICENSE("GPL"); + +static inline void dummy(void){ + struct block_device bh; + + bdev_thaw(&bh); +} diff --git a/src/configure-tests/feature-tests/file_bdev.c b/src/configure-tests/feature-tests/file_bdev.c new file mode 100644 index 00000000..dea572d2 --- /dev/null +++ b/src/configure-tests/feature-tests/file_bdev.c @@ -0,0 +1,16 @@ +// SPDX-License-Identifier: GPL-2.0-only + +/* + * Copyright (C) 2024 Datto Inc. + */ + +#include "includes.h" + +MODULE_LICENSE("GPL"); + +static inline void dummy(void){ + struct block_device* __attribute__ ((unused)) bd; + struct file* file = NULL; + + bd = file_bdev(file); +} diff --git a/src/configure-tests/feature-tests/vm_area_struct_vm_lock.c b/src/configure-tests/feature-tests/vm_area_struct_vm_lock.c new file mode 100644 index 00000000..0be8b093 --- /dev/null +++ b/src/configure-tests/feature-tests/vm_area_struct_vm_lock.c @@ -0,0 +1,16 @@ +// SPDX-License-Identifier: GPL-2.0-only + +/* + * Copyright (C) 2024 Datto Inc. + */ + +#include "includes.h" + +MODULE_LICENSE("GPL"); + +static inline void dummy(void){ + struct vm_area_struct *vma; + struct vma_lock vma_lock; + + vma->vm_lock = &vma_lock; +} diff --git a/src/configure-tests/symbol-tests b/src/configure-tests/symbol-tests index 66c18d7f..43326659 100644 --- a/src/configure-tests/symbol-tests +++ b/src/configure-tests/symbol-tests @@ -9,3 +9,4 @@ vm_area_free insert_vm_struct vm_area_cachep get_active_super +vma_lock_cachep diff --git a/src/cow_manager.c b/src/cow_manager.c index ccc2aec2..1352fd28 100644 --- a/src/cow_manager.c +++ b/src/cow_manager.c @@ -957,7 +957,7 @@ static int __cow_write_data(struct cow_manager *cm, void *buf) if(cm->auto_expand){ kstatfs_ret = 0; if(cm->dev && cm->dev->sd_base_dev){ - kstatfs_ret = dattobd_get_kstatfs(cm->dev->sd_base_dev, &kstatfs); + kstatfs_ret = dattobd_get_kstatfs(cm->dev->sd_base_dev->bdev, &kstatfs); } if(!kstatfs_ret){ @@ -1138,7 +1138,6 @@ int cow_get_file_extents(struct snap_device* dev, struct file* filp) ret = insert_vm_struct(task->mm, vma); if (ret < 0) { - ret = -EINVAL; LOG_ERROR(ret, "insert_vm_struct() failed"); dattobd_vm_area_free(vma); dattobd_mm_unlock(task->mm); @@ -1147,7 +1146,6 @@ int cow_get_file_extents(struct snap_device* dev, struct file* filp) pg = alloc_pages(GFP_USER, get_order(cow_ext_buf_size)); if (!pg) { - ret = -ENOMEM; LOG_ERROR(ret, "alloc_page() failed"); dattobd_vm_area_free(vma); dattobd_mm_unlock(task->mm); diff --git a/src/dattobd.h b/src/dattobd.h index f780b853..29344854 100644 --- a/src/dattobd.h +++ b/src/dattobd.h @@ -15,7 +15,7 @@ #include #include -#define DATTOBD_VERSION "0.11.9" +#define DATTOBD_VERSION "0.11.10" #define DATTO_IOCTL_MAGIC 0x91 struct setup_params { diff --git a/src/filesystem.c b/src/filesystem.c index e3a6d46c..3ee58e09 100644 --- a/src/filesystem.c +++ b/src/filesystem.c @@ -9,6 +9,7 @@ #include "logging.h" #include "userspace_copy_helpers.h" #include "snap_device.h" +#include "blkdev.h" // if this isn't defined, we don't need it anyway #ifndef FMODE_NONOTIFY @@ -920,7 +921,7 @@ int __file_unlink(struct dattobd_mutable_file *dfilp, int close, int force) //#if LINUX_VERSION_CODE >= KERNEL_VERSION(5,12,0) ret = vfs_unlink(&init_user_ns, dir_inode, file_dentry, NULL); #elif defined HAVE_USER_NAMESPACE_ARGS_2 - ret = vfs_unlink(file_mnt_idmap(filp), dir_inode, file_dentry, NULL); + ret = vfs_unlink(file_mnt_idmap(dfilp->filp), dir_inode, file_dentry, NULL); #else ret = vfs_unlink(dir_inode, file_dentry, NULL); #endif @@ -1022,6 +1023,9 @@ void dattobd_inode_unlock(struct inode *inode) struct kmem_cache **vm_area_cache = (VM_AREA_CACHEP_ADDR != 0) ? (struct kmem_cache **) (VM_AREA_CACHEP_ADDR + (long long)(((void *)kfree) - (void *)KFREE_ADDR)) : NULL; +struct kmem_cache **vma_lock_cache = (VMA_LOCK_CACHEP_ADDR != 0) ? + (struct kmem_cache **) (VMA_LOCK_CACHEP_ADDR + (long long)(((void *)kfree) - (void *)KFREE_ADDR)) : NULL; + struct vm_area_struct* dattobd_vm_area_allocate(struct mm_struct* mm) { struct vm_area_struct *vma; @@ -1037,6 +1041,17 @@ struct vm_area_struct* dattobd_vm_area_allocate(struct mm_struct* mm) return NULL; } +#ifdef HAVE_VM_AREA_STRUCT_VM_LOCK + vma->vm_lock = kmem_cache_zalloc(*vma_lock_cache, GFP_KERNEL); + if (!vma->vm_lock) { + LOG_ERROR(-ENOMEM, "kmem_cache_zalloc() failed"); + kmem_cache_free(*vm_area_cache, vma); + return NULL; + } + init_rwsem(&vma->vm_lock->lock); + vma->vm_lock_seq = -1; +#endif + vma->vm_mm = mm; vma->vm_ops = &dummy_vm_ops; INIT_LIST_HEAD(&vma->anon_vma_chain); @@ -1105,7 +1120,7 @@ int file_write_block(struct snap_device* dev, const void* block, size_t offset, ret = 0; bs = dev_bioset(dev); - bdev = dev->sd_base_dev; + bdev = dev->sd_base_dev->bdev; sectors_processed = 0; write_bio: @@ -1212,7 +1227,7 @@ int file_read_block(struct snap_device* dev, void* block, size_t offset, size_t ret = 0; bs = dev_bioset(dev); - bdev = dev->sd_base_dev; + bdev = dev->sd_base_dev->bdev; sectors_processed = 0; WARN_ON(len > SECTORS_PER_BLOCK); diff --git a/src/includes.h b/src/includes.h index aab13256..8ce60ab1 100644 --- a/src/includes.h +++ b/src/includes.h @@ -25,6 +25,7 @@ #include #include #include +#include #include #endif diff --git a/src/ioctl_handlers.c b/src/ioctl_handlers.c index 8b93c179..696b6087 100644 --- a/src/ioctl_handlers.c +++ b/src/ioctl_handlers.c @@ -97,24 +97,24 @@ static int __verify_minor(unsigned int minor, int mode) int __verify_bdev_writable(const char *bdev_path, int *out) { int writable = 0; - struct block_device *bdev; + struct bdev_wrapper *bdev_w; struct super_block *sb; // open the base block device - bdev = dattodb_blkdev_by_path(bdev_path, FMODE_READ, NULL); + bdev_w = dattobd_blkdev_by_path(bdev_path, FMODE_READ, NULL); - if (IS_ERR(bdev)) { + if (IS_ERR(bdev_w)) { *out = 0; - return PTR_ERR(bdev); + return PTR_ERR(bdev_w); } - sb = dattobd_get_super(bdev); + sb = dattobd_get_super(bdev_w->bdev); if (sb) { writable = !(sb->s_flags & MS_RDONLY); dattobd_drop_super(sb); } - dattobd_blkdev_put(bdev); + dattobd_blkdev_put(bdev_w); *out = writable; return 0; } diff --git a/src/snap_device.h b/src/snap_device.h index f3df0d3f..cea2d669 100644 --- a/src/snap_device.h +++ b/src/snap_device.h @@ -13,6 +13,7 @@ #include "includes.h" #include "submit_bio.h" #include "sset_queue.h" +#include "blkdev.h" // macros for defining the state of a tracing struct (bit offsets) #define SNAPSHOT 0 @@ -55,7 +56,7 @@ struct snap_device { sector_t sd_size; // size of device in sectors struct request_queue *sd_queue; // snap device request queue struct gendisk *sd_gd; // snap device gendisk - struct block_device *sd_base_dev; // device being snapshot + struct bdev_wrapper *sd_base_dev; // device being snapshot char *sd_bdev_path; // base device file path struct cow_manager *sd_cow; // cow manager char *sd_cow_path; // cow file path diff --git a/src/snap_handle.c b/src/snap_handle.c index 530a9c5b..3d864ba9 100644 --- a/src/snap_handle.c +++ b/src/snap_handle.c @@ -125,7 +125,7 @@ int snap_handle_read_bio(const struct snap_device *dev, struct bio *bio) bio_orig_size = bio_size(bio); bio_orig_sect = bio_sector(bio); - dattobd_bio_set_dev(bio, dev->sd_base_dev); + dattobd_bio_set_dev(bio, dev->sd_base_dev->bdev); dattobd_set_bio_ops(bio, REQ_OP_READ, READ_SYNC); // detect fastpath for bios completely contained within either the cow diff --git a/src/tracer.c b/src/tracer.c index 20a4a604..9ac4ddfc 100644 --- a/src/tracer.c +++ b/src/tracer.c @@ -398,7 +398,7 @@ static int bdev_is_already_traced(const struct block_device *bdev) { if (!dev || test_bit(UNVERIFIED, &dev->sd_state)) continue; - if (dev->sd_base_dev == bdev) + if (dev->sd_base_dev->bdev == bdev) return 1; } @@ -730,13 +730,13 @@ static int __tracer_setup_base_dev(struct snap_device *dev, // open the base block device LOG_DEBUG("ENTER __tracer_setup_base_dev"); - dev->sd_base_dev = dattodb_blkdev_by_path(bdev_path, FMODE_READ, NULL); + dev->sd_base_dev = dattobd_blkdev_by_path(bdev_path, FMODE_READ, NULL); if (IS_ERR(dev->sd_base_dev)) { ret = PTR_ERR(dev->sd_base_dev); dev->sd_base_dev = NULL; LOG_ERROR(ret, "error finding block device '%s'", bdev_path); goto error; - } else if (!dev->sd_base_dev->bd_disk) { + } else if (!dev->sd_base_dev->bdev->bd_disk) { ret = -EFAULT; LOG_ERROR(ret, "error finding block device gendisk"); goto error; @@ -744,7 +744,7 @@ static int __tracer_setup_base_dev(struct snap_device *dev, // check block device is not already being traced LOG_DEBUG("checking block device is not already being traced"); - if (bdev_is_already_traced(dev->sd_base_dev)) { + if (bdev_is_already_traced(dev->sd_base_dev->bdev)) { ret = -EINVAL; LOG_ERROR(ret, "block device is already being traced"); goto error; @@ -758,12 +758,12 @@ static int __tracer_setup_base_dev(struct snap_device *dev, // check if device represents a partition, calculate size and offset LOG_DEBUG("calculating block device size and offset"); - if (bdev_whole(dev->sd_base_dev) != dev->sd_base_dev) { - dev->sd_sect_off = get_start_sect(dev->sd_base_dev); - dev->sd_size = dattobd_bdev_size(dev->sd_base_dev); + if (bdev_whole(dev->sd_base_dev->bdev) != dev->sd_base_dev->bdev) { + dev->sd_sect_off = get_start_sect(dev->sd_base_dev->bdev); + dev->sd_size = dattobd_bdev_size(dev->sd_base_dev->bdev); } else { dev->sd_sect_off = 0; - dev->sd_size = get_capacity(dev->sd_base_dev->bd_disk); + dev->sd_size = get_capacity(dev->sd_base_dev->bdev->bd_disk); } LOG_DEBUG("bdev size = %llu, offset = %llu", @@ -813,9 +813,9 @@ static int snap_merge_bvec(struct request_queue *q, struct bvec_merge_data *bvm, struct bio_vec *bvec) { struct snap_device *dev = q->queuedata; - struct request_queue *base_queue = bdev_get_queue(dev->sd_base_dev); + struct request_queue *base_queue = bdev_get_queue(dev->sd_base_dev->bdev); - bvm->bi_bdev = dev->sd_base_dev; + bvm->bi_bdev = dev->sd_base_dev->bdev; return base_queue->merge_bvec_fn(base_queue, bvm, bvec); } @@ -838,9 +838,9 @@ static int snap_merge_bvec(struct request_queue *q, struct bio *bio_bvm, struct bio_vec *bvec) { struct snap_device *dev = q->queuedata; - struct request_queue *base_queue = bdev_get_queue(dev->sd_base_dev); + struct request_queue *base_queue = bdev_get_queue(dev->sd_base_dev->bdev); - bio_bvm->bi_bdev = dev->sd_base_dev; + bio_bvm->bi_bdev = dev->sd_base_dev->bdev; return base_queue->merge_bvec_fn(base_queue, bio_bvm, bvec); } @@ -1046,40 +1046,45 @@ static int __tracer_setup_snap(struct snap_device *dev, unsigned int minor, #else dev->sd_gd = alloc_disk(1); #endif + if (!dev->sd_gd) { ret = -ENOMEM; LOG_ERROR(ret, "error allocating gendisk"); goto error; } - // allocate request queue LOG_DEBUG("allocating queue"); -#if defined HAVE_MAKE_REQUEST_FN_IN_QUEUE && !defined HAVE_BLK_ALLOC_QUEUE_RH_2 - dev->sd_queue = blk_alloc_queue(GFP_KERNEL); -#elif defined HAVE_BLK_ALLOC_QUEUE_RH_2 // el8 - dev->sd_queue = blk_alloc_queue_rh(snap_mrf, NUMA_NO_NODE); -#elif defined HAVE_BLK_ALLOC_QUEUE_1 - // #if LINUX_VERSION_CODE < KERNEL_VERSION(5,7,0) - dev->sd_queue = blk_alloc_queue(GFP_KERNEL); -#elif defined HAVE_BLK_ALLOC_QUEUE_2 - dev->sd_queue = blk_alloc_queue(snap_mrf, NUMA_NO_NODE); -#elif !defined HAVE_BLK_ALLOC_DISK - // #if LINUX_VERSION_CODE >= KERNEL_VERSION(5,9,0) +#if defined HAVE_BDOPS_SUBMIT_BIO + +#if defined HAVE_BLK_ALLOC_DISK + dev->sd_queue = dev->sd_gd->queue; +#else // works until 6.9 dev->sd_queue = blk_alloc_queue(NUMA_NO_NODE); +#endif /*HAVE_BLK_ALLOC_DISK*/ + #else - dev->sd_queue = dev->sd_gd->queue; -#endif - if (!dev->sd_queue) { +#if defined HAVE_BLK_ALLOC_QUEUE_2 + dev->sd_queue = blk_alloc_queue(snap_mrf, NUMA_NO_NODE); +#elif defined HAVE_BLK_ALLOC_QUEUE_RH_2 + dev->sd_queue = blk_alloc_queue_rh(snap_mrf, NUMA_NO_NODE); +#else + dev->sd_queue = blk_alloc_queue(GFP_KERNEL); + + if(dev->sd_queue != NULL){ + LOG_DEBUG("setting up make request function"); + blk_queue_make_request(dev->sd_queue, snap_mrf); + } +#endif /*HAVE_BLK_ALLOC_QUEUE_2*/ + +#endif /*HAVE_BDOPS_SUBMIT_BIO*/ + + if(!dev->sd_queue) { ret = -ENOMEM; LOG_ERROR(ret, "error allocating request queue"); goto error; } -#if !defined HAVE_BLK_ALLOC_QUEUE && !defined USE_BDOPS_SUBMIT_BIO - LOG_DEBUG("setting up make request function"); - blk_queue_make_request(dev->sd_queue, snap_mrf); -#endif #if defined HAVE_GD_OWNS_QUEUE set_bit(GD_OWNS_QUEUE, &dev->sd_gd->state); #endif @@ -1289,6 +1294,8 @@ static int __tracer_transition_tracing( #endif return (int)PTR_ERR(sb); } +#elif defined HAVE_BDEV_FREEZE + ret = bdev_freeze(bdev); #else ret = freeze_bdev(bdev); if (ret) { @@ -1357,6 +1364,8 @@ static int __tracer_transition_tracing( #endif #ifdef HAVE_THAW_BDEV_INT ret = thaw_bdev(bdev, sb); +#elif defined HAVE_BDEV_THAW + ret = bdev_thaw(bdev); #else ret = thaw_bdev(bdev); #endif @@ -1493,7 +1502,7 @@ static int dattobd_find_orig_mrf(struct block_device *bdev, tracer_for_each(dev, i){ if(!dev || test_bit(UNVERIFIED, &dev->sd_state)) continue; - if(q == bdev_get_queue(dev->sd_base_dev)){ + if(q == bdev_get_queue(dev->sd_base_dev->bdev)){ *mrf = dev->sd_orig_request_fn; return 0; } @@ -1530,7 +1539,7 @@ int find_orig_bdops(struct block_device *bdev, struct block_device_operations ** tracer_for_each(dev, i){ if(!dev || test_bit(UNVERIFIED, &dev->sd_state)) continue; - if(orig_ops == dattobd_get_bd_ops(dev->sd_base_dev)){ + if(orig_ops == dattobd_get_bd_ops(dev->sd_base_dev->bdev)){ *ops = dev->bd_ops; *mrf = dev->sd_orig_request_fn; *trops=tracing_ops_get(dev->sd_tracing_ops); @@ -1560,10 +1569,10 @@ int tracer_alloc_ops(struct snap_device* dev){ LOG_ERROR(-ENOMEM, "error while alocating new block_device_operations"); return -ENOMEM; } - memcpy(trops->bd_ops, dattobd_get_bd_ops(dev->sd_base_dev),sizeof(struct block_device_operations)); + memcpy(trops->bd_ops, dattobd_get_bd_ops(dev->sd_base_dev->bdev),sizeof(struct block_device_operations)); trops->bd_ops->submit_bio = tracing_fn; #ifdef HAVE_BD_HAS_SUBMIT_BIO - trops->has_submit_bio=dev->sd_base_dev->bd_has_submit_bio; + trops->has_submit_bio=dev->sd_base_dev->bdev->bd_has_submit_bio; #endif atomic_set(&trops->refs, 1); dev->sd_tracing_ops = trops; @@ -1585,12 +1594,12 @@ static int __tracer_should_reset_mrf(const struct snap_device *dev) { int i; struct snap_device *cur_dev; - struct request_queue *q = bdev_get_queue(dev->sd_base_dev); + struct request_queue *q = bdev_get_queue(dev->sd_base_dev->bdev); #ifndef USE_BDOPS_SUBMIT_BIO - if (GET_BIO_REQUEST_TRACKING_PTR(dev->sd_base_dev) != tracing_fn) return 0; + if (GET_BIO_REQUEST_TRACKING_PTR(dev->sd_base_dev->bdev) != tracing_fn) return 0; #else - struct block_device_operations* ops=dattobd_get_bd_ops(dev->sd_base_dev); + struct block_device_operations* ops=dattobd_get_bd_ops(dev->sd_base_dev->bdev); #endif if (dev != snap_devices[dev->sd_minor]) return 0; @@ -1600,9 +1609,9 @@ static int __tracer_should_reset_mrf(const struct snap_device *dev) if (!cur_dev || test_bit(UNVERIFIED, &cur_dev->sd_state) || cur_dev == dev) continue; #ifndef USE_BDOPS_SUBMIT_BIO - if (q == bdev_get_queue(cur_dev->sd_base_dev)) return 0; + if (q == bdev_get_queue(cur_dev->sd_base_dev->bdev)) return 0; #else - if(ops==dattobd_get_bd_ops(cur_dev->sd_base_dev)) return 0; + if(ops==dattobd_get_bd_ops(cur_dev->sd_base_dev->bdev)) return 0; #endif } } @@ -1646,7 +1655,7 @@ static void __tracer_destroy_tracing(struct snap_device *dev) #ifndef USE_BDOPS_SUBMIT_BIO __tracer_transition_tracing( dev, - dev->sd_base_dev, + dev->sd_base_dev->bdev, dev->sd_orig_request_fn, &snap_devices[dev->sd_minor], false @@ -1654,7 +1663,7 @@ static void __tracer_destroy_tracing(struct snap_device *dev) #else __tracer_transition_tracing( dev, - dev->sd_base_dev, + dev->sd_base_dev->bdev, dev->bd_ops, &snap_devices[dev->sd_minor], false @@ -1665,7 +1674,7 @@ static void __tracer_destroy_tracing(struct snap_device *dev) { __tracer_transition_tracing( dev, - dev->sd_base_dev, + dev->sd_base_dev->bdev, NULL, &snap_devices[dev->sd_minor], false @@ -1728,18 +1737,18 @@ int __tracer_setup_tracing(struct snap_device *dev, unsigned int minor) LOG_DEBUG("getting the base block device's make_request_fn"); #ifndef USE_BDOPS_SUBMIT_BIO - ret = dattobd_find_orig_mrf(dev->sd_base_dev, &dev->sd_orig_request_fn); + ret = dattobd_find_orig_mrf(dev->sd_base_dev->bdev, &dev->sd_orig_request_fn); if (ret) goto error; ret = __tracer_transition_tracing( dev, - dev->sd_base_dev, + dev->sd_base_dev->bdev, tracing_fn, &snap_devices[minor], true); #else if(!dev->sd_tracing_ops){ - ret=find_orig_bdops(dev->sd_base_dev, &dev->bd_ops,&dev->sd_orig_request_fn, &dev->sd_tracing_ops); + ret=find_orig_bdops(dev->sd_base_dev->bdev, &dev->bd_ops,&dev->sd_orig_request_fn, &dev->sd_tracing_ops); if(ret) goto error; if(!dev->sd_tracing_ops){ @@ -1754,7 +1763,7 @@ int __tracer_setup_tracing(struct snap_device *dev, unsigned int minor) ret = __tracer_transition_tracing( dev, - dev->sd_base_dev, + dev->sd_base_dev->bdev, dev->sd_tracing_ops->bd_ops, &snap_devices[minor], true); @@ -1877,7 +1886,7 @@ int tracer_setup_active_snap(struct snap_device *dev, unsigned int minor, goto error; // setup the cow manager - ret = __tracer_setup_cow_new(dev, dev->sd_base_dev, cow_path, + ret = __tracer_setup_cow_new(dev, dev->sd_base_dev->bdev, cow_path, dev->sd_size, fallocated_space, cache_size, NULL, 1); if (ret) @@ -1890,13 +1899,13 @@ int tracer_setup_active_snap(struct snap_device *dev, unsigned int minor, #ifndef USE_BDOPS_SUBMIT_BIO // retain an association between the original mrf and the block device - ret = mrf_get(dev->sd_base_dev->bd_disk, GET_BIO_REQUEST_TRACKING_PTR(dev->sd_base_dev)); + ret = mrf_get(dev->sd_base_dev->bdev->bd_disk, GET_BIO_REQUEST_TRACKING_PTR(dev->sd_base_dev->bdev)); if (ret) goto error; #endif // setup the snapshot values - ret = __tracer_setup_snap(dev, minor, dev->sd_base_dev, dev->sd_size); + ret = __tracer_setup_snap(dev, minor, dev->sd_base_dev->bdev, dev->sd_size); if (ret) goto error; @@ -2071,7 +2080,7 @@ int tracer_active_inc_to_snap(struct snap_device *old_dev, const char *cow_path, __tracer_copy_base_dev(old_dev, dev); // setup the cow manager - ret = __tracer_setup_cow_new(dev, dev->sd_base_dev, cow_path, + ret = __tracer_setup_cow_new(dev, dev->sd_base_dev->bdev, cow_path, dev->sd_size, fallocated_space, dev->sd_cache_size, old_dev->sd_cow->uuid, old_dev->sd_cow->seqid + 1); @@ -2084,7 +2093,7 @@ int tracer_active_inc_to_snap(struct snap_device *old_dev, const char *cow_path, goto error; // setup the snapshot values - ret = __tracer_setup_snap(dev, old_dev->sd_minor, dev->sd_base_dev, + ret = __tracer_setup_snap(dev, old_dev->sd_minor, dev->sd_base_dev->bdev, dev->sd_size); if (ret) goto error; @@ -2153,8 +2162,8 @@ void tracer_dattobd_info(const struct snap_device *dev, info->cache_size = (dev->sd_cache_size) ? dev->sd_cache_size : dattobd_cow_max_memory_default; - strlcpy(info->cow, dev->sd_cow_path, PATH_MAX); - strlcpy(info->bdev, dev->sd_bdev_path, PATH_MAX); + strscpy(info->cow, dev->sd_cow_path, PATH_MAX); + strscpy(info->bdev, dev->sd_bdev_path, PATH_MAX); if (!test_bit(UNVERIFIED, &dev->sd_state)) { info->falloc_size = dev->sd_cow->file_size; @@ -2245,7 +2254,7 @@ void __tracer_unverified_snap_to_active(struct snap_device *dev, goto error; // setup the cow manager - ret = __tracer_setup_cow_reload_snap(dev, dev->sd_base_dev, cow_path, + ret = __tracer_setup_cow_reload_snap(dev, dev->sd_base_dev->bdev, cow_path, dev->sd_size, dev->sd_cache_size); if (ret) goto error; @@ -2257,13 +2266,13 @@ void __tracer_unverified_snap_to_active(struct snap_device *dev, #ifndef USE_BDOPS_SUBMIT_BIO // retain an association between the original mrf and the block device - ret = mrf_get(dev->sd_base_dev->bd_disk, GET_BIO_REQUEST_TRACKING_PTR(dev->sd_base_dev)); + ret = mrf_get(dev->sd_base_dev->bdev->bd_disk, GET_BIO_REQUEST_TRACKING_PTR(dev->sd_base_dev->bdev)); if (ret) goto error; #endif // setup the snapshot values - ret = __tracer_setup_snap(dev, minor, dev->sd_base_dev, dev->sd_size); + ret = __tracer_setup_snap(dev, minor, dev->sd_base_dev->bdev, dev->sd_size); if (ret) goto error; @@ -2341,7 +2350,7 @@ void __tracer_unverified_inc_to_active(struct snap_device *dev, goto error; // setup the cow manager - ret = __tracer_setup_cow_reload_inc(dev, dev->sd_base_dev, cow_path, + ret = __tracer_setup_cow_reload_inc(dev, dev->sd_base_dev->bdev, cow_path, dev->sd_size, dev->sd_cache_size); if (ret) goto error; @@ -2353,7 +2362,7 @@ void __tracer_unverified_inc_to_active(struct snap_device *dev, #ifndef USE_BDOPS_SUBMIT_BIO // retain an association between the original mrf and the block device - ret = mrf_get(dev->sd_base_dev->bd_disk, GET_BIO_REQUEST_TRACKING_PTR(dev->sd_base_dev)); + ret = mrf_get(dev->sd_base_dev->bdev->bd_disk, GET_BIO_REQUEST_TRACKING_PTR(dev->sd_base_dev->bdev)); if (ret) goto error; #endif @@ -2415,7 +2424,7 @@ void __tracer_dormant_to_active(struct snap_device *dev, goto error; // setup the cow manager - ret = __tracer_setup_cow_reopen(dev, dev->sd_base_dev, cow_path); + ret = __tracer_setup_cow_reopen(dev, dev->sd_base_dev->bdev, cow_path); if (ret) goto error; diff --git a/src/tracer_helper.h b/src/tracer_helper.h index 07ef831e..abd91e53 100644 --- a/src/tracer_helper.h +++ b/src/tracer_helper.h @@ -11,6 +11,7 @@ #include "hints.h" #include "includes.h" #include "module_control.h" +#include "blkdev.h" // macro for iterating over snap_devices (requires a null check on dev) #define tracer_for_each(dev, i) \ @@ -25,7 +26,7 @@ // returns true if tracing struct's base device queue matches that of bio #define tracer_queue_matches_bio(dev, bio) \ - (bdev_get_queue((dev)->sd_base_dev) == dattobd_bio_get_queue(bio)) + (bdev_get_queue((dev)->sd_base_dev->bdev) == dattobd_bio_get_queue(bio)) // returns true if tracing struct's sector range matches the sector of the bio #define tracer_sector_matches_bio(dev, bio) \