// SPDX-License-Identifier: BSD-3-Clause OR GPL-2.0
/* Copyright (c) 2018 Mellanox Technologies. All rights reserved */
#include <linux/module.h>
#include <linux/slab.h>
#include <linux/rhashtable.h>
#include <linux/idr.h>
#include <linux/list.h>
#include <linux/sort.h>
#include <linux/objagg.h>
#define CREATE_TRACE_POINTS
#include <trace/events/objagg.h>
struct objagg_hints {
struct rhashtable node_ht;
struct rhashtable_params ht_params;
struct list_head node_list;
unsigned int node_count;
unsigned int root_count;
unsigned int refcount;
const struct objagg_ops *ops;
};
struct objagg_hints_node {
struct rhash_head ht_node; /* member of objagg_hints->node_ht */
struct list_head list; /* member of objagg_hints->node_list */
struct objagg_hints_node *parent;
unsigned int root_id;
struct objagg_obj_stats_info stats_info;
unsigned long obj[];
};
static struct objagg_hints_node *
objagg_hints_lookup(struct objagg_hints *objagg_hints, void *obj)
{
if (!objagg_hints)
return NULL;
return rhashtable_lookup_fast(&objagg_hints->node_ht, obj,
objagg_hints->ht_params);
}
struct objagg {
const struct objagg_ops *ops;
void *priv;
struct rhashtable obj_ht;
struct rhashtable_params ht_params;
struct list_head obj_list;
unsigned int obj_count;
struct ida root_ida;
struct objagg_hints *hints;
};
struct objagg_obj {
struct rhash_head ht_node; /* member of objagg->obj_ht */
struct list_head list; /* member of objagg->obj_list */
struct objagg_obj *parent; /* if the object is nested, this
* holds pointer to parent, otherwise NULL
*/
union {
void *delta_priv; /* user delta private */
void *root_priv; /* user root private */
};
unsigned int root_id;
unsigned int refcount; /* counts number of users of this object
* including nested objects
*/
struct objagg_obj_stats stats;
unsigned long obj[];
};
static unsigned int objagg_obj_ref_inc(struct objagg_obj *objagg_obj)
{
return ++objagg_obj->refcount;
}
static unsigned int objagg_obj_ref_dec(struct objagg_obj *objagg_obj)
{
return --objagg_obj->refcount;
}
static void objagg_obj_stats_inc(struct objagg_obj *objagg_obj)
{
objagg_obj->stats.user_count++;
objagg_obj->stats.delta_user_count++;
if (objagg_obj->parent)
objagg_obj->parent->stats.delta_user_count++;
}
static void objagg_obj_stats_dec(struct objagg_obj *objagg_obj)
{
objagg_obj->stats.user_count--;
objagg_obj->stats.delta_user_count--;
if (objagg_obj->parent)
objagg_obj->parent->stats.delta_user_count--;
}
static bool objagg_obj_is_root(const struct objagg_obj *objagg_obj)
{
/* Nesting is not supported, so we can use ->parent
* to figure out if the object is root.
*/
return !objagg_obj->parent;
}
/**
* objagg_obj_root_priv - obtains root private for an object
* @objagg_obj: objagg object instance
*
* Note: all locking must be provided by the caller.
*
* Either the object is root itself when the private is returned
* directly, or the parent is root and its private is returned
* instead.
*
* Returns a user private root pointer.
*/
const void *objagg_obj_root_priv(const struct objagg_obj *objagg_obj)
{
if (objagg_obj_is_root(objagg_obj))
return objagg_obj->root_priv;
WARN_ON(!objagg_obj_is_root(objagg_obj->parent));
return objagg_obj->parent->root_priv;
}
EXPORT_SYMBOL(objagg_obj_root_priv);
/**
* objagg_obj_delta_priv - obtains delta private for an object
* @objagg_obj: objagg object instance
*
* Note: all locking must be provided by the caller.
*
* Returns user private delta pointer or NULL in case the passed
* object is root.
*/
const void *objagg_obj_delta_priv(const struct objagg_obj *objagg_obj)
{
if (objagg_obj_is_root(objagg_obj))
return NULL;
return objagg_obj->delta_priv;
}
EXPORT_SYMBOL(objagg_obj_delta_priv);
/**
* objagg_obj_raw - obtains object user private pointer
* @objagg_obj: objagg object instance
*
* Note: all locking must be provided by the caller.
*
* Returns user private pointer as was passed to objagg_obj_get() by "obj" arg.
*/
const void *objagg_obj_raw(const struct objagg_obj *objagg_obj)
{
return objagg_obj->obj;
}
EXPORT_SYMBOL(objagg_obj_raw);
static struct objagg_obj *objagg_obj_lookup(struct objagg *objagg, void *obj)
{
return rhashtable_lookup_fast(&objagg->obj_ht, obj, objagg->ht_params);
}
static int objagg_obj_parent_assign(struct objagg *objagg,
struct objagg_obj *objagg_obj,