diff options
-rw-r--r-- | src/kernel/CMakeLists.txt | 9 | ||||
-rw-r--r-- | src/kernel/uapi_xloop.h | 81 | ||||
-rw-r--r-- | src/kernel/xloop_file_fmt.c | 102 | ||||
-rw-r--r-- | src/kernel/xloop_file_fmt.h | 79 | ||||
-rw-r--r-- | src/kernel/xloop_file_fmt_qcow_cache.c | 83 | ||||
-rw-r--r-- | src/kernel/xloop_file_fmt_qcow_cache.h | 13 | ||||
-rw-r--r-- | src/kernel/xloop_file_fmt_qcow_cluster.c | 302 | ||||
-rw-r--r-- | src/kernel/xloop_file_fmt_qcow_cluster.h | 6 | ||||
-rw-r--r-- | src/kernel/xloop_file_fmt_qcow_main.c | 733 | ||||
-rw-r--r-- | src/kernel/xloop_file_fmt_qcow_main.h | 529 | ||||
-rw-r--r-- | src/kernel/xloop_file_fmt_raw.c | 99 | ||||
-rw-r--r-- | src/kernel/xloop_main.c | 423 | ||||
-rw-r--r-- | src/kernel/xloop_main.h | 93 |
13 files changed, 1111 insertions, 1441 deletions
diff --git a/src/kernel/CMakeLists.txt b/src/kernel/CMakeLists.txt index 1e51797..babcaf0 100644 --- a/src/kernel/CMakeLists.txt +++ b/src/kernel/CMakeLists.txt @@ -26,7 +26,14 @@ if(CMAKE_BUILD_TYPE MATCHES "Debug") endif(CMAKE_BUILD_TYPE MATCHES "Debug") # define list of options to ignore with the checkpatch.pl linter -set(CHECKPATCH_IGNORE_WARNINGS "LINUX_VERSION_CODE") +set(CHECKPATCH_IGNORE_WARNINGS "LINUX_VERSION_CODE" + "CONSTANT_COMPARISON" + "PREFER_PR_LEVEL" + "TRAILING_SEMICOLON" + "CONSIDER_KSTRTO" + "UNNECESSARY_ELSE" + "SPLIT_STRING" + "STATIC_CONST_CHAR_ARRAY") # xloop main Linux kernel module set(KERNEL_MODULE_XLOOP_SOURCE_FILES ${CMAKE_CURRENT_SOURCE_DIR}/xloop_file_fmt.c diff --git a/src/kernel/uapi_xloop.h b/src/kernel/uapi_xloop.h index 1bf13c6..0d6849e 100644 --- a/src/kernel/uapi_xloop.h +++ b/src/kernel/uapi_xloop.h @@ -10,19 +10,17 @@ #ifndef _UAPI_LINUX_XLOOP_H #define _UAPI_LINUX_XLOOP_H - -#define XLO_NAME_SIZE 64 -#define XLO_KEY_SIZE 32 - +#define XLO_NAME_SIZE 64 +#define XLO_KEY_SIZE 32 /* * xloop flags */ enum { - XLO_FLAGS_READ_ONLY = 1, - XLO_FLAGS_AUTOCLEAR = 4, - XLO_FLAGS_PARTSCAN = 8, - XLO_FLAGS_DIRECT_IO = 16, + XLO_FLAGS_READ_ONLY = 1, + XLO_FLAGS_AUTOCLEAR = 4, + XLO_FLAGS_PARTSCAN = 8, + XLO_FLAGS_DIRECT_IO = 16, }; /* XLO_FLAGS that can be set using XLOOP_SET_STATUS(64) */ @@ -32,11 +30,11 @@ enum { #define XLOOP_SET_STATUS_CLEARABLE_FLAGS (XLO_FLAGS_AUTOCLEAR) /* XLO_FLAGS that can be set using XLOOP_CONFIGURE */ -#define XLOOP_CONFIGURE_SETTABLE_FLAGS (XLO_FLAGS_READ_ONLY | XLO_FLAGS_AUTOCLEAR \ - | XLO_FLAGS_PARTSCAN | XLO_FLAGS_DIRECT_IO) +#define XLOOP_CONFIGURE_SETTABLE_FLAGS \ + (XLO_FLAGS_READ_ONLY | XLO_FLAGS_AUTOCLEAR | XLO_FLAGS_PARTSCAN | XLO_FLAGS_DIRECT_IO) -#include <asm/posix_types.h> /* for __kernel_old_dev_t */ -#include <linux/types.h> /* for __u64 */ +#include <asm/posix_types.h> /* for __kernel_old_dev_t */ +#include <linux/types.h> /* for __u64 */ /* Backwards compatibility version */ struct xloop_info { @@ -56,20 +54,20 @@ struct xloop_info { }; struct xloop_info64 { - __u64 xlo_device; /* ioctl r/o */ - __u64 xlo_inode; /* ioctl r/o */ - __u64 xlo_rdevice; /* ioctl r/o */ - __u64 xlo_offset; - __u64 xlo_sizelimit; /* bytes, 0 == max available */ - __u32 xlo_number; /* ioctl r/o */ - __u32 xlo_encrypt_type; - __u32 xlo_encrypt_key_size; /* ioctl w/o */ - __u32 xlo_flags; - __u8 xlo_file_name[XLO_NAME_SIZE]; - __u8 xlo_crypt_name[XLO_NAME_SIZE]; - __u8 xlo_encrypt_key[XLO_KEY_SIZE]; /* ioctl w/o */ - __u64 xlo_init[2]; - __u32 xlo_file_fmt_type; + __u64 xlo_device; /* ioctl r/o */ + __u64 xlo_inode; /* ioctl r/o */ + __u64 xlo_rdevice; /* ioctl r/o */ + __u64 xlo_offset; + __u64 xlo_sizelimit; /* bytes, 0 == max available */ + __u32 xlo_number; /* ioctl r/o */ + __u32 xlo_encrypt_type; + __u32 xlo_encrypt_key_size; /* ioctl w/o */ + __u32 xlo_flags; + __u8 xlo_file_name[XLO_NAME_SIZE]; + __u8 xlo_crypt_name[XLO_NAME_SIZE]; + __u8 xlo_encrypt_key[XLO_KEY_SIZE]; /* ioctl w/o */ + __u64 xlo_init[2]; + __u32 xlo_file_fmt_type; }; /** @@ -84,24 +82,24 @@ struct xloop_info64 { struct xloop_config { __u32 fd; __u32 block_size; - struct xloop_info64 info; + struct xloop_info64 info; __u64 __reserved[8]; }; /* * xloop filter types */ -#define XLO_CRYPT_NONE 0 -#define XLO_CRYPT_XOR 1 -#define XLO_CRYPT_DES 2 -#define XLO_CRYPT_FISH2 3 /* Twofish encryption */ -#define XLO_CRYPT_BLOW 4 -#define XLO_CRYPT_CAST128 5 -#define XLO_CRYPT_IDEA 6 -#define XLO_CRYPT_DUMMY 9 -#define XLO_CRYPT_SKIPJACK 10 -#define XLO_CRYPT_CRYPTOAPI 18 -#define MAX_XLO_CRYPT 20 +#define XLO_CRYPT_NONE 0 +#define XLO_CRYPT_XOR 1 +#define XLO_CRYPT_DES 2 +#define XLO_CRYPT_FISH2 3 /* Twofish encryption */ +#define XLO_CRYPT_BLOW 4 +#define XLO_CRYPT_CAST128 5 +#define XLO_CRYPT_IDEA 6 +#define XLO_CRYPT_DUMMY 9 +#define XLO_CRYPT_SKIPJACK 10 +#define XLO_CRYPT_CRYPTOAPI 18 +#define MAX_XLO_CRYPT 20 /* * IOCTL commands --- we will commandeer 0x4C ('L') @@ -119,7 +117,8 @@ struct xloop_config { #define XLOOP_CONFIGURE 0x4C0A /* /dev/xloop-control interface */ -#define XLOOP_CTL_ADD 0x4C80 -#define XLOOP_CTL_REMOVE 0x4C81 -#define XLOOP_CTL_GET_FREE 0x4C82 +#define XLOOP_CTL_ADD 0x4C80 +#define XLOOP_CTL_REMOVE 0x4C81 +#define XLOOP_CTL_GET_FREE 0x4C82 + #endif /* _UAPI_LINUX_XLOOP_H */ diff --git a/src/kernel/xloop_file_fmt.c b/src/kernel/xloop_file_fmt.c index 6c4902f..5a70ad5 100644 --- a/src/kernel/xloop_file_fmt.c +++ b/src/kernel/xloop_file_fmt.c @@ -1,4 +1,4 @@ -/* SPDX-License-Identifier: GPL-2.0 */ +// SPDX-License-Identifier: GPL-2.0 /* * xloop_file_fmt.c * @@ -16,9 +16,7 @@ #include "xloop_main.h" /* storage for all registered file format drivers */ -static struct xloop_file_fmt_driver *xloop_file_fmt_drivers[MAX_XLO_FILE_FMT] = { - NULL -}; +static struct xloop_file_fmt_driver *xloop_file_fmt_drivers[MAX_XLO_FILE_FMT] = { NULL }; int xloop_file_fmt_register_driver(struct xloop_file_fmt_driver *drv) { @@ -85,12 +83,12 @@ EXPORT_SYMBOL(xloop_file_fmt_get_xlo); struct device *xloop_file_fmt_to_dev(struct xloop_file_fmt *xlo_fmt) { struct xloop_device *xlo = xloop_file_fmt_get_xlo(xlo_fmt); + return xloop_device_to_dev(xlo); } EXPORT_SYMBOL(xloop_file_fmt_to_dev); -int xloop_file_fmt_init(struct xloop_file_fmt *xlo_fmt, - u32 file_fmt_type) +int xloop_file_fmt_init(struct xloop_file_fmt *xlo_fmt, u32 file_fmt_type) { struct xloop_file_fmt_ops *ops; struct module *drv; @@ -102,25 +100,22 @@ int xloop_file_fmt_init(struct xloop_file_fmt *xlo_fmt, xlo_fmt->file_fmt_type = file_fmt_type; if (xlo_fmt->file_fmt_state != file_fmt_uninitialized) { - dev_warn(xloop_file_fmt_to_dev(xlo_fmt), "file format is " - "initialized already\n"); + dev_warn(xloop_file_fmt_to_dev(xlo_fmt), "file format is initialized already\n"); return -EINVAL; } /* check if new file format driver is registered */ if (xloop_file_fmt_drivers[xlo_fmt->file_fmt_type] == NULL) { - dev_err(xloop_file_fmt_to_dev(xlo_fmt), "file format driver is " - "not available\n"); + dev_err(xloop_file_fmt_to_dev(xlo_fmt), "file format driver is not available\n"); return -ENODEV; } dev_info(xloop_file_fmt_to_dev(xlo_fmt), "use file format driver %s\n", - xloop_file_fmt_drivers[xlo_fmt->file_fmt_type]->name); + xloop_file_fmt_drivers[xlo_fmt->file_fmt_type]->name); drv = xloop_file_fmt_drivers[xlo_fmt->file_fmt_type]->owner; if (!try_module_get(drv)) { - dev_err(xloop_file_fmt_to_dev(xlo_fmt), "file format driver %s can " - "not be accessed\n", + dev_err(xloop_file_fmt_to_dev(xlo_fmt), "file format driver %s can not be accessed\n", xloop_file_fmt_drivers[xlo_fmt->file_fmt_type]->name); return -ENODEV; } @@ -132,8 +127,10 @@ int xloop_file_fmt_init(struct xloop_file_fmt *xlo_fmt, goto free_drv; } - /* after increasing the refcount of file format driver module and - * the successful initialization, the file format is initialized */ + /* + * after increasing the refcount of file format driver module and + * the successful initialization, the file format is initialized + */ xlo_fmt->file_fmt_state = file_fmt_initialized; return ret; @@ -150,8 +147,8 @@ void xloop_file_fmt_exit(struct xloop_file_fmt *xlo_fmt) struct module *drv; if (xlo_fmt->file_fmt_state != file_fmt_initialized) { - dev_warn(xloop_file_fmt_to_dev(xlo_fmt), "file format is " - "uninitialized already\n"); + dev_warn(xloop_file_fmt_to_dev(xlo_fmt), + "file format is uninitialized already\n"); return; } @@ -162,19 +159,20 @@ void xloop_file_fmt_exit(struct xloop_file_fmt *xlo_fmt) drv = xloop_file_fmt_drivers[xlo_fmt->file_fmt_type]->owner; module_put(drv); - /* after decreasing the refcount of file format driver module, - * the file format is uninitialized */ + /* + * after decreasing the refcount of file format driver module, + * the file format is uninitialized + */ xlo_fmt->file_fmt_state = file_fmt_uninitialized; } -int xloop_file_fmt_read(struct xloop_file_fmt *xlo_fmt, - struct request *rq) +int xloop_file_fmt_read(struct xloop_file_fmt *xlo_fmt, struct request *rq) { struct xloop_file_fmt_ops *ops; if (unlikely(xlo_fmt->file_fmt_state != file_fmt_initialized)) { - dev_err_ratelimited(xloop_file_fmt_to_dev(xlo_fmt), "file format " - "is not initialized, can not read\n"); + dev_err_ratelimited(xloop_file_fmt_to_dev(xlo_fmt), + "file format is not initialized, can not read\n"); return -EINVAL; } @@ -185,14 +183,13 @@ int xloop_file_fmt_read(struct xloop_file_fmt *xlo_fmt, return -EIO; } -int xloop_file_fmt_read_aio(struct xloop_file_fmt *xlo_fmt, - struct request *rq) +int xloop_file_fmt_read_aio(struct xloop_file_fmt *xlo_fmt, struct request *rq) { struct xloop_file_fmt_ops *ops; if (unlikely(xlo_fmt->file_fmt_state != file_fmt_initialized)) { - dev_err_ratelimited(xloop_file_fmt_to_dev(xlo_fmt), "file format " - "is not initialized, can not read aio\n"); + dev_err_ratelimited(xloop_file_fmt_to_dev(xlo_fmt), + "file format is not initialized, can not read aio\n"); return -EINVAL; } @@ -203,14 +200,13 @@ int xloop_file_fmt_read_aio(struct xloop_file_fmt *xlo_fmt, return -EIO; } -int xloop_file_fmt_write(struct xloop_file_fmt *xlo_fmt, - struct request *rq) +int xloop_file_fmt_write(struct xloop_file_fmt *xlo_fmt, struct request *rq) { struct xloop_file_fmt_ops *ops; if (unlikely(xlo_fmt->file_fmt_state != file_fmt_initialized)) { - dev_err_ratelimited(xloop_file_fmt_to_dev(xlo_fmt), "file format " - "is not initialized, can not write\n"); + dev_err_ratelimited(xloop_file_fmt_to_dev(xlo_fmt), + "file format is not initialized, can not write\n"); return -EINVAL; } @@ -221,14 +217,13 @@ int xloop_file_fmt_write(struct xloop_file_fmt *xlo_fmt, return -EIO; } -int xloop_file_fmt_write_aio(struct xloop_file_fmt *xlo_fmt, - struct request *rq) +int xloop_file_fmt_write_aio(struct xloop_file_fmt *xlo_fmt, struct request *rq) { struct xloop_file_fmt_ops *ops; if (unlikely(xlo_fmt->file_fmt_state != file_fmt_initialized)) { - dev_err_ratelimited(xloop_file_fmt_to_dev(xlo_fmt), "file format " - "is not initialized, can not write aio\n"); + dev_err_ratelimited(xloop_file_fmt_to_dev(xlo_fmt), + "file format is not initialized, can not write aio\n"); return -EINVAL; } @@ -239,14 +234,13 @@ int xloop_file_fmt_write_aio(struct xloop_file_fmt *xlo_fmt, return -EIO; } -int xloop_file_fmt_write_zeros(struct xloop_file_fmt *xlo_fmt, - struct request *rq) +int xloop_file_fmt_write_zeros(struct xloop_file_fmt *xlo_fmt, struct request *rq) { struct xloop_file_fmt_ops *ops; if (unlikely(xlo_fmt->file_fmt_state != file_fmt_initialized)) { - dev_err_ratelimited(xloop_file_fmt_to_dev(xlo_fmt), "file format " - "is not initialized, can not write zeros\n"); + dev_err_ratelimited(xloop_file_fmt_to_dev(xlo_fmt), + "file format is not initialized, can not write zeros\n"); return -EINVAL; } @@ -257,14 +251,13 @@ int xloop_file_fmt_write_zeros(struct xloop_file_fmt *xlo_fmt, return -EIO; } -int xloop_file_fmt_discard(struct xloop_file_fmt *xlo_fmt, - struct request *rq) +int xloop_file_fmt_discard(struct xloop_file_fmt *xlo_fmt, struct request *rq) { struct xloop_file_fmt_ops *ops; if (unlikely(xlo_fmt->file_fmt_state != file_fmt_initialized)) { - dev_err_ratelimited(xloop_file_fmt_to_dev(xlo_fmt), "file format " - "is not initialized, can not discard\n"); + dev_err_ratelimited(xloop_file_fmt_to_dev(xlo_fmt), + "file format is not initialized, can not discard\n"); return -EINVAL; } @@ -280,8 +273,8 @@ int xloop_file_fmt_flush(struct xloop_file_fmt *xlo_fmt) struct xloop_file_fmt_ops *ops; if (unlikely(xlo_fmt->file_fmt_state != file_fmt_initialized)) { - dev_err_ratelimited(xloop_file_fmt_to_dev(xlo_fmt), "file format " - "is not initialized, can not flush\n"); + dev_err_ratelimited(xloop_file_fmt_to_dev(xlo_fmt), + "file format is not initialized, can not flush\n"); return -EINVAL; } @@ -292,14 +285,13 @@ int xloop_file_fmt_flush(struct xloop_file_fmt *xlo_fmt) return 0; } -loff_t xloop_file_fmt_sector_size(struct xloop_file_fmt *xlo_fmt, - struct file *file, loff_t offset, loff_t sizelimit) +loff_t xloop_file_fmt_sector_size(struct xloop_file_fmt *xlo_fmt, struct file *file, loff_t offset, loff_t sizelimit) { struct xloop_file_fmt_ops *ops; if (unlikely(xlo_fmt->file_fmt_state != file_fmt_initialized)) { - dev_err_ratelimited(xloop_file_fmt_to_dev(xlo_fmt), "file format " - "is not initialized, can not read sector size\n"); + dev_err_ratelimited(xloop_file_fmt_to_dev(xlo_fmt), + "file format is not initialized, can not read sector size\n"); return 0; } @@ -310,21 +302,18 @@ loff_t xloop_file_fmt_sector_size(struct xloop_file_fmt *xlo_fmt, return 0; } -int xloop_file_fmt_change(struct xloop_file_fmt *xlo_fmt, - u32 file_fmt_type_new) +int xloop_file_fmt_change(struct xloop_file_fmt *xlo_fmt, u32 file_fmt_type_new) { if (file_fmt_type_new > MAX_XLO_FILE_FMT) return -EINVAL; dev_info(xloop_file_fmt_to_dev(xlo_fmt), "change file format\n"); - /* Unload the old file format driver if the file format is - * initialized */ + /* unload the old file format driver if the file format is initialized */ if (xlo_fmt->file_fmt_state == file_fmt_initialized) xloop_file_fmt_exit(xlo_fmt); - /* Load the new file format driver because the file format is - * uninitialized now */ + /* Load the new file format driver because the file format is uninitialized now */ return xloop_file_fmt_init(xlo_fmt, file_fmt_type_new); } @@ -346,8 +335,7 @@ ssize_t xloop_file_fmt_print_type(u32 file_fmt_type, char *file_fmt_name) len = sprintf(file_fmt_name, "%s", "VMDK"); break; default: - len = sprintf(file_fmt_name, "%s", "ERROR: Unsupported xloop " - "file format!"); + len = sprintf(file_fmt_name, "%s", "ERROR: Unsupported xloop file format!"); break; } diff --git a/src/kernel/xloop_file_fmt.h b/src/kernel/xloop_file_fmt.h index 20589c1..4c26495 100644 --- a/src/kernel/xloop_file_fmt.h +++ b/src/kernel/xloop_file_fmt.h @@ -14,11 +14,11 @@ struct xloop_file_fmt; -#define XLO_FILE_FMT_RAW 0 -#define XLO_FILE_FMT_QCOW 1 -#define XLO_FILE_FMT_VDI 2 -#define XLO_FILE_FMT_VMDK 3 -#define MAX_XLO_FILE_FMT (XLO_FILE_FMT_VMDK + 1) +#define XLO_FILE_FMT_RAW 0 +#define XLO_FILE_FMT_QCOW 1 +#define XLO_FILE_FMT_VDI 2 +#define XLO_FILE_FMT_VMDK 3 +#define MAX_XLO_FILE_FMT (XLO_FILE_FMT_VMDK + 1) /** * struct xloop_file_fmt_ops - File format subsystem operations @@ -29,59 +29,52 @@ struct xloop_file_fmt_ops { /** * @init: Initialization callback function */ - int (*init) (struct xloop_file_fmt *xlo_fmt); + int (*init)(struct xloop_file_fmt *xlo_fmt); /** * @exit: Release callback function */ - void (*exit) (struct xloop_file_fmt *xlo_fmt); + void (*exit)(struct xloop_file_fmt *xlo_fmt); /** * @read: Read IO callback function */ - int (*read) (struct xloop_file_fmt *xlo_fmt, - struct request *rq); + int (*read)(struct xloop_file_fmt *xlo_fmt, struct request *rq); /** * @write: Write IO callback function */ - int (*write) (struct xloop_file_fmt *xlo_fmt, - struct request *rq); + int (*write)(struct xloop_file_fmt *xlo_fmt, struct request *rq); /** * @read_aio: Asynchronous read IO callback function */ - int (*read_aio) (struct xloop_file_fmt *xlo_fmt, - struct request *rq); + int (*read_aio)(struct xloop_file_fmt *xlo_fmt, struct request *rq); /** * @write_aio: Asynchronous write IO callback function */ - int (*write_aio) (struct xloop_file_fmt *xlo_fmt, - struct request *rq); + int (*write_aio)(struct xloop_file_fmt *xlo_fmt, struct request *rq); /** * @zero: Zero (discard) IO callback function */ - int (*write_zeros) (struct xloop_file_fmt *xlo_fmt, - struct request *rq); + int (*write_zeros)(struct xloop_file_fmt *xlo_fmt, struct request *rq); /** * @discard: Discard IO callback function */ - int (*discard) (struct xloop_file_fmt *xlo_fmt, - struct request *rq); + int (*discard)(struct xloop_file_fmt *xlo_fmt, struct request *rq); /** * @flush: Flush callback function */ - int (*flush) (struct xloop_file_fmt *xlo_fmt); + int (*flush)(struct xloop_file_fmt *xlo_fmt); /** * @sector_size: Get sector size callback function */ - loff_t (*sector_size) (struct xloop_file_fmt *xlo_fmt, - struct file *file, loff_t offset, loff_t sizelimit); + loff_t (*sector_size)(struct xloop_file_fmt *xlo_fmt, struct file *file, loff_t offset, loff_t sizelimit); }; /** @@ -141,10 +134,7 @@ struct xloop_file_fmt_driver { * | initialized -------> uninitialized -------> initialized | * +-----------------------------------------------------------+ */ -enum { - file_fmt_uninitialized = 0, - file_fmt_initialized -}; +enum { file_fmt_uninitialized = 0, file_fmt_initialized }; /** * struct xloop_file_fmt - xloop file format @@ -173,7 +163,6 @@ struct xloop_file_fmt { void *private_data; }; - /* subsystem functions for the driver implementation */ /** @@ -194,7 +183,6 @@ extern int xloop_file_fmt_register_driver(struct xloop_file_fmt_driver *drv); */ extern void xloop_file_fmt_unregister_driver(struct xloop_file_fmt_driver *drv); - /* subsystem functions for subsystem usage */ /** @@ -220,8 +208,7 @@ extern void xloop_file_fmt_free(struct xloop_file_fmt *xlo_fmt); * * The link to the xloop device @xlo is set in the xloop file format @xlo_fmt. */ -extern int xloop_file_fmt_set_xlo(struct xloop_file_fmt *xlo_fmt, - struct xloop_device *xlo); +extern int xloop_file_fmt_set_xlo(struct xloop_file_fmt *xlo_fmt, struct xloop_device *xlo); /** * xloop_file_fmt_get_xlo - Get the xloop file format's xloop device @@ -250,8 +237,7 @@ extern inline struct device *xloop_file_fmt_to_dev(struct xloop_file_fmt *xlo_fm * format driver for the specified file format is available an error is * returned. */ -extern int xloop_file_fmt_init(struct xloop_file_fmt *xlo_fmt, - u32 file_fmt_type); +extern int xloop_file_fmt_init(struct xloop_file_fmt *xlo_fmt, u32 file_fmt_type); /** * xloop_file_fmt_exit - Release a xloop file format @@ -270,8 +256,7 @@ extern void xloop_file_fmt_exit(struct xloop_file_fmt *xlo_fmt); * @rq to the xloop file format subsystem. The subsystem calls the registered * callback function of the suitable xloop file format driver. */ -extern int xloop_file_fmt_read(struct xloop_file_fmt *xlo_fmt, - struct request *rq); +extern int xloop_file_fmt_read(struct xloop_file_fmt *xlo_fmt, struct request *rq); /** * xloop_file_fmt_read_aio - Read IO from a xloop file format asynchronously @@ -283,8 +268,7 @@ extern int xloop_file_fmt_read(struct xloop_file_fmt *xlo_fmt, * calls the registered callback function of the suitable xloop file format * driver. */ -extern int xloop_file_fmt_read_aio(struct xloop_file_fmt *xlo_fmt, - struct request *rq); +extern int xloop_file_fmt_read_aio(struct xloop_file_fmt *xlo_fmt, struct request *rq); /** * xloop_file_fmt_write - Write IO to a xloop file format @@ -295,8 +279,7 @@ extern int xloop_file_fmt_read_aio(struct xloop_file_fmt *xlo_fmt, * @rq to the xloop file format subsystem. The subsystem calls the registered * callback function of the suitable xloop file format driver. */ -extern int xloop_file_fmt_write(struct xloop_file_fmt *xlo_fmt, - struct request *rq); +extern int xloop_file_fmt_write(struct xloop_file_fmt *xlo_fmt, struct request *rq); /** * xloop_file_fmt_write_aio - Write IO to a xloop file format asynchronously @@ -308,8 +291,7 @@ extern int xloop_file_fmt_write(struct xloop_file_fmt *xlo_fmt, * calls the registered callback function of the suitable xloop file format * driver. */ -extern int xloop_file_fmt_write_aio(struct xloop_file_fmt *xlo_fmt, - struct request *rq); +extern int xloop_file_fmt_write_aio(struct xloop_file_fmt *xlo_fmt, struct request *rq); /** * xloop_file_fmt_write_zeros - Zero (discard) IO on a xloop file format @@ -320,8 +302,7 @@ extern int xloop_file_fmt_write_aio(struct xloop_file_fmt *xlo_fmt, * zeros request @rq to the xloop file format subsystem. The subsystem calls the * registered callback function of the suitable xloop file format driver. */ -extern int xloop_file_fmt_write_zeros(struct xloop_file_fmt *xlo_fmt, - struct request *rq); +extern int xloop_file_fmt_write_zeros(struct xloop_file_fmt *xlo_fmt, struct request *rq); /** * xloop_file_fmt_discard - Discard IO on a xloop file format @@ -332,8 +313,7 @@ extern int xloop_file_fmt_write_zeros(struct xloop_file_fmt *xlo_fmt, * request @rq to the xloop file format subsystem. The subsystem calls the * registered callback function of the suitable xloop file format driver. */ -extern int xloop_file_fmt_discard(struct xloop_file_fmt *xlo_fmt, - struct request *rq); +extern int xloop_file_fmt_discard(struct xloop_file_fmt *xlo_fmt, struct request *rq); /** * xloop_file_fmt_flush - Flush a xloop file format @@ -355,8 +335,8 @@ extern int xloop_file_fmt_flush(struct xloop_file_fmt *xlo_fmt); * If the xloop file format implements a sparse disk image format, then this * function returns the virtual sector size. */ -extern loff_t xloop_file_fmt_sector_size(struct xloop_file_fmt *xlo_fmt, - struct file *file, loff_t offset, loff_t sizelimit); +extern loff_t xloop_file_fmt_sector_size(struct xloop_file_fmt *xlo_fmt, struct file *file, loff_t offset, + loff_t sizelimit); /** * xloop_file_fmt_change - Change the xloop file format's type @@ -368,9 +348,7 @@ extern loff_t xloop_file_fmt_sector_size(struct xloop_file_fmt *xlo_fmt, * of its resources before the xloop file format @xlo_fmt is initialized and set * up with the new file format @file_fmt_type_new. */ -extern int xloop_file_fmt_change(struct xloop_file_fmt *xlo_fmt, - u32 file_fmt_type_new); - +extern int xloop_file_fmt_change(struct xloop_file_fmt *xlo_fmt, u32 file_fmt_type_new); /* helper functions of the subsystem */ @@ -382,7 +360,6 @@ extern int xloop_file_fmt_change(struct xloop_file_fmt *xlo_fmt, * Converts the specified numeric @file_fmt_type value into a human readable * string stating the file format as string in @file_fmt_name. */ -extern ssize_t xloop_file_fmt_print_type(u32 file_fmt_type, - char *file_fmt_name); +extern ssize_t xloop_file_fmt_print_type(u32 file_fmt_type, char *file_fmt_name); #endif diff --git a/src/kernel/xloop_file_fmt_qcow_cache.c b/src/kernel/xloop_file_fmt_qcow_cache.c index 14f0b75..d9701b6 100644 --- a/src/kernel/xloop_file_fmt_qcow_cache.c +++ b/src/kernel/xloop_file_fmt_qcow_cache.c @@ -1,4 +1,4 @@ -/* SPDX-License-Identifier: GPL-2.0 */ +// SPDX-License-Identifier: GPL-2.0 /* * xloop_file_fmt_qcow_cache.c * @@ -26,20 +26,19 @@ #include "xloop_file_fmt_qcow_main.h" #include "xloop_file_fmt_qcow_cache.h" -static inline void *__xloop_file_fmt_qcow_cache_get_table_addr( - struct xloop_file_fmt_qcow_cache *c, int table) +static inline void *__xloop_file_fmt_qcow_cache_get_table_addr(struct xloop_file_fmt_qcow_cache *c, int table) { - return (u8 *) c->table_array + (size_t) table * c->table_size; + return (u8 *)c->table_array + (size_t)table * c->table_size; } -static inline int __xloop_file_fmt_qcow_cache_get_table_idx( - struct xloop_file_fmt_qcow_cache *c, void *table) +static inline int __xloop_file_fmt_qcow_cache_get_table_idx(struct xloop_file_fmt_qcow_cache *c, void *table) { - ptrdiff_t table_offset = (u8 *) table - (u8 *) c->table_array; + ptrdiff_t table_offset = (u8 *)table - (u8 *)c->table_array; int idx = div_s64(table_offset, c->table_size); #ifdef ASSERT s32 rem_table_offset_mod_table_size; + div_s64_rem(table_offset, c->table_size, &rem_table_offset_mod_table_size); ASSERT(idx >= 0 && idx < c->size && rem_table_offset_mod_table_size == 0); #endif @@ -47,8 +46,8 @@ static inline int __xloop_file_fmt_qcow_cache_get_table_idx( return idx; } -static inline const char *__xloop_file_fmt_qcow_cache_get_name( - struct xloop_file_fmt *xlo_fmt, struct xloop_file_fmt_qcow_cache *c) +static inline const char *__xloop_file_fmt_qcow_cache_get_name(struct xloop_file_fmt *xlo_fmt, + struct xloop_file_fmt_qcow_cache *c) { struct xloop_file_fmt_qcow_data *qcow_data = xlo_fmt->private_data; @@ -62,8 +61,8 @@ static inline const char *__xloop_file_fmt_qcow_cache_get_name( } } -struct xloop_file_fmt_qcow_cache *xloop_file_fmt_qcow_cache_create( - struct xloop_file_fmt *xlo_fmt, int num_tables, unsigned table_size) +struct xloop_file_fmt_qcow_cache *xloop_file_fmt_qcow_cache_create(struct xloop_file_fmt *xlo_fmt, int num_tables, + unsigned int table_size) { #ifdef CONFIG_DEBUG_DRIVER struct xloop_file_fmt_qcow_data *qcow_data = xlo_fmt->private_data; @@ -76,14 +75,12 @@ struct xloop_file_fmt_qcow_cache *xloop_file_fmt_qcow_cache_create( ASSERT(table_size <= qcow_data->cluster_size); c = kzalloc(sizeof(*c), GFP_KERNEL); - if (!c) { + if (!c) return NULL; - } c->size = num_tables; c->table_size = table_size; - c->entries = vzalloc(sizeof(struct xloop_file_fmt_qcow_cache_table) * - num_tables); + c->entries = vzalloc(sizeof(struct xloop_file_fmt_qcow_cache_table) * num_tables); c->table_array = vzalloc(num_tables * c->table_size); if (!c->entries || !c->table_array) { @@ -102,30 +99,27 @@ void xloop_file_fmt_qcow_cache_destroy(struct xloop_file_fmt *xlo_fmt) struct xloop_file_fmt_qcow_cache *c = qcow_data->l2_table_cache; int i; - for (i = 0; i < c->size; i++) { + for (i = 0; i < c->size; i++) ASSERT(c->entries[i].ref == 0); - } vfree(c->table_array); vfree(c->entries); kfree(c); } -static int __xloop_file_fmt_qcow_cache_entry_flush( - struct xloop_file_fmt *xlo_fmt, struct xloop_file_fmt_qcow_cache *c, int i) +static int __xloop_file_fmt_qcow_cache_entry_flush(struct xloop_file_fmt *xlo_fmt, struct xloop_file_fmt_qcow_cache *c, + int i) { if (!c->entries[i].dirty || !c->entries[i].offset) { return 0; } else { - dev_err_ratelimited(xloop_file_fmt_to_dev(xlo_fmt), "flush dirty " - "cache tables is not supported yet\n"); - return -ENOSYS; + dev_err_ratelimited(xloop_file_fmt_to_dev(xlo_fmt), "flush dirty cache tables is not supported yet\n"); + return -EINVAL; } } -static int __xloop_file_fmt_qcow_cache_do_get(struct xloop_file_fmt *xlo_fmt, - struct xloop_file_fmt_qcow_cache *c, u64 offset, void **table, - bool read_from_disk) +static int __xloop_file_fmt_qcow_cache_do_get(struct xloop_file_fmt *xlo_fmt, struct xloop_file_fmt_qcow_cache *c, + u64 offset, void **table, bool read_from_disk) { struct xloop_device *xlo = xloop_file_fmt_get_xlo(xlo_fmt); int i; @@ -140,9 +134,9 @@ static int __xloop_file_fmt_qcow_cache_do_get(struct xloop_file_fmt *xlo_fmt, ASSERT(offset != 0); if (!IS_ALIGNED(offset, c->table_size)) { - dev_err_ratelimited(xloop_file_fmt_to_dev(xlo_fmt), "cannot get entry " - "from %s cache: offset %llx is unaligned\n", - __xloop_file_fmt_qcow_cache_get_name(xlo_fmt, c), offset); + dev_err_ratelimited(xloop_file_fmt_to_dev(xlo_fmt), + "cannot get entry from %s cache: offset %llx is unaligned\n", + __xloop_file_fmt_qcow_cache_get_name(xlo_fmt, c), offset); return -EIO; } @@ -151,41 +145,37 @@ static int __xloop_file_fmt_qcow_cache_do_get(struct xloop_file_fmt *xlo_fmt, div_u64_rem(offset_div_table_size, c->size, &lookup_index); i = lookup_index; do { - const struct xloop_file_fmt_qcow_cache_table *t = - &c->entries[i]; - if (t->offset == offset) { + const struct xloop_file_fmt_qcow_cache_table *t = &c->entries[i]; + + if (t->offset == offset) goto found; - } + if (t->ref == 0 && t->lru_counter < min_lru_counter) { min_lru_counter = t->lru_counter; min_lru_index = i; } - if (++i == c->size) { + if (++i == c->size) i = 0; - } + } while (i != lookup_index); if (min_lru_index == -1) { BUG(); - panic("Oops: This can't happen in current synchronous code, " - "but leave the check here as a reminder for whoever " - "starts using AIO with the QCOW cache"); + panic("Oops: This can't happen in current synchronous code while using AIO with the QCOW cache\n"); } /* Cache miss: write a table back and replace it */ i = min_lru_index; ret = __xloop_file_fmt_qcow_cache_entry_flush(xlo_fmt, c, i); - if (ret < 0) { + if (ret < 0) return ret; - } c->entries[i].offset = 0; if (read_from_disk) { read_offset = offset; - len = kernel_read(xlo->xlo_backing_file, - __xloop_file_fmt_qcow_cache_get_table_addr(c, i), - c->table_size, &read_offset); + len = kernel_read(xlo->xlo_backing_file, __xloop_file_fmt_qcow_cache_get_table_addr(c, i), + c->table_size, &read_offset); if (len < 0) { len = ret; return ret; @@ -202,14 +192,12 @@ found: return 0; } -int xloop_file_fmt_qcow_cache_get(struct xloop_file_fmt *xlo_fmt, u64 offset, - void **table) +int xloop_file_fmt_qcow_cache_get(struct xloop_file_fmt *xlo_fmt, u64 offset, void **table) { struct xloop_file_fmt_qcow_data *qcow_data = xlo_fmt->private_data; struct xloop_file_fmt_qcow_cache *c = qcow_data->l2_table_cache; - return __xloop_file_fmt_qcow_cache_do_get(xlo_fmt, c, offset, table, - true); + return __xloop_file_fmt_qcow_cache_do_get(xlo_fmt, c, offset, table, true); } void xloop_file_fmt_qcow_cache_put(struct xloop_file_fmt *xlo_fmt, void **table) @@ -221,9 +209,8 @@ void xloop_file_fmt_qcow_cache_put(struct xloop_file_fmt *xlo_fmt, void **table) c->entries[i].ref--; *table = NULL; - if (c->entries[i].ref == 0) { + if (c->entries[i].ref == 0) c->entries[i].lru_counter = ++c->lru_counter; - } ASSERT(c->entries[i].ref >= 0); } diff --git a/src/kernel/xloop_file_fmt_qcow_cache.h b/src/kernel/xloop_file_fmt_qcow_cache.h index 527d4ae..213a8b4 100644 --- a/src/kernel/xloop_file_fmt_qcow_cache.h +++ b/src/kernel/xloop_file_fmt_qcow_cache.h @@ -34,18 +34,13 @@ struct xloop_file_fmt_qcow_cache { u64 cache_clean_lru_counter; }; -extern struct xloop_file_fmt_qcow_cache *xloop_file_fmt_qcow_cache_create( - struct xloop_file_fmt *xlo_fmt, - int num_tables, - unsigned table_size); +extern struct xloop_file_fmt_qcow_cache *xloop_file_fmt_qcow_cache_create(struct xloop_file_fmt *xlo_fmt, + int num_tables, unsigned int table_size); extern void xloop_file_fmt_qcow_cache_destroy(struct xloop_file_fmt *xlo_fmt); -extern int xloop_file_fmt_qcow_cache_get(struct xloop_file_fmt *xlo_fmt, - u64 offset, - void **table); +extern int xloop_file_fmt_qcow_cache_get(struct xloop_file_fmt *xlo_fmt, u64 offset, void **table); -extern void xloop_file_fmt_qcow_cache_put(struct xloop_file_fmt *xlo_fmt, - void **table); +extern void xloop_file_fmt_qcow_cache_put(struct xloop_file_fmt *xlo_fmt, void **table); #endif diff --git a/src/kernel/xloop_file_fmt_qcow_cluster.c b/src/kernel/xloop_file_fmt_qcow_cluster.c index 8394c76..6f11923 100644 --- a/src/kernel/xloop_file_fmt_qcow_cluster.c +++ b/src/kernel/xloop_file_fmt_qcow_cluster.c @@ -1,4 +1,4 @@ -/* SPDX-License-Identifier: GPL-2.0 */ +// SPDX-License-Identifier: GPL-2.0 /* * xloop_file_fmt_qcow_cluster.c * @@ -34,19 +34,17 @@ * the cache is used; otherwise the L2 slice is loaded from the image * file. */ -static int __xloop_file_fmt_qcow_cluster_l2_load(struct xloop_file_fmt *xlo_fmt, - u64 offset, u64 l2_offset, u64 **l2_slice) +static int __xloop_file_fmt_qcow_cluster_l2_load(struct xloop_file_fmt *xlo_fmt, u64 offset, u64 l2_offset, + u64 **l2_slice) { struct xloop_file_fmt_qcow_data *qcow_data = xlo_fmt->private_data; - int start_of_slice = xloop_file_fmt_qcow_l2_entry_size(qcow_data) * ( - xloop_file_fmt_qcow_offset_to_l2_index(qcow_data, offset) - - xloop_file_fmt_qcow_offset_to_l2_slice_index(qcow_data, offset) - ); + int start_of_slice = xloop_file_fmt_qcow_l2_entry_size(qcow_data) * + (xloop_file_fmt_qcow_offset_to_l2_index(qcow_data, offset) - + xloop_file_fmt_qcow_offset_to_l2_slice_index(qcow_data, offset)); ASSERT(qcow_data->l2_table_cache != NULL); - return xloop_file_fmt_qcow_cache_get(xlo_fmt, l2_offset + start_of_slice, - (void **) l2_slice); + return xloop_file_fmt_qcow_cache_get(xlo_fmt, l2_offset + start_of_slice, (void **)l2_slice); } /* @@ -61,45 +59,41 @@ static int __xloop_file_fmt_qcow_cluster_l2_load(struct xloop_file_fmt *xlo_fmt, * If the L2 entry is invalid return -errno and set @type to * QCOW_SUBCLUSTER_INVALID. */ -static int __xloop_file_fmt_qcow_get_subcluster_range_type( - struct xloop_file_fmt *xlo_fmt, u64 l2_entry, u64 l2_bitmap, - unsigned int sc_from, enum xloop_file_fmt_qcow_subcluster_type *type) +static int __xloop_file_fmt_qcow_get_subcluster_range_type(struct xloop_file_fmt *xlo_fmt, u64 l2_entry, u64 l2_bitmap, + unsigned int sc_from, + enum xloop_file_fmt_qcow_subcluster_type *type) { - struct xloop_file_fmt_qcow_data *qcow_data = xlo_fmt->private_data; - u32 val; - - *type = xloop_file_fmt_qcow_get_subcluster_type(xlo_fmt, l2_entry, - l2_bitmap, sc_from); - - if (*type == QCOW_SUBCLUSTER_INVALID) { - return -EINVAL; - } else if (!xloop_file_fmt_qcow_has_subclusters(qcow_data) || - *type == QCOW_SUBCLUSTER_COMPRESSED) { - return qcow_data->subclusters_per_cluster - sc_from; - } - - switch (*type) { - case QCOW_SUBCLUSTER_NORMAL: - val = l2_bitmap | QCOW_OFLAG_SUB_ALLOC_RANGE(0, sc_from); - return __builtin_ctz(~val) - sc_from; - - case QCOW_SUBCLUSTER_ZERO_PLAIN: - case QCOW_SUBCLUSTER_ZERO_ALLOC: - val = (l2_bitmap | QCOW_OFLAG_SUB_ZERO_RANGE(0, sc_from)) >> 32; - return __builtin_ctz(~val) - sc_from; - - case QCOW_SUBCLUSTER_UNALLOCATED_PLAIN: - case QCOW_SUBCLUSTER_UNALLOCATED_ALLOC: - val = ((l2_bitmap >> 32) | l2_bitmap) - & ~QCOW_OFLAG_SUB_ALLOC_RANGE(0, sc_from); - return __builtin_ctz(val) - sc_from; - - default: - /* not reachable */ - ASSERT(false); + struct xloop_file_fmt_qcow_data *qcow_data = xlo_fmt->private_data; + u32 val; + + *type = xloop_file_fmt_qcow_get_subcluster_type(xlo_fmt, l2_entry, l2_bitmap, sc_from); + + if (*type == QCOW_SUBCLUSTER_INVALID) + return -EINVAL; + else if (!xloop_file_fmt_qcow_has_subclusters(qcow_data) || *type == QCOW_SUBCLUSTER_COMPRESSED) + return qcow_data->subclusters_per_cluster - sc_from; + + switch (*type) { + case QCOW_SUBCLUSTER_NORMAL: + val = l2_bitmap | QCOW_OFLAG_SUB_ALLOC_RANGE(0, sc_from); + return __builtin_ctz(~val) - sc_from; + + case QCOW_SUBCLUSTER_ZERO_PLAIN: + case QCOW_SUBCLUSTER_ZERO_ALLOC: + val = (l2_bitmap | QCOW_OFLAG_SUB_ZERO_RANGE(0, sc_from)) >> 32; + return __builtin_ctz(~val) - sc_from; + + case QCOW_SUBCLUSTER_UNALLOCATED_PLAIN: + case QCOW_SUBCLUSTER_UNALLOCATED_ALLOC: + val = ((l2_bitmap >> 32) | l2_bitmap) & ~QCOW_OFLAG_SUB_ALLOC_RANGE(0, sc_from); + return __builtin_ctz(val) - sc_from; + + default: + /* not reachable */ + ASSERT(false); *type = QCOW_SUBCLUSTER_INVALID; return 0; - } + } } /* @@ -115,58 +109,52 @@ static int __xloop_file_fmt_qcow_get_subcluster_range_type( * On failure return -errno and update @l2_index to point to the * invalid entry. */ -static int __xloop_file_fmt_qcow_count_contiguous_subclusters( - struct xloop_file_fmt *xlo_fmt, int nb_clusters, unsigned int sc_index, - u64 *l2_slice, unsigned int *l2_index) +static int __xloop_file_fmt_qcow_count_contiguous_subclusters(struct xloop_file_fmt *xlo_fmt, int nb_clusters, + unsigned int sc_index, u64 *l2_slice, + unsigned int *l2_index) { - struct xloop_file_fmt_qcow_data *qcow_data = xlo_fmt->private_data; - int i, count = 0; - bool check_offset = false; - u64 expected_offset = 0; - enum xloop_file_fmt_qcow_subcluster_type expected_type = - QCOW_SUBCLUSTER_NORMAL; + struct xloop_file_fmt_qcow_data *qcow_data = xlo_fmt->private_data; + int i, count = 0; + bool check_offset = false; + u64 expected_offset = 0; + enum xloop_file_fmt_qcow_subcluster_type expected_type = QCOW_SUBCLUSTER_NORMAL; enum xloop_file_fmt_qcow_subcluster_type type; - ASSERT(*l2_index + nb_clusters <= qcow_data->l2_slice_size); - - for (i = 0; i < nb_clusters; i++) { - unsigned int first_sc = (i == 0) ? sc_index : 0; - u64 l2_entry = xloop_file_fmt_qcow_get_l2_entry(qcow_data, l2_slice, - *l2_index + i); - u64 l2_bitmap = xloop_file_fmt_qcow_get_l2_bitmap(qcow_data, l2_slice, - *l2_index + i); - int ret = __xloop_file_fmt_qcow_get_subcluster_range_type(xlo_fmt, - l2_entry, l2_bitmap, first_sc, &type); - if (ret < 0) { - *l2_index += i; /* Point to the invalid entry */ - return -EIO; - } - if (i == 0) { - if (type == QCOW_SUBCLUSTER_COMPRESSED) { - /* Compressed clusters are always processed one by one */ - return ret; - } - expected_type = type; - expected_offset = l2_entry & QCOW_L2E_OFFSET_MASK; - check_offset = (type == QCOW_SUBCLUSTER_NORMAL || - type == QCOW_SUBCLUSTER_ZERO_ALLOC || - type == QCOW_SUBCLUSTER_UNALLOCATED_ALLOC); - } else if (type != expected_type) { - break; - } else if (check_offset) { - expected_offset += qcow_data->cluster_size; - if (expected_offset != (l2_entry & QCOW_L2E_OFFSET_MASK)) { - break; - } - } - count += ret; - /* Stop if there are type changes before the end of the cluster */ - if (first_sc + ret < qcow_data->subclusters_per_cluster) { - break; - } - } - - return count; + ASSERT(*l2_index + nb_clusters <= qcow_data->l2_slice_size); + + for (i = 0; i < nb_clusters; i++) { + unsigned int first_sc = (i == 0) ? sc_index : 0; + u64 l2_entry = xloop_file_fmt_qcow_get_l2_entry(qcow_data, l2_slice, *l2_index + i); + u64 l2_bitmap = xloop_file_fmt_qcow_get_l2_bitmap(qcow_data, l2_slice, *l2_index + i); + int ret = + __xloop_file_fmt_qcow_get_subcluster_range_type(xlo_fmt, l2_entry, l2_bitmap, first_sc, &type); + if (ret < 0) { + *l2_index += i; /* Point to the invalid entry */ + return -EIO; + } + if (i == 0) { + if (type == QCOW_SUBCLUSTER_COMPRESSED) { + /* Compressed clusters are always processed one by one */ + return ret; + } + expected_type = type; + expected_offset = l2_entry & QCOW_L2E_OFFSET_MASK; + check_offset = (type == QCOW_SUBCLUSTER_NORMAL || type == QCOW_SUBCLUSTER_ZERO_ALLOC || + type == QCOW_SUBCLUSTER_UNALLOCATED_ALLOC); + } else if (type != expected_type) { + break; + } else if (check_offset) { + expected_offset += qcow_data->cluster_size; + if (expected_offset != (l2_entry & QCOW_L2E_OFFSET_MASK)) + break; + } + count += ret; + /* Stop if there are type changes before the end of the cluster */ + if (first_sc + ret < qcow_data->subclusters_per_cluster) + break; + } + + return count; } /* @@ -190,9 +178,8 @@ static int __xloop_file_fmt_qcow_count_contiguous_subclusters( * * Returns 0 on success, -errno in error cases. */ -int xloop_file_fmt_qcow_get_host_offset(struct xloop_file_fmt *xlo_fmt, - u64 offset, unsigned int *bytes, u64 *host_offset, - enum xloop_file_fmt_qcow_subcluster_type *subcluster_type) +int xloop_file_fmt_qcow_get_host_offset(struct xloop_file_fmt *xlo_fmt, u64 offset, unsigned int *bytes, + u64 *host_offset, enum xloop_file_fmt_qcow_subcluster_type *subcluster_type) { struct xloop_file_fmt_qcow_data *qcow_data = xlo_fmt->private_data; unsigned int l2_index, sc_index; @@ -204,21 +191,20 @@ int xloop_file_fmt_qcow_get_host_offset(struct xloop_file_fmt *xlo_fmt, int ret; u64 host_cluster_offset; - offset_in_cluster = xloop_file_fmt_qcow_offset_into_cluster(qcow_data, - offset); - bytes_needed = (u64) *bytes + offset_in_cluster; + offset_in_cluster = xloop_file_fmt_qcow_offset_into_cluster(qcow_data, offset); + bytes_needed = (u64)*bytes + offset_in_cluster; - /* compute how many bytes there are between the start of the cluster + /* + * compute how many bytes there are between the start of the cluster * containing offset and the end of the l2 slice that contains - * the entry pointing to it */ - bytes_available = ((u64)( - qcow_data->l2_slice_size - - xloop_file_fmt_qcow_offset_to_l2_slice_index(qcow_data, offset)) - ) << qcow_data->cluster_bits; + * the entry pointing to it + */ + bytes_available = + ((u64)(qcow_data->l2_slice_size - xloop_file_fmt_qcow_offset_to_l2_slice_index(qcow_data, offset))) + << qcow_data->cluster_bits; - if (bytes_needed > bytes_available) { + if (bytes_needed > bytes_available) bytes_needed = bytes_available; - } *host_offset = 0; @@ -236,52 +222,45 @@ int xloop_file_fmt_qcow_get_host_offset(struct xloop_file_fmt *xlo_fmt, } if (xloop_file_fmt_qcow_offset_into_cluster(qcow_data, l2_offset)) { - dev_err_ratelimited(xloop_file_fmt_to_dev(xlo_fmt), "L2 table offset " - "%llx unaligned (L1 index: %llx)", l2_offset, l1_index); + dev_err_ratelimited(xloop_file_fmt_to_dev(xlo_fmt), "L2 table offset %llx unaligned (L1 index: %llx)", + l2_offset, l1_index); return -EIO; } /* load the l2 slice in memory */ - ret = __xloop_file_fmt_qcow_cluster_l2_load(xlo_fmt, offset, l2_offset, - &l2_slice); - if (ret < 0) { + ret = __xloop_file_fmt_qcow_cluster_l2_load(xlo_fmt, offset, l2_offset, &l2_slice); + if (ret < 0) return ret; - } /* find the cluster offset for the given disk offset */ - l2_index = xloop_file_fmt_qcow_offset_to_l2_slice_index(qcow_data, - offset); + l2_index = xloop_file_fmt_qcow_offset_to_l2_slice_index(qcow_data, offset); sc_index = xloop_file_fmt_qcow_offset_to_sc_index(qcow_data, offset); - l2_entry = xloop_file_fmt_qcow_get_l2_entry(qcow_data, l2_slice, - l2_index); - l2_bitmap = xloop_file_fmt_qcow_get_l2_bitmap(qcow_data, l2_slice, - l2_index); - - nb_clusters = xloop_file_fmt_qcow_size_to_clusters(qcow_data, - bytes_needed); - /* bytes_needed <= *bytes + offset_in_cluster, both of which are + l2_entry = xloop_file_fmt_qcow_get_l2_entry(qcow_data, l2_slice, l2_index); + l2_bitmap = xloop_file_fmt_qcow_get_l2_bitmap(qcow_data, l2_slice, l2_index); + + nb_clusters = xloop_file_fmt_qcow_size_to_clusters(qcow_data, bytes_needed); + /* + * bytes_needed <= *bytes + offset_in_cluster, both of which are * unsigned integers; the minimum cluster size is 512, so this - * assertion is always true */ + * assertion is always true + */ ASSERT(nb_clusters <= INT_MAX); - type = xloop_file_fmt_qcow_get_subcluster_type(xlo_fmt, l2_entry, - l2_bitmap, sc_index); - if (qcow_data->qcow_version < 3 && ( - type == QCOW_SUBCLUSTER_ZERO_PLAIN || - type == QCOW_SUBCLUSTER_ZERO_ALLOC)) { - dev_err_ratelimited(xloop_file_fmt_to_dev(xlo_fmt), "zero cluster " - "entry found in pre-v3 image (L2 offset: %llx, L2 index: %x)\n", - l2_offset, l2_index); + type = xloop_file_fmt_qcow_get_subcluster_type(xlo_fmt, l2_entry, l2_bitmap, sc_index); + if (qcow_data->qcow_version < 3 && (type == QCOW_SUBCLUSTER_ZERO_PLAIN || type == QCOW_SUBCLUSTER_ZERO_ALLOC)) { + dev_err_ratelimited(xloop_file_fmt_to_dev(xlo_fmt), + "zero cluster entry found in pre-v3 image (L2 offset: %llx, L2 index: %x)\n", + l2_offset, l2_index); ret = -EIO; goto fail; } switch (type) { - case QCOW_SUBCLUSTER_INVALID: - break; /* This is handled by count_contiguous_subclusters() below */ + case QCOW_SUBCLUSTER_INVALID: + break; /* This is handled by count_contiguous_subclusters() below */ case QCOW_SUBCLUSTER_COMPRESSED: if (xloop_file_fmt_qcow_has_data_file(qcow_data)) { - dev_err_ratelimited(xloop_file_fmt_to_dev(xlo_fmt), "compressed " - "cluster entry found in image with external data file " + dev_err_ratelimited(xloop_file_fmt_to_dev(xlo_fmt), + "compressed cluster entry found in image with external data file " "(L2 offset: %llx, L2 index: %x)\n", l2_offset, l2_index); ret = -EIO; goto fail; @@ -296,20 +275,17 @@ int xloop_file_fmt_qcow_get_host_offset(struct xloop_file_fmt *xlo_fmt, case QCOW_SUBCLUSTER_UNALLOCATED_ALLOC: host_cluster_offset = l2_entry & QCOW_L2E_OFFSET_MASK; *host_offset = host_cluster_offset + offset_in_cluster; - if (xloop_file_fmt_qcow_offset_into_cluster(qcow_data, - host_cluster_offset)) { - dev_err_ratelimited(xloop_file_fmt_to_dev(xlo_fmt), "cluster " - "allocation offset %llx unaligned (L2 offset: %llx, " - "L2 index: %x)\n", host_cluster_offset, l2_offset, l2_index); + if (xloop_file_fmt_qcow_offset_into_cluster(qcow_data, host_cluster_offset)) { + dev_err_ratelimited(xloop_file_fmt_to_dev(xlo_fmt), + "cluster allocation offset %llx unaligned (L2 offset: %llx, L2 index: %x)\n", + host_cluster_offset, l2_offset, l2_index); ret = -EIO; goto fail; } - if (xloop_file_fmt_qcow_has_data_file(qcow_data) && - *host_offset != offset) { - dev_err_ratelimited(xloop_file_fmt_to_dev(xlo_fmt), "external " - "data file host cluster offset %llx does not match guest " - "cluster offset: %llx, L2 index: %x)\n", host_cluster_offset, - offset - offset_in_cluster, l2_index); + if (xloop_file_fmt_qcow_has_data_file(qcow_data) && *host_offset != offset) { + dev_err_ratelimited(xloop_file_fmt_to_dev(xlo_fmt), + "external data file host cluster offset %llx does not match guest cluster offset: " + "%llx, L2 index: %x)\n", host_cluster_offset, offset - offset_in_cluster, l2_index); ret = -EIO; goto fail; } @@ -318,28 +294,28 @@ int xloop_file_fmt_qcow_get_host_offset(struct xloop_file_fmt *xlo_fmt, BUG(); } - sc = __xloop_file_fmt_qcow_count_contiguous_subclusters(xlo_fmt, - nb_clusters, sc_index, l2_slice, &l2_index); + sc = __xloop_file_fmt_qcow_count_contiguous_subclusters(xlo_fmt, nb_clusters, sc_index, l2_slice, &l2_index); if (sc < 0) { - dev_err_ratelimited(xloop_file_fmt_to_dev(xlo_fmt), "invalid cluster " - "entry found (L2 offset: %#llx, L2 index: %#x)", l2_offset, - l2_index); - ret = -EIO; - goto fail; - } - xloop_file_fmt_qcow_cache_put(xlo_fmt, (void **) &l2_slice); + dev_err_ratelimited(xloop_file_fmt_to_dev(xlo_fmt), + "invalid cluster entry found (L2 offset: %#llx, L2 index: %#x)", l2_offset, + l2_index); + ret = -EIO; + goto fail; + } + xloop_file_fmt_qcow_cache_put(xlo_fmt, (void **)&l2_slice); - bytes_available = ((s64) sc + sc_index) << qcow_data->subcluster_bits; + bytes_available = ((s64)sc + sc_index) << qcow_data->subcluster_bits; out: - if (bytes_available > bytes_needed) { + if (bytes_available > bytes_needed) bytes_available = bytes_needed; - } - /* bytes_available <= bytes_needed <= *bytes + offset_in_cluster; + /* + * bytes_available <= bytes_needed <= *bytes + offset_in_cluster; * subtracting offset_in_cluster will therefore definitely yield - * something not exceeding UINT_MAX */ + * something not exceeding UINT_MAX + */ ASSERT(bytes_available - offset_in_cluster <= UINT_MAX); *bytes = bytes_available - offset_in_cluster; @@ -348,6 +324,6 @@ out: return 0; fail: - xloop_file_fmt_qcow_cache_put(xlo_fmt, (void **) &l2_slice); + xloop_file_fmt_qcow_cache_put(xlo_fmt, (void **)&l2_slice); return ret; } diff --git a/src/kernel/xloop_file_fmt_qcow_cluster.h b/src/kernel/xloop_file_fmt_qcow_cluster.h index a3716f5..8be0592 100644 --- a/src/kernel/xloop_file_fmt_qcow_cluster.h +++ b/src/kernel/xloop_file_fmt_qcow_cluster.h @@ -15,8 +15,8 @@ #include "xloop_file_fmt.h" -extern int xloop_file_fmt_qcow_get_host_offset(struct xloop_file_fmt *xlo_fmt, - u64 offset, unsigned int *bytes, u64 *host_offset, - enum xloop_file_fmt_qcow_subcluster_type *subcluster_type); +extern int xloop_file_fmt_qcow_get_host_offset(struct xloop_file_fmt *xlo_fmt, u64 offset, unsigned int *bytes, + u64 *host_offset, + enum xloop_file_fmt_qcow_subcluster_type *subcluster_type); #endif diff --git a/src/kernel/xloop_file_fmt_qcow_main.c b/src/kernel/xloop_file_fmt_qcow_main.c index 376273d..e642160 100644 --- a/src/kernel/xloop_file_fmt_qcow_main.c +++ b/src/kernel/xloop_file_fmt_qcow_main.c @@ -1,4 +1,4 @@ -/* SPDX-License-Identifier: GPL-2.0 */ +// SPDX-License-Identifier: GPL-2.0 /* * xloop_file_fmt_qcow.c * @@ -36,15 +36,15 @@ #include "xloop_file_fmt_qcow_cluster.h" #ifdef CONFIG_ZSTD_DECOMPRESS -#define ZSTD_WINDOWLOG_LIMIT_DEFAULT 27 -#define ZSTD_MAXWINDOWSIZE ((U32_C(1) << ZSTD_WINDOWLOG_LIMIT_DEFAULT) + 1) +#define ZSTD_WINDOWLOG_LIMIT_DEFAULT 27 +#define ZSTD_MAXWINDOWSIZE ((U32_C(1) << ZSTD_WINDOWLOG_LIMIT_DEFAULT) + 1) #endif -typedef ssize_t (*qcow_file_fmt_decompress_fn)(struct xloop_file_fmt *xlo_fmt, - void *dest, size_t dest_size, const void *src, size_t src_size); +typedef ssize_t (*qcow_file_fmt_decompress_fn)(struct xloop_file_fmt *xlo_fmt, void *dest, size_t dest_size, + const void *src, size_t src_size); -static int __qcow_file_fmt_header_read(struct xloop_file_fmt *xlo_fmt, - struct file *file, struct xloop_file_fmt_qcow_header *header) +static int __qcow_file_fmt_header_read(struct xloop_file_fmt *xlo_fmt, struct file *file, + struct xloop_file_fmt_qcow_header *header) { ssize_t len; loff_t offset; @@ -54,8 +54,7 @@ static int __qcow_file_fmt_header_read(struct xloop_file_fmt *xlo_fmt, offset = 0; len = kernel_read(file, header, sizeof(*header), &offset); if (len < 0) { - dev_err(xloop_file_fmt_to_dev(xlo_fmt), "could not read QCOW " - "header\n"); + dev_err(xloop_file_fmt_to_dev(xlo_fmt), "could not read QCOW header\n"); return len; } @@ -68,40 +67,33 @@ static int __qcow_file_fmt_header_read(struct xloop_file_fmt *xlo_fmt, header->crypt_method = be32_to_cpu(header->crypt_method); header->l1_size = be32_to_cpu(header->l1_size); header->l1_table_offset = be64_to_cpu(header->l1_table_offset); - header->refcount_table_offset = - be64_to_cpu(header->refcount_table_offset); - header->refcount_table_clusters = - be32_to_cpu(header->refcount_table_clusters); + header->refcount_table_offset = be64_to_cpu(header->refcount_table_offset); + header->refcount_table_clusters = be32_to_cpu(header->refcount_table_clusters); header->nb_snapshots = be32_to_cpu(header->nb_snapshots); header->snapshots_offset = be64_to_cpu(header->snapshots_offset); /* check QCOW file format and header version */ if (header->magic != QCOW_MAGIC) { - dev_err(xloop_file_fmt_to_dev(xlo_fmt), "image is not in QCOW " - "format\n"); + dev_err(xloop_file_fmt_to_dev(xlo_fmt), "image is not in QCOW format\n"); return -EINVAL; } if (header->version < 2 || header->version > 3) { - dev_err(xloop_file_fmt_to_dev(xlo_fmt), "unsupported QCOW " - "version %d\n", header->version); + dev_err(xloop_file_fmt_to_dev(xlo_fmt), "unsupported QCOW version %d\n", header->version); return -ENOTSUPP; } /* initialize version 3 header fields */ if (header->version == 2) { - header->incompatible_features = 0; - header->compatible_features = 0; - header->autoclear_features = 0; - header->refcount_order = 4; - header->header_length = 72; + header->incompatible_features = 0; + header->compatible_features = 0; + header->autoclear_features = 0; + header->refcount_order = 4; + header->header_length = 72; } else { - header->incompatible_features = - be64_to_cpu(header->incompatible_features); - header->compatible_features = - be64_to_cpu(header->compatible_features); - header->autoclear_features = - be64_to_cpu(header->autoclear_features); + header->incompatible_features = be64_to_cpu(header->incompatible_features); + header->compatible_features = be64_to_cpu(header->compatible_features); + header->autoclear_features = be64_to_cpu(header->autoclear_features); header->refcount_order = be32_to_cpu(header->refcount_order); header->header_length = be32_to_cpu(header->header_length); @@ -114,9 +106,8 @@ static int __qcow_file_fmt_header_read(struct xloop_file_fmt *xlo_fmt, return ret; } -static int __qcow_file_fmt_validate_table(struct xloop_file_fmt *xlo_fmt, - u64 offset, u64 entries, size_t entry_len, s64 max_size_bytes, - const char *table_name) +static int __qcow_file_fmt_validate_table(struct xloop_file_fmt *xlo_fmt, u64 offset, u64 entries, size_t entry_len, + s64 max_size_bytes, const char *table_name) { struct xloop_file_fmt_qcow_data *qcow_data = xlo_fmt->private_data; @@ -125,24 +116,24 @@ static int __qcow_file_fmt_validate_table(struct xloop_file_fmt *xlo_fmt, return -EFBIG; } - /* Use signed S64_MAX as the maximum even for u64 header fields, - * because values will be passed to qemu functions taking s64. */ - if ((S64_MAX - entries * entry_len < offset) || ( - xloop_file_fmt_qcow_offset_into_cluster(qcow_data, offset) != 0) - ) { - dev_err(xloop_file_fmt_to_dev(xlo_fmt), "%s offset invalid", - table_name); + /* + * Use signed S64_MAX as the maximum even for u64 header fields, + * because values will be passed to qemu functions taking s64. + */ + if ((S64_MAX - entries * entry_len < offset) || + (xloop_file_fmt_qcow_offset_into_cluster(qcow_data, offset) != 0)) { + dev_err(xloop_file_fmt_to_dev(xlo_fmt), "%s offset invalid", table_name); return -EINVAL; } return 0; } -static inline loff_t __qcow_file_fmt_rq_get_pos(struct xloop_file_fmt *xlo_fmt, - struct request *rq) +static inline loff_t __qcow_file_fmt_rq_get_pos(struct xloop_file_fmt *xlo_fmt, struct request *rq) { struct xloop_device *xlo = xloop_file_fmt_get_xlo(xlo_fmt); - return ((loff_t) blk_rq_pos(rq) << 9) + xlo->xlo_offset; + + return ((loff_t)blk_rq_pos(rq) << 9) + xlo->xlo_offset; } static int __qcow_file_fmt_compression_init(struct xloop_file_fmt *xlo_fmt) @@ -168,10 +159,10 @@ static int __qcow_file_fmt_compression_init(struct xloop_file_fmt *xlo_fmt) /* set up ZLIB decompression stream */ ret = zlib_inflateInit2(qcow_data->zlib_dstrm, -12); - if (ret != Z_OK) { - ret = -EIO; + if (ret != Z_OK) { + ret = -EIO; goto out_free_zlib_dworkspace; - } + } #ifdef CONFIG_ZSTD_DECOMPRESS /* create workspace for ZSTD decompression stream */ @@ -183,8 +174,7 @@ static int __qcow_file_fmt_compression_init(struct xloop_file_fmt *xlo_fmt) } /* set up ZSTD decompression stream */ - qcow_data->zstd_dstrm = ZSTD_initDStream(ZSTD_MAXWINDOWSIZE, - qcow_data->zstd_dworkspace, workspace_size); + qcow_data->zstd_dstrm = ZSTD_initDStream(ZSTD_MAXWINDOWSIZE, qcow_data->zstd_dworkspace, workspace_size); if (!qcow_data->zstd_dstrm) { ret = -EINVAL; goto out_free_zstd_dworkspace; @@ -237,85 +227,53 @@ static void __qcow_file_fmt_compression_exit(struct xloop_file_fmt *xlo_fmt) #ifdef CONFIG_DEBUG_FS static void __qcow_file_fmt_header_to_buf(struct xloop_file_fmt *xlo_fmt, - const struct xloop_file_fmt_qcow_header *header) + const struct xloop_file_fmt_qcow_header *header) { struct xloop_file_fmt_qcow_data *qcow_data = xlo_fmt->private_data; char *header_buf = qcow_data->dbgfs_file_qcow_header_buf; ssize_t len = 0; - len += sprintf(header_buf + len, "magic: %d\n", - header->magic); - len += sprintf(header_buf + len, "version: %d\n", - header->version); - len += sprintf(header_buf + len, "backing_file_offset: %lld\n", - header->backing_file_offset); - len += sprintf(header_buf + len, "backing_file_size: %d\n", - header->backing_file_size); - len += sprintf(header_buf + len, "cluster_bits: %d\n", - header->cluster_bits); - len += sprintf(header_buf + len, "size: %lld\n", - header->size); - len += sprintf(header_buf + len, "crypt_method: %d\n", - header->crypt_method); - len += sprintf(header_buf + len, "l1_size: %d\n", - header->l1_size); - len += sprintf(header_buf + len, "l1_table_offset: %lld\n", - header->l1_table_offset); - len += sprintf(header_buf + len, "refcount_table_offset: %lld\n", - header->refcount_table_offset); - len += sprintf(header_buf + len, "refcount_table_clusters: %d\n", - header->refcount_table_clusters); - len += sprintf(header_buf + len, "nb_snapshots: %d\n", - header->nb_snapshots); - len += sprintf(header_buf + len, "snapshots_offset: %lld\n", - header->snapshots_offset); + len += sprintf(header_buf + len, "magic: %d\n", header->magic); + len += sprintf(header_buf + len, "version: %d\n", header->version); + len += sprintf(header_buf + len, "backing_file_offset: %lld\n", header->backing_file_offset); + len += sprintf(header_buf + len, "backing_file_size: %d\n", header->backing_file_size); + len += sprintf(header_buf + len, "cluster_bits: %d\n", header->cluster_bits); + len += sprintf(header_buf + len, "size: %lld\n", header->size); + len += sprintf(header_buf + len, "crypt_method: %d\n", header->crypt_method); + len += sprintf(header_buf + len, "l1_size: %d\n", header->l1_size); + len += sprintf(header_buf + len, "l1_table_offset: %lld\n", header->l1_table_offset); + len += sprintf(header_buf + len, "refcount_table_offset: %lld\n", header->refcount_table_offset); + len += sprintf(header_buf + len, "refcount_table_clusters: %d\n", header->refcount_table_clusters); + len += sprintf(header_buf + len, "nb_snapshots: %d\n", header->nb_snapshots); + len += sprintf(header_buf + len, "snapshots_offset: %lld\n", header->snapshots_offset); if (header->version == 3) { - len += sprintf(header_buf + len, - "incompatible_features: %lld\n", - header->incompatible_features); - len += sprintf(header_buf + len, - "compatible_features: %lld\n", - header->compatible_features); - len += sprintf(header_buf + len, - "autoclear_features: %lld\n", - header->autoclear_features); - len += sprintf(header_buf + len, - "refcount_order: %d\n", - header->refcount_order); - len += sprintf(header_buf + len, - "header_length: %d\n", - header->header_length); + len += sprintf(header_buf + len, "incompatible_features: %lld\n", header->incompatible_features); + len += sprintf(header_buf + len, "compatible_features: %lld\n", header->compatible_features); + len += sprintf(header_buf + len, "autoclear_features: %lld\n", header->autoclear_features); + len += sprintf(header_buf + len, "refcount_order: %d\n", header->refcount_order); + len += sprintf(header_buf + len, "header_length: %d\n", header->header_length); } - if (header->header_length > offsetof(struct xloop_file_fmt_qcow_header, - compression_type)) { - len += sprintf(header_buf + len, - "compression_type: %d\n", - header->compression_type); - } + if (header->header_length > offsetof(struct xloop_file_fmt_qcow_header, compression_type)) + len += sprintf(header_buf + len, "compression_type: %d\n", header->compression_type); ASSERT(len < QCOW_HEADER_BUF_LEN); } -static ssize_t __qcow_file_fmt_dbgfs_hdr_read(struct file *file, - char __user *buf, size_t size, loff_t *ppos) +static ssize_t __qcow_file_fmt_dbgfs_hdr_read(struct file *file, char __user *buf, size_t size, loff_t *ppos) { struct xloop_file_fmt *xlo_fmt = file->private_data; struct xloop_file_fmt_qcow_data *qcow_data = xlo_fmt->private_data; char *header_buf = qcow_data->dbgfs_file_qcow_header_buf; - return simple_read_from_buffer(buf, size, ppos, header_buf, - strlen(header_buf)); + return simple_read_from_buffer(buf, size, ppos, header_buf, strlen(header_buf)); } -static const struct file_operations qcow_file_fmt_dbgfs_hdr_fops = { - .open = simple_open, - .read = __qcow_file_fmt_dbgfs_hdr_read -}; +static const struct file_operations qcow_file_fmt_dbgfs_hdr_fops = { .open = simple_open, + .read = __qcow_file_fmt_dbgfs_hdr_read }; -static ssize_t __qcow_file_fmt_dbgfs_ofs_read(struct file *file, - char __user *buf, size_t size, loff_t *ppos) +static ssize_t __qcow_file_fmt_dbgfs_ofs_read(struct file *file, char __user *buf, size_t size, loff_t *ppos) { struct xloop_file_fmt *xlo_fmt = file->private_data; struct xloop_file_fmt_qcow_data *qcow_data = xlo_fmt->private_data; @@ -337,44 +295,37 @@ static ssize_t __qcow_file_fmt_dbgfs_ofs_read(struct file *file, mutex_unlock(&qcow_data->dbgfs_qcow_offset_mutex); /* calculate and print the cluster offset */ - ret = xloop_file_fmt_qcow_get_host_offset(xlo_fmt, - offset, &cur_bytes, &host_offset, &type); + ret = xloop_file_fmt_qcow_get_host_offset(xlo_fmt, offset, &cur_bytes, &host_offset, &type); if (ret < 0) return -EINVAL; - offset_in_cluster = xloop_file_fmt_qcow_offset_into_cluster(qcow_data, - offset); + offset_in_cluster = xloop_file_fmt_qcow_offset_into_cluster(qcow_data, offset); len = sprintf(qcow_data->dbgfs_file_qcow_cluster_buf, - "cluster type: %s\n" - "cluster offset host: %lld\n" - "cluster offset guest: %lld\n" - "cluster offset in-cluster: %lld\n", - xloop_file_fmt_qcow_get_subcluster_name(type), - host_offset, offset, offset_in_cluster); - - if (type == QCOW_SUBCLUSTER_COMPRESSED) { - coffset = host_offset & qcow_data->cluster_offset_mask; - nb_csectors = ((host_offset >> qcow_data->csize_shift) & - qcow_data->csize_mask) + 1; - csize = nb_csectors * QCOW_COMPRESSED_SECTOR_SIZE - - (coffset & ~QCOW_COMPRESSED_SECTOR_MASK); + "cluster type: %s\n" + "cluster offset host: %lld\n" + "cluster offset guest: %lld\n" + "cluster offset in-cluster: %lld\n", + xloop_file_fmt_qcow_get_subcluster_name(type), host_offset, offset, offset_in_cluster); + + if (type == QCOW_SUBCLUSTER_COMPRESSED) { + coffset = host_offset & qcow_data->cluster_offset_mask; + nb_csectors = ((host_offset >> qcow_data->csize_shift) & qcow_data->csize_mask) + 1; + csize = nb_csectors * QCOW_COMPRESSED_SECTOR_SIZE - (coffset & ~QCOW_COMPRESSED_SECTOR_MASK); len += sprintf(qcow_data->dbgfs_file_qcow_cluster_buf + len, - "cluster compressed offset: %lld\n" - "cluster compressed sectors: %d\n" - "cluster compressed size: %d\n", - coffset, nb_csectors, csize); - } + "cluster compressed offset: %lld\n" + "cluster compressed sectors: %d\n" + "cluster compressed size: %d\n", + coffset, nb_csectors, csize); + } ASSERT(len < QCOW_CLUSTER_BUF_LEN); - return simple_read_from_buffer(buf, size, ppos, - qcow_data->dbgfs_file_qcow_cluster_buf, len); + return simple_read_from_buffer(buf, size, ppos, qcow_data->dbgfs_file_qcow_cluster_buf, len); } -static ssize_t __qcow_file_fmt_dbgfs_ofs_write(struct file *file, - const char __user *buf, size_t size, loff_t *ppos) +static ssize_t __qcow_file_fmt_dbgfs_ofs_write(struct file *file, const char __user *buf, size_t size, loff_t *ppos) { struct xloop_file_fmt *xlo_fmt = file->private_data; struct xloop_file_fmt_qcow_data *qcow_data = xlo_fmt->private_data; @@ -384,8 +335,7 @@ static ssize_t __qcow_file_fmt_dbgfs_ofs_write(struct file *file, if (*ppos > QCOW_OFFSET_BUF_LEN || size > QCOW_OFFSET_BUF_LEN) return -EINVAL; - len = simple_write_to_buffer(qcow_data->dbgfs_file_qcow_offset_buf, - QCOW_OFFSET_BUF_LEN, ppos, buf, size); + len = simple_write_to_buffer(qcow_data->dbgfs_file_qcow_offset_buf, QCOW_OFFSET_BUF_LEN, ppos, buf, size); if (len < 0) return len; @@ -395,8 +345,7 @@ static ssize_t __qcow_file_fmt_dbgfs_ofs_write(struct file *file, if (ret) return ret; - ret = kstrtou64(qcow_data->dbgfs_file_qcow_offset_buf, 10, - &qcow_data->dbgfs_qcow_offset); + ret = kstrtou64(qcow_data->dbgfs_file_qcow_offset_buf, 10, &qcow_data->dbgfs_qcow_offset); if (ret < 0) goto out; @@ -406,11 +355,9 @@ out: return ret; } -static const struct file_operations qcow_file_fmt_dbgfs_ofs_fops = { - .open = simple_open, - .read = __qcow_file_fmt_dbgfs_ofs_read, - .write = __qcow_file_fmt_dbgfs_ofs_write -}; +static const struct file_operations qcow_file_fmt_dbgfs_ofs_fops = { .open = simple_open, + .read = __qcow_file_fmt_dbgfs_ofs_read, + .write = __qcow_file_fmt_dbgfs_ofs_write }; static int __qcow_file_fmt_dbgfs_init(struct xloop_file_fmt *xlo_fmt) { @@ -424,17 +371,15 @@ static int __qcow_file_fmt_dbgfs_init(struct xloop_file_fmt *xlo_fmt) goto out; } - qcow_data->dbgfs_file_qcow_header = debugfs_create_file("header", - S_IRUGO, qcow_data->dbgfs_dir, xlo_fmt, - &qcow_file_fmt_dbgfs_hdr_fops); + qcow_data->dbgfs_file_qcow_header = + debugfs_create_file("header", 0444, qcow_data->dbgfs_dir, xlo_fmt, &qcow_file_fmt_dbgfs_hdr_fops); if (IS_ERR_OR_NULL(qcow_data->dbgfs_file_qcow_header)) { ret = -ENODEV; goto out_free_dbgfs_dir; } - qcow_data->dbgfs_file_qcow_offset = debugfs_create_file("offset", - S_IRUGO | S_IWUSR, qcow_data->dbgfs_dir, xlo_fmt, - &qcow_file_fmt_dbgfs_ofs_fops); + qcow_data->dbgfs_file_qcow_offset = debugfs_create_file("offset", 0644, qcow_data->dbgfs_dir, + xlo_fmt, &qcow_file_fmt_dbgfs_ofs_fops); if (IS_ERR_OR_NULL(qcow_data->dbgfs_file_qcow_offset)) { qcow_data->dbgfs_file_qcow_offset = NULL; ret = -ENODEV; @@ -460,55 +405,50 @@ static void __qcow_file_fmt_dbgfs_exit(struct xloop_file_fmt *xlo_fmt) { struct xloop_file_fmt_qcow_data *qcow_data = xlo_fmt->private_data; - if (qcow_data->dbgfs_file_qcow_offset) - debugfs_remove(qcow_data->dbgfs_file_qcow_offset); + debugfs_remove(qcow_data->dbgfs_file_qcow_offset); mutex_destroy(&qcow_data->dbgfs_qcow_offset_mutex); - if (qcow_data->dbgfs_file_qcow_header) - debugfs_remove(qcow_data->dbgfs_file_qcow_header); + debugfs_remove(qcow_data->dbgfs_file_qcow_header); - if (qcow_data->dbgfs_dir) - debugfs_remove(qcow_data->dbgfs_dir); + debugfs_remove(qcow_data->dbgfs_dir); } #endif -static int __qcow_file_fmt_validate_compression_type( - struct xloop_file_fmt *xlo_fmt) +static int __qcow_file_fmt_validate_compression_type(struct xloop_file_fmt *xlo_fmt) { struct xloop_file_fmt_qcow_data *qcow_data = xlo_fmt->private_data; - switch (qcow_data->compression_type) { - case QCOW_COMPRESSION_TYPE_ZLIB: + switch (qcow_data->compression_type) { + case QCOW_COMPRESSION_TYPE_ZLIB: #ifdef CONFIG_ZSTD_DECOMPRESS - case QCOW_COMPRESSION_TYPE_ZSTD: + case QCOW_COMPRESSION_TYPE_ZSTD: #endif - break; - default: - dev_err(xloop_file_fmt_to_dev(xlo_fmt), "unknown compression type: %u", - qcow_data->compression_type); - return -ENOTSUPP; - } - - /* - * if the compression type differs from QCOW_COMPRESSION_TYPE_ZLIB - * the incompatible feature flag must be set - */ - if (qcow_data->compression_type == QCOW_COMPRESSION_TYPE_ZLIB) { - if (qcow_data->incompatible_features & QCOW_INCOMPAT_COMPRESSION) { - dev_err(xloop_file_fmt_to_dev(xlo_fmt), "compression type " - "incompatible feature bit must not be set\n"); - return -EINVAL; - } - } else { - if (!(qcow_data->incompatible_features & QCOW_INCOMPAT_COMPRESSION)) { - dev_err(xloop_file_fmt_to_dev(xlo_fmt), "compression type " - "incompatible feature bit must be set\n"); - return -EINVAL; - } - } - - return 0; + break; + default: + dev_err(xloop_file_fmt_to_dev(xlo_fmt), "unknown compression type: %u", qcow_data->compression_type); + return -ENOTSUPP; + } + + /* + * if the compression type differs from QCOW_COMPRESSION_TYPE_ZLIB + * the incompatible feature flag must be set + */ + if (qcow_data->compression_type == QCOW_COMPRESSION_TYPE_ZLIB) { + if (qcow_data->incompatible_features & QCOW_INCOMPAT_COMPRESSION) { + dev_err(xloop_file_fmt_to_dev(xlo_fmt), + "compression type incompatible feature bit must not be set\n"); + return -EINVAL; + } + } else { + if (!(qcow_data->incompatible_features & QCOW_INCOMPAT_COMPRESSION)) { + dev_err(xloop_file_fmt_to_dev(xlo_fmt), + "compression type incompatible feature bit must be set\n"); + return -EINVAL; + } + } + + return 0; } static int qcow_file_fmt_init(struct xloop_file_fmt *xlo_fmt) @@ -539,8 +479,10 @@ static int qcow_file_fmt_init(struct xloop_file_fmt *xlo_fmt) if (ret) goto free_qcow_data; - /* save information of the header fields in human readable format in - * a file buffer to access it with debugfs */ + /* + * save information of the header fields in human readable format in + * a file buffer to access it with debugfs + */ #ifdef CONFIG_DEBUG_FS __qcow_file_fmt_header_to_buf(xlo_fmt, &header); #endif @@ -548,10 +490,8 @@ static int qcow_file_fmt_init(struct xloop_file_fmt *xlo_fmt) qcow_data->qcow_version = header.version; /* Initialise cluster size */ - if (header.cluster_bits < QCOW_MIN_CLUSTER_BITS - || header.cluster_bits > QCOW_MAX_CLUSTER_BITS) { - dev_err(xloop_file_fmt_to_dev(xlo_fmt), "unsupported cluster size: " - "2^%d\n", header.cluster_bits); + if (header.cluster_bits < QCOW_MIN_CLUSTER_BITS || header.cluster_bits > QCOW_MAX_CLUSTER_BITS) { + dev_err(xloop_file_fmt_to_dev(xlo_fmt), "unsupported cluster size: 2^%d\n", header.cluster_bits); ret = -EINVAL; goto free_qcow_data; } @@ -560,22 +500,19 @@ static int qcow_file_fmt_init(struct xloop_file_fmt *xlo_fmt) qcow_data->cluster_size = 1 << qcow_data->cluster_bits; if (header.header_length > qcow_data->cluster_size) { - dev_err(xloop_file_fmt_to_dev(xlo_fmt), "QCOW header exceeds cluster " - "size\n"); + dev_err(xloop_file_fmt_to_dev(xlo_fmt), "QCOW header exceeds cluster size\n"); ret = -EINVAL; goto free_qcow_data; } if (header.backing_file_offset > qcow_data->cluster_size) { - dev_err(xloop_file_fmt_to_dev(xlo_fmt), "invalid backing file " - "offset\n"); + dev_err(xloop_file_fmt_to_dev(xlo_fmt), "invalid backing file offset\n"); ret = -EINVAL; goto free_qcow_data; } if (header.backing_file_offset) { - dev_err(xloop_file_fmt_to_dev(xlo_fmt), "backing file support not " - "available\n"); + dev_err(xloop_file_fmt_to_dev(xlo_fmt), "backing file support not available\n"); ret = -ENOTSUPP; goto free_qcow_data; } @@ -585,69 +522,61 @@ static int qcow_file_fmt_init(struct xloop_file_fmt *xlo_fmt) qcow_data->compatible_features = header.compatible_features; qcow_data->autoclear_features = header.autoclear_features; - /* - * Handle compression type - * Older qcow2 images don't contain the compression type header. - * Distinguish them by the header length and use - * the only valid (default) compression type in that case - */ - if (header.header_length > offsetof(struct xloop_file_fmt_qcow_header, - compression_type)) { - qcow_data->compression_type = header.compression_type; - } else { - qcow_data->compression_type = QCOW_COMPRESSION_TYPE_ZLIB; - } - - ret = __qcow_file_fmt_validate_compression_type(xlo_fmt); - if (ret) { - goto free_qcow_data; - } + /* + * Handle compression type + * Older qcow2 images don't contain the compression type header. + * Distinguish them by the header length and use + * the only valid (default) compression type in that case + */ + if (header.header_length > offsetof(struct xloop_file_fmt_qcow_header, compression_type)) + qcow_data->compression_type = header.compression_type; + else + qcow_data->compression_type = QCOW_COMPRESSION_TYPE_ZLIB; + + ret = __qcow_file_fmt_validate_compression_type(xlo_fmt); + if (ret) + goto free_qcow_data; /* check for incompatible features */ if (qcow_data->incompatible_features & QCOW_INCOMPAT_DIRTY) { - dev_err(xloop_file_fmt_to_dev(xlo_fmt), "image contains inconsistent " - "refcounts\n"); + dev_err(xloop_file_fmt_to_dev(xlo_fmt), "image contains inconsistent refcounts\n"); ret = -EACCES; goto free_qcow_data; } if (qcow_data->incompatible_features & QCOW_INCOMPAT_CORRUPT) { - dev_err(xloop_file_fmt_to_dev(xlo_fmt), "image is corrupt; cannot be " - "opened read/write\n"); + dev_err(xloop_file_fmt_to_dev(xlo_fmt), "image is corrupt; cannot be opened read/write\n"); ret = -EACCES; goto free_qcow_data; } if (qcow_data->incompatible_features & QCOW_INCOMPAT_DATA_FILE) { - dev_err(xloop_file_fmt_to_dev(xlo_fmt), "data-file is required for " - "this image\n"); + dev_err(xloop_file_fmt_to_dev(xlo_fmt), "data-file is required for this image\n"); ret = -EINVAL; goto free_qcow_data; } qcow_data->subclusters_per_cluster = - xloop_file_fmt_qcow_has_subclusters(qcow_data) ? - QCOW_EXTL2_SUBCLUSTERS_PER_CLUSTER : 1; - qcow_data->subcluster_size = - qcow_data->cluster_size / qcow_data->subclusters_per_cluster; - /* + xloop_file_fmt_qcow_has_subclusters(qcow_data) ? QCOW_EXTL2_SUBCLUSTERS_PER_CLUSTER : 1; + qcow_data->subcluster_size = qcow_data->cluster_size / qcow_data->subclusters_per_cluster; + /* * check if subcluster_size is non-zero to avoid unknown results of * __builtin_ctz */ ASSERT(qcow_data->subcluster_size != 0); - qcow_data->subcluster_bits = __builtin_ctz(qcow_data->subcluster_size); + qcow_data->subcluster_bits = __builtin_ctz(qcow_data->subcluster_size); - if (qcow_data->subcluster_size < (1 << QCOW_MIN_CLUSTER_BITS)) { - dev_err(xloop_file_fmt_to_dev(xlo_fmt), "unsupported subcluster " - "size: %d\n", qcow_data->subcluster_size); - ret = -EINVAL; - goto free_qcow_data; - } + if (qcow_data->subcluster_size < (1 << QCOW_MIN_CLUSTER_BITS)) { + dev_err(xloop_file_fmt_to_dev(xlo_fmt), "unsupported subcluster size: %d\n", + qcow_data->subcluster_size); + ret = -EINVAL; + goto free_qcow_data; + } /* Check support for various header values */ if (header.refcount_order > 6) { - dev_err(xloop_file_fmt_to_dev(xlo_fmt), "reference count entry width " - "too large; may not exceed 64 bits\n"); + dev_err(xloop_file_fmt_to_dev(xlo_fmt), + "reference count entry width too large; may not exceed 64 bits\n"); ret = -EINVAL; goto free_qcow_data; } @@ -658,23 +587,20 @@ static int qcow_file_fmt_init(struct xloop_file_fmt *xlo_fmt) qcow_data->crypt_method_header = header.crypt_method; if (qcow_data->crypt_method_header) { - dev_err(xloop_file_fmt_to_dev(xlo_fmt), "encryption support not " - "available\n"); + dev_err(xloop_file_fmt_to_dev(xlo_fmt), "encryption support not available\n"); ret = -ENOTSUPP; goto free_qcow_data; } - /* + /* * check if xloop_file_fmt_qcow_l2_entry_size(qcow_data) is non-zero to * avoid unknown results of __builtin_ctz */ ASSERT(xloop_file_fmt_qcow_l2_entry_size(qcow_data) != 0); - qcow_data->l2_bits = qcow_data->cluster_bits - - __builtin_ctz(xloop_file_fmt_qcow_l2_entry_size(qcow_data)); + qcow_data->l2_bits = qcow_data->cluster_bits - __builtin_ctz(xloop_file_fmt_qcow_l2_entry_size(qcow_data)); qcow_data->l2_size = 1 << qcow_data->l2_bits; /* 2^(qcow_data->refcount_order - 3) is the refcount width in bytes */ - qcow_data->refcount_block_bits = qcow_data->cluster_bits - - (qcow_data->refcount_order - 3); + qcow_data->refcount_block_bits = qcow_data->cluster_bits - (qcow_data->refcount_order - 3); qcow_data->refcount_block_size = 1 << qcow_data->refcount_block_bits; qcow_data->size = header.size; qcow_data->csize_shift = (62 - (qcow_data->cluster_bits - 8)); @@ -682,49 +608,42 @@ static int qcow_file_fmt_init(struct xloop_file_fmt *xlo_fmt) qcow_data->cluster_offset_mask = (1LL << qcow_data->csize_shift) - 1; qcow_data->refcount_table_offset = header.refcount_table_offset; - qcow_data->refcount_table_size = header.refcount_table_clusters << - (qcow_data->cluster_bits - 3); + qcow_data->refcount_table_size = header.refcount_table_clusters << (qcow_data->cluster_bits - 3); if (header.refcount_table_clusters == 0) { - dev_err(xloop_file_fmt_to_dev(xlo_fmt), "image does not contain a " - "reference count table\n"); + dev_err(xloop_file_fmt_to_dev(xlo_fmt), "image does not contain a reference count table\n"); ret = -EINVAL; goto free_qcow_data; } - ret = __qcow_file_fmt_validate_table(xlo_fmt, - qcow_data->refcount_table_offset, - header.refcount_table_clusters, qcow_data->cluster_size, - QCOW_MAX_REFTABLE_SIZE, "Reference count table"); - if (ret < 0) { + ret = __qcow_file_fmt_validate_table(xlo_fmt, qcow_data->refcount_table_offset, header.refcount_table_clusters, + qcow_data->cluster_size, QCOW_MAX_REFTABLE_SIZE, "Reference count table"); + if (ret < 0) goto free_qcow_data; - } - /* The total size in bytes of the snapshot table is checked in + /* + * The total size in bytes of the snapshot table is checked in * qcow2_read_snapshots() because the size of each snapshot is * variable and we don't know it yet. - * Here we only check the offset and number of snapshots. */ - ret = __qcow_file_fmt_validate_table(xlo_fmt, header.snapshots_offset, - header.nb_snapshots, - sizeof(struct xloop_file_fmt_qcow_snapshot_header), - sizeof(struct xloop_file_fmt_qcow_snapshot_header) * - QCOW_MAX_SNAPSHOTS, "Snapshot table"); - if (ret < 0) { + * Here we only check the offset and number of snapshots. + */ + ret = __qcow_file_fmt_validate_table(xlo_fmt, header.snapshots_offset, header.nb_snapshots, + sizeof(struct xloop_file_fmt_qcow_snapshot_header), + sizeof(struct xloop_file_fmt_qcow_snapshot_header) * QCOW_MAX_SNAPSHOTS, + "Snapshot table"); + if (ret < 0) goto free_qcow_data; - } /* read the level 1 table */ - ret = __qcow_file_fmt_validate_table(xlo_fmt, header.l1_table_offset, - header.l1_size, QCOW_L1E_SIZE, QCOW_MAX_L1_SIZE, - "Active L1 table"); - if (ret < 0) { + ret = __qcow_file_fmt_validate_table(xlo_fmt, header.l1_table_offset, header.l1_size, QCOW_L1E_SIZE, + QCOW_MAX_L1_SIZE, "Active L1 table"); + if (ret < 0) goto free_qcow_data; - } + qcow_data->l1_size = header.l1_size; qcow_data->l1_table_offset = header.l1_table_offset; - l1_vm_state_index = xloop_file_fmt_qcow_size_to_l1(qcow_data, - header.size); + l1_vm_state_index = xloop_file_fmt_qcow_size_to_l1(qcow_data, header.size); if (l1_vm_state_index > INT_MAX) { dev_err(xloop_file_fmt_to_dev(xlo_fmt), "image is too big\n"); ret = -EFBIG; @@ -732,8 +651,7 @@ static int qcow_file_fmt_init(struct xloop_file_fmt *xlo_fmt) } qcow_data->l1_vm_state_index = l1_vm_state_index; - /* the L1 table must contain at least enough entries to put header.size - * bytes */ + /* the L1 table must contain at least enough entries to put header.size bytes */ if (qcow_data->l1_size < qcow_data->l1_vm_state_index) { dev_err(xloop_file_fmt_to_dev(xlo_fmt), "L1 table is too small\n"); ret = -EINVAL; @@ -741,27 +659,20 @@ static int qcow_file_fmt_init(struct xloop_file_fmt *xlo_fmt) } if (qcow_data->l1_size > 0) { - qcow_data->l1_table = vzalloc(round_up(qcow_data->l1_size * - QCOW_L1E_SIZE, 512)); + qcow_data->l1_table = vzalloc(round_up(qcow_data->l1_size * QCOW_L1E_SIZE, 512)); if (qcow_data->l1_table == NULL) { - dev_err(xloop_file_fmt_to_dev(xlo_fmt), "could not allocate " - "L1 table\n"); ret = -ENOMEM; goto free_qcow_data; } - len = kernel_read(xlo->xlo_backing_file, qcow_data->l1_table, - qcow_data->l1_size * QCOW_L1E_SIZE, - &qcow_data->l1_table_offset); + len = kernel_read(xlo->xlo_backing_file, qcow_data->l1_table, qcow_data->l1_size * QCOW_L1E_SIZE, + &qcow_data->l1_table_offset); if (len < 0) { - dev_err(xloop_file_fmt_to_dev(xlo_fmt), "could not read " - "L1 table\n"); + dev_err(xloop_file_fmt_to_dev(xlo_fmt), "could not read L1 table\n"); ret = len; goto free_l1_table; } - for (i = 0; i < qcow_data->l1_size; i++) { - qcow_data->l1_table[i] = - be64_to_cpu(qcow_data->l1_table[i]); - } + for (i = 0; i < qcow_data->l1_size; i++) + qcow_data->l1_table[i] = be64_to_cpu(qcow_data->l1_table[i]); } /* Internal snapshots */ @@ -769,8 +680,7 @@ static int qcow_file_fmt_init(struct xloop_file_fmt *xlo_fmt) qcow_data->nb_snapshots = header.nb_snapshots; if (qcow_data->nb_snapshots > 0) { - dev_err(xloop_file_fmt_to_dev(xlo_fmt), "snapshots support not " - "available\n"); + dev_err(xloop_file_fmt_to_dev(xlo_fmt), "snapshots support not available\n"); ret = -ENOTSUPP; goto free_l1_table; } @@ -778,9 +688,7 @@ static int qcow_file_fmt_init(struct xloop_file_fmt *xlo_fmt) /* create cache for L2 */ virtual_disk_size = qcow_data->size; max_l2_entries = DIV64_U64_ROUND_UP(virtual_disk_size, qcow_data->cluster_size); - max_l2_cache = round_up( - max_l2_entries * xloop_file_fmt_qcow_l2_entry_size(qcow_data), - qcow_data->cluster_size); + max_l2_cache = round_up(max_l2_entries * xloop_file_fmt_qcow_l2_entry_size(qcow_data), qcow_data->cluster_size); /* define the maximum L2 cache size */ l2_cache_max_setting = QCOW_DEFAULT_L2_CACHE_MAX_SIZE; @@ -789,13 +697,12 @@ static int qcow_file_fmt_init(struct xloop_file_fmt *xlo_fmt) l2_cache_size = min(max_l2_cache, l2_cache_max_setting); /* determine the size of a cache entry */ - l2_cache_entry_size = min(qcow_data->cluster_size, (int)PAGE_SIZE); + l2_cache_entry_size = min_t(int, qcow_data->cluster_size, PAGE_SIZE); /* calculate the number of cache tables */ l2_cache_size = div_u64(l2_cache_size, l2_cache_entry_size); - if (l2_cache_size < QCOW_MIN_L2_CACHE_SIZE) { + if (l2_cache_size < QCOW_MIN_L2_CACHE_SIZE) l2_cache_size = QCOW_MIN_L2_CACHE_SIZE; - } if (l2_cache_size > INT_MAX) { dev_err(xloop_file_fmt_to_dev(xlo_fmt), "L2 cache size too big\n"); @@ -803,11 +710,9 @@ static int qcow_file_fmt_init(struct xloop_file_fmt *xlo_fmt) goto free_l1_table; } - qcow_data->l2_slice_size = div_u64(l2_cache_entry_size, - xloop_file_fmt_qcow_l2_entry_size(qcow_data)); + qcow_data->l2_slice_size = div_u64(l2_cache_entry_size, xloop_file_fmt_qcow_l2_entry_size(qcow_data)); - qcow_data->l2_table_cache = xloop_file_fmt_qcow_cache_create(xlo_fmt, - l2_cache_size, l2_cache_entry_size); + qcow_data->l2_table_cache = xloop_file_fmt_qcow_cache_create(xlo_fmt, l2_cache_size, l2_cache_entry_size); if (!qcow_data->l2_table_cache) { ret = -ENOMEM; goto free_l1_table; @@ -847,18 +752,14 @@ static void qcow_file_fmt_exit(struct xloop_file_fmt *xlo_fmt) __qcow_file_fmt_compression_exit(xlo_fmt); - if (qcow_data->l1_table) { + if (qcow_data->l1_table) vfree(qcow_data->l1_table); - } - if (qcow_data->l2_table_cache) { + if (qcow_data->l2_table_cache) xloop_file_fmt_qcow_cache_destroy(xlo_fmt); - } - if (qcow_data) { - kfree(qcow_data); - xlo_fmt->private_data = NULL; - } + kfree(qcow_data); + xlo_fmt->private_data = NULL; } /* @@ -874,11 +775,8 @@ static void qcow_file_fmt_exit(struct xloop_file_fmt *xlo_fmt) * Returns: 0 on success * -EIO on fail */ -static ssize_t __qcow_file_fmt_zlib_decompress(struct xloop_file_fmt *xlo_fmt, - void *dest, - size_t dest_size, - const void *src, - size_t src_size) +static ssize_t __qcow_file_fmt_zlib_decompress(struct xloop_file_fmt *xlo_fmt, void *dest, size_t dest_size, + const void *src, size_t src_size) { struct xloop_file_fmt_qcow_data *qcow_data = xlo_fmt->private_data; u8 zerostuff = 0; @@ -901,8 +799,7 @@ static ssize_t __qcow_file_fmt_zlib_decompress(struct xloop_file_fmt *xlo_fmt, * byte when being used in the (undocumented) raw deflate mode. * (From USAGI). */ - if (ret == Z_OK && !qcow_data->zlib_dstrm->avail_in && - qcow_data->zlib_dstrm->avail_out) { + if (ret == Z_OK && !qcow_data->zlib_dstrm->avail_in && qcow_data->zlib_dstrm->avail_out) { qcow_data->zlib_dstrm->next_in = &zerostuff; qcow_data->zlib_dstrm->avail_in = 1; ret = zlib_inflate(qcow_data->zlib_dstrm, Z_FINISH); @@ -930,83 +827,71 @@ out: * Returns: 0 on success * -EIO on any error */ -static ssize_t __qcow_file_fmt_zstd_decompress(struct xloop_file_fmt *xlo_fmt, - void *dest, - size_t dest_size, - const void *src, - size_t src_size) +static ssize_t __qcow_file_fmt_zstd_decompress(struct xloop_file_fmt *xlo_fmt, void *dest, size_t dest_size, + const void *src, size_t src_size) { struct xloop_file_fmt_qcow_data *qcow_data = xlo_fmt->private_data; size_t zstd_ret = 0; - ssize_t ret = 0; + ssize_t ret = 0; - ZSTD_outBuffer output = { - .dst = dest, - .size = dest_size, - .pos = 0 - }; + ZSTD_outBuffer output = { .dst = dest, .size = dest_size, .pos = 0 }; - ZSTD_inBuffer input = { - .src = src, - .size = src_size, - .pos = 0 - }; + ZSTD_inBuffer input = { .src = src, .size = src_size, .pos = 0 }; zstd_ret = ZSTD_resetDStream(qcow_data->zstd_dstrm); - if (ZSTD_isError(zstd_ret)) { - ret = -EIO; + if (ZSTD_isError(zstd_ret)) { + ret = -EIO; goto out; - } + } + + /* + * The compressed stream from the input buffer may consist of more + * than one zstd frame. So we iterate until we get a fully + * uncompressed cluster. + * From zstd docs related to ZSTD_decompressStream: + * "return : 0 when a frame is completely decoded and fully flushed" + * We suppose that this means: each time ZSTD_decompressStream reads + * only ONE full frame and returns 0 if and only if that frame + * is completely decoded and flushed. Only after returning 0, + * ZSTD_decompressStream reads another ONE full frame. + */ + while (output.pos < output.size) { + size_t last_in_pos = input.pos; + size_t last_out_pos = output.pos; + + zstd_ret = ZSTD_decompressStream(qcow_data->zstd_dstrm, &output, &input); + if (ZSTD_isError(zstd_ret)) { + ret = -EIO; + break; + } + + /* + * The ZSTD manual is vague about what to do if it reads + * the buffer partially, and we don't want to get stuck + * in an infinite loop where ZSTD_decompressStream + * returns > 0 waiting for another input chunk. So, we add + * a check which ensures that the loop makes some progress + * on each step. + */ + if (last_in_pos >= input.pos && last_out_pos >= output.pos) { + ret = -EIO; + break; + } + } /* - * The compressed stream from the input buffer may consist of more - * than one zstd frame. So we iterate until we get a fully - * uncompressed cluster. - * From zstd docs related to ZSTD_decompressStream: - * "return : 0 when a frame is completely decoded and fully flushed" - * We suppose that this means: each time ZSTD_decompressStream reads - * only ONE full frame and returns 0 if and only if that frame - * is completely decoded and flushed. Only after returning 0, - * ZSTD_decompressStream reads another ONE full frame. - */ - while (output.pos < output.size) { - size_t last_in_pos = input.pos; - size_t last_out_pos = output.pos; - zstd_ret = ZSTD_decompressStream(qcow_data->zstd_dstrm, &output, &input); - - if (ZSTD_isError(zstd_ret)) { - ret = -EIO; - break; - } - - /* - * The ZSTD manual is vague about what to do if it reads - * the buffer partially, and we don't want to get stuck - * in an infinite loop where ZSTD_decompressStream - * returns > 0 waiting for another input chunk. So, we add - * a check which ensures that the loop makes some progress - * on each step. - */ - if (last_in_pos >= input.pos && - last_out_pos >= output.pos) { - ret = -EIO; - break; - } - } - /* - * Make sure that we have the frame fully flushed here - * if not, we somehow managed to get uncompressed cluster - * greater then the cluster size, possibly because of its - * damage. - */ - if (zstd_ret > 0) { - ret = -EIO; - } + * Make sure that we have the frame fully flushed here + * if not, we somehow managed to get uncompressed cluster + * greater then the cluster size, possibly because of its + * damage. + */ + if (zstd_ret > 0) + ret = -EIO; out: - ASSERT(ret == 0 || ret == -EIO); - return ret; + ASSERT(ret == 0 || ret == -EIO); + return ret; } #endif @@ -1023,39 +908,31 @@ out: * Returns: compressed size on success * a negative error code on failure */ -static ssize_t __qcow_file_fmt_buffer_decompress(struct xloop_file_fmt *xlo_fmt, - void *dest, - size_t dest_size, - const void *src, - size_t src_size) +static ssize_t __qcow_file_fmt_buffer_decompress(struct xloop_file_fmt *xlo_fmt, void *dest, size_t dest_size, + const void *src, size_t src_size) { - struct xloop_file_fmt_qcow_data *qcow_data = xlo_fmt->private_data; - qcow_file_fmt_decompress_fn decompress_fn; + struct xloop_file_fmt_qcow_data *qcow_data = xlo_fmt->private_data; + qcow_file_fmt_decompress_fn decompress_fn; - switch (qcow_data->compression_type) { - case QCOW_COMPRESSION_TYPE_ZLIB: - decompress_fn = __qcow_file_fmt_zlib_decompress; - break; + switch (qcow_data->compression_type) { + case QCOW_COMPRESSION_TYPE_ZLIB: + decompress_fn = __qcow_file_fmt_zlib_decompress; + break; #ifdef CONFIG_ZSTD_DECOMPRESS - case QCOW_COMPRESSION_TYPE_ZSTD: - decompress_fn = __qcow_file_fmt_zstd_decompress; - break; + case QCOW_COMPRESSION_TYPE_ZSTD: + decompress_fn = __qcow_file_fmt_zstd_decompress; + break; #endif - default: - return -EINVAL; - } + default: + return -EINVAL; + } - return decompress_fn(xlo_fmt, dest, dest_size, src, src_size); + return decompress_fn(xlo_fmt, dest, dest_size, src, src_size); } - -static int __qcow_file_fmt_read_compressed(struct xloop_file_fmt *xlo_fmt, - struct bio_vec *bvec, - u64 file_cluster_offset, - u64 offset, - u64 bytes, - u64 bytes_done) +static int __qcow_file_fmt_read_compressed(struct xloop_file_fmt *xlo_fmt, struct bio_vec *bvec, + u64 file_cluster_offset, u64 offset, u64 bytes, u64 bytes_done) { struct xloop_file_fmt_qcow_data *qcow_data = xlo_fmt->private_data; struct xloop_device *xlo = xloop_file_fmt_get_xlo(xlo_fmt); @@ -1065,15 +942,11 @@ static int __qcow_file_fmt_read_compressed(struct xloop_file_fmt *xlo_fmt, ssize_t len; void *data; unsigned long irq_flags; - int offset_in_cluster = xloop_file_fmt_qcow_offset_into_cluster( - qcow_data, offset); + int offset_in_cluster = xloop_file_fmt_qcow_offset_into_cluster(qcow_data, offset); coffset = file_cluster_offset & qcow_data->cluster_offset_mask; - nb_csectors = ((file_cluster_offset >> qcow_data->csize_shift) & - qcow_data->csize_mask) + 1; - csize = nb_csectors * QCOW_COMPRESSED_SECTOR_SIZE - - (coffset & ~QCOW_COMPRESSED_SECTOR_MASK); - + nb_csectors = ((file_cluster_offset >> qcow_data->csize_shift) & qcow_data->csize_mask) + 1; + csize = nb_csectors * QCOW_COMPRESSED_SECTOR_SIZE - (coffset & ~QCOW_COMPRESSED_SECTOR_MASK); if (qcow_data->cmp_last_coffset != coffset) { in_buf = vmalloc(csize); @@ -1089,8 +962,8 @@ static int __qcow_file_fmt_read_compressed(struct xloop_file_fmt *xlo_fmt, goto out_free_in_buf; } - if (__qcow_file_fmt_buffer_decompress(xlo_fmt, qcow_data->cmp_out_buf, - qcow_data->cluster_size, in_buf, csize) < 0) { + if (__qcow_file_fmt_buffer_decompress(xlo_fmt, qcow_data->cmp_out_buf, qcow_data->cluster_size, in_buf, + csize) < 0) { qcow_data->cmp_last_coffset = ULLONG_MAX; ret = -EIO; goto out_free_in_buf; @@ -1109,9 +982,7 @@ out_free_in_buf: return ret; } -static int __qcow_file_fmt_read_bvec(struct xloop_file_fmt *xlo_fmt, - struct bio_vec *bvec, - loff_t *ppos) +static int __qcow_file_fmt_read_bvec(struct xloop_file_fmt *xlo_fmt, struct bio_vec *bvec, loff_t *ppos) { struct xloop_file_fmt_qcow_data *qcow_data = xlo_fmt->private_data; struct xloop_device *xlo = xloop_file_fmt_get_xlo(xlo_fmt); @@ -1130,18 +1001,14 @@ static int __qcow_file_fmt_read_bvec(struct xloop_file_fmt *xlo_fmt, bytes = bvec->bv_len; while (bytes != 0) { - /* prepare next request */ cur_bytes = bytes; - ret = xloop_file_fmt_qcow_get_host_offset(xlo_fmt, *ppos, - &cur_bytes, &host_offset, &type); - if (ret < 0) { + ret = xloop_file_fmt_qcow_get_host_offset(xlo_fmt, *ppos, &cur_bytes, &host_offset, &type); + if (ret < 0) goto fail; - } - offset_in_cluster = xloop_file_fmt_qcow_offset_into_cluster( - qcow_data, *ppos); + offset_in_cluster = xloop_file_fmt_qcow_offset_into_cluster(qcow_data, *ppos); switch (type) { case QCOW_SUBCLUSTER_ZERO_PLAIN: @@ -1155,11 +1022,9 @@ static int __qcow_file_fmt_read_bvec(struct xloop_file_fmt *xlo_fmt, break; case QCOW_SUBCLUSTER_COMPRESSED: - ret = __qcow_file_fmt_read_compressed(xlo_fmt, bvec, - host_offset, *ppos, cur_bytes, bytes_done); - if (ret < 0) { + ret = __qcow_file_fmt_read_compressed(xlo_fmt, bvec, host_offset, *ppos, cur_bytes, bytes_done); + if (ret < 0) goto fail; - } break; @@ -1167,8 +1032,7 @@ static int __qcow_file_fmt_read_bvec(struct xloop_file_fmt *xlo_fmt, pos_read = host_offset; data = bvec_kmap_irq(bvec, &irq_flags) + bytes_done; - len = kernel_read(xlo->xlo_backing_file, data, cur_bytes, - &pos_read); + len = kernel_read(xlo->xlo_backing_file, data, cur_bytes, &pos_read); flush_dcache_page(bvec->bv_page); bvec_kunmap_irq(data, &irq_flags); @@ -1194,8 +1058,7 @@ fail: return ret; } -static int qcow_file_fmt_read(struct xloop_file_fmt *xlo_fmt, - struct request *rq) +static int qcow_file_fmt_read(struct xloop_file_fmt *xlo_fmt, struct request *rq) { struct bio_vec bvec; struct req_iterator iter; @@ -1215,8 +1078,8 @@ static int qcow_file_fmt_read(struct xloop_file_fmt *xlo_fmt, return ret; } -static loff_t qcow_file_fmt_sector_size(struct xloop_file_fmt *xlo_fmt, - struct file *file, loff_t offset, loff_t sizelimit) +static loff_t qcow_file_fmt_sector_size(struct xloop_file_fmt *xlo_fmt, struct file *file, loff_t offset, + loff_t sizelimit) { struct xloop_file_fmt_qcow_header header; loff_t xloopsize; @@ -1245,23 +1108,23 @@ static loff_t qcow_file_fmt_sector_size(struct xloop_file_fmt *xlo_fmt, } static struct xloop_file_fmt_ops qcow_file_fmt_ops = { - .init = qcow_file_fmt_init, - .exit = qcow_file_fmt_exit, - .read = qcow_file_fmt_read, - .write = NULL, - .read_aio = NULL, - .write_aio = NULL, + .init = qcow_file_fmt_init, + .exit = qcow_file_fmt_exit, + .read = qcow_file_fmt_read, + .write = NULL, + .read_aio = NULL, + .write_aio = NULL, .write_zeros = NULL, - .discard = NULL, - .flush = NULL, + .discard = NULL, + .flush = NULL, .sector_size = qcow_file_fmt_sector_size, }; static struct xloop_file_fmt_driver qcow_file_fmt_driver = { - .name = "QCOW", + .name = "QCOW", .file_fmt_type = XLO_FILE_FMT_QCOW, - .ops = &qcow_file_fmt_ops, - .owner = THIS_MODULE, + .ops = &qcow_file_fmt_ops, + .owner = THIS_MODULE, }; static int __init xloop_file_fmt_qcow_init(void) diff --git a/src/kernel/xloop_file_fmt_qcow_main.h b/src/kernel/xloop_file_fmt_qcow_main.h index 023c679..4556e3c 100644 --- a/src/kernel/xloop_file_fmt_qcow_main.h +++ b/src/kernel/xloop_file_fmt_qcow_main.h @@ -30,16 +30,17 @@ #include "xloop_file_fmt.h" #ifdef CONFIG_DEBUG_DRIVER -#define ASSERT(x) \ -do { \ - if (!(x)) { \ - printk(KERN_EMERG "assertion failed %s: %d: %s\n", \ - __FILE__, __LINE__, #x); \ - BUG(); \ - } \ -} while (0) +#define ASSERT(x) \ + do { \ + if (!(x)) { \ + printk(KERN_EMERG "assertion failed %s: %d: %s\n", __FILE__, __LINE__, #x); \ + BUG(); \ + } \ + } while (0) #else -#define ASSERT(x) do { } while (0) +#define ASSERT(x) \ + do { \ + } while (0) #endif #define KiB (1024) @@ -48,28 +49,36 @@ do { \ #define QCOW_MAGIC (('Q' << 24) | ('F' << 16) | ('I' << 8) | 0xfb) #define QCOW_CRYPT_NONE 0 -#define QCOW_CRYPT_AES 1 +#define QCOW_CRYPT_AES 1 #define QCOW_CRYPT_LUKS 2 #define QCOW_MAX_CRYPT_CLUSTERS 32 #define QCOW_MAX_SNAPSHOTS 65536 -/* Field widths in QCOW mean normal cluster offsets cannot reach +/* + * Field widths in QCOW mean normal cluster offsets cannot reach * 64PB; depending on cluster size, compressed clusters can have a * smaller limit (64PB for up to 16k clusters, then ramps down to - * 512TB for 2M clusters). */ + * 512TB for 2M clusters). + */ #define QCOW_MAX_CLUSTER_OFFSET ((1ULL << 56) - 1) -/* 8 MB refcount table is enough for 2 PB images at 64k cluster size - * (128 GB for 512 byte clusters, 2 EB for 2 MB clusters) */ +/* + * 8 MB refcount table is enough for 2 PB images at 64k cluster size + * (128 GB for 512 byte clusters, 2 EB for 2 MB clusters) + */ #define QCOW_MAX_REFTABLE_SIZE (8 * MiB) -/* 32 MB L1 table is enough for 2 PB images at 64k cluster size - * (128 GB for 512 byte clusters, 2 EB for 2 MB clusters) */ +/* + * 32 MB L1 table is enough for 2 PB images at 64k cluster size + * (128 GB for 512 byte clusters, 2 EB for 2 MB clusters) + */ #define QCOW_MAX_L1_SIZE (32 * MiB) -/* Allow for an average of 1k per snapshot table entry, should be plenty of - * space for snapshot names and IDs */ +/* + * Allow for an average of 1k per snapshot table entry, should be plenty of + * space for snapshot names and IDs + */ #define QCOW_MAX_SNAPSHOTS_SIZE (1024 * QCOW_MAX_SNAPSHOTS) /* Bitmap header extension constraints */ @@ -77,7 +86,7 @@ do { \ #define QCOW_MAX_BITMAP_DIRECTORY_SIZE (1024 * QCOW_MAX_BITMAPS) /* indicate that the refcount of the referenced cluster is exactly one. */ -#define QCOW_OFLAG_COPIED (1ULL << 63) +#define QCOW_OFLAG_COPIED (1ULL << 63) /* indicate that the cluster is compressed (they never have the copied flag) */ #define QCOW_OFLAG_COMPRESSED (1ULL << 62) /* The cluster reads as all zeros */ @@ -86,22 +95,20 @@ do { \ #define QCOW_EXTL2_SUBCLUSTERS_PER_CLUSTER 32 /* The subcluster X [0..31] is allocated */ -#define QCOW_OFLAG_SUB_ALLOC(X) (1ULL << (X)) +#define QCOW_OFLAG_SUB_ALLOC(X) (1ULL << (X)) /* The subcluster X [0..31] reads as zeroes */ -#define QCOW_OFLAG_SUB_ZERO(X) (QCOW_OFLAG_SUB_ALLOC(X) << 32) +#define QCOW_OFLAG_SUB_ZERO(X) (QCOW_OFLAG_SUB_ALLOC(X) << 32) /* Subclusters [X, Y) (0 <= X <= Y <= 32) are allocated */ -#define QCOW_OFLAG_SUB_ALLOC_RANGE(X, Y) \ - (QCOW_OFLAG_SUB_ALLOC(Y) - QCOW_OFLAG_SUB_ALLOC(X)) +#define QCOW_OFLAG_SUB_ALLOC_RANGE(X, Y) (QCOW_OFLAG_SUB_ALLOC(Y) - QCOW_OFLAG_SUB_ALLOC(X)) /* Subclusters [X, Y) (0 <= X <= Y <= 32) read as zeroes */ -#define QCOW_OFLAG_SUB_ZERO_RANGE(X, Y) \ - (QCOW_OFLAG_SUB_ALLOC_RANGE(X, Y) << 32) +#define QCOW_OFLAG_SUB_ZERO_RANGE(X, Y) (QCOW_OFLAG_SUB_ALLOC_RANGE(X, Y) << 32) /* L2 entry bitmap with all allocation bits set */ -#define QCOW_L2_BITMAP_ALL_ALLOC (QCOW_OFLAG_SUB_ALLOC_RANGE(0, 32)) +#define QCOW_L2_BITMAP_ALL_ALLOC (QCOW_OFLAG_SUB_ALLOC_RANGE(0, 32)) /* L2 entry bitmap with all "read as zeroes" bits set */ #define QCOW_L2_BITMAP_ALL_ZEROES (QCOW_OFLAG_SUB_ZERO_RANGE(0, 32)) /* Size of normal and extended L2 entries */ -#define QCOW_L2E_SIZE_NORMAL (sizeof(u64)) +#define QCOW_L2E_SIZE_NORMAL (sizeof(u64)) #define QCOW_L2E_SIZE_EXTENDED (sizeof(u64) * 2) /* Size of L1 table entries */ @@ -124,15 +131,17 @@ do { \ #define QCOW_MIN_REFCOUNT_CACHE_SIZE 4 /* clusters */ #define QCOW_DEFAULT_L2_CACHE_MAX_SIZE (32 * MiB) -#define QCOW_DEFAULT_CACHE_CLEAN_INTERVAL 600 /* seconds */ +#define QCOW_DEFAULT_CACHE_CLEAN_INTERVAL 600 /* seconds */ #define QCOW_DEFAULT_CLUSTER_SIZE 65536 /* Buffer size for debugfs file buffer to display QCOW header information */ #define QCOW_HEADER_BUF_LEN 1024 -/* Buffer size for debugfs file buffer to receive and display offset and - * cluster offset information */ +/* + * Buffer size for debugfs file buffer to receive and display offset and + * cluster offset information + */ #define QCOW_OFFSET_BUF_LEN 32 #define QCOW_CLUSTER_BUF_LEN 256 @@ -160,57 +169,54 @@ struct xloop_file_fmt_qcow_header { u32 header_length; /* Additional fields */ - u8 compression_type; + u8 compression_type; - /* header must be a multiple of 8 */ - u8 padding[7]; -} __attribute__((packed)); + /* header must be a multiple of 8 */ + u8 padding[7]; +} __packed; struct xloop_file_fmt_qcow_snapshot_header { /* header is 8 byte aligned */ - u64 l1_table_offset; + u64 l1_table_offset; - u32 l1_size; - u16 id_str_size; - u16 name_size; + u32 l1_size; + u16 id_str_size; + u16 name_size; - u32 date_sec; - u32 date_nsec; + u32 date_sec; + u32 date_nsec; - u64 vm_clock_nsec; + u64 vm_clock_nsec; - u32 vm_state_size; + u32 vm_state_size; - /* Size of all extra data, including QCowSnapshotExtraData if available */ - u32 extra_data_size; - /* Data beyond QCowSnapshotExtraData, if any */ - void *unknown_extra_data; -} __attribute__((packed)); + /* Size of all extra data, including QCowSnapshotExtraData if available */ + u32 extra_data_size; + /* Data beyond QCowSnapshotExtraData, if any */ + void *unknown_extra_data; +} __packed; enum { - QCOW_FEAT_TYPE_INCOMPATIBLE = 0, - QCOW_FEAT_TYPE_COMPATIBLE = 1, - QCOW_FEAT_TYPE_AUTOCLEAR = 2, + QCOW_FEAT_TYPE_INCOMPATIBLE = 0, + QCOW_FEAT_TYPE_COMPATIBLE = 1, + QCOW_FEAT_TYPE_AUTOCLEAR = 2, }; /* incompatible feature bits */ enum { - QCOW_INCOMPAT_DIRTY_BITNR = 0, - QCOW_INCOMPAT_CORRUPT_BITNR = 1, - QCOW_INCOMPAT_DATA_FILE_BITNR = 2, + QCOW_INCOMPAT_DIRTY_BITNR = 0, + QCOW_INCOMPAT_CORRUPT_BITNR = 1, + QCOW_INCOMPAT_DATA_FILE_BITNR = 2, QCOW_INCOMPAT_COMPRESSION_BITNR = 3, - QCOW_INCOMPAT_EXTL2_BITNR = 4, - QCOW_INCOMPAT_DIRTY = 1 << QCOW_INCOMPAT_DIRTY_BITNR, - QCOW_INCOMPAT_CORRUPT = 1 << QCOW_INCOMPAT_CORRUPT_BITNR, - QCOW_INCOMPAT_DATA_FILE = 1 << QCOW_INCOMPAT_DATA_FILE_BITNR, - QCOW_INCOMPAT_COMPRESSION = 1 << QCOW_INCOMPAT_COMPRESSION_BITNR, - QCOW_INCOMPAT_EXTL2 = 1 << QCOW_INCOMPAT_EXTL2_BITNR, - - QCOW_INCOMPAT_MASK = QCOW_INCOMPAT_DIRTY - | QCOW_INCOMPAT_CORRUPT - | QCOW_INCOMPAT_DATA_FILE - | QCOW_INCOMPAT_COMPRESSION - | QCOW_INCOMPAT_EXTL2, + QCOW_INCOMPAT_EXTL2_BITNR = 4, + QCOW_INCOMPAT_DIRTY = 1 << QCOW_INCOMPAT_DIRTY_BITNR, + QCOW_INCOMPAT_CORRUPT = 1 << QCOW_INCOMPAT_CORRUPT_BITNR, + QCOW_INCOMPAT_DATA_FILE = 1 << QCOW_INCOMPAT_DATA_FILE_BITNR, + QCOW_INCOMPAT_COMPRESSION = 1 << QCOW_INCOMPAT_COMPRESSION_BITNR, + QCOW_INCOMPAT_EXTL2 = 1 << QCOW_INCOMPAT_EXTL2_BITNR, + + QCOW_INCOMPAT_MASK = QCOW_INCOMPAT_DIRTY | QCOW_INCOMPAT_CORRUPT | QCOW_INCOMPAT_DATA_FILE | + QCOW_INCOMPAT_COMPRESSION | QCOW_INCOMPAT_EXTL2, }; /* compatible feature bits */ @@ -228,8 +234,7 @@ enum { QCOW_AUTOCLEAR_BITMAPS = 1 << QCOW_AUTOCLEAR_BITMAPS_BITNR, QCOW_AUTOCLEAR_DATA_FILE_RAW = 1 << QCOW_AUTOCLEAR_DATA_FILE_RAW_BITNR, - QCOW_AUTOCLEAR_MASK = QCOW_AUTOCLEAR_BITMAPS | - QCOW_AUTOCLEAR_DATA_FILE_RAW, + QCOW_AUTOCLEAR_MASK = QCOW_AUTOCLEAR_BITMAPS | QCOW_AUTOCLEAR_DATA_FILE_RAW, }; enum xloop_file_fmt_qcow_compression_type { @@ -238,85 +243,85 @@ enum xloop_file_fmt_qcow_compression_type { }; struct xloop_file_fmt_qcow_data { - u64 size; - int cluster_bits; - int cluster_size; - int l2_slice_size; - int subcluster_bits; - int subcluster_size; - int subclusters_per_cluster; - int l2_bits; - int l2_size; - int l1_size; - int l1_vm_state_index; - int refcount_block_bits; - int refcount_block_size; - int csize_shift; - int csize_mask; - u64 cluster_offset_mask; - u64 l1_table_offset; - u64 *l1_table; + u64 size; + int cluster_bits; + int cluster_size; + int l2_slice_size; + int subcluster_bits; + int subcluster_size; + int subclusters_per_cluster; + int l2_bits; + int l2_size; + int l1_size; + int l1_vm_state_index; + int refcount_block_bits; + int refcount_block_size; + int csize_shift; + int csize_mask; + u64 cluster_offset_mask; + u64 l1_table_offset; + u64 *l1_table; struct xloop_file_fmt_qcow_cache *l2_table_cache; struct xloop_file_fmt_qcow_cache *refcount_block_cache; - u64 *refcount_table; - u64 refcount_table_offset; - u32 refcount_table_size; - u32 max_refcount_table_index; /* Last used entry in refcount_table */ - u64 free_cluster_index; - u64 free_byte_offset; + u64 *refcount_table; + u64 refcount_table_offset; + u32 refcount_table_size; + u32 max_refcount_table_index; /* Last used entry in refcount_table */ + u64 free_cluster_index; + u64 free_byte_offset; - u32 crypt_method_header; - u64 snapshots_offset; - int snapshots_size; - unsigned int nb_snapshots; + u32 crypt_method_header; + u64 snapshots_offset; + int snapshots_size; + unsigned int nb_snapshots; - u32 nb_bitmaps; - u64 bitmap_directory_size; - u64 bitmap_directory_offset; + u32 nb_bitmaps; + u64 bitmap_directory_size; + u64 bitmap_directory_offset; - int qcow_version; - bool use_lazy_refcounts; - int refcount_order; - int refcount_bits; - u64 refcount_max; + int qcow_version; + bool use_lazy_refcounts; + int refcount_order; + int refcount_bits; + u64 refcount_max; - u64 incompatible_features; - u64 compatible_features; - u64 autoclear_features; + u64 incompatible_features; + u64 compatible_features; + u64 autoclear_features; /* ZLIB specific data */ - z_streamp zlib_dstrm; + z_streamp zlib_dstrm; /* ZSTD specific data */ #ifdef CONFIG_ZSTD_DECOMPRESS - void *zstd_dworkspace; - ZSTD_DStream *zstd_dstrm; + void *zstd_dworkspace; + ZSTD_DStream *zstd_dstrm; #endif /* used to cache last compressed QCOW cluster */ - u8 *cmp_out_buf; - u64 cmp_last_coffset; - - /* - * Compression type used for the image. Default: 0 - ZLIB - * The image compression type is set on image creation. - * For now, the only way to change the compression type - * is to convert the image with the desired compression type set. - */ - enum xloop_file_fmt_qcow_compression_type compression_type; + u8 *cmp_out_buf; + u64 cmp_last_coffset; + + /* + * Compression type used for the image. Default: 0 - ZLIB + * The image compression type is set on image creation. + * For now, the only way to change the compression type + * is to convert the image with the desired compression type set. + */ + enum xloop_file_fmt_qcow_compression_type compression_type; /* debugfs entries */ #ifdef CONFIG_DEBUG_FS struct dentry *dbgfs_dir; struct dentry *dbgfs_file_qcow_header; - char dbgfs_file_qcow_header_buf[QCOW_HEADER_BUF_LEN]; + char dbgfs_file_qcow_header_buf[QCOW_HEADER_BUF_LEN]; struct dentry *dbgfs_file_qcow_offset; - char dbgfs_file_qcow_offset_buf[QCOW_OFFSET_BUF_LEN]; - char dbgfs_file_qcow_cluster_buf[QCOW_CLUSTER_BUF_LEN]; - u64 dbgfs_qcow_offset; - struct mutex dbgfs_qcow_offset_mutex; + char dbgfs_file_qcow_offset_buf[QCOW_OFFSET_BUF_LEN]; + char dbgfs_file_qcow_cluster_buf[QCOW_CLUSTER_BUF_LEN]; + u64 dbgfs_qcow_offset; + struct mutex dbgfs_qcow_offset_mutex; #endif }; @@ -325,10 +330,10 @@ struct xloop_file_fmt_qcow_cow_region { * Offset of the COW region in bytes from the start of the first * cluster touched by the request. */ - unsigned offset; + unsigned int offset; /** Number of bytes to copy */ - unsigned nb_bytes; + unsigned int nb_bytes; }; /* @@ -368,13 +373,13 @@ enum xloop_file_fmt_qcow_cluster_type { }; enum xloop_file_fmt_qcow_subcluster_type { - QCOW_SUBCLUSTER_UNALLOCATED_PLAIN, - QCOW_SUBCLUSTER_UNALLOCATED_ALLOC, - QCOW_SUBCLUSTER_ZERO_PLAIN, - QCOW_SUBCLUSTER_ZERO_ALLOC, - QCOW_SUBCLUSTER_NORMAL, - QCOW_SUBCLUSTER_COMPRESSED, - QCOW_SUBCLUSTER_INVALID, + QCOW_SUBCLUSTER_UNALLOCATED_PLAIN, + QCOW_SUBCLUSTER_UNALLOCATED_ALLOC, + QCOW_SUBCLUSTER_ZERO_PLAIN, + QCOW_SUBCLUSTER_ZERO_ALLOC, + QCOW_SUBCLUSTER_NORMAL, + QCOW_SUBCLUSTER_COMPRESSED, + QCOW_SUBCLUSTER_INVALID, }; enum xloop_file_fmt_qcow_metadata_overlap { @@ -390,173 +395,146 @@ enum xloop_file_fmt_qcow_metadata_overlap { QCOW_OL_MAX_BITNR = 9, - QCOW_OL_NONE = 0, - QCOW_OL_MAIN_HEADER = (1 << QCOW_OL_MAIN_HEADER_BITNR), - QCOW_OL_ACTIVE_L1 = (1 << QCOW_OL_ACTIVE_L1_BITNR), - QCOW_OL_ACTIVE_L2 = (1 << QCOW_OL_ACTIVE_L2_BITNR), - QCOW_OL_REFCOUNT_TABLE = (1 << QCOW_OL_REFCOUNT_TABLE_BITNR), - QCOW_OL_REFCOUNT_BLOCK = (1 << QCOW_OL_REFCOUNT_BLOCK_BITNR), - QCOW_OL_SNAPSHOT_TABLE = (1 << QCOW_OL_SNAPSHOT_TABLE_BITNR), - QCOW_OL_INACTIVE_L1 = (1 << QCOW_OL_INACTIVE_L1_BITNR), - /* NOTE: Checking overlaps with inactive L2 tables will result in bdrv - * reads. */ - QCOW_OL_INACTIVE_L2 = (1 << QCOW_OL_INACTIVE_L2_BITNR), - QCOW_OL_BITMAP_DIRECTORY = (1 << QCOW_OL_BITMAP_DIRECTORY_BITNR), + QCOW_OL_NONE = 0, + QCOW_OL_MAIN_HEADER = (1 << QCOW_OL_MAIN_HEADER_BITNR), + QCOW_OL_ACTIVE_L1 = (1 << QCOW_OL_ACTIVE_L1_BITNR), + QCOW_OL_ACTIVE_L2 = (1 << QCOW_OL_ACTIVE_L2_BITNR), + QCOW_OL_REFCOUNT_TABLE = (1 << QCOW_OL_REFCOUNT_TABLE_BITNR), + QCOW_OL_REFCOUNT_BLOCK = (1 << QCOW_OL_REFCOUNT_BLOCK_BITNR), + QCOW_OL_SNAPSHOT_TABLE = (1 << QCOW_OL_SNAPSHOT_TABLE_BITNR), + QCOW_OL_INACTIVE_L1 = (1 << QCOW_OL_INACTIVE_L1_BITNR), + /* NOTE: Checking overlaps with inactive L2 tables will result in bdrv reads. */ + QCOW_OL_INACTIVE_L2 = (1 << QCOW_OL_INACTIVE_L2_BITNR), + QCOW_OL_BITMAP_DIRECTORY = (1 << QCOW_OL_BITMAP_DIRECTORY_BITNR), }; /* Perform all overlap checks which can be done in constant time */ -#define QCOW_OL_CONSTANT \ - (QCOW_OL_MAIN_HEADER | QCOW_OL_ACTIVE_L1 | QCOW_OL_REFCOUNT_TABLE | \ - QCOW_OL_SNAPSHOT_TABLE | QCOW_OL_BITMAP_DIRECTORY) +#define QCOW_OL_CONSTANT \ + (QCOW_OL_MAIN_HEADER | QCOW_OL_ACTIVE_L1 | QCOW_OL_REFCOUNT_TABLE | QCOW_OL_SNAPSHOT_TABLE | \ + QCOW_OL_BITMAP_DIRECTORY) /* Perform all overlap checks which don't require disk access */ -#define QCOW_OL_CACHED \ - (QCOW_OL_CONSTANT | QCOW_OL_ACTIVE_L2 | QCOW_OL_REFCOUNT_BLOCK | \ - QCOW_OL_INACTIVE_L1) +#define QCOW_OL_CACHED (QCOW_OL_CONSTANT | QCOW_OL_ACTIVE_L2 | QCOW_OL_REFCOUNT_BLOCK | QCOW_OL_INACTIVE_L1) /* Perform all overlap checks */ -#define QCOW_OL_ALL \ - (QCOW_OL_CACHED | QCOW_OL_INACTIVE_L2) +#define QCOW_OL_ALL (QCOW_OL_CACHED | QCOW_OL_INACTIVE_L2) #define QCOW_L1E_OFFSET_MASK 0x00fffffffffffe00ULL #define QCOW_L2E_OFFSET_MASK 0x00fffffffffffe00ULL #define QCOW_L2E_COMPRESSED_OFFSET_SIZE_MASK 0x3fffffffffffffffULL -static inline bool xloop_file_fmt_qcow_has_subclusters( - struct xloop_file_fmt_qcow_data *qcow_data) +static inline bool xloop_file_fmt_qcow_has_subclusters(struct xloop_file_fmt_qcow_data *qcow_data) { - return qcow_data->incompatible_features & QCOW_INCOMPAT_EXTL2; + return qcow_data->incompatible_features & QCOW_INCOMPAT_EXTL2; } -static inline size_t xloop_file_fmt_qcow_l2_entry_size( - struct xloop_file_fmt_qcow_data *qcow_data) +static inline size_t xloop_file_fmt_qcow_l2_entry_size(struct xloop_file_fmt_qcow_data *qcow_data) { - return xloop_file_fmt_qcow_has_subclusters(qcow_data) ? - QCOW_L2E_SIZE_EXTENDED : QCOW_L2E_SIZE_NORMAL; + return xloop_file_fmt_qcow_has_subclusters(qcow_data) ? QCOW_L2E_SIZE_EXTENDED : QCOW_L2E_SIZE_NORMAL; } -static inline u64 xloop_file_fmt_qcow_get_l2_entry( - struct xloop_file_fmt_qcow_data *qcow_data, u64 *l2_slice, int idx) +static inline u64 xloop_file_fmt_qcow_get_l2_entry(struct xloop_file_fmt_qcow_data *qcow_data, u64 *l2_slice, int idx) { - idx *= xloop_file_fmt_qcow_l2_entry_size(qcow_data) / sizeof(u64); - return be64_to_cpu(l2_slice[idx]); + idx *= xloop_file_fmt_qcow_l2_entry_size(qcow_data) / sizeof(u64); + return be64_to_cpu(l2_slice[idx]); } -static inline u64 xloop_file_fmt_qcow_get_l2_bitmap( - struct xloop_file_fmt_qcow_data *qcow_data, u64 *l2_slice, int idx) +static inline u64 xloop_file_fmt_qcow_get_l2_bitmap(struct xloop_file_fmt_qcow_data *qcow_data, u64 *l2_slice, int idx) { - if (xloop_file_fmt_qcow_has_subclusters(qcow_data)) { - idx *= xloop_file_fmt_qcow_l2_entry_size(qcow_data) / sizeof(u64); - return be64_to_cpu(l2_slice[idx + 1]); - } else { - return 0; /* For convenience only; this value has no meaning. */ - } + if (xloop_file_fmt_qcow_has_subclusters(qcow_data)) { + idx *= xloop_file_fmt_qcow_l2_entry_size(qcow_data) / sizeof(u64); + return be64_to_cpu(l2_slice[idx + 1]); + } else { + return 0; /* For convenience only; this value has no meaning. */ + } } -static inline bool xloop_file_fmt_qcow_has_data_file( - struct xloop_file_fmt_qcow_data *qcow_data) +static inline bool xloop_file_fmt_qcow_has_data_file(struct xloop_file_fmt_qcow_data *qcow_data) { /* At the moment, there is no support for copy on write! */ return false; } -static inline bool xloop_file_fmt_qcow_data_file_is_raw( - struct xloop_file_fmt_qcow_data *qcow_data) +static inline bool xloop_file_fmt_qcow_data_file_is_raw(struct xloop_file_fmt_qcow_data *qcow_data) { - return !!(qcow_data->autoclear_features & - QCOW_AUTOCLEAR_DATA_FILE_RAW); + return !!(qcow_data->autoclear_features & QCOW_AUTOCLEAR_DATA_FILE_RAW); } -static inline s64 xloop_file_fmt_qcow_start_of_cluster( - struct xloop_file_fmt_qcow_data *qcow_data, s64 offset) +static inline s64 xloop_file_fmt_qcow_start_of_cluster(struct xloop_file_fmt_qcow_data *qcow_data, s64 offset) { return offset & ~(qcow_data->cluster_size - 1); } -static inline s64 xloop_file_fmt_qcow_offset_into_cluster( - struct xloop_file_fmt_qcow_data *qcow_data, s64 offset) +static inline s64 xloop_file_fmt_qcow_offset_into_cluster(struct xloop_file_fmt_qcow_data *qcow_data, s64 offset) { return offset & (qcow_data->cluster_size - 1); } -static inline s64 xloop_file_fmt_qcow_offset_into_subcluster( - struct xloop_file_fmt_qcow_data *qcow_data, s64 offset) +static inline s64 xloop_file_fmt_qcow_offset_into_subcluster(struct xloop_file_fmt_qcow_data *qcow_data, s64 offset) { return offset & (qcow_data->subcluster_size - 1); } -static inline s64 xloop_file_fmt_qcow_size_to_clusters( - struct xloop_file_fmt_qcow_data *qcow_data, u64 size) +static inline s64 xloop_file_fmt_qcow_size_to_clusters(struct xloop_file_fmt_qcow_data *qcow_data, u64 size) { - return (size + (qcow_data->cluster_size - 1)) >> - qcow_data->cluster_bits; + return (size + (qcow_data->cluster_size - 1)) >> qcow_data->cluster_bits; } -static inline s64 xloop_file_fmt_qcow_size_to_l1( - struct xloop_file_fmt_qcow_data *qcow_data, s64 size) +static inline s64 xloop_file_fmt_qcow_size_to_l1(struct xloop_file_fmt_qcow_data *qcow_data, s64 size) { int shift = qcow_data->cluster_bits + qcow_data->l2_bits; + return (size + (1ULL << shift) - 1) >> shift; } -static inline int xloop_file_fmt_qcow_offset_to_l1_index( - struct xloop_file_fmt_qcow_data *qcow_data, u64 offset) +static inline int xloop_file_fmt_qcow_offset_to_l1_index(struct xloop_file_fmt_qcow_data *qcow_data, u64 offset) { return offset >> (qcow_data->l2_bits + qcow_data->cluster_bits); } -static inline int xloop_file_fmt_qcow_offset_to_l2_index( - struct xloop_file_fmt_qcow_data *qcow_data, s64 offset) +static inline int xloop_file_fmt_qcow_offset_to_l2_index(struct xloop_file_fmt_qcow_data *qcow_data, s64 offset) { return (offset >> qcow_data->cluster_bits) & (qcow_data->l2_size - 1); } -static inline int xloop_file_fmt_qcow_offset_to_l2_slice_index( - struct xloop_file_fmt_qcow_data *qcow_data, s64 offset) +static inline int xloop_file_fmt_qcow_offset_to_l2_slice_index(struct xloop_file_fmt_qcow_data *qcow_data, s64 offset) { - return (offset >> qcow_data->cluster_bits) & - (qcow_data->l2_slice_size - 1); + return (offset >> qcow_data->cluster_bits) & (qcow_data->l2_slice_size - 1); } -static inline int xloop_file_fmt_qcow_offset_to_sc_index( - struct xloop_file_fmt_qcow_data *qcow_data, s64 offset) +static inline int xloop_file_fmt_qcow_offset_to_sc_index(struct xloop_file_fmt_qcow_data *qcow_data, s64 offset) { - return (offset >> qcow_data->subcluster_bits) & - (qcow_data->subclusters_per_cluster - 1); + return (offset >> qcow_data->subcluster_bits) & (qcow_data->subclusters_per_cluster - 1); } -static inline s64 xloop_file_fmt_qcow_vm_state_offset( - struct xloop_file_fmt_qcow_data *qcow_data) +static inline s64 xloop_file_fmt_qcow_vm_state_offset(struct xloop_file_fmt_qcow_data *qcow_data) { - return (s64)qcow_data->l1_vm_state_index << - (qcow_data->cluster_bits + qcow_data->l2_bits); + return (s64)qcow_data->l1_vm_state_index << (qcow_data->cluster_bits + qcow_data->l2_bits); } -static inline enum xloop_file_fmt_qcow_cluster_type -xloop_file_fmt_qcow_get_cluster_type(struct xloop_file_fmt *xlo_fmt, - u64 l2_entry) +static inline enum xloop_file_fmt_qcow_cluster_type xloop_file_fmt_qcow_get_cluster_type(struct xloop_file_fmt *xlo_fmt, + u64 l2_entry) { struct xloop_file_fmt_qcow_data *qcow_data = xlo_fmt->private_data; if (l2_entry & QCOW_OFLAG_COMPRESSED) { return QCOW_CLUSTER_COMPRESSED; } else if (l2_entry & QCOW_OFLAG_ZERO) { - if (l2_entry & QCOW_L2E_OFFSET_MASK) { + if (l2_entry & QCOW_L2E_OFFSET_MASK) return QCOW_CLUSTER_ZERO_ALLOC; - } return QCOW_CLUSTER_ZERO_PLAIN; } else if (!(l2_entry & QCOW_L2E_OFFSET_MASK)) { - /* Offset 0 generally means unallocated, but it is ambiguous + /* + * Offset 0 generally means unallocated, but it is ambiguous * with external data files because 0 is a valid offset there. * However, all clusters in external data files always have * refcount 1, so we can rely on QCOW_OFLAG_COPIED to - * disambiguate. */ - if (xloop_file_fmt_qcow_has_data_file(qcow_data) && - (l2_entry & QCOW_OFLAG_COPIED)) { + * disambiguate. + */ + if (xloop_file_fmt_qcow_has_data_file(qcow_data) && (l2_entry & QCOW_OFLAG_COPIED)) return QCOW_CLUSTER_NORMAL; - } else { + else return QCOW_CLUSTER_UNALLOCATED; - } } else { return QCOW_CLUSTER_NORMAL; } @@ -570,76 +548,71 @@ xloop_file_fmt_qcow_get_cluster_type(struct xloop_file_fmt *xlo_fmt, * to subcluster @sc_index). */ static inline enum xloop_file_fmt_qcow_subcluster_type -xloop_file_fmt_qcow_get_subcluster_type(struct xloop_file_fmt *xlo_fmt, - u64 l2_entry, u64 l2_bitmap, unsigned int sc_index) +xloop_file_fmt_qcow_get_subcluster_type(struct xloop_file_fmt *xlo_fmt, u64 l2_entry, u64 l2_bitmap, + unsigned int sc_index) { struct xloop_file_fmt_qcow_data *qcow_data = xlo_fmt->private_data; - enum xloop_file_fmt_qcow_cluster_type type = - xloop_file_fmt_qcow_get_cluster_type(xlo_fmt, l2_entry); - ASSERT(sc_index < qcow_data->subclusters_per_cluster); - - if (xloop_file_fmt_qcow_has_subclusters(qcow_data)) { - switch (type) { - case QCOW_CLUSTER_COMPRESSED: - return QCOW_SUBCLUSTER_COMPRESSED; - case QCOW_CLUSTER_NORMAL: - if ((l2_bitmap >> 32) & l2_bitmap) { - return QCOW_SUBCLUSTER_INVALID; - } else if (l2_bitmap & QCOW_OFLAG_SUB_ZERO(sc_index)) { - return QCOW_SUBCLUSTER_ZERO_ALLOC; - } else if (l2_bitmap & QCOW_OFLAG_SUB_ALLOC(sc_index)) { - return QCOW_SUBCLUSTER_NORMAL; - } else { - return QCOW_SUBCLUSTER_UNALLOCATED_ALLOC; - } - case QCOW_CLUSTER_UNALLOCATED: - if (l2_bitmap & QCOW_L2_BITMAP_ALL_ALLOC) { - return QCOW_SUBCLUSTER_INVALID; - } else if (l2_bitmap & QCOW_OFLAG_SUB_ZERO(sc_index)) { - return QCOW_SUBCLUSTER_ZERO_PLAIN; - } else { - return QCOW_SUBCLUSTER_UNALLOCATED_PLAIN; - } - default: + enum xloop_file_fmt_qcow_cluster_type type = xloop_file_fmt_qcow_get_cluster_type(xlo_fmt, l2_entry); + + ASSERT(sc_index < qcow_data->subclusters_per_cluster); + + if (xloop_file_fmt_qcow_has_subclusters(qcow_data)) { + switch (type) { + case QCOW_CLUSTER_COMPRESSED: + return QCOW_SUBCLUSTER_COMPRESSED; + case QCOW_CLUSTER_NORMAL: + if ((l2_bitmap >> 32) & l2_bitmap) + return QCOW_SUBCLUSTER_INVALID; + else if (l2_bitmap & QCOW_OFLAG_SUB_ZERO(sc_index)) + return QCOW_SUBCLUSTER_ZERO_ALLOC; + else if (l2_bitmap & QCOW_OFLAG_SUB_ALLOC(sc_index)) + return QCOW_SUBCLUSTER_NORMAL; + else + return QCOW_SUBCLUSTER_UNALLOCATED_ALLOC; + case QCOW_CLUSTER_UNALLOCATED: + if (l2_bitmap & QCOW_L2_BITMAP_ALL_ALLOC) + return QCOW_SUBCLUSTER_INVALID; + else if (l2_bitmap & QCOW_OFLAG_SUB_ZERO(sc_index)) + return QCOW_SUBCLUSTER_ZERO_PLAIN; + else + return QCOW_SUBCLUSTER_UNALLOCATED_PLAIN; + default: /* not reachable */ - ASSERT(false); + ASSERT(false); return QCOW_SUBCLUSTER_INVALID; - } - } else { - switch (type) { - case QCOW_CLUSTER_COMPRESSED: - return QCOW_SUBCLUSTER_COMPRESSED; - case QCOW_CLUSTER_ZERO_PLAIN: - return QCOW_SUBCLUSTER_ZERO_PLAIN; - case QCOW_CLUSTER_ZERO_ALLOC: - return QCOW_SUBCLUSTER_ZERO_ALLOC; - case QCOW_CLUSTER_NORMAL: - return QCOW_SUBCLUSTER_NORMAL; - case QCOW_CLUSTER_UNALLOCATED: - return QCOW_SUBCLUSTER_UNALLOCATED_PLAIN; - default: - /* not reachable */ - ASSERT(false); + } + } else { + switch (type) { + case QCOW_CLUSTER_COMPRESSED: + return QCOW_SUBCLUSTER_COMPRESSED; + case QCOW_CLUSTER_ZERO_PLAIN: + return QCOW_SUBCLUSTER_ZERO_PLAIN; + case QCOW_CLUSTER_ZERO_ALLOC: + return QCOW_SUBCLUSTER_ZERO_ALLOC; + case QCOW_CLUSTER_NORMAL: + return QCOW_SUBCLUSTER_NORMAL; + case QCOW_CLUSTER_UNALLOCATED: + return QCOW_SUBCLUSTER_UNALLOCATED_PLAIN; + default: + /* not reachable */ + ASSERT(false); return QCOW_SUBCLUSTER_INVALID; - } - } + } + } } #ifdef CONFIG_DEBUG_FS -static inline const char *xloop_file_fmt_qcow_get_subcluster_name( - const enum xloop_file_fmt_qcow_subcluster_type type) +static inline const char *xloop_file_fmt_qcow_get_subcluster_name(const enum xloop_file_fmt_qcow_subcluster_type type) { - static const char *subcluster_names[] = { - "QCOW2_SUBCLUSTER_UNALLOCATED_PLAIN", - "QCOW2_SUBCLUSTER_UNALLOCATED_ALLOC", - "QCOW2_SUBCLUSTER_ZERO_PLAIN", - "QCOW2_SUBCLUSTER_ZERO_ALLOC", - "QCOW2_SUBCLUSTER_NORMAL", - "QCOW2_SUBCLUSTER_COMPRESSED", - "QCOW2_SUBCLUSTER_INVALID" - }; - - return subcluster_names[type]; + static const char * const subcluster_names[] = { "QCOW2_SUBCLUSTER_UNALLOCATED_PLAIN", + "QCOW2_SUBCLUSTER_UNALLOCATED_ALLOC", + "QCOW2_SUBCLUSTER_ZERO_PLAIN", + "QCOW2_SUBCLUSTER_ZERO_ALLOC", + "QCOW2_SUBCLUSTER_NORMAL", + "QCOW2_SUBCLUSTER_COMPRESSED", + "QCOW2_SUBCLUSTER_INVALID" }; + + return subcluster_names[type]; } #endif diff --git a/src/kernel/xloop_file_fmt_raw.c b/src/kernel/xloop_file_fmt_raw.c index 12914e8..1c2c42b 100644 --- a/src/kernel/xloop_file_fmt_raw.c +++ b/src/kernel/xloop_file_fmt_raw.c @@ -1,4 +1,4 @@ -/* SPDX-License-Identifier: GPL-2.0 */ +// SPDX-License-Identifier: GPL-2.0 /* * xloop_file_fmt_raw.c * @@ -27,18 +27,16 @@ #include "xloop_file_fmt.h" -static inline loff_t __raw_file_fmt_rq_get_pos(struct xloop_file_fmt *xlo_fmt, - struct request *rq) +static inline loff_t __raw_file_fmt_rq_get_pos(struct xloop_file_fmt *xlo_fmt, struct request *rq) { struct xloop_device *xlo = xloop_file_fmt_get_xlo(xlo_fmt); - return ((loff_t) blk_rq_pos(rq) << 9) + xlo->xlo_offset; + + return ((loff_t)blk_rq_pos(rq) << 9) + xlo->xlo_offset; } /* transfer function for DEPRECATED cryptoxloop support */ -static inline int __raw_file_fmt_do_transfer(struct xloop_device *xlo, int cmd, - struct page *rpage, unsigned roffs, - struct page *lpage, unsigned loffs, - int size, sector_t rblock) +static inline int __raw_file_fmt_do_transfer(struct xloop_device *xlo, int cmd, struct page *rpage, unsigned int roffs, + struct page *lpage, unsigned int loffs, int size, sector_t rblock) { int ret; @@ -46,13 +44,11 @@ static inline int __raw_file_fmt_do_transfer(struct xloop_device *xlo, int cmd, if (likely(!ret)) return 0; - pr_err_ratelimited("transfer error at byte offset %llu, length %i.\n", - (unsigned long long)rblock << 9, size); + pr_err_ratelimited("transfer error at byte offset %llu, length %i.\n", (unsigned long long)rblock << 9, size); return ret; } -static int __raw_file_fmt_read_transfer(struct xloop_device *xlo, - struct request *rq, loff_t pos) +static int __raw_file_fmt_read_transfer(struct xloop_device *xlo, struct request *rq, loff_t pos) { struct bio_vec bvec, b; struct req_iterator iter; @@ -79,8 +75,7 @@ static int __raw_file_fmt_read_transfer(struct xloop_device *xlo, goto out_free_page; } - ret = __raw_file_fmt_do_transfer(xlo, READ, page, 0, bvec.bv_page, - bvec.bv_offset, len, offset >> 9); + ret = __raw_file_fmt_do_transfer(xlo, READ, page, 0, bvec.bv_page, bvec.bv_offset, len, offset >> 9); if (ret) goto out_free_page; @@ -101,8 +96,7 @@ out_free_page: return ret; } -static int raw_file_fmt_read(struct xloop_file_fmt *xlo_fmt, - struct request *rq) +static int raw_file_fmt_read(struct xloop_file_fmt *xlo_fmt, struct request *rq) { struct bio_vec bvec; struct req_iterator iter; @@ -164,8 +158,7 @@ static void __raw_file_fmt_rw_aio_complete(struct kiocb *iocb, long ret, long re __raw_file_fmt_rw_aio_do_completion(cmd); } -static int __raw_file_fmt_rw_aio(struct xloop_device *xlo, - struct xloop_cmd *cmd, loff_t pos, bool rw) +static int __raw_file_fmt_rw_aio(struct xloop_device *xlo, struct xloop_cmd *cmd, loff_t pos, bool rw) { struct iov_iter iter; struct req_iterator rq_iter; @@ -188,8 +181,7 @@ static int __raw_file_fmt_rw_aio(struct xloop_device *xlo, __rq_for_each_bio(bio, rq) nr_bvec += bio_segments(bio); #endif - bvec = kmalloc_array(nr_bvec, sizeof(struct bio_vec), - GFP_NOIO); + bvec = kmalloc_array(nr_bvec, sizeof(struct bio_vec), GFP_NOIO); if (!bvec) return -EIO; cmd->bvec = bvec; @@ -248,8 +240,7 @@ static int __raw_file_fmt_rw_aio(struct xloop_device *xlo, return 0; } -static int raw_file_fmt_read_aio(struct xloop_file_fmt *xlo_fmt, - struct request *rq) +static int raw_file_fmt_read_aio(struct xloop_file_fmt *xlo_fmt, struct request *rq) { struct xloop_device *xlo = xloop_file_fmt_get_xlo(xlo_fmt); struct xloop_cmd *cmd = blk_mq_rq_to_pdu(rq); @@ -258,9 +249,7 @@ static int raw_file_fmt_read_aio(struct xloop_file_fmt *xlo_fmt, return __raw_file_fmt_rw_aio(xlo, cmd, pos, READ); } -static int __raw_file_fmt_write_bvec(struct file *file, - struct bio_vec *bvec, - loff_t *ppos) +static int __raw_file_fmt_write_bvec(struct file *file, struct bio_vec *bvec, loff_t *ppos) { struct iov_iter i; ssize_t bw; @@ -271,11 +260,10 @@ static int __raw_file_fmt_write_bvec(struct file *file, bw = vfs_iter_write(file, &i, ppos, 0); file_end_write(file); - if (likely(bw == bvec->bv_len)) + if (likely(bw == bvec->bv_len)) return 0; - pr_err_ratelimited("write error at byte offset %llu, length %i.\n", - (unsigned long long)*ppos, bvec->bv_len); + pr_err_ratelimited("write error at byte offset %llu, length %i.\n", (unsigned long long)*ppos, bvec->bv_len); if (bw >= 0) bw = -EIO; return bw; @@ -286,10 +274,9 @@ static int __raw_file_fmt_write_bvec(struct file *file, * data as it cannot do the transformations in place without having direct * access to the destination pages of the backing file. */ -static int __raw_file_fmt_write_transfer(struct xloop_device *xlo, - struct request *rq, loff_t pos) +static int __raw_file_fmt_write_transfer(struct xloop_device *xlo, struct request *rq, loff_t pos) { -struct bio_vec bvec, b; + struct bio_vec bvec, b; struct req_iterator iter; struct page *page; int ret = 0; @@ -299,8 +286,8 @@ struct bio_vec bvec, b; return -ENOMEM; rq_for_each_segment(bvec, rq, iter) { - ret = __raw_file_fmt_do_transfer(xlo, WRITE, page, 0, bvec.bv_page, - bvec.bv_offset, bvec.bv_len, pos >> 9); + ret = __raw_file_fmt_do_transfer(xlo, WRITE, page, 0, bvec.bv_page, bvec.bv_offset, bvec.bv_len, + pos >> 9); if (unlikely(ret)) break; @@ -316,8 +303,7 @@ struct bio_vec bvec, b; return ret; } -static int raw_file_fmt_write(struct xloop_file_fmt *xlo_fmt, - struct request *rq) +static int raw_file_fmt_write(struct xloop_file_fmt *xlo_fmt, struct request *rq) { struct bio_vec bvec; struct req_iterator iter; @@ -341,8 +327,7 @@ static int raw_file_fmt_write(struct xloop_file_fmt *xlo_fmt, return ret; } -static int raw_file_fmt_write_aio(struct xloop_file_fmt *xlo_fmt, - struct request *rq) +static int raw_file_fmt_write_aio(struct xloop_file_fmt *xlo_fmt, struct request *rq) { struct xloop_device *xlo = xloop_file_fmt_get_xlo(xlo_fmt); struct xloop_cmd *cmd = blk_mq_rq_to_pdu(rq); @@ -351,8 +336,7 @@ static int raw_file_fmt_write_aio(struct xloop_file_fmt *xlo_fmt, return __raw_file_fmt_rw_aio(xlo, cmd, pos, WRITE); } -static int __raw_file_fmt_fallocate(struct xloop_device *xlo, - struct request *rq, loff_t pos, int mode) +static int __raw_file_fmt_fallocate(struct xloop_device *xlo, struct request *rq, loff_t pos, int mode) { /* * We use fallocate to manipulate the space mappings used by the image @@ -378,8 +362,7 @@ out: return ret; } -static int raw_file_fmt_write_zeros(struct xloop_file_fmt *xlo_fmt, - struct request *rq) +static int raw_file_fmt_write_zeros(struct xloop_file_fmt *xlo_fmt, struct request *rq) { loff_t pos = __raw_file_fmt_rq_get_pos(xlo_fmt, rq); struct xloop_device *xlo = xloop_file_fmt_get_xlo(xlo_fmt); @@ -389,13 +372,10 @@ static int raw_file_fmt_write_zeros(struct xloop_file_fmt *xlo_fmt, * write zeroes the range. Otherwise, punch them out. */ return __raw_file_fmt_fallocate(xlo, rq, pos, - (rq->cmd_flags & REQ_NOUNMAP) ? - FALLOC_FL_ZERO_RANGE : - FALLOC_FL_PUNCH_HOLE); + (rq->cmd_flags & REQ_NOUNMAP) ? FALLOC_FL_ZERO_RANGE : FALLOC_FL_PUNCH_HOLE); } -static int raw_file_fmt_discard(struct xloop_file_fmt *xlo_fmt, - struct request *rq) +static int raw_file_fmt_discard(struct xloop_file_fmt *xlo_fmt, struct request *rq) { loff_t pos = __raw_file_fmt_rq_get_pos(xlo_fmt, rq); struct xloop_device *xlo = xloop_file_fmt_get_xlo(xlo_fmt); @@ -408,14 +388,15 @@ static int raw_file_fmt_flush(struct xloop_file_fmt *xlo_fmt) struct xloop_device *xlo = xloop_file_fmt_get_xlo(xlo_fmt); struct file *file = xlo->xlo_backing_file; int ret = vfs_fsync(file, 0); + if (unlikely(ret && ret != -EINVAL)) ret = -EIO; return ret; } -static loff_t raw_file_fmt_sector_size(struct xloop_file_fmt *xlo_fmt, - struct file *file, loff_t offset, loff_t sizelimit) +static loff_t raw_file_fmt_sector_size(struct xloop_file_fmt *xlo_fmt, struct file *file, loff_t offset, + loff_t sizelimit) { loff_t xloopsize; @@ -437,23 +418,23 @@ static loff_t raw_file_fmt_sector_size(struct xloop_file_fmt *xlo_fmt, } static struct xloop_file_fmt_ops raw_file_fmt_ops = { - .init = NULL, - .exit = NULL, - .read = raw_file_fmt_read, - .write = raw_file_fmt_write, - .read_aio = raw_file_fmt_read_aio, - .write_aio = raw_file_fmt_write_aio, + .init = NULL, + .exit = NULL, + .read = raw_file_fmt_read, + .write = raw_file_fmt_write, + .read_aio = raw_file_fmt_read_aio, + .write_aio = raw_file_fmt_write_aio, .write_zeros = raw_file_fmt_write_zeros, - .discard = raw_file_fmt_discard, - .flush = raw_file_fmt_flush, + .discard = raw_file_fmt_discard, + .flush = raw_file_fmt_flush, .sector_size = raw_file_fmt_sector_size, }; static struct xloop_file_fmt_driver raw_file_fmt_driver = { - .name = "RAW", + .name = "RAW", .file_fmt_type = XLO_FILE_FMT_RAW, - .ops = &raw_file_fmt_ops, - .owner = THIS_MODULE, + .ops = &raw_file_fmt_ops, + .owner = THIS_MODULE, }; static int __init xloop_file_fmt_raw_init(void) diff --git a/src/kernel/xloop_main.c b/src/kernel/xloop_main.c index aa75c41..fb3f17b 100644 --- a/src/kernel/xloop_main.c +++ b/src/kernel/xloop_main.c @@ -1,3 +1,4 @@ +// SPDX-License-Identifier: GPL-2.0 /* * xloop_main.c * @@ -97,9 +98,9 @@ /* define RHEL_CHECK_VERSION macro to check CentOS version */ #if defined(RHEL_RELEASE_CODE) && defined(RHEL_RELEASE_VERSION) - #define RHEL_CHECK_VERSION(CONDITION) (CONDITION) +#define RHEL_CHECK_VERSION(CONDITION) (CONDITION) #else - #define RHEL_CHECK_VERSION(CONDITION) (0) +#define RHEL_CHECK_VERSION(CONDITION) (0) #endif static DEFINE_IDR(xloop_index_idr); @@ -114,10 +115,8 @@ struct device *xloop_device_to_dev(struct xloop_device *xlo) } EXPORT_SYMBOL(xloop_device_to_dev); -static int transfer_xor(struct xloop_device *xlo, int cmd, - struct page *raw_page, unsigned raw_off, - struct page *xloop_page, unsigned xloop_off, - int size, sector_t real_block) +static int transfer_xor(struct xloop_device *xlo, int cmd, struct page *raw_page, unsigned int raw_off, + struct page *xloop_page, unsigned int xloop_off, int size, sector_t real_block) { char *raw_buf = kmap_atomic(raw_page) + raw_off; char *xloop_buf = kmap_atomic(xloop_page) + xloop_off; @@ -152,24 +151,16 @@ static int xor_init(struct xloop_device *xlo, const struct xloop_info64 *info) static struct xloop_func_table none_funcs = { .number = XLO_CRYPT_NONE, -}; +}; -static struct xloop_func_table xor_funcs = { - .number = XLO_CRYPT_XOR, - .transfer = transfer_xor, - .init = xor_init -}; +static struct xloop_func_table xor_funcs = { .number = XLO_CRYPT_XOR, .transfer = transfer_xor, .init = xor_init }; /* xfer_funcs[0] is special - its release function is never called */ -static struct xloop_func_table *xfer_funcs[MAX_XLO_CRYPT] = { - &none_funcs, - &xor_funcs -}; +static struct xloop_func_table *xfer_funcs[MAX_XLO_CRYPT] = { &none_funcs, &xor_funcs }; static loff_t get_xloop_size(struct xloop_device *xlo, struct file *file) { - return xloop_file_fmt_sector_size(xlo->xlo_fmt, file, xlo->xlo_offset, - xlo->xlo_sizelimit); + return xloop_file_fmt_sector_size(xlo->xlo_fmt, file, xlo->xlo_offset, xlo->xlo_sizelimit); } static void __xloop_update_dio(struct xloop_device *xlo, bool dio) @@ -178,7 +169,7 @@ static void __xloop_update_dio(struct xloop_device *xlo, bool dio) struct address_space *mapping = file->f_mapping; struct inode *inode = mapping->host; unsigned short sb_bsize = 0; - unsigned dio_align = 0; + unsigned int dio_align = 0; bool use_dio; if (inode->i_sb->s_bdev) { @@ -197,10 +188,8 @@ static void __xloop_update_dio(struct xloop_device *xlo, bool dio) * of requests in sane applications should be PAGE_SIZE aligned */ if (dio) { - if (queue_logical_block_size(xlo->xlo_queue) >= sb_bsize && - !(xlo->xlo_offset & dio_align) && - mapping->a_ops->direct_IO && - !xlo->transfer) + if (queue_logical_block_size(xlo->xlo_queue) >= sb_bsize && !(xlo->xlo_offset & dio_align) && + mapping->a_ops->direct_IO && !xlo->transfer) use_dio = true; else use_dio = false; @@ -237,8 +226,7 @@ static void __xloop_update_dio(struct xloop_device *xlo, bool dio) * xloop_validate_block_size() - validates the passed in block size * @bsize: size to validate */ -static int -xloop_validate_block_size(unsigned short bsize) +static int xloop_validate_block_size(unsigned short bsize) { if (bsize < 512 || bsize > PAGE_SIZE || !is_power_of_2(bsize)) return -EINVAL; @@ -274,12 +262,12 @@ static void xloop_set_size(struct xloop_device *xlo, loff_t size) set_capacity_revalidate_and_notify(xlo->xlo_disk, size, false); #else capacity = get_capacity(xlo->xlo_disk); - set_capacity(xlo->xlo_disk, size); - if (capacity != size && capacity != 0 && size != 0) { - char *envp[] = { "RESIZE=1", NULL }; - kobject_uevent_env(&disk_to_dev(xlo->xlo_disk)->kobj, KOBJ_CHANGE, - envp); - } + set_capacity(xlo->xlo_disk, size); + if (capacity != size && capacity != 0 && size != 0) { + char *envp[] = { "RESIZE=1", NULL }; + + kobject_uevent_env(&disk_to_dev(xlo->xlo_disk)->kobj, KOBJ_CHANGE, envp); + } #endif } @@ -288,8 +276,7 @@ static void xlo_complete_rq(struct request *rq) struct xloop_cmd *cmd = blk_mq_rq_to_pdu(rq); blk_status_t ret = BLK_STS_OK; - if (!cmd->use_aio || cmd->ret < 0 || cmd->ret == blk_rq_bytes(rq) || - req_op(rq) != REQ_OP_READ) { + if (!cmd->use_aio || cmd->ret < 0 || cmd->ret == blk_rq_bytes(rq) || req_op(rq) != REQ_OP_READ) { if (cmd->ret < 0) ret = errno_to_blk_status(cmd->ret); goto end_io; @@ -356,17 +343,15 @@ static int do_req_filebacked(struct xloop_device *xlo, struct request *rq) static inline void xloop_update_dio(struct xloop_device *xlo) { - __xloop_update_dio(xlo, (xlo->xlo_backing_file->f_flags & O_DIRECT) | - xlo->use_dio); + __xloop_update_dio(xlo, (xlo->xlo_backing_file->f_flags & O_DIRECT) | xlo->use_dio); } -static void xloop_reread_partitions(struct xloop_device *xlo, - struct block_device *bdev) +static void xloop_reread_partitions(struct xloop_device *xlo, struct block_device *bdev) { int rc; -#if (LINUX_VERSION_CODE >= KERNEL_VERSION(5, 5, 0)) || \ - RHEL_CHECK_VERSION(RHEL_RELEASE_CODE >= RHEL_RELEASE_VERSION(8, 3)) +#if (KERNEL_VERSION(5, 5, 0) <= LINUX_VERSION_CODE) || \ + RHEL_CHECK_VERSION(RHEL_RELEASE_VERSION(8, 3) <= RHEL_RELEASE_CODE) mutex_lock(&bdev->bd_mutex); rc = bdev_disk_changed(bdev, false); mutex_unlock(&bdev->bd_mutex); @@ -374,8 +359,7 @@ static void xloop_reread_partitions(struct xloop_device *xlo, rc = blkdev_reread_part(bdev); #endif if (rc) - dev_warn(xloop_device_to_dev(xlo), "partition scan failed (rc=%d)\n", - rc); + dev_warn(xloop_device_to_dev(xlo), "partition scan failed (rc=%d)\n", rc); } static inline int is_xloop_device(struct file *file) @@ -387,8 +371,8 @@ static inline int is_xloop_device(struct file *file) static int xloop_validate_file(struct file *file, struct block_device *bdev) { - struct inode *inode = file->f_mapping->host; - struct file *f = file; + struct inode *inode = file->f_mapping->host; + struct file *f = file; /* Avoid recursion */ while (is_xloop_device(f)) { @@ -398,9 +382,9 @@ static int xloop_validate_file(struct file *file, struct block_device *bdev) return -EBADF; l = f->f_mapping->host->i_bdev->bd_disk->private_data; - if (l->xlo_state != Xlo_bound) { + if (l->xlo_state != Xlo_bound) return -EINVAL; - } + f = l->xlo_backing_file; } if (!S_ISREG(inode->i_mode) && !S_ISBLK(inode->i_mode)) @@ -416,12 +400,11 @@ static int xloop_validate_file(struct file *file, struct block_device *bdev) * This can only work if the xloop device is used read-only, and if the * new backing store is the same size and type as the old backing store. */ -static int xloop_change_fd(struct xloop_device *xlo, struct block_device *bdev, - unsigned int arg) +static int xloop_change_fd(struct xloop_device *xlo, struct block_device *bdev, unsigned int arg) { - struct file *file = NULL, *old_file; - int error; - bool partscan; + struct file *file = NULL, *old_file; + int error; + bool partscan; error = mutex_lock_killable(&xloop_ctl_mutex); if (error) @@ -457,8 +440,7 @@ static int xloop_change_fd(struct xloop_device *xlo, struct block_device *bdev, mapping_set_gfp_mask(old_file->f_mapping, xlo->old_gfp_mask); xlo->xlo_backing_file = file; xlo->old_gfp_mask = mapping_gfp_mask(file->f_mapping); - mapping_set_gfp_mask(file->f_mapping, - xlo->old_gfp_mask & ~(__GFP_IO|__GFP_FS)); + mapping_set_gfp_mask(file->f_mapping, xlo->old_gfp_mask & ~(__GFP_IO | __GFP_FS)); xloop_update_dio(xlo); blk_mq_unfreeze_queue(xlo->xlo_queue); partscan = xlo->xlo_flags & XLO_FLAGS_PARTSCAN; @@ -482,8 +464,7 @@ out_err: /* xloop sysfs attributes */ -static ssize_t xloop_attr_show(struct device *dev, char *page, - ssize_t (*callback)(struct xloop_device *, char *)) +static ssize_t xloop_attr_show(struct device *dev, char *page, ssize_t (*callback)(struct xloop_device *, char *)) { struct gendisk *disk = dev_to_disk(dev); struct xloop_device *xlo = disk->private_data; @@ -491,15 +472,13 @@ static ssize_t xloop_attr_show(struct device *dev, char *page, return callback(xlo, page); } -#define XLOOP_ATTR_RO(_name) \ -static ssize_t xloop_attr_##_name##_show(struct xloop_device *, char *); \ -static ssize_t xloop_attr_do_show_##_name(struct device *d, \ - struct device_attribute *attr, char *b) \ -{ \ - return xloop_attr_show(d, b, xloop_attr_##_name##_show); \ -} \ -static struct device_attribute xloop_attr_##_name = \ - __ATTR(_name, 0444, xloop_attr_do_show_##_name, NULL); +#define XLOOP_ATTR_RO(_name) \ + static ssize_t xloop_attr_##_name##_show(struct xloop_device *, char *); \ + static ssize_t xloop_attr_do_show_##_name(struct device *d, struct device_attribute *attr, char *b) \ + { \ + return xloop_attr_show(d, b, xloop_attr_##_name##_show); \ + } \ + static struct device_attribute xloop_attr_##_name = __ATTR(_name, 0444, xloop_attr_do_show_##_name, NULL); static ssize_t xloop_attr_backing_file_show(struct xloop_device *xlo, char *buf) { @@ -523,8 +502,7 @@ static ssize_t xloop_attr_backing_file_show(struct xloop_device *xlo, char *buf) return ret; } -static ssize_t xloop_attr_file_fmt_type_show(struct xloop_device *xlo, - char *buf) +static ssize_t xloop_attr_file_fmt_type_show(struct xloop_device *xlo, char *buf) { ssize_t len = 0; @@ -574,32 +552,26 @@ XLOOP_ATTR_RO(partscan); XLOOP_ATTR_RO(dio); static struct attribute *xloop_attrs[] = { - &xloop_attr_backing_file.attr, - &xloop_attr_file_fmt_type.attr, - &xloop_attr_offset.attr, - &xloop_attr_sizelimit.attr, - &xloop_attr_autoclear.attr, - &xloop_attr_partscan.attr, - &xloop_attr_dio.attr, - NULL, + &xloop_attr_backing_file.attr, &xloop_attr_file_fmt_type.attr, + &xloop_attr_offset.attr, &xloop_attr_sizelimit.attr, + &xloop_attr_autoclear.attr, &xloop_attr_partscan.attr, + &xloop_attr_dio.attr, NULL, }; static struct attribute_group xloop_attribute_group = { - .name = "xloop", - .attrs= xloop_attrs, + .name = "xloop", + .attrs = xloop_attrs, }; static void xloop_sysfs_init(struct xloop_device *xlo) { - xlo->sysfs_inited = !sysfs_create_group(&disk_to_dev(xlo->xlo_disk)->kobj, - &xloop_attribute_group); + xlo->sysfs_inited = !sysfs_create_group(&disk_to_dev(xlo->xlo_disk)->kobj, &xloop_attribute_group); } static void xloop_sysfs_exit(struct xloop_device *xlo) { if (xlo->sysfs_inited) - sysfs_remove_group(&disk_to_dev(xlo->xlo_disk)->kobj, - &xloop_attribute_group); + sysfs_remove_group(&disk_to_dev(xlo->xlo_disk)->kobj, &xloop_attribute_group); } static void xloop_config_discard(struct xloop_device *xlo) @@ -622,8 +594,7 @@ static void xloop_config_discard(struct xloop_device *xlo) backingq = bdev_get_queue(inode->i_bdev); max_discard_sectors = backingq->limits.max_write_zeroes_sectors; - granularity = backingq->limits.discard_granularity ?: - queue_physical_block_size(backingq); + granularity = backingq->limits.discard_granularity ?: queue_physical_block_size(backingq); /* * We use punch hole to reclaim the free space used by the @@ -673,8 +644,7 @@ static int xloop_kthread_worker_fn(void *worker_ptr) static int xloop_prepare_queue(struct xloop_device *xlo) { kthread_init_worker(&xlo->worker); - xlo->worker_task = kthread_run(xloop_kthread_worker_fn, - &xlo->worker, "xloop%d", xlo->xlo_number); + xlo->worker_task = kthread_run(xloop_kthread_worker_fn, &xlo->worker, "xloop%d", xlo->xlo_number); if (IS_ERR(xlo->worker_task)) return -ENOMEM; set_user_nice(xlo->worker_task, MIN_NICE); @@ -699,8 +669,7 @@ static void xloop_update_rotational(struct xloop_device *xlo) blk_queue_flag_clear(QUEUE_FLAG_NONROT, q); } -static int -xloop_release_xfer(struct xloop_device *xlo) +static int xloop_release_xfer(struct xloop_device *xlo) { int err = 0; struct xloop_func_table *xfer = xlo->xlo_encryption; @@ -715,9 +684,7 @@ xloop_release_xfer(struct xloop_device *xlo) return err; } -static int -xloop_init_xfer(struct xloop_device *xlo, struct xloop_func_table *xfer, - const struct xloop_info64 *i) +static int xloop_init_xfer(struct xloop_device *xlo, struct xloop_func_table *xfer, const struct xloop_info64 *i) { int err = 0; @@ -744,15 +711,13 @@ xloop_init_xfer(struct xloop_device *xlo, struct xloop_func_table *xfer, * Configures the xloop device parameters according to the passed * in xloop_info64 configuration. */ -static int -xloop_set_status_from_info(struct xloop_device *xlo, - const struct xloop_info64 *info) +static int xloop_set_status_from_info(struct xloop_device *xlo, const struct xloop_info64 *info) { int err; struct xloop_func_table *xfer; kuid_t uid = current_uid(); - if ((unsigned int) info->xlo_encrypt_key_size > XLO_KEY_SIZE) + if ((unsigned int)info->xlo_encrypt_key_size > XLO_KEY_SIZE) return -EINVAL; err = xloop_release_xfer(xlo); @@ -778,8 +743,8 @@ xloop_set_status_from_info(struct xloop_device *xlo, xlo->xlo_sizelimit = info->xlo_sizelimit; memcpy(xlo->xlo_file_name, info->xlo_file_name, XLO_NAME_SIZE); memcpy(xlo->xlo_crypt_name, info->xlo_crypt_name, XLO_NAME_SIZE); - xlo->xlo_file_name[XLO_NAME_SIZE-1] = 0; - xlo->xlo_crypt_name[XLO_NAME_SIZE-1] = 0; + xlo->xlo_file_name[XLO_NAME_SIZE - 1] = 0; + xlo->xlo_crypt_name[XLO_NAME_SIZE - 1] = 0; if (!xfer) xfer = &none_funcs; @@ -792,28 +757,26 @@ xloop_set_status_from_info(struct xloop_device *xlo, xlo->xlo_init[0] = info->xlo_init[0]; xlo->xlo_init[1] = info->xlo_init[1]; if (info->xlo_encrypt_key_size) { - memcpy(xlo->xlo_encrypt_key, info->xlo_encrypt_key, - info->xlo_encrypt_key_size); + memcpy(xlo->xlo_encrypt_key, info->xlo_encrypt_key, info->xlo_encrypt_key_size); xlo->xlo_key_owner = uid; } return 0; } -static int xloop_configure(struct xloop_device *xlo, fmode_t mode, - struct block_device *bdev, - const struct xloop_config *config) +static int xloop_configure(struct xloop_device *xlo, fmode_t mode, struct block_device *bdev, + const struct xloop_config *config) { - struct file *file; - struct inode *inode; + struct file *file; + struct inode *inode; struct address_space *mapping; #if LINUX_VERSION_CODE >= KERNEL_VERSION(5, 2, 0) struct block_device *claimed_bdev = NULL; #endif - int error; - loff_t size; - bool partscan; - unsigned short bsize; + int error; + loff_t size; + bool partscan; + unsigned short bsize; /* This is safe, since we have a reference from open(). */ __module_get(THIS_MODULE); @@ -877,8 +840,7 @@ static int xloop_configure(struct xloop_device *xlo, fmode_t mode, if (error) goto out_unlock; - if (!(file->f_mode & FMODE_WRITE) || !(mode & FMODE_WRITE) || - !file->f_op->write_iter) + if (!(file->f_mode & FMODE_WRITE) || !(mode & FMODE_WRITE) || !file->f_op->write_iter) xlo->xlo_flags |= XLO_FLAGS_READ_ONLY; error = xloop_prepare_queue(xlo); @@ -891,10 +853,9 @@ static int xloop_configure(struct xloop_device *xlo, fmode_t mode, xlo->xlo_device = bdev; xlo->xlo_backing_file = file; xlo->old_gfp_mask = mapping_gfp_mask(mapping); - mapping_set_gfp_mask(mapping, xlo->old_gfp_mask & ~(__GFP_IO|__GFP_FS)); + mapping_set_gfp_mask(mapping, xlo->old_gfp_mask & ~(__GFP_IO | __GFP_FS)); - error = xloop_file_fmt_init(xlo->xlo_fmt, - config->info.xlo_file_fmt_type); + error = xloop_file_fmt_init(xlo->xlo_fmt, config->info.xlo_file_fmt_type); if (error) goto out_unlock; @@ -920,8 +881,7 @@ static int xloop_configure(struct xloop_device *xlo, fmode_t mode, size = get_xloop_size(xlo, file); xloop_set_size(xlo, size); - set_blocksize(bdev, S_ISBLK(inode->i_mode) ? - block_size(inode->i_bdev) : PAGE_SIZE); + set_blocksize(bdev, S_ISBLK(inode->i_mode) ? block_size(inode->i_bdev) : PAGE_SIZE); xlo->xlo_state = Xlo_bound; if (part_shift) @@ -1043,8 +1003,7 @@ out_unlock: * must be at least one and it can only become zero when the * current holder is released. */ -#if LINUX_VERSION_CODE >= KERNEL_VERSION(5, 5, 0) || \ - RHEL_CHECK_VERSION(RHEL_RELEASE_CODE >= RHEL_RELEASE_VERSION(8, 3)) +#if LINUX_VERSION_CODE >= KERNEL_VERSION(5, 5, 0) || RHEL_CHECK_VERSION(RHEL_RELEASE_VERSION(8, 3) <= RHEL_RELEASE_CODE) if (!release) mutex_lock(&bdev->bd_mutex); err = bdev_disk_changed(bdev, false); @@ -1056,8 +1015,8 @@ out_unlock: mutex_unlock(&bdev->bd_mutex); #endif if (err) - dev_warn(xloop_device_to_dev(xlo), "partition scan failed " - "(rc=%d)\n", err); + dev_warn(xloop_device_to_dev(xlo), "partition scan failed (rc=%d)\n", err); + /* Device is gone, no point in returning error */ err = 0; } @@ -1121,8 +1080,7 @@ static int xloop_clr_fd(struct xloop_device *xlo) return __xloop_clr_fd(xlo, false); } -static int -xloop_set_status(struct xloop_device *xlo, const struct xloop_info64 *info) +static int xloop_set_status(struct xloop_device *xlo, const struct xloop_info64 *info) { int err; struct block_device *bdev; @@ -1134,9 +1092,7 @@ xloop_set_status(struct xloop_device *xlo, const struct xloop_info64 *info) err = mutex_lock_killable(&xloop_ctl_mutex); if (err) return err; - if (xlo->xlo_encrypt_key_size && - !uid_eq(xlo->xlo_key_owner, uid) && - !capable(CAP_SYS_ADMIN)) { + if (xlo->xlo_encrypt_key_size && !uid_eq(xlo->xlo_key_owner, uid) && !capable(CAP_SYS_ADMIN)) { err = -EPERM; goto out_unlock; } @@ -1145,8 +1101,7 @@ xloop_set_status(struct xloop_device *xlo, const struct xloop_info64 *info) goto out_unlock; } - if (xlo->xlo_offset != info->xlo_offset || - xlo->xlo_sizelimit != info->xlo_sizelimit) { + if (xlo->xlo_offset != info->xlo_offset || xlo->xlo_sizelimit != info->xlo_sizelimit) { size_changed = true; sync_blockdev(xlo->xlo_device); invalidate_bdev(xlo->xlo_device); @@ -1158,9 +1113,9 @@ xloop_set_status(struct xloop_device *xlo, const struct xloop_info64 *info) if (size_changed && xlo->xlo_device->bd_inode->i_mapping->nrpages) { /* If any pages were dirtied after invalidate_bdev(), try again */ err = -EAGAIN; - dev_warn(xloop_device_to_dev(xlo), "xloop device has still dirty " - "pages (nrpages=%lu)\n", - xlo->xlo_device->bd_inode->i_mapping->nrpages); + dev_warn(xloop_device_to_dev(xlo), + "xloop device has still dirty pages (nrpages=%lu)\n", + xlo->xlo_device->bd_inode->i_mapping->nrpages); goto out_unfreeze; } @@ -1183,13 +1138,13 @@ xloop_set_status(struct xloop_device *xlo, const struct xloop_info64 *info) if (err) goto out_unfreeze; - /* After change of the file format, recalculate the capacity of - * the loop device. */ + /* After change of the file format, recalculate the capacity of the xloop device. */ size_changed = true; } if (size_changed) { loff_t new_size = get_xloop_size(xlo, xlo->xlo_backing_file); + xloop_set_size(xlo, new_size); } @@ -1201,8 +1156,7 @@ xloop_set_status(struct xloop_device *xlo, const struct xloop_info64 *info) out_unfreeze: blk_mq_unfreeze_queue(xlo->xlo_queue); - if (!err && (xlo->xlo_flags & XLO_FLAGS_PARTSCAN) && - !(prev_xlo_flags & XLO_FLAGS_PARTSCAN)) { + if (!err && (xlo->xlo_flags & XLO_FLAGS_PARTSCAN) && !(prev_xlo_flags & XLO_FLAGS_PARTSCAN)) { xlo->xlo_disk->flags &= ~GENHD_FL_NO_PART_SCAN; bdev = xlo->xlo_device; partscan = true; @@ -1215,8 +1169,7 @@ out_unlock: return err; } -static int -xloop_get_status(struct xloop_device *xlo, struct xloop_info64 *info) +static int xloop_get_status(struct xloop_device *xlo, struct xloop_info64 *info) { struct path path; struct kstat stat; @@ -1237,12 +1190,10 @@ xloop_get_status(struct xloop_device *xlo, struct xloop_info64 *info) info->xlo_flags = xlo->xlo_flags; memcpy(info->xlo_file_name, xlo->xlo_file_name, XLO_NAME_SIZE); memcpy(info->xlo_crypt_name, xlo->xlo_crypt_name, XLO_NAME_SIZE); - info->xlo_encrypt_type = - xlo->xlo_encryption ? xlo->xlo_encryption->number : 0; + info->xlo_encrypt_type = xlo->xlo_encryption ? xlo->xlo_encryption->number : 0; if (xlo->xlo_encrypt_key_size && capable(CAP_SYS_ADMIN)) { info->xlo_encrypt_key_size = xlo->xlo_encrypt_key_size; - memcpy(info->xlo_encrypt_key, xlo->xlo_encrypt_key, - xlo->xlo_encrypt_key_size); + memcpy(info->xlo_encrypt_key, xlo->xlo_encrypt_key, xlo->xlo_encrypt_key_size); } /* Drop xloop_ctl_mutex while we call into the filesystem. */ @@ -1259,8 +1210,7 @@ xloop_get_status(struct xloop_device *xlo, struct xloop_info64 *info) return ret; } -static void -xloop_info64_from_old(const struct xloop_info *info, struct xloop_info64 *info64) +static void xloop_info64_from_old(const struct xloop_info *info, struct xloop_info64 *info64) { memset(info64, 0, sizeof(*info64)); info64->xlo_number = info->xlo_number; @@ -1282,8 +1232,7 @@ xloop_info64_from_old(const struct xloop_info *info, struct xloop_info64 *info64 memcpy(info64->xlo_encrypt_key, info->xlo_encrypt_key, XLO_KEY_SIZE); } -static int -xloop_info64_to_old(const struct xloop_info64 *info64, struct xloop_info *info) +static int xloop_info64_to_old(const struct xloop_info64 *info64, struct xloop_info *info) { memset(info, 0, sizeof(*info)); info->xlo_number = info64->xlo_number; @@ -1304,39 +1253,35 @@ xloop_info64_to_old(const struct xloop_info64 *info64, struct xloop_info *info) memcpy(info->xlo_encrypt_key, info64->xlo_encrypt_key, XLO_KEY_SIZE); /* error in case values were truncated */ - if (info->xlo_device != info64->xlo_device || - info->xlo_rdevice != info64->xlo_rdevice || - info->xlo_inode != info64->xlo_inode || - info->xlo_offset != info64->xlo_offset) + if (info->xlo_device != info64->xlo_device || info->xlo_rdevice != info64->xlo_rdevice || + info->xlo_inode != info64->xlo_inode || info->xlo_offset != info64->xlo_offset) return -EOVERFLOW; return 0; } -static int -xloop_set_status_old(struct xloop_device *xlo, const struct xloop_info __user *arg) +static int xloop_set_status_old(struct xloop_device *xlo, const struct xloop_info __user *arg) { struct xloop_info info; struct xloop_info64 info64; - if (copy_from_user(&info, arg, sizeof (struct xloop_info))) + if (copy_from_user(&info, arg, sizeof(struct xloop_info))) return -EFAULT; xloop_info64_from_old(&info, &info64); return xloop_set_status(xlo, &info64); } -static int -xloop_set_status64(struct xloop_device *xlo, const struct xloop_info64 __user *arg) +static int xloop_set_status64(struct xloop_device *xlo, const struct xloop_info64 __user *arg) { struct xloop_info64 info64; - if (copy_from_user(&info64, arg, sizeof (struct xloop_info64))) + if (copy_from_user(&info64, arg, sizeof(struct xloop_info64))) return -EFAULT; return xloop_set_status(xlo, &info64); } -static int -xloop_get_status_old(struct xloop_device *xlo, struct xloop_info __user *arg) { +static int xloop_get_status_old(struct xloop_device *xlo, struct xloop_info __user *arg) +{ struct xloop_info info; struct xloop_info64 info64; int err; @@ -1352,8 +1297,8 @@ xloop_get_status_old(struct xloop_device *xlo, struct xloop_info __user *arg) { return err; } -static int -xloop_get_status64(struct xloop_device *xlo, struct xloop_info64 __user *arg) { +static int xloop_get_status64(struct xloop_device *xlo, struct xloop_info64 __user *arg) +{ struct xloop_info64 info64; int err; @@ -1382,6 +1327,7 @@ static int xloop_set_capacity(struct xloop_device *xlo) static int xloop_set_dio(struct xloop_device *xlo, unsigned long arg) { int error = -ENXIO; + if (xlo->xlo_state != Xlo_bound) goto out; @@ -1389,7 +1335,7 @@ static int xloop_set_dio(struct xloop_device *xlo, unsigned long arg) if (xlo->use_dio == !!arg) return 0; error = -EINVAL; - out: +out: return error; } @@ -1415,9 +1361,9 @@ static int xloop_set_block_size(struct xloop_device *xlo, unsigned long arg) /* invalidate_bdev should have truncated all the pages */ if (xlo->xlo_device->bd_inode->i_mapping->nrpages) { err = -EAGAIN; - dev_warn(xloop_device_to_dev(xlo), "xloop device has still dirty " - "pages (nrpages=%lu)\n", - xlo->xlo_device->bd_inode->i_mapping->nrpages); + dev_warn(xloop_device_to_dev(xlo), + "xloop device has still dirty pages (nrpages=%lu)\n", + xlo->xlo_device->bd_inode->i_mapping->nrpages); goto out_unfreeze; } @@ -1431,8 +1377,7 @@ out_unfreeze: return err; } -static int xlo_simple_ioctl(struct xloop_device *xlo, unsigned int cmd, - unsigned long arg) +static int xlo_simple_ioctl(struct xloop_device *xlo, unsigned int cmd, unsigned long arg) { int err; @@ -1456,11 +1401,10 @@ static int xlo_simple_ioctl(struct xloop_device *xlo, unsigned int cmd, return err; } -static int xlo_ioctl(struct block_device *bdev, fmode_t mode, - unsigned int cmd, unsigned long arg) +static int xlo_ioctl(struct block_device *bdev, fmode_t mode, unsigned int cmd, unsigned long arg) { struct xloop_device *xlo = bdev->bd_disk->private_data; - void __user *argp = (void __user *) arg; + void __user *argp = (void __user *)arg; int err; switch (cmd) { @@ -1491,17 +1435,15 @@ static int xlo_ioctl(struct block_device *bdev, fmode_t mode, return xloop_clr_fd(xlo); case XLOOP_SET_STATUS: err = -EPERM; - if ((mode & FMODE_WRITE) || capable(CAP_SYS_ADMIN)) { + if ((mode & FMODE_WRITE) || capable(CAP_SYS_ADMIN)) err = xloop_set_status_old(xlo, argp); - } break; case XLOOP_GET_STATUS: return xloop_get_status_old(xlo, argp); case XLOOP_SET_STATUS64: err = -EPERM; - if ((mode & FMODE_WRITE) || capable(CAP_SYS_ADMIN)) { + if ((mode & FMODE_WRITE) || capable(CAP_SYS_ADMIN)) err = xloop_set_status64(xlo, argp); - } break; case XLOOP_GET_STATUS64: return xloop_get_status64(xlo, argp); @@ -1513,7 +1455,7 @@ static int xlo_ioctl(struct block_device *bdev, fmode_t mode, #if LINUX_VERSION_CODE >= KERNEL_VERSION(5, 4, 0) fallthrough; #else - /* fall through */ + /* fall through */ #endif default: err = xlo_simple_ioctl(xlo, cmd, arg); @@ -1525,28 +1467,26 @@ static int xlo_ioctl(struct block_device *bdev, fmode_t mode, #ifdef CONFIG_COMPAT struct compat_xloop_info { - compat_int_t xlo_number; /* ioctl r/o */ - compat_dev_t xlo_device; /* ioctl r/o */ - compat_ulong_t xlo_inode; /* ioctl r/o */ - compat_dev_t xlo_rdevice; /* ioctl r/o */ - compat_int_t xlo_offset; - compat_int_t xlo_encrypt_type; - compat_int_t xlo_encrypt_key_size; /* ioctl w/o */ - compat_int_t xlo_flags; /* ioctl r/o */ - char xlo_name[XLO_NAME_SIZE]; - unsigned char xlo_encrypt_key[XLO_KEY_SIZE]; /* ioctl w/o */ - compat_ulong_t xlo_init[2]; - char reserved[4]; - compat_int_t xlo_file_fmt_type; + compat_int_t xlo_number; /* ioctl r/o */ + compat_dev_t xlo_device; /* ioctl r/o */ + compat_ulong_t xlo_inode; /* ioctl r/o */ + compat_dev_t xlo_rdevice; /* ioctl r/o */ + compat_int_t xlo_offset; + compat_int_t xlo_encrypt_type; + compat_int_t xlo_encrypt_key_size; /* ioctl w/o */ + compat_int_t xlo_flags; /* ioctl r/o */ + char xlo_name[XLO_NAME_SIZE]; + unsigned char xlo_encrypt_key[XLO_KEY_SIZE]; /* ioctl w/o */ + compat_ulong_t xlo_init[2]; + char reserved[4]; + compat_int_t xlo_file_fmt_type; }; /* * Transfer 32-bit compatibility structure in userspace to 64-bit xloop info * - noinlined to reduce stack space usage in main part of driver */ -static noinline int -xloop_info64_from_compat(const struct compat_xloop_info __user *arg, - struct xloop_info64 *info64) +static noinline int xloop_info64_from_compat(const struct compat_xloop_info __user *arg, struct xloop_info64 *info64) { struct compat_xloop_info info; @@ -1578,9 +1518,7 @@ xloop_info64_from_compat(const struct compat_xloop_info __user *arg, * Transfer 64-bit xloop info to 32-bit compatibility structure in userspace * - noinlined to reduce stack space usage in main part of driver */ -static noinline int -xloop_info64_to_compat(const struct xloop_info64 *info64, - struct compat_xloop_info __user *arg) +static noinline int xloop_info64_to_compat(const struct xloop_info64 *info64, struct compat_xloop_info __user *arg) { struct compat_xloop_info info; @@ -1603,13 +1541,10 @@ xloop_info64_to_compat(const struct xloop_info64 *info64, memcpy(info.xlo_encrypt_key, info64->xlo_encrypt_key, XLO_KEY_SIZE); /* error in case values were truncated */ - if (info.xlo_device != info64->xlo_device || - info.xlo_rdevice != info64->xlo_rdevice || - info.xlo_inode != info64->xlo_inode || - info.xlo_offset != info64->xlo_offset || - info.xlo_init[0] != info64->xlo_init[0] || - info.xlo_init[1] != info64->xlo_init[1] || - info.xlo_file_fmt_type != info64->xlo_file_fmt_type) + if (info.xlo_device != info64->xlo_device || info.xlo_rdevice != info64->xlo_rdevice || + info.xlo_inode != info64->xlo_inode || info.xlo_offset != info64->xlo_offset || + info.xlo_init[0] != info64->xlo_init[0] || info.xlo_init[1] != info64->xlo_init[1] || + info.xlo_file_fmt_type != info64->xlo_file_fmt_type) return -EOVERFLOW; if (copy_to_user(arg, &info, sizeof(info))) @@ -1617,9 +1552,7 @@ xloop_info64_to_compat(const struct xloop_info64 *info64, return 0; } -static int -xloop_set_status_compat(struct xloop_device *xlo, - const struct compat_xloop_info __user *arg) +static int xloop_set_status_compat(struct xloop_device *xlo, const struct compat_xloop_info __user *arg) { struct xloop_info64 info64; int ret; @@ -1630,9 +1563,7 @@ xloop_set_status_compat(struct xloop_device *xlo, return xloop_set_status(xlo, &info64); } -static int -xloop_get_status_compat(struct xloop_device *xlo, - struct compat_xloop_info __user *arg) +static int xloop_get_status_compat(struct xloop_device *xlo, struct compat_xloop_info __user *arg) { struct xloop_info64 info64; int err; @@ -1645,27 +1576,24 @@ xloop_get_status_compat(struct xloop_device *xlo, return err; } -static int xlo_compat_ioctl(struct block_device *bdev, fmode_t mode, - unsigned int cmd, unsigned long arg) +static int xlo_compat_ioctl(struct block_device *bdev, fmode_t mode, unsigned int cmd, unsigned long arg) { struct xloop_device *xlo = bdev->bd_disk->private_data; int err; - switch(cmd) { + switch (cmd) { case XLOOP_SET_STATUS: - err = xloop_set_status_compat(xlo, - (const struct compat_xloop_info __user *)arg); + err = xloop_set_status_compat(xlo, (const struct compat_xloop_info __user *)arg); break; case XLOOP_GET_STATUS: - err = xloop_get_status_compat(xlo, - (struct compat_xloop_info __user *)arg); + err = xloop_get_status_compat(xlo, (struct compat_xloop_info __user *)arg); break; case XLOOP_SET_CAPACITY: case XLOOP_CLR_FD: case XLOOP_GET_STATUS64: case XLOOP_SET_STATUS64: case XLOOP_CONFIGURE: - arg = (unsigned long) compat_ptr(arg); + arg = (unsigned long)compat_ptr(arg); #if LINUX_VERSION_CODE >= KERNEL_VERSION(5, 4, 0) fallthrough; #else @@ -1739,12 +1667,12 @@ out_unlock: } static const struct block_device_operations xlo_fops = { - .owner = THIS_MODULE, - .open = xlo_open, - .release = xlo_release, - .ioctl = xlo_ioctl, + .owner = THIS_MODULE, + .open = xlo_open, + .release = xlo_release, + .ioctl = xlo_ioctl, #ifdef CONFIG_COMPAT - .compat_ioctl = xlo_compat_ioctl, + .compat_ioctl = xlo_compat_ioctl, #endif }; @@ -1770,6 +1698,7 @@ int xloop_register_transfer(struct xloop_func_table *funcs) xfer_funcs[n] = funcs; return 0; } +EXPORT_SYMBOL(xloop_register_transfer); static int unregister_transfer_cb(int id, void *ptr, void *data) { @@ -1788,19 +1717,18 @@ int xloop_unregister_transfer(int number) unsigned int n = number; struct xloop_func_table *xfer; - if (n == 0 || n >= MAX_XLO_CRYPT || (xfer = xfer_funcs[n]) == NULL) + xfer = xfer_funcs[n]; + + if (n == 0 || n >= MAX_XLO_CRYPT || xfer == NULL) return -EINVAL; xfer_funcs[n] = NULL; idr_for_each(&xloop_index_idr, &unregister_transfer_cb, xfer); return 0; } - -EXPORT_SYMBOL(xloop_register_transfer); EXPORT_SYMBOL(xloop_unregister_transfer); -static blk_status_t xloop_queue_rq(struct blk_mq_hw_ctx *hctx, - const struct blk_mq_queue_data *bd) +static blk_status_t xloop_queue_rq(struct blk_mq_hw_ctx *hctx, const struct blk_mq_queue_data *bd) { struct request *rq = bd->rq; struct xloop_cmd *cmd = blk_mq_rq_to_pdu(rq); @@ -1848,7 +1776,7 @@ static void xloop_handle_cmd(struct xloop_cmd *cmd) } ret = do_req_filebacked(xlo, rq); - failed: +failed: /* complete non-aio request */ if (!cmd->use_aio || ret) { if (ret == -EOPNOTSUPP) @@ -1866,14 +1794,13 @@ static void xloop_handle_cmd(struct xloop_cmd *cmd) static void xloop_queue_work(struct kthread_work *work) { - struct xloop_cmd *cmd = - container_of(work, struct xloop_cmd, work); + struct xloop_cmd *cmd = container_of(work, struct xloop_cmd, work); xloop_handle_cmd(cmd); } -static int xloop_init_request(struct blk_mq_tag_set *set, struct request *rq, - unsigned int hctx_idx, unsigned int numa_node) +static int xloop_init_request(struct blk_mq_tag_set *set, struct request *rq, unsigned int hctx_idx, + unsigned int numa_node) { struct xloop_cmd *cmd = blk_mq_rq_to_pdu(rq); @@ -1882,9 +1809,9 @@ static int xloop_init_request(struct blk_mq_tag_set *set, struct request *rq, } static const struct blk_mq_ops xloop_mq_ops = { - .queue_rq = xloop_queue_rq, + .queue_rq = xloop_queue_rq, .init_request = xloop_init_request, - .complete = xlo_complete_rq, + .complete = xlo_complete_rq, }; static struct dentry *xloop_dbgfs_dir; @@ -1982,21 +1909,24 @@ static int xloop_add(struct xloop_device **l, int i) disk->flags |= GENHD_FL_NO_PART_SCAN; disk->flags |= GENHD_FL_EXT_DEVT; atomic_set(&xlo->xlo_refcnt, 0); - xlo->xlo_number = i; + xlo->xlo_number = i; spin_lock_init(&xlo->xlo_lock); - disk->major = XLOOP_MAJOR; - disk->first_minor = i << part_shift; - disk->fops = &xlo_fops; - disk->private_data = xlo; - disk->queue = xlo->xlo_queue; + disk->major = XLOOP_MAJOR; + disk->first_minor = i << part_shift; + disk->fops = &xlo_fops; + disk->private_data = xlo; + disk->queue = xlo->xlo_queue; sprintf(disk->disk_name, "xloop%d", i); add_disk(disk); *l = xlo; - /* initialize debugfs entries */ - /* create for each loop device a debugfs directory under 'loop' if + /* + * initialize debugfs entries + * + * create for each loop device a debugfs directory under 'loop' if * the 'block' directory exists, otherwise create the loop directory in - * the root directory */ + * the root directory + */ #ifdef CONFIG_DEBUG_FS xlo->xlo_dbgfs_dir = debugfs_create_dir(disk->disk_name, xloop_dbgfs_dir); @@ -2092,8 +2022,7 @@ static struct kobject *xloop_probe(dev_t dev, int *part, void *data) return kobj; } -static long xloop_control_ioctl(struct file *file, unsigned int cmd, - unsigned long parm) +static long xloop_control_ioctl(struct file *file, unsigned int cmd, unsigned long parm) { struct xloop_device *xlo; int ret; @@ -2102,7 +2031,7 @@ static long xloop_control_ioctl(struct file *file, unsigned int cmd, if (ret) return ret; - ret = -ENOSYS; + ret = -EINVAL; switch (cmd) { case XLOOP_CTL_ADD: ret = xloop_lookup(&xlo, parm); @@ -2140,17 +2069,17 @@ static long xloop_control_ioctl(struct file *file, unsigned int cmd, } static const struct file_operations xloop_ctl_fops = { - .open = nonseekable_open, - .unlocked_ioctl = xloop_control_ioctl, - .compat_ioctl = xloop_control_ioctl, - .owner = THIS_MODULE, - .llseek = noop_llseek, + .open = nonseekable_open, + .unlocked_ioctl = xloop_control_ioctl, + .compat_ioctl = xloop_control_ioctl, + .owner = THIS_MODULE, + .llseek = noop_llseek, }; static struct miscdevice xloop_misc = { - .minor = XLOOP_CTRL_MINOR, - .name = "xloop-control", - .fops = &xloop_ctl_fops, + .minor = XLOOP_CTRL_MINOR, + .name = "xloop-control", + .fops = &xloop_ctl_fops, }; MODULE_ALIAS_MISCDEV(XLOOP_CTRL_MINOR); @@ -2205,7 +2134,6 @@ static int __init xloop_init(void) if (err < 0) goto err_out; - if (register_blkdev(XLOOP_MAJOR, "xloop")) { err = -EIO; goto misc_out; @@ -2219,8 +2147,7 @@ static int __init xloop_init(void) } #endif - blk_register_region(MKDEV(XLOOP_MAJOR, 0), range, - THIS_MODULE, xloop_probe, NULL, NULL); + blk_register_region(MKDEV(XLOOP_MAJOR, 0), range, THIS_MODULE, xloop_probe, NULL, NULL); /* pre-create number of devices given by config or max_xloop */ mutex_lock(&xloop_ctl_mutex); diff --git a/src/kernel/xloop_main.h b/src/kernel/xloop_main.h index e1b4cb6..97c2654 100644 --- a/src/kernel/xloop_main.h +++ b/src/kernel/xloop_main.h @@ -1,3 +1,4 @@ +/* SPDX-License-Identifier: GPL-2.0 */ /* * loop_main.h * @@ -32,76 +33,72 @@ enum { struct xloop_func_table; struct xloop_device { - int xlo_number; - atomic_t xlo_refcnt; - loff_t xlo_offset; - loff_t xlo_sizelimit; - int xlo_flags; - int (*transfer)(struct xloop_device *, int cmd, - struct page *raw_page, unsigned raw_off, - struct page *xloop_page, unsigned xloop_off, - int size, sector_t real_block); - char xlo_file_name[XLO_NAME_SIZE]; - char xlo_crypt_name[XLO_NAME_SIZE]; - char xlo_encrypt_key[XLO_KEY_SIZE]; - int xlo_encrypt_key_size; + int xlo_number; + atomic_t xlo_refcnt; + loff_t xlo_offset; + loff_t xlo_sizelimit; + int xlo_flags; + int (*transfer)(struct xloop_device *xlo, int cmd, struct page *raw_page, + unsigned int raw_off, struct page *xloop_page, unsigned int xloop_off, + int size, sector_t real_block); + char xlo_file_name[XLO_NAME_SIZE]; + char xlo_crypt_name[XLO_NAME_SIZE]; + char xlo_encrypt_key[XLO_KEY_SIZE]; + int xlo_encrypt_key_size; struct xloop_func_table *xlo_encryption; - __u32 xlo_init[2]; - kuid_t xlo_key_owner; /* Who set the key */ - int (*ioctl)(struct xloop_device *, int cmd, - unsigned long arg); + __u32 xlo_init[2]; + kuid_t xlo_key_owner; /* Who set the key */ + int (*ioctl)(struct xloop_device *xlo, int cmd, unsigned long arg); - struct xloop_file_fmt *xlo_fmt; + struct xloop_file_fmt *xlo_fmt; - struct file * xlo_backing_file; - struct block_device *xlo_device; - void *key_data; + struct file *xlo_backing_file; + struct block_device *xlo_device; + void *key_data; - gfp_t old_gfp_mask; + gfp_t old_gfp_mask; - spinlock_t xlo_lock; - int xlo_state; - struct kthread_worker worker; - struct task_struct *worker_task; - bool use_dio; - bool sysfs_inited; + spinlock_t xlo_lock; + int xlo_state; + struct kthread_worker worker; + struct task_struct *worker_task; + bool use_dio; + bool sysfs_inited; - struct request_queue *xlo_queue; - struct blk_mq_tag_set tag_set; - struct gendisk *xlo_disk; + struct request_queue *xlo_queue; + struct blk_mq_tag_set tag_set; + struct gendisk *xlo_disk; #ifdef CONFIG_DEBUG_FS - struct dentry *xlo_dbgfs_dir; + struct dentry *xlo_dbgfs_dir; #endif }; struct xloop_cmd { - struct kthread_work work; - bool use_aio; /* use AIO interface to handle I/O */ - atomic_t ref; /* only for aio */ - long ret; - struct kiocb iocb; - struct bio_vec *bvec; + struct kthread_work work; + bool use_aio; /* use AIO interface to handle I/O */ + atomic_t ref; /* only for aio */ + long ret; + struct kiocb iocb; + struct bio_vec *bvec; struct cgroup_subsys_state *css; }; /* Support for loadable transfer modules */ struct xloop_func_table { - int number; /* filter type */ - int (*transfer)(struct xloop_device *xlo, int cmd, - struct page *raw_page, unsigned raw_off, - struct page *xloop_page, unsigned xloop_off, - int size, sector_t real_block); - int (*init)(struct xloop_device *, const struct xloop_info64 *); + int number; /* filter type */ + int (*transfer)(struct xloop_device *xlo, int cmd, struct page *raw_page, unsigned int raw_off, + struct page *xloop_page, unsigned int xloop_off, int size, sector_t real_block); + int (*init)(struct xloop_device *xlo, const struct xloop_info64 *info); /* release is called from xloop_unregister_transfer or clr_fd */ - int (*release)(struct xloop_device *); - int (*ioctl)(struct xloop_device *, int cmd, unsigned long arg); + int (*release)(struct xloop_device *xlo); + int (*ioctl)(struct xloop_device *xlo, int cmd, unsigned long arg); struct module *owner; -}; +}; extern inline struct device *xloop_device_to_dev(struct xloop_device *xlo); int xloop_register_transfer(struct xloop_func_table *funcs); -int xloop_unregister_transfer(int number); +int xloop_unregister_transfer(int number); #endif |