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 +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 - - 4.11.0.1-7 +- serialize BDB environment open/close (#924417) + * Wed May 22 2013 Panu Matilainen - - 4.11.0.1-6 - only consider files with .pm suffix as perl modules (#927211)