162306a36Sopenharmony_ci// SPDX-License-Identifier: BSD-3-Clause OR GPL-2.0 262306a36Sopenharmony_ci/* Copyright (c) 2018 Mellanox Technologies. All rights reserved */ 362306a36Sopenharmony_ci 462306a36Sopenharmony_ci#include <linux/module.h> 562306a36Sopenharmony_ci#include <linux/slab.h> 662306a36Sopenharmony_ci#include <linux/rhashtable.h> 762306a36Sopenharmony_ci#include <linux/idr.h> 862306a36Sopenharmony_ci#include <linux/list.h> 962306a36Sopenharmony_ci#include <linux/sort.h> 1062306a36Sopenharmony_ci#include <linux/objagg.h> 1162306a36Sopenharmony_ci 1262306a36Sopenharmony_ci#define CREATE_TRACE_POINTS 1362306a36Sopenharmony_ci#include <trace/events/objagg.h> 1462306a36Sopenharmony_ci 1562306a36Sopenharmony_cistruct objagg_hints { 1662306a36Sopenharmony_ci struct rhashtable node_ht; 1762306a36Sopenharmony_ci struct rhashtable_params ht_params; 1862306a36Sopenharmony_ci struct list_head node_list; 1962306a36Sopenharmony_ci unsigned int node_count; 2062306a36Sopenharmony_ci unsigned int root_count; 2162306a36Sopenharmony_ci unsigned int refcount; 2262306a36Sopenharmony_ci const struct objagg_ops *ops; 2362306a36Sopenharmony_ci}; 2462306a36Sopenharmony_ci 2562306a36Sopenharmony_cistruct objagg_hints_node { 2662306a36Sopenharmony_ci struct rhash_head ht_node; /* member of objagg_hints->node_ht */ 2762306a36Sopenharmony_ci struct list_head list; /* member of objagg_hints->node_list */ 2862306a36Sopenharmony_ci struct objagg_hints_node *parent; 2962306a36Sopenharmony_ci unsigned int root_id; 3062306a36Sopenharmony_ci struct objagg_obj_stats_info stats_info; 3162306a36Sopenharmony_ci unsigned long obj[]; 3262306a36Sopenharmony_ci}; 3362306a36Sopenharmony_ci 3462306a36Sopenharmony_cistatic struct objagg_hints_node * 3562306a36Sopenharmony_ciobjagg_hints_lookup(struct objagg_hints *objagg_hints, void *obj) 3662306a36Sopenharmony_ci{ 3762306a36Sopenharmony_ci if (!objagg_hints) 3862306a36Sopenharmony_ci return NULL; 3962306a36Sopenharmony_ci return rhashtable_lookup_fast(&objagg_hints->node_ht, obj, 4062306a36Sopenharmony_ci objagg_hints->ht_params); 4162306a36Sopenharmony_ci} 4262306a36Sopenharmony_ci 4362306a36Sopenharmony_cistruct objagg { 4462306a36Sopenharmony_ci const struct objagg_ops *ops; 4562306a36Sopenharmony_ci void *priv; 4662306a36Sopenharmony_ci struct rhashtable obj_ht; 4762306a36Sopenharmony_ci struct rhashtable_params ht_params; 4862306a36Sopenharmony_ci struct list_head obj_list; 4962306a36Sopenharmony_ci unsigned int obj_count; 5062306a36Sopenharmony_ci struct ida root_ida; 5162306a36Sopenharmony_ci struct objagg_hints *hints; 5262306a36Sopenharmony_ci}; 5362306a36Sopenharmony_ci 5462306a36Sopenharmony_cistruct objagg_obj { 5562306a36Sopenharmony_ci struct rhash_head ht_node; /* member of objagg->obj_ht */ 5662306a36Sopenharmony_ci struct list_head list; /* member of objagg->obj_list */ 5762306a36Sopenharmony_ci struct objagg_obj *parent; /* if the object is nested, this 5862306a36Sopenharmony_ci * holds pointer to parent, otherwise NULL 5962306a36Sopenharmony_ci */ 6062306a36Sopenharmony_ci union { 6162306a36Sopenharmony_ci void *delta_priv; /* user delta private */ 6262306a36Sopenharmony_ci void *root_priv; /* user root private */ 6362306a36Sopenharmony_ci }; 6462306a36Sopenharmony_ci unsigned int root_id; 6562306a36Sopenharmony_ci unsigned int refcount; /* counts number of users of this object 6662306a36Sopenharmony_ci * including nested objects 6762306a36Sopenharmony_ci */ 6862306a36Sopenharmony_ci struct objagg_obj_stats stats; 6962306a36Sopenharmony_ci unsigned long obj[]; 7062306a36Sopenharmony_ci}; 7162306a36Sopenharmony_ci 7262306a36Sopenharmony_cistatic unsigned int objagg_obj_ref_inc(struct objagg_obj *objagg_obj) 7362306a36Sopenharmony_ci{ 7462306a36Sopenharmony_ci return ++objagg_obj->refcount; 7562306a36Sopenharmony_ci} 7662306a36Sopenharmony_ci 7762306a36Sopenharmony_cistatic unsigned int objagg_obj_ref_dec(struct objagg_obj *objagg_obj) 7862306a36Sopenharmony_ci{ 7962306a36Sopenharmony_ci return --objagg_obj->refcount; 8062306a36Sopenharmony_ci} 8162306a36Sopenharmony_ci 8262306a36Sopenharmony_cistatic void objagg_obj_stats_inc(struct objagg_obj *objagg_obj) 8362306a36Sopenharmony_ci{ 8462306a36Sopenharmony_ci objagg_obj->stats.user_count++; 8562306a36Sopenharmony_ci objagg_obj->stats.delta_user_count++; 8662306a36Sopenharmony_ci if (objagg_obj->parent) 8762306a36Sopenharmony_ci objagg_obj->parent->stats.delta_user_count++; 8862306a36Sopenharmony_ci} 8962306a36Sopenharmony_ci 9062306a36Sopenharmony_cistatic void objagg_obj_stats_dec(struct objagg_obj *objagg_obj) 9162306a36Sopenharmony_ci{ 9262306a36Sopenharmony_ci objagg_obj->stats.user_count--; 9362306a36Sopenharmony_ci objagg_obj->stats.delta_user_count--; 9462306a36Sopenharmony_ci if (objagg_obj->parent) 9562306a36Sopenharmony_ci objagg_obj->parent->stats.delta_user_count--; 9662306a36Sopenharmony_ci} 9762306a36Sopenharmony_ci 9862306a36Sopenharmony_cistatic bool objagg_obj_is_root(const struct objagg_obj *objagg_obj) 9962306a36Sopenharmony_ci{ 10062306a36Sopenharmony_ci /* Nesting is not supported, so we can use ->parent 10162306a36Sopenharmony_ci * to figure out if the object is root. 10262306a36Sopenharmony_ci */ 10362306a36Sopenharmony_ci return !objagg_obj->parent; 10462306a36Sopenharmony_ci} 10562306a36Sopenharmony_ci 10662306a36Sopenharmony_ci/** 10762306a36Sopenharmony_ci * objagg_obj_root_priv - obtains root private for an object 10862306a36Sopenharmony_ci * @objagg_obj: objagg object instance 10962306a36Sopenharmony_ci * 11062306a36Sopenharmony_ci * Note: all locking must be provided by the caller. 11162306a36Sopenharmony_ci * 11262306a36Sopenharmony_ci * Either the object is root itself when the private is returned 11362306a36Sopenharmony_ci * directly, or the parent is root and its private is returned 11462306a36Sopenharmony_ci * instead. 11562306a36Sopenharmony_ci * 11662306a36Sopenharmony_ci * Returns a user private root pointer. 11762306a36Sopenharmony_ci */ 11862306a36Sopenharmony_ciconst void *objagg_obj_root_priv(const struct objagg_obj *objagg_obj) 11962306a36Sopenharmony_ci{ 12062306a36Sopenharmony_ci if (objagg_obj_is_root(objagg_obj)) 12162306a36Sopenharmony_ci return objagg_obj->root_priv; 12262306a36Sopenharmony_ci WARN_ON(!objagg_obj_is_root(objagg_obj->parent)); 12362306a36Sopenharmony_ci return objagg_obj->parent->root_priv; 12462306a36Sopenharmony_ci} 12562306a36Sopenharmony_ciEXPORT_SYMBOL(objagg_obj_root_priv); 12662306a36Sopenharmony_ci 12762306a36Sopenharmony_ci/** 12862306a36Sopenharmony_ci * objagg_obj_delta_priv - obtains delta private for an object 12962306a36Sopenharmony_ci * @objagg_obj: objagg object instance 13062306a36Sopenharmony_ci * 13162306a36Sopenharmony_ci * Note: all locking must be provided by the caller. 13262306a36Sopenharmony_ci * 13362306a36Sopenharmony_ci * Returns user private delta pointer or NULL in case the passed 13462306a36Sopenharmony_ci * object is root. 13562306a36Sopenharmony_ci */ 13662306a36Sopenharmony_ciconst void *objagg_obj_delta_priv(const struct objagg_obj *objagg_obj) 13762306a36Sopenharmony_ci{ 13862306a36Sopenharmony_ci if (objagg_obj_is_root(objagg_obj)) 13962306a36Sopenharmony_ci return NULL; 14062306a36Sopenharmony_ci return objagg_obj->delta_priv; 14162306a36Sopenharmony_ci} 14262306a36Sopenharmony_ciEXPORT_SYMBOL(objagg_obj_delta_priv); 14362306a36Sopenharmony_ci 14462306a36Sopenharmony_ci/** 14562306a36Sopenharmony_ci * objagg_obj_raw - obtains object user private pointer 14662306a36Sopenharmony_ci * @objagg_obj: objagg object instance 14762306a36Sopenharmony_ci * 14862306a36Sopenharmony_ci * Note: all locking must be provided by the caller. 14962306a36Sopenharmony_ci * 15062306a36Sopenharmony_ci * Returns user private pointer as was passed to objagg_obj_get() by "obj" arg. 15162306a36Sopenharmony_ci */ 15262306a36Sopenharmony_ciconst void *objagg_obj_raw(const struct objagg_obj *objagg_obj) 15362306a36Sopenharmony_ci{ 15462306a36Sopenharmony_ci return objagg_obj->obj; 15562306a36Sopenharmony_ci} 15662306a36Sopenharmony_ciEXPORT_SYMBOL(objagg_obj_raw); 15762306a36Sopenharmony_ci 15862306a36Sopenharmony_cistatic struct objagg_obj *objagg_obj_lookup(struct objagg *objagg, void *obj) 15962306a36Sopenharmony_ci{ 16062306a36Sopenharmony_ci return rhashtable_lookup_fast(&objagg->obj_ht, obj, objagg->ht_params); 16162306a36Sopenharmony_ci} 16262306a36Sopenharmony_ci 16362306a36Sopenharmony_cistatic int objagg_obj_parent_assign(struct objagg *objagg, 16462306a36Sopenharmony_ci struct objagg_obj *objagg_obj, 16562306a36Sopenharmony_ci struct objagg_obj *parent, 16662306a36Sopenharmony_ci bool take_parent_ref) 16762306a36Sopenharmony_ci{ 16862306a36Sopenharmony_ci void *delta_priv; 16962306a36Sopenharmony_ci 17062306a36Sopenharmony_ci delta_priv = objagg->ops->delta_create(objagg->priv, parent->obj, 17162306a36Sopenharmony_ci objagg_obj->obj); 17262306a36Sopenharmony_ci if (IS_ERR(delta_priv)) 17362306a36Sopenharmony_ci return PTR_ERR(delta_priv); 17462306a36Sopenharmony_ci 17562306a36Sopenharmony_ci /* User returned a delta private, that means that 17662306a36Sopenharmony_ci * our object can be aggregated into the parent. 17762306a36Sopenharmony_ci */ 17862306a36Sopenharmony_ci objagg_obj->parent = parent; 17962306a36Sopenharmony_ci objagg_obj->delta_priv = delta_priv; 18062306a36Sopenharmony_ci if (take_parent_ref) 18162306a36Sopenharmony_ci objagg_obj_ref_inc(objagg_obj->parent); 18262306a36Sopenharmony_ci trace_objagg_obj_parent_assign(objagg, objagg_obj, 18362306a36Sopenharmony_ci parent, 18462306a36Sopenharmony_ci parent->refcount); 18562306a36Sopenharmony_ci return 0; 18662306a36Sopenharmony_ci} 18762306a36Sopenharmony_ci 18862306a36Sopenharmony_cistatic int objagg_obj_parent_lookup_assign(struct objagg *objagg, 18962306a36Sopenharmony_ci struct objagg_obj *objagg_obj) 19062306a36Sopenharmony_ci{ 19162306a36Sopenharmony_ci struct objagg_obj *objagg_obj_cur; 19262306a36Sopenharmony_ci int err; 19362306a36Sopenharmony_ci 19462306a36Sopenharmony_ci list_for_each_entry(objagg_obj_cur, &objagg->obj_list, list) { 19562306a36Sopenharmony_ci /* Nesting is not supported. In case the object 19662306a36Sopenharmony_ci * is not root, it cannot be assigned as parent. 19762306a36Sopenharmony_ci */ 19862306a36Sopenharmony_ci if (!objagg_obj_is_root(objagg_obj_cur)) 19962306a36Sopenharmony_ci continue; 20062306a36Sopenharmony_ci err = objagg_obj_parent_assign(objagg, objagg_obj, 20162306a36Sopenharmony_ci objagg_obj_cur, true); 20262306a36Sopenharmony_ci if (!err) 20362306a36Sopenharmony_ci return 0; 20462306a36Sopenharmony_ci } 20562306a36Sopenharmony_ci return -ENOENT; 20662306a36Sopenharmony_ci} 20762306a36Sopenharmony_ci 20862306a36Sopenharmony_cistatic void __objagg_obj_put(struct objagg *objagg, 20962306a36Sopenharmony_ci struct objagg_obj *objagg_obj); 21062306a36Sopenharmony_ci 21162306a36Sopenharmony_cistatic void objagg_obj_parent_unassign(struct objagg *objagg, 21262306a36Sopenharmony_ci struct objagg_obj *objagg_obj) 21362306a36Sopenharmony_ci{ 21462306a36Sopenharmony_ci trace_objagg_obj_parent_unassign(objagg, objagg_obj, 21562306a36Sopenharmony_ci objagg_obj->parent, 21662306a36Sopenharmony_ci objagg_obj->parent->refcount); 21762306a36Sopenharmony_ci objagg->ops->delta_destroy(objagg->priv, objagg_obj->delta_priv); 21862306a36Sopenharmony_ci __objagg_obj_put(objagg, objagg_obj->parent); 21962306a36Sopenharmony_ci} 22062306a36Sopenharmony_ci 22162306a36Sopenharmony_cistatic int objagg_obj_root_id_alloc(struct objagg *objagg, 22262306a36Sopenharmony_ci struct objagg_obj *objagg_obj, 22362306a36Sopenharmony_ci struct objagg_hints_node *hnode) 22462306a36Sopenharmony_ci{ 22562306a36Sopenharmony_ci unsigned int min, max; 22662306a36Sopenharmony_ci int root_id; 22762306a36Sopenharmony_ci 22862306a36Sopenharmony_ci /* In case there are no hints available, the root id is invalid. */ 22962306a36Sopenharmony_ci if (!objagg->hints) { 23062306a36Sopenharmony_ci objagg_obj->root_id = OBJAGG_OBJ_ROOT_ID_INVALID; 23162306a36Sopenharmony_ci return 0; 23262306a36Sopenharmony_ci } 23362306a36Sopenharmony_ci 23462306a36Sopenharmony_ci if (hnode) { 23562306a36Sopenharmony_ci min = hnode->root_id; 23662306a36Sopenharmony_ci max = hnode->root_id; 23762306a36Sopenharmony_ci } else { 23862306a36Sopenharmony_ci /* For objects with no hint, start after the last 23962306a36Sopenharmony_ci * hinted root_id. 24062306a36Sopenharmony_ci */ 24162306a36Sopenharmony_ci min = objagg->hints->root_count; 24262306a36Sopenharmony_ci max = ~0; 24362306a36Sopenharmony_ci } 24462306a36Sopenharmony_ci 24562306a36Sopenharmony_ci root_id = ida_alloc_range(&objagg->root_ida, min, max, GFP_KERNEL); 24662306a36Sopenharmony_ci 24762306a36Sopenharmony_ci if (root_id < 0) 24862306a36Sopenharmony_ci return root_id; 24962306a36Sopenharmony_ci objagg_obj->root_id = root_id; 25062306a36Sopenharmony_ci return 0; 25162306a36Sopenharmony_ci} 25262306a36Sopenharmony_ci 25362306a36Sopenharmony_cistatic void objagg_obj_root_id_free(struct objagg *objagg, 25462306a36Sopenharmony_ci struct objagg_obj *objagg_obj) 25562306a36Sopenharmony_ci{ 25662306a36Sopenharmony_ci if (!objagg->hints) 25762306a36Sopenharmony_ci return; 25862306a36Sopenharmony_ci ida_free(&objagg->root_ida, objagg_obj->root_id); 25962306a36Sopenharmony_ci} 26062306a36Sopenharmony_ci 26162306a36Sopenharmony_cistatic int objagg_obj_root_create(struct objagg *objagg, 26262306a36Sopenharmony_ci struct objagg_obj *objagg_obj, 26362306a36Sopenharmony_ci struct objagg_hints_node *hnode) 26462306a36Sopenharmony_ci{ 26562306a36Sopenharmony_ci int err; 26662306a36Sopenharmony_ci 26762306a36Sopenharmony_ci err = objagg_obj_root_id_alloc(objagg, objagg_obj, hnode); 26862306a36Sopenharmony_ci if (err) 26962306a36Sopenharmony_ci return err; 27062306a36Sopenharmony_ci objagg_obj->root_priv = objagg->ops->root_create(objagg->priv, 27162306a36Sopenharmony_ci objagg_obj->obj, 27262306a36Sopenharmony_ci objagg_obj->root_id); 27362306a36Sopenharmony_ci if (IS_ERR(objagg_obj->root_priv)) { 27462306a36Sopenharmony_ci err = PTR_ERR(objagg_obj->root_priv); 27562306a36Sopenharmony_ci goto err_root_create; 27662306a36Sopenharmony_ci } 27762306a36Sopenharmony_ci trace_objagg_obj_root_create(objagg, objagg_obj); 27862306a36Sopenharmony_ci return 0; 27962306a36Sopenharmony_ci 28062306a36Sopenharmony_cierr_root_create: 28162306a36Sopenharmony_ci objagg_obj_root_id_free(objagg, objagg_obj); 28262306a36Sopenharmony_ci return err; 28362306a36Sopenharmony_ci} 28462306a36Sopenharmony_ci 28562306a36Sopenharmony_cistatic void objagg_obj_root_destroy(struct objagg *objagg, 28662306a36Sopenharmony_ci struct objagg_obj *objagg_obj) 28762306a36Sopenharmony_ci{ 28862306a36Sopenharmony_ci trace_objagg_obj_root_destroy(objagg, objagg_obj); 28962306a36Sopenharmony_ci objagg->ops->root_destroy(objagg->priv, objagg_obj->root_priv); 29062306a36Sopenharmony_ci objagg_obj_root_id_free(objagg, objagg_obj); 29162306a36Sopenharmony_ci} 29262306a36Sopenharmony_ci 29362306a36Sopenharmony_cistatic struct objagg_obj *__objagg_obj_get(struct objagg *objagg, void *obj); 29462306a36Sopenharmony_ci 29562306a36Sopenharmony_cistatic int objagg_obj_init_with_hints(struct objagg *objagg, 29662306a36Sopenharmony_ci struct objagg_obj *objagg_obj, 29762306a36Sopenharmony_ci bool *hint_found) 29862306a36Sopenharmony_ci{ 29962306a36Sopenharmony_ci struct objagg_hints_node *hnode; 30062306a36Sopenharmony_ci struct objagg_obj *parent; 30162306a36Sopenharmony_ci int err; 30262306a36Sopenharmony_ci 30362306a36Sopenharmony_ci hnode = objagg_hints_lookup(objagg->hints, objagg_obj->obj); 30462306a36Sopenharmony_ci if (!hnode) { 30562306a36Sopenharmony_ci *hint_found = false; 30662306a36Sopenharmony_ci return 0; 30762306a36Sopenharmony_ci } 30862306a36Sopenharmony_ci *hint_found = true; 30962306a36Sopenharmony_ci 31062306a36Sopenharmony_ci if (!hnode->parent) 31162306a36Sopenharmony_ci return objagg_obj_root_create(objagg, objagg_obj, hnode); 31262306a36Sopenharmony_ci 31362306a36Sopenharmony_ci parent = __objagg_obj_get(objagg, hnode->parent->obj); 31462306a36Sopenharmony_ci if (IS_ERR(parent)) 31562306a36Sopenharmony_ci return PTR_ERR(parent); 31662306a36Sopenharmony_ci 31762306a36Sopenharmony_ci err = objagg_obj_parent_assign(objagg, objagg_obj, parent, false); 31862306a36Sopenharmony_ci if (err) { 31962306a36Sopenharmony_ci *hint_found = false; 32062306a36Sopenharmony_ci err = 0; 32162306a36Sopenharmony_ci goto err_parent_assign; 32262306a36Sopenharmony_ci } 32362306a36Sopenharmony_ci 32462306a36Sopenharmony_ci return 0; 32562306a36Sopenharmony_ci 32662306a36Sopenharmony_cierr_parent_assign: 32762306a36Sopenharmony_ci objagg_obj_put(objagg, parent); 32862306a36Sopenharmony_ci return err; 32962306a36Sopenharmony_ci} 33062306a36Sopenharmony_ci 33162306a36Sopenharmony_cistatic int objagg_obj_init(struct objagg *objagg, 33262306a36Sopenharmony_ci struct objagg_obj *objagg_obj) 33362306a36Sopenharmony_ci{ 33462306a36Sopenharmony_ci bool hint_found; 33562306a36Sopenharmony_ci int err; 33662306a36Sopenharmony_ci 33762306a36Sopenharmony_ci /* First, try to use hints if they are available and 33862306a36Sopenharmony_ci * if they provide result. 33962306a36Sopenharmony_ci */ 34062306a36Sopenharmony_ci err = objagg_obj_init_with_hints(objagg, objagg_obj, &hint_found); 34162306a36Sopenharmony_ci if (err) 34262306a36Sopenharmony_ci return err; 34362306a36Sopenharmony_ci 34462306a36Sopenharmony_ci if (hint_found) 34562306a36Sopenharmony_ci return 0; 34662306a36Sopenharmony_ci 34762306a36Sopenharmony_ci /* Try to find if the object can be aggregated under an existing one. */ 34862306a36Sopenharmony_ci err = objagg_obj_parent_lookup_assign(objagg, objagg_obj); 34962306a36Sopenharmony_ci if (!err) 35062306a36Sopenharmony_ci return 0; 35162306a36Sopenharmony_ci /* If aggregation is not possible, make the object a root. */ 35262306a36Sopenharmony_ci return objagg_obj_root_create(objagg, objagg_obj, NULL); 35362306a36Sopenharmony_ci} 35462306a36Sopenharmony_ci 35562306a36Sopenharmony_cistatic void objagg_obj_fini(struct objagg *objagg, 35662306a36Sopenharmony_ci struct objagg_obj *objagg_obj) 35762306a36Sopenharmony_ci{ 35862306a36Sopenharmony_ci if (!objagg_obj_is_root(objagg_obj)) 35962306a36Sopenharmony_ci objagg_obj_parent_unassign(objagg, objagg_obj); 36062306a36Sopenharmony_ci else 36162306a36Sopenharmony_ci objagg_obj_root_destroy(objagg, objagg_obj); 36262306a36Sopenharmony_ci} 36362306a36Sopenharmony_ci 36462306a36Sopenharmony_cistatic struct objagg_obj *objagg_obj_create(struct objagg *objagg, void *obj) 36562306a36Sopenharmony_ci{ 36662306a36Sopenharmony_ci struct objagg_obj *objagg_obj; 36762306a36Sopenharmony_ci int err; 36862306a36Sopenharmony_ci 36962306a36Sopenharmony_ci objagg_obj = kzalloc(sizeof(*objagg_obj) + objagg->ops->obj_size, 37062306a36Sopenharmony_ci GFP_KERNEL); 37162306a36Sopenharmony_ci if (!objagg_obj) 37262306a36Sopenharmony_ci return ERR_PTR(-ENOMEM); 37362306a36Sopenharmony_ci objagg_obj_ref_inc(objagg_obj); 37462306a36Sopenharmony_ci memcpy(objagg_obj->obj, obj, objagg->ops->obj_size); 37562306a36Sopenharmony_ci 37662306a36Sopenharmony_ci err = objagg_obj_init(objagg, objagg_obj); 37762306a36Sopenharmony_ci if (err) 37862306a36Sopenharmony_ci goto err_obj_init; 37962306a36Sopenharmony_ci 38062306a36Sopenharmony_ci err = rhashtable_insert_fast(&objagg->obj_ht, &objagg_obj->ht_node, 38162306a36Sopenharmony_ci objagg->ht_params); 38262306a36Sopenharmony_ci if (err) 38362306a36Sopenharmony_ci goto err_ht_insert; 38462306a36Sopenharmony_ci list_add(&objagg_obj->list, &objagg->obj_list); 38562306a36Sopenharmony_ci objagg->obj_count++; 38662306a36Sopenharmony_ci trace_objagg_obj_create(objagg, objagg_obj); 38762306a36Sopenharmony_ci 38862306a36Sopenharmony_ci return objagg_obj; 38962306a36Sopenharmony_ci 39062306a36Sopenharmony_cierr_ht_insert: 39162306a36Sopenharmony_ci objagg_obj_fini(objagg, objagg_obj); 39262306a36Sopenharmony_cierr_obj_init: 39362306a36Sopenharmony_ci kfree(objagg_obj); 39462306a36Sopenharmony_ci return ERR_PTR(err); 39562306a36Sopenharmony_ci} 39662306a36Sopenharmony_ci 39762306a36Sopenharmony_cistatic struct objagg_obj *__objagg_obj_get(struct objagg *objagg, void *obj) 39862306a36Sopenharmony_ci{ 39962306a36Sopenharmony_ci struct objagg_obj *objagg_obj; 40062306a36Sopenharmony_ci 40162306a36Sopenharmony_ci /* First, try to find the object exactly as user passed it, 40262306a36Sopenharmony_ci * perhaps it is already in use. 40362306a36Sopenharmony_ci */ 40462306a36Sopenharmony_ci objagg_obj = objagg_obj_lookup(objagg, obj); 40562306a36Sopenharmony_ci if (objagg_obj) { 40662306a36Sopenharmony_ci objagg_obj_ref_inc(objagg_obj); 40762306a36Sopenharmony_ci return objagg_obj; 40862306a36Sopenharmony_ci } 40962306a36Sopenharmony_ci 41062306a36Sopenharmony_ci return objagg_obj_create(objagg, obj); 41162306a36Sopenharmony_ci} 41262306a36Sopenharmony_ci 41362306a36Sopenharmony_ci/** 41462306a36Sopenharmony_ci * objagg_obj_get - gets an object within objagg instance 41562306a36Sopenharmony_ci * @objagg: objagg instance 41662306a36Sopenharmony_ci * @obj: user-specific private object pointer 41762306a36Sopenharmony_ci * 41862306a36Sopenharmony_ci * Note: all locking must be provided by the caller. 41962306a36Sopenharmony_ci * 42062306a36Sopenharmony_ci * Size of the "obj" memory is specified in "objagg->ops". 42162306a36Sopenharmony_ci * 42262306a36Sopenharmony_ci * There are 3 main options this function wraps: 42362306a36Sopenharmony_ci * 1) The object according to "obj" already exist. In that case 42462306a36Sopenharmony_ci * the reference counter is incrementes and the object is returned. 42562306a36Sopenharmony_ci * 2) The object does not exist, but it can be aggregated within 42662306a36Sopenharmony_ci * another object. In that case, user ops->delta_create() is called 42762306a36Sopenharmony_ci * to obtain delta data and a new object is created with returned 42862306a36Sopenharmony_ci * user-delta private pointer. 42962306a36Sopenharmony_ci * 3) The object does not exist and cannot be aggregated into 43062306a36Sopenharmony_ci * any of the existing objects. In that case, user ops->root_create() 43162306a36Sopenharmony_ci * is called to create the root and a new object is created with 43262306a36Sopenharmony_ci * returned user-root private pointer. 43362306a36Sopenharmony_ci * 43462306a36Sopenharmony_ci * Returns a pointer to objagg object instance in case of success, 43562306a36Sopenharmony_ci * otherwise it returns pointer error using ERR_PTR macro. 43662306a36Sopenharmony_ci */ 43762306a36Sopenharmony_cistruct objagg_obj *objagg_obj_get(struct objagg *objagg, void *obj) 43862306a36Sopenharmony_ci{ 43962306a36Sopenharmony_ci struct objagg_obj *objagg_obj; 44062306a36Sopenharmony_ci 44162306a36Sopenharmony_ci objagg_obj = __objagg_obj_get(objagg, obj); 44262306a36Sopenharmony_ci if (IS_ERR(objagg_obj)) 44362306a36Sopenharmony_ci return objagg_obj; 44462306a36Sopenharmony_ci objagg_obj_stats_inc(objagg_obj); 44562306a36Sopenharmony_ci trace_objagg_obj_get(objagg, objagg_obj, objagg_obj->refcount); 44662306a36Sopenharmony_ci return objagg_obj; 44762306a36Sopenharmony_ci} 44862306a36Sopenharmony_ciEXPORT_SYMBOL(objagg_obj_get); 44962306a36Sopenharmony_ci 45062306a36Sopenharmony_cistatic void objagg_obj_destroy(struct objagg *objagg, 45162306a36Sopenharmony_ci struct objagg_obj *objagg_obj) 45262306a36Sopenharmony_ci{ 45362306a36Sopenharmony_ci trace_objagg_obj_destroy(objagg, objagg_obj); 45462306a36Sopenharmony_ci --objagg->obj_count; 45562306a36Sopenharmony_ci list_del(&objagg_obj->list); 45662306a36Sopenharmony_ci rhashtable_remove_fast(&objagg->obj_ht, &objagg_obj->ht_node, 45762306a36Sopenharmony_ci objagg->ht_params); 45862306a36Sopenharmony_ci objagg_obj_fini(objagg, objagg_obj); 45962306a36Sopenharmony_ci kfree(objagg_obj); 46062306a36Sopenharmony_ci} 46162306a36Sopenharmony_ci 46262306a36Sopenharmony_cistatic void __objagg_obj_put(struct objagg *objagg, 46362306a36Sopenharmony_ci struct objagg_obj *objagg_obj) 46462306a36Sopenharmony_ci{ 46562306a36Sopenharmony_ci if (!objagg_obj_ref_dec(objagg_obj)) 46662306a36Sopenharmony_ci objagg_obj_destroy(objagg, objagg_obj); 46762306a36Sopenharmony_ci} 46862306a36Sopenharmony_ci 46962306a36Sopenharmony_ci/** 47062306a36Sopenharmony_ci * objagg_obj_put - puts an object within objagg instance 47162306a36Sopenharmony_ci * @objagg: objagg instance 47262306a36Sopenharmony_ci * @objagg_obj: objagg object instance 47362306a36Sopenharmony_ci * 47462306a36Sopenharmony_ci * Note: all locking must be provided by the caller. 47562306a36Sopenharmony_ci * 47662306a36Sopenharmony_ci * Symmetric to objagg_obj_get(). 47762306a36Sopenharmony_ci */ 47862306a36Sopenharmony_civoid objagg_obj_put(struct objagg *objagg, struct objagg_obj *objagg_obj) 47962306a36Sopenharmony_ci{ 48062306a36Sopenharmony_ci trace_objagg_obj_put(objagg, objagg_obj, objagg_obj->refcount); 48162306a36Sopenharmony_ci objagg_obj_stats_dec(objagg_obj); 48262306a36Sopenharmony_ci __objagg_obj_put(objagg, objagg_obj); 48362306a36Sopenharmony_ci} 48462306a36Sopenharmony_ciEXPORT_SYMBOL(objagg_obj_put); 48562306a36Sopenharmony_ci 48662306a36Sopenharmony_ci/** 48762306a36Sopenharmony_ci * objagg_create - creates a new objagg instance 48862306a36Sopenharmony_ci * @ops: user-specific callbacks 48962306a36Sopenharmony_ci * @objagg_hints: hints, can be NULL 49062306a36Sopenharmony_ci * @priv: pointer to a private data passed to the ops 49162306a36Sopenharmony_ci * 49262306a36Sopenharmony_ci * Note: all locking must be provided by the caller. 49362306a36Sopenharmony_ci * 49462306a36Sopenharmony_ci * The purpose of the library is to provide an infrastructure to 49562306a36Sopenharmony_ci * aggregate user-specified objects. Library does not care about the type 49662306a36Sopenharmony_ci * of the object. User fills-up ops which take care of the specific 49762306a36Sopenharmony_ci * user object manipulation. 49862306a36Sopenharmony_ci * 49962306a36Sopenharmony_ci * As a very stupid example, consider integer numbers. For example 50062306a36Sopenharmony_ci * number 8 as a root object. That can aggregate number 9 with delta 1, 50162306a36Sopenharmony_ci * number 10 with delta 2, etc. This example is implemented as 50262306a36Sopenharmony_ci * a part of a testing module in test_objagg.c file. 50362306a36Sopenharmony_ci * 50462306a36Sopenharmony_ci * Each objagg instance contains multiple trees. Each tree node is 50562306a36Sopenharmony_ci * represented by "an object". In the current implementation there can be 50662306a36Sopenharmony_ci * only roots and leafs nodes. Leaf nodes are called deltas. 50762306a36Sopenharmony_ci * But in general, this can be easily extended for intermediate nodes. 50862306a36Sopenharmony_ci * In that extension, a delta would be associated with all non-root 50962306a36Sopenharmony_ci * nodes. 51062306a36Sopenharmony_ci * 51162306a36Sopenharmony_ci * Returns a pointer to newly created objagg instance in case of success, 51262306a36Sopenharmony_ci * otherwise it returns pointer error using ERR_PTR macro. 51362306a36Sopenharmony_ci */ 51462306a36Sopenharmony_cistruct objagg *objagg_create(const struct objagg_ops *ops, 51562306a36Sopenharmony_ci struct objagg_hints *objagg_hints, void *priv) 51662306a36Sopenharmony_ci{ 51762306a36Sopenharmony_ci struct objagg *objagg; 51862306a36Sopenharmony_ci int err; 51962306a36Sopenharmony_ci 52062306a36Sopenharmony_ci if (WARN_ON(!ops || !ops->root_create || !ops->root_destroy || 52162306a36Sopenharmony_ci !ops->delta_check || !ops->delta_create || 52262306a36Sopenharmony_ci !ops->delta_destroy)) 52362306a36Sopenharmony_ci return ERR_PTR(-EINVAL); 52462306a36Sopenharmony_ci 52562306a36Sopenharmony_ci objagg = kzalloc(sizeof(*objagg), GFP_KERNEL); 52662306a36Sopenharmony_ci if (!objagg) 52762306a36Sopenharmony_ci return ERR_PTR(-ENOMEM); 52862306a36Sopenharmony_ci objagg->ops = ops; 52962306a36Sopenharmony_ci if (objagg_hints) { 53062306a36Sopenharmony_ci objagg->hints = objagg_hints; 53162306a36Sopenharmony_ci objagg_hints->refcount++; 53262306a36Sopenharmony_ci } 53362306a36Sopenharmony_ci objagg->priv = priv; 53462306a36Sopenharmony_ci INIT_LIST_HEAD(&objagg->obj_list); 53562306a36Sopenharmony_ci 53662306a36Sopenharmony_ci objagg->ht_params.key_len = ops->obj_size; 53762306a36Sopenharmony_ci objagg->ht_params.key_offset = offsetof(struct objagg_obj, obj); 53862306a36Sopenharmony_ci objagg->ht_params.head_offset = offsetof(struct objagg_obj, ht_node); 53962306a36Sopenharmony_ci 54062306a36Sopenharmony_ci err = rhashtable_init(&objagg->obj_ht, &objagg->ht_params); 54162306a36Sopenharmony_ci if (err) 54262306a36Sopenharmony_ci goto err_rhashtable_init; 54362306a36Sopenharmony_ci 54462306a36Sopenharmony_ci ida_init(&objagg->root_ida); 54562306a36Sopenharmony_ci 54662306a36Sopenharmony_ci trace_objagg_create(objagg); 54762306a36Sopenharmony_ci return objagg; 54862306a36Sopenharmony_ci 54962306a36Sopenharmony_cierr_rhashtable_init: 55062306a36Sopenharmony_ci kfree(objagg); 55162306a36Sopenharmony_ci return ERR_PTR(err); 55262306a36Sopenharmony_ci} 55362306a36Sopenharmony_ciEXPORT_SYMBOL(objagg_create); 55462306a36Sopenharmony_ci 55562306a36Sopenharmony_ci/** 55662306a36Sopenharmony_ci * objagg_destroy - destroys a new objagg instance 55762306a36Sopenharmony_ci * @objagg: objagg instance 55862306a36Sopenharmony_ci * 55962306a36Sopenharmony_ci * Note: all locking must be provided by the caller. 56062306a36Sopenharmony_ci */ 56162306a36Sopenharmony_civoid objagg_destroy(struct objagg *objagg) 56262306a36Sopenharmony_ci{ 56362306a36Sopenharmony_ci trace_objagg_destroy(objagg); 56462306a36Sopenharmony_ci ida_destroy(&objagg->root_ida); 56562306a36Sopenharmony_ci WARN_ON(!list_empty(&objagg->obj_list)); 56662306a36Sopenharmony_ci rhashtable_destroy(&objagg->obj_ht); 56762306a36Sopenharmony_ci if (objagg->hints) 56862306a36Sopenharmony_ci objagg_hints_put(objagg->hints); 56962306a36Sopenharmony_ci kfree(objagg); 57062306a36Sopenharmony_ci} 57162306a36Sopenharmony_ciEXPORT_SYMBOL(objagg_destroy); 57262306a36Sopenharmony_ci 57362306a36Sopenharmony_cistatic int objagg_stats_info_sort_cmp_func(const void *a, const void *b) 57462306a36Sopenharmony_ci{ 57562306a36Sopenharmony_ci const struct objagg_obj_stats_info *stats_info1 = a; 57662306a36Sopenharmony_ci const struct objagg_obj_stats_info *stats_info2 = b; 57762306a36Sopenharmony_ci 57862306a36Sopenharmony_ci if (stats_info1->is_root != stats_info2->is_root) 57962306a36Sopenharmony_ci return stats_info2->is_root - stats_info1->is_root; 58062306a36Sopenharmony_ci if (stats_info1->stats.delta_user_count != 58162306a36Sopenharmony_ci stats_info2->stats.delta_user_count) 58262306a36Sopenharmony_ci return stats_info2->stats.delta_user_count - 58362306a36Sopenharmony_ci stats_info1->stats.delta_user_count; 58462306a36Sopenharmony_ci return stats_info2->stats.user_count - stats_info1->stats.user_count; 58562306a36Sopenharmony_ci} 58662306a36Sopenharmony_ci 58762306a36Sopenharmony_ci/** 58862306a36Sopenharmony_ci * objagg_stats_get - obtains stats of the objagg instance 58962306a36Sopenharmony_ci * @objagg: objagg instance 59062306a36Sopenharmony_ci * 59162306a36Sopenharmony_ci * Note: all locking must be provided by the caller. 59262306a36Sopenharmony_ci * 59362306a36Sopenharmony_ci * The returned structure contains statistics of all object 59462306a36Sopenharmony_ci * currently in use, ordered by following rules: 59562306a36Sopenharmony_ci * 1) Root objects are always on lower indexes than the rest. 59662306a36Sopenharmony_ci * 2) Objects with higher delta user count are always on lower 59762306a36Sopenharmony_ci * indexes. 59862306a36Sopenharmony_ci * 3) In case more objects have the same delta user count, 59962306a36Sopenharmony_ci * the objects are ordered by user count. 60062306a36Sopenharmony_ci * 60162306a36Sopenharmony_ci * Returns a pointer to stats instance in case of success, 60262306a36Sopenharmony_ci * otherwise it returns pointer error using ERR_PTR macro. 60362306a36Sopenharmony_ci */ 60462306a36Sopenharmony_ciconst struct objagg_stats *objagg_stats_get(struct objagg *objagg) 60562306a36Sopenharmony_ci{ 60662306a36Sopenharmony_ci struct objagg_stats *objagg_stats; 60762306a36Sopenharmony_ci struct objagg_obj *objagg_obj; 60862306a36Sopenharmony_ci int i; 60962306a36Sopenharmony_ci 61062306a36Sopenharmony_ci objagg_stats = kzalloc(struct_size(objagg_stats, stats_info, 61162306a36Sopenharmony_ci objagg->obj_count), GFP_KERNEL); 61262306a36Sopenharmony_ci if (!objagg_stats) 61362306a36Sopenharmony_ci return ERR_PTR(-ENOMEM); 61462306a36Sopenharmony_ci 61562306a36Sopenharmony_ci i = 0; 61662306a36Sopenharmony_ci list_for_each_entry(objagg_obj, &objagg->obj_list, list) { 61762306a36Sopenharmony_ci memcpy(&objagg_stats->stats_info[i].stats, &objagg_obj->stats, 61862306a36Sopenharmony_ci sizeof(objagg_stats->stats_info[0].stats)); 61962306a36Sopenharmony_ci objagg_stats->stats_info[i].objagg_obj = objagg_obj; 62062306a36Sopenharmony_ci objagg_stats->stats_info[i].is_root = 62162306a36Sopenharmony_ci objagg_obj_is_root(objagg_obj); 62262306a36Sopenharmony_ci if (objagg_stats->stats_info[i].is_root) 62362306a36Sopenharmony_ci objagg_stats->root_count++; 62462306a36Sopenharmony_ci i++; 62562306a36Sopenharmony_ci } 62662306a36Sopenharmony_ci objagg_stats->stats_info_count = i; 62762306a36Sopenharmony_ci 62862306a36Sopenharmony_ci sort(objagg_stats->stats_info, objagg_stats->stats_info_count, 62962306a36Sopenharmony_ci sizeof(struct objagg_obj_stats_info), 63062306a36Sopenharmony_ci objagg_stats_info_sort_cmp_func, NULL); 63162306a36Sopenharmony_ci 63262306a36Sopenharmony_ci return objagg_stats; 63362306a36Sopenharmony_ci} 63462306a36Sopenharmony_ciEXPORT_SYMBOL(objagg_stats_get); 63562306a36Sopenharmony_ci 63662306a36Sopenharmony_ci/** 63762306a36Sopenharmony_ci * objagg_stats_put - puts stats of the objagg instance 63862306a36Sopenharmony_ci * @objagg_stats: objagg instance stats 63962306a36Sopenharmony_ci * 64062306a36Sopenharmony_ci * Note: all locking must be provided by the caller. 64162306a36Sopenharmony_ci */ 64262306a36Sopenharmony_civoid objagg_stats_put(const struct objagg_stats *objagg_stats) 64362306a36Sopenharmony_ci{ 64462306a36Sopenharmony_ci kfree(objagg_stats); 64562306a36Sopenharmony_ci} 64662306a36Sopenharmony_ciEXPORT_SYMBOL(objagg_stats_put); 64762306a36Sopenharmony_ci 64862306a36Sopenharmony_cistatic struct objagg_hints_node * 64962306a36Sopenharmony_ciobjagg_hints_node_create(struct objagg_hints *objagg_hints, 65062306a36Sopenharmony_ci struct objagg_obj *objagg_obj, size_t obj_size, 65162306a36Sopenharmony_ci struct objagg_hints_node *parent_hnode) 65262306a36Sopenharmony_ci{ 65362306a36Sopenharmony_ci unsigned int user_count = objagg_obj->stats.user_count; 65462306a36Sopenharmony_ci struct objagg_hints_node *hnode; 65562306a36Sopenharmony_ci int err; 65662306a36Sopenharmony_ci 65762306a36Sopenharmony_ci hnode = kzalloc(sizeof(*hnode) + obj_size, GFP_KERNEL); 65862306a36Sopenharmony_ci if (!hnode) 65962306a36Sopenharmony_ci return ERR_PTR(-ENOMEM); 66062306a36Sopenharmony_ci memcpy(hnode->obj, &objagg_obj->obj, obj_size); 66162306a36Sopenharmony_ci hnode->stats_info.stats.user_count = user_count; 66262306a36Sopenharmony_ci hnode->stats_info.stats.delta_user_count = user_count; 66362306a36Sopenharmony_ci if (parent_hnode) { 66462306a36Sopenharmony_ci parent_hnode->stats_info.stats.delta_user_count += user_count; 66562306a36Sopenharmony_ci } else { 66662306a36Sopenharmony_ci hnode->root_id = objagg_hints->root_count++; 66762306a36Sopenharmony_ci hnode->stats_info.is_root = true; 66862306a36Sopenharmony_ci } 66962306a36Sopenharmony_ci hnode->stats_info.objagg_obj = objagg_obj; 67062306a36Sopenharmony_ci 67162306a36Sopenharmony_ci err = rhashtable_insert_fast(&objagg_hints->node_ht, &hnode->ht_node, 67262306a36Sopenharmony_ci objagg_hints->ht_params); 67362306a36Sopenharmony_ci if (err) 67462306a36Sopenharmony_ci goto err_ht_insert; 67562306a36Sopenharmony_ci 67662306a36Sopenharmony_ci list_add(&hnode->list, &objagg_hints->node_list); 67762306a36Sopenharmony_ci hnode->parent = parent_hnode; 67862306a36Sopenharmony_ci objagg_hints->node_count++; 67962306a36Sopenharmony_ci 68062306a36Sopenharmony_ci return hnode; 68162306a36Sopenharmony_ci 68262306a36Sopenharmony_cierr_ht_insert: 68362306a36Sopenharmony_ci kfree(hnode); 68462306a36Sopenharmony_ci return ERR_PTR(err); 68562306a36Sopenharmony_ci} 68662306a36Sopenharmony_ci 68762306a36Sopenharmony_cistatic void objagg_hints_flush(struct objagg_hints *objagg_hints) 68862306a36Sopenharmony_ci{ 68962306a36Sopenharmony_ci struct objagg_hints_node *hnode, *tmp; 69062306a36Sopenharmony_ci 69162306a36Sopenharmony_ci list_for_each_entry_safe(hnode, tmp, &objagg_hints->node_list, list) { 69262306a36Sopenharmony_ci list_del(&hnode->list); 69362306a36Sopenharmony_ci rhashtable_remove_fast(&objagg_hints->node_ht, &hnode->ht_node, 69462306a36Sopenharmony_ci objagg_hints->ht_params); 69562306a36Sopenharmony_ci kfree(hnode); 69662306a36Sopenharmony_ci } 69762306a36Sopenharmony_ci} 69862306a36Sopenharmony_ci 69962306a36Sopenharmony_cistruct objagg_tmp_node { 70062306a36Sopenharmony_ci struct objagg_obj *objagg_obj; 70162306a36Sopenharmony_ci bool crossed_out; 70262306a36Sopenharmony_ci}; 70362306a36Sopenharmony_ci 70462306a36Sopenharmony_cistruct objagg_tmp_graph { 70562306a36Sopenharmony_ci struct objagg_tmp_node *nodes; 70662306a36Sopenharmony_ci unsigned long nodes_count; 70762306a36Sopenharmony_ci unsigned long *edges; 70862306a36Sopenharmony_ci}; 70962306a36Sopenharmony_ci 71062306a36Sopenharmony_cistatic int objagg_tmp_graph_edge_index(struct objagg_tmp_graph *graph, 71162306a36Sopenharmony_ci int parent_index, int index) 71262306a36Sopenharmony_ci{ 71362306a36Sopenharmony_ci return index * graph->nodes_count + parent_index; 71462306a36Sopenharmony_ci} 71562306a36Sopenharmony_ci 71662306a36Sopenharmony_cistatic void objagg_tmp_graph_edge_set(struct objagg_tmp_graph *graph, 71762306a36Sopenharmony_ci int parent_index, int index) 71862306a36Sopenharmony_ci{ 71962306a36Sopenharmony_ci int edge_index = objagg_tmp_graph_edge_index(graph, index, 72062306a36Sopenharmony_ci parent_index); 72162306a36Sopenharmony_ci 72262306a36Sopenharmony_ci __set_bit(edge_index, graph->edges); 72362306a36Sopenharmony_ci} 72462306a36Sopenharmony_ci 72562306a36Sopenharmony_cistatic bool objagg_tmp_graph_is_edge(struct objagg_tmp_graph *graph, 72662306a36Sopenharmony_ci int parent_index, int index) 72762306a36Sopenharmony_ci{ 72862306a36Sopenharmony_ci int edge_index = objagg_tmp_graph_edge_index(graph, index, 72962306a36Sopenharmony_ci parent_index); 73062306a36Sopenharmony_ci 73162306a36Sopenharmony_ci return test_bit(edge_index, graph->edges); 73262306a36Sopenharmony_ci} 73362306a36Sopenharmony_ci 73462306a36Sopenharmony_cistatic unsigned int objagg_tmp_graph_node_weight(struct objagg_tmp_graph *graph, 73562306a36Sopenharmony_ci unsigned int index) 73662306a36Sopenharmony_ci{ 73762306a36Sopenharmony_ci struct objagg_tmp_node *node = &graph->nodes[index]; 73862306a36Sopenharmony_ci unsigned int weight = node->objagg_obj->stats.user_count; 73962306a36Sopenharmony_ci int j; 74062306a36Sopenharmony_ci 74162306a36Sopenharmony_ci /* Node weight is sum of node users and all other nodes users 74262306a36Sopenharmony_ci * that this node can represent with delta. 74362306a36Sopenharmony_ci */ 74462306a36Sopenharmony_ci 74562306a36Sopenharmony_ci for (j = 0; j < graph->nodes_count; j++) { 74662306a36Sopenharmony_ci if (!objagg_tmp_graph_is_edge(graph, index, j)) 74762306a36Sopenharmony_ci continue; 74862306a36Sopenharmony_ci node = &graph->nodes[j]; 74962306a36Sopenharmony_ci if (node->crossed_out) 75062306a36Sopenharmony_ci continue; 75162306a36Sopenharmony_ci weight += node->objagg_obj->stats.user_count; 75262306a36Sopenharmony_ci } 75362306a36Sopenharmony_ci return weight; 75462306a36Sopenharmony_ci} 75562306a36Sopenharmony_ci 75662306a36Sopenharmony_cistatic int objagg_tmp_graph_node_max_weight(struct objagg_tmp_graph *graph) 75762306a36Sopenharmony_ci{ 75862306a36Sopenharmony_ci struct objagg_tmp_node *node; 75962306a36Sopenharmony_ci unsigned int max_weight = 0; 76062306a36Sopenharmony_ci unsigned int weight; 76162306a36Sopenharmony_ci int max_index = -1; 76262306a36Sopenharmony_ci int i; 76362306a36Sopenharmony_ci 76462306a36Sopenharmony_ci for (i = 0; i < graph->nodes_count; i++) { 76562306a36Sopenharmony_ci node = &graph->nodes[i]; 76662306a36Sopenharmony_ci if (node->crossed_out) 76762306a36Sopenharmony_ci continue; 76862306a36Sopenharmony_ci weight = objagg_tmp_graph_node_weight(graph, i); 76962306a36Sopenharmony_ci if (weight >= max_weight) { 77062306a36Sopenharmony_ci max_weight = weight; 77162306a36Sopenharmony_ci max_index = i; 77262306a36Sopenharmony_ci } 77362306a36Sopenharmony_ci } 77462306a36Sopenharmony_ci return max_index; 77562306a36Sopenharmony_ci} 77662306a36Sopenharmony_ci 77762306a36Sopenharmony_cistatic struct objagg_tmp_graph *objagg_tmp_graph_create(struct objagg *objagg) 77862306a36Sopenharmony_ci{ 77962306a36Sopenharmony_ci unsigned int nodes_count = objagg->obj_count; 78062306a36Sopenharmony_ci struct objagg_tmp_graph *graph; 78162306a36Sopenharmony_ci struct objagg_tmp_node *node; 78262306a36Sopenharmony_ci struct objagg_tmp_node *pnode; 78362306a36Sopenharmony_ci struct objagg_obj *objagg_obj; 78462306a36Sopenharmony_ci int i, j; 78562306a36Sopenharmony_ci 78662306a36Sopenharmony_ci graph = kzalloc(sizeof(*graph), GFP_KERNEL); 78762306a36Sopenharmony_ci if (!graph) 78862306a36Sopenharmony_ci return NULL; 78962306a36Sopenharmony_ci 79062306a36Sopenharmony_ci graph->nodes = kcalloc(nodes_count, sizeof(*graph->nodes), GFP_KERNEL); 79162306a36Sopenharmony_ci if (!graph->nodes) 79262306a36Sopenharmony_ci goto err_nodes_alloc; 79362306a36Sopenharmony_ci graph->nodes_count = nodes_count; 79462306a36Sopenharmony_ci 79562306a36Sopenharmony_ci graph->edges = bitmap_zalloc(nodes_count * nodes_count, GFP_KERNEL); 79662306a36Sopenharmony_ci if (!graph->edges) 79762306a36Sopenharmony_ci goto err_edges_alloc; 79862306a36Sopenharmony_ci 79962306a36Sopenharmony_ci i = 0; 80062306a36Sopenharmony_ci list_for_each_entry(objagg_obj, &objagg->obj_list, list) { 80162306a36Sopenharmony_ci node = &graph->nodes[i++]; 80262306a36Sopenharmony_ci node->objagg_obj = objagg_obj; 80362306a36Sopenharmony_ci } 80462306a36Sopenharmony_ci 80562306a36Sopenharmony_ci /* Assemble a temporary graph. Insert edge X->Y in case Y can be 80662306a36Sopenharmony_ci * in delta of X. 80762306a36Sopenharmony_ci */ 80862306a36Sopenharmony_ci for (i = 0; i < nodes_count; i++) { 80962306a36Sopenharmony_ci for (j = 0; j < nodes_count; j++) { 81062306a36Sopenharmony_ci if (i == j) 81162306a36Sopenharmony_ci continue; 81262306a36Sopenharmony_ci pnode = &graph->nodes[i]; 81362306a36Sopenharmony_ci node = &graph->nodes[j]; 81462306a36Sopenharmony_ci if (objagg->ops->delta_check(objagg->priv, 81562306a36Sopenharmony_ci pnode->objagg_obj->obj, 81662306a36Sopenharmony_ci node->objagg_obj->obj)) { 81762306a36Sopenharmony_ci objagg_tmp_graph_edge_set(graph, i, j); 81862306a36Sopenharmony_ci 81962306a36Sopenharmony_ci } 82062306a36Sopenharmony_ci } 82162306a36Sopenharmony_ci } 82262306a36Sopenharmony_ci return graph; 82362306a36Sopenharmony_ci 82462306a36Sopenharmony_cierr_edges_alloc: 82562306a36Sopenharmony_ci kfree(graph->nodes); 82662306a36Sopenharmony_cierr_nodes_alloc: 82762306a36Sopenharmony_ci kfree(graph); 82862306a36Sopenharmony_ci return NULL; 82962306a36Sopenharmony_ci} 83062306a36Sopenharmony_ci 83162306a36Sopenharmony_cistatic void objagg_tmp_graph_destroy(struct objagg_tmp_graph *graph) 83262306a36Sopenharmony_ci{ 83362306a36Sopenharmony_ci bitmap_free(graph->edges); 83462306a36Sopenharmony_ci kfree(graph->nodes); 83562306a36Sopenharmony_ci kfree(graph); 83662306a36Sopenharmony_ci} 83762306a36Sopenharmony_ci 83862306a36Sopenharmony_cistatic int 83962306a36Sopenharmony_ciobjagg_opt_simple_greedy_fillup_hints(struct objagg_hints *objagg_hints, 84062306a36Sopenharmony_ci struct objagg *objagg) 84162306a36Sopenharmony_ci{ 84262306a36Sopenharmony_ci struct objagg_hints_node *hnode, *parent_hnode; 84362306a36Sopenharmony_ci struct objagg_tmp_graph *graph; 84462306a36Sopenharmony_ci struct objagg_tmp_node *node; 84562306a36Sopenharmony_ci int index; 84662306a36Sopenharmony_ci int j; 84762306a36Sopenharmony_ci int err; 84862306a36Sopenharmony_ci 84962306a36Sopenharmony_ci graph = objagg_tmp_graph_create(objagg); 85062306a36Sopenharmony_ci if (!graph) 85162306a36Sopenharmony_ci return -ENOMEM; 85262306a36Sopenharmony_ci 85362306a36Sopenharmony_ci /* Find the nodes from the ones that can accommodate most users 85462306a36Sopenharmony_ci * and cross them out of the graph. Save them to the hint list. 85562306a36Sopenharmony_ci */ 85662306a36Sopenharmony_ci while ((index = objagg_tmp_graph_node_max_weight(graph)) != -1) { 85762306a36Sopenharmony_ci node = &graph->nodes[index]; 85862306a36Sopenharmony_ci node->crossed_out = true; 85962306a36Sopenharmony_ci hnode = objagg_hints_node_create(objagg_hints, 86062306a36Sopenharmony_ci node->objagg_obj, 86162306a36Sopenharmony_ci objagg->ops->obj_size, 86262306a36Sopenharmony_ci NULL); 86362306a36Sopenharmony_ci if (IS_ERR(hnode)) { 86462306a36Sopenharmony_ci err = PTR_ERR(hnode); 86562306a36Sopenharmony_ci goto out; 86662306a36Sopenharmony_ci } 86762306a36Sopenharmony_ci parent_hnode = hnode; 86862306a36Sopenharmony_ci for (j = 0; j < graph->nodes_count; j++) { 86962306a36Sopenharmony_ci if (!objagg_tmp_graph_is_edge(graph, index, j)) 87062306a36Sopenharmony_ci continue; 87162306a36Sopenharmony_ci node = &graph->nodes[j]; 87262306a36Sopenharmony_ci if (node->crossed_out) 87362306a36Sopenharmony_ci continue; 87462306a36Sopenharmony_ci node->crossed_out = true; 87562306a36Sopenharmony_ci hnode = objagg_hints_node_create(objagg_hints, 87662306a36Sopenharmony_ci node->objagg_obj, 87762306a36Sopenharmony_ci objagg->ops->obj_size, 87862306a36Sopenharmony_ci parent_hnode); 87962306a36Sopenharmony_ci if (IS_ERR(hnode)) { 88062306a36Sopenharmony_ci err = PTR_ERR(hnode); 88162306a36Sopenharmony_ci goto out; 88262306a36Sopenharmony_ci } 88362306a36Sopenharmony_ci } 88462306a36Sopenharmony_ci } 88562306a36Sopenharmony_ci 88662306a36Sopenharmony_ci err = 0; 88762306a36Sopenharmony_ciout: 88862306a36Sopenharmony_ci objagg_tmp_graph_destroy(graph); 88962306a36Sopenharmony_ci return err; 89062306a36Sopenharmony_ci} 89162306a36Sopenharmony_ci 89262306a36Sopenharmony_cistruct objagg_opt_algo { 89362306a36Sopenharmony_ci int (*fillup_hints)(struct objagg_hints *objagg_hints, 89462306a36Sopenharmony_ci struct objagg *objagg); 89562306a36Sopenharmony_ci}; 89662306a36Sopenharmony_ci 89762306a36Sopenharmony_cistatic const struct objagg_opt_algo objagg_opt_simple_greedy = { 89862306a36Sopenharmony_ci .fillup_hints = objagg_opt_simple_greedy_fillup_hints, 89962306a36Sopenharmony_ci}; 90062306a36Sopenharmony_ci 90162306a36Sopenharmony_ci 90262306a36Sopenharmony_cistatic const struct objagg_opt_algo *objagg_opt_algos[] = { 90362306a36Sopenharmony_ci [OBJAGG_OPT_ALGO_SIMPLE_GREEDY] = &objagg_opt_simple_greedy, 90462306a36Sopenharmony_ci}; 90562306a36Sopenharmony_ci 90662306a36Sopenharmony_cistatic int objagg_hints_obj_cmp(struct rhashtable_compare_arg *arg, 90762306a36Sopenharmony_ci const void *obj) 90862306a36Sopenharmony_ci{ 90962306a36Sopenharmony_ci struct rhashtable *ht = arg->ht; 91062306a36Sopenharmony_ci struct objagg_hints *objagg_hints = 91162306a36Sopenharmony_ci container_of(ht, struct objagg_hints, node_ht); 91262306a36Sopenharmony_ci const struct objagg_ops *ops = objagg_hints->ops; 91362306a36Sopenharmony_ci const char *ptr = obj; 91462306a36Sopenharmony_ci 91562306a36Sopenharmony_ci ptr += ht->p.key_offset; 91662306a36Sopenharmony_ci return ops->hints_obj_cmp ? ops->hints_obj_cmp(ptr, arg->key) : 91762306a36Sopenharmony_ci memcmp(ptr, arg->key, ht->p.key_len); 91862306a36Sopenharmony_ci} 91962306a36Sopenharmony_ci 92062306a36Sopenharmony_ci/** 92162306a36Sopenharmony_ci * objagg_hints_get - obtains hints instance 92262306a36Sopenharmony_ci * @objagg: objagg instance 92362306a36Sopenharmony_ci * @opt_algo_type: type of hints finding algorithm 92462306a36Sopenharmony_ci * 92562306a36Sopenharmony_ci * Note: all locking must be provided by the caller. 92662306a36Sopenharmony_ci * 92762306a36Sopenharmony_ci * According to the algo type, the existing objects of objagg instance 92862306a36Sopenharmony_ci * are going to be went-through to assemble an optimal tree. We call this 92962306a36Sopenharmony_ci * tree hints. These hints can be later on used for creation of 93062306a36Sopenharmony_ci * a new objagg instance. There, the future object creations are going 93162306a36Sopenharmony_ci * to be consulted with these hints in order to find out, where exactly 93262306a36Sopenharmony_ci * the new object should be put as a root or delta. 93362306a36Sopenharmony_ci * 93462306a36Sopenharmony_ci * Returns a pointer to hints instance in case of success, 93562306a36Sopenharmony_ci * otherwise it returns pointer error using ERR_PTR macro. 93662306a36Sopenharmony_ci */ 93762306a36Sopenharmony_cistruct objagg_hints *objagg_hints_get(struct objagg *objagg, 93862306a36Sopenharmony_ci enum objagg_opt_algo_type opt_algo_type) 93962306a36Sopenharmony_ci{ 94062306a36Sopenharmony_ci const struct objagg_opt_algo *algo = objagg_opt_algos[opt_algo_type]; 94162306a36Sopenharmony_ci struct objagg_hints *objagg_hints; 94262306a36Sopenharmony_ci int err; 94362306a36Sopenharmony_ci 94462306a36Sopenharmony_ci objagg_hints = kzalloc(sizeof(*objagg_hints), GFP_KERNEL); 94562306a36Sopenharmony_ci if (!objagg_hints) 94662306a36Sopenharmony_ci return ERR_PTR(-ENOMEM); 94762306a36Sopenharmony_ci 94862306a36Sopenharmony_ci objagg_hints->ops = objagg->ops; 94962306a36Sopenharmony_ci objagg_hints->refcount = 1; 95062306a36Sopenharmony_ci 95162306a36Sopenharmony_ci INIT_LIST_HEAD(&objagg_hints->node_list); 95262306a36Sopenharmony_ci 95362306a36Sopenharmony_ci objagg_hints->ht_params.key_len = objagg->ops->obj_size; 95462306a36Sopenharmony_ci objagg_hints->ht_params.key_offset = 95562306a36Sopenharmony_ci offsetof(struct objagg_hints_node, obj); 95662306a36Sopenharmony_ci objagg_hints->ht_params.head_offset = 95762306a36Sopenharmony_ci offsetof(struct objagg_hints_node, ht_node); 95862306a36Sopenharmony_ci objagg_hints->ht_params.obj_cmpfn = objagg_hints_obj_cmp; 95962306a36Sopenharmony_ci 96062306a36Sopenharmony_ci err = rhashtable_init(&objagg_hints->node_ht, &objagg_hints->ht_params); 96162306a36Sopenharmony_ci if (err) 96262306a36Sopenharmony_ci goto err_rhashtable_init; 96362306a36Sopenharmony_ci 96462306a36Sopenharmony_ci err = algo->fillup_hints(objagg_hints, objagg); 96562306a36Sopenharmony_ci if (err) 96662306a36Sopenharmony_ci goto err_fillup_hints; 96762306a36Sopenharmony_ci 96862306a36Sopenharmony_ci if (WARN_ON(objagg_hints->node_count != objagg->obj_count)) { 96962306a36Sopenharmony_ci err = -EINVAL; 97062306a36Sopenharmony_ci goto err_node_count_check; 97162306a36Sopenharmony_ci } 97262306a36Sopenharmony_ci 97362306a36Sopenharmony_ci return objagg_hints; 97462306a36Sopenharmony_ci 97562306a36Sopenharmony_cierr_node_count_check: 97662306a36Sopenharmony_cierr_fillup_hints: 97762306a36Sopenharmony_ci objagg_hints_flush(objagg_hints); 97862306a36Sopenharmony_ci rhashtable_destroy(&objagg_hints->node_ht); 97962306a36Sopenharmony_cierr_rhashtable_init: 98062306a36Sopenharmony_ci kfree(objagg_hints); 98162306a36Sopenharmony_ci return ERR_PTR(err); 98262306a36Sopenharmony_ci} 98362306a36Sopenharmony_ciEXPORT_SYMBOL(objagg_hints_get); 98462306a36Sopenharmony_ci 98562306a36Sopenharmony_ci/** 98662306a36Sopenharmony_ci * objagg_hints_put - puts hints instance 98762306a36Sopenharmony_ci * @objagg_hints: objagg hints instance 98862306a36Sopenharmony_ci * 98962306a36Sopenharmony_ci * Note: all locking must be provided by the caller. 99062306a36Sopenharmony_ci */ 99162306a36Sopenharmony_civoid objagg_hints_put(struct objagg_hints *objagg_hints) 99262306a36Sopenharmony_ci{ 99362306a36Sopenharmony_ci if (--objagg_hints->refcount) 99462306a36Sopenharmony_ci return; 99562306a36Sopenharmony_ci objagg_hints_flush(objagg_hints); 99662306a36Sopenharmony_ci rhashtable_destroy(&objagg_hints->node_ht); 99762306a36Sopenharmony_ci kfree(objagg_hints); 99862306a36Sopenharmony_ci} 99962306a36Sopenharmony_ciEXPORT_SYMBOL(objagg_hints_put); 100062306a36Sopenharmony_ci 100162306a36Sopenharmony_ci/** 100262306a36Sopenharmony_ci * objagg_hints_stats_get - obtains stats of the hints instance 100362306a36Sopenharmony_ci * @objagg_hints: hints instance 100462306a36Sopenharmony_ci * 100562306a36Sopenharmony_ci * Note: all locking must be provided by the caller. 100662306a36Sopenharmony_ci * 100762306a36Sopenharmony_ci * The returned structure contains statistics of all objects 100862306a36Sopenharmony_ci * currently in use, ordered by following rules: 100962306a36Sopenharmony_ci * 1) Root objects are always on lower indexes than the rest. 101062306a36Sopenharmony_ci * 2) Objects with higher delta user count are always on lower 101162306a36Sopenharmony_ci * indexes. 101262306a36Sopenharmony_ci * 3) In case multiple objects have the same delta user count, 101362306a36Sopenharmony_ci * the objects are ordered by user count. 101462306a36Sopenharmony_ci * 101562306a36Sopenharmony_ci * Returns a pointer to stats instance in case of success, 101662306a36Sopenharmony_ci * otherwise it returns pointer error using ERR_PTR macro. 101762306a36Sopenharmony_ci */ 101862306a36Sopenharmony_ciconst struct objagg_stats * 101962306a36Sopenharmony_ciobjagg_hints_stats_get(struct objagg_hints *objagg_hints) 102062306a36Sopenharmony_ci{ 102162306a36Sopenharmony_ci struct objagg_stats *objagg_stats; 102262306a36Sopenharmony_ci struct objagg_hints_node *hnode; 102362306a36Sopenharmony_ci int i; 102462306a36Sopenharmony_ci 102562306a36Sopenharmony_ci objagg_stats = kzalloc(struct_size(objagg_stats, stats_info, 102662306a36Sopenharmony_ci objagg_hints->node_count), 102762306a36Sopenharmony_ci GFP_KERNEL); 102862306a36Sopenharmony_ci if (!objagg_stats) 102962306a36Sopenharmony_ci return ERR_PTR(-ENOMEM); 103062306a36Sopenharmony_ci 103162306a36Sopenharmony_ci i = 0; 103262306a36Sopenharmony_ci list_for_each_entry(hnode, &objagg_hints->node_list, list) { 103362306a36Sopenharmony_ci memcpy(&objagg_stats->stats_info[i], &hnode->stats_info, 103462306a36Sopenharmony_ci sizeof(objagg_stats->stats_info[0])); 103562306a36Sopenharmony_ci if (objagg_stats->stats_info[i].is_root) 103662306a36Sopenharmony_ci objagg_stats->root_count++; 103762306a36Sopenharmony_ci i++; 103862306a36Sopenharmony_ci } 103962306a36Sopenharmony_ci objagg_stats->stats_info_count = i; 104062306a36Sopenharmony_ci 104162306a36Sopenharmony_ci sort(objagg_stats->stats_info, objagg_stats->stats_info_count, 104262306a36Sopenharmony_ci sizeof(struct objagg_obj_stats_info), 104362306a36Sopenharmony_ci objagg_stats_info_sort_cmp_func, NULL); 104462306a36Sopenharmony_ci 104562306a36Sopenharmony_ci return objagg_stats; 104662306a36Sopenharmony_ci} 104762306a36Sopenharmony_ciEXPORT_SYMBOL(objagg_hints_stats_get); 104862306a36Sopenharmony_ci 104962306a36Sopenharmony_ciMODULE_LICENSE("Dual BSD/GPL"); 105062306a36Sopenharmony_ciMODULE_AUTHOR("Jiri Pirko <jiri@mellanox.com>"); 105162306a36Sopenharmony_ciMODULE_DESCRIPTION("Object aggregation manager"); 1052