1*14c5024dSHans Petter Selasky /*- 2*14c5024dSHans Petter Selasky * Copyright (c) 2017 Mellanox Technologies, Ltd. 3*14c5024dSHans Petter Selasky * All rights reserved. 4*14c5024dSHans Petter Selasky * 5*14c5024dSHans Petter Selasky * Redistribution and use in source and binary forms, with or without 6*14c5024dSHans Petter Selasky * modification, are permitted provided that the following conditions 7*14c5024dSHans Petter Selasky * are met: 8*14c5024dSHans Petter Selasky * 1. Redistributions of source code must retain the above copyright 9*14c5024dSHans Petter Selasky * notice unmodified, this list of conditions, and the following 10*14c5024dSHans Petter Selasky * disclaimer. 11*14c5024dSHans Petter Selasky * 2. Redistributions in binary form must reproduce the above copyright 12*14c5024dSHans Petter Selasky * notice, this list of conditions and the following disclaimer in the 13*14c5024dSHans Petter Selasky * documentation and/or other materials provided with the distribution. 14*14c5024dSHans Petter Selasky * 15*14c5024dSHans Petter Selasky * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR 16*14c5024dSHans Petter Selasky * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES 17*14c5024dSHans Petter Selasky * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. 18*14c5024dSHans Petter Selasky * IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT, 19*14c5024dSHans Petter Selasky * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT 20*14c5024dSHans Petter Selasky * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, 21*14c5024dSHans Petter Selasky * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY 22*14c5024dSHans Petter Selasky * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT 23*14c5024dSHans Petter Selasky * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF 24*14c5024dSHans Petter Selasky * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. 25*14c5024dSHans Petter Selasky */ 26*14c5024dSHans Petter Selasky 27*14c5024dSHans Petter Selasky #include <sys/cdefs.h> 28*14c5024dSHans Petter Selasky __FBSDID("$FreeBSD$"); 29*14c5024dSHans Petter Selasky 30*14c5024dSHans Petter Selasky #include <linux/slab.h> 31*14c5024dSHans Petter Selasky #include <linux/rcupdate.h> 32*14c5024dSHans Petter Selasky #include <linux/kernel.h> 33*14c5024dSHans Petter Selasky 34*14c5024dSHans Petter Selasky struct linux_kmem_rcu { 35*14c5024dSHans Petter Selasky struct rcu_head rcu_head; 36*14c5024dSHans Petter Selasky struct linux_kmem_cache *cache; 37*14c5024dSHans Petter Selasky }; 38*14c5024dSHans Petter Selasky 39*14c5024dSHans Petter Selasky #define LINUX_KMEM_TO_RCU(c, m) \ 40*14c5024dSHans Petter Selasky ((struct linux_kmem_rcu *)((char *)(m) + \ 41*14c5024dSHans Petter Selasky (c)->cache_size - sizeof(struct linux_kmem_rcu))) 42*14c5024dSHans Petter Selasky 43*14c5024dSHans Petter Selasky #define LINUX_RCU_TO_KMEM(r) \ 44*14c5024dSHans Petter Selasky ((void *)((char *)(r) + sizeof(struct linux_kmem_rcu) - \ 45*14c5024dSHans Petter Selasky (r)->cache->cache_size)) 46*14c5024dSHans Petter Selasky 47*14c5024dSHans Petter Selasky static int 48*14c5024dSHans Petter Selasky linux_kmem_ctor(void *mem, int size, void *arg, int flags) 49*14c5024dSHans Petter Selasky { 50*14c5024dSHans Petter Selasky struct linux_kmem_cache *c = arg; 51*14c5024dSHans Petter Selasky 52*14c5024dSHans Petter Selasky if (unlikely(c->cache_flags & SLAB_DESTROY_BY_RCU)) { 53*14c5024dSHans Petter Selasky struct linux_kmem_rcu *rcu = LINUX_KMEM_TO_RCU(c, mem); 54*14c5024dSHans Petter Selasky 55*14c5024dSHans Petter Selasky /* duplicate cache pointer */ 56*14c5024dSHans Petter Selasky rcu->cache = c; 57*14c5024dSHans Petter Selasky } 58*14c5024dSHans Petter Selasky 59*14c5024dSHans Petter Selasky /* check for constructor */ 60*14c5024dSHans Petter Selasky if (likely(c->cache_ctor != NULL)) 61*14c5024dSHans Petter Selasky c->cache_ctor(mem); 62*14c5024dSHans Petter Selasky 63*14c5024dSHans Petter Selasky return (0); 64*14c5024dSHans Petter Selasky } 65*14c5024dSHans Petter Selasky 66*14c5024dSHans Petter Selasky static void 67*14c5024dSHans Petter Selasky linux_kmem_cache_free_rcu_callback(struct rcu_head *head) 68*14c5024dSHans Petter Selasky { 69*14c5024dSHans Petter Selasky struct linux_kmem_rcu *rcu = 70*14c5024dSHans Petter Selasky container_of(head, struct linux_kmem_rcu, rcu_head); 71*14c5024dSHans Petter Selasky 72*14c5024dSHans Petter Selasky uma_zfree(rcu->cache->cache_zone, LINUX_RCU_TO_KMEM(rcu)); 73*14c5024dSHans Petter Selasky } 74*14c5024dSHans Petter Selasky 75*14c5024dSHans Petter Selasky struct linux_kmem_cache * 76*14c5024dSHans Petter Selasky linux_kmem_cache_create(const char *name, size_t size, size_t align, 77*14c5024dSHans Petter Selasky unsigned flags, linux_kmem_ctor_t *ctor) 78*14c5024dSHans Petter Selasky { 79*14c5024dSHans Petter Selasky struct linux_kmem_cache *c; 80*14c5024dSHans Petter Selasky 81*14c5024dSHans Petter Selasky c = malloc(sizeof(*c), M_KMALLOC, M_WAITOK); 82*14c5024dSHans Petter Selasky 83*14c5024dSHans Petter Selasky if (flags & SLAB_HWCACHE_ALIGN) 84*14c5024dSHans Petter Selasky align = UMA_ALIGN_CACHE; 85*14c5024dSHans Petter Selasky else if (align != 0) 86*14c5024dSHans Petter Selasky align--; 87*14c5024dSHans Petter Selasky 88*14c5024dSHans Petter Selasky if (flags & SLAB_DESTROY_BY_RCU) { 89*14c5024dSHans Petter Selasky /* make room for RCU structure */ 90*14c5024dSHans Petter Selasky size = ALIGN(size, sizeof(void *)); 91*14c5024dSHans Petter Selasky size += sizeof(struct linux_kmem_rcu); 92*14c5024dSHans Petter Selasky 93*14c5024dSHans Petter Selasky /* create cache_zone */ 94*14c5024dSHans Petter Selasky c->cache_zone = uma_zcreate(name, size, 95*14c5024dSHans Petter Selasky linux_kmem_ctor, NULL, NULL, NULL, 96*14c5024dSHans Petter Selasky align, UMA_ZONE_ZINIT); 97*14c5024dSHans Petter Selasky } else { 98*14c5024dSHans Petter Selasky /* create cache_zone */ 99*14c5024dSHans Petter Selasky c->cache_zone = uma_zcreate(name, size, 100*14c5024dSHans Petter Selasky ctor ? linux_kmem_ctor : NULL, NULL, 101*14c5024dSHans Petter Selasky NULL, NULL, align, 0); 102*14c5024dSHans Petter Selasky } 103*14c5024dSHans Petter Selasky 104*14c5024dSHans Petter Selasky c->cache_flags = flags; 105*14c5024dSHans Petter Selasky c->cache_ctor = ctor; 106*14c5024dSHans Petter Selasky c->cache_size = size; 107*14c5024dSHans Petter Selasky return (c); 108*14c5024dSHans Petter Selasky } 109*14c5024dSHans Petter Selasky 110*14c5024dSHans Petter Selasky void 111*14c5024dSHans Petter Selasky linux_kmem_cache_free_rcu(struct linux_kmem_cache *c, void *m) 112*14c5024dSHans Petter Selasky { 113*14c5024dSHans Petter Selasky struct linux_kmem_rcu *rcu = LINUX_KMEM_TO_RCU(c, m); 114*14c5024dSHans Petter Selasky 115*14c5024dSHans Petter Selasky call_rcu(&rcu->rcu_head, linux_kmem_cache_free_rcu_callback); 116*14c5024dSHans Petter Selasky } 117*14c5024dSHans Petter Selasky 118*14c5024dSHans Petter Selasky void 119*14c5024dSHans Petter Selasky linux_kmem_cache_destroy(struct linux_kmem_cache *c) 120*14c5024dSHans Petter Selasky { 121*14c5024dSHans Petter Selasky if (unlikely(c->cache_flags & SLAB_DESTROY_BY_RCU)) { 122*14c5024dSHans Petter Selasky /* make sure all free callbacks have been called */ 123*14c5024dSHans Petter Selasky rcu_barrier(); 124*14c5024dSHans Petter Selasky } 125*14c5024dSHans Petter Selasky 126*14c5024dSHans Petter Selasky uma_zdestroy(c->cache_zone); 127*14c5024dSHans Petter Selasky free(c, M_KMALLOC); 128*14c5024dSHans Petter Selasky } 129