struct objagg_obj { struct rhash_head ht_node; /* member of objagg->obj_ht */ struct list_head list; /* member of objagg->obj_list */ struct objagg_obj *parent; /* if the object is nested, this * holds pointer to parent, otherwise NULL
*/ union { void *delta_priv; /* user delta private */ void *root_priv; /* user root private */
}; unsignedint root_id; unsignedint refcount; /* counts number of users of this object * including nested objects
*/ struct objagg_obj_stats stats; unsignedlong obj[];
};
staticbool objagg_obj_is_root(conststruct objagg_obj *objagg_obj)
{ /* Nesting is not supported, so we can use ->parent * to figure out if the object is root.
*/ return !objagg_obj->parent;
}
/** * objagg_obj_root_priv - obtains root private for an object * @objagg_obj: objagg object instance * * Note: all locking must be provided by the caller. * * Either the object is root itself when the private is returned * directly, or the parent is root and its private is returned * instead. * * Returns a user private root pointer.
*/ constvoid *objagg_obj_root_priv(conststruct objagg_obj *objagg_obj)
{ if (objagg_obj_is_root(objagg_obj)) return objagg_obj->root_priv;
WARN_ON(!objagg_obj_is_root(objagg_obj->parent)); return objagg_obj->parent->root_priv;
}
EXPORT_SYMBOL(objagg_obj_root_priv);
/** * objagg_obj_delta_priv - obtains delta private for an object * @objagg_obj: objagg object instance * * Note: all locking must be provided by the caller. * * Returns user private delta pointer or NULL in case the passed * object is root.
*/ constvoid *objagg_obj_delta_priv(conststruct objagg_obj *objagg_obj)
{ if (objagg_obj_is_root(objagg_obj)) return NULL; return objagg_obj->delta_priv;
}
EXPORT_SYMBOL(objagg_obj_delta_priv);
/** * objagg_obj_raw - obtains object user private pointer * @objagg_obj: objagg object instance * * Note: all locking must be provided by the caller. * * Returns user private pointer as was passed to objagg_obj_get() by "obj" arg.
*/ constvoid *objagg_obj_raw(conststruct objagg_obj *objagg_obj)
{ return objagg_obj->obj;
}
EXPORT_SYMBOL(objagg_obj_raw);
if (WARN_ON(!objagg_obj_is_root(parent))) return -EINVAL;
delta_priv = objagg->ops->delta_create(objagg->priv, parent->obj,
objagg_obj->obj); if (IS_ERR(delta_priv)) return PTR_ERR(delta_priv);
/* User returned a delta private, that means that * our object can be aggregated into the parent.
*/
objagg_obj->parent = parent;
objagg_obj->delta_priv = delta_priv; if (take_parent_ref)
objagg_obj_ref_inc(objagg_obj->parent);
trace_objagg_obj_parent_assign(objagg, objagg_obj,
parent,
parent->refcount); return 0;
}
list_for_each_entry(objagg_obj_cur, &objagg->obj_list, list) { /* Nesting is not supported. In case the object * is not root, it cannot be assigned as parent.
*/ if (!objagg_obj_is_root(objagg_obj_cur)) continue;
err = objagg_obj_parent_assign(objagg, objagg_obj,
objagg_obj_cur, true); if (!err) return 0;
} return -ENOENT;
}
/* In case there are no hints available, the root id is invalid. */ if (!objagg->hints) {
objagg_obj->root_id = OBJAGG_OBJ_ROOT_ID_INVALID; return 0;
}
if (hnode) {
min = hnode->root_id;
max = hnode->root_id;
} else { /* For objects with no hint, start after the last * hinted root_id.
*/
min = objagg->hints->root_count;
max = ~0;
}
/* First, try to use hints if they are available and * if they provide result.
*/
err = objagg_obj_init_with_hints(objagg, objagg_obj, &hint_found); if (err) return err;
if (hint_found) return 0;
/* Try to find if the object can be aggregated under an existing one. */
err = objagg_obj_parent_lookup_assign(objagg, objagg_obj); if (!err) return 0; /* If aggregation is not possible, make the object a root. */ return objagg_obj_root_create(objagg, objagg_obj, NULL);
}
/* First, try to find the object exactly as user passed it, * perhaps it is already in use.
*/
objagg_obj = objagg_obj_lookup(objagg, obj); if (objagg_obj) {
objagg_obj_ref_inc(objagg_obj); return objagg_obj;
}
return objagg_obj_create(objagg, obj);
}
/** * objagg_obj_get - gets an object within objagg instance * @objagg: objagg instance * @obj: user-specific private object pointer * * Note: all locking must be provided by the caller. * * Size of the "obj" memory is specified in "objagg->ops". * * There are 3 main options this function wraps: * 1) The object according to "obj" already exist. In that case * the reference counter is incremented and the object is returned. * 2) The object does not exist, but it can be aggregated within * another object. In that case, user ops->delta_create() is called * to obtain delta data and a new object is created with returned * user-delta private pointer. * 3) The object does not exist and cannot be aggregated into * any of the existing objects. In that case, user ops->root_create() * is called to create the root and a new object is created with * returned user-root private pointer. * * Returns a pointer to objagg object instance in case of success, * otherwise it returns pointer error using ERR_PTR macro.
*/ struct objagg_obj *objagg_obj_get(struct objagg *objagg, void *obj)
{ struct objagg_obj *objagg_obj;
/** * objagg_obj_put - puts an object within objagg instance * @objagg: objagg instance * @objagg_obj: objagg object instance * * Note: all locking must be provided by the caller. * * Symmetric to objagg_obj_get().
*/ void objagg_obj_put(struct objagg *objagg, struct objagg_obj *objagg_obj)
{
trace_objagg_obj_put(objagg, objagg_obj, objagg_obj->refcount);
objagg_obj_stats_dec(objagg_obj);
__objagg_obj_put(objagg, objagg_obj);
}
EXPORT_SYMBOL(objagg_obj_put);
/** * objagg_create - creates a new objagg instance * @ops: user-specific callbacks * @objagg_hints: hints, can be NULL * @priv: pointer to a private data passed to the ops * * Note: all locking must be provided by the caller. * * The purpose of the library is to provide an infrastructure to * aggregate user-specified objects. Library does not care about the type * of the object. User fills-up ops which take care of the specific * user object manipulation. * * As a very stupid example, consider integer numbers. For example * number 8 as a root object. That can aggregate number 9 with delta 1, * number 10 with delta 2, etc. This example is implemented as * a part of a testing module in test_objagg.c file. * * Each objagg instance contains multiple trees. Each tree node is * represented by "an object". In the current implementation there can be * only roots and leafs nodes. Leaf nodes are called deltas. * But in general, this can be easily extended for intermediate nodes. * In that extension, a delta would be associated with all non-root * nodes. * * Returns a pointer to newly created objagg instance in case of success, * otherwise it returns pointer error using ERR_PTR macro.
*/ struct objagg *objagg_create(conststruct objagg_ops *ops, struct objagg_hints *objagg_hints, void *priv)
{ struct objagg *objagg; int err;
/** * objagg_destroy - destroys a new objagg instance * @objagg: objagg instance * * Note: all locking must be provided by the caller.
*/ void objagg_destroy(struct objagg *objagg)
{
trace_objagg_destroy(objagg);
ida_destroy(&objagg->root_ida);
WARN_ON(!list_empty(&objagg->obj_list));
rhashtable_destroy(&objagg->obj_ht); if (objagg->hints)
objagg_hints_put(objagg->hints);
kfree(objagg);
}
EXPORT_SYMBOL(objagg_destroy);
/** * objagg_stats_get - obtains stats of the objagg instance * @objagg: objagg instance * * Note: all locking must be provided by the caller. * * The returned structure contains statistics of all object * currently in use, ordered by following rules: * 1) Root objects are always on lower indexes than the rest. * 2) Objects with higher delta user count are always on lower * indexes. * 3) In case more objects have the same delta user count, * the objects are ordered by user count. * * Returns a pointer to stats instance in case of success, * otherwise it returns pointer error using ERR_PTR macro.
*/ conststruct objagg_stats *objagg_stats_get(struct objagg *objagg)
{ struct objagg_stats *objagg_stats; struct objagg_obj *objagg_obj; int i;
objagg_stats = kzalloc(struct_size(objagg_stats, stats_info,
objagg->obj_count), GFP_KERNEL); if (!objagg_stats) return ERR_PTR(-ENOMEM);
/** * objagg_stats_put - puts stats of the objagg instance * @objagg_stats: objagg instance stats * * Note: all locking must be provided by the caller.
*/ void objagg_stats_put(conststruct objagg_stats *objagg_stats)
{
kfree(objagg_stats);
}
EXPORT_SYMBOL(objagg_stats_put);
staticint objagg_tmp_graph_edge_index(struct objagg_tmp_graph *graph, int parent_index, int index)
{ return index * graph->nodes_count + parent_index;
}
staticvoid objagg_tmp_graph_edge_set(struct objagg_tmp_graph *graph, int parent_index, int index)
{ int edge_index = objagg_tmp_graph_edge_index(graph, index,
parent_index);
__set_bit(edge_index, graph->edges);
}
staticbool objagg_tmp_graph_is_edge(struct objagg_tmp_graph *graph, int parent_index, int index)
{ int edge_index = objagg_tmp_graph_edge_index(graph, index,
parent_index);
/* Assemble a temporary graph. Insert edge X->Y in case Y can be * in delta of X.
*/ for (i = 0; i < nodes_count; i++) { for (j = 0; j < nodes_count; j++) { if (i == j) continue;
pnode = &graph->nodes[i];
node = &graph->nodes[j]; if (objagg->ops->delta_check(objagg->priv,
pnode->objagg_obj->obj,
node->objagg_obj->obj)) {
objagg_tmp_graph_edge_set(graph, i, j);
staticint
objagg_opt_simple_greedy_fillup_hints(struct objagg_hints *objagg_hints, struct objagg *objagg)
{ struct objagg_hints_node *hnode, *parent_hnode; struct objagg_tmp_graph *graph; struct objagg_tmp_node *node; int index; int j; int err;
graph = objagg_tmp_graph_create(objagg); if (!graph) return -ENOMEM;
/* Find the nodes from the ones that can accommodate most users * and cross them out of the graph. Save them to the hint list.
*/ while ((index = objagg_tmp_graph_node_max_weight(graph)) != -1) {
node = &graph->nodes[index];
node->crossed_out = true;
hnode = objagg_hints_node_create(objagg_hints,
node->objagg_obj,
objagg->ops->obj_size,
NULL); if (IS_ERR(hnode)) {
err = PTR_ERR(hnode); goto out;
}
parent_hnode = hnode; for (j = 0; j < graph->nodes_count; j++) { if (!objagg_tmp_graph_is_edge(graph, index, j)) continue;
node = &graph->nodes[j]; if (node->crossed_out) continue;
node->crossed_out = true;
hnode = objagg_hints_node_create(objagg_hints,
node->objagg_obj,
objagg->ops->obj_size,
parent_hnode); if (IS_ERR(hnode)) {
err = PTR_ERR(hnode); goto out;
}
}
}
/** * objagg_hints_get - obtains hints instance * @objagg: objagg instance * @opt_algo_type: type of hints finding algorithm * * Note: all locking must be provided by the caller. * * According to the algo type, the existing objects of objagg instance * are going to be went-through to assemble an optimal tree. We call this * tree hints. These hints can be later on used for creation of * a new objagg instance. There, the future object creations are going * to be consulted with these hints in order to find out, where exactly * the new object should be put as a root or delta. * * Returns a pointer to hints instance in case of success, * otherwise it returns pointer error using ERR_PTR macro.
*/ struct objagg_hints *objagg_hints_get(struct objagg *objagg, enum objagg_opt_algo_type opt_algo_type)
{ conststruct objagg_opt_algo *algo = objagg_opt_algos[opt_algo_type]; struct objagg_hints *objagg_hints; int err;
objagg_hints = kzalloc(sizeof(*objagg_hints), GFP_KERNEL); if (!objagg_hints) return ERR_PTR(-ENOMEM);
/** * objagg_hints_put - puts hints instance * @objagg_hints: objagg hints instance * * Note: all locking must be provided by the caller.
*/ void objagg_hints_put(struct objagg_hints *objagg_hints)
{ if (--objagg_hints->refcount) return;
objagg_hints_flush(objagg_hints);
rhashtable_destroy(&objagg_hints->node_ht);
kfree(objagg_hints);
}
EXPORT_SYMBOL(objagg_hints_put);
/** * objagg_hints_stats_get - obtains stats of the hints instance * @objagg_hints: hints instance * * Note: all locking must be provided by the caller. * * The returned structure contains statistics of all objects * currently in use, ordered by following rules: * 1) Root objects are always on lower indexes than the rest. * 2) Objects with higher delta user count are always on lower * indexes. * 3) In case multiple objects have the same delta user count, * the objects are ordered by user count. * * Returns a pointer to stats instance in case of success, * otherwise it returns pointer error using ERR_PTR macro.
*/ conststruct objagg_stats *
objagg_hints_stats_get(struct objagg_hints *objagg_hints)
{ struct objagg_stats *objagg_stats; struct objagg_hints_node *hnode; int i;
objagg_stats = kzalloc(struct_size(objagg_stats, stats_info,
objagg_hints->node_count),
GFP_KERNEL); if (!objagg_stats) return ERR_PTR(-ENOMEM);
i = 0;
list_for_each_entry(hnode, &objagg_hints->node_list, list) {
memcpy(&objagg_stats->stats_info[i], &hnode->stats_info, sizeof(objagg_stats->stats_info[0])); if (objagg_stats->stats_info[i].is_root)
objagg_stats->root_count++;
i++;
}
objagg_stats->stats_info_count = i;
Die Informationen auf dieser Webseite wurden
nach bestem Wissen sorgfältig zusammengestellt. Es wird jedoch weder Vollständigkeit, noch Richtigkeit,
noch Qualität der bereit gestellten Informationen zugesichert.
Bemerkung:
Die farbliche Syntaxdarstellung und die Messung sind noch experimentell.