1
0
mirror of https://git.FreeBSD.org/ports.git synced 2024-12-11 02:50:24 +00:00

databases/lmdb: in db_env_close0(), destroy robust mutexes if we are

the only remaining user.

When closing an lmdb database, all memory and file descriptor resources
are released, including the shared memory pages that contained the
robust mutex.

However, before this commit, prior to unmapping the pages that contained
the robust mutexex, lmdb did not destroy the mutexes first.  This would
create a problem when an application opens and closes a database, then
open it again.

According to libthr(3), by default, a shared lock backed by a mapped
file in memory is automatically destroyed on the last unmap of the
corresponding file' page, which is allowed by POSIX.

After unmapping the shared pages, the kernel writes off all active
robust mutexes associated with these pages.  However, the userland
threading library still keeps the record (pshared_lookup in
thr_pshared.c of libthr) for these objects as they are not really
destroyed before, so that it don't have to ask the kernel every
time when looking them up.

Now, a later re-open of the database might have mapped the lock file
to the same memory location.  Because the threading library have
remembered the robust mutex object, it would just reuse it even though
it was already invalid from kernel's point of view.  Unfortunately,
regular lock operations would still work for this process.

Should another lmdb process opens the same database, it would attempt
to obtain the robust mutex (no longer recognized by kernel) because it
would see another process holding a file lock, but that would fail
because the robust mutex is invalid for the kernel.

Explicitly destroy the mutex if we are the last remaining user to ensure
the mutex is always in a known defined state.

OpenLDAP ITS #9278

With debugging help from:	kib
PR:				244493
MFH:				2020Q2
This commit is contained in:
Xin LI 2020-06-16 21:51:55 +00:00
parent 5efda94307
commit 6c3f69c928
Notes: svn2git 2021-03-31 03:12:20 +00:00
svn path=/head/; revision=539379
2 changed files with 31 additions and 4 deletions

View File

@ -3,7 +3,7 @@
PORTNAME= lmdb
PORTVERSION= 0.9.24
PORTREVISION= 1
PORTREVISION= 2
DISTVERSIONPREFIX= ${PORTNAME:tu}_
PORTEPOCH= 1
CATEGORIES= databases

View File

@ -5,10 +5,37 @@
#endif
-#if defined(__APPLE__) || defined (BSD) || defined(__FreeBSD_kernel__)
+#if defined(__FreeBSD__)
+# define MDB_USE_POSIX_MUTEX 1
+# define MDB_USE_ROBUST 1
+#if defined(__FreeBSD__) && defined(__FreeBSD_version) && __FreeBSD_version >= 1100110
+# define MDB_USE_POSIX_MUTEX 1
+# define MDB_USE_ROBUST 1
+#elif defined(__APPLE__) || defined (BSD) || defined(__FreeBSD_kernel__)
# define MDB_USE_POSIX_SEM 1
# define MDB_FDATASYNC fsync
#elif defined(ANDROID)
@@ -1375,7 +1378,7 @@ static int mdb_page_split(MDB_cursor *mc, MDB_val *new
static int mdb_env_read_header(MDB_env *env, MDB_meta *meta);
static MDB_meta *mdb_env_pick_meta(const MDB_env *env);
static int mdb_env_write_meta(MDB_txn *txn);
-#ifdef MDB_USE_POSIX_MUTEX /* Drop unused excl arg */
+#if defined(MDB_USE_POSIX_MUTEX) && !defined(MDB_ROBUST_SUPPORTED) /* Drop unused excl arg */
# define mdb_env_close0(env, excl) mdb_env_close1(env)
#endif
static void mdb_env_close0(MDB_env *env, int excl);
@@ -5127,6 +5130,17 @@ mdb_env_close0(MDB_env *env, int excl)
sem_unlink(env->me_txns->mti_rmname);
sem_unlink(env->me_txns->mti_wmname);
}
+ }
+#elif defined(MDB_ROBUST_SUPPORTED)
+ /* If we have the filelock: If we are the
+ * only remaining user, clean up robust
+ * mutexes.
+ */
+ if (excl == 0)
+ mdb_env_excl_lock(env, &excl);
+ if (excl > 0) {
+ pthread_mutex_destroy(env->me_txns->mti_rmutex);
+ pthread_mutex_destroy(env->me_txns->mti_wmutex);
}
#endif
munmap((void *)env->me_txns, (env->me_maxreaders-1)*sizeof(MDB_reader)+sizeof(MDB_txninfo));