[rpm] - serialize BDB environment open/close (#924417)
Panu Matilainen
pmatilai at fedoraproject.org
Tue May 28 06:39:14 UTC 2013
commit e033e9868a2effd40d8c883080a1d4198820090b
Author: Panu Matilainen <pmatilai at redhat.com>
Date: Tue May 28 09:38:53 2013 +0300
- serialize BDB environment open/close (#924417)
rpm-4.11.x-dbenv-serialize.patch | 138 ++++++++++++++++++++++++++++++++++++++
rpm.spec | 8 ++-
2 files changed, 145 insertions(+), 1 deletions(-)
---
diff --git a/rpm-4.11.x-dbenv-serialize.patch b/rpm-4.11.x-dbenv-serialize.patch
new file mode 100644
index 0000000..4db97d7
--- /dev/null
+++ b/rpm-4.11.x-dbenv-serialize.patch
@@ -0,0 +1,138 @@
+commit e7d5980e2a7b091d973171144de04397204ebcd7
+Author: Panu Matilainen <pmatilai at redhat.com>
+Date: Tue May 28 08:56:22 2013 +0300
+
+ Serialize BDB environment open/close (RhBug:924417 etc)
+
+ - Introduce Yet Another Broken Lock[*] to serialize BDB environment open:
+ otherwise we can end up calling dbenv->failchk() while another process
+ is just joining the environment, leading to transient "Thread died in..."
+ DB_RUNRECOVER errors. Also prevents races on chrooted operations where
+ we remove the entire environment on close.
+ - This should also make it possible to handle at least some cases of
+ real DB_RUNRECOVER errors by just nuking the environment but that's
+ another topic...
+
+ [*] YABL as this is nowhere near foolproof or sufficient for all
+ the possible variants, but better than not having it...
+ (cherry picked from commit ad874d60e3804f1bcd64f3510e1e2dfbf81456cd)
+
+diff --git a/lib/backend/db3.c b/lib/backend/db3.c
+index de8071b..9d385c6 100644
+--- a/lib/backend/db3.c
++++ b/lib/backend/db3.c
+@@ -57,10 +57,42 @@ static uint32_t db_envflags(DB * db)
+ return eflags;
+ }
+
++/*
++ * Try to acquire db environment open/close serialization lock.
++ * Return the open, locked fd on success, -1 on failure.
++ */
++static int serialize_env(const char *dbhome)
++{
++ char *lock_path = rstrscat(NULL, dbhome, "/.dbenv.lock", NULL);
++ mode_t oldmask = umask(022);
++ int fd = open(lock_path, (O_RDWR|O_CREAT), 0644);
++ umask(oldmask);
++
++ if (fd >= 0) {
++ int rc;
++ struct flock info;
++ memset(&info, 0, sizeof(info));
++ info.l_type = F_WRLCK;
++ info.l_whence = SEEK_SET;
++ do {
++ rc = fcntl(fd, F_SETLKW, &info);
++ } while (rc == -1 && errno == EINTR);
++
++ if (rc == -1) {
++ close(fd);
++ fd = -1;
++ }
++ }
++
++ free(lock_path);
++ return fd;
++}
++
+ static int db_fini(rpmdb rdb, const char * dbhome)
+ {
+ DB_ENV * dbenv = rdb->db_dbenv;
+ int rc;
++ int lockfd = -1;
+ uint32_t eflags = 0;
+
+ if (dbenv == NULL)
+@@ -72,6 +104,9 @@ static int db_fini(rpmdb rdb, const char * dbhome)
+ }
+
+ (void) dbenv->get_open_flags(dbenv, &eflags);
++ if (!(eflags & DB_PRIVATE))
++ lockfd = serialize_env(dbhome);
++
+ rc = dbenv->close(dbenv, 0);
+ rc = dbapi_err(rdb, "dbenv->close", rc, _debug);
+
+@@ -89,6 +124,10 @@ static int db_fini(rpmdb rdb, const char * dbhome)
+ rpmlog(RPMLOG_DEBUG, "removed db environment %s\n", dbhome);
+
+ }
++
++ if (lockfd >= 0)
++ close(lockfd);
++
+ return rc;
+ }
+
+@@ -122,6 +161,7 @@ static int db_init(rpmdb rdb, const char * dbhome)
+ DB_ENV *dbenv = NULL;
+ int rc, xx;
+ int retry_open = 2;
++ int lockfd = -1;
+ struct dbConfig_s * cfg = &rdb->cfg;
+ /* This is our setup, thou shall not have other setups before us */
+ uint32_t eflags = (DB_CREATE|DB_INIT_MPOOL|DB_INIT_CDB);
+@@ -176,6 +216,24 @@ static int db_init(rpmdb rdb, const char * dbhome)
+ }
+
+ /*
++ * Serialize shared environment open (and clock) via fcntl() lock.
++ * Otherwise we can end up calling dbenv->failchk() while another
++ * process is joining the environment, leading to transient
++ * DB_RUNRECOVER errors. Also prevents races wrt removing the
++ * environment (eg chrooted operation). Silently fall back to
++ * private environment on failure to allow non-privileged queries
++ * to "work", broken as it might be.
++ */
++ if (!(eflags & DB_PRIVATE)) {
++ lockfd = serialize_env(dbhome);
++ if (lockfd < 0) {
++ eflags |= DB_PRIVATE;
++ retry_open--;
++ rpmlog(RPMLOG_DEBUG, "serialize failed, using private dbenv\n");
++ }
++ }
++
++ /*
+ * Actually open the environment. Fall back to private environment
+ * if we dont have permission to join/create shared environment or
+ * system doesn't support it..
+@@ -208,6 +266,8 @@ static int db_init(rpmdb rdb, const char * dbhome)
+ rdb->db_dbenv = dbenv;
+ rdb->db_opens = 1;
+
++ if (lockfd >= 0)
++ close(lockfd);
+ return 0;
+
+ errxit:
+@@ -216,6 +276,8 @@ errxit:
+ xx = dbenv->close(dbenv, 0);
+ xx = dbapi_err(rdb, "dbenv->close", xx, _debug);
+ }
++ if (lockfd >= 0)
++ close(lockfd);
+ return rc;
+ }
+
diff --git a/rpm.spec b/rpm.spec
index 64ff0bc..b02e476 100644
--- a/rpm.spec
+++ b/rpm.spec
@@ -21,7 +21,7 @@
Summary: The RPM package management system
Name: rpm
Version: %{rpmver}
-Release: %{?snapver:0.%{snapver}.}6%{?dist}
+Release: %{?snapver:0.%{snapver}.}7%{?dist}
Group: System Environment/Base
Url: http://www.rpm.org/
Source0: http://rpm.org/releases/testing/%{name}-%{srcver}.tar.bz2
@@ -53,6 +53,8 @@ Patch101: rpm-4.11.x-cursor-failchk.patch
Patch102: rpm-4.11.x-filter-soname-deps.patch
# Stricter perllib classification
Patch103: rpm-4.11.x-perllib-attr.patch
+# Serialize BDB environment open+close
+Patch104: rpm-4.11.x-dbenv-serialize.patch
# These are not yet upstream
Patch301: rpm-4.6.0-niagara.patch
@@ -235,6 +237,7 @@ packages on a system.
%patch101 -p1 -b .cursor-failchk
%patch102 -p1 -b .filter-soname-deps
%patch103 -p1 -b .perllib-attr
+%patch104 -p1 -b .dbenv-serialize
%patch301 -p1 -b .niagara
%patch302 -p1 -b .geode
@@ -468,6 +471,9 @@ exit 0
%doc COPYING doc/librpm/html/*
%changelog
+* Tue May 28 2013 Panu Matilainen <pmatilai at redhat.com> - - 4.11.0.1-7
+- serialize BDB environment open/close (#924417)
+
* Wed May 22 2013 Panu Matilainen <pmatilai at redhat.com> - - 4.11.0.1-6
- only consider files with .pm suffix as perl modules (#927211)
More information about the scm-commits
mailing list