xref: /kernel/linux/linux-5.10/include/linux/kref.h (revision 8c2ecf20)
18c2ecf20Sopenharmony_ci/* SPDX-License-Identifier: GPL-2.0-only */
28c2ecf20Sopenharmony_ci/*
38c2ecf20Sopenharmony_ci * kref.h - library routines for handling generic reference counted objects
48c2ecf20Sopenharmony_ci *
58c2ecf20Sopenharmony_ci * Copyright (C) 2004 Greg Kroah-Hartman <greg@kroah.com>
68c2ecf20Sopenharmony_ci * Copyright (C) 2004 IBM Corp.
78c2ecf20Sopenharmony_ci *
88c2ecf20Sopenharmony_ci * based on kobject.h which was:
98c2ecf20Sopenharmony_ci * Copyright (C) 2002-2003 Patrick Mochel <mochel@osdl.org>
108c2ecf20Sopenharmony_ci * Copyright (C) 2002-2003 Open Source Development Labs
118c2ecf20Sopenharmony_ci */
128c2ecf20Sopenharmony_ci
138c2ecf20Sopenharmony_ci#ifndef _KREF_H_
148c2ecf20Sopenharmony_ci#define _KREF_H_
158c2ecf20Sopenharmony_ci
168c2ecf20Sopenharmony_ci#include <linux/spinlock.h>
178c2ecf20Sopenharmony_ci#include <linux/refcount.h>
188c2ecf20Sopenharmony_ci
198c2ecf20Sopenharmony_cistruct kref {
208c2ecf20Sopenharmony_ci	refcount_t refcount;
218c2ecf20Sopenharmony_ci};
228c2ecf20Sopenharmony_ci
238c2ecf20Sopenharmony_ci#define KREF_INIT(n)	{ .refcount = REFCOUNT_INIT(n), }
248c2ecf20Sopenharmony_ci
258c2ecf20Sopenharmony_ci/**
268c2ecf20Sopenharmony_ci * kref_init - initialize object.
278c2ecf20Sopenharmony_ci * @kref: object in question.
288c2ecf20Sopenharmony_ci */
298c2ecf20Sopenharmony_cistatic inline void kref_init(struct kref *kref)
308c2ecf20Sopenharmony_ci{
318c2ecf20Sopenharmony_ci	refcount_set(&kref->refcount, 1);
328c2ecf20Sopenharmony_ci}
338c2ecf20Sopenharmony_ci
348c2ecf20Sopenharmony_cistatic inline unsigned int kref_read(const struct kref *kref)
358c2ecf20Sopenharmony_ci{
368c2ecf20Sopenharmony_ci	return refcount_read(&kref->refcount);
378c2ecf20Sopenharmony_ci}
388c2ecf20Sopenharmony_ci
398c2ecf20Sopenharmony_ci/**
408c2ecf20Sopenharmony_ci * kref_get - increment refcount for object.
418c2ecf20Sopenharmony_ci * @kref: object.
428c2ecf20Sopenharmony_ci */
438c2ecf20Sopenharmony_cistatic inline void kref_get(struct kref *kref)
448c2ecf20Sopenharmony_ci{
458c2ecf20Sopenharmony_ci	refcount_inc(&kref->refcount);
468c2ecf20Sopenharmony_ci}
478c2ecf20Sopenharmony_ci
488c2ecf20Sopenharmony_ci/**
498c2ecf20Sopenharmony_ci * kref_put - decrement refcount for object.
508c2ecf20Sopenharmony_ci * @kref: object.
518c2ecf20Sopenharmony_ci * @release: pointer to the function that will clean up the object when the
528c2ecf20Sopenharmony_ci *	     last reference to the object is released.
538c2ecf20Sopenharmony_ci *	     This pointer is required, and it is not acceptable to pass kfree
548c2ecf20Sopenharmony_ci *	     in as this function.
558c2ecf20Sopenharmony_ci *
568c2ecf20Sopenharmony_ci * Decrement the refcount, and if 0, call release().
578c2ecf20Sopenharmony_ci * Return 1 if the object was removed, otherwise return 0.  Beware, if this
588c2ecf20Sopenharmony_ci * function returns 0, you still can not count on the kref from remaining in
598c2ecf20Sopenharmony_ci * memory.  Only use the return value if you want to see if the kref is now
608c2ecf20Sopenharmony_ci * gone, not present.
618c2ecf20Sopenharmony_ci */
628c2ecf20Sopenharmony_cistatic inline int kref_put(struct kref *kref, void (*release)(struct kref *kref))
638c2ecf20Sopenharmony_ci{
648c2ecf20Sopenharmony_ci	if (refcount_dec_and_test(&kref->refcount)) {
658c2ecf20Sopenharmony_ci		release(kref);
668c2ecf20Sopenharmony_ci		return 1;
678c2ecf20Sopenharmony_ci	}
688c2ecf20Sopenharmony_ci	return 0;
698c2ecf20Sopenharmony_ci}
708c2ecf20Sopenharmony_ci
718c2ecf20Sopenharmony_cistatic inline int kref_put_mutex(struct kref *kref,
728c2ecf20Sopenharmony_ci				 void (*release)(struct kref *kref),
738c2ecf20Sopenharmony_ci				 struct mutex *lock)
748c2ecf20Sopenharmony_ci{
758c2ecf20Sopenharmony_ci	if (refcount_dec_and_mutex_lock(&kref->refcount, lock)) {
768c2ecf20Sopenharmony_ci		release(kref);
778c2ecf20Sopenharmony_ci		return 1;
788c2ecf20Sopenharmony_ci	}
798c2ecf20Sopenharmony_ci	return 0;
808c2ecf20Sopenharmony_ci}
818c2ecf20Sopenharmony_ci
828c2ecf20Sopenharmony_cistatic inline int kref_put_lock(struct kref *kref,
838c2ecf20Sopenharmony_ci				void (*release)(struct kref *kref),
848c2ecf20Sopenharmony_ci				spinlock_t *lock)
858c2ecf20Sopenharmony_ci{
868c2ecf20Sopenharmony_ci	if (refcount_dec_and_lock(&kref->refcount, lock)) {
878c2ecf20Sopenharmony_ci		release(kref);
888c2ecf20Sopenharmony_ci		return 1;
898c2ecf20Sopenharmony_ci	}
908c2ecf20Sopenharmony_ci	return 0;
918c2ecf20Sopenharmony_ci}
928c2ecf20Sopenharmony_ci
938c2ecf20Sopenharmony_ci/**
948c2ecf20Sopenharmony_ci * kref_get_unless_zero - Increment refcount for object unless it is zero.
958c2ecf20Sopenharmony_ci * @kref: object.
968c2ecf20Sopenharmony_ci *
978c2ecf20Sopenharmony_ci * Return non-zero if the increment succeeded. Otherwise return 0.
988c2ecf20Sopenharmony_ci *
998c2ecf20Sopenharmony_ci * This function is intended to simplify locking around refcounting for
1008c2ecf20Sopenharmony_ci * objects that can be looked up from a lookup structure, and which are
1018c2ecf20Sopenharmony_ci * removed from that lookup structure in the object destructor.
1028c2ecf20Sopenharmony_ci * Operations on such objects require at least a read lock around
1038c2ecf20Sopenharmony_ci * lookup + kref_get, and a write lock around kref_put + remove from lookup
1048c2ecf20Sopenharmony_ci * structure. Furthermore, RCU implementations become extremely tricky.
1058c2ecf20Sopenharmony_ci * With a lookup followed by a kref_get_unless_zero *with return value check*
1068c2ecf20Sopenharmony_ci * locking in the kref_put path can be deferred to the actual removal from
1078c2ecf20Sopenharmony_ci * the lookup structure and RCU lookups become trivial.
1088c2ecf20Sopenharmony_ci */
1098c2ecf20Sopenharmony_cistatic inline int __must_check kref_get_unless_zero(struct kref *kref)
1108c2ecf20Sopenharmony_ci{
1118c2ecf20Sopenharmony_ci	return refcount_inc_not_zero(&kref->refcount);
1128c2ecf20Sopenharmony_ci}
1138c2ecf20Sopenharmony_ci#endif /* _KREF_H_ */
114