1219820Sjeff/*-
2219820Sjeff * Copyright (c) 2010 Isilon Systems, Inc.
3219820Sjeff * Copyright (c) 2010 iX Systems, Inc.
4219820Sjeff * Copyright (c) 2010 Panasas, Inc.
5289578Shselasky * Copyright (c) 2013-2015 Mellanox Technologies, Ltd.
6289578Shselasky * Copyright (c) 2013 Fran��ois Tigeot
7219820Sjeff * All rights reserved.
8219820Sjeff *
9219820Sjeff * Redistribution and use in source and binary forms, with or without
10219820Sjeff * modification, are permitted provided that the following conditions
11219820Sjeff * are met:
12219820Sjeff * 1. Redistributions of source code must retain the above copyright
13219820Sjeff *    notice unmodified, this list of conditions, and the following
14219820Sjeff *    disclaimer.
15219820Sjeff * 2. Redistributions in binary form must reproduce the above copyright
16219820Sjeff *    notice, this list of conditions and the following disclaimer in the
17219820Sjeff *    documentation and/or other materials provided with the distribution.
18219820Sjeff *
19219820Sjeff * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR
20219820Sjeff * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
21219820Sjeff * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED.
22219820Sjeff * IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT,
23219820Sjeff * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT
24219820Sjeff * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
25219820Sjeff * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
26219820Sjeff * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
27219820Sjeff * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF
28219820Sjeff * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
29289644Shselasky *
30289644Shselasky * $FreeBSD: stable/11/sys/compat/linuxkpi/common/include/linux/kref.h 329961 2018-02-25 10:25:47Z hselasky $
31219820Sjeff */
32219820Sjeff#ifndef _LINUX_KREF_H_
33219820Sjeff#define _LINUX_KREF_H_
34219820Sjeff
35278681Shselasky#include <sys/types.h>
36219820Sjeff#include <sys/refcount.h>
37219820Sjeff
38290335Shselasky#include <linux/compiler.h>
39300497Shselasky#include <linux/kernel.h>
40300497Shselasky#include <linux/mutex.h>
41300497Shselasky
42289578Shselasky#include <asm/atomic.h>
43289578Shselasky
44219820Sjeffstruct kref {
45289578Shselasky	atomic_t refcount;
46219820Sjeff};
47219820Sjeff
48219820Sjeffstatic inline void
49219820Sjeffkref_init(struct kref *kref)
50219820Sjeff{
51219820Sjeff
52289578Shselasky	refcount_init(&kref->refcount.counter, 1);
53219820Sjeff}
54219820Sjeff
55329961Shselaskystatic inline unsigned int
56329961Shselaskykref_read(const struct kref *kref)
57329961Shselasky{
58329961Shselasky
59329961Shselasky	return (atomic_read(&kref->refcount));
60329961Shselasky}
61329961Shselasky
62219820Sjeffstatic inline void
63219820Sjeffkref_get(struct kref *kref)
64219820Sjeff{
65219820Sjeff
66289578Shselasky	refcount_acquire(&kref->refcount.counter);
67219820Sjeff}
68219820Sjeff
69219820Sjeffstatic inline int
70219820Sjeffkref_put(struct kref *kref, void (*rel)(struct kref *kref))
71219820Sjeff{
72219820Sjeff
73289578Shselasky	if (refcount_release(&kref->refcount.counter)) {
74219820Sjeff		rel(kref);
75219820Sjeff		return 1;
76219820Sjeff	}
77219820Sjeff	return 0;
78219820Sjeff}
79219820Sjeff
80289578Shselaskystatic inline int
81289578Shselaskykref_sub(struct kref *kref, unsigned int count,
82289578Shselasky    void (*rel)(struct kref *kref))
83289578Shselasky{
84289578Shselasky
85289578Shselasky	while (count--) {
86289578Shselasky		if (refcount_release(&kref->refcount.counter)) {
87289578Shselasky			rel(kref);
88289578Shselasky			return 1;
89289578Shselasky		}
90289578Shselasky	}
91289578Shselasky	return 0;
92289578Shselasky}
93289578Shselasky
94289578Shselaskystatic inline int __must_check
95289578Shselaskykref_get_unless_zero(struct kref *kref)
96289578Shselasky{
97289578Shselasky
98289578Shselasky	return atomic_add_unless(&kref->refcount, 1, 0);
99289578Shselasky}
100289578Shselasky
101300497Shselaskystatic inline int kref_put_mutex(struct kref *kref,
102300497Shselasky    void (*release)(struct kref *kref), struct mutex *lock)
103300497Shselasky{
104300497Shselasky	WARN_ON(release == NULL);
105300497Shselasky	if (unlikely(!atomic_add_unless(&kref->refcount, -1, 1))) {
106300497Shselasky		mutex_lock(lock);
107300497Shselasky		if (unlikely(!atomic_dec_and_test(&kref->refcount))) {
108300497Shselasky			mutex_unlock(lock);
109300497Shselasky			return 0;
110300497Shselasky		}
111300497Shselasky		release(kref);
112300497Shselasky		return 1;
113300497Shselasky	}
114300497Shselasky	return 0;
115300497Shselasky}
116300497Shselasky
117270710Shselasky#endif /* _LINUX_KREF_H_ */
118