Besides the already special cased non-transform fastpath there are only two different transfers. Hardcode them instead of the maze of indirect calls and switch the whole cryptoloop code to use IS_ENABLED for dead code elimination. Signed-off-by: Christoph Hellwig <hch@xxxxxx> --- drivers/block/loop.c | 146 +++++++++++-------------------------------- drivers/block/loop.h | 21 ++----- 2 files changed, 41 insertions(+), 126 deletions(-) diff --git a/drivers/block/loop.c b/drivers/block/loop.c index 45c7e88b0aff..6ee4b046bdcc 100644 --- a/drivers/block/loop.c +++ b/drivers/block/loop.c @@ -140,7 +140,7 @@ static void loop_global_unlock(struct loop_device *lo, bool global) static int max_part; static int part_shift; -static int transfer_xor(struct loop_device *lo, int cmd, +static void xor_transfer(struct loop_device *lo, int cmd, struct page *raw_page, unsigned raw_off, struct page *loop_page, unsigned loop_off, int size, sector_t real_block) @@ -166,27 +166,14 @@ static int transfer_xor(struct loop_device *lo, int cmd, kunmap_atomic(loop_buf); kunmap_atomic(raw_buf); cond_resched(); - return 0; } -static int xor_init(struct loop_device *lo, const struct loop_info64 *info) +static inline bool is_cryptoloop(int encrypt_type) { - if (unlikely(info->lo_encrypt_key_size <= 0)) - return -EINVAL; - return 0; + return IS_ENABLED(CONFIG_BLK_DEV_CRYPTOLOOP) && + encrypt_type == LO_CRYPT_CRYPTOAPI; } -static struct loop_func_table none_funcs = { - .number = LO_CRYPT_NONE, -}; - -static struct loop_func_table xor_funcs = { - .number = LO_CRYPT_XOR, - .transfer = transfer_xor, - .init = xor_init -}; - -#ifdef CONFIG_BLK_DEV_CRYPTOLOOP static int cryptoloop_init(struct loop_device *lo, const struct loop_info64 *info) { @@ -235,7 +222,7 @@ static int cryptoloop_init(struct loop_device *lo, info->lo_encrypt_key_size); if (err != 0) goto out_free_tfm; - lo->key_data = tfm; + lo->lo_encrypt_tfm = tfm; return 0; out_free_tfm: @@ -249,7 +236,7 @@ static int cryptoloop_transfer(struct loop_device *lo, int cmd, struct page *raw_page, unsigned raw_off, struct page *loop_page, unsigned loop_off, int size, sector_t IV) { - struct crypto_sync_skcipher *tfm = lo->key_data; + struct crypto_sync_skcipher *tfm = lo->lo_encrypt_tfm; SYNC_SKCIPHER_REQUEST_ON_STACK(req, tfm); struct scatterlist sg_out; struct scatterlist sg_in; @@ -300,32 +287,11 @@ static int cryptoloop_transfer(struct loop_device *lo, int cmd, err = 0; out: skcipher_request_zero(req); + pr_err_ratelimited("loop: Transfer error at byte offset %llu, length %i.\n", + IV << 9, size); return err; } -static void cryptoloop_release(struct loop_device *lo) -{ - crypto_free_sync_skcipher(lo->key_data); - lo->key_data = NULL; -} - -static struct loop_func_table cryptoloop_funcs = { - .number = LO_CRYPT_CRYPTOAPI, - .init = cryptoloop_init, - .transfer = cryptoloop_transfer, - .release = cryptoloop_release, -}; -#endif /* CONFIG_BLK_DEV_CRYPTOLOOP */ - -/* xfer_funcs[0] is special - its release function is never called */ -static struct loop_func_table *xfer_funcs[MAX_LO_CRYPT] = { - [LO_CRYPT_NONE] = &none_funcs, - [LO_CRYPT_XOR] = &xor_funcs, -#ifdef CONFIG_BLK_DEV_CRYPTOLOOP - [LO_CRYPT_CRYPTOAPI] = &cryptoloop_funcs, -#endif -}; - static loff_t get_size(loff_t offset, loff_t sizelimit, struct file *file) { loff_t loopsize; @@ -380,7 +346,7 @@ static void __loop_update_dio(struct loop_device *lo, bool dio) if (queue_logical_block_size(lo->lo_queue) >= sb_bsize && !(lo->lo_offset & dio_align) && mapping->a_ops->direct_IO && - !lo->transfer) + !lo->lo_encrypt_type) use_dio = true; else use_dio = false; @@ -446,16 +412,11 @@ lo_do_transfer(struct loop_device *lo, int cmd, struct page *lpage, unsigned loffs, int size, sector_t rblock) { - int ret; - - ret = lo->transfer(lo, cmd, rpage, roffs, lpage, loffs, size, rblock); - if (likely(!ret)) - return 0; - - printk_ratelimited(KERN_ERR - "loop: Transfer error at byte offset %llu, length %i.\n", - (unsigned long long)rblock << 9, size); - return ret; + if (is_cryptoloop(lo->lo_encrypt_type)) + return cryptoloop_transfer(lo, cmd, rpage, roffs, lpage, loffs, + size, rblock); + xor_transfer(lo, cmd, rpage, roffs, lpage, loffs, size, rblock); + return 0; } static int lo_write_bvec(struct file *file, struct bio_vec *bvec, loff_t *ppos) @@ -801,14 +762,14 @@ static int do_req_filebacked(struct loop_device *lo, struct request *rq) case REQ_OP_DISCARD: return lo_fallocate(lo, rq, pos, FALLOC_FL_PUNCH_HOLE); case REQ_OP_WRITE: - if (lo->transfer) + if (lo->lo_encrypt_type) return lo_write_transfer(lo, rq, pos); else if (cmd->use_aio) return lo_rw_aio(lo, cmd, pos, WRITE); else return lo_write_simple(lo, rq, pos); case REQ_OP_READ: - if (lo->transfer) + if (lo->lo_encrypt_type) return lo_read_transfer(lo, rq, pos); else if (cmd->use_aio) return lo_rw_aio(lo, cmd, pos, READ); @@ -1225,33 +1186,6 @@ static void loop_update_rotational(struct loop_device *lo) blk_queue_flag_clear(QUEUE_FLAG_NONROT, q); } -static void -loop_release_xfer(struct loop_device *lo) -{ - struct loop_func_table *xfer = lo->lo_encryption; - - if (xfer) { - if (xfer->release) - xfer->release(lo); - lo->transfer = NULL; - lo->lo_encryption = NULL; - } -} - -static int -loop_init_xfer(struct loop_device *lo, struct loop_func_table *xfer, - const struct loop_info64 *i) -{ - int err = 0; - - if (xfer && xfer->init) { - err = xfer->init(lo, i); - if (!err) - lo->lo_encryption = xfer; - } - return err; -} - /** * loop_set_status_from_info - configure device from loop_info * @lo: struct loop_device to configure @@ -1265,29 +1199,28 @@ loop_set_status_from_info(struct loop_device *lo, const struct loop_info64 *info) { int err; - struct loop_func_table *xfer; kuid_t uid = current_uid(); if ((unsigned int) info->lo_encrypt_key_size > LO_KEY_SIZE) return -EINVAL; - loop_release_xfer(lo); - - if (info->lo_encrypt_type) { - unsigned int type = info->lo_encrypt_type; + if (is_cryptoloop(lo->lo_encrypt_type)) + crypto_free_sync_skcipher(lo->lo_encrypt_tfm); + lo->lo_encrypt_tfm = NULL; - if (type >= MAX_LO_CRYPT) + if (info->lo_encrypt_type == LO_CRYPT_XOR) { + if (info->lo_encrypt_key_size <= 0) return -EINVAL; - xfer = xfer_funcs[type]; - if (xfer == NULL) + } else if (is_cryptoloop(info->lo_encrypt_type)) { + err = cryptoloop_init(lo, info); + if (err) + return err; + } else { + if (info->lo_encrypt_type != LO_CRYPT_NONE) return -EINVAL; - } else - xfer = NULL; - - err = loop_init_xfer(lo, xfer, info); - if (err) - return err; + } + lo->lo_encrypt_type = info->lo_encrypt_type; lo->lo_offset = info->lo_offset; lo->lo_sizelimit = info->lo_sizelimit; memcpy(lo->lo_file_name, info->lo_file_name, LO_NAME_SIZE); @@ -1295,10 +1228,6 @@ loop_set_status_from_info(struct loop_device *lo, lo->lo_file_name[LO_NAME_SIZE-1] = 0; lo->lo_crypt_name[LO_NAME_SIZE-1] = 0; - if (!xfer) - xfer = &none_funcs; - lo->transfer = xfer->transfer; - lo->lo_flags = info->lo_flags; lo->lo_encrypt_key_size = info->lo_encrypt_key_size; @@ -1509,10 +1438,10 @@ static int __loop_clr_fd(struct loop_device *lo, bool release) lo->lo_backing_file = NULL; spin_unlock_irq(&lo->lo_lock); - loop_release_xfer(lo); - lo->transfer = NULL; + if (is_cryptoloop(lo->lo_encrypt_type)) + crypto_free_sync_skcipher(lo->lo_encrypt_tfm); + lo->lo_encrypt_tfm = NULL; lo->lo_device = NULL; - lo->lo_encryption = NULL; lo->lo_offset = 0; lo->lo_sizelimit = 0; lo->lo_encrypt_key_size = 0; @@ -1725,8 +1654,7 @@ loop_get_status(struct loop_device *lo, struct loop_info64 *info) info->lo_flags = lo->lo_flags; memcpy(info->lo_file_name, lo->lo_file_name, LO_NAME_SIZE); memcpy(info->lo_crypt_name, lo->lo_crypt_name, LO_NAME_SIZE); - info->lo_encrypt_type = - lo->lo_encryption ? lo->lo_encryption->number : 0; + info->lo_encrypt_type = lo->lo_encrypt_type; if (lo->lo_encrypt_key_size && capable(CAP_SYS_ADMIN)) { info->lo_encrypt_key_size = lo->lo_encrypt_key_size; memcpy(info->lo_encrypt_key, lo->lo_encrypt_key, @@ -1762,7 +1690,7 @@ loop_info64_from_old(const struct loop_info *info, struct loop_info64 *info64) info64->lo_flags = info->lo_flags; info64->lo_init[0] = info->lo_init[0]; info64->lo_init[1] = info->lo_init[1]; - if (info->lo_encrypt_type == LO_CRYPT_CRYPTOAPI) + if (is_cryptoloop(info->lo_encrypt_type)) memcpy(info64->lo_crypt_name, info->lo_name, LO_NAME_SIZE); else memcpy(info64->lo_file_name, info->lo_name, LO_NAME_SIZE); @@ -1783,7 +1711,7 @@ loop_info64_to_old(const struct loop_info64 *info64, struct loop_info *info) info->lo_flags = info64->lo_flags; info->lo_init[0] = info64->lo_init[0]; info->lo_init[1] = info64->lo_init[1]; - if (info->lo_encrypt_type == LO_CRYPT_CRYPTOAPI) + if (is_cryptoloop(info->lo_encrypt_type)) memcpy(info->lo_name, info64->lo_crypt_name, LO_NAME_SIZE); else memcpy(info->lo_name, info64->lo_file_name, LO_NAME_SIZE); @@ -2046,7 +1974,7 @@ loop_info64_from_compat(const struct compat_loop_info __user *arg, info64->lo_flags = info.lo_flags; info64->lo_init[0] = info.lo_init[0]; info64->lo_init[1] = info.lo_init[1]; - if (info.lo_encrypt_type == LO_CRYPT_CRYPTOAPI) + if (is_cryptoloop(info.lo_encrypt_type)) memcpy(info64->lo_crypt_name, info.lo_name, LO_NAME_SIZE); else memcpy(info64->lo_file_name, info.lo_name, LO_NAME_SIZE); @@ -2075,7 +2003,7 @@ loop_info64_to_compat(const struct loop_info64 *info64, info.lo_flags = info64->lo_flags; info.lo_init[0] = info64->lo_init[0]; info.lo_init[1] = info64->lo_init[1]; - if (info.lo_encrypt_type == LO_CRYPT_CRYPTOAPI) + if (is_cryptoloop(info.lo_encrypt_type)) memcpy(info.lo_name, info64->lo_crypt_name, LO_NAME_SIZE); else memcpy(info.lo_name, info64->lo_file_name, LO_NAME_SIZE); diff --git a/drivers/block/loop.h b/drivers/block/loop.h index dd12d7f1ce30..d14ce6bdc014 100644 --- a/drivers/block/loop.h +++ b/drivers/block/loop.h @@ -16,6 +16,8 @@ #include <linux/mutex.h> #include <uapi/linux/loop.h> +struct crypto_sync_skcipher; + /* Possible states of device */ enum { Lo_unbound, @@ -32,21 +34,17 @@ struct loop_device { loff_t lo_offset; loff_t lo_sizelimit; int lo_flags; - int (*transfer)(struct loop_device *, int cmd, - struct page *raw_page, unsigned raw_off, - struct page *loop_page, unsigned loop_off, - int size, sector_t real_block); char lo_file_name[LO_NAME_SIZE]; char lo_crypt_name[LO_NAME_SIZE]; char lo_encrypt_key[LO_KEY_SIZE]; int lo_encrypt_key_size; - struct loop_func_table *lo_encryption; + int lo_encrypt_type; + struct crypto_sync_skcipher *lo_encrypt_tfm; __u32 lo_init[2]; kuid_t lo_key_owner; /* Who set the key */ struct file * lo_backing_file; struct block_device *lo_device; - void *key_data; gfp_t old_gfp_mask; @@ -79,15 +77,4 @@ struct loop_cmd { struct cgroup_subsys_state *memcg_css; }; -/* Support for loadable transfer modules */ -struct loop_func_table { - int number; /* filter type */ - int (*transfer)(struct loop_device *lo, int cmd, - struct page *raw_page, unsigned raw_off, - struct page *loop_page, unsigned loop_off, - int size, sector_t real_block); - int (*init)(struct loop_device *, const struct loop_info64 *); - void (*release)(struct loop_device *); -}; - #endif -- 2.30.2