Try looking at libdb's env lock details via /proc/locks during env_attach
As flock-style locks have no way to check whether another lock on the file is held by the current process and is safe for libdb to access the its environment (in read-mode only), a helper function that parses /proc/locks for this information has been added. Additionally, db-5.3.28-rpm-lock-check.patch has been modified to use the helper function in order for libdb to not have to leak file descriptors while checking for rpm's transaction lock when accessing rpm's environment.
This commit is contained in:
parent
273921eda9
commit
3a3ae67b51
111
db-5.3.28-condition-variable-ppc.patch
Normal file
111
db-5.3.28-condition-variable-ppc.patch
Normal file
@ -0,0 +1,111 @@
|
||||
diff -up db-5.3.28/src/env/env_region.c.pthreads db-5.3.28/src/env/env_region.c
|
||||
--- db-5.3.28/src/env/env_region.c.pthreads 2017-06-19 08:48:19.362325045 +0200
|
||||
+++ db-5.3.28/src/env/env_region.c 2017-06-19 08:49:38.910773653 +0200
|
||||
@@ -305,15 +305,7 @@ user_map_functions:
|
||||
goto creation;
|
||||
}
|
||||
|
||||
- /* We have an old environment but cannot rebuild it safely. */
|
||||
- if (ret == DB_OLD_VERSION) {
|
||||
- __db_errx(env, DB_STR("1539",
|
||||
- "Build signature doesn't match environment"));
|
||||
- ret = DB_VERSION_MISMATCH;
|
||||
- goto err;
|
||||
- }
|
||||
-
|
||||
if (renv->majver != DB_VERSION_MAJOR ||
|
||||
renv->minver != DB_VERSION_MINOR) {
|
||||
/*
|
||||
* Special case a region that's all nul bytes, just treat it
|
||||
@@ -337,6 +329,20 @@ user_map_functions:
|
||||
goto err;
|
||||
}
|
||||
|
||||
+ /*
|
||||
+ * We have an old environment but cannot rebuild it safely.
|
||||
+ * The environment might still be readable by the current process
|
||||
+ * (only the libpthread timestamp changed) if this process is the one
|
||||
+ * that is holding the lock on the region file as we can be sure
|
||||
+ * the environment did not get rebuilt under our feet.
|
||||
+ */
|
||||
+ if (ret == DB_OLD_VERSION && __check_lock_fn(env->lockfhp->name, getpid()) ) {
|
||||
+ __db_errx(env, DB_STR("1539",
|
||||
+ "Build signature doesn't match environment"));
|
||||
+ ret = DB_VERSION_MISMATCH;
|
||||
+ goto err;
|
||||
+ }
|
||||
+
|
||||
/*
|
||||
* Check if the environment has had a catastrophic failure.
|
||||
*
|
||||
diff -up db-5.3.28/src/os/os_flock.c.pthreads db-5.3.28/src/os/os_flock.c
|
||||
--- db-5.3.28/src/os/os_flock.c.pthreads 2017-06-19 08:48:19.362325045 +0200
|
||||
+++ db-5.3.28/src/os/os_flock.c 2017-06-19 08:48:19.364325006 +0200
|
||||
@@ -15,6 +15,67 @@ static int __os_filelocking_notsup __P((
|
||||
#endif
|
||||
|
||||
/*
|
||||
+ * __check_lock_fn --
|
||||
+ * Parse /proc/locks to see if the file described by 'fn' is locked.
|
||||
+ * Additionally (if 'pid' is not 0) check if the process holding
|
||||
+ * the lock has the same pid value as 'pid'.
|
||||
+ *
|
||||
+ * Returns 0 if a lock on fn is found, 1 if it is not found and -1 on error.
|
||||
+ */
|
||||
+
|
||||
+int __check_lock_fn(fn, pid)
|
||||
+ char *fn;
|
||||
+ pid_t pid;
|
||||
+{
|
||||
+ FILE* fp;
|
||||
+ char buffer[PATH_MAX];
|
||||
+ char *token;
|
||||
+ int i, fd, inode;
|
||||
+ struct stat st;
|
||||
+ pid_t lpid = 0;
|
||||
+
|
||||
+ if (!fn)
|
||||
+ return -1;
|
||||
+
|
||||
+ fp = fopen("/proc/locks", "r");
|
||||
+ if (!fp)
|
||||
+ return -1;
|
||||
+
|
||||
+ /* Get the file's inode */
|
||||
+ if (stat(fn, &st))
|
||||
+ return -1;
|
||||
+
|
||||
+ while (fgets(buffer, sizeof(buffer), fp))
|
||||
+ for (token = strtok(buffer, " "), i = 0; token; token = strtok(NULL, " "), i++) {
|
||||
+ /* Do not parse any other fields */
|
||||
+ if (i > 5)
|
||||
+ break;
|
||||
+ /* Save the PID */
|
||||
+ if (i == 4)
|
||||
+ lpid = atoi(token);
|
||||
+ /* Check the inode */
|
||||
+ else if (i == 5) {
|
||||
+ inode = 0;
|
||||
+ sscanf(token, "%*02x:%*02x:%d", &inode);
|
||||
+ /* Not the inode we are looking for */
|
||||
+ if (inode != st.st_ino)
|
||||
+ continue;
|
||||
+ /*
|
||||
+ * We have the correct file.
|
||||
+ * We are either looking for a specific process or we do not care at all.
|
||||
+ */
|
||||
+ if (!pid || lpid == pid) {
|
||||
+ fclose(fp);
|
||||
+ return 0;
|
||||
+ }
|
||||
+ /* Not the lock we are looking for */
|
||||
+ }
|
||||
+ }
|
||||
+ fclose(fp);
|
||||
+ return 1;
|
||||
+}
|
||||
+
|
||||
+/*
|
||||
* __os_fdlock --
|
||||
* Acquire/release a lock on a byte in a file.
|
||||
*
|
@ -1,67 +1,73 @@
|
||||
diff -up db-5.3.28/src/env/env_region.c.rpmlock db-5.3.28/src/env/env_region.c
|
||||
--- db-5.3.28/src/env/env_region.c.rpmlock 2017-06-13 11:17:13.750899154 +0200
|
||||
+++ db-5.3.28/src/env/env_region.c 2017-06-13 11:18:22.221560122 +0200
|
||||
@@ -290,7 +290,8 @@ user_map_functions:
|
||||
|
||||
--- db-5.3.28/src/env/env_region.c.rpmlock 2017-06-19 09:53:42.727715374 +0200
|
||||
+++ db-5.3.28/src/env/env_region.c 2017-06-19 09:55:28.195688220 +0200
|
||||
@@ -291,18 +291,23 @@ user_map_functions:
|
||||
if (create_ok &&
|
||||
ret == DB_OLD_VERSION &&
|
||||
- ENV_PRIMARY_LOCK(env, DB_LOCK_WRITE, 1) == 0) {
|
||||
+ ENV_PRIMARY_LOCK(env, DB_LOCK_WRITE, 1) == 0 &&
|
||||
+ __rpm_lock_check(env) == 0) {
|
||||
if (FLD_ISSET(dbenv->verbose, DB_VERB_RECOVERY))
|
||||
__db_msg(env, "Recreating idle environment");
|
||||
F_SET(infop, REGION_CREATE_OK);
|
||||
ENV_PRIMARY_LOCK(env, DB_LOCK_WRITE, 1) == 0) {
|
||||
- if (FLD_ISSET(dbenv->verbose, DB_VERB_RECOVERY))
|
||||
- __db_msg(env, "Recreating idle environment");
|
||||
- F_SET(infop, REGION_CREATE_OK);
|
||||
+ /* If the rpm transaction lock is taken we cannot safely rebuild */
|
||||
+ if (!__rpm_lock_free(env))
|
||||
+ ENV_PRIMARY_UNLOCK(env);
|
||||
+ else {
|
||||
+ if (FLD_ISSET(dbenv->verbose, DB_VERB_RECOVERY))
|
||||
+ __db_msg(env, "Recreating idle environment");
|
||||
+ F_SET(infop, REGION_CREATE_OK);
|
||||
|
||||
- /*
|
||||
- * Detach from the environment region; we need to unmap it (and
|
||||
- * close any file handle) so that we don't leak memory or files.
|
||||
- */
|
||||
- DB_ASSERT(env, infop->rp == NULL);
|
||||
- infop->rp = &tregion;
|
||||
- (void)__env_sys_detach(env, infop, 0);
|
||||
- goto creation;
|
||||
+ /*
|
||||
+ * Detach from the environment region; we need to unmap it (and
|
||||
+ * close any file handle) so that we don't leak memory or files.
|
||||
+ */
|
||||
+ DB_ASSERT(env, infop->rp == NULL);
|
||||
+ infop->rp = &tregion;
|
||||
+ (void)__env_sys_detach(env, infop, 0);
|
||||
+ goto creation;
|
||||
+ }
|
||||
}
|
||||
|
||||
if (renv->majver != DB_VERSION_MAJOR ||
|
||||
diff -up db-5.3.28/src/os/os_flock.c.rpmlock db-5.3.28/src/os/os_flock.c
|
||||
--- db-5.3.28/src/os/os_flock.c.rpmlock 2017-06-13 11:17:13.748899193 +0200
|
||||
+++ db-5.3.28/src/os/os_flock.c 2017-06-13 11:17:13.750899154 +0200
|
||||
@@ -15,6 +15,53 @@ static int __os_filelocking_notsup __P((
|
||||
#endif
|
||||
--- db-5.3.28/src/os/os_flock.c.rpmlock 2017-06-19 09:52:49.418740004 +0200
|
||||
+++ db-5.3.28/src/os/os_flock.c 2017-06-19 09:53:16.428220866 +0200
|
||||
@@ -70,6 +70,34 @@ int __check_lock_fn(fn, pid)
|
||||
}
|
||||
|
||||
/*
|
||||
+ * __rpm_lock_check --
|
||||
+ * Try to acquire and release a lock used by rpm to see
|
||||
+ * if libdb is being updated and it is safe to access
|
||||
+ * its environment files.
|
||||
+ *
|
||||
+ * FIXME: This function leaks the file descriptor on purpose
|
||||
+ * so that rpm's transaction lock is not dropped due to
|
||||
+ * how fcntl locks interact with close(2).
|
||||
+ * __rpm_lock_free --
|
||||
+ * Try to look at a lock used by rpm to see if libdb is being
|
||||
+ * updated and it is safe to access its environment files.
|
||||
+ */
|
||||
+
|
||||
+#define RPM_PATH SHAREDSTATEDIR "/rpm"
|
||||
+#define RPMLOCK_PATH RPM_PATH "/.rpm.lock"
|
||||
+
|
||||
+int __rpm_lock_check(env)
|
||||
+int __rpm_lock_free(env)
|
||||
+ ENV *env;
|
||||
+{
|
||||
+#ifdef HAVE_FCNTL
|
||||
+ struct flock info;
|
||||
+ int fd;
|
||||
+ int ret;
|
||||
+
|
||||
+ if (strstr(env->db_home, RPM_PATH) == NULL)
|
||||
+ /* No need to check the transaction lock if not in rpm */
|
||||
+ return 0;
|
||||
+ if (strstr(env->db_home, RPM_PATH) == NULL)
|
||||
+ return 1;
|
||||
+
|
||||
+ fd = open(RPMLOCK_PATH, O_RDWR);
|
||||
+ if (fd == -1)
|
||||
+ /* Assume it is safe to rebuild if the lock file does not exist */
|
||||
+ if (access(RPMLOCK_PATH, F_OK) && errno == ENOENT)
|
||||
+ return 1;
|
||||
+ /* Try to get an exclusive lock on rpm's lock file */
|
||||
+ info.l_type = F_WRLCK;
|
||||
+ info.l_whence = SEEK_SET;
|
||||
+ info.l_start = 0;
|
||||
+ info.l_len = 0;
|
||||
+ info.l_pid = 0;
|
||||
+ /* We do not want to hold so just check if we can get it */
|
||||
+ if ((ret = fcntl(fd, F_GETLK, &info)) != -1 && info.l_type == F_UNLCK)
|
||||
+ /* Lock is not taken, the environment can be rebuilt */
|
||||
+ return 0;
|
||||
+ else
|
||||
+ return 1;
|
||||
+#else
|
||||
+ /* fcntl not supported, fail with error message */
|
||||
+ return __os_filelocking_notsup(env);
|
||||
+#endif
|
||||
+
|
||||
+ ret = __check_lock_fn(RPMLOCK_PATH, 0);
|
||||
+ /* __check_lock_fn can return -1 on failure - return 0 (taken) instead */
|
||||
+ return ret == -1 ? 0: ret;
|
||||
+
|
||||
+}
|
||||
+
|
||||
+/*
|
||||
|
@ -35,9 +35,11 @@ Patch29: db-5.3.28-lemon_hash.patch
|
||||
# upstream patch adding the ability to recreate libdb's environment on version mismatch
|
||||
# or when libpthread.so is modified (rhbz#1394862)
|
||||
Patch30: db-5.3.28-condition_variable.patch
|
||||
# downstream patch to check whether there is a rpm transaction going on when rpm's environment needs to be rebuilt
|
||||
# TODO: remove this patch as soon as we can afford to
|
||||
Patch31: db-5.3.28-rpm-lock-check.patch
|
||||
# additional changes to the upstream patch to address rhbz#1460003
|
||||
Patch31: db-5.3.28-condition-variable-ppc.patch
|
||||
# downstream patch that adds a check for rpm transaction lock in order to be able to update libdb
|
||||
# FIXME: remove when able
|
||||
Patch32: db-5.3.28-rpm-lock-check.patch
|
||||
|
||||
URL: http://www.oracle.com/database/berkeley-db/
|
||||
License: BSD and LGPLv2 and Sleepycat
|
||||
@ -232,6 +234,7 @@ popd
|
||||
%patch29 -p1
|
||||
%patch30 -p1
|
||||
%patch31 -p1
|
||||
%patch32 -p1
|
||||
|
||||
cd dist
|
||||
./s_config
|
||||
|
Loading…
Reference in New Issue
Block a user