diff options
author | Marcel Telka <marcel@telka.sk> | 2017-02-28 12:19:19 +0100 |
---|---|---|
committer | Robert Mustacchi <rm@joyent.com> | 2017-03-22 21:08:11 +0000 |
commit | 7909625fdb7ecb20e9b7a777cfc0ec7ee63b4642 (patch) | |
tree | 222ac7fad529a689f94e0baeb23660669eb931ba /usr/src | |
parent | 4d4fcbb2e6013422cc7d02d2dc43e469a8691706 (diff) | |
download | illumos-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.c | 73 | ||||
-rw-r--r-- | usr/src/uts/common/nfs/rnode.h | 1 |
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; /* |