Commit 00601079 authored by Dave Kleikamp's avatar Dave Kleikamp

Fix races in JFS threads.

Timing window between JFS threads dropping a lock and going to sleep
allowed a waker to send wake_up_process right before wakee slept.
This resulted in the thread going to sleep indefinately.
parent b533e812
......@@ -73,10 +73,11 @@
/*
* lbuf's ready to be redriven. Protected by log_redrive_lock (jfsIOtask)
* lbuf's ready to be redriven. Protected by log_redrive_lock (jfsIO thread)
*/
static lbuf_t *log_redrive_list;
static spinlock_t log_redrive_lock = SPIN_LOCK_UNLOCKED;
DECLARE_WAIT_QUEUE_HEAD(jfs_IO_thread_wait);
/*
......@@ -159,8 +160,7 @@ do { \
* external references
*/
extern void txLazyUnlock(tblock_t * tblk);
extern int jfs_thread_stopped(void);
extern struct task_struct *jfsIOtask;
extern int jfs_stop_threads;
extern struct completion jfsIOwait;
/*
......@@ -1779,7 +1779,7 @@ static inline void lbmRedrive(lbuf_t *bp)
log_redrive_list = bp;
spin_unlock_irqrestore(&log_redrive_lock, flags);
wake_up_process(jfsIOtask);
wake_up(&jfs_IO_thread_wait);
}
......@@ -2154,17 +2154,16 @@ int jfsIOWait(void *arg)
unlock_kernel();
jfsIOtask = current;
spin_lock_irq(&current->sigmask_lock);
siginitsetinv(&current->blocked,
sigmask(SIGHUP) | sigmask(SIGKILL) | sigmask(SIGSTOP)
| sigmask(SIGCONT));
sigfillset(&current->blocked);
recalc_sigpending(current);
spin_unlock_irq(&current->sigmask_lock);
complete(&jfsIOwait);
do {
DECLARE_WAITQUEUE(wq, current);
spin_lock_irq(&log_redrive_lock);
while ((bp = log_redrive_list)) {
log_redrive_list = bp->l_redrive_next;
......@@ -2173,11 +2172,13 @@ int jfsIOWait(void *arg)
lbmStartIO(bp);
spin_lock_irq(&log_redrive_lock);
}
spin_unlock_irq(&log_redrive_lock);
add_wait_queue(&jfs_IO_thread_wait, &wq);
set_current_state(TASK_INTERRUPTIBLE);
spin_unlock_irq(&log_redrive_lock);
schedule();
} while (!jfs_thread_stopped());
current->state = TASK_RUNNING;
remove_wait_queue(&jfs_IO_thread_wait, &wq);
} while (!jfs_stop_threads);
jFYI(1,("jfsIOWait being killed!\n"));
complete(&jfsIOwait);
......
......@@ -100,6 +100,9 @@ static spinlock_t jfsTxnLock = SPIN_LOCK_UNLOCKED;
#define LAZY_LOCK(flags) spin_lock_irqsave(&TxAnchor.LazyLock, flags)
#define LAZY_UNLOCK(flags) spin_unlock_irqrestore(&TxAnchor.LazyLock, flags)
DECLARE_WAIT_QUEUE_HEAD(jfs_sync_thread_wait);
DECLARE_WAIT_QUEUE_HEAD(jfs_commit_thread_wait);
/*
* Retry logic exist outside these macros to protect from spurrious wakeups.
*/
......@@ -143,11 +146,10 @@ extern int lmGroupCommit(log_t * log, tblock_t * tblk);
extern void lmSync(log_t *);
extern int readSuper(struct super_block *sb, metapage_t ** bpp);
extern int jfs_commit_inode(struct inode *, int);
extern int jfs_thread_stopped(void);
extern int jfs_stop_threads;
extern struct task_struct *jfsCommitTask;
struct task_struct *jfsCommitTask;
extern struct completion jfsIOwait;
extern struct task_struct *jfsSyncTask;
/*
* forward references
......@@ -190,7 +192,7 @@ static lid_t txLockAlloc(void)
if ((++TxAnchor.tlocksInUse > TxLockHWM) && (TlocksLow == 0)) {
jEVENT(0,("txLockAlloc TlocksLow\n"));
TlocksLow = 1;
wake_up_process(jfsSyncTask);
wake_up(&jfs_sync_thread_wait);
}
return lid;
......@@ -2784,9 +2786,8 @@ int jfs_lazycommit(void)
jfsCommitTask = current;
spin_lock_irq(&current->sigmask_lock);
siginitsetinv(&current->blocked,
sigmask(SIGHUP) | sigmask(SIGKILL) | sigmask(SIGSTOP)
| sigmask(SIGCONT));
sigfillset(&current->blocked);
recalc_sigpending(current);
spin_unlock_irq(&current->sigmask_lock);
LAZY_LOCK_INIT();
......@@ -2795,6 +2796,8 @@ int jfs_lazycommit(void)
complete(&jfsIOwait);
do {
DECLARE_WAITQUEUE(wq, current);
LAZY_LOCK(flags);
restart:
WorkDone = 0;
......@@ -2832,10 +2835,13 @@ int jfs_lazycommit(void)
if (WorkDone)
goto restart;
LAZY_UNLOCK(flags);
add_wait_queue(&jfs_commit_thread_wait, &wq);
set_current_state(TASK_INTERRUPTIBLE);
LAZY_UNLOCK(flags);
schedule();
} while (!jfs_thread_stopped());
current->state = TASK_RUNNING;
remove_wait_queue(&jfs_commit_thread_wait, &wq);
} while (!jfs_stop_threads);
if (TxAnchor.unlock_queue)
jERROR(1, ("jfs_lazycommit being killed with pending transactions!\n"));
......@@ -2858,7 +2864,7 @@ void txLazyUnlock(tblock_t * tblk)
TxAnchor.unlock_tail = tblk;
tblk->cqnext = 0;
LAZY_UNLOCK(flags);
wake_up_process(jfsCommitTask);
wake_up(&jfs_commit_thread_wait);
}
static void LogSyncRelease(metapage_t * mp)
......@@ -2905,17 +2911,15 @@ int jfs_sync(void)
unlock_kernel();
jfsSyncTask = current;
spin_lock_irq(&current->sigmask_lock);
siginitsetinv(&current->blocked,
sigmask(SIGHUP) | sigmask(SIGKILL) | sigmask(SIGSTOP)
| sigmask(SIGCONT));
sigfillset(&current->blocked);
recalc_sigpending(current);
spin_unlock_irq(&current->sigmask_lock);
complete(&jfsIOwait);
do {
DECLARE_WAITQUEUE(wq, current);
/*
* write each inode on the anonymous inode list
*/
......@@ -2976,11 +2980,13 @@ int jfs_sync(void)
list_splice(&TxAnchor.anon_list2, &TxAnchor.anon_list);
INIT_LIST_HEAD(&TxAnchor.anon_list2);
}
TXN_UNLOCK();
add_wait_queue(&jfs_sync_thread_wait, &wq);
set_current_state(TASK_INTERRUPTIBLE);
TXN_UNLOCK();
schedule();
} while (!jfs_thread_stopped());
current->state = TASK_RUNNING;
remove_wait_queue(&jfs_sync_thread_wait, &wq);
} while (!jfs_stop_threads);
jFYI(1, ("jfs_sync being killed\n"));
complete(&jfsIOwait);
......
......@@ -36,13 +36,10 @@ MODULE_LICENSE("GPL");
static kmem_cache_t * jfs_inode_cachep;
static int in_shutdown;
int jfs_stop_threads;
static pid_t jfsIOthread;
static pid_t jfsCommitThread;
static pid_t jfsSyncThread;
struct task_struct *jfsIOtask;
struct task_struct *jfsCommitTask;
struct task_struct *jfsSyncTask;
DECLARE_COMPLETION(jfsIOwait);
#ifdef CONFIG_JFS_DEBUG
......@@ -76,19 +73,9 @@ extern void jfs_proc_init(void);
extern void jfs_proc_clean(void);
#endif
int jfs_thread_stopped(void)
{
unsigned long signr;
siginfo_t info;
spin_lock_irq(&current->sigmask_lock);
signr = dequeue_signal(&current->blocked, &info);
spin_unlock_irq(&current->sigmask_lock);
if (signr == SIGKILL && in_shutdown)
return 1;
return 0;
}
extern wait_queue_head_t jfs_IO_thread_wait;
extern wait_queue_head_t jfs_commit_thread_wait;
extern wait_queue_head_t jfs_sync_thread_wait;
static struct inode *jfs_alloc_inode(struct super_block *sb)
{
......@@ -469,10 +456,12 @@ static int __init init_jfs_fs(void)
kill_committask:
send_sig(SIGKILL, jfsCommitTask, 1);
jfs_stop_threads = 1;
wake_up(&jfs_commit_thread_wait);
wait_for_completion(&jfsIOwait); /* Wait until Commit thread exits */
kill_iotask:
send_sig(SIGKILL, jfsIOtask, 1);
jfs_stop_threads = 1;
wake_up(&jfs_IO_thread_wait);
wait_for_completion(&jfsIOwait); /* Wait until IO thread exits */
end_txmngr:
txExit();
......@@ -487,14 +476,14 @@ static void __exit exit_jfs_fs(void)
{
jFYI(1, ("exit_jfs_fs called\n"));
in_shutdown = 1;
jfs_stop_threads = 1;
txExit();
metapage_exit();
send_sig(SIGKILL, jfsIOtask, 1);
wake_up(&jfs_IO_thread_wait);
wait_for_completion(&jfsIOwait); /* Wait until IO thread exits */
send_sig(SIGKILL, jfsCommitTask, 1);
wake_up(&jfs_commit_thread_wait);
wait_for_completion(&jfsIOwait); /* Wait until Commit thread exits */
send_sig(SIGKILL, jfsSyncTask, 1);
wake_up(&jfs_sync_thread_wait);
wait_for_completion(&jfsIOwait); /* Wait until Sync thread exits */
#if defined(CONFIG_JFS_DEBUG) && defined(CONFIG_PROC_FS)
jfs_proc_clean();
......
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