0001
0002
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;
0027 struct list_head 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;
0056 struct list_head list;
0057 struct objagg_obj *parent;
0058
0059
0060 union {
0061 void *delta_priv;
0062 void *root_priv;
0063 };
0064 unsigned int root_id;
0065 unsigned int refcount;
0066
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
0101
0102
0103 return !objagg_obj->parent;
0104 }
0105
0106
0107
0108
0109
0110
0111
0112
0113
0114
0115
0116
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
0129
0130
0131
0132
0133
0134
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
0146
0147
0148
0149
0150
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
0176
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
0196
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
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
0239
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
0338
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
0348 err = objagg_obj_parent_lookup_assign(objagg, objagg_obj);
0349 if (!err)
0350 return 0;
0351
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
0402
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
0415
0416
0417
0418
0419
0420
0421
0422
0423
0424
0425
0426
0427
0428
0429
0430
0431
0432
0433
0434
0435
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
0471
0472
0473
0474
0475
0476
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
0488
0489
0490
0491
0492
0493
0494
0495
0496
0497
0498
0499
0500
0501
0502
0503
0504
0505
0506
0507
0508
0509
0510
0511
0512
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
0557
0558
0559
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
0589
0590
0591
0592
0593
0594
0595
0596
0597
0598
0599
0600
0601
0602
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
0638
0639
0640
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
0742
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
0806
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
0854
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
0922
0923
0924
0925
0926
0927
0928
0929
0930
0931
0932
0933
0934
0935
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
0987
0988
0989
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
1003
1004
1005
1006
1007
1008
1009
1010
1011
1012
1013
1014
1015
1016
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");