1 // SPDX-License-Identifier: BSD-3-Clause OR GPL-2.0 2 /* Copyright (c) 2018 Mellanox Technologies. All rights reserved */ 3 4 #include <linux/module.h> 5 #include <linux/slab.h> 6 #include <linux/rhashtable.h> 7 #include <linux/idr.h> 8 #include <linux/list.h> 9 #include <linux/sort.h> 10 #include <linux/objagg.h> 11 12 #define CREATE_TRACE_POINTS 13 #include <trace/events/objagg.h> 14 15 struct objagg_hints { 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; 23 }; 24 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; 29 unsigned int root_id; 30 struct objagg_obj_stats_info stats_info; 31 unsigned long obj[]; 32 }; 33 34 static struct objagg_hints_node * 35 objagg_hints_lookup(struct objagg_hints *objagg_hints, void *obj) 36 { 37 if (!objagg_hints) 38 return NULL; 39 return rhashtable_lookup_fast(&objagg_hints->node_ht, obj, 40 objagg_hints->ht_params); 41 } 42 43 struct objagg { 44 const struct objagg_ops *ops; 45 void *priv; 46 struct rhashtable obj_ht; 47 struct rhashtable_params ht_params; 48 struct list_head obj_list; 49 unsigned int obj_count; 50 struct ida root_ida; 51 struct objagg_hints *hints; 52 }; 53 54 struct objagg_obj { 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 59 */ 60 union { 61 void *delta_priv; /* user delta private */ 62 void *root_priv; /* user root private */ 63 }; 64 unsigned int root_id; 65 unsigned int refcount; /* counts number of users of this object 66 * including nested objects 67 */ 68 struct objagg_obj_stats stats; 69 unsigned long obj[]; 70 }; 71 72 static unsigned int objagg_obj_ref_inc(struct objagg_obj *objagg_obj) 73 { 74 return ++objagg_obj->refcount; 75 } 76 77 static unsigned int objagg_obj_ref_dec(struct objagg_obj *objagg_obj) 78 { 79 return --objagg_obj->refcount; 80 } 81 82 static void objagg_obj_stats_inc(struct objagg_obj *objagg_obj) 83 { 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++; 88 } 89 90 static void objagg_obj_stats_dec(struct objagg_obj *objagg_obj) 91 { 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--; 96 } 97 98 static bool objagg_obj_is_root(const struct objagg_obj *objagg_obj) 99 { 100 /* Nesting is not supported, so we can use ->parent 101 * to figure out if the object is root. 102 */ 103 return !objagg_obj->parent; 104 } 105 106 /** 107 * objagg_obj_root_priv - obtains root private for an object 108 * @objagg_obj: objagg object instance 109 * 110 * Note: all locking must be provided by the caller. 111 * 112 * Either the object is root itself when the private is returned 113 * directly, or the parent is root and its private is returned 114 * instead. 115 * 116 * Returns a user private root pointer. 117 */ 118 const void *objagg_obj_root_priv(const struct objagg_obj *objagg_obj) 119 { 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; 124 } 125 EXPORT_SYMBOL(objagg_obj_root_priv); 126 127 /** 128 * objagg_obj_delta_priv - obtains delta private for an object 129 * @objagg_obj: objagg object instance 130 * 131 * Note: all locking must be provided by the caller. 132 * 133 * Returns user private delta pointer or NULL in case the passed 134 * object is root. 135 */ 136 const void *objagg_obj_delta_priv(const struct objagg_obj *objagg_obj) 137 { 138 if (objagg_obj_is_root(objagg_obj)) 139 return NULL; 140 return objagg_obj->delta_priv; 141 } 142 EXPORT_SYMBOL(objagg_obj_delta_priv); 143 144 /** 145 * objagg_obj_raw - obtains object user private pointer 146 * @objagg_obj: objagg object instance 147 * 148 * Note: all locking must be provided by the caller. 149 * 150 * Returns user private pointer as was passed to objagg_obj_get() by "obj" arg. 151 */ 152 const void *objagg_obj_raw(const struct objagg_obj *objagg_obj) 153 { 154 return objagg_obj->obj; 155 } 156 EXPORT_SYMBOL(objagg_obj_raw); 157 158 static struct objagg_obj *objagg_obj_lookup(struct objagg *objagg, void *obj) 159 { 160 return rhashtable_lookup_fast(&objagg->obj_ht, obj, objagg->ht_params); 161 } 162 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) 167 { 168 void *delta_priv; 169 170 delta_priv = objagg->ops->delta_create(objagg->priv, parent->obj, 171 objagg_obj->obj); 172 if (IS_ERR(delta_priv)) 173 return PTR_ERR(delta_priv); 174 175 /* User returned a delta private, that means that 176 * our object can be aggregated into the parent. 177 */ 178 objagg_obj->parent = parent; 179 objagg_obj->delta_priv = delta_priv; 180 if (take_parent_ref) 181 objagg_obj_ref_inc(objagg_obj->parent); 182 trace_objagg_obj_parent_assign(objagg, objagg_obj, 183 parent, 184 parent->refcount); 185 return 0; 186 } 187 188 static int objagg_obj_parent_lookup_assign(struct objagg *objagg, 189 struct objagg_obj *objagg_obj) 190 { 191 struct objagg_obj *objagg_obj_cur; 192 int err; 193 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. 197 */ 198 if (!objagg_obj_is_root(objagg_obj_cur)) 199 continue; 200 err = objagg_obj_parent_assign(objagg, objagg_obj, 201 objagg_obj_cur, true); 202 if (!err) 203 return 0; 204 } 205 return -ENOENT; 206 } 207 208 static void __objagg_obj_put(struct objagg *objagg, 209 struct objagg_obj *objagg_obj); 210 211 static void objagg_obj_parent_unassign(struct objagg *objagg, 212 struct objagg_obj *objagg_obj) 213 { 214 trace_objagg_obj_parent_unassign(objagg, objagg_obj, 215 objagg_obj->parent, 216 objagg_obj->parent->refcount); 217 objagg->ops->delta_destroy(objagg->priv, objagg_obj->delta_priv); 218 __objagg_obj_put(objagg, objagg_obj->parent); 219 } 220 221 static int objagg_obj_root_id_alloc(struct objagg *objagg, 222 struct objagg_obj *objagg_obj, 223 struct objagg_hints_node *hnode) 224 { 225 unsigned int min, max; 226 int root_id; 227 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; 231 return 0; 232 } 233 234 if (hnode) { 235 min = hnode->root_id; 236 max = hnode->root_id; 237 } else { 238 /* For objects with no hint, start after the last 239 * hinted root_id. 240 */ 241 min = objagg->hints->root_count; 242 max = ~0; 243 } 244 245 root_id = ida_alloc_range(&objagg->root_ida, min, max, GFP_KERNEL); 246 247 if (root_id < 0) 248 return root_id; 249 objagg_obj->root_id = root_id; 250 return 0; 251 } 252 253 static void objagg_obj_root_id_free(struct objagg *objagg, 254 struct objagg_obj *objagg_obj) 255 { 256 if (!objagg->hints) 257 return; 258 ida_free(&objagg->root_ida, objagg_obj->root_id); 259 } 260 261 static int objagg_obj_root_create(struct objagg *objagg, 262 struct objagg_obj *objagg_obj, 263 struct objagg_hints_node *hnode) 264 { 265 int err; 266 267 err = objagg_obj_root_id_alloc(objagg, objagg_obj, hnode); 268 if (err) 269 return err; 270 objagg_obj->root_priv = objagg->ops->root_create(objagg->priv, 271 objagg_obj->obj, 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; 276 } 277 trace_objagg_obj_root_create(objagg, objagg_obj); 278 return 0; 279 280 err_root_create: 281 objagg_obj_root_id_free(objagg, objagg_obj); 282 return err; 283 } 284 285 static void objagg_obj_root_destroy(struct objagg *objagg, 286 struct objagg_obj *objagg_obj) 287 { 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); 291 } 292 293 static struct objagg_obj *__objagg_obj_get(struct objagg *objagg, void *obj); 294 295 static int objagg_obj_init_with_hints(struct objagg *objagg, 296 struct objagg_obj *objagg_obj, 297 bool *hint_found) 298 { 299 struct objagg_hints_node *hnode; 300 struct objagg_obj *parent; 301 int err; 302 303 hnode = objagg_hints_lookup(objagg->hints, objagg_obj->obj); 304 if (!hnode) { 305 *hint_found = false; 306 return 0; 307 } 308 *hint_found = true; 309 310 if (!hnode->parent) 311 return objagg_obj_root_create(objagg, objagg_obj, hnode); 312 313 parent = __objagg_obj_get(objagg, hnode->parent->obj); 314 if (IS_ERR(parent)) 315 return PTR_ERR(parent); 316 317 err = objagg_obj_parent_assign(objagg, objagg_obj, parent, false); 318 if (err) { 319 *hint_found = false; 320 err = 0; 321 goto err_parent_assign; 322 } 323 324 return 0; 325 326 err_parent_assign: 327 objagg_obj_put(objagg, parent); 328 return err; 329 } 330 331 static int objagg_obj_init(struct objagg *objagg, 332 struct objagg_obj *objagg_obj) 333 { 334 bool hint_found; 335 int err; 336 337 /* First, try to use hints if they are available and 338 * if they provide result. 339 */ 340 err = objagg_obj_init_with_hints(objagg, objagg_obj, &hint_found); 341 if (err) 342 return err; 343 344 if (hint_found) 345 return 0; 346 347 /* Try to find if the object can be aggregated under an existing one. */ 348 err = objagg_obj_parent_lookup_assign(objagg, objagg_obj); 349 if (!err) 350 return 0; 351 /* If aggregation is not possible, make the object a root. */ 352 return objagg_obj_root_create(objagg, objagg_obj, NULL); 353 } 354 355 static void objagg_obj_fini(struct objagg *objagg, 356 struct objagg_obj *objagg_obj) 357 { 358 if (!objagg_obj_is_root(objagg_obj)) 359 objagg_obj_parent_unassign(objagg, objagg_obj); 360 else 361 objagg_obj_root_destroy(objagg, objagg_obj); 362 } 363 364 static struct objagg_obj *objagg_obj_create(struct objagg *objagg, void *obj) 365 { 366 struct objagg_obj *objagg_obj; 367 int err; 368 369 objagg_obj = kzalloc(sizeof(*objagg_obj) + objagg->ops->obj_size, 370 GFP_KERNEL); 371 if (!objagg_obj) 372 return ERR_PTR(-ENOMEM); 373 objagg_obj_ref_inc(objagg_obj); 374 memcpy(objagg_obj->obj, obj, objagg->ops->obj_size); 375 376 err = objagg_obj_init(objagg, objagg_obj); 377 if (err) 378 goto err_obj_init; 379 380 err = rhashtable_insert_fast(&objagg->obj_ht, &objagg_obj->ht_node, 381 objagg->ht_params); 382 if (err) 383 goto err_ht_insert; 384 list_add(&objagg_obj->list, &objagg->obj_list); 385 objagg->obj_count++; 386 trace_objagg_obj_create(objagg, objagg_obj); 387 388 return objagg_obj; 389 390 err_ht_insert: 391 objagg_obj_fini(objagg, objagg_obj); 392 err_obj_init: 393 kfree(objagg_obj); 394 return ERR_PTR(err); 395 } 396 397 static struct objagg_obj *__objagg_obj_get(struct objagg *objagg, void *obj) 398 { 399 struct objagg_obj *objagg_obj; 400 401 /* First, try to find the object exactly as user passed it, 402 * perhaps it is already in use. 403 */ 404 objagg_obj = objagg_obj_lookup(objagg, obj); 405 if (objagg_obj) { 406 objagg_obj_ref_inc(objagg_obj); 407 return objagg_obj; 408 } 409 410 return objagg_obj_create(objagg, obj); 411 } 412 413 /** 414 * objagg_obj_get - gets an object within objagg instance 415 * @objagg: objagg instance 416 * @obj: user-specific private object pointer 417 * 418 * Note: all locking must be provided by the caller. 419 * 420 * Size of the "obj" memory is specified in "objagg->ops". 421 * 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. 433 * 434 * Returns a pointer to objagg object instance in case of success, 435 * otherwise it returns pointer error using ERR_PTR macro. 436 */ 437 struct objagg_obj *objagg_obj_get(struct objagg *objagg, void *obj) 438 { 439 struct objagg_obj *objagg_obj; 440 441 objagg_obj = __objagg_obj_get(objagg, obj); 442 if (IS_ERR(objagg_obj)) 443 return objagg_obj; 444 objagg_obj_stats_inc(objagg_obj); 445 trace_objagg_obj_get(objagg, objagg_obj, objagg_obj->refcount); 446 return objagg_obj; 447 } 448 EXPORT_SYMBOL(objagg_obj_get); 449 450 static void objagg_obj_destroy(struct objagg *objagg, 451 struct objagg_obj *objagg_obj) 452 { 453 trace_objagg_obj_destroy(objagg, objagg_obj); 454 --objagg->obj_count; 455 list_del(&objagg_obj->list); 456 rhashtable_remove_fast(&objagg->obj_ht, &objagg_obj->ht_node, 457 objagg->ht_params); 458 objagg_obj_fini(objagg, objagg_obj); 459 kfree(objagg_obj); 460 } 461 462 static void __objagg_obj_put(struct objagg *objagg, 463 struct objagg_obj *objagg_obj) 464 { 465 if (!objagg_obj_ref_dec(objagg_obj)) 466 objagg_obj_destroy(objagg, objagg_obj); 467 } 468 469 /** 470 * objagg_obj_put - puts an object within objagg instance 471 * @objagg: objagg instance 472 * @objagg_obj: objagg object instance 473 * 474 * Note: all locking must be provided by the caller. 475 * 476 * Symmetric to objagg_obj_get(). 477 */ 478 void objagg_obj_put(struct objagg *objagg, struct objagg_obj *objagg_obj) 479 { 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); 483 } 484 EXPORT_SYMBOL(objagg_obj_put); 485 486 /** 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 491 * 492 * Note: all locking must be provided by the caller. 493 * 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. 498 * 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. 503 * 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 509 * nodes. 510 * 511 * Returns a pointer to newly created objagg instance in case of success, 512 * otherwise it returns pointer error using ERR_PTR macro. 513 */ 514 struct objagg *objagg_create(const struct objagg_ops *ops, 515 struct objagg_hints *objagg_hints, void *priv) 516 { 517 struct objagg *objagg; 518 int err; 519 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); 524 525 objagg = kzalloc(sizeof(*objagg), GFP_KERNEL); 526 if (!objagg) 527 return ERR_PTR(-ENOMEM); 528 objagg->ops = ops; 529 if (objagg_hints) { 530 objagg->hints = objagg_hints; 531 objagg_hints->refcount++; 532 } 533 objagg->priv = priv; 534 INIT_LIST_HEAD(&objagg->obj_list); 535 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); 539 540 err = rhashtable_init(&objagg->obj_ht, &objagg->ht_params); 541 if (err) 542 goto err_rhashtable_init; 543 544 ida_init(&objagg->root_ida); 545 546 trace_objagg_create(objagg); 547 return objagg; 548 549 err_rhashtable_init: 550 kfree(objagg); 551 return ERR_PTR(err); 552 } 553 EXPORT_SYMBOL(objagg_create); 554 555 /** 556 * objagg_destroy - destroys a new objagg instance 557 * @objagg: objagg instance 558 * 559 * Note: all locking must be provided by the caller. 560 */ 561 void objagg_destroy(struct objagg *objagg) 562 { 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); 567 if (objagg->hints) 568 objagg_hints_put(objagg->hints); 569 kfree(objagg); 570 } 571 EXPORT_SYMBOL(objagg_destroy); 572 573 static int objagg_stats_info_sort_cmp_func(const void *a, const void *b) 574 { 575 const struct objagg_obj_stats_info *stats_info1 = a; 576 const struct objagg_obj_stats_info *stats_info2 = b; 577 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; 585 } 586 587 /** 588 * objagg_stats_get - obtains stats of the objagg instance 589 * @objagg: objagg instance 590 * 591 * Note: all locking must be provided by the caller. 592 * 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 597 * indexes. 598 * 3) In case more objects have the same delta user count, 599 * the objects are ordered by user count. 600 * 601 * Returns a pointer to stats instance in case of success, 602 * otherwise it returns pointer error using ERR_PTR macro. 603 */ 604 const struct objagg_stats *objagg_stats_get(struct objagg *objagg) 605 { 606 struct objagg_stats *objagg_stats; 607 struct objagg_obj *objagg_obj; 608 int i; 609 610 objagg_stats = kzalloc(struct_size(objagg_stats, stats_info, 611 objagg->obj_count), GFP_KERNEL); 612 if (!objagg_stats) 613 return ERR_PTR(-ENOMEM); 614 615 i = 0; 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++; 624 i++; 625 } 626 objagg_stats->stats_info_count = i; 627 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); 631 632 return objagg_stats; 633 } 634 EXPORT_SYMBOL(objagg_stats_get); 635 636 /** 637 * objagg_stats_put - puts stats of the objagg instance 638 * @objagg_stats: objagg instance stats 639 * 640 * Note: all locking must be provided by the caller. 641 */ 642 void objagg_stats_put(const struct objagg_stats *objagg_stats) 643 { 644 kfree(objagg_stats); 645 } 646 EXPORT_SYMBOL(objagg_stats_put); 647 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) 652 { 653 unsigned int user_count = objagg_obj->stats.user_count; 654 struct objagg_hints_node *hnode; 655 int err; 656 657 hnode = kzalloc(sizeof(*hnode) + obj_size, GFP_KERNEL); 658 if (!hnode) 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; 663 if (parent_hnode) { 664 parent_hnode->stats_info.stats.delta_user_count += user_count; 665 } else { 666 hnode->root_id = objagg_hints->root_count++; 667 hnode->stats_info.is_root = true; 668 } 669 hnode->stats_info.objagg_obj = objagg_obj; 670 671 err = rhashtable_insert_fast(&objagg_hints->node_ht, &hnode->ht_node, 672 objagg_hints->ht_params); 673 if (err) 674 goto err_ht_insert; 675 676 list_add(&hnode->list, &objagg_hints->node_list); 677 hnode->parent = parent_hnode; 678 objagg_hints->node_count++; 679 680 return hnode; 681 682 err_ht_insert: 683 kfree(hnode); 684 return ERR_PTR(err); 685 } 686 687 static void objagg_hints_flush(struct objagg_hints *objagg_hints) 688 { 689 struct objagg_hints_node *hnode, *tmp; 690 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); 695 kfree(hnode); 696 } 697 } 698 699 struct objagg_tmp_node { 700 struct objagg_obj *objagg_obj; 701 bool crossed_out; 702 }; 703 704 struct objagg_tmp_graph { 705 struct objagg_tmp_node *nodes; 706 unsigned long nodes_count; 707 unsigned long *edges; 708 }; 709 710 static int objagg_tmp_graph_edge_index(struct objagg_tmp_graph *graph, 711 int parent_index, int index) 712 { 713 return index * graph->nodes_count + parent_index; 714 } 715 716 static void objagg_tmp_graph_edge_set(struct objagg_tmp_graph *graph, 717 int parent_index, int index) 718 { 719 int edge_index = objagg_tmp_graph_edge_index(graph, index, 720 parent_index); 721 722 __set_bit(edge_index, graph->edges); 723 } 724 725 static bool objagg_tmp_graph_is_edge(struct objagg_tmp_graph *graph, 726 int parent_index, int index) 727 { 728 int edge_index = objagg_tmp_graph_edge_index(graph, index, 729 parent_index); 730 731 return test_bit(edge_index, graph->edges); 732 } 733 734 static unsigned int objagg_tmp_graph_node_weight(struct objagg_tmp_graph *graph, 735 unsigned int index) 736 { 737 struct objagg_tmp_node *node = &graph->nodes[index]; 738 unsigned int weight = node->objagg_obj->stats.user_count; 739 int j; 740 741 /* Node weight is sum of node users and all other nodes users 742 * that this node can represent with delta. 743 */ 744 745 for (j = 0; j < graph->nodes_count; j++) { 746 if (!objagg_tmp_graph_is_edge(graph, index, j)) 747 continue; 748 node = &graph->nodes[j]; 749 if (node->crossed_out) 750 continue; 751 weight += node->objagg_obj->stats.user_count; 752 } 753 return weight; 754 } 755 756 static int objagg_tmp_graph_node_max_weight(struct objagg_tmp_graph *graph) 757 { 758 struct objagg_tmp_node *node; 759 unsigned int max_weight = 0; 760 unsigned int weight; 761 int max_index = -1; 762 int i; 763 764 for (i = 0; i < graph->nodes_count; i++) { 765 node = &graph->nodes[i]; 766 if (node->crossed_out) 767 continue; 768 weight = objagg_tmp_graph_node_weight(graph, i); 769 if (weight >= max_weight) { 770 max_weight = weight; 771 max_index = i; 772 } 773 } 774 return max_index; 775 } 776 777 static struct objagg_tmp_graph *objagg_tmp_graph_create(struct objagg *objagg) 778 { 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; 784 size_t alloc_size; 785 int i, j; 786 787 graph = kzalloc(sizeof(*graph), GFP_KERNEL); 788 if (!graph) 789 return NULL; 790 791 graph->nodes = kcalloc(nodes_count, sizeof(*graph->nodes), GFP_KERNEL); 792 if (!graph->nodes) 793 goto err_nodes_alloc; 794 graph->nodes_count = nodes_count; 795 796 alloc_size = BITS_TO_LONGS(nodes_count * nodes_count) * 797 sizeof(unsigned long); 798 graph->edges = kzalloc(alloc_size, GFP_KERNEL); 799 if (!graph->edges) 800 goto err_edges_alloc; 801 802 i = 0; 803 list_for_each_entry(objagg_obj, &objagg->obj_list, list) { 804 node = &graph->nodes[i++]; 805 node->objagg_obj = objagg_obj; 806 } 807 808 /* Assemble a temporary graph. Insert edge X->Y in case Y can be 809 * in delta of X. 810 */ 811 for (i = 0; i < nodes_count; i++) { 812 for (j = 0; j < nodes_count; j++) { 813 if (i == j) 814 continue; 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); 821 822 } 823 } 824 } 825 return graph; 826 827 err_edges_alloc: 828 kfree(graph->nodes); 829 err_nodes_alloc: 830 kfree(graph); 831 return NULL; 832 } 833 834 static void objagg_tmp_graph_destroy(struct objagg_tmp_graph *graph) 835 { 836 kfree(graph->edges); 837 kfree(graph->nodes); 838 kfree(graph); 839 } 840 841 static int 842 objagg_opt_simple_greedy_fillup_hints(struct objagg_hints *objagg_hints, 843 struct objagg *objagg) 844 { 845 struct objagg_hints_node *hnode, *parent_hnode; 846 struct objagg_tmp_graph *graph; 847 struct objagg_tmp_node *node; 848 int index; 849 int j; 850 int err; 851 852 graph = objagg_tmp_graph_create(objagg); 853 if (!graph) 854 return -ENOMEM; 855 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. 858 */ 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, 863 node->objagg_obj, 864 objagg->ops->obj_size, 865 NULL); 866 if (IS_ERR(hnode)) { 867 err = PTR_ERR(hnode); 868 goto out; 869 } 870 parent_hnode = hnode; 871 for (j = 0; j < graph->nodes_count; j++) { 872 if (!objagg_tmp_graph_is_edge(graph, index, j)) 873 continue; 874 node = &graph->nodes[j]; 875 if (node->crossed_out) 876 continue; 877 node->crossed_out = true; 878 hnode = objagg_hints_node_create(objagg_hints, 879 node->objagg_obj, 880 objagg->ops->obj_size, 881 parent_hnode); 882 if (IS_ERR(hnode)) { 883 err = PTR_ERR(hnode); 884 goto out; 885 } 886 } 887 } 888 889 err = 0; 890 out: 891 objagg_tmp_graph_destroy(graph); 892 return err; 893 } 894 895 struct objagg_opt_algo { 896 int (*fillup_hints)(struct objagg_hints *objagg_hints, 897 struct objagg *objagg); 898 }; 899 900 static const struct objagg_opt_algo objagg_opt_simple_greedy = { 901 .fillup_hints = objagg_opt_simple_greedy_fillup_hints, 902 }; 903 904 905 static const struct objagg_opt_algo *objagg_opt_algos[] = { 906 [OBJAGG_OPT_ALGO_SIMPLE_GREEDY] = &objagg_opt_simple_greedy, 907 }; 908 909 static int objagg_hints_obj_cmp(struct rhashtable_compare_arg *arg, 910 const void *obj) 911 { 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; 917 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); 921 } 922 923 /** 924 * objagg_hints_get - obtains hints instance 925 * @objagg: objagg instance 926 * @opt_algo_type: type of hints finding algorithm 927 * 928 * Note: all locking must be provided by the caller. 929 * 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. 936 * 937 * Returns a pointer to hints instance in case of success, 938 * otherwise it returns pointer error using ERR_PTR macro. 939 */ 940 struct objagg_hints *objagg_hints_get(struct objagg *objagg, 941 enum objagg_opt_algo_type opt_algo_type) 942 { 943 const struct objagg_opt_algo *algo = objagg_opt_algos[opt_algo_type]; 944 struct objagg_hints *objagg_hints; 945 int err; 946 947 objagg_hints = kzalloc(sizeof(*objagg_hints), GFP_KERNEL); 948 if (!objagg_hints) 949 return ERR_PTR(-ENOMEM); 950 951 objagg_hints->ops = objagg->ops; 952 objagg_hints->refcount = 1; 953 954 INIT_LIST_HEAD(&objagg_hints->node_list); 955 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; 962 963 err = rhashtable_init(&objagg_hints->node_ht, &objagg_hints->ht_params); 964 if (err) 965 goto err_rhashtable_init; 966 967 err = algo->fillup_hints(objagg_hints, objagg); 968 if (err) 969 goto err_fillup_hints; 970 971 if (WARN_ON(objagg_hints->node_count != objagg->obj_count)) { 972 err = -EINVAL; 973 goto err_node_count_check; 974 } 975 976 return objagg_hints; 977 978 err_node_count_check: 979 err_fillup_hints: 980 objagg_hints_flush(objagg_hints); 981 rhashtable_destroy(&objagg_hints->node_ht); 982 err_rhashtable_init: 983 kfree(objagg_hints); 984 return ERR_PTR(err); 985 } 986 EXPORT_SYMBOL(objagg_hints_get); 987 988 /** 989 * objagg_hints_put - puts hints instance 990 * @objagg_hints: objagg hints instance 991 * 992 * Note: all locking must be provided by the caller. 993 */ 994 void objagg_hints_put(struct objagg_hints *objagg_hints) 995 { 996 if (--objagg_hints->refcount) 997 return; 998 objagg_hints_flush(objagg_hints); 999 rhashtable_destroy(&objagg_hints->node_ht); 1000 kfree(objagg_hints); 1001 } 1002 EXPORT_SYMBOL(objagg_hints_put); 1003 1004 /** 1005 * objagg_hints_stats_get - obtains stats of the hints instance 1006 * @objagg_hints: hints instance 1007 * 1008 * Note: all locking must be provided by the caller. 1009 * 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 1014 * indexes. 1015 * 3) In case multiple objects have the same delta user count, 1016 * the objects are ordered by user count. 1017 * 1018 * Returns a pointer to stats instance in case of success, 1019 * otherwise it returns pointer error using ERR_PTR macro. 1020 */ 1021 const struct objagg_stats * 1022 objagg_hints_stats_get(struct objagg_hints *objagg_hints) 1023 { 1024 struct objagg_stats *objagg_stats; 1025 struct objagg_hints_node *hnode; 1026 int i; 1027 1028 objagg_stats = kzalloc(struct_size(objagg_stats, stats_info, 1029 objagg_hints->node_count), 1030 GFP_KERNEL); 1031 if (!objagg_stats) 1032 return ERR_PTR(-ENOMEM); 1033 1034 i = 0; 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++; 1040 i++; 1041 } 1042 objagg_stats->stats_info_count = i; 1043 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); 1047 1048 return objagg_stats; 1049 } 1050 EXPORT_SYMBOL(objagg_hints_stats_get); 1051 1052 MODULE_LICENSE("Dual BSD/GPL"); 1053 MODULE_AUTHOR("Jiri Pirko <jiri@mellanox.com>"); 1054 MODULE_DESCRIPTION("Object aggregation manager"); 1055