18c2ecf20Sopenharmony_ci// SPDX-License-Identifier: BSD-3-Clause OR GPL-2.0 28c2ecf20Sopenharmony_ci/* Copyright (c) 2018 Mellanox Technologies. All rights reserved */ 38c2ecf20Sopenharmony_ci 48c2ecf20Sopenharmony_ci#include <linux/module.h> 58c2ecf20Sopenharmony_ci#include <linux/slab.h> 68c2ecf20Sopenharmony_ci#include <linux/rhashtable.h> 78c2ecf20Sopenharmony_ci#include <linux/idr.h> 88c2ecf20Sopenharmony_ci#include <linux/list.h> 98c2ecf20Sopenharmony_ci#include <linux/sort.h> 108c2ecf20Sopenharmony_ci#include <linux/objagg.h> 118c2ecf20Sopenharmony_ci 128c2ecf20Sopenharmony_ci#define CREATE_TRACE_POINTS 138c2ecf20Sopenharmony_ci#include <trace/events/objagg.h> 148c2ecf20Sopenharmony_ci 158c2ecf20Sopenharmony_cistruct objagg_hints { 168c2ecf20Sopenharmony_ci struct rhashtable node_ht; 178c2ecf20Sopenharmony_ci struct rhashtable_params ht_params; 188c2ecf20Sopenharmony_ci struct list_head node_list; 198c2ecf20Sopenharmony_ci unsigned int node_count; 208c2ecf20Sopenharmony_ci unsigned int root_count; 218c2ecf20Sopenharmony_ci unsigned int refcount; 228c2ecf20Sopenharmony_ci const struct objagg_ops *ops; 238c2ecf20Sopenharmony_ci}; 248c2ecf20Sopenharmony_ci 258c2ecf20Sopenharmony_cistruct objagg_hints_node { 268c2ecf20Sopenharmony_ci struct rhash_head ht_node; /* member of objagg_hints->node_ht */ 278c2ecf20Sopenharmony_ci struct list_head list; /* member of objagg_hints->node_list */ 288c2ecf20Sopenharmony_ci struct objagg_hints_node *parent; 298c2ecf20Sopenharmony_ci unsigned int root_id; 308c2ecf20Sopenharmony_ci struct objagg_obj_stats_info stats_info; 318c2ecf20Sopenharmony_ci unsigned long obj[]; 328c2ecf20Sopenharmony_ci}; 338c2ecf20Sopenharmony_ci 348c2ecf20Sopenharmony_cistatic struct objagg_hints_node * 358c2ecf20Sopenharmony_ciobjagg_hints_lookup(struct objagg_hints *objagg_hints, void *obj) 368c2ecf20Sopenharmony_ci{ 378c2ecf20Sopenharmony_ci if (!objagg_hints) 388c2ecf20Sopenharmony_ci return NULL; 398c2ecf20Sopenharmony_ci return rhashtable_lookup_fast(&objagg_hints->node_ht, obj, 408c2ecf20Sopenharmony_ci objagg_hints->ht_params); 418c2ecf20Sopenharmony_ci} 428c2ecf20Sopenharmony_ci 438c2ecf20Sopenharmony_cistruct objagg { 448c2ecf20Sopenharmony_ci const struct objagg_ops *ops; 458c2ecf20Sopenharmony_ci void *priv; 468c2ecf20Sopenharmony_ci struct rhashtable obj_ht; 478c2ecf20Sopenharmony_ci struct rhashtable_params ht_params; 488c2ecf20Sopenharmony_ci struct list_head obj_list; 498c2ecf20Sopenharmony_ci unsigned int obj_count; 508c2ecf20Sopenharmony_ci struct ida root_ida; 518c2ecf20Sopenharmony_ci struct objagg_hints *hints; 528c2ecf20Sopenharmony_ci}; 538c2ecf20Sopenharmony_ci 548c2ecf20Sopenharmony_cistruct objagg_obj { 558c2ecf20Sopenharmony_ci struct rhash_head ht_node; /* member of objagg->obj_ht */ 568c2ecf20Sopenharmony_ci struct list_head list; /* member of objagg->obj_list */ 578c2ecf20Sopenharmony_ci struct objagg_obj *parent; /* if the object is nested, this 588c2ecf20Sopenharmony_ci * holds pointer to parent, otherwise NULL 598c2ecf20Sopenharmony_ci */ 608c2ecf20Sopenharmony_ci union { 618c2ecf20Sopenharmony_ci void *delta_priv; /* user delta private */ 628c2ecf20Sopenharmony_ci void *root_priv; /* user root private */ 638c2ecf20Sopenharmony_ci }; 648c2ecf20Sopenharmony_ci unsigned int root_id; 658c2ecf20Sopenharmony_ci unsigned int refcount; /* counts number of users of this object 668c2ecf20Sopenharmony_ci * including nested objects 678c2ecf20Sopenharmony_ci */ 688c2ecf20Sopenharmony_ci struct objagg_obj_stats stats; 698c2ecf20Sopenharmony_ci unsigned long obj[]; 708c2ecf20Sopenharmony_ci}; 718c2ecf20Sopenharmony_ci 728c2ecf20Sopenharmony_cistatic unsigned int objagg_obj_ref_inc(struct objagg_obj *objagg_obj) 738c2ecf20Sopenharmony_ci{ 748c2ecf20Sopenharmony_ci return ++objagg_obj->refcount; 758c2ecf20Sopenharmony_ci} 768c2ecf20Sopenharmony_ci 778c2ecf20Sopenharmony_cistatic unsigned int objagg_obj_ref_dec(struct objagg_obj *objagg_obj) 788c2ecf20Sopenharmony_ci{ 798c2ecf20Sopenharmony_ci return --objagg_obj->refcount; 808c2ecf20Sopenharmony_ci} 818c2ecf20Sopenharmony_ci 828c2ecf20Sopenharmony_cistatic void objagg_obj_stats_inc(struct objagg_obj *objagg_obj) 838c2ecf20Sopenharmony_ci{ 848c2ecf20Sopenharmony_ci objagg_obj->stats.user_count++; 858c2ecf20Sopenharmony_ci objagg_obj->stats.delta_user_count++; 868c2ecf20Sopenharmony_ci if (objagg_obj->parent) 878c2ecf20Sopenharmony_ci objagg_obj->parent->stats.delta_user_count++; 888c2ecf20Sopenharmony_ci} 898c2ecf20Sopenharmony_ci 908c2ecf20Sopenharmony_cistatic void objagg_obj_stats_dec(struct objagg_obj *objagg_obj) 918c2ecf20Sopenharmony_ci{ 928c2ecf20Sopenharmony_ci objagg_obj->stats.user_count--; 938c2ecf20Sopenharmony_ci objagg_obj->stats.delta_user_count--; 948c2ecf20Sopenharmony_ci if (objagg_obj->parent) 958c2ecf20Sopenharmony_ci objagg_obj->parent->stats.delta_user_count--; 968c2ecf20Sopenharmony_ci} 978c2ecf20Sopenharmony_ci 988c2ecf20Sopenharmony_cistatic bool objagg_obj_is_root(const struct objagg_obj *objagg_obj) 998c2ecf20Sopenharmony_ci{ 1008c2ecf20Sopenharmony_ci /* Nesting is not supported, so we can use ->parent 1018c2ecf20Sopenharmony_ci * to figure out if the object is root. 1028c2ecf20Sopenharmony_ci */ 1038c2ecf20Sopenharmony_ci return !objagg_obj->parent; 1048c2ecf20Sopenharmony_ci} 1058c2ecf20Sopenharmony_ci 1068c2ecf20Sopenharmony_ci/** 1078c2ecf20Sopenharmony_ci * objagg_obj_root_priv - obtains root private for an object 1088c2ecf20Sopenharmony_ci * @objagg_obj: objagg object instance 1098c2ecf20Sopenharmony_ci * 1108c2ecf20Sopenharmony_ci * Note: all locking must be provided by the caller. 1118c2ecf20Sopenharmony_ci * 1128c2ecf20Sopenharmony_ci * Either the object is root itself when the private is returned 1138c2ecf20Sopenharmony_ci * directly, or the parent is root and its private is returned 1148c2ecf20Sopenharmony_ci * instead. 1158c2ecf20Sopenharmony_ci * 1168c2ecf20Sopenharmony_ci * Returns a user private root pointer. 1178c2ecf20Sopenharmony_ci */ 1188c2ecf20Sopenharmony_ciconst void *objagg_obj_root_priv(const struct objagg_obj *objagg_obj) 1198c2ecf20Sopenharmony_ci{ 1208c2ecf20Sopenharmony_ci if (objagg_obj_is_root(objagg_obj)) 1218c2ecf20Sopenharmony_ci return objagg_obj->root_priv; 1228c2ecf20Sopenharmony_ci WARN_ON(!objagg_obj_is_root(objagg_obj->parent)); 1238c2ecf20Sopenharmony_ci return objagg_obj->parent->root_priv; 1248c2ecf20Sopenharmony_ci} 1258c2ecf20Sopenharmony_ciEXPORT_SYMBOL(objagg_obj_root_priv); 1268c2ecf20Sopenharmony_ci 1278c2ecf20Sopenharmony_ci/** 1288c2ecf20Sopenharmony_ci * objagg_obj_delta_priv - obtains delta private for an object 1298c2ecf20Sopenharmony_ci * @objagg_obj: objagg object instance 1308c2ecf20Sopenharmony_ci * 1318c2ecf20Sopenharmony_ci * Note: all locking must be provided by the caller. 1328c2ecf20Sopenharmony_ci * 1338c2ecf20Sopenharmony_ci * Returns user private delta pointer or NULL in case the passed 1348c2ecf20Sopenharmony_ci * object is root. 1358c2ecf20Sopenharmony_ci */ 1368c2ecf20Sopenharmony_ciconst void *objagg_obj_delta_priv(const struct objagg_obj *objagg_obj) 1378c2ecf20Sopenharmony_ci{ 1388c2ecf20Sopenharmony_ci if (objagg_obj_is_root(objagg_obj)) 1398c2ecf20Sopenharmony_ci return NULL; 1408c2ecf20Sopenharmony_ci return objagg_obj->delta_priv; 1418c2ecf20Sopenharmony_ci} 1428c2ecf20Sopenharmony_ciEXPORT_SYMBOL(objagg_obj_delta_priv); 1438c2ecf20Sopenharmony_ci 1448c2ecf20Sopenharmony_ci/** 1458c2ecf20Sopenharmony_ci * objagg_obj_raw - obtains object user private pointer 1468c2ecf20Sopenharmony_ci * @objagg_obj: objagg object instance 1478c2ecf20Sopenharmony_ci * 1488c2ecf20Sopenharmony_ci * Note: all locking must be provided by the caller. 1498c2ecf20Sopenharmony_ci * 1508c2ecf20Sopenharmony_ci * Returns user private pointer as was passed to objagg_obj_get() by "obj" arg. 1518c2ecf20Sopenharmony_ci */ 1528c2ecf20Sopenharmony_ciconst void *objagg_obj_raw(const struct objagg_obj *objagg_obj) 1538c2ecf20Sopenharmony_ci{ 1548c2ecf20Sopenharmony_ci return objagg_obj->obj; 1558c2ecf20Sopenharmony_ci} 1568c2ecf20Sopenharmony_ciEXPORT_SYMBOL(objagg_obj_raw); 1578c2ecf20Sopenharmony_ci 1588c2ecf20Sopenharmony_cistatic struct objagg_obj *objagg_obj_lookup(struct objagg *objagg, void *obj) 1598c2ecf20Sopenharmony_ci{ 1608c2ecf20Sopenharmony_ci return rhashtable_lookup_fast(&objagg->obj_ht, obj, objagg->ht_params); 1618c2ecf20Sopenharmony_ci} 1628c2ecf20Sopenharmony_ci 1638c2ecf20Sopenharmony_cistatic int objagg_obj_parent_assign(struct objagg *objagg, 1648c2ecf20Sopenharmony_ci struct objagg_obj *objagg_obj, 1658c2ecf20Sopenharmony_ci struct objagg_obj *parent, 1668c2ecf20Sopenharmony_ci bool take_parent_ref) 1678c2ecf20Sopenharmony_ci{ 1688c2ecf20Sopenharmony_ci void *delta_priv; 1698c2ecf20Sopenharmony_ci 1708c2ecf20Sopenharmony_ci delta_priv = objagg->ops->delta_create(objagg->priv, parent->obj, 1718c2ecf20Sopenharmony_ci objagg_obj->obj); 1728c2ecf20Sopenharmony_ci if (IS_ERR(delta_priv)) 1738c2ecf20Sopenharmony_ci return PTR_ERR(delta_priv); 1748c2ecf20Sopenharmony_ci 1758c2ecf20Sopenharmony_ci /* User returned a delta private, that means that 1768c2ecf20Sopenharmony_ci * our object can be aggregated into the parent. 1778c2ecf20Sopenharmony_ci */ 1788c2ecf20Sopenharmony_ci objagg_obj->parent = parent; 1798c2ecf20Sopenharmony_ci objagg_obj->delta_priv = delta_priv; 1808c2ecf20Sopenharmony_ci if (take_parent_ref) 1818c2ecf20Sopenharmony_ci objagg_obj_ref_inc(objagg_obj->parent); 1828c2ecf20Sopenharmony_ci trace_objagg_obj_parent_assign(objagg, objagg_obj, 1838c2ecf20Sopenharmony_ci parent, 1848c2ecf20Sopenharmony_ci parent->refcount); 1858c2ecf20Sopenharmony_ci return 0; 1868c2ecf20Sopenharmony_ci} 1878c2ecf20Sopenharmony_ci 1888c2ecf20Sopenharmony_cistatic int objagg_obj_parent_lookup_assign(struct objagg *objagg, 1898c2ecf20Sopenharmony_ci struct objagg_obj *objagg_obj) 1908c2ecf20Sopenharmony_ci{ 1918c2ecf20Sopenharmony_ci struct objagg_obj *objagg_obj_cur; 1928c2ecf20Sopenharmony_ci int err; 1938c2ecf20Sopenharmony_ci 1948c2ecf20Sopenharmony_ci list_for_each_entry(objagg_obj_cur, &objagg->obj_list, list) { 1958c2ecf20Sopenharmony_ci /* Nesting is not supported. In case the object 1968c2ecf20Sopenharmony_ci * is not root, it cannot be assigned as parent. 1978c2ecf20Sopenharmony_ci */ 1988c2ecf20Sopenharmony_ci if (!objagg_obj_is_root(objagg_obj_cur)) 1998c2ecf20Sopenharmony_ci continue; 2008c2ecf20Sopenharmony_ci err = objagg_obj_parent_assign(objagg, objagg_obj, 2018c2ecf20Sopenharmony_ci objagg_obj_cur, true); 2028c2ecf20Sopenharmony_ci if (!err) 2038c2ecf20Sopenharmony_ci return 0; 2048c2ecf20Sopenharmony_ci } 2058c2ecf20Sopenharmony_ci return -ENOENT; 2068c2ecf20Sopenharmony_ci} 2078c2ecf20Sopenharmony_ci 2088c2ecf20Sopenharmony_cistatic void __objagg_obj_put(struct objagg *objagg, 2098c2ecf20Sopenharmony_ci struct objagg_obj *objagg_obj); 2108c2ecf20Sopenharmony_ci 2118c2ecf20Sopenharmony_cistatic void objagg_obj_parent_unassign(struct objagg *objagg, 2128c2ecf20Sopenharmony_ci struct objagg_obj *objagg_obj) 2138c2ecf20Sopenharmony_ci{ 2148c2ecf20Sopenharmony_ci trace_objagg_obj_parent_unassign(objagg, objagg_obj, 2158c2ecf20Sopenharmony_ci objagg_obj->parent, 2168c2ecf20Sopenharmony_ci objagg_obj->parent->refcount); 2178c2ecf20Sopenharmony_ci objagg->ops->delta_destroy(objagg->priv, objagg_obj->delta_priv); 2188c2ecf20Sopenharmony_ci __objagg_obj_put(objagg, objagg_obj->parent); 2198c2ecf20Sopenharmony_ci} 2208c2ecf20Sopenharmony_ci 2218c2ecf20Sopenharmony_cistatic int objagg_obj_root_id_alloc(struct objagg *objagg, 2228c2ecf20Sopenharmony_ci struct objagg_obj *objagg_obj, 2238c2ecf20Sopenharmony_ci struct objagg_hints_node *hnode) 2248c2ecf20Sopenharmony_ci{ 2258c2ecf20Sopenharmony_ci unsigned int min, max; 2268c2ecf20Sopenharmony_ci int root_id; 2278c2ecf20Sopenharmony_ci 2288c2ecf20Sopenharmony_ci /* In case there are no hints available, the root id is invalid. */ 2298c2ecf20Sopenharmony_ci if (!objagg->hints) { 2308c2ecf20Sopenharmony_ci objagg_obj->root_id = OBJAGG_OBJ_ROOT_ID_INVALID; 2318c2ecf20Sopenharmony_ci return 0; 2328c2ecf20Sopenharmony_ci } 2338c2ecf20Sopenharmony_ci 2348c2ecf20Sopenharmony_ci if (hnode) { 2358c2ecf20Sopenharmony_ci min = hnode->root_id; 2368c2ecf20Sopenharmony_ci max = hnode->root_id; 2378c2ecf20Sopenharmony_ci } else { 2388c2ecf20Sopenharmony_ci /* For objects with no hint, start after the last 2398c2ecf20Sopenharmony_ci * hinted root_id. 2408c2ecf20Sopenharmony_ci */ 2418c2ecf20Sopenharmony_ci min = objagg->hints->root_count; 2428c2ecf20Sopenharmony_ci max = ~0; 2438c2ecf20Sopenharmony_ci } 2448c2ecf20Sopenharmony_ci 2458c2ecf20Sopenharmony_ci root_id = ida_alloc_range(&objagg->root_ida, min, max, GFP_KERNEL); 2468c2ecf20Sopenharmony_ci 2478c2ecf20Sopenharmony_ci if (root_id < 0) 2488c2ecf20Sopenharmony_ci return root_id; 2498c2ecf20Sopenharmony_ci objagg_obj->root_id = root_id; 2508c2ecf20Sopenharmony_ci return 0; 2518c2ecf20Sopenharmony_ci} 2528c2ecf20Sopenharmony_ci 2538c2ecf20Sopenharmony_cistatic void objagg_obj_root_id_free(struct objagg *objagg, 2548c2ecf20Sopenharmony_ci struct objagg_obj *objagg_obj) 2558c2ecf20Sopenharmony_ci{ 2568c2ecf20Sopenharmony_ci if (!objagg->hints) 2578c2ecf20Sopenharmony_ci return; 2588c2ecf20Sopenharmony_ci ida_free(&objagg->root_ida, objagg_obj->root_id); 2598c2ecf20Sopenharmony_ci} 2608c2ecf20Sopenharmony_ci 2618c2ecf20Sopenharmony_cistatic int objagg_obj_root_create(struct objagg *objagg, 2628c2ecf20Sopenharmony_ci struct objagg_obj *objagg_obj, 2638c2ecf20Sopenharmony_ci struct objagg_hints_node *hnode) 2648c2ecf20Sopenharmony_ci{ 2658c2ecf20Sopenharmony_ci int err; 2668c2ecf20Sopenharmony_ci 2678c2ecf20Sopenharmony_ci err = objagg_obj_root_id_alloc(objagg, objagg_obj, hnode); 2688c2ecf20Sopenharmony_ci if (err) 2698c2ecf20Sopenharmony_ci return err; 2708c2ecf20Sopenharmony_ci objagg_obj->root_priv = objagg->ops->root_create(objagg->priv, 2718c2ecf20Sopenharmony_ci objagg_obj->obj, 2728c2ecf20Sopenharmony_ci objagg_obj->root_id); 2738c2ecf20Sopenharmony_ci if (IS_ERR(objagg_obj->root_priv)) { 2748c2ecf20Sopenharmony_ci err = PTR_ERR(objagg_obj->root_priv); 2758c2ecf20Sopenharmony_ci goto err_root_create; 2768c2ecf20Sopenharmony_ci } 2778c2ecf20Sopenharmony_ci trace_objagg_obj_root_create(objagg, objagg_obj); 2788c2ecf20Sopenharmony_ci return 0; 2798c2ecf20Sopenharmony_ci 2808c2ecf20Sopenharmony_cierr_root_create: 2818c2ecf20Sopenharmony_ci objagg_obj_root_id_free(objagg, objagg_obj); 2828c2ecf20Sopenharmony_ci return err; 2838c2ecf20Sopenharmony_ci} 2848c2ecf20Sopenharmony_ci 2858c2ecf20Sopenharmony_cistatic void objagg_obj_root_destroy(struct objagg *objagg, 2868c2ecf20Sopenharmony_ci struct objagg_obj *objagg_obj) 2878c2ecf20Sopenharmony_ci{ 2888c2ecf20Sopenharmony_ci trace_objagg_obj_root_destroy(objagg, objagg_obj); 2898c2ecf20Sopenharmony_ci objagg->ops->root_destroy(objagg->priv, objagg_obj->root_priv); 2908c2ecf20Sopenharmony_ci objagg_obj_root_id_free(objagg, objagg_obj); 2918c2ecf20Sopenharmony_ci} 2928c2ecf20Sopenharmony_ci 2938c2ecf20Sopenharmony_cistatic struct objagg_obj *__objagg_obj_get(struct objagg *objagg, void *obj); 2948c2ecf20Sopenharmony_ci 2958c2ecf20Sopenharmony_cistatic int objagg_obj_init_with_hints(struct objagg *objagg, 2968c2ecf20Sopenharmony_ci struct objagg_obj *objagg_obj, 2978c2ecf20Sopenharmony_ci bool *hint_found) 2988c2ecf20Sopenharmony_ci{ 2998c2ecf20Sopenharmony_ci struct objagg_hints_node *hnode; 3008c2ecf20Sopenharmony_ci struct objagg_obj *parent; 3018c2ecf20Sopenharmony_ci int err; 3028c2ecf20Sopenharmony_ci 3038c2ecf20Sopenharmony_ci hnode = objagg_hints_lookup(objagg->hints, objagg_obj->obj); 3048c2ecf20Sopenharmony_ci if (!hnode) { 3058c2ecf20Sopenharmony_ci *hint_found = false; 3068c2ecf20Sopenharmony_ci return 0; 3078c2ecf20Sopenharmony_ci } 3088c2ecf20Sopenharmony_ci *hint_found = true; 3098c2ecf20Sopenharmony_ci 3108c2ecf20Sopenharmony_ci if (!hnode->parent) 3118c2ecf20Sopenharmony_ci return objagg_obj_root_create(objagg, objagg_obj, hnode); 3128c2ecf20Sopenharmony_ci 3138c2ecf20Sopenharmony_ci parent = __objagg_obj_get(objagg, hnode->parent->obj); 3148c2ecf20Sopenharmony_ci if (IS_ERR(parent)) 3158c2ecf20Sopenharmony_ci return PTR_ERR(parent); 3168c2ecf20Sopenharmony_ci 3178c2ecf20Sopenharmony_ci err = objagg_obj_parent_assign(objagg, objagg_obj, parent, false); 3188c2ecf20Sopenharmony_ci if (err) { 3198c2ecf20Sopenharmony_ci *hint_found = false; 3208c2ecf20Sopenharmony_ci err = 0; 3218c2ecf20Sopenharmony_ci goto err_parent_assign; 3228c2ecf20Sopenharmony_ci } 3238c2ecf20Sopenharmony_ci 3248c2ecf20Sopenharmony_ci return 0; 3258c2ecf20Sopenharmony_ci 3268c2ecf20Sopenharmony_cierr_parent_assign: 3278c2ecf20Sopenharmony_ci objagg_obj_put(objagg, parent); 3288c2ecf20Sopenharmony_ci return err; 3298c2ecf20Sopenharmony_ci} 3308c2ecf20Sopenharmony_ci 3318c2ecf20Sopenharmony_cistatic int objagg_obj_init(struct objagg *objagg, 3328c2ecf20Sopenharmony_ci struct objagg_obj *objagg_obj) 3338c2ecf20Sopenharmony_ci{ 3348c2ecf20Sopenharmony_ci bool hint_found; 3358c2ecf20Sopenharmony_ci int err; 3368c2ecf20Sopenharmony_ci 3378c2ecf20Sopenharmony_ci /* First, try to use hints if they are available and 3388c2ecf20Sopenharmony_ci * if they provide result. 3398c2ecf20Sopenharmony_ci */ 3408c2ecf20Sopenharmony_ci err = objagg_obj_init_with_hints(objagg, objagg_obj, &hint_found); 3418c2ecf20Sopenharmony_ci if (err) 3428c2ecf20Sopenharmony_ci return err; 3438c2ecf20Sopenharmony_ci 3448c2ecf20Sopenharmony_ci if (hint_found) 3458c2ecf20Sopenharmony_ci return 0; 3468c2ecf20Sopenharmony_ci 3478c2ecf20Sopenharmony_ci /* Try to find if the object can be aggregated under an existing one. */ 3488c2ecf20Sopenharmony_ci err = objagg_obj_parent_lookup_assign(objagg, objagg_obj); 3498c2ecf20Sopenharmony_ci if (!err) 3508c2ecf20Sopenharmony_ci return 0; 3518c2ecf20Sopenharmony_ci /* If aggregation is not possible, make the object a root. */ 3528c2ecf20Sopenharmony_ci return objagg_obj_root_create(objagg, objagg_obj, NULL); 3538c2ecf20Sopenharmony_ci} 3548c2ecf20Sopenharmony_ci 3558c2ecf20Sopenharmony_cistatic void objagg_obj_fini(struct objagg *objagg, 3568c2ecf20Sopenharmony_ci struct objagg_obj *objagg_obj) 3578c2ecf20Sopenharmony_ci{ 3588c2ecf20Sopenharmony_ci if (!objagg_obj_is_root(objagg_obj)) 3598c2ecf20Sopenharmony_ci objagg_obj_parent_unassign(objagg, objagg_obj); 3608c2ecf20Sopenharmony_ci else 3618c2ecf20Sopenharmony_ci objagg_obj_root_destroy(objagg, objagg_obj); 3628c2ecf20Sopenharmony_ci} 3638c2ecf20Sopenharmony_ci 3648c2ecf20Sopenharmony_cistatic struct objagg_obj *objagg_obj_create(struct objagg *objagg, void *obj) 3658c2ecf20Sopenharmony_ci{ 3668c2ecf20Sopenharmony_ci struct objagg_obj *objagg_obj; 3678c2ecf20Sopenharmony_ci int err; 3688c2ecf20Sopenharmony_ci 3698c2ecf20Sopenharmony_ci objagg_obj = kzalloc(sizeof(*objagg_obj) + objagg->ops->obj_size, 3708c2ecf20Sopenharmony_ci GFP_KERNEL); 3718c2ecf20Sopenharmony_ci if (!objagg_obj) 3728c2ecf20Sopenharmony_ci return ERR_PTR(-ENOMEM); 3738c2ecf20Sopenharmony_ci objagg_obj_ref_inc(objagg_obj); 3748c2ecf20Sopenharmony_ci memcpy(objagg_obj->obj, obj, objagg->ops->obj_size); 3758c2ecf20Sopenharmony_ci 3768c2ecf20Sopenharmony_ci err = objagg_obj_init(objagg, objagg_obj); 3778c2ecf20Sopenharmony_ci if (err) 3788c2ecf20Sopenharmony_ci goto err_obj_init; 3798c2ecf20Sopenharmony_ci 3808c2ecf20Sopenharmony_ci err = rhashtable_insert_fast(&objagg->obj_ht, &objagg_obj->ht_node, 3818c2ecf20Sopenharmony_ci objagg->ht_params); 3828c2ecf20Sopenharmony_ci if (err) 3838c2ecf20Sopenharmony_ci goto err_ht_insert; 3848c2ecf20Sopenharmony_ci list_add(&objagg_obj->list, &objagg->obj_list); 3858c2ecf20Sopenharmony_ci objagg->obj_count++; 3868c2ecf20Sopenharmony_ci trace_objagg_obj_create(objagg, objagg_obj); 3878c2ecf20Sopenharmony_ci 3888c2ecf20Sopenharmony_ci return objagg_obj; 3898c2ecf20Sopenharmony_ci 3908c2ecf20Sopenharmony_cierr_ht_insert: 3918c2ecf20Sopenharmony_ci objagg_obj_fini(objagg, objagg_obj); 3928c2ecf20Sopenharmony_cierr_obj_init: 3938c2ecf20Sopenharmony_ci kfree(objagg_obj); 3948c2ecf20Sopenharmony_ci return ERR_PTR(err); 3958c2ecf20Sopenharmony_ci} 3968c2ecf20Sopenharmony_ci 3978c2ecf20Sopenharmony_cistatic struct objagg_obj *__objagg_obj_get(struct objagg *objagg, void *obj) 3988c2ecf20Sopenharmony_ci{ 3998c2ecf20Sopenharmony_ci struct objagg_obj *objagg_obj; 4008c2ecf20Sopenharmony_ci 4018c2ecf20Sopenharmony_ci /* First, try to find the object exactly as user passed it, 4028c2ecf20Sopenharmony_ci * perhaps it is already in use. 4038c2ecf20Sopenharmony_ci */ 4048c2ecf20Sopenharmony_ci objagg_obj = objagg_obj_lookup(objagg, obj); 4058c2ecf20Sopenharmony_ci if (objagg_obj) { 4068c2ecf20Sopenharmony_ci objagg_obj_ref_inc(objagg_obj); 4078c2ecf20Sopenharmony_ci return objagg_obj; 4088c2ecf20Sopenharmony_ci } 4098c2ecf20Sopenharmony_ci 4108c2ecf20Sopenharmony_ci return objagg_obj_create(objagg, obj); 4118c2ecf20Sopenharmony_ci} 4128c2ecf20Sopenharmony_ci 4138c2ecf20Sopenharmony_ci/** 4148c2ecf20Sopenharmony_ci * objagg_obj_get - gets an object within objagg instance 4158c2ecf20Sopenharmony_ci * @objagg: objagg instance 4168c2ecf20Sopenharmony_ci * @obj: user-specific private object pointer 4178c2ecf20Sopenharmony_ci * 4188c2ecf20Sopenharmony_ci * Note: all locking must be provided by the caller. 4198c2ecf20Sopenharmony_ci * 4208c2ecf20Sopenharmony_ci * Size of the "obj" memory is specified in "objagg->ops". 4218c2ecf20Sopenharmony_ci * 4228c2ecf20Sopenharmony_ci * There are 3 main options this function wraps: 4238c2ecf20Sopenharmony_ci * 1) The object according to "obj" already exist. In that case 4248c2ecf20Sopenharmony_ci * the reference counter is incrementes and the object is returned. 4258c2ecf20Sopenharmony_ci * 2) The object does not exist, but it can be aggregated within 4268c2ecf20Sopenharmony_ci * another object. In that case, user ops->delta_create() is called 4278c2ecf20Sopenharmony_ci * to obtain delta data and a new object is created with returned 4288c2ecf20Sopenharmony_ci * user-delta private pointer. 4298c2ecf20Sopenharmony_ci * 3) The object does not exist and cannot be aggregated into 4308c2ecf20Sopenharmony_ci * any of the existing objects. In that case, user ops->root_create() 4318c2ecf20Sopenharmony_ci * is called to create the root and a new object is created with 4328c2ecf20Sopenharmony_ci * returned user-root private pointer. 4338c2ecf20Sopenharmony_ci * 4348c2ecf20Sopenharmony_ci * Returns a pointer to objagg object instance in case of success, 4358c2ecf20Sopenharmony_ci * otherwise it returns pointer error using ERR_PTR macro. 4368c2ecf20Sopenharmony_ci */ 4378c2ecf20Sopenharmony_cistruct objagg_obj *objagg_obj_get(struct objagg *objagg, void *obj) 4388c2ecf20Sopenharmony_ci{ 4398c2ecf20Sopenharmony_ci struct objagg_obj *objagg_obj; 4408c2ecf20Sopenharmony_ci 4418c2ecf20Sopenharmony_ci objagg_obj = __objagg_obj_get(objagg, obj); 4428c2ecf20Sopenharmony_ci if (IS_ERR(objagg_obj)) 4438c2ecf20Sopenharmony_ci return objagg_obj; 4448c2ecf20Sopenharmony_ci objagg_obj_stats_inc(objagg_obj); 4458c2ecf20Sopenharmony_ci trace_objagg_obj_get(objagg, objagg_obj, objagg_obj->refcount); 4468c2ecf20Sopenharmony_ci return objagg_obj; 4478c2ecf20Sopenharmony_ci} 4488c2ecf20Sopenharmony_ciEXPORT_SYMBOL(objagg_obj_get); 4498c2ecf20Sopenharmony_ci 4508c2ecf20Sopenharmony_cistatic void objagg_obj_destroy(struct objagg *objagg, 4518c2ecf20Sopenharmony_ci struct objagg_obj *objagg_obj) 4528c2ecf20Sopenharmony_ci{ 4538c2ecf20Sopenharmony_ci trace_objagg_obj_destroy(objagg, objagg_obj); 4548c2ecf20Sopenharmony_ci --objagg->obj_count; 4558c2ecf20Sopenharmony_ci list_del(&objagg_obj->list); 4568c2ecf20Sopenharmony_ci rhashtable_remove_fast(&objagg->obj_ht, &objagg_obj->ht_node, 4578c2ecf20Sopenharmony_ci objagg->ht_params); 4588c2ecf20Sopenharmony_ci objagg_obj_fini(objagg, objagg_obj); 4598c2ecf20Sopenharmony_ci kfree(objagg_obj); 4608c2ecf20Sopenharmony_ci} 4618c2ecf20Sopenharmony_ci 4628c2ecf20Sopenharmony_cistatic void __objagg_obj_put(struct objagg *objagg, 4638c2ecf20Sopenharmony_ci struct objagg_obj *objagg_obj) 4648c2ecf20Sopenharmony_ci{ 4658c2ecf20Sopenharmony_ci if (!objagg_obj_ref_dec(objagg_obj)) 4668c2ecf20Sopenharmony_ci objagg_obj_destroy(objagg, objagg_obj); 4678c2ecf20Sopenharmony_ci} 4688c2ecf20Sopenharmony_ci 4698c2ecf20Sopenharmony_ci/** 4708c2ecf20Sopenharmony_ci * objagg_obj_put - puts an object within objagg instance 4718c2ecf20Sopenharmony_ci * @objagg: objagg instance 4728c2ecf20Sopenharmony_ci * @objagg_obj: objagg object instance 4738c2ecf20Sopenharmony_ci * 4748c2ecf20Sopenharmony_ci * Note: all locking must be provided by the caller. 4758c2ecf20Sopenharmony_ci * 4768c2ecf20Sopenharmony_ci * Symmetric to objagg_obj_get(). 4778c2ecf20Sopenharmony_ci */ 4788c2ecf20Sopenharmony_civoid objagg_obj_put(struct objagg *objagg, struct objagg_obj *objagg_obj) 4798c2ecf20Sopenharmony_ci{ 4808c2ecf20Sopenharmony_ci trace_objagg_obj_put(objagg, objagg_obj, objagg_obj->refcount); 4818c2ecf20Sopenharmony_ci objagg_obj_stats_dec(objagg_obj); 4828c2ecf20Sopenharmony_ci __objagg_obj_put(objagg, objagg_obj); 4838c2ecf20Sopenharmony_ci} 4848c2ecf20Sopenharmony_ciEXPORT_SYMBOL(objagg_obj_put); 4858c2ecf20Sopenharmony_ci 4868c2ecf20Sopenharmony_ci/** 4878c2ecf20Sopenharmony_ci * objagg_create - creates a new objagg instance 4888c2ecf20Sopenharmony_ci * @ops: user-specific callbacks 4898c2ecf20Sopenharmony_ci * @objagg_hints: hints, can be NULL 4908c2ecf20Sopenharmony_ci * @priv: pointer to a private data passed to the ops 4918c2ecf20Sopenharmony_ci * 4928c2ecf20Sopenharmony_ci * Note: all locking must be provided by the caller. 4938c2ecf20Sopenharmony_ci * 4948c2ecf20Sopenharmony_ci * The purpose of the library is to provide an infrastructure to 4958c2ecf20Sopenharmony_ci * aggregate user-specified objects. Library does not care about the type 4968c2ecf20Sopenharmony_ci * of the object. User fills-up ops which take care of the specific 4978c2ecf20Sopenharmony_ci * user object manipulation. 4988c2ecf20Sopenharmony_ci * 4998c2ecf20Sopenharmony_ci * As a very stupid example, consider integer numbers. For example 5008c2ecf20Sopenharmony_ci * number 8 as a root object. That can aggregate number 9 with delta 1, 5018c2ecf20Sopenharmony_ci * number 10 with delta 2, etc. This example is implemented as 5028c2ecf20Sopenharmony_ci * a part of a testing module in test_objagg.c file. 5038c2ecf20Sopenharmony_ci * 5048c2ecf20Sopenharmony_ci * Each objagg instance contains multiple trees. Each tree node is 5058c2ecf20Sopenharmony_ci * represented by "an object". In the current implementation there can be 5068c2ecf20Sopenharmony_ci * only roots and leafs nodes. Leaf nodes are called deltas. 5078c2ecf20Sopenharmony_ci * But in general, this can be easily extended for intermediate nodes. 5088c2ecf20Sopenharmony_ci * In that extension, a delta would be associated with all non-root 5098c2ecf20Sopenharmony_ci * nodes. 5108c2ecf20Sopenharmony_ci * 5118c2ecf20Sopenharmony_ci * Returns a pointer to newly created objagg instance in case of success, 5128c2ecf20Sopenharmony_ci * otherwise it returns pointer error using ERR_PTR macro. 5138c2ecf20Sopenharmony_ci */ 5148c2ecf20Sopenharmony_cistruct objagg *objagg_create(const struct objagg_ops *ops, 5158c2ecf20Sopenharmony_ci struct objagg_hints *objagg_hints, void *priv) 5168c2ecf20Sopenharmony_ci{ 5178c2ecf20Sopenharmony_ci struct objagg *objagg; 5188c2ecf20Sopenharmony_ci int err; 5198c2ecf20Sopenharmony_ci 5208c2ecf20Sopenharmony_ci if (WARN_ON(!ops || !ops->root_create || !ops->root_destroy || 5218c2ecf20Sopenharmony_ci !ops->delta_check || !ops->delta_create || 5228c2ecf20Sopenharmony_ci !ops->delta_destroy)) 5238c2ecf20Sopenharmony_ci return ERR_PTR(-EINVAL); 5248c2ecf20Sopenharmony_ci 5258c2ecf20Sopenharmony_ci objagg = kzalloc(sizeof(*objagg), GFP_KERNEL); 5268c2ecf20Sopenharmony_ci if (!objagg) 5278c2ecf20Sopenharmony_ci return ERR_PTR(-ENOMEM); 5288c2ecf20Sopenharmony_ci objagg->ops = ops; 5298c2ecf20Sopenharmony_ci if (objagg_hints) { 5308c2ecf20Sopenharmony_ci objagg->hints = objagg_hints; 5318c2ecf20Sopenharmony_ci objagg_hints->refcount++; 5328c2ecf20Sopenharmony_ci } 5338c2ecf20Sopenharmony_ci objagg->priv = priv; 5348c2ecf20Sopenharmony_ci INIT_LIST_HEAD(&objagg->obj_list); 5358c2ecf20Sopenharmony_ci 5368c2ecf20Sopenharmony_ci objagg->ht_params.key_len = ops->obj_size; 5378c2ecf20Sopenharmony_ci objagg->ht_params.key_offset = offsetof(struct objagg_obj, obj); 5388c2ecf20Sopenharmony_ci objagg->ht_params.head_offset = offsetof(struct objagg_obj, ht_node); 5398c2ecf20Sopenharmony_ci 5408c2ecf20Sopenharmony_ci err = rhashtable_init(&objagg->obj_ht, &objagg->ht_params); 5418c2ecf20Sopenharmony_ci if (err) 5428c2ecf20Sopenharmony_ci goto err_rhashtable_init; 5438c2ecf20Sopenharmony_ci 5448c2ecf20Sopenharmony_ci ida_init(&objagg->root_ida); 5458c2ecf20Sopenharmony_ci 5468c2ecf20Sopenharmony_ci trace_objagg_create(objagg); 5478c2ecf20Sopenharmony_ci return objagg; 5488c2ecf20Sopenharmony_ci 5498c2ecf20Sopenharmony_cierr_rhashtable_init: 5508c2ecf20Sopenharmony_ci kfree(objagg); 5518c2ecf20Sopenharmony_ci return ERR_PTR(err); 5528c2ecf20Sopenharmony_ci} 5538c2ecf20Sopenharmony_ciEXPORT_SYMBOL(objagg_create); 5548c2ecf20Sopenharmony_ci 5558c2ecf20Sopenharmony_ci/** 5568c2ecf20Sopenharmony_ci * objagg_destroy - destroys a new objagg instance 5578c2ecf20Sopenharmony_ci * @objagg: objagg instance 5588c2ecf20Sopenharmony_ci * 5598c2ecf20Sopenharmony_ci * Note: all locking must be provided by the caller. 5608c2ecf20Sopenharmony_ci */ 5618c2ecf20Sopenharmony_civoid objagg_destroy(struct objagg *objagg) 5628c2ecf20Sopenharmony_ci{ 5638c2ecf20Sopenharmony_ci trace_objagg_destroy(objagg); 5648c2ecf20Sopenharmony_ci ida_destroy(&objagg->root_ida); 5658c2ecf20Sopenharmony_ci WARN_ON(!list_empty(&objagg->obj_list)); 5668c2ecf20Sopenharmony_ci rhashtable_destroy(&objagg->obj_ht); 5678c2ecf20Sopenharmony_ci if (objagg->hints) 5688c2ecf20Sopenharmony_ci objagg_hints_put(objagg->hints); 5698c2ecf20Sopenharmony_ci kfree(objagg); 5708c2ecf20Sopenharmony_ci} 5718c2ecf20Sopenharmony_ciEXPORT_SYMBOL(objagg_destroy); 5728c2ecf20Sopenharmony_ci 5738c2ecf20Sopenharmony_cistatic int objagg_stats_info_sort_cmp_func(const void *a, const void *b) 5748c2ecf20Sopenharmony_ci{ 5758c2ecf20Sopenharmony_ci const struct objagg_obj_stats_info *stats_info1 = a; 5768c2ecf20Sopenharmony_ci const struct objagg_obj_stats_info *stats_info2 = b; 5778c2ecf20Sopenharmony_ci 5788c2ecf20Sopenharmony_ci if (stats_info1->is_root != stats_info2->is_root) 5798c2ecf20Sopenharmony_ci return stats_info2->is_root - stats_info1->is_root; 5808c2ecf20Sopenharmony_ci if (stats_info1->stats.delta_user_count != 5818c2ecf20Sopenharmony_ci stats_info2->stats.delta_user_count) 5828c2ecf20Sopenharmony_ci return stats_info2->stats.delta_user_count - 5838c2ecf20Sopenharmony_ci stats_info1->stats.delta_user_count; 5848c2ecf20Sopenharmony_ci return stats_info2->stats.user_count - stats_info1->stats.user_count; 5858c2ecf20Sopenharmony_ci} 5868c2ecf20Sopenharmony_ci 5878c2ecf20Sopenharmony_ci/** 5888c2ecf20Sopenharmony_ci * objagg_stats_get - obtains stats of the objagg instance 5898c2ecf20Sopenharmony_ci * @objagg: objagg instance 5908c2ecf20Sopenharmony_ci * 5918c2ecf20Sopenharmony_ci * Note: all locking must be provided by the caller. 5928c2ecf20Sopenharmony_ci * 5938c2ecf20Sopenharmony_ci * The returned structure contains statistics of all object 5948c2ecf20Sopenharmony_ci * currently in use, ordered by following rules: 5958c2ecf20Sopenharmony_ci * 1) Root objects are always on lower indexes than the rest. 5968c2ecf20Sopenharmony_ci * 2) Objects with higher delta user count are always on lower 5978c2ecf20Sopenharmony_ci * indexes. 5988c2ecf20Sopenharmony_ci * 3) In case more objects have the same delta user count, 5998c2ecf20Sopenharmony_ci * the objects are ordered by user count. 6008c2ecf20Sopenharmony_ci * 6018c2ecf20Sopenharmony_ci * Returns a pointer to stats instance in case of success, 6028c2ecf20Sopenharmony_ci * otherwise it returns pointer error using ERR_PTR macro. 6038c2ecf20Sopenharmony_ci */ 6048c2ecf20Sopenharmony_ciconst struct objagg_stats *objagg_stats_get(struct objagg *objagg) 6058c2ecf20Sopenharmony_ci{ 6068c2ecf20Sopenharmony_ci struct objagg_stats *objagg_stats; 6078c2ecf20Sopenharmony_ci struct objagg_obj *objagg_obj; 6088c2ecf20Sopenharmony_ci int i; 6098c2ecf20Sopenharmony_ci 6108c2ecf20Sopenharmony_ci objagg_stats = kzalloc(struct_size(objagg_stats, stats_info, 6118c2ecf20Sopenharmony_ci objagg->obj_count), GFP_KERNEL); 6128c2ecf20Sopenharmony_ci if (!objagg_stats) 6138c2ecf20Sopenharmony_ci return ERR_PTR(-ENOMEM); 6148c2ecf20Sopenharmony_ci 6158c2ecf20Sopenharmony_ci i = 0; 6168c2ecf20Sopenharmony_ci list_for_each_entry(objagg_obj, &objagg->obj_list, list) { 6178c2ecf20Sopenharmony_ci memcpy(&objagg_stats->stats_info[i].stats, &objagg_obj->stats, 6188c2ecf20Sopenharmony_ci sizeof(objagg_stats->stats_info[0].stats)); 6198c2ecf20Sopenharmony_ci objagg_stats->stats_info[i].objagg_obj = objagg_obj; 6208c2ecf20Sopenharmony_ci objagg_stats->stats_info[i].is_root = 6218c2ecf20Sopenharmony_ci objagg_obj_is_root(objagg_obj); 6228c2ecf20Sopenharmony_ci if (objagg_stats->stats_info[i].is_root) 6238c2ecf20Sopenharmony_ci objagg_stats->root_count++; 6248c2ecf20Sopenharmony_ci i++; 6258c2ecf20Sopenharmony_ci } 6268c2ecf20Sopenharmony_ci objagg_stats->stats_info_count = i; 6278c2ecf20Sopenharmony_ci 6288c2ecf20Sopenharmony_ci sort(objagg_stats->stats_info, objagg_stats->stats_info_count, 6298c2ecf20Sopenharmony_ci sizeof(struct objagg_obj_stats_info), 6308c2ecf20Sopenharmony_ci objagg_stats_info_sort_cmp_func, NULL); 6318c2ecf20Sopenharmony_ci 6328c2ecf20Sopenharmony_ci return objagg_stats; 6338c2ecf20Sopenharmony_ci} 6348c2ecf20Sopenharmony_ciEXPORT_SYMBOL(objagg_stats_get); 6358c2ecf20Sopenharmony_ci 6368c2ecf20Sopenharmony_ci/** 6378c2ecf20Sopenharmony_ci * objagg_stats_put - puts stats of the objagg instance 6388c2ecf20Sopenharmony_ci * @objagg_stats: objagg instance stats 6398c2ecf20Sopenharmony_ci * 6408c2ecf20Sopenharmony_ci * Note: all locking must be provided by the caller. 6418c2ecf20Sopenharmony_ci */ 6428c2ecf20Sopenharmony_civoid objagg_stats_put(const struct objagg_stats *objagg_stats) 6438c2ecf20Sopenharmony_ci{ 6448c2ecf20Sopenharmony_ci kfree(objagg_stats); 6458c2ecf20Sopenharmony_ci} 6468c2ecf20Sopenharmony_ciEXPORT_SYMBOL(objagg_stats_put); 6478c2ecf20Sopenharmony_ci 6488c2ecf20Sopenharmony_cistatic struct objagg_hints_node * 6498c2ecf20Sopenharmony_ciobjagg_hints_node_create(struct objagg_hints *objagg_hints, 6508c2ecf20Sopenharmony_ci struct objagg_obj *objagg_obj, size_t obj_size, 6518c2ecf20Sopenharmony_ci struct objagg_hints_node *parent_hnode) 6528c2ecf20Sopenharmony_ci{ 6538c2ecf20Sopenharmony_ci unsigned int user_count = objagg_obj->stats.user_count; 6548c2ecf20Sopenharmony_ci struct objagg_hints_node *hnode; 6558c2ecf20Sopenharmony_ci int err; 6568c2ecf20Sopenharmony_ci 6578c2ecf20Sopenharmony_ci hnode = kzalloc(sizeof(*hnode) + obj_size, GFP_KERNEL); 6588c2ecf20Sopenharmony_ci if (!hnode) 6598c2ecf20Sopenharmony_ci return ERR_PTR(-ENOMEM); 6608c2ecf20Sopenharmony_ci memcpy(hnode->obj, &objagg_obj->obj, obj_size); 6618c2ecf20Sopenharmony_ci hnode->stats_info.stats.user_count = user_count; 6628c2ecf20Sopenharmony_ci hnode->stats_info.stats.delta_user_count = user_count; 6638c2ecf20Sopenharmony_ci if (parent_hnode) { 6648c2ecf20Sopenharmony_ci parent_hnode->stats_info.stats.delta_user_count += user_count; 6658c2ecf20Sopenharmony_ci } else { 6668c2ecf20Sopenharmony_ci hnode->root_id = objagg_hints->root_count++; 6678c2ecf20Sopenharmony_ci hnode->stats_info.is_root = true; 6688c2ecf20Sopenharmony_ci } 6698c2ecf20Sopenharmony_ci hnode->stats_info.objagg_obj = objagg_obj; 6708c2ecf20Sopenharmony_ci 6718c2ecf20Sopenharmony_ci err = rhashtable_insert_fast(&objagg_hints->node_ht, &hnode->ht_node, 6728c2ecf20Sopenharmony_ci objagg_hints->ht_params); 6738c2ecf20Sopenharmony_ci if (err) 6748c2ecf20Sopenharmony_ci goto err_ht_insert; 6758c2ecf20Sopenharmony_ci 6768c2ecf20Sopenharmony_ci list_add(&hnode->list, &objagg_hints->node_list); 6778c2ecf20Sopenharmony_ci hnode->parent = parent_hnode; 6788c2ecf20Sopenharmony_ci objagg_hints->node_count++; 6798c2ecf20Sopenharmony_ci 6808c2ecf20Sopenharmony_ci return hnode; 6818c2ecf20Sopenharmony_ci 6828c2ecf20Sopenharmony_cierr_ht_insert: 6838c2ecf20Sopenharmony_ci kfree(hnode); 6848c2ecf20Sopenharmony_ci return ERR_PTR(err); 6858c2ecf20Sopenharmony_ci} 6868c2ecf20Sopenharmony_ci 6878c2ecf20Sopenharmony_cistatic void objagg_hints_flush(struct objagg_hints *objagg_hints) 6888c2ecf20Sopenharmony_ci{ 6898c2ecf20Sopenharmony_ci struct objagg_hints_node *hnode, *tmp; 6908c2ecf20Sopenharmony_ci 6918c2ecf20Sopenharmony_ci list_for_each_entry_safe(hnode, tmp, &objagg_hints->node_list, list) { 6928c2ecf20Sopenharmony_ci list_del(&hnode->list); 6938c2ecf20Sopenharmony_ci rhashtable_remove_fast(&objagg_hints->node_ht, &hnode->ht_node, 6948c2ecf20Sopenharmony_ci objagg_hints->ht_params); 6958c2ecf20Sopenharmony_ci kfree(hnode); 6968c2ecf20Sopenharmony_ci } 6978c2ecf20Sopenharmony_ci} 6988c2ecf20Sopenharmony_ci 6998c2ecf20Sopenharmony_cistruct objagg_tmp_node { 7008c2ecf20Sopenharmony_ci struct objagg_obj *objagg_obj; 7018c2ecf20Sopenharmony_ci bool crossed_out; 7028c2ecf20Sopenharmony_ci}; 7038c2ecf20Sopenharmony_ci 7048c2ecf20Sopenharmony_cistruct objagg_tmp_graph { 7058c2ecf20Sopenharmony_ci struct objagg_tmp_node *nodes; 7068c2ecf20Sopenharmony_ci unsigned long nodes_count; 7078c2ecf20Sopenharmony_ci unsigned long *edges; 7088c2ecf20Sopenharmony_ci}; 7098c2ecf20Sopenharmony_ci 7108c2ecf20Sopenharmony_cistatic int objagg_tmp_graph_edge_index(struct objagg_tmp_graph *graph, 7118c2ecf20Sopenharmony_ci int parent_index, int index) 7128c2ecf20Sopenharmony_ci{ 7138c2ecf20Sopenharmony_ci return index * graph->nodes_count + parent_index; 7148c2ecf20Sopenharmony_ci} 7158c2ecf20Sopenharmony_ci 7168c2ecf20Sopenharmony_cistatic void objagg_tmp_graph_edge_set(struct objagg_tmp_graph *graph, 7178c2ecf20Sopenharmony_ci int parent_index, int index) 7188c2ecf20Sopenharmony_ci{ 7198c2ecf20Sopenharmony_ci int edge_index = objagg_tmp_graph_edge_index(graph, index, 7208c2ecf20Sopenharmony_ci parent_index); 7218c2ecf20Sopenharmony_ci 7228c2ecf20Sopenharmony_ci __set_bit(edge_index, graph->edges); 7238c2ecf20Sopenharmony_ci} 7248c2ecf20Sopenharmony_ci 7258c2ecf20Sopenharmony_cistatic bool objagg_tmp_graph_is_edge(struct objagg_tmp_graph *graph, 7268c2ecf20Sopenharmony_ci int parent_index, int index) 7278c2ecf20Sopenharmony_ci{ 7288c2ecf20Sopenharmony_ci int edge_index = objagg_tmp_graph_edge_index(graph, index, 7298c2ecf20Sopenharmony_ci parent_index); 7308c2ecf20Sopenharmony_ci 7318c2ecf20Sopenharmony_ci return test_bit(edge_index, graph->edges); 7328c2ecf20Sopenharmony_ci} 7338c2ecf20Sopenharmony_ci 7348c2ecf20Sopenharmony_cistatic unsigned int objagg_tmp_graph_node_weight(struct objagg_tmp_graph *graph, 7358c2ecf20Sopenharmony_ci unsigned int index) 7368c2ecf20Sopenharmony_ci{ 7378c2ecf20Sopenharmony_ci struct objagg_tmp_node *node = &graph->nodes[index]; 7388c2ecf20Sopenharmony_ci unsigned int weight = node->objagg_obj->stats.user_count; 7398c2ecf20Sopenharmony_ci int j; 7408c2ecf20Sopenharmony_ci 7418c2ecf20Sopenharmony_ci /* Node weight is sum of node users and all other nodes users 7428c2ecf20Sopenharmony_ci * that this node can represent with delta. 7438c2ecf20Sopenharmony_ci */ 7448c2ecf20Sopenharmony_ci 7458c2ecf20Sopenharmony_ci for (j = 0; j < graph->nodes_count; j++) { 7468c2ecf20Sopenharmony_ci if (!objagg_tmp_graph_is_edge(graph, index, j)) 7478c2ecf20Sopenharmony_ci continue; 7488c2ecf20Sopenharmony_ci node = &graph->nodes[j]; 7498c2ecf20Sopenharmony_ci if (node->crossed_out) 7508c2ecf20Sopenharmony_ci continue; 7518c2ecf20Sopenharmony_ci weight += node->objagg_obj->stats.user_count; 7528c2ecf20Sopenharmony_ci } 7538c2ecf20Sopenharmony_ci return weight; 7548c2ecf20Sopenharmony_ci} 7558c2ecf20Sopenharmony_ci 7568c2ecf20Sopenharmony_cistatic int objagg_tmp_graph_node_max_weight(struct objagg_tmp_graph *graph) 7578c2ecf20Sopenharmony_ci{ 7588c2ecf20Sopenharmony_ci struct objagg_tmp_node *node; 7598c2ecf20Sopenharmony_ci unsigned int max_weight = 0; 7608c2ecf20Sopenharmony_ci unsigned int weight; 7618c2ecf20Sopenharmony_ci int max_index = -1; 7628c2ecf20Sopenharmony_ci int i; 7638c2ecf20Sopenharmony_ci 7648c2ecf20Sopenharmony_ci for (i = 0; i < graph->nodes_count; i++) { 7658c2ecf20Sopenharmony_ci node = &graph->nodes[i]; 7668c2ecf20Sopenharmony_ci if (node->crossed_out) 7678c2ecf20Sopenharmony_ci continue; 7688c2ecf20Sopenharmony_ci weight = objagg_tmp_graph_node_weight(graph, i); 7698c2ecf20Sopenharmony_ci if (weight >= max_weight) { 7708c2ecf20Sopenharmony_ci max_weight = weight; 7718c2ecf20Sopenharmony_ci max_index = i; 7728c2ecf20Sopenharmony_ci } 7738c2ecf20Sopenharmony_ci } 7748c2ecf20Sopenharmony_ci return max_index; 7758c2ecf20Sopenharmony_ci} 7768c2ecf20Sopenharmony_ci 7778c2ecf20Sopenharmony_cistatic struct objagg_tmp_graph *objagg_tmp_graph_create(struct objagg *objagg) 7788c2ecf20Sopenharmony_ci{ 7798c2ecf20Sopenharmony_ci unsigned int nodes_count = objagg->obj_count; 7808c2ecf20Sopenharmony_ci struct objagg_tmp_graph *graph; 7818c2ecf20Sopenharmony_ci struct objagg_tmp_node *node; 7828c2ecf20Sopenharmony_ci struct objagg_tmp_node *pnode; 7838c2ecf20Sopenharmony_ci struct objagg_obj *objagg_obj; 7848c2ecf20Sopenharmony_ci size_t alloc_size; 7858c2ecf20Sopenharmony_ci int i, j; 7868c2ecf20Sopenharmony_ci 7878c2ecf20Sopenharmony_ci graph = kzalloc(sizeof(*graph), GFP_KERNEL); 7888c2ecf20Sopenharmony_ci if (!graph) 7898c2ecf20Sopenharmony_ci return NULL; 7908c2ecf20Sopenharmony_ci 7918c2ecf20Sopenharmony_ci graph->nodes = kcalloc(nodes_count, sizeof(*graph->nodes), GFP_KERNEL); 7928c2ecf20Sopenharmony_ci if (!graph->nodes) 7938c2ecf20Sopenharmony_ci goto err_nodes_alloc; 7948c2ecf20Sopenharmony_ci graph->nodes_count = nodes_count; 7958c2ecf20Sopenharmony_ci 7968c2ecf20Sopenharmony_ci alloc_size = BITS_TO_LONGS(nodes_count * nodes_count) * 7978c2ecf20Sopenharmony_ci sizeof(unsigned long); 7988c2ecf20Sopenharmony_ci graph->edges = kzalloc(alloc_size, GFP_KERNEL); 7998c2ecf20Sopenharmony_ci if (!graph->edges) 8008c2ecf20Sopenharmony_ci goto err_edges_alloc; 8018c2ecf20Sopenharmony_ci 8028c2ecf20Sopenharmony_ci i = 0; 8038c2ecf20Sopenharmony_ci list_for_each_entry(objagg_obj, &objagg->obj_list, list) { 8048c2ecf20Sopenharmony_ci node = &graph->nodes[i++]; 8058c2ecf20Sopenharmony_ci node->objagg_obj = objagg_obj; 8068c2ecf20Sopenharmony_ci } 8078c2ecf20Sopenharmony_ci 8088c2ecf20Sopenharmony_ci /* Assemble a temporary graph. Insert edge X->Y in case Y can be 8098c2ecf20Sopenharmony_ci * in delta of X. 8108c2ecf20Sopenharmony_ci */ 8118c2ecf20Sopenharmony_ci for (i = 0; i < nodes_count; i++) { 8128c2ecf20Sopenharmony_ci for (j = 0; j < nodes_count; j++) { 8138c2ecf20Sopenharmony_ci if (i == j) 8148c2ecf20Sopenharmony_ci continue; 8158c2ecf20Sopenharmony_ci pnode = &graph->nodes[i]; 8168c2ecf20Sopenharmony_ci node = &graph->nodes[j]; 8178c2ecf20Sopenharmony_ci if (objagg->ops->delta_check(objagg->priv, 8188c2ecf20Sopenharmony_ci pnode->objagg_obj->obj, 8198c2ecf20Sopenharmony_ci node->objagg_obj->obj)) { 8208c2ecf20Sopenharmony_ci objagg_tmp_graph_edge_set(graph, i, j); 8218c2ecf20Sopenharmony_ci 8228c2ecf20Sopenharmony_ci } 8238c2ecf20Sopenharmony_ci } 8248c2ecf20Sopenharmony_ci } 8258c2ecf20Sopenharmony_ci return graph; 8268c2ecf20Sopenharmony_ci 8278c2ecf20Sopenharmony_cierr_edges_alloc: 8288c2ecf20Sopenharmony_ci kfree(graph->nodes); 8298c2ecf20Sopenharmony_cierr_nodes_alloc: 8308c2ecf20Sopenharmony_ci kfree(graph); 8318c2ecf20Sopenharmony_ci return NULL; 8328c2ecf20Sopenharmony_ci} 8338c2ecf20Sopenharmony_ci 8348c2ecf20Sopenharmony_cistatic void objagg_tmp_graph_destroy(struct objagg_tmp_graph *graph) 8358c2ecf20Sopenharmony_ci{ 8368c2ecf20Sopenharmony_ci kfree(graph->edges); 8378c2ecf20Sopenharmony_ci kfree(graph->nodes); 8388c2ecf20Sopenharmony_ci kfree(graph); 8398c2ecf20Sopenharmony_ci} 8408c2ecf20Sopenharmony_ci 8418c2ecf20Sopenharmony_cistatic int 8428c2ecf20Sopenharmony_ciobjagg_opt_simple_greedy_fillup_hints(struct objagg_hints *objagg_hints, 8438c2ecf20Sopenharmony_ci struct objagg *objagg) 8448c2ecf20Sopenharmony_ci{ 8458c2ecf20Sopenharmony_ci struct objagg_hints_node *hnode, *parent_hnode; 8468c2ecf20Sopenharmony_ci struct objagg_tmp_graph *graph; 8478c2ecf20Sopenharmony_ci struct objagg_tmp_node *node; 8488c2ecf20Sopenharmony_ci int index; 8498c2ecf20Sopenharmony_ci int j; 8508c2ecf20Sopenharmony_ci int err; 8518c2ecf20Sopenharmony_ci 8528c2ecf20Sopenharmony_ci graph = objagg_tmp_graph_create(objagg); 8538c2ecf20Sopenharmony_ci if (!graph) 8548c2ecf20Sopenharmony_ci return -ENOMEM; 8558c2ecf20Sopenharmony_ci 8568c2ecf20Sopenharmony_ci /* Find the nodes from the ones that can accommodate most users 8578c2ecf20Sopenharmony_ci * and cross them out of the graph. Save them to the hint list. 8588c2ecf20Sopenharmony_ci */ 8598c2ecf20Sopenharmony_ci while ((index = objagg_tmp_graph_node_max_weight(graph)) != -1) { 8608c2ecf20Sopenharmony_ci node = &graph->nodes[index]; 8618c2ecf20Sopenharmony_ci node->crossed_out = true; 8628c2ecf20Sopenharmony_ci hnode = objagg_hints_node_create(objagg_hints, 8638c2ecf20Sopenharmony_ci node->objagg_obj, 8648c2ecf20Sopenharmony_ci objagg->ops->obj_size, 8658c2ecf20Sopenharmony_ci NULL); 8668c2ecf20Sopenharmony_ci if (IS_ERR(hnode)) { 8678c2ecf20Sopenharmony_ci err = PTR_ERR(hnode); 8688c2ecf20Sopenharmony_ci goto out; 8698c2ecf20Sopenharmony_ci } 8708c2ecf20Sopenharmony_ci parent_hnode = hnode; 8718c2ecf20Sopenharmony_ci for (j = 0; j < graph->nodes_count; j++) { 8728c2ecf20Sopenharmony_ci if (!objagg_tmp_graph_is_edge(graph, index, j)) 8738c2ecf20Sopenharmony_ci continue; 8748c2ecf20Sopenharmony_ci node = &graph->nodes[j]; 8758c2ecf20Sopenharmony_ci if (node->crossed_out) 8768c2ecf20Sopenharmony_ci continue; 8778c2ecf20Sopenharmony_ci node->crossed_out = true; 8788c2ecf20Sopenharmony_ci hnode = objagg_hints_node_create(objagg_hints, 8798c2ecf20Sopenharmony_ci node->objagg_obj, 8808c2ecf20Sopenharmony_ci objagg->ops->obj_size, 8818c2ecf20Sopenharmony_ci parent_hnode); 8828c2ecf20Sopenharmony_ci if (IS_ERR(hnode)) { 8838c2ecf20Sopenharmony_ci err = PTR_ERR(hnode); 8848c2ecf20Sopenharmony_ci goto out; 8858c2ecf20Sopenharmony_ci } 8868c2ecf20Sopenharmony_ci } 8878c2ecf20Sopenharmony_ci } 8888c2ecf20Sopenharmony_ci 8898c2ecf20Sopenharmony_ci err = 0; 8908c2ecf20Sopenharmony_ciout: 8918c2ecf20Sopenharmony_ci objagg_tmp_graph_destroy(graph); 8928c2ecf20Sopenharmony_ci return err; 8938c2ecf20Sopenharmony_ci} 8948c2ecf20Sopenharmony_ci 8958c2ecf20Sopenharmony_cistruct objagg_opt_algo { 8968c2ecf20Sopenharmony_ci int (*fillup_hints)(struct objagg_hints *objagg_hints, 8978c2ecf20Sopenharmony_ci struct objagg *objagg); 8988c2ecf20Sopenharmony_ci}; 8998c2ecf20Sopenharmony_ci 9008c2ecf20Sopenharmony_cistatic const struct objagg_opt_algo objagg_opt_simple_greedy = { 9018c2ecf20Sopenharmony_ci .fillup_hints = objagg_opt_simple_greedy_fillup_hints, 9028c2ecf20Sopenharmony_ci}; 9038c2ecf20Sopenharmony_ci 9048c2ecf20Sopenharmony_ci 9058c2ecf20Sopenharmony_cistatic const struct objagg_opt_algo *objagg_opt_algos[] = { 9068c2ecf20Sopenharmony_ci [OBJAGG_OPT_ALGO_SIMPLE_GREEDY] = &objagg_opt_simple_greedy, 9078c2ecf20Sopenharmony_ci}; 9088c2ecf20Sopenharmony_ci 9098c2ecf20Sopenharmony_ci/** 9108c2ecf20Sopenharmony_ci * objagg_hints_get - obtains hints instance 9118c2ecf20Sopenharmony_ci * @objagg: objagg instance 9128c2ecf20Sopenharmony_ci * @opt_algo_type: type of hints finding algorithm 9138c2ecf20Sopenharmony_ci * 9148c2ecf20Sopenharmony_ci * Note: all locking must be provided by the caller. 9158c2ecf20Sopenharmony_ci * 9168c2ecf20Sopenharmony_ci * According to the algo type, the existing objects of objagg instance 9178c2ecf20Sopenharmony_ci * are going to be went-through to assemble an optimal tree. We call this 9188c2ecf20Sopenharmony_ci * tree hints. These hints can be later on used for creation of 9198c2ecf20Sopenharmony_ci * a new objagg instance. There, the future object creations are going 9208c2ecf20Sopenharmony_ci * to be consulted with these hints in order to find out, where exactly 9218c2ecf20Sopenharmony_ci * the new object should be put as a root or delta. 9228c2ecf20Sopenharmony_ci * 9238c2ecf20Sopenharmony_ci * Returns a pointer to hints instance in case of success, 9248c2ecf20Sopenharmony_ci * otherwise it returns pointer error using ERR_PTR macro. 9258c2ecf20Sopenharmony_ci */ 9268c2ecf20Sopenharmony_cistruct objagg_hints *objagg_hints_get(struct objagg *objagg, 9278c2ecf20Sopenharmony_ci enum objagg_opt_algo_type opt_algo_type) 9288c2ecf20Sopenharmony_ci{ 9298c2ecf20Sopenharmony_ci const struct objagg_opt_algo *algo = objagg_opt_algos[opt_algo_type]; 9308c2ecf20Sopenharmony_ci struct objagg_hints *objagg_hints; 9318c2ecf20Sopenharmony_ci int err; 9328c2ecf20Sopenharmony_ci 9338c2ecf20Sopenharmony_ci objagg_hints = kzalloc(sizeof(*objagg_hints), GFP_KERNEL); 9348c2ecf20Sopenharmony_ci if (!objagg_hints) 9358c2ecf20Sopenharmony_ci return ERR_PTR(-ENOMEM); 9368c2ecf20Sopenharmony_ci 9378c2ecf20Sopenharmony_ci objagg_hints->ops = objagg->ops; 9388c2ecf20Sopenharmony_ci objagg_hints->refcount = 1; 9398c2ecf20Sopenharmony_ci 9408c2ecf20Sopenharmony_ci INIT_LIST_HEAD(&objagg_hints->node_list); 9418c2ecf20Sopenharmony_ci 9428c2ecf20Sopenharmony_ci objagg_hints->ht_params.key_len = objagg->ops->obj_size; 9438c2ecf20Sopenharmony_ci objagg_hints->ht_params.key_offset = 9448c2ecf20Sopenharmony_ci offsetof(struct objagg_hints_node, obj); 9458c2ecf20Sopenharmony_ci objagg_hints->ht_params.head_offset = 9468c2ecf20Sopenharmony_ci offsetof(struct objagg_hints_node, ht_node); 9478c2ecf20Sopenharmony_ci 9488c2ecf20Sopenharmony_ci err = rhashtable_init(&objagg_hints->node_ht, &objagg_hints->ht_params); 9498c2ecf20Sopenharmony_ci if (err) 9508c2ecf20Sopenharmony_ci goto err_rhashtable_init; 9518c2ecf20Sopenharmony_ci 9528c2ecf20Sopenharmony_ci err = algo->fillup_hints(objagg_hints, objagg); 9538c2ecf20Sopenharmony_ci if (err) 9548c2ecf20Sopenharmony_ci goto err_fillup_hints; 9558c2ecf20Sopenharmony_ci 9568c2ecf20Sopenharmony_ci if (WARN_ON(objagg_hints->node_count != objagg->obj_count)) { 9578c2ecf20Sopenharmony_ci err = -EINVAL; 9588c2ecf20Sopenharmony_ci goto err_node_count_check; 9598c2ecf20Sopenharmony_ci } 9608c2ecf20Sopenharmony_ci 9618c2ecf20Sopenharmony_ci return objagg_hints; 9628c2ecf20Sopenharmony_ci 9638c2ecf20Sopenharmony_cierr_node_count_check: 9648c2ecf20Sopenharmony_cierr_fillup_hints: 9658c2ecf20Sopenharmony_ci objagg_hints_flush(objagg_hints); 9668c2ecf20Sopenharmony_ci rhashtable_destroy(&objagg_hints->node_ht); 9678c2ecf20Sopenharmony_cierr_rhashtable_init: 9688c2ecf20Sopenharmony_ci kfree(objagg_hints); 9698c2ecf20Sopenharmony_ci return ERR_PTR(err); 9708c2ecf20Sopenharmony_ci} 9718c2ecf20Sopenharmony_ciEXPORT_SYMBOL(objagg_hints_get); 9728c2ecf20Sopenharmony_ci 9738c2ecf20Sopenharmony_ci/** 9748c2ecf20Sopenharmony_ci * objagg_hints_put - puts hints instance 9758c2ecf20Sopenharmony_ci * @objagg_hints: objagg hints instance 9768c2ecf20Sopenharmony_ci * 9778c2ecf20Sopenharmony_ci * Note: all locking must be provided by the caller. 9788c2ecf20Sopenharmony_ci */ 9798c2ecf20Sopenharmony_civoid objagg_hints_put(struct objagg_hints *objagg_hints) 9808c2ecf20Sopenharmony_ci{ 9818c2ecf20Sopenharmony_ci if (--objagg_hints->refcount) 9828c2ecf20Sopenharmony_ci return; 9838c2ecf20Sopenharmony_ci objagg_hints_flush(objagg_hints); 9848c2ecf20Sopenharmony_ci rhashtable_destroy(&objagg_hints->node_ht); 9858c2ecf20Sopenharmony_ci kfree(objagg_hints); 9868c2ecf20Sopenharmony_ci} 9878c2ecf20Sopenharmony_ciEXPORT_SYMBOL(objagg_hints_put); 9888c2ecf20Sopenharmony_ci 9898c2ecf20Sopenharmony_ci/** 9908c2ecf20Sopenharmony_ci * objagg_hints_stats_get - obtains stats of the hints instance 9918c2ecf20Sopenharmony_ci * @objagg_hints: hints instance 9928c2ecf20Sopenharmony_ci * 9938c2ecf20Sopenharmony_ci * Note: all locking must be provided by the caller. 9948c2ecf20Sopenharmony_ci * 9958c2ecf20Sopenharmony_ci * The returned structure contains statistics of all objects 9968c2ecf20Sopenharmony_ci * currently in use, ordered by following rules: 9978c2ecf20Sopenharmony_ci * 1) Root objects are always on lower indexes than the rest. 9988c2ecf20Sopenharmony_ci * 2) Objects with higher delta user count are always on lower 9998c2ecf20Sopenharmony_ci * indexes. 10008c2ecf20Sopenharmony_ci * 3) In case multiple objects have the same delta user count, 10018c2ecf20Sopenharmony_ci * the objects are ordered by user count. 10028c2ecf20Sopenharmony_ci * 10038c2ecf20Sopenharmony_ci * Returns a pointer to stats instance in case of success, 10048c2ecf20Sopenharmony_ci * otherwise it returns pointer error using ERR_PTR macro. 10058c2ecf20Sopenharmony_ci */ 10068c2ecf20Sopenharmony_ciconst struct objagg_stats * 10078c2ecf20Sopenharmony_ciobjagg_hints_stats_get(struct objagg_hints *objagg_hints) 10088c2ecf20Sopenharmony_ci{ 10098c2ecf20Sopenharmony_ci struct objagg_stats *objagg_stats; 10108c2ecf20Sopenharmony_ci struct objagg_hints_node *hnode; 10118c2ecf20Sopenharmony_ci int i; 10128c2ecf20Sopenharmony_ci 10138c2ecf20Sopenharmony_ci objagg_stats = kzalloc(struct_size(objagg_stats, stats_info, 10148c2ecf20Sopenharmony_ci objagg_hints->node_count), 10158c2ecf20Sopenharmony_ci GFP_KERNEL); 10168c2ecf20Sopenharmony_ci if (!objagg_stats) 10178c2ecf20Sopenharmony_ci return ERR_PTR(-ENOMEM); 10188c2ecf20Sopenharmony_ci 10198c2ecf20Sopenharmony_ci i = 0; 10208c2ecf20Sopenharmony_ci list_for_each_entry(hnode, &objagg_hints->node_list, list) { 10218c2ecf20Sopenharmony_ci memcpy(&objagg_stats->stats_info[i], &hnode->stats_info, 10228c2ecf20Sopenharmony_ci sizeof(objagg_stats->stats_info[0])); 10238c2ecf20Sopenharmony_ci if (objagg_stats->stats_info[i].is_root) 10248c2ecf20Sopenharmony_ci objagg_stats->root_count++; 10258c2ecf20Sopenharmony_ci i++; 10268c2ecf20Sopenharmony_ci } 10278c2ecf20Sopenharmony_ci objagg_stats->stats_info_count = i; 10288c2ecf20Sopenharmony_ci 10298c2ecf20Sopenharmony_ci sort(objagg_stats->stats_info, objagg_stats->stats_info_count, 10308c2ecf20Sopenharmony_ci sizeof(struct objagg_obj_stats_info), 10318c2ecf20Sopenharmony_ci objagg_stats_info_sort_cmp_func, NULL); 10328c2ecf20Sopenharmony_ci 10338c2ecf20Sopenharmony_ci return objagg_stats; 10348c2ecf20Sopenharmony_ci} 10358c2ecf20Sopenharmony_ciEXPORT_SYMBOL(objagg_hints_stats_get); 10368c2ecf20Sopenharmony_ci 10378c2ecf20Sopenharmony_ciMODULE_LICENSE("Dual BSD/GPL"); 10388c2ecf20Sopenharmony_ciMODULE_AUTHOR("Jiri Pirko <jiri@mellanox.com>"); 10398c2ecf20Sopenharmony_ciMODULE_DESCRIPTION("Object aggregation manager"); 1040