Linux kernel mirror (for testing) git.kernel.org/pub/scm/linux/kernel/git/torvalds/linux.git
kernel os linux

crypto: acomp - Add ACOMP_REQUEST_ALLOC and acomp_request_alloc_extra

Add ACOMP_REQUEST_ALLOC which is a wrapper around acomp_request_alloc
that falls back to a synchronous stack reqeust if the allocation
fails.

Also add ACOMP_REQUEST_ON_STACK which stores the request on the stack
only.

The request should be freed with acomp_request_free.

Finally add acomp_request_alloc_extra which gives the user extra
memory to use in conjunction with the request.

Signed-off-by: Herbert Xu <herbert@gondor.apana.org.au>

+117 -8
+33 -5
crypto/acompress.c
··· 60 60 struct crypto_acomp *acomp = __crypto_acomp_tfm(tfm); 61 61 struct acomp_alg *alg = crypto_acomp_alg(acomp); 62 62 63 - alg->exit(acomp); 63 + if (alg->exit) 64 + alg->exit(acomp); 65 + 66 + if (acomp_is_async(acomp)) 67 + crypto_free_acomp(acomp->fb); 64 68 } 65 69 66 70 static int crypto_acomp_init_tfm(struct crypto_tfm *tfm) 67 71 { 68 72 struct crypto_acomp *acomp = __crypto_acomp_tfm(tfm); 69 73 struct acomp_alg *alg = crypto_acomp_alg(acomp); 74 + struct crypto_acomp *fb = NULL; 75 + int err; 76 + 77 + acomp->fb = acomp; 70 78 71 79 if (tfm->__crt_alg->cra_type != &crypto_acomp_type) 72 80 return crypto_init_scomp_ops_async(tfm); 81 + 82 + if (acomp_is_async(acomp)) { 83 + fb = crypto_alloc_acomp(crypto_acomp_alg_name(acomp), 0, 84 + CRYPTO_ALG_ASYNC); 85 + if (IS_ERR(fb)) 86 + return PTR_ERR(fb); 87 + 88 + err = -EINVAL; 89 + if (crypto_acomp_reqsize(fb) > MAX_SYNC_COMP_REQSIZE) 90 + goto out_free_fb; 91 + 92 + acomp->fb = fb; 93 + } 73 94 74 95 acomp->compress = alg->compress; 75 96 acomp->decompress = alg->decompress; 76 97 acomp->reqsize = alg->reqsize; 77 98 78 - if (alg->exit) 79 - acomp->base.exit = crypto_acomp_exit_tfm; 99 + acomp->base.exit = crypto_acomp_exit_tfm; 80 100 81 - if (alg->init) 82 - return alg->init(acomp); 101 + if (!alg->init) 102 + return 0; 103 + 104 + err = alg->init(acomp); 105 + if (err) 106 + goto out_free_fb; 83 107 84 108 return 0; 109 + 110 + out_free_fb: 111 + crypto_free_acomp(fb); 112 + return err; 85 113 } 86 114 87 115 static unsigned int crypto_acomp_extsize(struct crypto_alg *alg)
+77 -3
include/crypto/acompress.h
··· 10 10 #define _CRYPTO_ACOMP_H 11 11 12 12 #include <linux/atomic.h> 13 + #include <linux/args.h> 13 14 #include <linux/compiler_types.h> 14 15 #include <linux/container_of.h> 15 16 #include <linux/crypto.h> 17 + #include <linux/err.h> 16 18 #include <linux/scatterlist.h> 17 19 #include <linux/slab.h> 18 20 #include <linux/spinlock_types.h> ··· 33 31 #define CRYPTO_ACOMP_REQ_DST_NONDMA 0x00000010 34 32 35 33 #define CRYPTO_ACOMP_DST_MAX 131072 34 + 35 + #define MAX_SYNC_COMP_REQSIZE 0 36 + 37 + #define ACOMP_REQUEST_ALLOC(name, tfm, gfp) \ 38 + char __##name##_req[sizeof(struct acomp_req) + \ 39 + MAX_SYNC_COMP_REQSIZE] CRYPTO_MINALIGN_ATTR; \ 40 + struct acomp_req *name = acomp_request_on_stack_init( \ 41 + __##name##_req, (tfm), (gfp), false) 36 42 37 43 struct acomp_req; 38 44 ··· 93 83 * @compress: Function performs a compress operation 94 84 * @decompress: Function performs a de-compress operation 95 85 * @reqsize: Context size for (de)compression requests 86 + * @fb: Synchronous fallback tfm 96 87 * @base: Common crypto API algorithm data structure 97 88 */ 98 89 struct crypto_acomp { 99 90 int (*compress)(struct acomp_req *req); 100 91 int (*decompress)(struct acomp_req *req); 101 92 unsigned int reqsize; 93 + struct crypto_acomp *fb; 102 94 struct crypto_tfm base; 103 95 }; 104 96 ··· 222 210 return crypto_has_alg(alg_name, type, mask); 223 211 } 224 212 213 + static inline const char *crypto_acomp_alg_name(struct crypto_acomp *tfm) 214 + { 215 + return crypto_tfm_alg_name(crypto_acomp_tfm(tfm)); 216 + } 217 + 218 + static inline const char *crypto_acomp_driver_name(struct crypto_acomp *tfm) 219 + { 220 + return crypto_tfm_alg_driver_name(crypto_acomp_tfm(tfm)); 221 + } 222 + 225 223 /** 226 224 * acomp_request_alloc() -- allocates asynchronous (de)compression request 227 225 * 228 226 * @tfm: ACOMPRESS tfm handle allocated with crypto_alloc_acomp() 227 + * @gfp: gfp to pass to kzalloc (defaults to GFP_KERNEL) 229 228 * 230 229 * Return: allocated handle in case of success or NULL in case of an error 231 230 */ 232 - static inline struct acomp_req *acomp_request_alloc_noprof(struct crypto_acomp *tfm) 231 + static inline struct acomp_req *acomp_request_alloc_extra_noprof( 232 + struct crypto_acomp *tfm, size_t extra, gfp_t gfp) 233 233 { 234 234 struct acomp_req *req; 235 + size_t len; 235 236 236 - req = kzalloc_noprof(sizeof(*req) + crypto_acomp_reqsize(tfm), GFP_KERNEL); 237 + len = ALIGN(sizeof(*req) + crypto_acomp_reqsize(tfm), CRYPTO_MINALIGN); 238 + if (check_add_overflow(len, extra, &len)) 239 + return NULL; 240 + 241 + req = kzalloc_noprof(len, gfp); 237 242 if (likely(req)) 238 243 acomp_request_set_tfm(req, tfm); 239 244 return req; 240 245 } 246 + #define acomp_request_alloc_noprof(tfm, ...) \ 247 + CONCATENATE(acomp_request_alloc_noprof_, COUNT_ARGS(__VA_ARGS__))( \ 248 + tfm, ##__VA_ARGS__) 249 + #define acomp_request_alloc_noprof_0(tfm) \ 250 + acomp_request_alloc_noprof_1(tfm, GFP_KERNEL) 251 + #define acomp_request_alloc_noprof_1(tfm, gfp) \ 252 + acomp_request_alloc_extra_noprof(tfm, 0, gfp) 241 253 #define acomp_request_alloc(...) alloc_hooks(acomp_request_alloc_noprof(__VA_ARGS__)) 254 + 255 + /** 256 + * acomp_request_alloc_extra() -- allocate acomp request with extra memory 257 + * 258 + * @tfm: ACOMPRESS tfm handle allocated with crypto_alloc_acomp() 259 + * @extra: amount of extra memory 260 + * @gfp: gfp to pass to kzalloc 261 + * 262 + * Return: allocated handle in case of success or NULL in case of an error 263 + */ 264 + #define acomp_request_alloc_extra(...) alloc_hooks(acomp_request_alloc_extra_noprof(__VA_ARGS__)) 265 + 266 + static inline void *acomp_request_extra(struct acomp_req *req) 267 + { 268 + struct crypto_acomp *tfm = crypto_acomp_reqtfm(req); 269 + size_t len; 270 + 271 + len = ALIGN(sizeof(*req) + crypto_acomp_reqsize(tfm), CRYPTO_MINALIGN); 272 + return (void *)((char *)req + len); 273 + } 242 274 243 275 /** 244 276 * acomp_request_free() -- zeroize and free asynchronous (de)compression ··· 293 237 */ 294 238 static inline void acomp_request_free(struct acomp_req *req) 295 239 { 240 + if (!req || (req->base.flags & CRYPTO_TFM_REQ_ON_STACK)) 241 + return; 296 242 kfree_sensitive(req); 297 243 } 298 244 ··· 315 257 void *data) 316 258 { 317 259 u32 keep = CRYPTO_ACOMP_REQ_SRC_VIRT | CRYPTO_ACOMP_REQ_SRC_NONDMA | 318 - CRYPTO_ACOMP_REQ_DST_VIRT | CRYPTO_ACOMP_REQ_DST_NONDMA; 260 + CRYPTO_ACOMP_REQ_DST_VIRT | CRYPTO_ACOMP_REQ_DST_NONDMA | 261 + CRYPTO_TFM_REQ_ON_STACK; 319 262 320 263 req->base.complete = cmpl; 321 264 req->base.data = data; ··· 504 445 * Return: zero on success; error code in case of error 505 446 */ 506 447 int crypto_acomp_decompress(struct acomp_req *req); 448 + 449 + static inline struct acomp_req *acomp_request_on_stack_init( 450 + char *buf, struct crypto_acomp *tfm, gfp_t gfp, bool stackonly) 451 + { 452 + struct acomp_req *req; 453 + 454 + if (!stackonly && (req = acomp_request_alloc(tfm, gfp))) 455 + return req; 456 + 457 + req = (void *)buf; 458 + acomp_request_set_tfm(req, tfm->fb); 459 + req->base.flags = CRYPTO_TFM_REQ_ON_STACK; 460 + 461 + return req; 462 + } 507 463 508 464 #endif
+6
include/crypto/internal/acompress.h
··· 12 12 #include <crypto/acompress.h> 13 13 #include <crypto/algapi.h> 14 14 15 + #define ACOMP_REQUEST_ON_STACK(name, tfm) \ 16 + char __##name##_req[sizeof(struct acomp_req) + \ 17 + MAX_SYNC_COMP_REQSIZE] CRYPTO_MINALIGN_ATTR; \ 18 + struct acomp_req *name = acomp_request_on_stack_init( \ 19 + __##name##_req, (tfm), 0, true) 20 + 15 21 /** 16 22 * struct acomp_alg - asynchronous compression algorithm 17 23 *
+1
include/linux/crypto.h
··· 138 138 #define CRYPTO_TFM_REQ_FORBID_WEAK_KEYS 0x00000100 139 139 #define CRYPTO_TFM_REQ_MAY_SLEEP 0x00000200 140 140 #define CRYPTO_TFM_REQ_MAY_BACKLOG 0x00000400 141 + #define CRYPTO_TFM_REQ_ON_STACK 0x00000800 141 142 142 143 /* 143 144 * Miscellaneous stuff.