summaryrefslogtreecommitdiff
path: root/usr/src
diff options
context:
space:
mode:
authorMarcel Telka <marcel@telka.sk>2017-02-28 12:19:19 +0100
committerRobert Mustacchi <rm@joyent.com>2017-03-22 21:08:11 +0000
commit7909625fdb7ecb20e9b7a777cfc0ec7ee63b4642 (patch)
tree222ac7fad529a689f94e0baeb23660669eb931ba /usr/src
parent4d4fcbb2e6013422cc7d02d2dc43e469a8691706 (diff)
downloadillumos-gate-7909625fdb7ecb20e9b7a777cfc0ec7ee63b4642.tar.gz
7912 nfs_rwlock readers are running wild waiting for a writer that cannot come
Reviewed by: Arne Jansen <arne@die-jansens.de> Reviewed by: Gordon Ross <Gordon.W.Ross@gmail.com> Approved by: Robert Mustacchi <rm@joyent.com>
Diffstat (limited to 'usr/src')
-rw-r--r--usr/src/uts/common/fs/nfs/nfs_subr.c73
-rw-r--r--usr/src/uts/common/nfs/rnode.h1
2 files changed, 35 insertions, 39 deletions
diff --git a/usr/src/uts/common/fs/nfs/nfs_subr.c b/usr/src/uts/common/fs/nfs/nfs_subr.c
index 7ffb4591bb..96844660f4 100644
--- a/usr/src/uts/common/fs/nfs/nfs_subr.c
+++ b/usr/src/uts/common/fs/nfs/nfs_subr.c
@@ -4760,7 +4760,7 @@ nfs_rw_enter_sig(nfs_rwlock_t *l, krw_t rw, int intr)
if (lwp != NULL)
lwp->lwp_nostop++;
- if (cv_wait_sig(&l->cv, &l->lock) == 0) {
+ if (cv_wait_sig(&l->cv_rd, &l->lock) == 0) {
if (lwp != NULL)
lwp->lwp_nostop--;
mutex_exit(&l->lock);
@@ -4769,26 +4769,7 @@ nfs_rw_enter_sig(nfs_rwlock_t *l, krw_t rw, int intr)
if (lwp != NULL)
lwp->lwp_nostop--;
} else
- cv_wait(&l->cv, &l->lock);
-
- /*
- * If there are no readers active nor a writer active
- * we need to wake up the next waiter. If there is a
- * writer waiting we will wait again so we need to wake
- * up the next waiter (possible writer). If there is
- * no writer waiting we need to wake up the next
- * waiting reader (if any) so it is invited to the
- * party.
- */
- if (l->count == 0)
- cv_signal(&l->cv);
-
- /*
- * If there are readers active and no writers waiting
- * then wake up the next waiting reader (if any).
- */
- if (l->count > 0 && l->waiters == 0)
- cv_signal(&l->cv);
+ cv_wait(&l->cv_rd, &l->lock);
}
ASSERT(l->count < INT_MAX);
#ifdef DEBUG
@@ -4820,11 +4801,11 @@ nfs_rw_enter_sig(nfs_rwlock_t *l, krw_t rw, int intr)
l->waiters--;
/*
* If there are readers active and no
- * writers waiting then wake up the
- * next waiting reader (if any).
+ * writers waiting then wake up all of
+ * the waiting readers (if any).
*/
if (l->count > 0 && l->waiters == 0)
- cv_signal(&l->cv);
+ cv_broadcast(&l->cv_rd);
mutex_exit(&l->lock);
return (EINTR);
}
@@ -4898,31 +4879,43 @@ nfs_rw_exit(nfs_rwlock_t *l)
{
mutex_enter(&l->lock);
- /*
- * If this is releasing a writer lock, then increment count to
- * indicate that there is one less writer active. If this was
- * the last of possibly nested writer locks, then clear the owner
- * field as well to indicate that there is no writer active
- * and wakeup the first waiting writer or reader.
- *
- * If releasing a reader lock, then just decrement count to
- * indicate that there is one less reader active. If this was
- * the last active reader and there are writer(s) waiting,
- * then wake up the first.
- */
+
if (l->owner != NULL) {
ASSERT(l->owner == curthread);
+
+ /*
+ * To release a writer lock increment count to indicate that
+ * there is one less writer active. If this was the last of
+ * possibly nested writer locks, then clear the owner field as
+ * well to indicate that there is no writer active.
+ */
+ ASSERT(l->count < 0);
l->count++;
if (l->count == 0) {
l->owner = NULL;
- cv_signal(&l->cv);
+
+ /*
+ * If there are no writers waiting then wakeup all of
+ * the waiting readers (if any).
+ */
+ if (l->waiters == 0)
+ cv_broadcast(&l->cv_rd);
}
} else {
+ /*
+ * To release a reader lock just decrement count to indicate
+ * that there is one less reader active.
+ */
ASSERT(l->count > 0);
l->count--;
- if (l->count == 0 && l->waiters > 0)
- cv_signal(&l->cv);
}
+
+ /*
+ * If there are no readers active nor a writer active and there is a
+ * writer waiting we need to wake up it.
+ */
+ if (l->count == 0 && l->waiters > 0)
+ cv_signal(&l->cv);
mutex_exit(&l->lock);
}
@@ -4946,6 +4939,7 @@ nfs_rw_init(nfs_rwlock_t *l, char *name, krw_type_t type, void *arg)
l->owner = NULL;
mutex_init(&l->lock, NULL, MUTEX_DEFAULT, NULL);
cv_init(&l->cv, NULL, CV_DEFAULT, NULL);
+ cv_init(&l->cv_rd, NULL, CV_DEFAULT, NULL);
}
void
@@ -4954,6 +4948,7 @@ nfs_rw_destroy(nfs_rwlock_t *l)
mutex_destroy(&l->lock);
cv_destroy(&l->cv);
+ cv_destroy(&l->cv_rd);
}
int
diff --git a/usr/src/uts/common/nfs/rnode.h b/usr/src/uts/common/nfs/rnode.h
index fc85e2e5ec..b790b03d8a 100644
--- a/usr/src/uts/common/nfs/rnode.h
+++ b/usr/src/uts/common/nfs/rnode.h
@@ -172,6 +172,7 @@ typedef struct nfs_rwlock {
kthread_t *owner;
kmutex_t lock;
kcondvar_t cv;
+ kcondvar_t cv_rd;
} nfs_rwlock_t;
/*