Adding a function in order to be able to optimize away a number of locked bus cycles. Callers might for whatever reason want to accumulate unreferences in certain code paths (rcu grace periods, atomic regions ...). This makes it possible to perform the batched unreference more efficiently.
If accepted, I'd prefer patch 1 goes through Dave's DRM tree.
Makes it possible to optimize batched multiple unrefs. Initial user will be drivers/gpu/ttm which accumulates unrefs to be processed outside of atomic code.
Signed-off-by: Thomas Hellstrom thellstrom@vmware.com --- include/linux/kref.h | 2 ++ lib/kref.c | 30 ++++++++++++++++++++++++++++++ 2 files changed, 32 insertions(+), 0 deletions(-)
diff --git a/include/linux/kref.h b/include/linux/kref.h index 6cc38fc..d4a62ab 100644 --- a/include/linux/kref.h +++ b/include/linux/kref.h @@ -24,5 +24,7 @@ struct kref { void kref_init(struct kref *kref); void kref_get(struct kref *kref); int kref_put(struct kref *kref, void (*release) (struct kref *kref)); +int kref_sub(struct kref *kref, unsigned int count, + void (*release) (struct kref *kref));
#endif /* _KREF_H_ */ diff --git a/lib/kref.c b/lib/kref.c index d3d227a..3efb882 100644 --- a/lib/kref.c +++ b/lib/kref.c @@ -62,6 +62,36 @@ int kref_put(struct kref *kref, void (*release)(struct kref *kref)) return 0; }
+ +/** + * kref_sub - subtract a number of refcounts for object. + * @kref: object. + * @count: Number of recounts to subtract. + * @release: pointer to the function that will clean up the object when the + * last reference to the object is released. + * This pointer is required, and it is not acceptable to pass kfree + * in as this function. + * + * Subtract @count from the refcount, and if 0, call release(). + * Return 1 if the object was removed, otherwise return 0. Beware, if this + * function returns 0, you still can not count on the kref from remaining in + * memory. Only use the return value if you want to see if the kref is now + * gone, not present. + */ +int kref_sub(struct kref *kref, unsigned int count, + void (*release)(struct kref *kref)) +{ + WARN_ON(release == NULL); + WARN_ON(release == (void (*)(struct kref *))kfree); + + if (atomic_sub_and_test((int) count, &kref->refcount)) { + release(kref); + return 1; + } + return 0; +} + EXPORT_SYMBOL(kref_init); EXPORT_SYMBOL(kref_get); EXPORT_SYMBOL(kref_put); +EXPORT_SYMBOL(kref_sub);
Signed-off-by: Thomas Hellstrom thellstrom@vmware.com --- drivers/gpu/drm/ttm/ttm_bo.c | 6 ++---- 1 files changed, 2 insertions(+), 4 deletions(-)
diff --git a/drivers/gpu/drm/ttm/ttm_bo.c b/drivers/gpu/drm/ttm/ttm_bo.c index a586378..9ef893d 100644 --- a/drivers/gpu/drm/ttm/ttm_bo.c +++ b/drivers/gpu/drm/ttm/ttm_bo.c @@ -266,10 +266,8 @@ static void ttm_bo_ref_bug(struct kref *list_kref) void ttm_bo_list_ref_sub(struct ttm_buffer_object *bo, int count, bool never_free) { - while (count--) - kref_put(&bo->list_kref, - (never_free || (count >= 0)) ? ttm_bo_ref_bug : - ttm_bo_release_list); + kref_sub(&bo->list_kref, count, + (never_free) ? ttm_bo_ref_bug : ttm_bo_release_list); }
int ttm_bo_reserve(struct ttm_buffer_object *bo,
dri-devel@lists.freedesktop.org