Date: Sun, 3 May 2009 17:51:38 +0000 (UTC) From: Konstantin Belousov <kib@FreeBSD.org> To: src-committers@freebsd.org, svn-src-all@freebsd.org, svn-src-stable@freebsd.org, svn-src-stable-7@freebsd.org Subject: svn commit: r191767 - in stable/7/lib/libc: . stdlib string Message-ID: <200905031751.n43HpcGV020175@svn.freebsd.org>
next in thread | raw e-mail | index | archive | help
Author: kib Date: Sun May 3 17:51:38 2009 New Revision: 191767 URL: http://svn.freebsd.org/changeset/base/191767 Log: MFC r185514 (by jasone): Fix a lock order reversal bug that could cause deadlock during fork(2). Reported and tested by: makc Approved by: re (kensmith) Modified: stable/7/lib/libc/ (props changed) stable/7/lib/libc/stdlib/malloc.c stable/7/lib/libc/string/ffsll.c (props changed) stable/7/lib/libc/string/flsll.c (props changed) Modified: stable/7/lib/libc/stdlib/malloc.c ============================================================================== --- stable/7/lib/libc/stdlib/malloc.c Sun May 3 17:47:21 2009 (r191766) +++ stable/7/lib/libc/stdlib/malloc.c Sun May 3 17:51:38 2009 (r191767) @@ -4715,16 +4715,41 @@ _malloc_thread_cleanup(void) void _malloc_prefork(void) { - unsigned i; + bool again; + unsigned i, j; + arena_t *larenas[narenas], *tarenas[narenas]; /* Acquire all mutexes in a safe order. */ - malloc_spin_lock(&arenas_lock); - for (i = 0; i < narenas; i++) { - if (arenas[i] != NULL) - malloc_spin_lock(&arenas[i]->lock); - } - malloc_spin_unlock(&arenas_lock); + /* + * arenas_lock must be acquired after all of the arena mutexes, in + * order to avoid potential deadlock with arena_lock_balance[_hard](). + * Since arenas_lock protects the arenas array, the following code has + * to race with arenas_extend() callers until it succeeds in locking + * all arenas before locking arenas_lock. + */ + memset(larenas, 0, sizeof(arena_t *) * narenas); + do { + again = false; + + malloc_spin_lock(&arenas_lock); + for (i = 0; i < narenas; i++) { + if (arenas[i] != larenas[i]) { + memcpy(tarenas, arenas, sizeof(arena_t *) * + narenas); + malloc_spin_unlock(&arenas_lock); + for (j = 0; j < narenas; j++) { + if (larenas[j] != tarenas[j]) { + larenas[j] = tarenas[j]; + malloc_spin_lock( + &larenas[j]->lock); + } + } + again = true; + break; + } + } + } while (again); malloc_mutex_lock(&base_mtx); @@ -4739,6 +4764,7 @@ void _malloc_postfork(void) { unsigned i; + arena_t *larenas[narenas]; /* Release all mutexes, now that fork() has completed. */ @@ -4750,12 +4776,12 @@ _malloc_postfork(void) malloc_mutex_unlock(&base_mtx); - malloc_spin_lock(&arenas_lock); + memcpy(larenas, arenas, sizeof(arena_t *) * narenas); + malloc_spin_unlock(&arenas_lock); for (i = 0; i < narenas; i++) { - if (arenas[i] != NULL) - malloc_spin_unlock(&arenas[i]->lock); + if (larenas[i] != NULL) + malloc_spin_unlock(&larenas[i]->lock); } - malloc_spin_unlock(&arenas_lock); } /*
Want to link to this message? Use this URL: <https://mail-archive.FreeBSD.org/cgi/mid.cgi?200905031751.n43HpcGV020175>