xref: /freebsd-src/sys/compat/linuxkpi/common/include/linux/kref.h (revision abb1a1340e3f0dcdbb81b5c42ad304f02c812e20)
18d59ecb2SHans Petter Selasky /*-
28d59ecb2SHans Petter Selasky  * Copyright (c) 2010 Isilon Systems, Inc.
38d59ecb2SHans Petter Selasky  * Copyright (c) 2010 iX Systems, Inc.
48d59ecb2SHans Petter Selasky  * Copyright (c) 2010 Panasas, Inc.
58d59ecb2SHans Petter Selasky  * Copyright (c) 2013-2015 Mellanox Technologies, Ltd.
68d59ecb2SHans Petter Selasky  * Copyright (c) 2013 François Tigeot
78d59ecb2SHans Petter Selasky  * All rights reserved.
88d59ecb2SHans Petter Selasky  *
98d59ecb2SHans Petter Selasky  * Redistribution and use in source and binary forms, with or without
108d59ecb2SHans Petter Selasky  * modification, are permitted provided that the following conditions
118d59ecb2SHans Petter Selasky  * are met:
128d59ecb2SHans Petter Selasky  * 1. Redistributions of source code must retain the above copyright
138d59ecb2SHans Petter Selasky  *    notice unmodified, this list of conditions, and the following
148d59ecb2SHans Petter Selasky  *    disclaimer.
158d59ecb2SHans Petter Selasky  * 2. Redistributions in binary form must reproduce the above copyright
168d59ecb2SHans Petter Selasky  *    notice, this list of conditions and the following disclaimer in the
178d59ecb2SHans Petter Selasky  *    documentation and/or other materials provided with the distribution.
188d59ecb2SHans Petter Selasky  *
198d59ecb2SHans Petter Selasky  * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR
208d59ecb2SHans Petter Selasky  * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
218d59ecb2SHans Petter Selasky  * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED.
228d59ecb2SHans Petter Selasky  * IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT,
238d59ecb2SHans Petter Selasky  * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT
248d59ecb2SHans Petter Selasky  * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
258d59ecb2SHans Petter Selasky  * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
268d59ecb2SHans Petter Selasky  * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
278d59ecb2SHans Petter Selasky  * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF
288d59ecb2SHans Petter Selasky  * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
298d59ecb2SHans Petter Selasky  */
30307f78f3SVladimir Kondratyev #ifndef _LINUXKPI_LINUX_KREF_H_
31307f78f3SVladimir Kondratyev #define _LINUXKPI_LINUX_KREF_H_
328d59ecb2SHans Petter Selasky 
338d59ecb2SHans Petter Selasky #include <sys/types.h>
348d59ecb2SHans Petter Selasky #include <sys/refcount.h>
358d59ecb2SHans Petter Selasky 
368e7baabcSHans Petter Selasky #include <linux/compiler.h>
3708a5e6ecSHans Petter Selasky #include <linux/kernel.h>
3808a5e6ecSHans Petter Selasky #include <linux/mutex.h>
397237a74fSEmmanuel Vadot #include <linux/refcount.h>
4008a5e6ecSHans Petter Selasky 
418d59ecb2SHans Petter Selasky #include <asm/atomic.h>
428d59ecb2SHans Petter Selasky 
438d59ecb2SHans Petter Selasky struct kref {
44*abb1a134SEmmanuel Vadot 	refcount_t refcount;
458d59ecb2SHans Petter Selasky };
468d59ecb2SHans Petter Selasky 
478d59ecb2SHans Petter Selasky static inline void
kref_init(struct kref * kref)488d59ecb2SHans Petter Selasky kref_init(struct kref *kref)
498d59ecb2SHans Petter Selasky {
508d59ecb2SHans Petter Selasky 
51e6bc24b0SMateusz Guzik 	refcount_init((uint32_t *)&kref->refcount, 1);
528d59ecb2SHans Petter Selasky }
538d59ecb2SHans Petter Selasky 
54e35dc514SHans Petter Selasky static inline unsigned int
kref_read(const struct kref * kref)55e6bc24b0SMateusz Guzik kref_read(const struct kref *kref)
56e35dc514SHans Petter Selasky {
57e35dc514SHans Petter Selasky 
58e6bc24b0SMateusz Guzik 	return (refcount_load(__DECONST(u_int32_t *, &kref->refcount)));
59e35dc514SHans Petter Selasky }
60e35dc514SHans Petter Selasky 
618d59ecb2SHans Petter Selasky static inline void
kref_get(struct kref * kref)628d59ecb2SHans Petter Selasky kref_get(struct kref *kref)
638d59ecb2SHans Petter Selasky {
648d59ecb2SHans Petter Selasky 
65e6bc24b0SMateusz Guzik 	refcount_acquire((uint32_t *)&kref->refcount);
668d59ecb2SHans Petter Selasky }
678d59ecb2SHans Petter Selasky 
688d59ecb2SHans Petter Selasky static inline int
kref_put(struct kref * kref,void (* rel)(struct kref * kref))698d59ecb2SHans Petter Selasky kref_put(struct kref *kref, void (*rel)(struct kref *kref))
708d59ecb2SHans Petter Selasky {
718d59ecb2SHans Petter Selasky 
72e6bc24b0SMateusz Guzik 	if (refcount_release((uint32_t *)&kref->refcount)) {
738d59ecb2SHans Petter Selasky 		rel(kref);
748d59ecb2SHans Petter Selasky 		return 1;
758d59ecb2SHans Petter Selasky 	}
768d59ecb2SHans Petter Selasky 	return 0;
778d59ecb2SHans Petter Selasky }
788d59ecb2SHans Petter Selasky 
798d59ecb2SHans Petter Selasky static inline int
kref_put_lock(struct kref * kref,void (* rel)(struct kref * kref),spinlock_t * lock)807237a74fSEmmanuel Vadot kref_put_lock(struct kref *kref, void (*rel)(struct kref *kref),
817237a74fSEmmanuel Vadot     spinlock_t *lock)
827237a74fSEmmanuel Vadot {
837237a74fSEmmanuel Vadot 
84e6bc24b0SMateusz Guzik 	if (refcount_release((uint32_t *)&kref->refcount)) {
857237a74fSEmmanuel Vadot 		spin_lock(lock);
867237a74fSEmmanuel Vadot 		rel(kref);
877237a74fSEmmanuel Vadot 		return (1);
887237a74fSEmmanuel Vadot 	}
897237a74fSEmmanuel Vadot 	return (0);
907237a74fSEmmanuel Vadot }
917237a74fSEmmanuel Vadot 
927237a74fSEmmanuel Vadot static inline int
kref_sub(struct kref * kref,unsigned int count,void (* rel)(struct kref * kref))938d59ecb2SHans Petter Selasky kref_sub(struct kref *kref, unsigned int count,
948d59ecb2SHans Petter Selasky     void (*rel)(struct kref *kref))
958d59ecb2SHans Petter Selasky {
968d59ecb2SHans Petter Selasky 
978d59ecb2SHans Petter Selasky 	while (count--) {
98e6bc24b0SMateusz Guzik 		if (refcount_release((uint32_t *)&kref->refcount)) {
998d59ecb2SHans Petter Selasky 			rel(kref);
1008d59ecb2SHans Petter Selasky 			return 1;
1018d59ecb2SHans Petter Selasky 		}
1028d59ecb2SHans Petter Selasky 	}
1038d59ecb2SHans Petter Selasky 	return 0;
1048d59ecb2SHans Petter Selasky }
1058d59ecb2SHans Petter Selasky 
1068d59ecb2SHans Petter Selasky static inline int __must_check
kref_get_unless_zero(struct kref * kref)1078d59ecb2SHans Petter Selasky kref_get_unless_zero(struct kref *kref)
1088d59ecb2SHans Petter Selasky {
1098d59ecb2SHans Petter Selasky 
110e6bc24b0SMateusz Guzik 	return refcount_acquire_if_not_zero((uint32_t *)&kref->refcount);
1118d59ecb2SHans Petter Selasky }
1128d59ecb2SHans Petter Selasky 
kref_put_mutex(struct kref * kref,void (* release)(struct kref * kref),struct mutex * lock)11308a5e6ecSHans Petter Selasky static inline int kref_put_mutex(struct kref *kref,
11408a5e6ecSHans Petter Selasky     void (*release)(struct kref *kref), struct mutex *lock)
11508a5e6ecSHans Petter Selasky {
11608a5e6ecSHans Petter Selasky 	WARN_ON(release == NULL);
117e6bc24b0SMateusz Guzik 	if (unlikely(!refcount_release_if_not_last((uint32_t *)&kref->refcount))) {
11808a5e6ecSHans Petter Selasky 		mutex_lock(lock);
119e6bc24b0SMateusz Guzik 		if (unlikely(!refcount_release((uint32_t *)&kref->refcount))) {
12008a5e6ecSHans Petter Selasky 			mutex_unlock(lock);
12108a5e6ecSHans Petter Selasky 			return 0;
12208a5e6ecSHans Petter Selasky 		}
12308a5e6ecSHans Petter Selasky 		release(kref);
12408a5e6ecSHans Petter Selasky 		return 1;
12508a5e6ecSHans Petter Selasky 	}
12608a5e6ecSHans Petter Selasky 	return 0;
12708a5e6ecSHans Petter Selasky }
12808a5e6ecSHans Petter Selasky 
129307f78f3SVladimir Kondratyev #endif /* _LINUXKPI_LINUX_KREF_H_ */
130