diff options
author | mishra <none@none> | 2007-06-13 09:54:38 -0700 |
---|---|---|
committer | mishra <none@none> | 2007-06-13 09:54:38 -0700 |
commit | 8db829a5d6be690fdcfbcb57bae3b8ffdbc36875 (patch) | |
tree | ecc037e81b7ae8c7c1f41950af435045eec1d852 | |
parent | b2e8ece49d4c2e04af8e8e83caa60e23caa58061 (diff) | |
download | illumos-joyent-8db829a5d6be690fdcfbcb57bae3b8ffdbc36875.tar.gz |
6249442 competing ufs_sync_with_thread() callers can cause system hang
-rw-r--r-- | usr/src/uts/common/fs/ufs/ufs_thread.c | 41 |
1 files changed, 31 insertions, 10 deletions
diff --git a/usr/src/uts/common/fs/ufs/ufs_thread.c b/usr/src/uts/common/fs/ufs/ufs_thread.c index 2828cc43cd..36256db6ac 100644 --- a/usr/src/uts/common/fs/ufs/ufs_thread.c +++ b/usr/src/uts/common/fs/ufs/ufs_thread.c @@ -152,14 +152,18 @@ ufs_thread_suspend(struct ufs_q *uq) cv_wait(&uq->uq_cv, &uq->uq_mutex); } + uq->uq_flags |= (UQ_SUSPEND | UQ_WAIT); + /* * wait for the thread to suspend itself */ - uq->uq_flags |= UQ_SUSPEND; - while (((uq->uq_flags & UQ_SUSPENDED) == 0) && + if ((uq->uq_flags & UQ_SUSPENDED) == 0 && (uq->uq_threadp != NULL)) { - uq->uq_flags |= UQ_WAIT; cv_broadcast(&uq->uq_cv); + } + + while (((uq->uq_flags & UQ_SUSPENDED) == 0) && + (uq->uq_threadp != NULL)) { cv_wait(&uq->uq_cv, &uq->uq_mutex); } } @@ -566,16 +570,19 @@ void ufs_sync_with_thread(struct ufs_q *uq) { mutex_enter(&uq->uq_mutex); - uq->uq_flags |= UQ_WAIT; + /* - * Someone other than the thread we're interested in might - * send a signal, so make sure the thread's given an - * acknowledgement. + * Wake up delete thread to free up space. */ - while ((uq->uq_threadp != NULL) && (uq->uq_flags & UQ_WAIT)) { + if ((uq->uq_flags & UQ_WAIT) == 0) { + uq->uq_flags |= UQ_WAIT; cv_broadcast(&uq->uq_cv); + } + + while ((uq->uq_threadp != NULL) && (uq->uq_flags & UQ_WAIT)) { cv_wait(&uq->uq_cv, &uq->uq_mutex); } + mutex_exit(&uq->uq_mutex); } @@ -593,9 +600,23 @@ ufs_delete_drain_wait(struct ufsvfs *ufsvfsp, int dolockfs) { struct ufs_q *uq = &ufsvfsp->vfs_delete; int error; + struct ufs_q *delq = &ufsvfsp->vfs_delete; + struct ufs_delq_info *delq_info = &ufsvfsp->vfs_delete_info; - (void) ufs_delete_drain(ufsvfsp->vfs_vfs, 0, dolockfs); - ufs_sync_with_thread(uq); + /* + * If there is something on delq or delete thread + * working on delq. + */ + mutex_enter(&delq->uq_mutex); + if (delq_info->delq_unreclaimed_files > 0) { + mutex_exit(&delq->uq_mutex); + (void) ufs_delete_drain(ufsvfsp->vfs_vfs, 0, dolockfs); + ufs_sync_with_thread(uq); + } else { + ASSERT(delq_info->delq_unreclaimed_files == 0); + mutex_exit(&delq->uq_mutex); + return; + } /* * Commit any outstanding transactions to make sure |