114c5024dSHans Petter Selasky /*- 214c5024dSHans Petter Selasky * Copyright (c) 2017 Mellanox Technologies, Ltd. 314c5024dSHans Petter Selasky * All rights reserved. 414c5024dSHans Petter Selasky * 514c5024dSHans Petter Selasky * Redistribution and use in source and binary forms, with or without 614c5024dSHans Petter Selasky * modification, are permitted provided that the following conditions 714c5024dSHans Petter Selasky * are met: 814c5024dSHans Petter Selasky * 1. Redistributions of source code must retain the above copyright 914c5024dSHans Petter Selasky * notice unmodified, this list of conditions, and the following 1014c5024dSHans Petter Selasky * disclaimer. 1114c5024dSHans Petter Selasky * 2. Redistributions in binary form must reproduce the above copyright 1214c5024dSHans Petter Selasky * notice, this list of conditions and the following disclaimer in the 1314c5024dSHans Petter Selasky * documentation and/or other materials provided with the distribution. 1414c5024dSHans Petter Selasky * 1514c5024dSHans Petter Selasky * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR 1614c5024dSHans Petter Selasky * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES 1714c5024dSHans Petter Selasky * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. 1814c5024dSHans Petter Selasky * IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT, 1914c5024dSHans Petter Selasky * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT 2014c5024dSHans Petter Selasky * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, 2114c5024dSHans Petter Selasky * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY 2214c5024dSHans Petter Selasky * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT 2314c5024dSHans Petter Selasky * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF 2414c5024dSHans Petter Selasky * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. 2514c5024dSHans Petter Selasky */ 2614c5024dSHans Petter Selasky 2714c5024dSHans Petter Selasky #include <sys/cdefs.h> 2814c5024dSHans Petter Selasky __FBSDID("$FreeBSD$"); 2914c5024dSHans Petter Selasky 3014c5024dSHans Petter Selasky #include <linux/slab.h> 3114c5024dSHans Petter Selasky #include <linux/rcupdate.h> 3214c5024dSHans Petter Selasky #include <linux/kernel.h> 3314c5024dSHans Petter Selasky 3414c5024dSHans Petter Selasky struct linux_kmem_rcu { 3514c5024dSHans Petter Selasky struct rcu_head rcu_head; 3614c5024dSHans Petter Selasky struct linux_kmem_cache *cache; 3714c5024dSHans Petter Selasky }; 3814c5024dSHans Petter Selasky 3914c5024dSHans Petter Selasky #define LINUX_KMEM_TO_RCU(c, m) \ 4014c5024dSHans Petter Selasky ((struct linux_kmem_rcu *)((char *)(m) + \ 4114c5024dSHans Petter Selasky (c)->cache_size - sizeof(struct linux_kmem_rcu))) 4214c5024dSHans Petter Selasky 4314c5024dSHans Petter Selasky #define LINUX_RCU_TO_KMEM(r) \ 4414c5024dSHans Petter Selasky ((void *)((char *)(r) + sizeof(struct linux_kmem_rcu) - \ 4514c5024dSHans Petter Selasky (r)->cache->cache_size)) 4614c5024dSHans Petter Selasky 4714c5024dSHans Petter Selasky static int 4814c5024dSHans Petter Selasky linux_kmem_ctor(void *mem, int size, void *arg, int flags) 4914c5024dSHans Petter Selasky { 5014c5024dSHans Petter Selasky struct linux_kmem_cache *c = arg; 5114c5024dSHans Petter Selasky 52*782a90d1SHans Petter Selasky if (unlikely(c->cache_flags & SLAB_TYPESAFE_BY_RCU)) { 5314c5024dSHans Petter Selasky struct linux_kmem_rcu *rcu = LINUX_KMEM_TO_RCU(c, mem); 5414c5024dSHans Petter Selasky 5514c5024dSHans Petter Selasky /* duplicate cache pointer */ 5614c5024dSHans Petter Selasky rcu->cache = c; 5714c5024dSHans Petter Selasky } 5814c5024dSHans Petter Selasky 5914c5024dSHans Petter Selasky /* check for constructor */ 6014c5024dSHans Petter Selasky if (likely(c->cache_ctor != NULL)) 6114c5024dSHans Petter Selasky c->cache_ctor(mem); 6214c5024dSHans Petter Selasky 6314c5024dSHans Petter Selasky return (0); 6414c5024dSHans Petter Selasky } 6514c5024dSHans Petter Selasky 6614c5024dSHans Petter Selasky static void 6714c5024dSHans Petter Selasky linux_kmem_cache_free_rcu_callback(struct rcu_head *head) 6814c5024dSHans Petter Selasky { 6914c5024dSHans Petter Selasky struct linux_kmem_rcu *rcu = 7014c5024dSHans Petter Selasky container_of(head, struct linux_kmem_rcu, rcu_head); 7114c5024dSHans Petter Selasky 7214c5024dSHans Petter Selasky uma_zfree(rcu->cache->cache_zone, LINUX_RCU_TO_KMEM(rcu)); 7314c5024dSHans Petter Selasky } 7414c5024dSHans Petter Selasky 7514c5024dSHans Petter Selasky struct linux_kmem_cache * 7614c5024dSHans Petter Selasky linux_kmem_cache_create(const char *name, size_t size, size_t align, 7714c5024dSHans Petter Selasky unsigned flags, linux_kmem_ctor_t *ctor) 7814c5024dSHans Petter Selasky { 7914c5024dSHans Petter Selasky struct linux_kmem_cache *c; 8014c5024dSHans Petter Selasky 8114c5024dSHans Petter Selasky c = malloc(sizeof(*c), M_KMALLOC, M_WAITOK); 8214c5024dSHans Petter Selasky 8314c5024dSHans Petter Selasky if (flags & SLAB_HWCACHE_ALIGN) 8414c5024dSHans Petter Selasky align = UMA_ALIGN_CACHE; 8514c5024dSHans Petter Selasky else if (align != 0) 8614c5024dSHans Petter Selasky align--; 8714c5024dSHans Petter Selasky 88*782a90d1SHans Petter Selasky if (flags & SLAB_TYPESAFE_BY_RCU) { 8914c5024dSHans Petter Selasky /* make room for RCU structure */ 9014c5024dSHans Petter Selasky size = ALIGN(size, sizeof(void *)); 9114c5024dSHans Petter Selasky size += sizeof(struct linux_kmem_rcu); 9214c5024dSHans Petter Selasky 9314c5024dSHans Petter Selasky /* create cache_zone */ 9414c5024dSHans Petter Selasky c->cache_zone = uma_zcreate(name, size, 9514c5024dSHans Petter Selasky linux_kmem_ctor, NULL, NULL, NULL, 9614c5024dSHans Petter Selasky align, UMA_ZONE_ZINIT); 9714c5024dSHans Petter Selasky } else { 9814c5024dSHans Petter Selasky /* create cache_zone */ 9914c5024dSHans Petter Selasky c->cache_zone = uma_zcreate(name, size, 10014c5024dSHans Petter Selasky ctor ? linux_kmem_ctor : NULL, NULL, 10114c5024dSHans Petter Selasky NULL, NULL, align, 0); 10214c5024dSHans Petter Selasky } 10314c5024dSHans Petter Selasky 10414c5024dSHans Petter Selasky c->cache_flags = flags; 10514c5024dSHans Petter Selasky c->cache_ctor = ctor; 10614c5024dSHans Petter Selasky c->cache_size = size; 10714c5024dSHans Petter Selasky return (c); 10814c5024dSHans Petter Selasky } 10914c5024dSHans Petter Selasky 11014c5024dSHans Petter Selasky void 11114c5024dSHans Petter Selasky linux_kmem_cache_free_rcu(struct linux_kmem_cache *c, void *m) 11214c5024dSHans Petter Selasky { 11314c5024dSHans Petter Selasky struct linux_kmem_rcu *rcu = LINUX_KMEM_TO_RCU(c, m); 11414c5024dSHans Petter Selasky 11514c5024dSHans Petter Selasky call_rcu(&rcu->rcu_head, linux_kmem_cache_free_rcu_callback); 11614c5024dSHans Petter Selasky } 11714c5024dSHans Petter Selasky 11814c5024dSHans Petter Selasky void 11914c5024dSHans Petter Selasky linux_kmem_cache_destroy(struct linux_kmem_cache *c) 12014c5024dSHans Petter Selasky { 121*782a90d1SHans Petter Selasky if (unlikely(c->cache_flags & SLAB_TYPESAFE_BY_RCU)) { 12214c5024dSHans Petter Selasky /* make sure all free callbacks have been called */ 12314c5024dSHans Petter Selasky rcu_barrier(); 12414c5024dSHans Petter Selasky } 12514c5024dSHans Petter Selasky 12614c5024dSHans Petter Selasky uma_zdestroy(c->cache_zone); 12714c5024dSHans Petter Selasky free(c, M_KMALLOC); 12814c5024dSHans Petter Selasky } 129