|
|
7f4c2a |
From 62ed8b36d67e073fd26c2c7353a8b7cc0961be20 Mon Sep 17 00:00:00 2001
|
|
|
7f4c2a |
From: Niels de Vos <ndevos@redhat.com>
|
|
|
7f4c2a |
Date: Sun, 31 May 2015 15:16:41 +0200
|
|
|
7f4c2a |
Subject: [PATCH 144/190] core: add "gf_ref_t" for common refcounting structures
|
|
|
7f4c2a |
|
|
|
7f4c2a |
This is a backport of http://review.gluster.org/#/c/11022/
|
|
|
7f4c2a |
|
|
|
7f4c2a |
There were errors from checkpatch.pl, it is fixed as part of
|
|
|
7f4c2a |
this backport, below are the changes:
|
|
|
7f4c2a |
added additional parenthesis for macro definition
|
|
|
7f4c2a |
GF_REF_INIT
|
|
|
7f4c2a |
GF_REF_GET
|
|
|
7f4c2a |
GF_REF_PUT
|
|
|
7f4c2a |
|
|
|
7f4c2a |
> Checks for compiler supported atomic operations comes from client_t.h.
|
|
|
7f4c2a |
>
|
|
|
7f4c2a |
> An example usage of this change can be found in adding reference
|
|
|
7f4c2a |
> counting to "struct auth_cache_entry" in http://review.gluster.org/11023
|
|
|
7f4c2a |
>
|
|
|
7f4c2a |
> Basic usage looks like this:
|
|
|
7f4c2a |
>
|
|
|
7f4c2a |
> #include "refcount.h"
|
|
|
7f4c2a |
>
|
|
|
7f4c2a |
> struct my_struct {
|
|
|
7f4c2a |
> GF_REF_DECL;
|
|
|
7f4c2a |
> ... /* more members */
|
|
|
7f4c2a |
> }
|
|
|
7f4c2a |
>
|
|
|
7f4c2a |
> void my_destructor (void *data)
|
|
|
7f4c2a |
> {
|
|
|
7f4c2a |
> struct my_struct *my_ptr = (struct my_struct *) data;
|
|
|
7f4c2a |
>
|
|
|
7f4c2a |
> ... /* do some more cleanups */
|
|
|
7f4c2a |
> GF_FREE (my_ptr);
|
|
|
7f4c2a |
> }
|
|
|
7f4c2a |
>
|
|
|
7f4c2a |
> void init_ptr (struct parent *parent)
|
|
|
7f4c2a |
> {
|
|
|
7f4c2a |
> struct my_struct *my_ptr = malloc (sizeof (struct my_struct));
|
|
|
7f4c2a |
>
|
|
|
7f4c2a |
> GF_REF_INIT (my_ptr, my_destructor); /* refcount is set to 1 */
|
|
|
7f4c2a |
>
|
|
|
7f4c2a |
> ... /* my_ptr probably gets added to some parent structure */
|
|
|
7f4c2a |
> parent_add_ptr (parent, my_ptr);
|
|
|
7f4c2a |
> }
|
|
|
7f4c2a |
>
|
|
|
7f4c2a |
> void do_something (struct parent *parent)
|
|
|
7f4c2a |
> {
|
|
|
7f4c2a |
> struct my_struct *my_ptr = NULL;
|
|
|
7f4c2a |
>
|
|
|
7f4c2a |
> /* likely need to lock parent, depends on its access pattern */
|
|
|
7f4c2a |
> my_ptr = parent_remove_first_ptr (parent);
|
|
|
7f4c2a |
> /* unlock parent */
|
|
|
7f4c2a |
>
|
|
|
7f4c2a |
> ... /* do something */
|
|
|
7f4c2a |
>
|
|
|
7f4c2a |
> GF_REF_PUT (my_ptr); /* calls my_destructor on refcount = 0 */
|
|
|
7f4c2a |
> }
|
|
|
7f4c2a |
>
|
|
|
7f4c2a |
> URL: http://thread.gmane.org/gmane.comp.file-systems.gluster.devel/11202
|
|
|
7f4c2a |
> Change-Id: Idb98a5861a44c31676108ed8876db12c320912ef
|
|
|
7f4c2a |
> BUG: 1228157
|
|
|
7f4c2a |
> Signed-off-by: Niels de Vos <ndevos@redhat.com>
|
|
|
7f4c2a |
> Reviewed-on: http://review.gluster.org/11022
|
|
|
7f4c2a |
> Reviewed-by: Xavier Hernandez <xhernandez@datalab.es>
|
|
|
7f4c2a |
> Reviewed-by: Krishnan Parthasarathi <kparthas@redhat.com>
|
|
|
7f4c2a |
> Tested-by: Gluster Build System <jenkins@build.gluster.com>
|
|
|
7f4c2a |
> Tested-by: NetBSD Build System <jenkins@build.gluster.org>
|
|
|
7f4c2a |
|
|
|
7f4c2a |
Change-Id: I5630ff3fbd0e0021a83597d778e1037796be5355
|
|
|
7f4c2a |
BUG: 1235628
|
|
|
7f4c2a |
Signed-off-by: vmallika <vmallika@redhat.com>
|
|
|
7f4c2a |
Reviewed-on: https://code.engineering.redhat.com/gerrit/51605
|
|
|
7f4c2a |
Reviewed-by: Raghavendra Gowdappa <rgowdapp@redhat.com>
|
|
|
7f4c2a |
Tested-by: Raghavendra Gowdappa <rgowdapp@redhat.com>
|
|
|
7f4c2a |
---
|
|
|
7f4c2a |
libglusterfs/src/Makefile.am | 4 +-
|
|
|
7f4c2a |
libglusterfs/src/refcount.c | 112 ++++++++++++++++++++++++++++++++++++++++++
|
|
|
7f4c2a |
libglusterfs/src/refcount.h | 103 ++++++++++++++++++++++++++++++++++++++
|
|
|
7f4c2a |
3 files changed, 217 insertions(+), 2 deletions(-)
|
|
|
7f4c2a |
create mode 100644 libglusterfs/src/refcount.c
|
|
|
7f4c2a |
create mode 100644 libglusterfs/src/refcount.h
|
|
|
7f4c2a |
|
|
|
7f4c2a |
diff --git a/libglusterfs/src/Makefile.am b/libglusterfs/src/Makefile.am
|
|
|
7f4c2a |
index 80ce672..ed441d0 100644
|
|
|
7f4c2a |
--- a/libglusterfs/src/Makefile.am
|
|
|
7f4c2a |
+++ b/libglusterfs/src/Makefile.am
|
|
|
7f4c2a |
@@ -22,7 +22,7 @@ libglusterfs_la_SOURCES = dict.c xlator.c logging.c \
|
|
|
7f4c2a |
$(CONTRIBDIR)/rbtree/rb.c rbthash.c store.c latency.c \
|
|
|
7f4c2a |
graph.c syncop.c graph-print.c trie.c run.c options.c fd-lk.c \
|
|
|
7f4c2a |
circ-buff.c event-history.c gidcache.c ctx.c client_t.c event-poll.c \
|
|
|
7f4c2a |
- event-epoll.c syncop-utils.c cluster-syncop.c \
|
|
|
7f4c2a |
+ event-epoll.c syncop-utils.c cluster-syncop.c refcount.c \
|
|
|
7f4c2a |
$(CONTRIBDIR)/libgen/basename_r.c \
|
|
|
7f4c2a |
$(CONTRIBDIR)/libgen/dirname_r.c $(CONTRIBDIR)/stdlib/gf_mkostemp.c \
|
|
|
7f4c2a |
strfd.c parse-utils.c $(CONTRIBDIR)/mount/mntent.c \
|
|
|
7f4c2a |
@@ -40,7 +40,7 @@ noinst_HEADERS = common-utils.h defaults.h dict.h glusterfs.h hashfn.h timespec.
|
|
|
7f4c2a |
gf-dirent.h locking.h syscall.h iobuf.h globals.h statedump.h \
|
|
|
7f4c2a |
checksum.h daemon.h $(CONTRIBDIR)/rbtree/rb.h store.h\
|
|
|
7f4c2a |
rbthash.h iatt.h latency.h mem-types.h syncop.h cluster-syncop.h \
|
|
|
7f4c2a |
- graph-utils.h trie.h \
|
|
|
7f4c2a |
+ graph-utils.h trie.h refcount.h \
|
|
|
7f4c2a |
run.h options.h lkowner.h fd-lk.h circ-buff.h event-history.h \
|
|
|
7f4c2a |
gidcache.h client_t.h glusterfs-acl.h glfs-message-id.h \
|
|
|
7f4c2a |
template-component-messages.h strfd.h syncop-utils.h parse-utils.h \
|
|
|
7f4c2a |
diff --git a/libglusterfs/src/refcount.c b/libglusterfs/src/refcount.c
|
|
|
7f4c2a |
new file mode 100644
|
|
|
7f4c2a |
index 0000000..96edc10
|
|
|
7f4c2a |
--- /dev/null
|
|
|
7f4c2a |
+++ b/libglusterfs/src/refcount.c
|
|
|
7f4c2a |
@@ -0,0 +1,112 @@
|
|
|
7f4c2a |
+/*
|
|
|
7f4c2a |
+ Copyright (c) 2015 Red Hat, Inc. <http://www.redhat.com>
|
|
|
7f4c2a |
+ This file is part of GlusterFS.
|
|
|
7f4c2a |
+
|
|
|
7f4c2a |
+ This file is licensed to you under your choice of the GNU Lesser
|
|
|
7f4c2a |
+ General Public License, version 3 or any later version (LGPLv3 or
|
|
|
7f4c2a |
+ later), or the GNU General Public License, version 2 (GPLv2), in all
|
|
|
7f4c2a |
+ cases as published by the Free Software Foundation.
|
|
|
7f4c2a |
+*/
|
|
|
7f4c2a |
+
|
|
|
7f4c2a |
+#include "common-utils.h"
|
|
|
7f4c2a |
+#include "refcount.h"
|
|
|
7f4c2a |
+
|
|
|
7f4c2a |
+#ifndef REFCOUNT_NEEDS_LOCK
|
|
|
7f4c2a |
+
|
|
|
7f4c2a |
+unsigned int
|
|
|
7f4c2a |
+_gf_ref_get (gf_ref_t *ref)
|
|
|
7f4c2a |
+{
|
|
|
7f4c2a |
+ unsigned int cnt = __sync_fetch_and_add (&ref->cnt, 1);
|
|
|
7f4c2a |
+
|
|
|
7f4c2a |
+ /* if cnt == 0, we're in a fatal position, the object will be free'd
|
|
|
7f4c2a |
+ *
|
|
|
7f4c2a |
+ * There is a race when two threads do a _gf_ref_get(). Only one of
|
|
|
7f4c2a |
+ * them may get a 0 returned. That is acceptible, because one
|
|
|
7f4c2a |
+ * _gf_ref_get() returning 0 should be handled as a fatal problem and
|
|
|
7f4c2a |
+ * when correct usage/locking is used, it should never happen.
|
|
|
7f4c2a |
+ */
|
|
|
7f4c2a |
+ GF_ASSERT (cnt != 0);
|
|
|
7f4c2a |
+
|
|
|
7f4c2a |
+ return cnt;
|
|
|
7f4c2a |
+}
|
|
|
7f4c2a |
+
|
|
|
7f4c2a |
+unsigned int
|
|
|
7f4c2a |
+_gf_ref_put (gf_ref_t *ref)
|
|
|
7f4c2a |
+{
|
|
|
7f4c2a |
+ unsigned int cnt = __sync_fetch_and_sub (&ref->cnt, 1);
|
|
|
7f4c2a |
+
|
|
|
7f4c2a |
+ /* if cnt == 1, the last user just did a _gf_ref_put()
|
|
|
7f4c2a |
+ *
|
|
|
7f4c2a |
+ * When cnt == 0, one _gf_ref_put() was done too much and there has
|
|
|
7f4c2a |
+ * been a thread using the refcounted structure when it was not
|
|
|
7f4c2a |
+ * supposed to.
|
|
|
7f4c2a |
+ */
|
|
|
7f4c2a |
+ GF_ASSERT (cnt != 0);
|
|
|
7f4c2a |
+
|
|
|
7f4c2a |
+ if (cnt == 1 && ref->release) {
|
|
|
7f4c2a |
+ ref->release (ref->data);
|
|
|
7f4c2a |
+ /* set return value to 0 to inform the caller correctly */
|
|
|
7f4c2a |
+ cnt = 0;
|
|
|
7f4c2a |
+ }
|
|
|
7f4c2a |
+
|
|
|
7f4c2a |
+ return cnt;
|
|
|
7f4c2a |
+}
|
|
|
7f4c2a |
+
|
|
|
7f4c2a |
+#else
|
|
|
7f4c2a |
+
|
|
|
7f4c2a |
+unsigned int
|
|
|
7f4c2a |
+_gf_ref_get (gf_ref_t *ref)
|
|
|
7f4c2a |
+{
|
|
|
7f4c2a |
+ unsigned int cnt = 0;
|
|
|
7f4c2a |
+
|
|
|
7f4c2a |
+ LOCK (&ref->lk);
|
|
|
7f4c2a |
+ {
|
|
|
7f4c2a |
+ /* never can be 0, should have been free'd */
|
|
|
7f4c2a |
+ if (ref->cnt > 0)
|
|
|
7f4c2a |
+ cnt = ++ref->cnt;
|
|
|
7f4c2a |
+ else
|
|
|
7f4c2a |
+ GF_ASSERT (ref->cnt > 0);
|
|
|
7f4c2a |
+ }
|
|
|
7f4c2a |
+ UNLOCK (&ref->lk);
|
|
|
7f4c2a |
+
|
|
|
7f4c2a |
+ return cnt;
|
|
|
7f4c2a |
+}
|
|
|
7f4c2a |
+
|
|
|
7f4c2a |
+unsigned int
|
|
|
7f4c2a |
+_gf_ref_put (gf_ref_t *ref)
|
|
|
7f4c2a |
+{
|
|
|
7f4c2a |
+ unsigned int cnt = 0;
|
|
|
7f4c2a |
+ int release = 0;
|
|
|
7f4c2a |
+
|
|
|
7f4c2a |
+ LOCK (&ref->lk);
|
|
|
7f4c2a |
+ {
|
|
|
7f4c2a |
+ if (ref->cnt != 0) {
|
|
|
7f4c2a |
+ cnt = --ref->cnt;
|
|
|
7f4c2a |
+ /* call release() only when cnt == 0 */
|
|
|
7f4c2a |
+ release = (cnt == 0);
|
|
|
7f4c2a |
+ } else
|
|
|
7f4c2a |
+ GF_ASSERT (ref->cnt != 0);
|
|
|
7f4c2a |
+ }
|
|
|
7f4c2a |
+ UNLOCK (&ref->lk);
|
|
|
7f4c2a |
+
|
|
|
7f4c2a |
+ if (release && ref->release)
|
|
|
7f4c2a |
+ ref->release (ref->data);
|
|
|
7f4c2a |
+
|
|
|
7f4c2a |
+ return cnt;
|
|
|
7f4c2a |
+}
|
|
|
7f4c2a |
+
|
|
|
7f4c2a |
+#endif /* REFCOUNT_NEEDS_LOCK */
|
|
|
7f4c2a |
+
|
|
|
7f4c2a |
+
|
|
|
7f4c2a |
+void
|
|
|
7f4c2a |
+_gf_ref_init (gf_ref_t *ref, gf_ref_release_t release, void *data)
|
|
|
7f4c2a |
+{
|
|
|
7f4c2a |
+ GF_ASSERT (ref);
|
|
|
7f4c2a |
+
|
|
|
7f4c2a |
+#ifdef REFCOUNT_NEEDS_LOCK
|
|
|
7f4c2a |
+ LOCK_INIT (&ref->lk);
|
|
|
7f4c2a |
+#endif
|
|
|
7f4c2a |
+ ref->cnt = 1;
|
|
|
7f4c2a |
+ ref->release = release;
|
|
|
7f4c2a |
+ ref->data = data;
|
|
|
7f4c2a |
+}
|
|
|
7f4c2a |
diff --git a/libglusterfs/src/refcount.h b/libglusterfs/src/refcount.h
|
|
|
7f4c2a |
new file mode 100644
|
|
|
7f4c2a |
index 0000000..c8113a2
|
|
|
7f4c2a |
--- /dev/null
|
|
|
7f4c2a |
+++ b/libglusterfs/src/refcount.h
|
|
|
7f4c2a |
@@ -0,0 +1,103 @@
|
|
|
7f4c2a |
+/*
|
|
|
7f4c2a |
+ Copyright (c) 2015 Red Hat, Inc. <http://www.redhat.com>
|
|
|
7f4c2a |
+ This file is part of GlusterFS.
|
|
|
7f4c2a |
+
|
|
|
7f4c2a |
+ This file is licensed to you under your choice of the GNU Lesser
|
|
|
7f4c2a |
+ General Public License, version 3 or any later version (LGPLv3 or
|
|
|
7f4c2a |
+ later), or the GNU General Public License, version 2 (GPLv2), in all
|
|
|
7f4c2a |
+ cases as published by the Free Software Foundation.
|
|
|
7f4c2a |
+*/
|
|
|
7f4c2a |
+
|
|
|
7f4c2a |
+#ifndef _REFCOUNT_H
|
|
|
7f4c2a |
+#define _REFCOUNT_H
|
|
|
7f4c2a |
+
|
|
|
7f4c2a |
+/* check for compiler support for __sync_*_and_fetch()
|
|
|
7f4c2a |
+ *
|
|
|
7f4c2a |
+ * a more comprehensive feature test is shown at
|
|
|
7f4c2a |
+ * http://lists.iptel.org/pipermail/semsdev/2010-October/005075.html
|
|
|
7f4c2a |
+ * this is sufficient for RHEL5 i386 builds
|
|
|
7f4c2a |
+ */
|
|
|
7f4c2a |
+#if (__GNUC__ > 4 || (__GNUC__ == 4 && __GNUC_MINOR__ >= 1)) && !defined(__i386__)
|
|
|
7f4c2a |
+#undef REFCOUNT_NEEDS_LOCK
|
|
|
7f4c2a |
+#else
|
|
|
7f4c2a |
+#define REFCOUNT_NEEDS_LOCK
|
|
|
7f4c2a |
+#include "locking.h"
|
|
|
7f4c2a |
+#endif /* compiler support for __sync_*_and_fetch() */
|
|
|
7f4c2a |
+
|
|
|
7f4c2a |
+typedef void (*gf_ref_release_t)(void *data);
|
|
|
7f4c2a |
+
|
|
|
7f4c2a |
+struct _gf_ref_t {
|
|
|
7f4c2a |
+#ifdef REFCOUNT_NEEDS_LOCK
|
|
|
7f4c2a |
+ gf_lock_t lk; /* lock for atomically adjust cnt */
|
|
|
7f4c2a |
+#endif
|
|
|
7f4c2a |
+ unsigned int cnt; /* number of users, free on 0 */
|
|
|
7f4c2a |
+
|
|
|
7f4c2a |
+ gf_ref_release_t release; /* cleanup when cnt == 0 */
|
|
|
7f4c2a |
+ void *data; /* parameter passed to release() */
|
|
|
7f4c2a |
+};
|
|
|
7f4c2a |
+typedef struct _gf_ref_t gf_ref_t;
|
|
|
7f4c2a |
+
|
|
|
7f4c2a |
+
|
|
|
7f4c2a |
+/* _gf_ref_get -- increase the refcount and return the number of references
|
|
|
7f4c2a |
+ *
|
|
|
7f4c2a |
+ * @return: greater then 0 when a reference was taken, 0 when not
|
|
|
7f4c2a |
+ */
|
|
|
7f4c2a |
+unsigned int
|
|
|
7f4c2a |
+_gf_ref_get (gf_ref_t *ref);
|
|
|
7f4c2a |
+
|
|
|
7f4c2a |
+/* _gf_ref_put -- decrease the refcount and return the number of references
|
|
|
7f4c2a |
+ *
|
|
|
7f4c2a |
+ * @return: greater then 0 when there are still references, 0 when cleanup
|
|
|
7f4c2a |
+ * should be done
|
|
|
7f4c2a |
+ */
|
|
|
7f4c2a |
+unsigned int
|
|
|
7f4c2a |
+_gf_ref_put (gf_ref_t *ref);
|
|
|
7f4c2a |
+
|
|
|
7f4c2a |
+/* _gf_ref_init -- initalize an embedded refcount object
|
|
|
7f4c2a |
+ *
|
|
|
7f4c2a |
+ * @release: function to call when the refcount == 0
|
|
|
7f4c2a |
+ * @data: parameter to be passed to @release
|
|
|
7f4c2a |
+ */
|
|
|
7f4c2a |
+void
|
|
|
7f4c2a |
+_gf_ref_init (gf_ref_t *ref, gf_ref_release_t release, void *data);
|
|
|
7f4c2a |
+
|
|
|
7f4c2a |
+
|
|
|
7f4c2a |
+/*
|
|
|
7f4c2a |
+ * Strong suggestion to use the simplified GF_REF_* API.
|
|
|
7f4c2a |
+ */
|
|
|
7f4c2a |
+
|
|
|
7f4c2a |
+/* GF_REF_DECL -- declaration to put inside your structure
|
|
|
7f4c2a |
+ *
|
|
|
7f4c2a |
+ * Example:
|
|
|
7f4c2a |
+ * struct my_struct {
|
|
|
7f4c2a |
+ * GF_REF_DECL;
|
|
|
7f4c2a |
+ *
|
|
|
7f4c2a |
+ * ... // additional members
|
|
|
7f4c2a |
+ * };
|
|
|
7f4c2a |
+ */
|
|
|
7f4c2a |
+#define GF_REF_DECL gf_ref_t _ref
|
|
|
7f4c2a |
+
|
|
|
7f4c2a |
+/* GF_REF_INIT -- initialize a GF_REF_DECL structure
|
|
|
7f4c2a |
+ *
|
|
|
7f4c2a |
+ * @p: allocated structure with GF_REF_DECL
|
|
|
7f4c2a |
+ * @d: destructor to call once refcounting reaches 0
|
|
|
7f4c2a |
+ *
|
|
|
7f4c2a |
+ * Sets the refcount to 1.
|
|
|
7f4c2a |
+ */
|
|
|
7f4c2a |
+#define GF_REF_INIT(p, d) (_gf_ref_init (&p->_ref, d, p))
|
|
|
7f4c2a |
+
|
|
|
7f4c2a |
+/* GF_REF_GET -- increase the refcount of a GF_REF_DECL structure
|
|
|
7f4c2a |
+ *
|
|
|
7f4c2a |
+ * @return: greater then 0 when a reference was taken, 0 when not
|
|
|
7f4c2a |
+ */
|
|
|
7f4c2a |
+#define GF_REF_GET(p) (_gf_ref_get (&p->_ref))
|
|
|
7f4c2a |
+
|
|
|
7f4c2a |
+/* GF_REF_PUT -- decrease the refcount of a GF_REF_DECL structure
|
|
|
7f4c2a |
+ *
|
|
|
7f4c2a |
+ * @return: greater then 0 when there are still references, 0 when cleanup
|
|
|
7f4c2a |
+ * should be done
|
|
|
7f4c2a |
+ */
|
|
|
7f4c2a |
+#define GF_REF_PUT(p) (_gf_ref_put (&p->_ref))
|
|
|
7f4c2a |
+
|
|
|
7f4c2a |
+
|
|
|
7f4c2a |
+#endif /* _REFCOUNT_H */
|
|
|
7f4c2a |
--
|
|
|
7f4c2a |
1.7.1
|
|
|
7f4c2a |
|