Source-Changes-HG archive

[Date Prev][Date Next][Thread Prev][Thread Next][Date Index][Thread Index][Old Index]

[src/trunk]: src/sys/kern Fix a deadlock where one thread exits, enters fstra...



details:   https://anonhg.NetBSD.org/src/rev/368fbc1ee233
branches:  trunk
changeset: 328719:368fbc1ee233
user:      hannken <hannken%NetBSD.org@localhost>
date:      Tue Apr 15 09:50:45 2014 +0000

description:
Fix a deadlock where one thread exits, enters fstrans_lwp_dtor()
and wants fstrans_lock.  This thread holds the proc_lock.
Another thread holds fstrans_lock and runs pserialize_perform().
As the first thread holds the proc_lock, timeouts are blocked and
the second thread blocks forever in kpause().

Change fstrans_lwp_dtor() to invalidate, but not free its info
structs.  No need to take fstrans_lock.

Change fstrans_get_lwp_info() to reuse invalidated info before
trying to allocate a new one.

diffstat:

 sys/kern/vfs_trans.c |  30 ++++++++++++++++++++----------
 1 files changed, 20 insertions(+), 10 deletions(-)

diffs (79 lines):

diff -r 5052d00b88ac -r 368fbc1ee233 sys/kern/vfs_trans.c
--- a/sys/kern/vfs_trans.c      Tue Apr 15 06:14:55 2014 +0000
+++ b/sys/kern/vfs_trans.c      Tue Apr 15 09:50:45 2014 +0000
@@ -1,4 +1,4 @@
-/*     $NetBSD: vfs_trans.c,v 1.29 2013/11/23 13:35:36 christos Exp $  */
+/*     $NetBSD: vfs_trans.c,v 1.30 2014/04/15 09:50:45 hannken Exp $   */
 
 /*-
  * Copyright (c) 2007 The NetBSD Foundation, Inc.
@@ -30,7 +30,7 @@
  */
 
 #include <sys/cdefs.h>
-__KERNEL_RCSID(0, "$NetBSD: vfs_trans.c,v 1.29 2013/11/23 13:35:36 christos Exp $");
+__KERNEL_RCSID(0, "$NetBSD: vfs_trans.c,v 1.30 2014/04/15 09:50:45 hannken Exp $");
 
 /*
  * File system transaction operations.
@@ -82,7 +82,6 @@
 static pserialize_t fstrans_psz;       /* Pserialize state. */
 static LIST_HEAD(fstrans_lwp_head, fstrans_lwp_info) fstrans_fli_head;
                                        /* List of all fstrans_lwp_info. */
-static pool_cache_t fstrans_cache;     /* Pool of struct fstrans_lwp_info. */
 
 static void fstrans_lwp_dtor(void *);
 static void fstrans_mount_dtor(struct mount *);
@@ -110,8 +109,6 @@
        cv_init(&fstrans_count_cv, "fstcnt");
        fstrans_psz = pserialize_create();
        LIST_INIT(&fstrans_fli_head);
-       fstrans_cache = pool_cache_init(sizeof(struct fstrans_lwp_info), 0, 0,
-           0, "fstrans", NULL, IPL_NONE, NULL, NULL, NULL);
 }
 
 /*
@@ -122,17 +119,16 @@
 {
        struct fstrans_lwp_info *fli, *fli_next;
 
-       mutex_enter(&fstrans_lock);
        for (fli = arg; fli; fli = fli_next) {
                KASSERT(fli->fli_trans_cnt == 0);
                KASSERT(fli->fli_cow_cnt == 0);
                if (fli->fli_mount != NULL)
                        fstrans_mount_dtor(fli->fli_mount);
                fli_next = fli->fli_succ;
-               LIST_REMOVE(fli, fli_list);
-               pool_cache_put(fstrans_cache, fli);
+               fli->fli_mount = NULL;
+               membar_sync();
+               fli->fli_self = NULL;
        }
-       mutex_exit(&fstrans_lock);
 }
 
 /*
@@ -237,7 +233,21 @@
                }
        }
        if (fli == NULL) {
-               fli = pool_cache_get(fstrans_cache, PR_WAITOK);
+               mutex_enter(&fstrans_lock);
+               LIST_FOREACH(fli, &fstrans_fli_head, fli_list) {
+                       if (fli->fli_self == NULL) {
+                               KASSERT(fli->fli_trans_cnt == 0);
+                               KASSERT(fli->fli_cow_cnt == 0);
+                               fli->fli_self = curlwp;
+                               fli->fli_succ = lwp_getspecific(lwp_data_key);
+                               lwp_setspecific(lwp_data_key, fli);
+                               break;
+                       }
+               }
+               mutex_exit(&fstrans_lock);
+       }
+       if (fli == NULL) {
+               fli = kmem_alloc(sizeof(*fli), KM_SLEEP);
                mutex_enter(&fstrans_lock);
                memset(fli, 0, sizeof(*fli));
                fli->fli_self = curlwp;



Home | Main Index | Thread Index | Old Index