netdev.vger.kernel.org archive mirror
 help / color / mirror / Atom feed
From: Jacob Keller <jacob.e.keller@intel.com>
To: netdev@vger.kernel.org
Cc: jiri@resnulli.us, valex@mellanox.com, linyunsheng@huawei.com,
	lihong.yang@intel.com, kuba@kernel.org,
	Jacob Keller <jacob.e.keller@intel.com>
Subject: [RFC PATCH v2 13/22] devlink: track snapshot ids using an IDR and refcounts
Date: Fri, 14 Feb 2020 15:22:12 -0800	[thread overview]
Message-ID: <20200214232223.3442651-14-jacob.e.keller@intel.com> (raw)
In-Reply-To: <20200214232223.3442651-1-jacob.e.keller@intel.com>

New snapshot ids are generated by calling a getter function. The same id
may be used by multiple snapshots created at the same trigger event.

Currently no effort is made to release any previously used snapshot ids.

Replace the basic logic of using a single devlink integer for tracking
ids with the IDR interface.

snapshot IDs will be reference counted using a refcount stored in the
IDR. First, ids are allocated using idr_alloc without a refcount (using
the NULL pointer).

Once the devlink_region_snapshot_create function is called, it will call
the new __devlink_region_snapshot_id_ref(). This function will insert
a new refcount or increment the pre-existing refcount.

devlink_region_snapshot_destroy will call the new
__devlink_region_snapshot_id_deref(), decrementing the reference count.
Once there are no other references, the refcount will be removed from
IDR.

Signed-off-by: Jacob Keller <jacob.e.keller@intel.com>
---
 include/net/devlink.h |   3 +-
 net/core/devlink.c    | 141 ++++++++++++++++++++++++++++++++++++++++--
 2 files changed, 138 insertions(+), 6 deletions(-)

diff --git a/include/net/devlink.h b/include/net/devlink.h
index 3a7759355434..3a5ff6bea143 100644
--- a/include/net/devlink.h
+++ b/include/net/devlink.h
@@ -17,6 +17,7 @@
 #include <linux/refcount.h>
 #include <net/net_namespace.h>
 #include <uapi/linux/devlink.h>
+#include <linux/idr.h>
 
 struct devlink_ops;
 
@@ -28,13 +29,13 @@ struct devlink {
 	struct list_head resource_list;
 	struct list_head param_list;
 	struct list_head region_list;
-	u32 snapshot_id;
 	struct list_head reporter_list;
 	struct mutex reporters_lock; /* protects reporter_list */
 	struct devlink_dpipe_headers *dpipe_headers;
 	struct list_head trap_list;
 	struct list_head trap_group_list;
 	const struct devlink_ops *ops;
+	struct idr snapshot_idr;
 	struct device *dev;
 	possible_net_t _net;
 	struct mutex lock;
diff --git a/net/core/devlink.c b/net/core/devlink.c
index da4e669f425b..9571063846cc 100644
--- a/net/core/devlink.c
+++ b/net/core/devlink.c
@@ -3760,21 +3760,118 @@ static void devlink_nl_region_notify(struct devlink_region *region,
 	nlmsg_free(msg);
 }
 
+/**
+ * __devlink_region_snapshot_id_ref - Increment reference for a snapshot ID
+ *	@devlink: devlink instance
+ *	@id: the snapshot id being referenced
+ *
+ *	Increments the reference count for the given snapshot id. If the id
+ *	was not yet allocated, it is allocated immediately. If the id was
+ *	allocated but no references exist, a new refcount is created and
+ *	inserted.
+ */
+static int __devlink_region_snapshot_id_ref(struct devlink *devlink, u32 id)
+{
+	struct idr *idr = &devlink->snapshot_idr;
+	refcount_t *ref;
+	void *old_ptr;
+	int err;
+
+	lockdep_assert_held(&devlink->lock);
+
+	if (id < 1 || id >= INT_MAX)
+		return -EINVAL;
+
+	/* Check if a refcount already exists. If so, increment it and exit */
+	ref = idr_find(idr, id);
+	if (ref) {
+		refcount_inc(ref);
+		return 0;
+	}
+
+	/* Allocate a new reference count */
+	ref = kzalloc(sizeof(*ref), GFP_KERNEL);
+	refcount_set(ref, 1);
+
+	/* The id was likely allocated ahead of time using
+	 * devlink_region_snapshot_id_get, so attempt to replace the NULL
+	 * pointer with the refcount. Since idr_find returned NULL,
+	 * idr_replace should either return ERR_PTR(-ENOENT) or NULL.
+	 */
+	old_ptr = idr_replace(idr, ref, id);
+	/* if old_ptr is NULL, we've inserted the reference */
+	if (old_ptr == NULL)
+		return 0;
+	if (PTR_ERR(old_ptr) != -ENOENT) {
+		kfree(ref);
+		return PTR_ERR(old_ptr);
+	}
+
+	/* the snapshot id was not reserved, so reserve it now. */
+	err = idr_alloc(idr, ref, id, id+1, GFP_KERNEL);
+	if (err < 0)
+		return err;
+	WARN_ON(err != id);
+
+	return 0;
+}
+
+/**
+ * __devlink_region_snapshot_id_deref - Decrement reference for a snapshot ID
+ *	@devlink: devlink instance
+ *	@id: the snapshot id being referenced
+ *
+ *	Decrements the reference count for a given snapshot id. If the
+ *	refcount has reached zero then remove the reference from the IDR.
+ */
+static void __devlink_region_snapshot_id_deref(struct devlink *devlink, u32 id)
+{
+	struct idr *idr = &devlink->snapshot_idr;
+	refcount_t *ref;
+
+	lockdep_assert_held(&devlink->lock);
+
+	if (WARN_ON(id < 1 || id >= INT_MAX))
+		return;
+
+	/* Find the reference pointer */
+	ref = idr_find(idr, id);
+	if (!ref) {
+		WARN(true, "no previous reference was inserted");
+		/* this shouldn't happen, but at least attempt to cleanup if
+		 * something went wrong.
+		 */
+		idr_remove(idr, id);
+		return;
+	}
+
+	if (refcount_dec_and_test(ref)) {
+		/* There are no more references, so remove it from the IDR and
+		 * free the reference count.
+		 */
+		idr_remove(idr, id);
+		kfree(ref);
+	}
+}
+
 /**
  *	__devlink_region_snapshot_id_get - get snapshot ID
  *	@devlink: devlink instance
  *
  *	Returns a new snapshot id or a negative error code on failure. Must be
  *	called while holding the devlink instance lock.
+ *
+ *	Snapshot ids are stored in an IDR and reference counted by the number
+ *	of snapshots currently using that id. This function pre-allocates
+ *	a snapshot id but does not fill in a reference count. A later call to
+ *	devlink_region_snapshot_create will update the IDR pointer to
+ *	a reference count. On devlink_region_snapshot_destory, if there are no
+ *	further references, the id will be removed from the IDR.
  */
 static int __devlink_region_snapshot_id_get(struct devlink *devlink)
 {
 	lockdep_assert_held(&devlink->lock);
-
-	if (devlink->snapshot_id >= INT_MAX)
-		return -ENOSPC;
-
-	return ++devlink->snapshot_id;
+	return idr_alloc(&devlink->snapshot_idr, NULL, 1, INT_MAX, GFP_KERNEL);
 }
 
 /**
@@ -3797,6 +3894,7 @@ __devlink_region_snapshot_create(struct devlink_region *region,
 {
 	struct devlink *devlink = region->devlink;
 	struct devlink_snapshot *snapshot;
+	int err;
 
 	lockdep_assert_held(&devlink->lock);
 
@@ -3811,6 +3909,11 @@ __devlink_region_snapshot_create(struct devlink_region *region,
 	if (!snapshot)
 		return -ENOMEM;
 
+	/* Increment snapshot id reference */
+	err = __devlink_region_snapshot_id_ref(devlink, snapshot_id);
+	if (err)
+		goto err_free_snapshot;
+
 	snapshot->id = snapshot_id;
 	snapshot->region = region;
 	snapshot->data = data;
@@ -3821,15 +3924,25 @@ __devlink_region_snapshot_create(struct devlink_region *region,
 
 	devlink_nl_region_notify(region, snapshot, DEVLINK_CMD_REGION_NEW);
 	return 0;
+
+err_free_snapshot:
+	kfree(snapshot);
+	return err;
 }
 
 static void devlink_region_snapshot_del(struct devlink_region *region,
 					struct devlink_snapshot *snapshot)
 {
+	struct devlink *devlink = region->devlink;
+
+	lockdep_assert_held(&devlink_mutex);
+
 	devlink_nl_region_notify(region, snapshot, DEVLINK_CMD_REGION_DEL);
 	region->cur_snapshots--;
 	list_del(&snapshot->list);
 	region->ops->destructor(snapshot->data);
+	__devlink_region_snapshot_id_deref(devlink, snapshot->id);
+
 	kfree(snapshot);
 }
 
@@ -6388,6 +6501,7 @@ struct devlink *devlink_alloc(const struct devlink_ops *ops, size_t priv_size)
 	if (!devlink)
 		return NULL;
 	devlink->ops = ops;
+	idr_init(&devlink->snapshot_idr);
 	__devlink_net_set(devlink, &init_net);
 	INIT_LIST_HEAD(&devlink->port_list);
 	INIT_LIST_HEAD(&devlink->sb_list);
@@ -6480,6 +6594,23 @@ EXPORT_SYMBOL_GPL(devlink_reload_disable);
  */
 void devlink_free(struct devlink *devlink)
 {
+	struct idr *idr = &devlink->snapshot_idr;
+
+	mutex_lock(&devlink->lock);
+	if (!idr_is_empty(idr)) {
+		refcount_t *ref;
+		int id;
+
+		WARN(true, "snapshot IDR is not empty");
+
+		idr_for_each_entry(idr, ref, id) {
+			if (ref)
+				kfree(ref);
+		}
+	}
+	idr_destroy(&devlink->snapshot_idr);
+	mutex_unlock(&devlink->lock);
+
 	mutex_destroy(&devlink->reporters_lock);
 	mutex_destroy(&devlink->lock);
 	WARN_ON(!list_empty(&devlink->trap_group_list));
-- 
2.25.0.368.g28a2d05eebfb


  parent reply	other threads:[~2020-02-14 23:22 UTC|newest]

Thread overview: 59+ messages / expand[flat|nested]  mbox.gz  Atom feed  top
2020-02-14 23:21 [RFC PATCH v2 00/22] devlink region updates Jacob Keller
2020-02-14 23:22 ` [RFC PATCH v2 01/22] ice: use __le16 types for explicitly Little Endian values Jacob Keller
2020-02-14 23:22 ` [RFC PATCH v2 02/22] ice: create function to read a section of the NVM and Shadow RAM Jacob Keller
2020-02-14 23:22 ` [RFC PATCH v2 03/22] ice: implement full NVM read from ETHTOOL_GEEPROM Jacob Keller
2020-02-14 23:22 ` [RFC PATCH v2 04/22] ice: enable initial devlink support Jacob Keller
2020-03-02 16:30   ` Jiri Pirko
2020-03-02 19:29     ` Jacob Keller
2020-03-03 13:47       ` Jiri Pirko
2020-03-03 17:53         ` Jacob Keller
2020-02-14 23:22 ` [RFC PATCH v2 05/22] ice: rename variables used for Option ROM version Jacob Keller
2020-02-14 23:22 ` [RFC PATCH v2 06/22] ice: add basic handler for devlink .info_get Jacob Keller
2020-02-19  2:45   ` Jakub Kicinski
2020-02-19 17:33     ` Jacob Keller
2020-02-19 19:57       ` Jakub Kicinski
2020-02-19 21:37         ` Jacob Keller
2020-02-19 23:47           ` Jakub Kicinski
2020-02-20  0:06             ` Jacob Keller
2020-02-21 22:11               ` Jacob Keller
2020-02-14 23:22 ` [RFC PATCH v2 07/22] ice: add board identifier info to " Jacob Keller
2020-02-14 23:22 ` [RFC PATCH v2 08/22] devlink: prepare to support region operations Jacob Keller
2020-03-02 17:42   ` Jiri Pirko
2020-02-14 23:22 ` [RFC PATCH v2 09/22] devlink: convert snapshot destructor callback to region op Jacob Keller
2020-03-02 17:42   ` Jiri Pirko
2020-02-14 23:22 ` [RFC PATCH v2 10/22] devlink: trivial: fix tab in function documentation Jacob Keller
2020-03-02 17:42   ` Jiri Pirko
2020-02-14 23:22 ` [RFC PATCH v2 11/22] devlink: add functions to take snapshot while locked Jacob Keller
2020-03-02 17:43   ` Jiri Pirko
2020-03-02 22:25     ` Jacob Keller
2020-03-03  8:41       ` Jiri Pirko
2020-02-14 23:22 ` [RFC PATCH v2 12/22] devlink: convert snapshot id getter to return an error Jacob Keller
2020-03-02 17:44   ` Jiri Pirko
2020-02-14 23:22 ` Jacob Keller [this message]
2020-02-18 21:44   ` [RFC PATCH v2 13/22] devlink: track snapshot ids using an IDR and refcounts Jacob Keller
2020-02-14 23:22 ` [RFC PATCH v2 14/22] devlink: implement DEVLINK_CMD_REGION_NEW Jacob Keller
2020-03-02 17:41   ` Jiri Pirko
2020-03-02 19:38     ` Jacob Keller
2020-03-03  9:30       ` Jiri Pirko
2020-03-03 17:51         ` Jacob Keller
2020-03-04 11:58           ` Jiri Pirko
2020-03-04 17:43             ` Jacob Keller
2020-03-05  6:41               ` Jiri Pirko
2020-03-05 22:33                 ` Jacob Keller
2020-03-06  6:16                   ` Jiri Pirko
2020-03-02 22:11     ` Jacob Keller
2020-03-02 22:14     ` Jacob Keller
2020-03-02 22:35     ` Jacob Keller
2020-03-03  9:31       ` Jiri Pirko
2020-02-14 23:22 ` [RFC PATCH v2 15/22] netdevsim: support taking immediate snapshot via devlink Jacob Keller
2020-02-14 23:22 ` [RFC PATCH v2 16/22] devlink: simplify arguments for read_snapshot_fill Jacob Keller
2020-02-14 23:22 ` [RFC PATCH v2 17/22] devlink: use min_t to calculate data_size Jacob Keller
2020-02-14 23:22 ` [RFC PATCH v2 18/22] devlink: report extended error message in region_read_dumpit Jacob Keller
2020-02-14 23:22 ` [RFC PATCH v2 19/22] devlink: remove unnecessary parameter from chunk_fill function Jacob Keller
2020-02-14 23:22 ` [RFC PATCH v2 20/22] devlink: refactor region_read_snapshot_fill to use a callback function Jacob Keller
2020-02-14 23:22 ` [RFC PATCH v2 21/22] devlink: support directly reading from region memory Jacob Keller
2020-02-14 23:22 ` [RFC PATCH v2 22/22] ice: add a devlink region to dump shadow RAM contents Jacob Keller
2020-02-14 23:22 ` [RFC PATCH v2 1/2] devlink: add support for DEVLINK_CMD_REGION_NEW Jacob Keller
2020-02-14 23:22 ` [RFC PATCH v2 2/2] devlink: stop requiring snapshot for regions Jacob Keller
2020-03-02 16:27 ` [RFC PATCH v2 00/22] devlink region updates Jiri Pirko
2020-03-02 19:27   ` Jacob Keller

Reply instructions:

You may reply publicly to this message via plain-text email
using any one of the following methods:

* Save the following mbox file, import it into your mail client,
  and reply-to-all from there: mbox

  Avoid top-posting and favor interleaved quoting:
  https://en.wikipedia.org/wiki/Posting_style#Interleaved_style

* Reply using the --to, --cc, and --in-reply-to
  switches of git-send-email(1):

  git send-email \
    --in-reply-to=20200214232223.3442651-14-jacob.e.keller@intel.com \
    --to=jacob.e.keller@intel.com \
    --cc=jiri@resnulli.us \
    --cc=kuba@kernel.org \
    --cc=lihong.yang@intel.com \
    --cc=linyunsheng@huawei.com \
    --cc=netdev@vger.kernel.org \
    --cc=valex@mellanox.com \
    /path/to/YOUR_REPLY

  https://kernel.org/pub/software/scm/git/docs/git-send-email.html

* If your mail client supports setting the In-Reply-To header
  via mailto: links, try the mailto: link
Be sure your reply has a Subject: header at the top and a blank line before the message body.
This is a public inbox, see mirroring instructions
for how to clone and mirror all data and code used for this inbox;
as well as URLs for NNTP newsgroup(s).