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 delta_priv
= objagg
->ops
->delta_create(objagg
->priv
, parent
->obj
,
172 if (IS_ERR(delta_priv
))
173 return PTR_ERR(delta_priv
);
175 /* User returned a delta private, that means that
176 * our object can be aggregated into the parent.
178 objagg_obj
->parent
= parent
;
179 objagg_obj
->delta_priv
= delta_priv
;
181 objagg_obj_ref_inc(objagg_obj
->parent
);
182 trace_objagg_obj_parent_assign(objagg
, objagg_obj
,
188 static int objagg_obj_parent_lookup_assign(struct objagg
*objagg
,
189 struct objagg_obj
*objagg_obj
)
191 struct objagg_obj
*objagg_obj_cur
;
194 list_for_each_entry(objagg_obj_cur
, &objagg
->obj_list
, list
) {
195 /* Nesting is not supported. In case the object
196 * is not root, it cannot be assigned as parent.
198 if (!objagg_obj_is_root(objagg_obj_cur
))
200 err
= objagg_obj_parent_assign(objagg
, objagg_obj
,
201 objagg_obj_cur
, true);
208 static void __objagg_obj_put(struct objagg
*objagg
,
209 struct objagg_obj
*objagg_obj
);
211 static void objagg_obj_parent_unassign(struct objagg
*objagg
,
212 struct objagg_obj
*objagg_obj
)
214 trace_objagg_obj_parent_unassign(objagg
, objagg_obj
,
216 objagg_obj
->parent
->refcount
);
217 objagg
->ops
->delta_destroy(objagg
->priv
, objagg_obj
->delta_priv
);
218 __objagg_obj_put(objagg
, objagg_obj
->parent
);
221 static int objagg_obj_root_id_alloc(struct objagg
*objagg
,
222 struct objagg_obj
*objagg_obj
,
223 struct objagg_hints_node
*hnode
)
225 unsigned int min
, max
;
228 /* In case there are no hints available, the root id is invalid. */
229 if (!objagg
->hints
) {
230 objagg_obj
->root_id
= OBJAGG_OBJ_ROOT_ID_INVALID
;
235 min
= hnode
->root_id
;
236 max
= hnode
->root_id
;
238 /* For objects with no hint, start after the last
241 min
= objagg
->hints
->root_count
;
245 root_id
= ida_alloc_range(&objagg
->root_ida
, min
, max
, GFP_KERNEL
);
249 objagg_obj
->root_id
= root_id
;
253 static void objagg_obj_root_id_free(struct objagg
*objagg
,
254 struct objagg_obj
*objagg_obj
)
258 ida_free(&objagg
->root_ida
, objagg_obj
->root_id
);
261 static int objagg_obj_root_create(struct objagg
*objagg
,
262 struct objagg_obj
*objagg_obj
,
263 struct objagg_hints_node
*hnode
)
267 err
= objagg_obj_root_id_alloc(objagg
, objagg_obj
, hnode
);
270 objagg_obj
->root_priv
= objagg
->ops
->root_create(objagg
->priv
,
272 objagg_obj
->root_id
);
273 if (IS_ERR(objagg_obj
->root_priv
)) {
274 err
= PTR_ERR(objagg_obj
->root_priv
);
275 goto err_root_create
;
277 trace_objagg_obj_root_create(objagg
, objagg_obj
);
281 objagg_obj_root_id_free(objagg
, objagg_obj
);
285 static void objagg_obj_root_destroy(struct objagg
*objagg
,
286 struct objagg_obj
*objagg_obj
)
288 trace_objagg_obj_root_destroy(objagg
, objagg_obj
);
289 objagg
->ops
->root_destroy(objagg
->priv
, objagg_obj
->root_priv
);
290 objagg_obj_root_id_free(objagg
, objagg_obj
);
293 static struct objagg_obj
*__objagg_obj_get(struct objagg
*objagg
, void *obj
);
295 static int objagg_obj_init_with_hints(struct objagg
*objagg
,
296 struct objagg_obj
*objagg_obj
,
299 struct objagg_hints_node
*hnode
;
300 struct objagg_obj
*parent
;
303 hnode
= objagg_hints_lookup(objagg
->hints
, objagg_obj
->obj
);
311 return objagg_obj_root_create(objagg
, objagg_obj
, hnode
);
313 parent
= __objagg_obj_get(objagg
, hnode
->parent
->obj
);
315 return PTR_ERR(parent
);
317 err
= objagg_obj_parent_assign(objagg
, objagg_obj
, parent
, false);
321 goto err_parent_assign
;
327 objagg_obj_put(objagg
, parent
);
331 static int objagg_obj_init(struct objagg
*objagg
,
332 struct objagg_obj
*objagg_obj
)
337 /* First, try to use hints if they are available and
338 * if they provide result.
340 err
= objagg_obj_init_with_hints(objagg
, objagg_obj
, &hint_found
);
347 /* Try to find if the object can be aggregated under an existing one. */
348 err
= objagg_obj_parent_lookup_assign(objagg
, objagg_obj
);
351 /* If aggregation is not possible, make the object a root. */
352 return objagg_obj_root_create(objagg
, objagg_obj
, NULL
);
355 static void objagg_obj_fini(struct objagg
*objagg
,
356 struct objagg_obj
*objagg_obj
)
358 if (!objagg_obj_is_root(objagg_obj
))
359 objagg_obj_parent_unassign(objagg
, objagg_obj
);
361 objagg_obj_root_destroy(objagg
, objagg_obj
);
364 static struct objagg_obj
*objagg_obj_create(struct objagg
*objagg
, void *obj
)
366 struct objagg_obj
*objagg_obj
;
369 objagg_obj
= kzalloc(sizeof(*objagg_obj
) + objagg
->ops
->obj_size
,
372 return ERR_PTR(-ENOMEM
);
373 objagg_obj_ref_inc(objagg_obj
);
374 memcpy(objagg_obj
->obj
, obj
, objagg
->ops
->obj_size
);
376 err
= objagg_obj_init(objagg
, objagg_obj
);
380 err
= rhashtable_insert_fast(&objagg
->obj_ht
, &objagg_obj
->ht_node
,
384 list_add(&objagg_obj
->list
, &objagg
->obj_list
);
386 trace_objagg_obj_create(objagg
, objagg_obj
);
391 objagg_obj_fini(objagg
, objagg_obj
);
397 static struct objagg_obj
*__objagg_obj_get(struct objagg
*objagg
, void *obj
)
399 struct objagg_obj
*objagg_obj
;
401 /* First, try to find the object exactly as user passed it,
402 * perhaps it is already in use.
404 objagg_obj
= objagg_obj_lookup(objagg
, obj
);
406 objagg_obj_ref_inc(objagg_obj
);
410 return objagg_obj_create(objagg
, obj
);
414 * objagg_obj_get - gets an object within objagg instance
415 * @objagg: objagg instance
416 * @obj: user-specific private object pointer
418 * Note: all locking must be provided by the caller.
420 * Size of the "obj" memory is specified in "objagg->ops".
422 * There are 3 main options this function wraps:
423 * 1) The object according to "obj" already exist. In that case
424 * the reference counter is incrementes and the object is returned.
425 * 2) The object does not exist, but it can be aggregated within
426 * another object. In that case, user ops->delta_create() is called
427 * to obtain delta data and a new object is created with returned
428 * user-delta private pointer.
429 * 3) The object does not exist and cannot be aggregated into
430 * any of the existing objects. In that case, user ops->root_create()
431 * is called to create the root and a new object is created with
432 * returned user-root private pointer.
434 * Returns a pointer to objagg object instance in case of success,
435 * otherwise it returns pointer error using ERR_PTR macro.
437 struct objagg_obj
*objagg_obj_get(struct objagg
*objagg
, void *obj
)
439 struct objagg_obj
*objagg_obj
;
441 objagg_obj
= __objagg_obj_get(objagg
, obj
);
442 if (IS_ERR(objagg_obj
))
444 objagg_obj_stats_inc(objagg_obj
);
445 trace_objagg_obj_get(objagg
, objagg_obj
, objagg_obj
->refcount
);
448 EXPORT_SYMBOL(objagg_obj_get
);
450 static void objagg_obj_destroy(struct objagg
*objagg
,
451 struct objagg_obj
*objagg_obj
)
453 trace_objagg_obj_destroy(objagg
, objagg_obj
);
455 list_del(&objagg_obj
->list
);
456 rhashtable_remove_fast(&objagg
->obj_ht
, &objagg_obj
->ht_node
,
458 objagg_obj_fini(objagg
, objagg_obj
);
462 static void __objagg_obj_put(struct objagg
*objagg
,
463 struct objagg_obj
*objagg_obj
)
465 if (!objagg_obj_ref_dec(objagg_obj
))
466 objagg_obj_destroy(objagg
, objagg_obj
);
470 * objagg_obj_put - puts an object within objagg instance
471 * @objagg: objagg instance
472 * @objagg_obj: objagg object instance
474 * Note: all locking must be provided by the caller.
476 * Symmetric to objagg_obj_get().
478 void objagg_obj_put(struct objagg
*objagg
, struct objagg_obj
*objagg_obj
)
480 trace_objagg_obj_put(objagg
, objagg_obj
, objagg_obj
->refcount
);
481 objagg_obj_stats_dec(objagg_obj
);
482 __objagg_obj_put(objagg
, objagg_obj
);
484 EXPORT_SYMBOL(objagg_obj_put
);
487 * objagg_create - creates a new objagg instance
488 * @ops: user-specific callbacks
489 * @objagg_hints: hints, can be NULL
490 * @priv: pointer to a private data passed to the ops
492 * Note: all locking must be provided by the caller.
494 * The purpose of the library is to provide an infrastructure to
495 * aggregate user-specified objects. Library does not care about the type
496 * of the object. User fills-up ops which take care of the specific
497 * user object manipulation.
499 * As a very stupid example, consider integer numbers. For example
500 * number 8 as a root object. That can aggregate number 9 with delta 1,
501 * number 10 with delta 2, etc. This example is implemented as
502 * a part of a testing module in test_objagg.c file.
504 * Each objagg instance contains multiple trees. Each tree node is
505 * represented by "an object". In the current implementation there can be
506 * only roots and leafs nodes. Leaf nodes are called deltas.
507 * But in general, this can be easily extended for intermediate nodes.
508 * In that extension, a delta would be associated with all non-root
511 * Returns a pointer to newly created objagg instance in case of success,
512 * otherwise it returns pointer error using ERR_PTR macro.
514 struct objagg
*objagg_create(const struct objagg_ops
*ops
,
515 struct objagg_hints
*objagg_hints
, void *priv
)
517 struct objagg
*objagg
;
520 if (WARN_ON(!ops
|| !ops
->root_create
|| !ops
->root_destroy
||
521 !ops
->delta_check
|| !ops
->delta_create
||
522 !ops
->delta_destroy
))
523 return ERR_PTR(-EINVAL
);
525 objagg
= kzalloc(sizeof(*objagg
), GFP_KERNEL
);
527 return ERR_PTR(-ENOMEM
);
530 objagg
->hints
= objagg_hints
;
531 objagg_hints
->refcount
++;
534 INIT_LIST_HEAD(&objagg
->obj_list
);
536 objagg
->ht_params
.key_len
= ops
->obj_size
;
537 objagg
->ht_params
.key_offset
= offsetof(struct objagg_obj
, obj
);
538 objagg
->ht_params
.head_offset
= offsetof(struct objagg_obj
, ht_node
);
540 err
= rhashtable_init(&objagg
->obj_ht
, &objagg
->ht_params
);
542 goto err_rhashtable_init
;
544 ida_init(&objagg
->root_ida
);
546 trace_objagg_create(objagg
);
553 EXPORT_SYMBOL(objagg_create
);
556 * objagg_destroy - destroys a new objagg instance
557 * @objagg: objagg instance
559 * Note: all locking must be provided by the caller.
561 void objagg_destroy(struct objagg
*objagg
)
563 trace_objagg_destroy(objagg
);
564 ida_destroy(&objagg
->root_ida
);
565 WARN_ON(!list_empty(&objagg
->obj_list
));
566 rhashtable_destroy(&objagg
->obj_ht
);
568 objagg_hints_put(objagg
->hints
);
571 EXPORT_SYMBOL(objagg_destroy
);
573 static int objagg_stats_info_sort_cmp_func(const void *a
, const void *b
)
575 const struct objagg_obj_stats_info
*stats_info1
= a
;
576 const struct objagg_obj_stats_info
*stats_info2
= b
;
578 if (stats_info1
->is_root
!= stats_info2
->is_root
)
579 return stats_info2
->is_root
- stats_info1
->is_root
;
580 if (stats_info1
->stats
.delta_user_count
!=
581 stats_info2
->stats
.delta_user_count
)
582 return stats_info2
->stats
.delta_user_count
-
583 stats_info1
->stats
.delta_user_count
;
584 return stats_info2
->stats
.user_count
- stats_info1
->stats
.user_count
;
588 * objagg_stats_get - obtains stats of the objagg instance
589 * @objagg: objagg instance
591 * Note: all locking must be provided by the caller.
593 * The returned structure contains statistics of all object
594 * currently in use, ordered by following rules:
595 * 1) Root objects are always on lower indexes than the rest.
596 * 2) Objects with higher delta user count are always on lower
598 * 3) In case more objects have the same delta user count,
599 * the objects are ordered by user count.
601 * Returns a pointer to stats instance in case of success,
602 * otherwise it returns pointer error using ERR_PTR macro.
604 const struct objagg_stats
*objagg_stats_get(struct objagg
*objagg
)
606 struct objagg_stats
*objagg_stats
;
607 struct objagg_obj
*objagg_obj
;
610 objagg_stats
= kzalloc(struct_size(objagg_stats
, stats_info
,
611 objagg
->obj_count
), GFP_KERNEL
);
613 return ERR_PTR(-ENOMEM
);
616 list_for_each_entry(objagg_obj
, &objagg
->obj_list
, list
) {
617 memcpy(&objagg_stats
->stats_info
[i
].stats
, &objagg_obj
->stats
,
618 sizeof(objagg_stats
->stats_info
[0].stats
));
619 objagg_stats
->stats_info
[i
].objagg_obj
= objagg_obj
;
620 objagg_stats
->stats_info
[i
].is_root
=
621 objagg_obj_is_root(objagg_obj
);
622 if (objagg_stats
->stats_info
[i
].is_root
)
623 objagg_stats
->root_count
++;
626 objagg_stats
->stats_info_count
= i
;
628 sort(objagg_stats
->stats_info
, objagg_stats
->stats_info_count
,
629 sizeof(struct objagg_obj_stats_info
),
630 objagg_stats_info_sort_cmp_func
, NULL
);
634 EXPORT_SYMBOL(objagg_stats_get
);
637 * objagg_stats_put - puts stats of the objagg instance
638 * @objagg_stats: objagg instance stats
640 * Note: all locking must be provided by the caller.
642 void objagg_stats_put(const struct objagg_stats
*objagg_stats
)
646 EXPORT_SYMBOL(objagg_stats_put
);
648 static struct objagg_hints_node
*
649 objagg_hints_node_create(struct objagg_hints
*objagg_hints
,
650 struct objagg_obj
*objagg_obj
, size_t obj_size
,
651 struct objagg_hints_node
*parent_hnode
)
653 unsigned int user_count
= objagg_obj
->stats
.user_count
;
654 struct objagg_hints_node
*hnode
;
657 hnode
= kzalloc(sizeof(*hnode
) + obj_size
, GFP_KERNEL
);
659 return ERR_PTR(-ENOMEM
);
660 memcpy(hnode
->obj
, &objagg_obj
->obj
, obj_size
);
661 hnode
->stats_info
.stats
.user_count
= user_count
;
662 hnode
->stats_info
.stats
.delta_user_count
= user_count
;
664 parent_hnode
->stats_info
.stats
.delta_user_count
+= user_count
;
666 hnode
->root_id
= objagg_hints
->root_count
++;
667 hnode
->stats_info
.is_root
= true;
669 hnode
->stats_info
.objagg_obj
= objagg_obj
;
671 err
= rhashtable_insert_fast(&objagg_hints
->node_ht
, &hnode
->ht_node
,
672 objagg_hints
->ht_params
);
676 list_add(&hnode
->list
, &objagg_hints
->node_list
);
677 hnode
->parent
= parent_hnode
;
678 objagg_hints
->node_count
++;
687 static void objagg_hints_flush(struct objagg_hints
*objagg_hints
)
689 struct objagg_hints_node
*hnode
, *tmp
;
691 list_for_each_entry_safe(hnode
, tmp
, &objagg_hints
->node_list
, list
) {
692 list_del(&hnode
->list
);
693 rhashtable_remove_fast(&objagg_hints
->node_ht
, &hnode
->ht_node
,
694 objagg_hints
->ht_params
);
699 struct objagg_tmp_node
{
700 struct objagg_obj
*objagg_obj
;
704 struct objagg_tmp_graph
{
705 struct objagg_tmp_node
*nodes
;
706 unsigned long nodes_count
;
707 unsigned long *edges
;
710 static int objagg_tmp_graph_edge_index(struct objagg_tmp_graph
*graph
,
711 int parent_index
, int index
)
713 return index
* graph
->nodes_count
+ parent_index
;
716 static void objagg_tmp_graph_edge_set(struct objagg_tmp_graph
*graph
,
717 int parent_index
, int index
)
719 int edge_index
= objagg_tmp_graph_edge_index(graph
, index
,
722 __set_bit(edge_index
, graph
->edges
);
725 static bool objagg_tmp_graph_is_edge(struct objagg_tmp_graph
*graph
,
726 int parent_index
, int index
)
728 int edge_index
= objagg_tmp_graph_edge_index(graph
, index
,
731 return test_bit(edge_index
, graph
->edges
);
734 static unsigned int objagg_tmp_graph_node_weight(struct objagg_tmp_graph
*graph
,
737 struct objagg_tmp_node
*node
= &graph
->nodes
[index
];
738 unsigned int weight
= node
->objagg_obj
->stats
.user_count
;
741 /* Node weight is sum of node users and all other nodes users
742 * that this node can represent with delta.
745 for (j
= 0; j
< graph
->nodes_count
; j
++) {
746 if (!objagg_tmp_graph_is_edge(graph
, index
, j
))
748 node
= &graph
->nodes
[j
];
749 if (node
->crossed_out
)
751 weight
+= node
->objagg_obj
->stats
.user_count
;
756 static int objagg_tmp_graph_node_max_weight(struct objagg_tmp_graph
*graph
)
758 struct objagg_tmp_node
*node
;
759 unsigned int max_weight
= 0;
764 for (i
= 0; i
< graph
->nodes_count
; i
++) {
765 node
= &graph
->nodes
[i
];
766 if (node
->crossed_out
)
768 weight
= objagg_tmp_graph_node_weight(graph
, i
);
769 if (weight
>= max_weight
) {
777 static struct objagg_tmp_graph
*objagg_tmp_graph_create(struct objagg
*objagg
)
779 unsigned int nodes_count
= objagg
->obj_count
;
780 struct objagg_tmp_graph
*graph
;
781 struct objagg_tmp_node
*node
;
782 struct objagg_tmp_node
*pnode
;
783 struct objagg_obj
*objagg_obj
;
787 graph
= kzalloc(sizeof(*graph
), GFP_KERNEL
);
791 graph
->nodes
= kcalloc(nodes_count
, sizeof(*graph
->nodes
), GFP_KERNEL
);
793 goto err_nodes_alloc
;
794 graph
->nodes_count
= nodes_count
;
796 alloc_size
= BITS_TO_LONGS(nodes_count
* nodes_count
) *
797 sizeof(unsigned long);
798 graph
->edges
= kzalloc(alloc_size
, 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
)
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
,
909 static int objagg_hints_obj_cmp(struct rhashtable_compare_arg
*arg
,
912 struct rhashtable
*ht
= arg
->ht
;
913 struct objagg_hints
*objagg_hints
=
914 container_of(ht
, struct objagg_hints
, node_ht
);
915 const struct objagg_ops
*ops
= objagg_hints
->ops
;
916 const char *ptr
= obj
;
918 ptr
+= ht
->p
.key_offset
;
919 return ops
->hints_obj_cmp
? ops
->hints_obj_cmp(ptr
, arg
->key
) :
920 memcmp(ptr
, arg
->key
, ht
->p
.key_len
);
924 * objagg_hints_get - obtains hints instance
925 * @objagg: objagg instance
926 * @opt_algo_type: type of hints finding algorithm
928 * Note: all locking must be provided by the caller.
930 * According to the algo type, the existing objects of objagg instance
931 * are going to be went-through to assemble an optimal tree. We call this
932 * tree hints. These hints can be later on used for creation of
933 * a new objagg instance. There, the future object creations are going
934 * to be consulted with these hints in order to find out, where exactly
935 * the new object should be put as a root or delta.
937 * Returns a pointer to hints instance in case of success,
938 * otherwise it returns pointer error using ERR_PTR macro.
940 struct objagg_hints
*objagg_hints_get(struct objagg
*objagg
,
941 enum objagg_opt_algo_type opt_algo_type
)
943 const struct objagg_opt_algo
*algo
= objagg_opt_algos
[opt_algo_type
];
944 struct objagg_hints
*objagg_hints
;
947 objagg_hints
= kzalloc(sizeof(*objagg_hints
), GFP_KERNEL
);
949 return ERR_PTR(-ENOMEM
);
951 objagg_hints
->ops
= objagg
->ops
;
952 objagg_hints
->refcount
= 1;
954 INIT_LIST_HEAD(&objagg_hints
->node_list
);
956 objagg_hints
->ht_params
.key_len
= objagg
->ops
->obj_size
;
957 objagg_hints
->ht_params
.key_offset
=
958 offsetof(struct objagg_hints_node
, obj
);
959 objagg_hints
->ht_params
.head_offset
=
960 offsetof(struct objagg_hints_node
, ht_node
);
961 objagg_hints
->ht_params
.obj_cmpfn
= objagg_hints_obj_cmp
;
963 err
= rhashtable_init(&objagg_hints
->node_ht
, &objagg_hints
->ht_params
);
965 goto err_rhashtable_init
;
967 err
= algo
->fillup_hints(objagg_hints
, objagg
);
969 goto err_fillup_hints
;
971 if (WARN_ON(objagg_hints
->node_count
!= objagg
->obj_count
)) {
973 goto err_node_count_check
;
978 err_node_count_check
:
980 objagg_hints_flush(objagg_hints
);
981 rhashtable_destroy(&objagg_hints
->node_ht
);
986 EXPORT_SYMBOL(objagg_hints_get
);
989 * objagg_hints_put - puts hints instance
990 * @objagg_hints: objagg hints instance
992 * Note: all locking must be provided by the caller.
994 void objagg_hints_put(struct objagg_hints
*objagg_hints
)
996 if (--objagg_hints
->refcount
)
998 objagg_hints_flush(objagg_hints
);
999 rhashtable_destroy(&objagg_hints
->node_ht
);
1000 kfree(objagg_hints
);
1002 EXPORT_SYMBOL(objagg_hints_put
);
1005 * objagg_hints_stats_get - obtains stats of the hints instance
1006 * @objagg_hints: hints instance
1008 * Note: all locking must be provided by the caller.
1010 * The returned structure contains statistics of all objects
1011 * currently in use, ordered by following rules:
1012 * 1) Root objects are always on lower indexes than the rest.
1013 * 2) Objects with higher delta user count are always on lower
1015 * 3) In case multiple objects have the same delta user count,
1016 * the objects are ordered by user count.
1018 * Returns a pointer to stats instance in case of success,
1019 * otherwise it returns pointer error using ERR_PTR macro.
1021 const struct objagg_stats
*
1022 objagg_hints_stats_get(struct objagg_hints
*objagg_hints
)
1024 struct objagg_stats
*objagg_stats
;
1025 struct objagg_hints_node
*hnode
;
1028 objagg_stats
= kzalloc(struct_size(objagg_stats
, stats_info
,
1029 objagg_hints
->node_count
),
1032 return ERR_PTR(-ENOMEM
);
1035 list_for_each_entry(hnode
, &objagg_hints
->node_list
, list
) {
1036 memcpy(&objagg_stats
->stats_info
[i
], &hnode
->stats_info
,
1037 sizeof(objagg_stats
->stats_info
[0]));
1038 if (objagg_stats
->stats_info
[i
].is_root
)
1039 objagg_stats
->root_count
++;
1042 objagg_stats
->stats_info_count
= i
;
1044 sort(objagg_stats
->stats_info
, objagg_stats
->stats_info_count
,
1045 sizeof(struct objagg_obj_stats_info
),
1046 objagg_stats_info_sort_cmp_func
, NULL
);
1048 return objagg_stats
;
1050 EXPORT_SYMBOL(objagg_hints_stats_get
);
1052 MODULE_LICENSE("Dual BSD/GPL");
1053 MODULE_AUTHOR("Jiri Pirko <jiri@mellanox.com>");
1054 MODULE_DESCRIPTION("Object aggregation manager");