|
Panu Matilainen |
e033e9 |
commit e7d5980e2a7b091d973171144de04397204ebcd7
|
|
Panu Matilainen |
e033e9 |
Author: Panu Matilainen <pmatilai@redhat.com>
|
|
Panu Matilainen |
e033e9 |
Date: Tue May 28 08:56:22 2013 +0300
|
|
Panu Matilainen |
e033e9 |
|
|
Panu Matilainen |
e033e9 |
Serialize BDB environment open/close (RhBug:924417 etc)
|
|
Panu Matilainen |
e033e9 |
|
|
Panu Matilainen |
e033e9 |
- Introduce Yet Another Broken Lock[*] to serialize BDB environment open:
|
|
Panu Matilainen |
e033e9 |
otherwise we can end up calling dbenv->failchk() while another process
|
|
Panu Matilainen |
e033e9 |
is just joining the environment, leading to transient "Thread died in..."
|
|
Panu Matilainen |
e033e9 |
DB_RUNRECOVER errors. Also prevents races on chrooted operations where
|
|
Panu Matilainen |
e033e9 |
we remove the entire environment on close.
|
|
Panu Matilainen |
e033e9 |
- This should also make it possible to handle at least some cases of
|
|
Panu Matilainen |
e033e9 |
real DB_RUNRECOVER errors by just nuking the environment but that's
|
|
Panu Matilainen |
e033e9 |
another topic...
|
|
Panu Matilainen |
e033e9 |
|
|
Panu Matilainen |
e033e9 |
[*] YABL as this is nowhere near foolproof or sufficient for all
|
|
Panu Matilainen |
e033e9 |
the possible variants, but better than not having it...
|
|
Panu Matilainen |
e033e9 |
(cherry picked from commit ad874d60e3804f1bcd64f3510e1e2dfbf81456cd)
|
|
Panu Matilainen |
e033e9 |
|
|
Panu Matilainen |
e033e9 |
diff --git a/lib/backend/db3.c b/lib/backend/db3.c
|
|
Panu Matilainen |
e033e9 |
index de8071b..9d385c6 100644
|
|
Panu Matilainen |
e033e9 |
--- a/lib/backend/db3.c
|
|
Panu Matilainen |
e033e9 |
+++ b/lib/backend/db3.c
|
|
Panu Matilainen |
e033e9 |
@@ -57,10 +57,42 @@ static uint32_t db_envflags(DB * db)
|
|
Panu Matilainen |
e033e9 |
return eflags;
|
|
Panu Matilainen |
e033e9 |
}
|
|
Panu Matilainen |
e033e9 |
|
|
Panu Matilainen |
e033e9 |
+/*
|
|
Panu Matilainen |
e033e9 |
+ * Try to acquire db environment open/close serialization lock.
|
|
Panu Matilainen |
e033e9 |
+ * Return the open, locked fd on success, -1 on failure.
|
|
Panu Matilainen |
e033e9 |
+ */
|
|
Panu Matilainen |
e033e9 |
+static int serialize_env(const char *dbhome)
|
|
Panu Matilainen |
e033e9 |
+{
|
|
Panu Matilainen |
e033e9 |
+ char *lock_path = rstrscat(NULL, dbhome, "/.dbenv.lock", NULL);
|
|
Panu Matilainen |
e033e9 |
+ mode_t oldmask = umask(022);
|
|
Panu Matilainen |
e033e9 |
+ int fd = open(lock_path, (O_RDWR|O_CREAT), 0644);
|
|
Panu Matilainen |
e033e9 |
+ umask(oldmask);
|
|
Panu Matilainen |
e033e9 |
+
|
|
Panu Matilainen |
e033e9 |
+ if (fd >= 0) {
|
|
Panu Matilainen |
e033e9 |
+ int rc;
|
|
Panu Matilainen |
e033e9 |
+ struct flock info;
|
|
Panu Matilainen |
e033e9 |
+ memset(&info, 0, sizeof(info));
|
|
Panu Matilainen |
e033e9 |
+ info.l_type = F_WRLCK;
|
|
Panu Matilainen |
e033e9 |
+ info.l_whence = SEEK_SET;
|
|
Panu Matilainen |
e033e9 |
+ do {
|
|
Panu Matilainen |
e033e9 |
+ rc = fcntl(fd, F_SETLKW, &info;;
|
|
Panu Matilainen |
e033e9 |
+ } while (rc == -1 && errno == EINTR);
|
|
Panu Matilainen |
e033e9 |
+
|
|
Panu Matilainen |
e033e9 |
+ if (rc == -1) {
|
|
Panu Matilainen |
e033e9 |
+ close(fd);
|
|
Panu Matilainen |
e033e9 |
+ fd = -1;
|
|
Panu Matilainen |
e033e9 |
+ }
|
|
Panu Matilainen |
e033e9 |
+ }
|
|
Panu Matilainen |
e033e9 |
+
|
|
Panu Matilainen |
e033e9 |
+ free(lock_path);
|
|
Panu Matilainen |
e033e9 |
+ return fd;
|
|
Panu Matilainen |
e033e9 |
+}
|
|
Panu Matilainen |
e033e9 |
+
|
|
Panu Matilainen |
e033e9 |
static int db_fini(rpmdb rdb, const char * dbhome)
|
|
Panu Matilainen |
e033e9 |
{
|
|
Panu Matilainen |
e033e9 |
DB_ENV * dbenv = rdb->db_dbenv;
|
|
Panu Matilainen |
e033e9 |
int rc;
|
|
Panu Matilainen |
e033e9 |
+ int lockfd = -1;
|
|
Panu Matilainen |
e033e9 |
uint32_t eflags = 0;
|
|
Panu Matilainen |
e033e9 |
|
|
Panu Matilainen |
e033e9 |
if (dbenv == NULL)
|
|
Panu Matilainen |
e033e9 |
@@ -72,6 +104,9 @@ static int db_fini(rpmdb rdb, const char * dbhome)
|
|
Panu Matilainen |
e033e9 |
}
|
|
Panu Matilainen |
e033e9 |
|
|
Panu Matilainen |
e033e9 |
(void) dbenv->get_open_flags(dbenv, &eflags);
|
|
Panu Matilainen |
e033e9 |
+ if (!(eflags & DB_PRIVATE))
|
|
Panu Matilainen |
e033e9 |
+ lockfd = serialize_env(dbhome);
|
|
Panu Matilainen |
e033e9 |
+
|
|
Panu Matilainen |
e033e9 |
rc = dbenv->close(dbenv, 0);
|
|
Panu Matilainen |
e033e9 |
rc = dbapi_err(rdb, "dbenv->close", rc, _debug);
|
|
Panu Matilainen |
e033e9 |
|
|
Panu Matilainen |
e033e9 |
@@ -89,6 +124,10 @@ static int db_fini(rpmdb rdb, const char * dbhome)
|
|
Panu Matilainen |
e033e9 |
rpmlog(RPMLOG_DEBUG, "removed db environment %s\n", dbhome);
|
|
Panu Matilainen |
e033e9 |
|
|
Panu Matilainen |
e033e9 |
}
|
|
Panu Matilainen |
e033e9 |
+
|
|
Panu Matilainen |
e033e9 |
+ if (lockfd >= 0)
|
|
Panu Matilainen |
e033e9 |
+ close(lockfd);
|
|
Panu Matilainen |
e033e9 |
+
|
|
Panu Matilainen |
e033e9 |
return rc;
|
|
Panu Matilainen |
e033e9 |
}
|
|
Panu Matilainen |
e033e9 |
|
|
Panu Matilainen |
e033e9 |
@@ -122,6 +161,7 @@ static int db_init(rpmdb rdb, const char * dbhome)
|
|
Panu Matilainen |
e033e9 |
DB_ENV *dbenv = NULL;
|
|
Panu Matilainen |
e033e9 |
int rc, xx;
|
|
Panu Matilainen |
e033e9 |
int retry_open = 2;
|
|
Panu Matilainen |
e033e9 |
+ int lockfd = -1;
|
|
Panu Matilainen |
e033e9 |
struct dbConfig_s * cfg = &rdb->cfg;
|
|
Panu Matilainen |
e033e9 |
/* This is our setup, thou shall not have other setups before us */
|
|
Panu Matilainen |
e033e9 |
uint32_t eflags = (DB_CREATE|DB_INIT_MPOOL|DB_INIT_CDB);
|
|
Panu Matilainen |
e033e9 |
@@ -176,6 +216,24 @@ static int db_init(rpmdb rdb, const char * dbhome)
|
|
Panu Matilainen |
e033e9 |
}
|
|
Panu Matilainen |
e033e9 |
|
|
Panu Matilainen |
e033e9 |
/*
|
|
Panu Matilainen |
e033e9 |
+ * Serialize shared environment open (and clock) via fcntl() lock.
|
|
Panu Matilainen |
e033e9 |
+ * Otherwise we can end up calling dbenv->failchk() while another
|
|
Panu Matilainen |
e033e9 |
+ * process is joining the environment, leading to transient
|
|
Panu Matilainen |
e033e9 |
+ * DB_RUNRECOVER errors. Also prevents races wrt removing the
|
|
Panu Matilainen |
e033e9 |
+ * environment (eg chrooted operation). Silently fall back to
|
|
Panu Matilainen |
e033e9 |
+ * private environment on failure to allow non-privileged queries
|
|
Panu Matilainen |
e033e9 |
+ * to "work", broken as it might be.
|
|
Panu Matilainen |
e033e9 |
+ */
|
|
Panu Matilainen |
e033e9 |
+ if (!(eflags & DB_PRIVATE)) {
|
|
Panu Matilainen |
e033e9 |
+ lockfd = serialize_env(dbhome);
|
|
Panu Matilainen |
e033e9 |
+ if (lockfd < 0) {
|
|
Panu Matilainen |
e033e9 |
+ eflags |= DB_PRIVATE;
|
|
Panu Matilainen |
e033e9 |
+ retry_open--;
|
|
Panu Matilainen |
e033e9 |
+ rpmlog(RPMLOG_DEBUG, "serialize failed, using private dbenv\n");
|
|
Panu Matilainen |
e033e9 |
+ }
|
|
Panu Matilainen |
e033e9 |
+ }
|
|
Panu Matilainen |
e033e9 |
+
|
|
Panu Matilainen |
e033e9 |
+ /*
|
|
Panu Matilainen |
e033e9 |
* Actually open the environment. Fall back to private environment
|
|
Panu Matilainen |
e033e9 |
* if we dont have permission to join/create shared environment or
|
|
Panu Matilainen |
e033e9 |
* system doesn't support it..
|
|
Panu Matilainen |
e033e9 |
@@ -208,6 +266,8 @@ static int db_init(rpmdb rdb, const char * dbhome)
|
|
Panu Matilainen |
e033e9 |
rdb->db_dbenv = dbenv;
|
|
Panu Matilainen |
e033e9 |
rdb->db_opens = 1;
|
|
Panu Matilainen |
e033e9 |
|
|
Panu Matilainen |
e033e9 |
+ if (lockfd >= 0)
|
|
Panu Matilainen |
e033e9 |
+ close(lockfd);
|
|
Panu Matilainen |
e033e9 |
return 0;
|
|
Panu Matilainen |
e033e9 |
|
|
Panu Matilainen |
e033e9 |
errxit:
|
|
Panu Matilainen |
e033e9 |
@@ -216,6 +276,8 @@ errxit:
|
|
Panu Matilainen |
e033e9 |
xx = dbenv->close(dbenv, 0);
|
|
Panu Matilainen |
e033e9 |
xx = dbapi_err(rdb, "dbenv->close", xx, _debug);
|
|
Panu Matilainen |
e033e9 |
}
|
|
Panu Matilainen |
e033e9 |
+ if (lockfd >= 0)
|
|
Panu Matilainen |
e033e9 |
+ close(lockfd);
|
|
Panu Matilainen |
e033e9 |
return rc;
|
|
Panu Matilainen |
e033e9 |
}
|
|
Panu Matilainen |
e033e9 |
|