Commit f6900d23 authored by Rusty Russell's avatar Rusty Russell

tdb2: check pid before unlock.

The original code assumed that unlocking would fail if we didn't have a lock;
this isn't true (at least, on my machine).  So we have to always check the
pid before unlocking.
parent 18fe5ef0
...@@ -37,7 +37,7 @@ static enum TDB_ERROR owner_conflict(struct tdb_context *tdb, const char *call) ...@@ -37,7 +37,7 @@ static enum TDB_ERROR owner_conflict(struct tdb_context *tdb, const char *call)
call); call);
} }
/* If we fork, we no longer really own locks: preserves errno */ /* If we fork, we no longer really own locks. */
static bool check_lock_pid(struct tdb_context *tdb, static bool check_lock_pid(struct tdb_context *tdb,
const char *call, bool log) const char *call, bool log)
{ {
...@@ -224,16 +224,14 @@ static enum TDB_ERROR tdb_brlock(struct tdb_context *tdb, ...@@ -224,16 +224,14 @@ static enum TDB_ERROR tdb_brlock(struct tdb_context *tdb,
static enum TDB_ERROR tdb_brunlock(struct tdb_context *tdb, static enum TDB_ERROR tdb_brunlock(struct tdb_context *tdb,
int rw_type, tdb_off_t offset, size_t len) int rw_type, tdb_off_t offset, size_t len)
{ {
int ret;
if (tdb->flags & TDB_NOLOCK) { if (tdb->flags & TDB_NOLOCK) {
return TDB_SUCCESS; return TDB_SUCCESS;
} }
ret = unlock(tdb, rw_type, offset, len); if (!check_lock_pid(tdb, "tdb_brunlock", true))
return TDB_ERR_LOCK;
/* If we fail, *then* we verify that we owned the lock. If not, ok. */ if (unlock(tdb, rw_type, offset, len) == -1) {
if (ret == -1 && check_lock_pid(tdb, "tdb_brunlock", false)) {
return tdb_logerr(tdb, TDB_ERR_LOCK, TDB_LOG_ERROR, return tdb_logerr(tdb, TDB_ERR_LOCK, TDB_LOG_ERROR,
"tdb_brunlock failed (fd=%d) at offset %zu" "tdb_brunlock failed (fd=%d) at offset %zu"
" rw_type=%d len=%zu: %s", " rw_type=%d len=%zu: %s",
...@@ -851,6 +849,10 @@ void tdb_lock_cleanup(struct tdb_context *tdb) ...@@ -851,6 +849,10 @@ void tdb_lock_cleanup(struct tdb_context *tdb)
{ {
unsigned int i; unsigned int i;
/* We don't want to warn: they're allowed to close tdb after fork. */
if (!check_lock_pid(tdb, "tdb_close", false))
return;
while (tdb->file->allrecord_lock.count while (tdb->file->allrecord_lock.count
&& tdb->file->allrecord_lock.owner == tdb) { && tdb->file->allrecord_lock.owner == tdb) {
tdb_allrecord_unlock(tdb, tdb->file->allrecord_lock.ltype); tdb_allrecord_unlock(tdb, tdb->file->allrecord_lock.ltype);
......
...@@ -85,10 +85,10 @@ int main(int argc, char *argv[]) ...@@ -85,10 +85,10 @@ int main(int argc, char *argv[])
return 2; return 2;
tdb_chainunlock(tdb, key); tdb_chainunlock(tdb, key);
if (tap_log_messages != 2) if (tap_log_messages != 3)
return 3; return 3;
tdb_close(tdb); tdb_close(tdb);
if (tap_log_messages != 2) if (tap_log_messages != 3)
return 4; return 4;
return 0; return 0;
} }
......
Markdown is supported
0%
or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment