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