Commit c7c17c27 authored by David S. Miller's avatar David S. Miller

bbc_envctrl: Clean up properly if kthread_run() fails.

In bbc_envctrl_init() we have to unlink the fan and temp instances
from the lists because our caller is going to free up the 'bp' object
if we return an error.

We can't rely upon bbc_envctrl_cleanup() to do this work for us in
this case.
Reported-by: default avatarPatrick Finnegan <pat@computer-refuge.org>
Signed-off-by: default avatarDavid S. Miller <davem@davemloft.net>
parent 7466bd3c
...@@ -522,6 +522,40 @@ static void attach_one_fan(struct bbc_i2c_bus *bp, struct of_device *op, ...@@ -522,6 +522,40 @@ static void attach_one_fan(struct bbc_i2c_bus *bp, struct of_device *op,
set_fan_speeds(fp); set_fan_speeds(fp);
} }
static void destroy_one_temp(struct bbc_cpu_temperature *tp)
{
bbc_i2c_detach(tp->client);
kfree(tp);
}
static void destroy_all_temps(struct bbc_i2c_bus *bp)
{
struct bbc_cpu_temperature *tp, *tpos;
list_for_each_entry_safe(tp, tpos, &bp->temps, bp_list) {
list_del(&tp->bp_list);
list_del(&tp->glob_list);
destroy_one_temp(tp);
}
}
static void destroy_one_fan(struct bbc_fan_control *fp)
{
bbc_i2c_detach(fp->client);
kfree(fp);
}
static void destroy_all_fans(struct bbc_i2c_bus *bp)
{
struct bbc_fan_control *fp, *fpos;
list_for_each_entry_safe(fp, fpos, &bp->fans, bp_list) {
list_del(&fp->bp_list);
list_del(&fp->glob_list);
destroy_one_fan(fp);
}
}
int bbc_envctrl_init(struct bbc_i2c_bus *bp) int bbc_envctrl_init(struct bbc_i2c_bus *bp)
{ {
struct of_device *op; struct of_device *op;
...@@ -541,6 +575,8 @@ int bbc_envctrl_init(struct bbc_i2c_bus *bp) ...@@ -541,6 +575,8 @@ int bbc_envctrl_init(struct bbc_i2c_bus *bp)
int err = PTR_ERR(kenvctrld_task); int err = PTR_ERR(kenvctrld_task);
kenvctrld_task = NULL; kenvctrld_task = NULL;
destroy_all_temps(bp);
destroy_all_fans(bp);
return err; return err;
} }
} }
...@@ -548,35 +584,11 @@ int bbc_envctrl_init(struct bbc_i2c_bus *bp) ...@@ -548,35 +584,11 @@ int bbc_envctrl_init(struct bbc_i2c_bus *bp)
return 0; return 0;
} }
static void destroy_one_temp(struct bbc_cpu_temperature *tp)
{
bbc_i2c_detach(tp->client);
kfree(tp);
}
static void destroy_one_fan(struct bbc_fan_control *fp)
{
bbc_i2c_detach(fp->client);
kfree(fp);
}
void bbc_envctrl_cleanup(struct bbc_i2c_bus *bp) void bbc_envctrl_cleanup(struct bbc_i2c_bus *bp)
{ {
struct bbc_cpu_temperature *tp, *tpos;
struct bbc_fan_control *fp, *fpos;
if (kenvctrld_task) if (kenvctrld_task)
kthread_stop(kenvctrld_task); kthread_stop(kenvctrld_task);
list_for_each_entry_safe(tp, tpos, &bp->temps, bp_list) { destroy_all_temps(bp);
list_del(&tp->bp_list); destroy_all_fans(bp);
list_del(&tp->glob_list);
destroy_one_temp(tp);
}
list_for_each_entry_safe(fp, fpos, &bp->fans, bp_list) {
list_del(&fp->bp_list);
list_del(&fp->glob_list);
destroy_one_fan(fp);
}
} }
Markdown is supported
0%
or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment