1 // SPDX-License-Identifier: BSD-3-Clause OR GPL-2.0
2 /* Copyright (c) 2018 Mellanox Technologies. All rights reserved */
4 #include <linux/module.h>
5 #include <linux/slab.h>
6 #include <linux/rhashtable.h>
8 #include <linux/list.h>
9 #include <linux/sort.h>
10 #include <linux/objagg.h>
12 #define CREATE_TRACE_POINTS
13 #include <trace/events/objagg.h>
16 struct rhashtable node_ht
;
17 struct rhashtable_params ht_params
;
18 struct list_head node_list
;
19 unsigned int node_count
;
20 unsigned int root_count
;
21 unsigned int refcount
;
22 const struct objagg_ops
*ops
;
25 struct objagg_hints_node
{
26 struct rhash_head ht_node
; /* member of objagg_hints->node_ht */
27 struct list_head list
; /* member of objagg_hints->node_list */
28 struct objagg_hints_node
*parent
;
30 struct objagg_obj_stats_info stats_info
;
34 static struct objagg_hints_node
*
35 objagg_hints_lookup(struct objagg_hints
*objagg_hints
, void *obj
)
39 return rhashtable_lookup_fast(&objagg_hints
->node_ht
, obj
,
40 objagg_hints
->ht_params
);
44 const struct objagg_ops
*ops
;
46 struct rhashtable obj_ht
;
47 struct rhashtable_params ht_params
;
48 struct list_head obj_list
;
49 unsigned int obj_count
;
51 struct objagg_hints
*hints
;
55 struct rhash_head ht_node
; /* member of objagg->obj_ht */
56 struct list_head list
; /* member of objagg->obj_list */
57 struct objagg_obj
*parent
; /* if the object is nested, this
58 * holds pointer to parent, otherwise NULL
61 void *delta_priv
; /* user delta private */
62 void *root_priv
; /* user root private */
65 unsigned int refcount
; /* counts number of users of this object
66 * including nested objects
68 struct objagg_obj_stats stats
;
72 static unsigned int objagg_obj_ref_inc(struct objagg_obj
*objagg_obj
)
74 return ++objagg_obj
->refcount
;
77 static unsigned int objagg_obj_ref_dec(struct objagg_obj
*objagg_obj
)
79 return --objagg_obj
->refcount
;
82 static void objagg_obj_stats_inc(struct objagg_obj
*objagg_obj
)
84 objagg_obj
->stats
.user_count
++;
85 objagg_obj
->stats
.delta_user_count
++;
86 if (objagg_obj
->parent
)
87 objagg_obj
->parent
->stats
.delta_user_count
++;
90 static void objagg_obj_stats_dec(struct objagg_obj
*objagg_obj
)
92 objagg_obj
->stats
.user_count
--;
93 objagg_obj
->stats
.delta_user_count
--;
94 if (objagg_obj
->parent
)
95 objagg_obj
->parent
->stats
.delta_user_count
--;
98 static bool objagg_obj_is_root(const struct objagg_obj
*objagg_obj
)
100 /* Nesting is not supported, so we can use ->parent
101 * to figure out if the object is root.
103 return !objagg_obj
->parent
;
107 * objagg_obj_root_priv - obtains root private for an object
108 * @objagg_obj: objagg object instance
110 * Note: all locking must be provided by the caller.
112 * Either the object is root itself when the private is returned
113 * directly, or the parent is root and its private is returned
116 * Returns a user private root pointer.
118 const void *objagg_obj_root_priv(const struct objagg_obj
*objagg_obj
)
120 if (objagg_obj_is_root(objagg_obj
))
121 return objagg_obj
->root_priv
;
122 WARN_ON(!objagg_obj_is_root(objagg_obj
->parent
));
123 return objagg_obj
->parent
->root_priv
;
125 EXPORT_SYMBOL(objagg_obj_root_priv
);
128 * objagg_obj_delta_priv - obtains delta private for an object
129 * @objagg_obj: objagg object instance
131 * Note: all locking must be provided by the caller.
133 * Returns user private delta pointer or NULL in case the passed
136 const void *objagg_obj_delta_priv(const struct objagg_obj
*objagg_obj
)
138 if (objagg_obj_is_root(objagg_obj
))
140 return objagg_obj
->delta_priv
;
142 EXPORT_SYMBOL(objagg_obj_delta_priv
);
145 * objagg_obj_raw - obtains object user private pointer
146 * @objagg_obj: objagg object instance
148 * Note: all locking must be provided by the caller.
150 * Returns user private pointer as was passed to objagg_obj_get() by "obj" arg.
152 const void *objagg_obj_raw(const struct objagg_obj
*objagg_obj
)
154 return objagg_obj
->obj
;
156 EXPORT_SYMBOL(objagg_obj_raw
);
158 static struct objagg_obj
*objagg_obj_lookup(struct objagg
*objagg
, void *obj
)
160 return rhashtable_lookup_fast(&objagg
->obj_ht
, obj
, objagg
->ht_params
);
163 static int objagg_obj_parent_assign(struct objagg
*objagg
,
164 struct objagg_obj
*objagg_obj
,
165 struct objagg_obj
*parent
,
166 bool take_parent_ref
)
170 if (WARN_ON(!objagg_obj_is_root(parent
)))
173 delta_priv
= objagg
->ops
->delta_create(objagg
->priv
, parent
->obj
,
175 if (IS_ERR(delta_priv
))
176 return PTR_ERR(delta_priv
);
178 /* User returned a delta private, that means that
179 * our object can be aggregated into the parent.
181 objagg_obj
->parent
= parent
;
182 objagg_obj
->delta_priv
= delta_priv
;
184 objagg_obj_ref_inc(objagg_obj
->parent
);
185 trace_objagg_obj_parent_assign(objagg
, objagg_obj
,
191 static int objagg_obj_parent_lookup_assign(struct objagg
*objagg
,
192 struct objagg_obj
*objagg_obj
)
194 struct objagg_obj
*objagg_obj_cur
;
197 list_for_each_entry(objagg_obj_cur
, &objagg
->obj_list
, list
) {
198 /* Nesting is not supported. In case the object
199 * is not root, it cannot be assigned as parent.
201 if (!objagg_obj_is_root(objagg_obj_cur
))
203 err
= objagg_obj_parent_assign(objagg
, objagg_obj
,
204 objagg_obj_cur
, true);
211 static void __objagg_obj_put(struct objagg
*objagg
,
212 struct objagg_obj
*objagg_obj
);
214 static void objagg_obj_parent_unassign(struct objagg
*objagg
,
215 struct objagg_obj
*objagg_obj
)
217 trace_objagg_obj_parent_unassign(objagg
, objagg_obj
,
219 objagg_obj
->parent
->refcount
);
220 objagg
->ops
->delta_destroy(objagg
->priv
, objagg_obj
->delta_priv
);
221 __objagg_obj_put(objagg
, objagg_obj
->parent
);
224 static int objagg_obj_root_id_alloc(struct objagg
*objagg
,
225 struct objagg_obj
*objagg_obj
,
226 struct objagg_hints_node
*hnode
)
228 unsigned int min
, max
;
231 /* In case there are no hints available, the root id is invalid. */
232 if (!objagg
->hints
) {
233 objagg_obj
->root_id
= OBJAGG_OBJ_ROOT_ID_INVALID
;
238 min
= hnode
->root_id
;
239 max
= hnode
->root_id
;
241 /* For objects with no hint, start after the last
244 min
= objagg
->hints
->root_count
;
248 root_id
= ida_alloc_range(&objagg
->root_ida
, min
, max
, GFP_KERNEL
);
252 objagg_obj
->root_id
= root_id
;
256 static void objagg_obj_root_id_free(struct objagg
*objagg
,
257 struct objagg_obj
*objagg_obj
)
261 ida_free(&objagg
->root_ida
, objagg_obj
->root_id
);
264 static int objagg_obj_root_create(struct objagg
*objagg
,
265 struct objagg_obj
*objagg_obj
,
266 struct objagg_hints_node
*hnode
)
270 err
= objagg_obj_root_id_alloc(objagg
, objagg_obj
, hnode
);
273 objagg_obj
->root_priv
= objagg
->ops
->root_create(objagg
->priv
,
275 objagg_obj
->root_id
);
276 if (IS_ERR(objagg_obj
->root_priv
)) {
277 err
= PTR_ERR(objagg_obj
->root_priv
);
278 goto err_root_create
;
280 trace_objagg_obj_root_create(objagg
, objagg_obj
);
284 objagg_obj_root_id_free(objagg
, objagg_obj
);
288 static void objagg_obj_root_destroy(struct objagg
*objagg
,
289 struct objagg_obj
*objagg_obj
)
291 trace_objagg_obj_root_destroy(objagg
, objagg_obj
);
292 objagg
->ops
->root_destroy(objagg
->priv
, objagg_obj
->root_priv
);
293 objagg_obj_root_id_free(objagg
, objagg_obj
);
296 static struct objagg_obj
*__objagg_obj_get(struct objagg
*objagg
, void *obj
);
298 static int objagg_obj_init_with_hints(struct objagg
*objagg
,
299 struct objagg_obj
*objagg_obj
,
302 struct objagg_hints_node
*hnode
;
303 struct objagg_obj
*parent
;
306 hnode
= objagg_hints_lookup(objagg
->hints
, objagg_obj
->obj
);
314 return objagg_obj_root_create(objagg
, objagg_obj
, hnode
);
316 parent
= __objagg_obj_get(objagg
, hnode
->parent
->obj
);
318 return PTR_ERR(parent
);
320 err
= objagg_obj_parent_assign(objagg
, objagg_obj
, parent
, false);
324 goto err_parent_assign
;
330 objagg_obj_put(objagg
, parent
);
334 static int objagg_obj_init(struct objagg
*objagg
,
335 struct objagg_obj
*objagg_obj
)
340 /* First, try to use hints if they are available and
341 * if they provide result.
343 err
= objagg_obj_init_with_hints(objagg
, objagg_obj
, &hint_found
);
350 /* Try to find if the object can be aggregated under an existing one. */
351 err
= objagg_obj_parent_lookup_assign(objagg
, objagg_obj
);
354 /* If aggregation is not possible, make the object a root. */
355 return objagg_obj_root_create(objagg
, objagg_obj
, NULL
);
358 static void objagg_obj_fini(struct objagg
*objagg
,
359 struct objagg_obj
*objagg_obj
)
361 if (!objagg_obj_is_root(objagg_obj
))
362 objagg_obj_parent_unassign(objagg
, objagg_obj
);
364 objagg_obj_root_destroy(objagg
, objagg_obj
);
367 static struct objagg_obj
*objagg_obj_create(struct objagg
*objagg
, void *obj
)
369 struct objagg_obj
*objagg_obj
;
372 objagg_obj
= kzalloc(sizeof(*objagg_obj
) + objagg
->ops
->obj_size
,
375 return ERR_PTR(-ENOMEM
);
376 objagg_obj_ref_inc(objagg_obj
);
377 memcpy(objagg_obj
->obj
, obj
, objagg
->ops
->obj_size
);
379 err
= objagg_obj_init(objagg
, objagg_obj
);
383 err
= rhashtable_insert_fast(&objagg
->obj_ht
, &objagg_obj
->ht_node
,
387 list_add(&objagg_obj
->list
, &objagg
->obj_list
);
389 trace_objagg_obj_create(objagg
, objagg_obj
);
394 objagg_obj_fini(objagg
, objagg_obj
);
400 static struct objagg_obj
*__objagg_obj_get(struct objagg
*objagg
, void *obj
)
402 struct objagg_obj
*objagg_obj
;
404 /* First, try to find the object exactly as user passed it,
405 * perhaps it is already in use.
407 objagg_obj
= objagg_obj_lookup(objagg
, obj
);
409 objagg_obj_ref_inc(objagg_obj
);
413 return objagg_obj_create(objagg
, obj
);
417 * objagg_obj_get - gets an object within objagg instance
418 * @objagg: objagg instance
419 * @obj: user-specific private object pointer
421 * Note: all locking must be provided by the caller.
423 * Size of the "obj" memory is specified in "objagg->ops".
425 * There are 3 main options this function wraps:
426 * 1) The object according to "obj" already exist. In that case
427 * the reference counter is incremented and the object is returned.
428 * 2) The object does not exist, but it can be aggregated within
429 * another object. In that case, user ops->delta_create() is called
430 * to obtain delta data and a new object is created with returned
431 * user-delta private pointer.
432 * 3) The object does not exist and cannot be aggregated into
433 * any of the existing objects. In that case, user ops->root_create()
434 * is called to create the root and a new object is created with
435 * returned user-root private pointer.
437 * Returns a pointer to objagg object instance in case of success,
438 * otherwise it returns pointer error using ERR_PTR macro.
440 struct objagg_obj
*objagg_obj_get(struct objagg
*objagg
, void *obj
)
442 struct objagg_obj
*objagg_obj
;
444 objagg_obj
= __objagg_obj_get(objagg
, obj
);
445 if (IS_ERR(objagg_obj
))
447 objagg_obj_stats_inc(objagg_obj
);
448 trace_objagg_obj_get(objagg
, objagg_obj
, objagg_obj
->refcount
);
451 EXPORT_SYMBOL(objagg_obj_get
);
453 static void objagg_obj_destroy(struct objagg
*objagg
,
454 struct objagg_obj
*objagg_obj
)
456 trace_objagg_obj_destroy(objagg
, objagg_obj
);
458 list_del(&objagg_obj
->list
);
459 rhashtable_remove_fast(&objagg
->obj_ht
, &objagg_obj
->ht_node
,
461 objagg_obj_fini(objagg
, objagg_obj
);
465 static void __objagg_obj_put(struct objagg
*objagg
,
466 struct objagg_obj
*objagg_obj
)
468 if (!objagg_obj_ref_dec(objagg_obj
))
469 objagg_obj_destroy(objagg
, objagg_obj
);
473 * objagg_obj_put - puts an object within objagg instance
474 * @objagg: objagg instance
475 * @objagg_obj: objagg object instance
477 * Note: all locking must be provided by the caller.
479 * Symmetric to objagg_obj_get().
481 void objagg_obj_put(struct objagg
*objagg
, struct objagg_obj
*objagg_obj
)
483 trace_objagg_obj_put(objagg
, objagg_obj
, objagg_obj
->refcount
);
484 objagg_obj_stats_dec(objagg_obj
);
485 __objagg_obj_put(objagg
, objagg_obj
);
487 EXPORT_SYMBOL(objagg_obj_put
);
490 * objagg_create - creates a new objagg instance
491 * @ops: user-specific callbacks
492 * @objagg_hints: hints, can be NULL
493 * @priv: pointer to a private data passed to the ops
495 * Note: all locking must be provided by the caller.
497 * The purpose of the library is to provide an infrastructure to
498 * aggregate user-specified objects. Library does not care about the type
499 * of the object. User fills-up ops which take care of the specific
500 * user object manipulation.
502 * As a very stupid example, consider integer numbers. For example
503 * number 8 as a root object. That can aggregate number 9 with delta 1,
504 * number 10 with delta 2, etc. This example is implemented as
505 * a part of a testing module in test_objagg.c file.
507 * Each objagg instance contains multiple trees. Each tree node is
508 * represented by "an object". In the current implementation there can be
509 * only roots and leafs nodes. Leaf nodes are called deltas.
510 * But in general, this can be easily extended for intermediate nodes.
511 * In that extension, a delta would be associated with all non-root
514 * Returns a pointer to newly created objagg instance in case of success,
515 * otherwise it returns pointer error using ERR_PTR macro.
517 struct objagg
*objagg_create(const struct objagg_ops
*ops
,
518 struct objagg_hints
*objagg_hints
, void *priv
)
520 struct objagg
*objagg
;
523 if (WARN_ON(!ops
|| !ops
->root_create
|| !ops
->root_destroy
||
524 !ops
->delta_check
|| !ops
->delta_create
||
525 !ops
->delta_destroy
))
526 return ERR_PTR(-EINVAL
);
528 objagg
= kzalloc(sizeof(*objagg
), GFP_KERNEL
);
530 return ERR_PTR(-ENOMEM
);
533 objagg
->hints
= objagg_hints
;
534 objagg_hints
->refcount
++;
537 INIT_LIST_HEAD(&objagg
->obj_list
);
539 objagg
->ht_params
.key_len
= ops
->obj_size
;
540 objagg
->ht_params
.key_offset
= offsetof(struct objagg_obj
, obj
);
541 objagg
->ht_params
.head_offset
= offsetof(struct objagg_obj
, ht_node
);
543 err
= rhashtable_init(&objagg
->obj_ht
, &objagg
->ht_params
);
545 goto err_rhashtable_init
;
547 ida_init(&objagg
->root_ida
);
549 trace_objagg_create(objagg
);
556 EXPORT_SYMBOL(objagg_create
);
559 * objagg_destroy - destroys a new objagg instance
560 * @objagg: objagg instance
562 * Note: all locking must be provided by the caller.
564 void objagg_destroy(struct objagg
*objagg
)
566 trace_objagg_destroy(objagg
);
567 ida_destroy(&objagg
->root_ida
);
568 WARN_ON(!list_empty(&objagg
->obj_list
));
569 rhashtable_destroy(&objagg
->obj_ht
);
571 objagg_hints_put(objagg
->hints
);
574 EXPORT_SYMBOL(objagg_destroy
);
576 static int objagg_stats_info_sort_cmp_func(const void *a
, const void *b
)
578 const struct objagg_obj_stats_info
*stats_info1
= a
;
579 const struct objagg_obj_stats_info
*stats_info2
= b
;
581 if (stats_info1
->is_root
!= stats_info2
->is_root
)
582 return stats_info2
->is_root
- stats_info1
->is_root
;
583 if (stats_info1
->stats
.delta_user_count
!=
584 stats_info2
->stats
.delta_user_count
)
585 return stats_info2
->stats
.delta_user_count
-
586 stats_info1
->stats
.delta_user_count
;
587 return stats_info2
->stats
.user_count
- stats_info1
->stats
.user_count
;
591 * objagg_stats_get - obtains stats of the objagg instance
592 * @objagg: objagg instance
594 * Note: all locking must be provided by the caller.
596 * The returned structure contains statistics of all object
597 * currently in use, ordered by following rules:
598 * 1) Root objects are always on lower indexes than the rest.
599 * 2) Objects with higher delta user count are always on lower
601 * 3) In case more objects have the same delta user count,
602 * the objects are ordered by user count.
604 * Returns a pointer to stats instance in case of success,
605 * otherwise it returns pointer error using ERR_PTR macro.
607 const struct objagg_stats
*objagg_stats_get(struct objagg
*objagg
)
609 struct objagg_stats
*objagg_stats
;
610 struct objagg_obj
*objagg_obj
;
613 objagg_stats
= kzalloc(struct_size(objagg_stats
, stats_info
,
614 objagg
->obj_count
), GFP_KERNEL
);
616 return ERR_PTR(-ENOMEM
);
619 list_for_each_entry(objagg_obj
, &objagg
->obj_list
, list
) {
620 memcpy(&objagg_stats
->stats_info
[i
].stats
, &objagg_obj
->stats
,
621 sizeof(objagg_stats
->stats_info
[0].stats
));
622 objagg_stats
->stats_info
[i
].objagg_obj
= objagg_obj
;
623 objagg_stats
->stats_info
[i
].is_root
=
624 objagg_obj_is_root(objagg_obj
);
625 if (objagg_stats
->stats_info
[i
].is_root
)
626 objagg_stats
->root_count
++;
629 objagg_stats
->stats_info_count
= i
;
631 sort(objagg_stats
->stats_info
, objagg_stats
->stats_info_count
,
632 sizeof(struct objagg_obj_stats_info
),
633 objagg_stats_info_sort_cmp_func
, NULL
);
637 EXPORT_SYMBOL(objagg_stats_get
);
640 * objagg_stats_put - puts stats of the objagg instance
641 * @objagg_stats: objagg instance stats
643 * Note: all locking must be provided by the caller.
645 void objagg_stats_put(const struct objagg_stats
*objagg_stats
)
649 EXPORT_SYMBOL(objagg_stats_put
);
651 static struct objagg_hints_node
*
652 objagg_hints_node_create(struct objagg_hints
*objagg_hints
,
653 struct objagg_obj
*objagg_obj
, size_t obj_size
,
654 struct objagg_hints_node
*parent_hnode
)
656 unsigned int user_count
= objagg_obj
->stats
.user_count
;
657 struct objagg_hints_node
*hnode
;
660 hnode
= kzalloc(sizeof(*hnode
) + obj_size
, GFP_KERNEL
);
662 return ERR_PTR(-ENOMEM
);
663 memcpy(hnode
->obj
, &objagg_obj
->obj
, obj_size
);
664 hnode
->stats_info
.stats
.user_count
= user_count
;
665 hnode
->stats_info
.stats
.delta_user_count
= user_count
;
667 parent_hnode
->stats_info
.stats
.delta_user_count
+= user_count
;
669 hnode
->root_id
= objagg_hints
->root_count
++;
670 hnode
->stats_info
.is_root
= true;
672 hnode
->stats_info
.objagg_obj
= objagg_obj
;
674 err
= rhashtable_insert_fast(&objagg_hints
->node_ht
, &hnode
->ht_node
,
675 objagg_hints
->ht_params
);
679 list_add(&hnode
->list
, &objagg_hints
->node_list
);
680 hnode
->parent
= parent_hnode
;
681 objagg_hints
->node_count
++;
690 static void objagg_hints_flush(struct objagg_hints
*objagg_hints
)
692 struct objagg_hints_node
*hnode
, *tmp
;
694 list_for_each_entry_safe(hnode
, tmp
, &objagg_hints
->node_list
, list
) {
695 list_del(&hnode
->list
);
696 rhashtable_remove_fast(&objagg_hints
->node_ht
, &hnode
->ht_node
,
697 objagg_hints
->ht_params
);
702 struct objagg_tmp_node
{
703 struct objagg_obj
*objagg_obj
;
707 struct objagg_tmp_graph
{
708 struct objagg_tmp_node
*nodes
;
709 unsigned long nodes_count
;
710 unsigned long *edges
;
713 static int objagg_tmp_graph_edge_index(struct objagg_tmp_graph
*graph
,
714 int parent_index
, int index
)
716 return index
* graph
->nodes_count
+ parent_index
;
719 static void objagg_tmp_graph_edge_set(struct objagg_tmp_graph
*graph
,
720 int parent_index
, int index
)
722 int edge_index
= objagg_tmp_graph_edge_index(graph
, index
,
725 __set_bit(edge_index
, graph
->edges
);
728 static bool objagg_tmp_graph_is_edge(struct objagg_tmp_graph
*graph
,
729 int parent_index
, int index
)
731 int edge_index
= objagg_tmp_graph_edge_index(graph
, index
,
734 return test_bit(edge_index
, graph
->edges
);
737 static unsigned int objagg_tmp_graph_node_weight(struct objagg_tmp_graph
*graph
,
740 struct objagg_tmp_node
*node
= &graph
->nodes
[index
];
741 unsigned int weight
= node
->objagg_obj
->stats
.user_count
;
744 /* Node weight is sum of node users and all other nodes users
745 * that this node can represent with delta.
748 for (j
= 0; j
< graph
->nodes_count
; j
++) {
749 if (!objagg_tmp_graph_is_edge(graph
, index
, j
))
751 node
= &graph
->nodes
[j
];
752 if (node
->crossed_out
)
754 weight
+= node
->objagg_obj
->stats
.user_count
;
759 static int objagg_tmp_graph_node_max_weight(struct objagg_tmp_graph
*graph
)
761 struct objagg_tmp_node
*node
;
762 unsigned int max_weight
= 0;
767 for (i
= 0; i
< graph
->nodes_count
; i
++) {
768 node
= &graph
->nodes
[i
];
769 if (node
->crossed_out
)
771 weight
= objagg_tmp_graph_node_weight(graph
, i
);
772 if (weight
>= max_weight
) {
780 static struct objagg_tmp_graph
*objagg_tmp_graph_create(struct objagg
*objagg
)
782 unsigned int nodes_count
= objagg
->obj_count
;
783 struct objagg_tmp_graph
*graph
;
784 struct objagg_tmp_node
*node
;
785 struct objagg_tmp_node
*pnode
;
786 struct objagg_obj
*objagg_obj
;
789 graph
= kzalloc(sizeof(*graph
), GFP_KERNEL
);
793 graph
->nodes
= kcalloc(nodes_count
, sizeof(*graph
->nodes
), GFP_KERNEL
);
795 goto err_nodes_alloc
;
796 graph
->nodes_count
= nodes_count
;
798 graph
->edges
= bitmap_zalloc(nodes_count
* nodes_count
, GFP_KERNEL
);
800 goto err_edges_alloc
;
803 list_for_each_entry(objagg_obj
, &objagg
->obj_list
, list
) {
804 node
= &graph
->nodes
[i
++];
805 node
->objagg_obj
= objagg_obj
;
808 /* Assemble a temporary graph. Insert edge X->Y in case Y can be
811 for (i
= 0; i
< nodes_count
; i
++) {
812 for (j
= 0; j
< nodes_count
; j
++) {
815 pnode
= &graph
->nodes
[i
];
816 node
= &graph
->nodes
[j
];
817 if (objagg
->ops
->delta_check(objagg
->priv
,
818 pnode
->objagg_obj
->obj
,
819 node
->objagg_obj
->obj
)) {
820 objagg_tmp_graph_edge_set(graph
, i
, j
);
834 static void objagg_tmp_graph_destroy(struct objagg_tmp_graph
*graph
)
836 bitmap_free(graph
->edges
);
842 objagg_opt_simple_greedy_fillup_hints(struct objagg_hints
*objagg_hints
,
843 struct objagg
*objagg
)
845 struct objagg_hints_node
*hnode
, *parent_hnode
;
846 struct objagg_tmp_graph
*graph
;
847 struct objagg_tmp_node
*node
;
852 graph
= objagg_tmp_graph_create(objagg
);
856 /* Find the nodes from the ones that can accommodate most users
857 * and cross them out of the graph. Save them to the hint list.
859 while ((index
= objagg_tmp_graph_node_max_weight(graph
)) != -1) {
860 node
= &graph
->nodes
[index
];
861 node
->crossed_out
= true;
862 hnode
= objagg_hints_node_create(objagg_hints
,
864 objagg
->ops
->obj_size
,
867 err
= PTR_ERR(hnode
);
870 parent_hnode
= hnode
;
871 for (j
= 0; j
< graph
->nodes_count
; j
++) {
872 if (!objagg_tmp_graph_is_edge(graph
, index
, j
))
874 node
= &graph
->nodes
[j
];
875 if (node
->crossed_out
)
877 node
->crossed_out
= true;
878 hnode
= objagg_hints_node_create(objagg_hints
,
880 objagg
->ops
->obj_size
,
883 err
= PTR_ERR(hnode
);
891 objagg_tmp_graph_destroy(graph
);
895 struct objagg_opt_algo
{
896 int (*fillup_hints
)(struct objagg_hints
*objagg_hints
,
897 struct objagg
*objagg
);
900 static const struct objagg_opt_algo objagg_opt_simple_greedy
= {
901 .fillup_hints
= objagg_opt_simple_greedy_fillup_hints
,
905 static const struct objagg_opt_algo
*objagg_opt_algos
[] = {
906 [OBJAGG_OPT_ALGO_SIMPLE_GREEDY
] = &objagg_opt_simple_greedy
,
910 * objagg_hints_get - obtains hints instance
911 * @objagg: objagg instance
912 * @opt_algo_type: type of hints finding algorithm
914 * Note: all locking must be provided by the caller.
916 * According to the algo type, the existing objects of objagg instance
917 * are going to be went-through to assemble an optimal tree. We call this
918 * tree hints. These hints can be later on used for creation of
919 * a new objagg instance. There, the future object creations are going
920 * to be consulted with these hints in order to find out, where exactly
921 * the new object should be put as a root or delta.
923 * Returns a pointer to hints instance in case of success,
924 * otherwise it returns pointer error using ERR_PTR macro.
926 struct objagg_hints
*objagg_hints_get(struct objagg
*objagg
,
927 enum objagg_opt_algo_type opt_algo_type
)
929 const struct objagg_opt_algo
*algo
= objagg_opt_algos
[opt_algo_type
];
930 struct objagg_hints
*objagg_hints
;
933 objagg_hints
= kzalloc(sizeof(*objagg_hints
), GFP_KERNEL
);
935 return ERR_PTR(-ENOMEM
);
937 objagg_hints
->ops
= objagg
->ops
;
938 objagg_hints
->refcount
= 1;
940 INIT_LIST_HEAD(&objagg_hints
->node_list
);
942 objagg_hints
->ht_params
.key_len
= objagg
->ops
->obj_size
;
943 objagg_hints
->ht_params
.key_offset
=
944 offsetof(struct objagg_hints_node
, obj
);
945 objagg_hints
->ht_params
.head_offset
=
946 offsetof(struct objagg_hints_node
, ht_node
);
948 err
= rhashtable_init(&objagg_hints
->node_ht
, &objagg_hints
->ht_params
);
950 goto err_rhashtable_init
;
952 err
= algo
->fillup_hints(objagg_hints
, objagg
);
954 goto err_fillup_hints
;
956 if (WARN_ON(objagg_hints
->node_count
!= objagg
->obj_count
)) {
958 goto err_node_count_check
;
963 err_node_count_check
:
965 objagg_hints_flush(objagg_hints
);
966 rhashtable_destroy(&objagg_hints
->node_ht
);
971 EXPORT_SYMBOL(objagg_hints_get
);
974 * objagg_hints_put - puts hints instance
975 * @objagg_hints: objagg hints instance
977 * Note: all locking must be provided by the caller.
979 void objagg_hints_put(struct objagg_hints
*objagg_hints
)
981 if (--objagg_hints
->refcount
)
983 objagg_hints_flush(objagg_hints
);
984 rhashtable_destroy(&objagg_hints
->node_ht
);
987 EXPORT_SYMBOL(objagg_hints_put
);
990 * objagg_hints_stats_get - obtains stats of the hints instance
991 * @objagg_hints: hints instance
993 * Note: all locking must be provided by the caller.
995 * The returned structure contains statistics of all objects
996 * currently in use, ordered by following rules:
997 * 1) Root objects are always on lower indexes than the rest.
998 * 2) Objects with higher delta user count are always on lower
1000 * 3) In case multiple objects have the same delta user count,
1001 * the objects are ordered by user count.
1003 * Returns a pointer to stats instance in case of success,
1004 * otherwise it returns pointer error using ERR_PTR macro.
1006 const struct objagg_stats
*
1007 objagg_hints_stats_get(struct objagg_hints
*objagg_hints
)
1009 struct objagg_stats
*objagg_stats
;
1010 struct objagg_hints_node
*hnode
;
1013 objagg_stats
= kzalloc(struct_size(objagg_stats
, stats_info
,
1014 objagg_hints
->node_count
),
1017 return ERR_PTR(-ENOMEM
);
1020 list_for_each_entry(hnode
, &objagg_hints
->node_list
, list
) {
1021 memcpy(&objagg_stats
->stats_info
[i
], &hnode
->stats_info
,
1022 sizeof(objagg_stats
->stats_info
[0]));
1023 if (objagg_stats
->stats_info
[i
].is_root
)
1024 objagg_stats
->root_count
++;
1027 objagg_stats
->stats_info_count
= i
;
1029 sort(objagg_stats
->stats_info
, objagg_stats
->stats_info_count
,
1030 sizeof(struct objagg_obj_stats_info
),
1031 objagg_stats_info_sort_cmp_func
, NULL
);
1033 return objagg_stats
;
1035 EXPORT_SYMBOL(objagg_hints_stats_get
);
1037 MODULE_LICENSE("Dual BSD/GPL");
1038 MODULE_AUTHOR("Jiri Pirko <jiri@mellanox.com>");
1039 MODULE_DESCRIPTION("Object aggregation manager");