// 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 objagg_hints_node { … }; static struct objagg_hints_node * objagg_hints_lookup(struct objagg_hints *objagg_hints, void *obj) { … } struct objagg { … }; struct objagg_obj { … }; static unsigned int objagg_obj_ref_inc(struct objagg_obj *objagg_obj) { … } static unsigned int objagg_obj_ref_dec(struct objagg_obj *objagg_obj) { … } static void objagg_obj_stats_inc(struct objagg_obj *objagg_obj) { … } static void objagg_obj_stats_dec(struct objagg_obj *objagg_obj) { … } static bool objagg_obj_is_root(const struct objagg_obj *objagg_obj) { … } /** * 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) { … } EXPORT_SYMBOL(…); /** * 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) { … } EXPORT_SYMBOL(…); /** * 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) { … } EXPORT_SYMBOL(…); static struct objagg_obj *objagg_obj_lookup(struct objagg *objagg, void *obj) { … } static int objagg_obj_parent_assign(struct objagg *objagg, struct objagg_obj *objagg_obj, struct objagg_obj *parent, bool take_parent_ref) { … } static int objagg_obj_parent_lookup_assign(struct objagg *objagg, struct objagg_obj *objagg_obj) { … } static void __objagg_obj_put(struct objagg *objagg, struct objagg_obj *objagg_obj); static void objagg_obj_parent_unassign(struct objagg *objagg, struct objagg_obj *objagg_obj) { … } static int objagg_obj_root_id_alloc(struct objagg *objagg, struct objagg_obj *objagg_obj, struct objagg_hints_node *hnode) { … } static void objagg_obj_root_id_free(struct objagg *objagg, struct objagg_obj *objagg_obj) { … } static int objagg_obj_root_create(struct objagg *objagg, struct objagg_obj *objagg_obj, struct objagg_hints_node *hnode) { … } static void objagg_obj_root_destroy(struct objagg *objagg, struct objagg_obj *objagg_obj) { … } static struct objagg_obj *__objagg_obj_get(struct objagg *objagg, void *obj); static int objagg_obj_init_with_hints(struct objagg *objagg, struct objagg_obj *objagg_obj, bool *hint_found) { … } static int objagg_obj_init(struct objagg *objagg, struct objagg_obj *objagg_obj) { … } static void objagg_obj_fini(struct objagg *objagg, struct objagg_obj *objagg_obj) { … } static struct objagg_obj *objagg_obj_create(struct objagg *objagg, void *obj) { … } static struct objagg_obj *__objagg_obj_get(struct objagg *objagg, void *obj) { … } /** * objagg_obj_get - gets an object within objagg instance * @objagg: objagg instance * @obj: user-specific private object pointer * * Note: all locking must be provided by the caller. * * Size of the "obj" memory is specified in "objagg->ops". * * There are 3 main options this function wraps: * 1) The object according to "obj" already exist. In that case * the reference counter is incremented and the object is returned. * 2) The object does not exist, but it can be aggregated within * another object. In that case, user ops->delta_create() is called * to obtain delta data and a new object is created with returned * user-delta private pointer. * 3) The object does not exist and cannot be aggregated into * any of the existing objects. In that case, user ops->root_create() * is called to create the root and a new object is created with * returned user-root private pointer. * * Returns a pointer to objagg object instance in case of success, * otherwise it returns pointer error using ERR_PTR macro. */ struct objagg_obj *objagg_obj_get(struct objagg *objagg, void *obj) { … } EXPORT_SYMBOL(…); static void objagg_obj_destroy(struct objagg *objagg, struct objagg_obj *objagg_obj) { … } static void __objagg_obj_put(struct objagg *objagg, struct objagg_obj *objagg_obj) { … } /** * objagg_obj_put - puts an object within objagg instance * @objagg: objagg instance * @objagg_obj: objagg object instance * * Note: all locking must be provided by the caller. * * Symmetric to objagg_obj_get(). */ void objagg_obj_put(struct objagg *objagg, struct objagg_obj *objagg_obj) { … } EXPORT_SYMBOL(…); /** * objagg_create - creates a new objagg instance * @ops: user-specific callbacks * @objagg_hints: hints, can be NULL * @priv: pointer to a private data passed to the ops * * Note: all locking must be provided by the caller. * * The purpose of the library is to provide an infrastructure to * aggregate user-specified objects. Library does not care about the type * of the object. User fills-up ops which take care of the specific * user object manipulation. * * As a very stupid example, consider integer numbers. For example * number 8 as a root object. That can aggregate number 9 with delta 1, * number 10 with delta 2, etc. This example is implemented as * a part of a testing module in test_objagg.c file. * * Each objagg instance contains multiple trees. Each tree node is * represented by "an object". In the current implementation there can be * only roots and leafs nodes. Leaf nodes are called deltas. * But in general, this can be easily extended for intermediate nodes. * In that extension, a delta would be associated with all non-root * nodes. * * Returns a pointer to newly created objagg instance in case of success, * otherwise it returns pointer error using ERR_PTR macro. */ struct objagg *objagg_create(const struct objagg_ops *ops, struct objagg_hints *objagg_hints, void *priv) { … } EXPORT_SYMBOL(…); /** * objagg_destroy - destroys a new objagg instance * @objagg: objagg instance * * Note: all locking must be provided by the caller. */ void objagg_destroy(struct objagg *objagg) { … } EXPORT_SYMBOL(…); static int objagg_stats_info_sort_cmp_func(const void *a, const void *b) { … } /** * objagg_stats_get - obtains stats of the objagg instance * @objagg: objagg instance * * Note: all locking must be provided by the caller. * * The returned structure contains statistics of all object * currently in use, ordered by following rules: * 1) Root objects are always on lower indexes than the rest. * 2) Objects with higher delta user count are always on lower * indexes. * 3) In case more objects have the same delta user count, * the objects are ordered by user count. * * Returns a pointer to stats instance in case of success, * otherwise it returns pointer error using ERR_PTR macro. */ const struct objagg_stats *objagg_stats_get(struct objagg *objagg) { … } EXPORT_SYMBOL(…); /** * objagg_stats_put - puts stats of the objagg instance * @objagg_stats: objagg instance stats * * Note: all locking must be provided by the caller. */ void objagg_stats_put(const struct objagg_stats *objagg_stats) { … } EXPORT_SYMBOL(…); static struct objagg_hints_node * objagg_hints_node_create(struct objagg_hints *objagg_hints, struct objagg_obj *objagg_obj, size_t obj_size, struct objagg_hints_node *parent_hnode) { … } static void objagg_hints_flush(struct objagg_hints *objagg_hints) { … } struct objagg_tmp_node { … }; struct objagg_tmp_graph { … }; static int objagg_tmp_graph_edge_index(struct objagg_tmp_graph *graph, int parent_index, int index) { … } static void objagg_tmp_graph_edge_set(struct objagg_tmp_graph *graph, int parent_index, int index) { … } static bool objagg_tmp_graph_is_edge(struct objagg_tmp_graph *graph, int parent_index, int index) { … } static unsigned int objagg_tmp_graph_node_weight(struct objagg_tmp_graph *graph, unsigned int index) { … } static int objagg_tmp_graph_node_max_weight(struct objagg_tmp_graph *graph) { … } static struct objagg_tmp_graph *objagg_tmp_graph_create(struct objagg *objagg) { … } static void objagg_tmp_graph_destroy(struct objagg_tmp_graph *graph) { … } static int objagg_opt_simple_greedy_fillup_hints(struct objagg_hints *objagg_hints, struct objagg *objagg) { … } struct objagg_opt_algo { … }; static const struct objagg_opt_algo objagg_opt_simple_greedy = …; static const struct objagg_opt_algo *objagg_opt_algos[] = …; /** * objagg_hints_get - obtains hints instance * @objagg: objagg instance * @opt_algo_type: type of hints finding algorithm * * Note: all locking must be provided by the caller. * * According to the algo type, the existing objects of objagg instance * are going to be went-through to assemble an optimal tree. We call this * tree hints. These hints can be later on used for creation of * a new objagg instance. There, the future object creations are going * to be consulted with these hints in order to find out, where exactly * the new object should be put as a root or delta. * * Returns a pointer to hints instance in case of success, * otherwise it returns pointer error using ERR_PTR macro. */ struct objagg_hints *objagg_hints_get(struct objagg *objagg, enum objagg_opt_algo_type opt_algo_type) { … } EXPORT_SYMBOL(…); /** * objagg_hints_put - puts hints instance * @objagg_hints: objagg hints instance * * Note: all locking must be provided by the caller. */ void objagg_hints_put(struct objagg_hints *objagg_hints) { … } EXPORT_SYMBOL(…); /** * objagg_hints_stats_get - obtains stats of the hints instance * @objagg_hints: hints instance * * Note: all locking must be provided by the caller. * * The returned structure contains statistics of all objects * currently in use, ordered by following rules: * 1) Root objects are always on lower indexes than the rest. * 2) Objects with higher delta user count are always on lower * indexes. * 3) In case multiple objects have the same delta user count, * the objects are ordered by user count. * * Returns a pointer to stats instance in case of success, * otherwise it returns pointer error using ERR_PTR macro. */ const struct objagg_stats * objagg_hints_stats_get(struct objagg_hints *objagg_hints) { … } EXPORT_SYMBOL(…); MODULE_LICENSE(…) …; MODULE_AUTHOR(…) …; MODULE_DESCRIPTION(…) …;