devlink: Rework devlink health reporter destructor

Devlink keeps its own reference to every reporter in a list and inits
refcount to 1 upon reporter's creation. Existing destructor waits to
free the memory indefinitely using msleep() until all references except
devlink's own are put.

Rework this mechanism by moving memory free routine to a separate
function, which is called when the last reporter reference is put.

Besides, it allows to call __devlink_health_reporter_destroy() while
locked on a reporters list mutex in symmetry to
__devlink_health_reporter_create(), which is required in follow-up
patch.

Signed-off-by: Vladyslav Tarasiuk <vladyslavt@mellanox.com>
Reviewed-by: Moshe Shemesh <moshe@mellanox.com>
Reviewed-by: Jiri Pirko <jiri@mellanox.com>
Signed-off-by: David S. Miller <davem@davemloft.net>
This commit is contained in:
Vladyslav Tarasiuk 2020-07-10 15:25:08 +03:00 committed by David S. Miller
parent c57544b3de
commit 3c5584bf0a

View File

@ -5379,6 +5379,29 @@ unlock:
} }
EXPORT_SYMBOL_GPL(devlink_health_reporter_create); EXPORT_SYMBOL_GPL(devlink_health_reporter_create);
static void
devlink_health_reporter_free(struct devlink_health_reporter *reporter)
{
mutex_destroy(&reporter->dump_lock);
if (reporter->dump_fmsg)
devlink_fmsg_free(reporter->dump_fmsg);
kfree(reporter);
}
static void
devlink_health_reporter_put(struct devlink_health_reporter *reporter)
{
if (refcount_dec_and_test(&reporter->refcount))
devlink_health_reporter_free(reporter);
}
static void
__devlink_health_reporter_destroy(struct devlink_health_reporter *reporter)
{
list_del(&reporter->list);
devlink_health_reporter_put(reporter);
}
/** /**
* devlink_health_reporter_destroy - destroy devlink health reporter * devlink_health_reporter_destroy - destroy devlink health reporter
* *
@ -5388,14 +5411,8 @@ void
devlink_health_reporter_destroy(struct devlink_health_reporter *reporter) devlink_health_reporter_destroy(struct devlink_health_reporter *reporter)
{ {
mutex_lock(&reporter->devlink->reporters_lock); mutex_lock(&reporter->devlink->reporters_lock);
list_del(&reporter->list); __devlink_health_reporter_destroy(reporter);
mutex_unlock(&reporter->devlink->reporters_lock); mutex_unlock(&reporter->devlink->reporters_lock);
while (refcount_read(&reporter->refcount) > 1)
msleep(100);
mutex_destroy(&reporter->dump_lock);
if (reporter->dump_fmsg)
devlink_fmsg_free(reporter->dump_fmsg);
kfree(reporter);
} }
EXPORT_SYMBOL_GPL(devlink_health_reporter_destroy); EXPORT_SYMBOL_GPL(devlink_health_reporter_destroy);
@ -5665,12 +5682,6 @@ unlock:
return NULL; return NULL;
} }
static void
devlink_health_reporter_put(struct devlink_health_reporter *reporter)
{
refcount_dec(&reporter->refcount);
}
void void
devlink_health_reporter_state_update(struct devlink_health_reporter *reporter, devlink_health_reporter_state_update(struct devlink_health_reporter *reporter,
enum devlink_health_reporter_state state) enum devlink_health_reporter_state state)