Module Name: src Committed By: hannken Date: Tue Apr 15 09:50:45 UTC 2014
Modified Files: src/sys/kern: vfs_trans.c Log Message: 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. To generate a diff of this commit: cvs rdiff -u -r1.29 -r1.30 src/sys/kern/vfs_trans.c Please note that diffs are not public domain; they are subject to the copyright notices on the relevant files.
Modified files: Index: src/sys/kern/vfs_trans.c diff -u src/sys/kern/vfs_trans.c:1.29 src/sys/kern/vfs_trans.c:1.30 --- src/sys/kern/vfs_trans.c:1.29 Sat Nov 23 13:35:36 2013 +++ src/sys/kern/vfs_trans.c Tue Apr 15 09:50:45 2014 @@ -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 kcondvar_t fstrans_count_cv; /* F 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 @@ fstrans_init(void) 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 @@ fstrans_lwp_dtor(void *arg) { 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 @@ fstrans_get_lwp_info(struct mount *mp, b } } 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;