summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authormishra <none@none>2007-06-13 09:54:38 -0700
committermishra <none@none>2007-06-13 09:54:38 -0700
commit8db829a5d6be690fdcfbcb57bae3b8ffdbc36875 (patch)
treeecc037e81b7ae8c7c1f41950af435045eec1d852
parentb2e8ece49d4c2e04af8e8e83caa60e23caa58061 (diff)
downloadillumos-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.c41
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