Back to home page

OSCL-LXR

 
 

    


0001 // SPDX-License-Identifier: BSD-3-Clause OR GPL-2.0
0002 /* Copyright (c) 2018 Mellanox Technologies. All rights reserved */
0003 
0004 #include <linux/module.h>
0005 #include <linux/slab.h>
0006 #include <linux/rhashtable.h>
0007 #include <linux/idr.h>
0008 #include <linux/list.h>
0009 #include <linux/sort.h>
0010 #include <linux/objagg.h>
0011 
0012 #define CREATE_TRACE_POINTS
0013 #include <trace/events/objagg.h>
0014 
0015 struct objagg_hints {
0016     struct rhashtable node_ht;
0017     struct rhashtable_params ht_params;
0018     struct list_head node_list;
0019     unsigned int node_count;
0020     unsigned int root_count;
0021     unsigned int refcount;
0022     const struct objagg_ops *ops;
0023 };
0024 
0025 struct objagg_hints_node {
0026     struct rhash_head ht_node; /* member of objagg_hints->node_ht */
0027     struct list_head list; /* member of objagg_hints->node_list */
0028     struct objagg_hints_node *parent;
0029     unsigned int root_id;
0030     struct objagg_obj_stats_info stats_info;
0031     unsigned long obj[];
0032 };
0033 
0034 static struct objagg_hints_node *
0035 objagg_hints_lookup(struct objagg_hints *objagg_hints, void *obj)
0036 {
0037     if (!objagg_hints)
0038         return NULL;
0039     return rhashtable_lookup_fast(&objagg_hints->node_ht, obj,
0040                       objagg_hints->ht_params);
0041 }
0042 
0043 struct objagg {
0044     const struct objagg_ops *ops;
0045     void *priv;
0046     struct rhashtable obj_ht;
0047     struct rhashtable_params ht_params;
0048     struct list_head obj_list;
0049     unsigned int obj_count;
0050     struct ida root_ida;
0051     struct objagg_hints *hints;
0052 };
0053 
0054 struct objagg_obj {
0055     struct rhash_head ht_node; /* member of objagg->obj_ht */
0056     struct list_head list; /* member of objagg->obj_list */
0057     struct objagg_obj *parent; /* if the object is nested, this
0058                     * holds pointer to parent, otherwise NULL
0059                     */
0060     union {
0061         void *delta_priv; /* user delta private */
0062         void *root_priv; /* user root private */
0063     };
0064     unsigned int root_id;
0065     unsigned int refcount; /* counts number of users of this object
0066                 * including nested objects
0067                 */
0068     struct objagg_obj_stats stats;
0069     unsigned long obj[];
0070 };
0071 
0072 static unsigned int objagg_obj_ref_inc(struct objagg_obj *objagg_obj)
0073 {
0074     return ++objagg_obj->refcount;
0075 }
0076 
0077 static unsigned int objagg_obj_ref_dec(struct objagg_obj *objagg_obj)
0078 {
0079     return --objagg_obj->refcount;
0080 }
0081 
0082 static void objagg_obj_stats_inc(struct objagg_obj *objagg_obj)
0083 {
0084     objagg_obj->stats.user_count++;
0085     objagg_obj->stats.delta_user_count++;
0086     if (objagg_obj->parent)
0087         objagg_obj->parent->stats.delta_user_count++;
0088 }
0089 
0090 static void objagg_obj_stats_dec(struct objagg_obj *objagg_obj)
0091 {
0092     objagg_obj->stats.user_count--;
0093     objagg_obj->stats.delta_user_count--;
0094     if (objagg_obj->parent)
0095         objagg_obj->parent->stats.delta_user_count--;
0096 }
0097 
0098 static bool objagg_obj_is_root(const struct objagg_obj *objagg_obj)
0099 {
0100     /* Nesting is not supported, so we can use ->parent
0101      * to figure out if the object is root.
0102      */
0103     return !objagg_obj->parent;
0104 }
0105 
0106 /**
0107  * objagg_obj_root_priv - obtains root private for an object
0108  * @objagg_obj: objagg object instance
0109  *
0110  * Note: all locking must be provided by the caller.
0111  *
0112  * Either the object is root itself when the private is returned
0113  * directly, or the parent is root and its private is returned
0114  * instead.
0115  *
0116  * Returns a user private root pointer.
0117  */
0118 const void *objagg_obj_root_priv(const struct objagg_obj *objagg_obj)
0119 {
0120     if (objagg_obj_is_root(objagg_obj))
0121         return objagg_obj->root_priv;
0122     WARN_ON(!objagg_obj_is_root(objagg_obj->parent));
0123     return objagg_obj->parent->root_priv;
0124 }
0125 EXPORT_SYMBOL(objagg_obj_root_priv);
0126 
0127 /**
0128  * objagg_obj_delta_priv - obtains delta private for an object
0129  * @objagg_obj: objagg object instance
0130  *
0131  * Note: all locking must be provided by the caller.
0132  *
0133  * Returns user private delta pointer or NULL in case the passed
0134  * object is root.
0135  */
0136 const void *objagg_obj_delta_priv(const struct objagg_obj *objagg_obj)
0137 {
0138     if (objagg_obj_is_root(objagg_obj))
0139         return NULL;
0140     return objagg_obj->delta_priv;
0141 }
0142 EXPORT_SYMBOL(objagg_obj_delta_priv);
0143 
0144 /**
0145  * objagg_obj_raw - obtains object user private pointer
0146  * @objagg_obj: objagg object instance
0147  *
0148  * Note: all locking must be provided by the caller.
0149  *
0150  * Returns user private pointer as was passed to objagg_obj_get() by "obj" arg.
0151  */
0152 const void *objagg_obj_raw(const struct objagg_obj *objagg_obj)
0153 {
0154     return objagg_obj->obj;
0155 }
0156 EXPORT_SYMBOL(objagg_obj_raw);
0157 
0158 static struct objagg_obj *objagg_obj_lookup(struct objagg *objagg, void *obj)
0159 {
0160     return rhashtable_lookup_fast(&objagg->obj_ht, obj, objagg->ht_params);
0161 }
0162 
0163 static int objagg_obj_parent_assign(struct objagg *objagg,
0164                     struct objagg_obj *objagg_obj,
0165                     struct objagg_obj *parent,
0166                     bool take_parent_ref)
0167 {
0168     void *delta_priv;
0169 
0170     delta_priv = objagg->ops->delta_create(objagg->priv, parent->obj,
0171                            objagg_obj->obj);
0172     if (IS_ERR(delta_priv))
0173         return PTR_ERR(delta_priv);
0174 
0175     /* User returned a delta private, that means that
0176      * our object can be aggregated into the parent.
0177      */
0178     objagg_obj->parent = parent;
0179     objagg_obj->delta_priv = delta_priv;
0180     if (take_parent_ref)
0181         objagg_obj_ref_inc(objagg_obj->parent);
0182     trace_objagg_obj_parent_assign(objagg, objagg_obj,
0183                        parent,
0184                        parent->refcount);
0185     return 0;
0186 }
0187 
0188 static int objagg_obj_parent_lookup_assign(struct objagg *objagg,
0189                        struct objagg_obj *objagg_obj)
0190 {
0191     struct objagg_obj *objagg_obj_cur;
0192     int err;
0193 
0194     list_for_each_entry(objagg_obj_cur, &objagg->obj_list, list) {
0195         /* Nesting is not supported. In case the object
0196          * is not root, it cannot be assigned as parent.
0197          */
0198         if (!objagg_obj_is_root(objagg_obj_cur))
0199             continue;
0200         err = objagg_obj_parent_assign(objagg, objagg_obj,
0201                            objagg_obj_cur, true);
0202         if (!err)
0203             return 0;
0204     }
0205     return -ENOENT;
0206 }
0207 
0208 static void __objagg_obj_put(struct objagg *objagg,
0209                  struct objagg_obj *objagg_obj);
0210 
0211 static void objagg_obj_parent_unassign(struct objagg *objagg,
0212                        struct objagg_obj *objagg_obj)
0213 {
0214     trace_objagg_obj_parent_unassign(objagg, objagg_obj,
0215                      objagg_obj->parent,
0216                      objagg_obj->parent->refcount);
0217     objagg->ops->delta_destroy(objagg->priv, objagg_obj->delta_priv);
0218     __objagg_obj_put(objagg, objagg_obj->parent);
0219 }
0220 
0221 static int objagg_obj_root_id_alloc(struct objagg *objagg,
0222                     struct objagg_obj *objagg_obj,
0223                     struct objagg_hints_node *hnode)
0224 {
0225     unsigned int min, max;
0226     int root_id;
0227 
0228     /* In case there are no hints available, the root id is invalid. */
0229     if (!objagg->hints) {
0230         objagg_obj->root_id = OBJAGG_OBJ_ROOT_ID_INVALID;
0231         return 0;
0232     }
0233 
0234     if (hnode) {
0235         min = hnode->root_id;
0236         max = hnode->root_id;
0237     } else {
0238         /* For objects with no hint, start after the last
0239          * hinted root_id.
0240          */
0241         min = objagg->hints->root_count;
0242         max = ~0;
0243     }
0244 
0245     root_id = ida_alloc_range(&objagg->root_ida, min, max, GFP_KERNEL);
0246 
0247     if (root_id < 0)
0248         return root_id;
0249     objagg_obj->root_id = root_id;
0250     return 0;
0251 }
0252 
0253 static void objagg_obj_root_id_free(struct objagg *objagg,
0254                     struct objagg_obj *objagg_obj)
0255 {
0256     if (!objagg->hints)
0257         return;
0258     ida_free(&objagg->root_ida, objagg_obj->root_id);
0259 }
0260 
0261 static int objagg_obj_root_create(struct objagg *objagg,
0262                   struct objagg_obj *objagg_obj,
0263                   struct objagg_hints_node *hnode)
0264 {
0265     int err;
0266 
0267     err = objagg_obj_root_id_alloc(objagg, objagg_obj, hnode);
0268     if (err)
0269         return err;
0270     objagg_obj->root_priv = objagg->ops->root_create(objagg->priv,
0271                              objagg_obj->obj,
0272                              objagg_obj->root_id);
0273     if (IS_ERR(objagg_obj->root_priv)) {
0274         err = PTR_ERR(objagg_obj->root_priv);
0275         goto err_root_create;
0276     }
0277     trace_objagg_obj_root_create(objagg, objagg_obj);
0278     return 0;
0279 
0280 err_root_create:
0281     objagg_obj_root_id_free(objagg, objagg_obj);
0282     return err;
0283 }
0284 
0285 static void objagg_obj_root_destroy(struct objagg *objagg,
0286                     struct objagg_obj *objagg_obj)
0287 {
0288     trace_objagg_obj_root_destroy(objagg, objagg_obj);
0289     objagg->ops->root_destroy(objagg->priv, objagg_obj->root_priv);
0290     objagg_obj_root_id_free(objagg, objagg_obj);
0291 }
0292 
0293 static struct objagg_obj *__objagg_obj_get(struct objagg *objagg, void *obj);
0294 
0295 static int objagg_obj_init_with_hints(struct objagg *objagg,
0296                       struct objagg_obj *objagg_obj,
0297                       bool *hint_found)
0298 {
0299     struct objagg_hints_node *hnode;
0300     struct objagg_obj *parent;
0301     int err;
0302 
0303     hnode = objagg_hints_lookup(objagg->hints, objagg_obj->obj);
0304     if (!hnode) {
0305         *hint_found = false;
0306         return 0;
0307     }
0308     *hint_found = true;
0309 
0310     if (!hnode->parent)
0311         return objagg_obj_root_create(objagg, objagg_obj, hnode);
0312 
0313     parent = __objagg_obj_get(objagg, hnode->parent->obj);
0314     if (IS_ERR(parent))
0315         return PTR_ERR(parent);
0316 
0317     err = objagg_obj_parent_assign(objagg, objagg_obj, parent, false);
0318     if (err) {
0319         *hint_found = false;
0320         err = 0;
0321         goto err_parent_assign;
0322     }
0323 
0324     return 0;
0325 
0326 err_parent_assign:
0327     objagg_obj_put(objagg, parent);
0328     return err;
0329 }
0330 
0331 static int objagg_obj_init(struct objagg *objagg,
0332                struct objagg_obj *objagg_obj)
0333 {
0334     bool hint_found;
0335     int err;
0336 
0337     /* First, try to use hints if they are available and
0338      * if they provide result.
0339      */
0340     err = objagg_obj_init_with_hints(objagg, objagg_obj, &hint_found);
0341     if (err)
0342         return err;
0343 
0344     if (hint_found)
0345         return 0;
0346 
0347     /* Try to find if the object can be aggregated under an existing one. */
0348     err = objagg_obj_parent_lookup_assign(objagg, objagg_obj);
0349     if (!err)
0350         return 0;
0351     /* If aggregation is not possible, make the object a root. */
0352     return objagg_obj_root_create(objagg, objagg_obj, NULL);
0353 }
0354 
0355 static void objagg_obj_fini(struct objagg *objagg,
0356                 struct objagg_obj *objagg_obj)
0357 {
0358     if (!objagg_obj_is_root(objagg_obj))
0359         objagg_obj_parent_unassign(objagg, objagg_obj);
0360     else
0361         objagg_obj_root_destroy(objagg, objagg_obj);
0362 }
0363 
0364 static struct objagg_obj *objagg_obj_create(struct objagg *objagg, void *obj)
0365 {
0366     struct objagg_obj *objagg_obj;
0367     int err;
0368 
0369     objagg_obj = kzalloc(sizeof(*objagg_obj) + objagg->ops->obj_size,
0370                  GFP_KERNEL);
0371     if (!objagg_obj)
0372         return ERR_PTR(-ENOMEM);
0373     objagg_obj_ref_inc(objagg_obj);
0374     memcpy(objagg_obj->obj, obj, objagg->ops->obj_size);
0375 
0376     err = objagg_obj_init(objagg, objagg_obj);
0377     if (err)
0378         goto err_obj_init;
0379 
0380     err = rhashtable_insert_fast(&objagg->obj_ht, &objagg_obj->ht_node,
0381                      objagg->ht_params);
0382     if (err)
0383         goto err_ht_insert;
0384     list_add(&objagg_obj->list, &objagg->obj_list);
0385     objagg->obj_count++;
0386     trace_objagg_obj_create(objagg, objagg_obj);
0387 
0388     return objagg_obj;
0389 
0390 err_ht_insert:
0391     objagg_obj_fini(objagg, objagg_obj);
0392 err_obj_init:
0393     kfree(objagg_obj);
0394     return ERR_PTR(err);
0395 }
0396 
0397 static struct objagg_obj *__objagg_obj_get(struct objagg *objagg, void *obj)
0398 {
0399     struct objagg_obj *objagg_obj;
0400 
0401     /* First, try to find the object exactly as user passed it,
0402      * perhaps it is already in use.
0403      */
0404     objagg_obj = objagg_obj_lookup(objagg, obj);
0405     if (objagg_obj) {
0406         objagg_obj_ref_inc(objagg_obj);
0407         return objagg_obj;
0408     }
0409 
0410     return objagg_obj_create(objagg, obj);
0411 }
0412 
0413 /**
0414  * objagg_obj_get - gets an object within objagg instance
0415  * @objagg: objagg instance
0416  * @obj:    user-specific private object pointer
0417  *
0418  * Note: all locking must be provided by the caller.
0419  *
0420  * Size of the "obj" memory is specified in "objagg->ops".
0421  *
0422  * There are 3 main options this function wraps:
0423  * 1) The object according to "obj" already exist. In that case
0424  *    the reference counter is incrementes and the object is returned.
0425  * 2) The object does not exist, but it can be aggregated within
0426  *    another object. In that case, user ops->delta_create() is called
0427  *    to obtain delta data and a new object is created with returned
0428  *    user-delta private pointer.
0429  * 3) The object does not exist and cannot be aggregated into
0430  *    any of the existing objects. In that case, user ops->root_create()
0431  *    is called to create the root and a new object is created with
0432  *    returned user-root private pointer.
0433  *
0434  * Returns a pointer to objagg object instance in case of success,
0435  * otherwise it returns pointer error using ERR_PTR macro.
0436  */
0437 struct objagg_obj *objagg_obj_get(struct objagg *objagg, void *obj)
0438 {
0439     struct objagg_obj *objagg_obj;
0440 
0441     objagg_obj = __objagg_obj_get(objagg, obj);
0442     if (IS_ERR(objagg_obj))
0443         return objagg_obj;
0444     objagg_obj_stats_inc(objagg_obj);
0445     trace_objagg_obj_get(objagg, objagg_obj, objagg_obj->refcount);
0446     return objagg_obj;
0447 }
0448 EXPORT_SYMBOL(objagg_obj_get);
0449 
0450 static void objagg_obj_destroy(struct objagg *objagg,
0451                    struct objagg_obj *objagg_obj)
0452 {
0453     trace_objagg_obj_destroy(objagg, objagg_obj);
0454     --objagg->obj_count;
0455     list_del(&objagg_obj->list);
0456     rhashtable_remove_fast(&objagg->obj_ht, &objagg_obj->ht_node,
0457                    objagg->ht_params);
0458     objagg_obj_fini(objagg, objagg_obj);
0459     kfree(objagg_obj);
0460 }
0461 
0462 static void __objagg_obj_put(struct objagg *objagg,
0463                  struct objagg_obj *objagg_obj)
0464 {
0465     if (!objagg_obj_ref_dec(objagg_obj))
0466         objagg_obj_destroy(objagg, objagg_obj);
0467 }
0468 
0469 /**
0470  * objagg_obj_put - puts an object within objagg instance
0471  * @objagg: objagg instance
0472  * @objagg_obj: objagg object instance
0473  *
0474  * Note: all locking must be provided by the caller.
0475  *
0476  * Symmetric to objagg_obj_get().
0477  */
0478 void objagg_obj_put(struct objagg *objagg, struct objagg_obj *objagg_obj)
0479 {
0480     trace_objagg_obj_put(objagg, objagg_obj, objagg_obj->refcount);
0481     objagg_obj_stats_dec(objagg_obj);
0482     __objagg_obj_put(objagg, objagg_obj);
0483 }
0484 EXPORT_SYMBOL(objagg_obj_put);
0485 
0486 /**
0487  * objagg_create - creates a new objagg instance
0488  * @ops:        user-specific callbacks
0489  * @objagg_hints:   hints, can be NULL
0490  * @priv:       pointer to a private data passed to the ops
0491  *
0492  * Note: all locking must be provided by the caller.
0493  *
0494  * The purpose of the library is to provide an infrastructure to
0495  * aggregate user-specified objects. Library does not care about the type
0496  * of the object. User fills-up ops which take care of the specific
0497  * user object manipulation.
0498  *
0499  * As a very stupid example, consider integer numbers. For example
0500  * number 8 as a root object. That can aggregate number 9 with delta 1,
0501  * number 10 with delta 2, etc. This example is implemented as
0502  * a part of a testing module in test_objagg.c file.
0503  *
0504  * Each objagg instance contains multiple trees. Each tree node is
0505  * represented by "an object". In the current implementation there can be
0506  * only roots and leafs nodes. Leaf nodes are called deltas.
0507  * But in general, this can be easily extended for intermediate nodes.
0508  * In that extension, a delta would be associated with all non-root
0509  * nodes.
0510  *
0511  * Returns a pointer to newly created objagg instance in case of success,
0512  * otherwise it returns pointer error using ERR_PTR macro.
0513  */
0514 struct objagg *objagg_create(const struct objagg_ops *ops,
0515                  struct objagg_hints *objagg_hints, void *priv)
0516 {
0517     struct objagg *objagg;
0518     int err;
0519 
0520     if (WARN_ON(!ops || !ops->root_create || !ops->root_destroy ||
0521             !ops->delta_check || !ops->delta_create ||
0522             !ops->delta_destroy))
0523         return ERR_PTR(-EINVAL);
0524 
0525     objagg = kzalloc(sizeof(*objagg), GFP_KERNEL);
0526     if (!objagg)
0527         return ERR_PTR(-ENOMEM);
0528     objagg->ops = ops;
0529     if (objagg_hints) {
0530         objagg->hints = objagg_hints;
0531         objagg_hints->refcount++;
0532     }
0533     objagg->priv = priv;
0534     INIT_LIST_HEAD(&objagg->obj_list);
0535 
0536     objagg->ht_params.key_len = ops->obj_size;
0537     objagg->ht_params.key_offset = offsetof(struct objagg_obj, obj);
0538     objagg->ht_params.head_offset = offsetof(struct objagg_obj, ht_node);
0539 
0540     err = rhashtable_init(&objagg->obj_ht, &objagg->ht_params);
0541     if (err)
0542         goto err_rhashtable_init;
0543 
0544     ida_init(&objagg->root_ida);
0545 
0546     trace_objagg_create(objagg);
0547     return objagg;
0548 
0549 err_rhashtable_init:
0550     kfree(objagg);
0551     return ERR_PTR(err);
0552 }
0553 EXPORT_SYMBOL(objagg_create);
0554 
0555 /**
0556  * objagg_destroy - destroys a new objagg instance
0557  * @objagg: objagg instance
0558  *
0559  * Note: all locking must be provided by the caller.
0560  */
0561 void objagg_destroy(struct objagg *objagg)
0562 {
0563     trace_objagg_destroy(objagg);
0564     ida_destroy(&objagg->root_ida);
0565     WARN_ON(!list_empty(&objagg->obj_list));
0566     rhashtable_destroy(&objagg->obj_ht);
0567     if (objagg->hints)
0568         objagg_hints_put(objagg->hints);
0569     kfree(objagg);
0570 }
0571 EXPORT_SYMBOL(objagg_destroy);
0572 
0573 static int objagg_stats_info_sort_cmp_func(const void *a, const void *b)
0574 {
0575     const struct objagg_obj_stats_info *stats_info1 = a;
0576     const struct objagg_obj_stats_info *stats_info2 = b;
0577 
0578     if (stats_info1->is_root != stats_info2->is_root)
0579         return stats_info2->is_root - stats_info1->is_root;
0580     if (stats_info1->stats.delta_user_count !=
0581         stats_info2->stats.delta_user_count)
0582         return stats_info2->stats.delta_user_count -
0583                stats_info1->stats.delta_user_count;
0584     return stats_info2->stats.user_count - stats_info1->stats.user_count;
0585 }
0586 
0587 /**
0588  * objagg_stats_get - obtains stats of the objagg instance
0589  * @objagg: objagg instance
0590  *
0591  * Note: all locking must be provided by the caller.
0592  *
0593  * The returned structure contains statistics of all object
0594  * currently in use, ordered by following rules:
0595  * 1) Root objects are always on lower indexes than the rest.
0596  * 2) Objects with higher delta user count are always on lower
0597  *    indexes.
0598  * 3) In case more objects have the same delta user count,
0599  *    the objects are ordered by user count.
0600  *
0601  * Returns a pointer to stats instance in case of success,
0602  * otherwise it returns pointer error using ERR_PTR macro.
0603  */
0604 const struct objagg_stats *objagg_stats_get(struct objagg *objagg)
0605 {
0606     struct objagg_stats *objagg_stats;
0607     struct objagg_obj *objagg_obj;
0608     int i;
0609 
0610     objagg_stats = kzalloc(struct_size(objagg_stats, stats_info,
0611                        objagg->obj_count), GFP_KERNEL);
0612     if (!objagg_stats)
0613         return ERR_PTR(-ENOMEM);
0614 
0615     i = 0;
0616     list_for_each_entry(objagg_obj, &objagg->obj_list, list) {
0617         memcpy(&objagg_stats->stats_info[i].stats, &objagg_obj->stats,
0618                sizeof(objagg_stats->stats_info[0].stats));
0619         objagg_stats->stats_info[i].objagg_obj = objagg_obj;
0620         objagg_stats->stats_info[i].is_root =
0621                     objagg_obj_is_root(objagg_obj);
0622         if (objagg_stats->stats_info[i].is_root)
0623             objagg_stats->root_count++;
0624         i++;
0625     }
0626     objagg_stats->stats_info_count = i;
0627 
0628     sort(objagg_stats->stats_info, objagg_stats->stats_info_count,
0629          sizeof(struct objagg_obj_stats_info),
0630          objagg_stats_info_sort_cmp_func, NULL);
0631 
0632     return objagg_stats;
0633 }
0634 EXPORT_SYMBOL(objagg_stats_get);
0635 
0636 /**
0637  * objagg_stats_put - puts stats of the objagg instance
0638  * @objagg_stats:   objagg instance stats
0639  *
0640  * Note: all locking must be provided by the caller.
0641  */
0642 void objagg_stats_put(const struct objagg_stats *objagg_stats)
0643 {
0644     kfree(objagg_stats);
0645 }
0646 EXPORT_SYMBOL(objagg_stats_put);
0647 
0648 static struct objagg_hints_node *
0649 objagg_hints_node_create(struct objagg_hints *objagg_hints,
0650              struct objagg_obj *objagg_obj, size_t obj_size,
0651              struct objagg_hints_node *parent_hnode)
0652 {
0653     unsigned int user_count = objagg_obj->stats.user_count;
0654     struct objagg_hints_node *hnode;
0655     int err;
0656 
0657     hnode = kzalloc(sizeof(*hnode) + obj_size, GFP_KERNEL);
0658     if (!hnode)
0659         return ERR_PTR(-ENOMEM);
0660     memcpy(hnode->obj, &objagg_obj->obj, obj_size);
0661     hnode->stats_info.stats.user_count = user_count;
0662     hnode->stats_info.stats.delta_user_count = user_count;
0663     if (parent_hnode) {
0664         parent_hnode->stats_info.stats.delta_user_count += user_count;
0665     } else {
0666         hnode->root_id = objagg_hints->root_count++;
0667         hnode->stats_info.is_root = true;
0668     }
0669     hnode->stats_info.objagg_obj = objagg_obj;
0670 
0671     err = rhashtable_insert_fast(&objagg_hints->node_ht, &hnode->ht_node,
0672                      objagg_hints->ht_params);
0673     if (err)
0674         goto err_ht_insert;
0675 
0676     list_add(&hnode->list, &objagg_hints->node_list);
0677     hnode->parent = parent_hnode;
0678     objagg_hints->node_count++;
0679 
0680     return hnode;
0681 
0682 err_ht_insert:
0683     kfree(hnode);
0684     return ERR_PTR(err);
0685 }
0686 
0687 static void objagg_hints_flush(struct objagg_hints *objagg_hints)
0688 {
0689     struct objagg_hints_node *hnode, *tmp;
0690 
0691     list_for_each_entry_safe(hnode, tmp, &objagg_hints->node_list, list) {
0692         list_del(&hnode->list);
0693         rhashtable_remove_fast(&objagg_hints->node_ht, &hnode->ht_node,
0694                        objagg_hints->ht_params);
0695         kfree(hnode);
0696     }
0697 }
0698 
0699 struct objagg_tmp_node {
0700     struct objagg_obj *objagg_obj;
0701     bool crossed_out;
0702 };
0703 
0704 struct objagg_tmp_graph {
0705     struct objagg_tmp_node *nodes;
0706     unsigned long nodes_count;
0707     unsigned long *edges;
0708 };
0709 
0710 static int objagg_tmp_graph_edge_index(struct objagg_tmp_graph *graph,
0711                        int parent_index, int index)
0712 {
0713     return index * graph->nodes_count + parent_index;
0714 }
0715 
0716 static void objagg_tmp_graph_edge_set(struct objagg_tmp_graph *graph,
0717                       int parent_index, int index)
0718 {
0719     int edge_index = objagg_tmp_graph_edge_index(graph, index,
0720                              parent_index);
0721 
0722     __set_bit(edge_index, graph->edges);
0723 }
0724 
0725 static bool objagg_tmp_graph_is_edge(struct objagg_tmp_graph *graph,
0726                      int parent_index, int index)
0727 {
0728     int edge_index = objagg_tmp_graph_edge_index(graph, index,
0729                              parent_index);
0730 
0731     return test_bit(edge_index, graph->edges);
0732 }
0733 
0734 static unsigned int objagg_tmp_graph_node_weight(struct objagg_tmp_graph *graph,
0735                          unsigned int index)
0736 {
0737     struct objagg_tmp_node *node = &graph->nodes[index];
0738     unsigned int weight = node->objagg_obj->stats.user_count;
0739     int j;
0740 
0741     /* Node weight is sum of node users and all other nodes users
0742      * that this node can represent with delta.
0743      */
0744 
0745     for (j = 0; j < graph->nodes_count; j++) {
0746         if (!objagg_tmp_graph_is_edge(graph, index, j))
0747             continue;
0748         node = &graph->nodes[j];
0749         if (node->crossed_out)
0750             continue;
0751         weight += node->objagg_obj->stats.user_count;
0752     }
0753     return weight;
0754 }
0755 
0756 static int objagg_tmp_graph_node_max_weight(struct objagg_tmp_graph *graph)
0757 {
0758     struct objagg_tmp_node *node;
0759     unsigned int max_weight = 0;
0760     unsigned int weight;
0761     int max_index = -1;
0762     int i;
0763 
0764     for (i = 0; i < graph->nodes_count; i++) {
0765         node = &graph->nodes[i];
0766         if (node->crossed_out)
0767             continue;
0768         weight = objagg_tmp_graph_node_weight(graph, i);
0769         if (weight >= max_weight) {
0770             max_weight = weight;
0771             max_index = i;
0772         }
0773     }
0774     return max_index;
0775 }
0776 
0777 static struct objagg_tmp_graph *objagg_tmp_graph_create(struct objagg *objagg)
0778 {
0779     unsigned int nodes_count = objagg->obj_count;
0780     struct objagg_tmp_graph *graph;
0781     struct objagg_tmp_node *node;
0782     struct objagg_tmp_node *pnode;
0783     struct objagg_obj *objagg_obj;
0784     int i, j;
0785 
0786     graph = kzalloc(sizeof(*graph), GFP_KERNEL);
0787     if (!graph)
0788         return NULL;
0789 
0790     graph->nodes = kcalloc(nodes_count, sizeof(*graph->nodes), GFP_KERNEL);
0791     if (!graph->nodes)
0792         goto err_nodes_alloc;
0793     graph->nodes_count = nodes_count;
0794 
0795     graph->edges = bitmap_zalloc(nodes_count * nodes_count, GFP_KERNEL);
0796     if (!graph->edges)
0797         goto err_edges_alloc;
0798 
0799     i = 0;
0800     list_for_each_entry(objagg_obj, &objagg->obj_list, list) {
0801         node = &graph->nodes[i++];
0802         node->objagg_obj = objagg_obj;
0803     }
0804 
0805     /* Assemble a temporary graph. Insert edge X->Y in case Y can be
0806      * in delta of X.
0807      */
0808     for (i = 0; i < nodes_count; i++) {
0809         for (j = 0; j < nodes_count; j++) {
0810             if (i == j)
0811                 continue;
0812             pnode = &graph->nodes[i];
0813             node = &graph->nodes[j];
0814             if (objagg->ops->delta_check(objagg->priv,
0815                              pnode->objagg_obj->obj,
0816                              node->objagg_obj->obj)) {
0817                 objagg_tmp_graph_edge_set(graph, i, j);
0818 
0819             }
0820         }
0821     }
0822     return graph;
0823 
0824 err_edges_alloc:
0825     kfree(graph->nodes);
0826 err_nodes_alloc:
0827     kfree(graph);
0828     return NULL;
0829 }
0830 
0831 static void objagg_tmp_graph_destroy(struct objagg_tmp_graph *graph)
0832 {
0833     bitmap_free(graph->edges);
0834     kfree(graph->nodes);
0835     kfree(graph);
0836 }
0837 
0838 static int
0839 objagg_opt_simple_greedy_fillup_hints(struct objagg_hints *objagg_hints,
0840                       struct objagg *objagg)
0841 {
0842     struct objagg_hints_node *hnode, *parent_hnode;
0843     struct objagg_tmp_graph *graph;
0844     struct objagg_tmp_node *node;
0845     int index;
0846     int j;
0847     int err;
0848 
0849     graph = objagg_tmp_graph_create(objagg);
0850     if (!graph)
0851         return -ENOMEM;
0852 
0853     /* Find the nodes from the ones that can accommodate most users
0854      * and cross them out of the graph. Save them to the hint list.
0855      */
0856     while ((index = objagg_tmp_graph_node_max_weight(graph)) != -1) {
0857         node = &graph->nodes[index];
0858         node->crossed_out = true;
0859         hnode = objagg_hints_node_create(objagg_hints,
0860                          node->objagg_obj,
0861                          objagg->ops->obj_size,
0862                          NULL);
0863         if (IS_ERR(hnode)) {
0864             err = PTR_ERR(hnode);
0865             goto out;
0866         }
0867         parent_hnode = hnode;
0868         for (j = 0; j < graph->nodes_count; j++) {
0869             if (!objagg_tmp_graph_is_edge(graph, index, j))
0870                 continue;
0871             node = &graph->nodes[j];
0872             if (node->crossed_out)
0873                 continue;
0874             node->crossed_out = true;
0875             hnode = objagg_hints_node_create(objagg_hints,
0876                              node->objagg_obj,
0877                              objagg->ops->obj_size,
0878                              parent_hnode);
0879             if (IS_ERR(hnode)) {
0880                 err = PTR_ERR(hnode);
0881                 goto out;
0882             }
0883         }
0884     }
0885 
0886     err = 0;
0887 out:
0888     objagg_tmp_graph_destroy(graph);
0889     return err;
0890 }
0891 
0892 struct objagg_opt_algo {
0893     int (*fillup_hints)(struct objagg_hints *objagg_hints,
0894                 struct objagg *objagg);
0895 };
0896 
0897 static const struct objagg_opt_algo objagg_opt_simple_greedy = {
0898     .fillup_hints = objagg_opt_simple_greedy_fillup_hints,
0899 };
0900 
0901 
0902 static const struct objagg_opt_algo *objagg_opt_algos[] = {
0903     [OBJAGG_OPT_ALGO_SIMPLE_GREEDY] = &objagg_opt_simple_greedy,
0904 };
0905 
0906 static int objagg_hints_obj_cmp(struct rhashtable_compare_arg *arg,
0907                 const void *obj)
0908 {
0909     struct rhashtable *ht = arg->ht;
0910     struct objagg_hints *objagg_hints =
0911             container_of(ht, struct objagg_hints, node_ht);
0912     const struct objagg_ops *ops = objagg_hints->ops;
0913     const char *ptr = obj;
0914 
0915     ptr += ht->p.key_offset;
0916     return ops->hints_obj_cmp ? ops->hints_obj_cmp(ptr, arg->key) :
0917                     memcmp(ptr, arg->key, ht->p.key_len);
0918 }
0919 
0920 /**
0921  * objagg_hints_get - obtains hints instance
0922  * @objagg:     objagg instance
0923  * @opt_algo_type:  type of hints finding algorithm
0924  *
0925  * Note: all locking must be provided by the caller.
0926  *
0927  * According to the algo type, the existing objects of objagg instance
0928  * are going to be went-through to assemble an optimal tree. We call this
0929  * tree hints. These hints can be later on used for creation of
0930  * a new objagg instance. There, the future object creations are going
0931  * to be consulted with these hints in order to find out, where exactly
0932  * the new object should be put as a root or delta.
0933  *
0934  * Returns a pointer to hints instance in case of success,
0935  * otherwise it returns pointer error using ERR_PTR macro.
0936  */
0937 struct objagg_hints *objagg_hints_get(struct objagg *objagg,
0938                       enum objagg_opt_algo_type opt_algo_type)
0939 {
0940     const struct objagg_opt_algo *algo = objagg_opt_algos[opt_algo_type];
0941     struct objagg_hints *objagg_hints;
0942     int err;
0943 
0944     objagg_hints = kzalloc(sizeof(*objagg_hints), GFP_KERNEL);
0945     if (!objagg_hints)
0946         return ERR_PTR(-ENOMEM);
0947 
0948     objagg_hints->ops = objagg->ops;
0949     objagg_hints->refcount = 1;
0950 
0951     INIT_LIST_HEAD(&objagg_hints->node_list);
0952 
0953     objagg_hints->ht_params.key_len = objagg->ops->obj_size;
0954     objagg_hints->ht_params.key_offset =
0955                 offsetof(struct objagg_hints_node, obj);
0956     objagg_hints->ht_params.head_offset =
0957                 offsetof(struct objagg_hints_node, ht_node);
0958     objagg_hints->ht_params.obj_cmpfn = objagg_hints_obj_cmp;
0959 
0960     err = rhashtable_init(&objagg_hints->node_ht, &objagg_hints->ht_params);
0961     if (err)
0962         goto err_rhashtable_init;
0963 
0964     err = algo->fillup_hints(objagg_hints, objagg);
0965     if (err)
0966         goto err_fillup_hints;
0967 
0968     if (WARN_ON(objagg_hints->node_count != objagg->obj_count)) {
0969         err = -EINVAL;
0970         goto err_node_count_check;
0971     }
0972 
0973     return objagg_hints;
0974 
0975 err_node_count_check:
0976 err_fillup_hints:
0977     objagg_hints_flush(objagg_hints);
0978     rhashtable_destroy(&objagg_hints->node_ht);
0979 err_rhashtable_init:
0980     kfree(objagg_hints);
0981     return ERR_PTR(err);
0982 }
0983 EXPORT_SYMBOL(objagg_hints_get);
0984 
0985 /**
0986  * objagg_hints_put - puts hints instance
0987  * @objagg_hints:   objagg hints instance
0988  *
0989  * Note: all locking must be provided by the caller.
0990  */
0991 void objagg_hints_put(struct objagg_hints *objagg_hints)
0992 {
0993     if (--objagg_hints->refcount)
0994         return;
0995     objagg_hints_flush(objagg_hints);
0996     rhashtable_destroy(&objagg_hints->node_ht);
0997     kfree(objagg_hints);
0998 }
0999 EXPORT_SYMBOL(objagg_hints_put);
1000 
1001 /**
1002  * objagg_hints_stats_get - obtains stats of the hints instance
1003  * @objagg_hints:   hints instance
1004  *
1005  * Note: all locking must be provided by the caller.
1006  *
1007  * The returned structure contains statistics of all objects
1008  * currently in use, ordered by following rules:
1009  * 1) Root objects are always on lower indexes than the rest.
1010  * 2) Objects with higher delta user count are always on lower
1011  *    indexes.
1012  * 3) In case multiple objects have the same delta user count,
1013  *    the objects are ordered by user count.
1014  *
1015  * Returns a pointer to stats instance in case of success,
1016  * otherwise it returns pointer error using ERR_PTR macro.
1017  */
1018 const struct objagg_stats *
1019 objagg_hints_stats_get(struct objagg_hints *objagg_hints)
1020 {
1021     struct objagg_stats *objagg_stats;
1022     struct objagg_hints_node *hnode;
1023     int i;
1024 
1025     objagg_stats = kzalloc(struct_size(objagg_stats, stats_info,
1026                        objagg_hints->node_count),
1027                    GFP_KERNEL);
1028     if (!objagg_stats)
1029         return ERR_PTR(-ENOMEM);
1030 
1031     i = 0;
1032     list_for_each_entry(hnode, &objagg_hints->node_list, list) {
1033         memcpy(&objagg_stats->stats_info[i], &hnode->stats_info,
1034                sizeof(objagg_stats->stats_info[0]));
1035         if (objagg_stats->stats_info[i].is_root)
1036             objagg_stats->root_count++;
1037         i++;
1038     }
1039     objagg_stats->stats_info_count = i;
1040 
1041     sort(objagg_stats->stats_info, objagg_stats->stats_info_count,
1042          sizeof(struct objagg_obj_stats_info),
1043          objagg_stats_info_sort_cmp_func, NULL);
1044 
1045     return objagg_stats;
1046 }
1047 EXPORT_SYMBOL(objagg_hints_stats_get);
1048 
1049 MODULE_LICENSE("Dual BSD/GPL");
1050 MODULE_AUTHOR("Jiri Pirko <jiri@mellanox.com>");
1051 MODULE_DESCRIPTION("Object aggregation manager");