Merge tag 'for-5.6/io_uring-vfs-2020-01-29' of git://git.kernel.dk/linux-block
[linux-2.6-microblaze.git] / crypto / scompress.c
index 6f8305f..738f4f8 100644 (file)
@@ -1,15 +1,10 @@
+// SPDX-License-Identifier: GPL-2.0-or-later
 /*
  * Synchronous Compression operations
  *
  * Copyright 2015 LG Electronics Inc.
  * Copyright (c) 2016, Intel Corporation
  * Author: Giovanni Cabiddu <giovanni.cabiddu@intel.com>
- *
- * This program is free software; you can redistribute it and/or modify it
- * under the terms of the GNU General Public License as published by the Free
- * Software Foundation; either version 2 of the License, or (at your option)
- * any later version.
- *
  */
 #include <linux/errno.h>
 #include <linux/kernel.h>
 #include <crypto/internal/scompress.h>
 #include "internal.h"
 
+struct scomp_scratch {
+       spinlock_t      lock;
+       void            *src;
+       void            *dst;
+};
+
+static DEFINE_PER_CPU(struct scomp_scratch, scomp_scratch) = {
+       .lock = __SPIN_LOCK_UNLOCKED(scomp_scratch.lock),
+};
+
 static const struct crypto_type crypto_scomp_type;
-static void * __percpu *scomp_src_scratches;
-static void * __percpu *scomp_dst_scratches;
 static int scomp_scratch_users;
 static DEFINE_MUTEX(scomp_lock);
 
@@ -62,76 +65,53 @@ static void crypto_scomp_show(struct seq_file *m, struct crypto_alg *alg)
        seq_puts(m, "type         : scomp\n");
 }
 
-static void crypto_scomp_free_scratches(void * __percpu *scratches)
+static void crypto_scomp_free_scratches(void)
 {
+       struct scomp_scratch *scratch;
        int i;
 
-       if (!scratches)
-               return;
-
-       for_each_possible_cpu(i)
-               vfree(*per_cpu_ptr(scratches, i));
+       for_each_possible_cpu(i) {
+               scratch = per_cpu_ptr(&scomp_scratch, i);
 
-       free_percpu(scratches);
+               vfree(scratch->src);
+               vfree(scratch->dst);
+               scratch->src = NULL;
+               scratch->dst = NULL;
+       }
 }
 
-static void * __percpu *crypto_scomp_alloc_scratches(void)
+static int crypto_scomp_alloc_scratches(void)
 {
-       void * __percpu *scratches;
+       struct scomp_scratch *scratch;
        int i;
 
-       scratches = alloc_percpu(void *);
-       if (!scratches)
-               return NULL;
-
        for_each_possible_cpu(i) {
-               void *scratch;
-
-               scratch = vmalloc_node(SCOMP_SCRATCH_SIZE, cpu_to_node(i));
-               if (!scratch)
-                       goto error;
-               *per_cpu_ptr(scratches, i) = scratch;
-       }
-
-       return scratches;
+               void *mem;
 
-error:
-       crypto_scomp_free_scratches(scratches);
-       return NULL;
-}
-
-static void crypto_scomp_free_all_scratches(void)
-{
-       if (!--scomp_scratch_users) {
-               crypto_scomp_free_scratches(scomp_src_scratches);
-               crypto_scomp_free_scratches(scomp_dst_scratches);
-               scomp_src_scratches = NULL;
-               scomp_dst_scratches = NULL;
-       }
-}
+               scratch = per_cpu_ptr(&scomp_scratch, i);
 
-static int crypto_scomp_alloc_all_scratches(void)
-{
-       if (!scomp_scratch_users++) {
-               scomp_src_scratches = crypto_scomp_alloc_scratches();
-               if (!scomp_src_scratches)
-                       return -ENOMEM;
-               scomp_dst_scratches = crypto_scomp_alloc_scratches();
-               if (!scomp_dst_scratches) {
-                       crypto_scomp_free_scratches(scomp_src_scratches);
-                       scomp_src_scratches = NULL;
-                       return -ENOMEM;
-               }
+               mem = vmalloc_node(SCOMP_SCRATCH_SIZE, cpu_to_node(i));
+               if (!mem)
+                       goto error;
+               scratch->src = mem;
+               mem = vmalloc_node(SCOMP_SCRATCH_SIZE, cpu_to_node(i));
+               if (!mem)
+                       goto error;
+               scratch->dst = mem;
        }
        return 0;
+error:
+       crypto_scomp_free_scratches();
+       return -ENOMEM;
 }
 
 static int crypto_scomp_init_tfm(struct crypto_tfm *tfm)
 {
-       int ret;
+       int ret = 0;
 
        mutex_lock(&scomp_lock);
-       ret = crypto_scomp_alloc_all_scratches();
+       if (!scomp_scratch_users++)
+               ret = crypto_scomp_alloc_scratches();
        mutex_unlock(&scomp_lock);
 
        return ret;
@@ -143,42 +123,41 @@ static int scomp_acomp_comp_decomp(struct acomp_req *req, int dir)
        void **tfm_ctx = acomp_tfm_ctx(tfm);
        struct crypto_scomp *scomp = *tfm_ctx;
        void **ctx = acomp_request_ctx(req);
-       const int cpu = get_cpu();
-       u8 *scratch_src = *per_cpu_ptr(scomp_src_scratches, cpu);
-       u8 *scratch_dst = *per_cpu_ptr(scomp_dst_scratches, cpu);
+       struct scomp_scratch *scratch;
        int ret;
 
-       if (!req->src || !req->slen || req->slen > SCOMP_SCRATCH_SIZE) {
-               ret = -EINVAL;
-               goto out;
-       }
+       if (!req->src || !req->slen || req->slen > SCOMP_SCRATCH_SIZE)
+               return -EINVAL;
 
-       if (req->dst && !req->dlen) {
-               ret = -EINVAL;
-               goto out;
-       }
+       if (req->dst && !req->dlen)
+               return -EINVAL;
 
        if (!req->dlen || req->dlen > SCOMP_SCRATCH_SIZE)
                req->dlen = SCOMP_SCRATCH_SIZE;
 
-       scatterwalk_map_and_copy(scratch_src, req->src, 0, req->slen, 0);
+       scratch = raw_cpu_ptr(&scomp_scratch);
+       spin_lock(&scratch->lock);
+
+       scatterwalk_map_and_copy(scratch->src, req->src, 0, req->slen, 0);
        if (dir)
-               ret = crypto_scomp_compress(scomp, scratch_src, req->slen,
-                                           scratch_dst, &req->dlen, *ctx);
+               ret = crypto_scomp_compress(scomp, scratch->src, req->slen,
+                                           scratch->dst, &req->dlen, *ctx);
        else
-               ret = crypto_scomp_decompress(scomp, scratch_src, req->slen,
-                                             scratch_dst, &req->dlen, *ctx);
+               ret = crypto_scomp_decompress(scomp, scratch->src, req->slen,
+                                             scratch->dst, &req->dlen, *ctx);
        if (!ret) {
                if (!req->dst) {
                        req->dst = sgl_alloc(req->dlen, GFP_ATOMIC, NULL);
-                       if (!req->dst)
+                       if (!req->dst) {
+                               ret = -ENOMEM;
                                goto out;
+                       }
                }
-               scatterwalk_map_and_copy(scratch_dst, req->dst, 0, req->dlen,
+               scatterwalk_map_and_copy(scratch->dst, req->dst, 0, req->dlen,
                                         1);
        }
 out:
-       put_cpu();
+       spin_unlock(&scratch->lock);
        return ret;
 }
 
@@ -199,7 +178,8 @@ static void crypto_exit_scomp_ops_async(struct crypto_tfm *tfm)
        crypto_free_scomp(*ctx);
 
        mutex_lock(&scomp_lock);
-       crypto_scomp_free_all_scratches();
+       if (!--scomp_scratch_users)
+               crypto_scomp_free_scratches();
        mutex_unlock(&scomp_lock);
 }
 
@@ -286,9 +266,9 @@ int crypto_register_scomp(struct scomp_alg *alg)
 }
 EXPORT_SYMBOL_GPL(crypto_register_scomp);
 
-int crypto_unregister_scomp(struct scomp_alg *alg)
+void crypto_unregister_scomp(struct scomp_alg *alg)
 {
-       return crypto_unregister_alg(&alg->base);
+       crypto_unregister_alg(&alg->base);
 }
 EXPORT_SYMBOL_GPL(crypto_unregister_scomp);