Linux kernel mirror (for testing) git.kernel.org/pub/scm/linux/kernel/git/torvalds/linux.git
kernel os linux
1
fork

Configure Feed

Select the types of activity you want to include in your feed.

dpll: Enhance and consolidate reference counting logic

Refactor the reference counting mechanism for DPLL devices and pins to
improve consistency and prevent potential lifetime issues.

Introduce internal helpers __dpll_{device,pin}_{hold,put}() to
centralize reference management.

Update the internal XArray reference helpers (dpll_xa_ref_*) to
automatically grab a reference to the target object when it is added to
a list, and release it when removed. This ensures that objects linked
internally (e.g., pins referenced by parent pins) are properly kept
alive without relying on the caller to manually manage the count.

Consequently, remove the now redundant manual `refcount_inc/dec` calls
in dpll_pin_on_pin_{,un}register()`, as ownership is now correctly handled
by the dpll_xa_ref_* functions.

Additionally, ensure that dpll_device_{,un}register()` takes/releases
a reference to the device, ensuring the device object remains valid for
the duration of its registration.

Reviewed-by: Aleksandr Loktionov <aleksandr.loktionov@intel.com>
Signed-off-by: Ivan Vecera <ivecera@redhat.com>
Reviewed-by: Arkadiusz Kubalewski <arkadiusz.kubalewski@intel.com>
Link: https://patch.msgid.link/20260203174002.705176-7-ivecera@redhat.com
Signed-off-by: Paolo Abeni <pabeni@redhat.com>

authored by

Ivan Vecera and committed by
Paolo Abeni
729f5e01 fdad05ed

+50 -24
+50 -24
drivers/dpll/dpll_core.c
··· 83 83 call_dpll_notifiers(action, &info); 84 84 } 85 85 86 + static void __dpll_device_hold(struct dpll_device *dpll) 87 + { 88 + refcount_inc(&dpll->refcount); 89 + } 90 + 91 + static void __dpll_device_put(struct dpll_device *dpll) 92 + { 93 + if (refcount_dec_and_test(&dpll->refcount)) { 94 + ASSERT_DPLL_NOT_REGISTERED(dpll); 95 + WARN_ON_ONCE(!xa_empty(&dpll->pin_refs)); 96 + xa_destroy(&dpll->pin_refs); 97 + xa_erase(&dpll_device_xa, dpll->id); 98 + WARN_ON(!list_empty(&dpll->registration_list)); 99 + kfree(dpll); 100 + } 101 + } 102 + 103 + static void __dpll_pin_hold(struct dpll_pin *pin) 104 + { 105 + refcount_inc(&pin->refcount); 106 + } 107 + 108 + static void dpll_pin_idx_free(u32 pin_idx); 109 + static void dpll_pin_prop_free(struct dpll_pin_properties *prop); 110 + 111 + static void __dpll_pin_put(struct dpll_pin *pin) 112 + { 113 + if (refcount_dec_and_test(&pin->refcount)) { 114 + xa_erase(&dpll_pin_xa, pin->id); 115 + xa_destroy(&pin->dpll_refs); 116 + xa_destroy(&pin->parent_refs); 117 + xa_destroy(&pin->ref_sync_pins); 118 + dpll_pin_prop_free(&pin->prop); 119 + fwnode_handle_put(pin->fwnode); 120 + dpll_pin_idx_free(pin->pin_idx); 121 + kfree_rcu(pin, rcu); 122 + } 123 + } 124 + 86 125 struct dpll_device *dpll_device_get_by_id(int id) 87 126 { 88 127 if (xa_get_mark(&dpll_device_xa, id, DPLL_REGISTERED)) ··· 191 152 reg->ops = ops; 192 153 reg->priv = priv; 193 154 reg->cookie = cookie; 155 + __dpll_pin_hold(pin); 194 156 if (ref_exists) 195 157 refcount_inc(&ref->refcount); 196 158 list_add_tail(&reg->list, &ref->registration_list); ··· 214 174 if (WARN_ON(!reg)) 215 175 return -EINVAL; 216 176 list_del(&reg->list); 177 + __dpll_pin_put(pin); 217 178 kfree(reg); 218 179 if (refcount_dec_and_test(&ref->refcount)) { 219 180 xa_erase(xa_pins, i); ··· 272 231 reg->ops = ops; 273 232 reg->priv = priv; 274 233 reg->cookie = cookie; 234 + __dpll_device_hold(dpll); 275 235 if (ref_exists) 276 236 refcount_inc(&ref->refcount); 277 237 list_add_tail(&reg->list, &ref->registration_list); ··· 295 253 if (WARN_ON(!reg)) 296 254 return; 297 255 list_del(&reg->list); 256 + __dpll_device_put(dpll); 298 257 kfree(reg); 299 258 if (refcount_dec_and_test(&ref->refcount)) { 300 259 xa_erase(xa_dplls, i); ··· 366 323 if (dpll->clock_id == clock_id && 367 324 dpll->device_idx == device_idx && 368 325 dpll->module == module) { 326 + __dpll_device_hold(dpll); 369 327 ret = dpll; 370 - refcount_inc(&ret->refcount); 371 328 break; 372 329 } 373 330 } ··· 390 347 void dpll_device_put(struct dpll_device *dpll) 391 348 { 392 349 mutex_lock(&dpll_lock); 393 - if (refcount_dec_and_test(&dpll->refcount)) { 394 - ASSERT_DPLL_NOT_REGISTERED(dpll); 395 - WARN_ON_ONCE(!xa_empty(&dpll->pin_refs)); 396 - xa_destroy(&dpll->pin_refs); 397 - xa_erase(&dpll_device_xa, dpll->id); 398 - WARN_ON(!list_empty(&dpll->registration_list)); 399 - kfree(dpll); 400 - } 350 + __dpll_device_put(dpll); 401 351 mutex_unlock(&dpll_lock); 402 352 } 403 353 EXPORT_SYMBOL_GPL(dpll_device_put); ··· 452 416 reg->ops = ops; 453 417 reg->priv = priv; 454 418 dpll->type = type; 419 + __dpll_device_hold(dpll); 455 420 first_registration = list_empty(&dpll->registration_list); 456 421 list_add_tail(&reg->list, &dpll->registration_list); 457 422 if (!first_registration) { ··· 492 455 return; 493 456 } 494 457 list_del(&reg->list); 458 + __dpll_device_put(dpll); 495 459 kfree(reg); 496 460 497 461 if (!list_empty(&dpll->registration_list)) { ··· 704 666 if (pos->clock_id == clock_id && 705 667 pos->pin_idx == pin_idx && 706 668 pos->module == module) { 669 + __dpll_pin_hold(pos); 707 670 ret = pos; 708 - refcount_inc(&ret->refcount); 709 671 break; 710 672 } 711 673 } ··· 728 690 void dpll_pin_put(struct dpll_pin *pin) 729 691 { 730 692 mutex_lock(&dpll_lock); 731 - if (refcount_dec_and_test(&pin->refcount)) { 732 - xa_erase(&dpll_pin_xa, pin->id); 733 - xa_destroy(&pin->dpll_refs); 734 - xa_destroy(&pin->parent_refs); 735 - xa_destroy(&pin->ref_sync_pins); 736 - dpll_pin_prop_free(&pin->prop); 737 - fwnode_handle_put(pin->fwnode); 738 - dpll_pin_idx_free(pin->pin_idx); 739 - kfree_rcu(pin, rcu); 740 - } 693 + __dpll_pin_put(pin); 741 694 mutex_unlock(&dpll_lock); 742 695 } 743 696 EXPORT_SYMBOL_GPL(dpll_pin_put); ··· 769 740 mutex_lock(&dpll_lock); 770 741 xa_for_each(&dpll_pin_xa, index, pin) { 771 742 if (pin->fwnode == fwnode) { 743 + __dpll_pin_hold(pin); 772 744 ret = pin; 773 - refcount_inc(&ret->refcount); 774 745 break; 775 746 } 776 747 } ··· 922 893 ret = dpll_xa_ref_pin_add(&pin->parent_refs, parent, ops, priv, pin); 923 894 if (ret) 924 895 goto unlock; 925 - refcount_inc(&pin->refcount); 926 896 xa_for_each(&parent->dpll_refs, i, ref) { 927 897 ret = __dpll_pin_register(ref->dpll, pin, ops, priv, parent); 928 898 if (ret) { ··· 941 913 parent); 942 914 dpll_pin_delete_ntf(pin); 943 915 } 944 - refcount_dec(&pin->refcount); 945 916 dpll_xa_ref_pin_del(&pin->parent_refs, parent, ops, priv, pin); 946 917 unlock: 947 918 mutex_unlock(&dpll_lock); ··· 967 940 mutex_lock(&dpll_lock); 968 941 dpll_pin_delete_ntf(pin); 969 942 dpll_xa_ref_pin_del(&pin->parent_refs, parent, ops, priv, pin); 970 - refcount_dec(&pin->refcount); 971 943 xa_for_each(&pin->dpll_refs, i, ref) 972 944 __dpll_pin_unregister(ref->dpll, pin, ops, priv, parent); 973 945 mutex_unlock(&dpll_lock);