ocfs2: Concurrent access of o2hb_region->hr_task was not locked
This means that a build-up and a teardown could race which would result in a double-kthread_stop(). Protect the setting and clearing of hr_task with o2hb_live_lock, as it's not a common thing and not performance critical. Signed-off-by: Joel Becker <joel.becker@oracle.com> Signed-off-by: Mark Fasheh <mark.fasheh@oracle.com>
This commit is contained in:
parent
c24f72cc7c
commit
e6c352dbc0
1 changed files with 32 additions and 12 deletions
|
@ -1234,6 +1234,7 @@ static ssize_t o2hb_region_dev_write(struct o2hb_region *reg,
|
||||||
const char *page,
|
const char *page,
|
||||||
size_t count)
|
size_t count)
|
||||||
{
|
{
|
||||||
|
struct task_struct *hb_task;
|
||||||
long fd;
|
long fd;
|
||||||
int sectsize;
|
int sectsize;
|
||||||
char *p = (char *)page;
|
char *p = (char *)page;
|
||||||
|
@ -1319,20 +1320,28 @@ static ssize_t o2hb_region_dev_write(struct o2hb_region *reg,
|
||||||
*/
|
*/
|
||||||
atomic_set(®->hr_steady_iterations, O2HB_LIVE_THRESHOLD + 1);
|
atomic_set(®->hr_steady_iterations, O2HB_LIVE_THRESHOLD + 1);
|
||||||
|
|
||||||
reg->hr_task = kthread_run(o2hb_thread, reg, "o2hb-%s",
|
hb_task = kthread_run(o2hb_thread, reg, "o2hb-%s",
|
||||||
reg->hr_item.ci_name);
|
reg->hr_item.ci_name);
|
||||||
if (IS_ERR(reg->hr_task)) {
|
if (IS_ERR(hb_task)) {
|
||||||
ret = PTR_ERR(reg->hr_task);
|
ret = PTR_ERR(hb_task);
|
||||||
mlog_errno(ret);
|
mlog_errno(ret);
|
||||||
reg->hr_task = NULL;
|
|
||||||
goto out;
|
goto out;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
spin_lock(&o2hb_live_lock);
|
||||||
|
reg->hr_task = hb_task;
|
||||||
|
spin_unlock(&o2hb_live_lock);
|
||||||
|
|
||||||
ret = wait_event_interruptible(o2hb_steady_queue,
|
ret = wait_event_interruptible(o2hb_steady_queue,
|
||||||
atomic_read(®->hr_steady_iterations) == 0);
|
atomic_read(®->hr_steady_iterations) == 0);
|
||||||
if (ret) {
|
if (ret) {
|
||||||
kthread_stop(reg->hr_task);
|
spin_lock(&o2hb_live_lock);
|
||||||
|
hb_task = reg->hr_task;
|
||||||
reg->hr_task = NULL;
|
reg->hr_task = NULL;
|
||||||
|
spin_unlock(&o2hb_live_lock);
|
||||||
|
|
||||||
|
if (hb_task)
|
||||||
|
kthread_stop(hb_task);
|
||||||
goto out;
|
goto out;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -1354,10 +1363,17 @@ out:
|
||||||
static ssize_t o2hb_region_pid_read(struct o2hb_region *reg,
|
static ssize_t o2hb_region_pid_read(struct o2hb_region *reg,
|
||||||
char *page)
|
char *page)
|
||||||
{
|
{
|
||||||
if (!reg->hr_task)
|
pid_t pid = 0;
|
||||||
|
|
||||||
|
spin_lock(&o2hb_live_lock);
|
||||||
|
if (reg->hr_task)
|
||||||
|
pid = reg->hr_task->pid;
|
||||||
|
spin_unlock(&o2hb_live_lock);
|
||||||
|
|
||||||
|
if (!pid)
|
||||||
return 0;
|
return 0;
|
||||||
|
|
||||||
return sprintf(page, "%u\n", reg->hr_task->pid);
|
return sprintf(page, "%u\n", pid);
|
||||||
}
|
}
|
||||||
|
|
||||||
struct o2hb_region_attribute {
|
struct o2hb_region_attribute {
|
||||||
|
@ -1495,13 +1511,17 @@ out:
|
||||||
static void o2hb_heartbeat_group_drop_item(struct config_group *group,
|
static void o2hb_heartbeat_group_drop_item(struct config_group *group,
|
||||||
struct config_item *item)
|
struct config_item *item)
|
||||||
{
|
{
|
||||||
|
struct task_struct *hb_task;
|
||||||
struct o2hb_region *reg = to_o2hb_region(item);
|
struct o2hb_region *reg = to_o2hb_region(item);
|
||||||
|
|
||||||
/* stop the thread when the user removes the region dir */
|
/* stop the thread when the user removes the region dir */
|
||||||
if (reg->hr_task) {
|
spin_lock(&o2hb_live_lock);
|
||||||
kthread_stop(reg->hr_task);
|
hb_task = reg->hr_task;
|
||||||
reg->hr_task = NULL;
|
reg->hr_task = NULL;
|
||||||
}
|
spin_unlock(&o2hb_live_lock);
|
||||||
|
|
||||||
|
if (hb_task)
|
||||||
|
kthread_stop(hb_task);
|
||||||
|
|
||||||
config_item_put(item);
|
config_item_put(item);
|
||||||
}
|
}
|
||||||
|
|
Loading…
Add table
Reference in a new issue