From 4442c0b2c92e4b2e88661e15022228c5f6547112 Mon Sep 17 00:00:00 2001 From: Rusty Russell Date: Fri, 23 Mar 2012 10:45:18 +1030 Subject: lib/tdb: fix transaction issue for HAVE_INCOHERENT_MMAP. We unmap the tdb on expand, the remap. But when we have INCOHERENT_MMAP (ie. OpenBSD) and we're inside a transaction, doing the expand can mean we need to read from the database to partially fill a transaction block. This fails, because if mmap is incoherent we never allow accessing the database via read/write. The solution is not to unmap and remap until we've actually written the padding at the end of the file. Reported-by: Amitay Isaacs Signed-off-by: Rusty Russell Autobuild-User: Rusty Russell Autobuild-Date: Fri Mar 23 02:53:15 CET 2012 on sn-devel-104 --- lib/tdb/common/io.c | 21 ++++++++++----------- 1 file changed, 10 insertions(+), 11 deletions(-) (limited to 'lib') diff --git a/lib/tdb/common/io.c b/lib/tdb/common/io.c index be5a9ca5b2..3131f4fa0a 100644 --- a/lib/tdb/common/io.c +++ b/lib/tdb/common/io.c @@ -381,37 +381,36 @@ int tdb_expand(struct tdb_context *tdb, tdb_off_t size) size = tdb_expand_adjust(tdb->map_size, size, tdb->page_size); - if (!(tdb->flags & TDB_INTERNAL)) - tdb_munmap(tdb); - /* expand the file itself */ if (!(tdb->flags & TDB_INTERNAL)) { if (tdb->methods->tdb_expand_file(tdb, tdb->map_size, size) != 0) goto fail; } - tdb->map_size += size; + /* form a new freelist record */ + offset = tdb->map_size; + memset(&rec,'\0',sizeof(rec)); + rec.rec_len = size - sizeof(rec); if (tdb->flags & TDB_INTERNAL) { char *new_map_ptr = (char *)realloc(tdb->map_ptr, - tdb->map_size); + tdb->map_size + size); if (!new_map_ptr) { - tdb->map_size -= size; goto fail; } tdb->map_ptr = new_map_ptr; + tdb->map_size += size; } else { + /* Explicitly remap: if we're in a transaction, this won't + * happen automatically! */ + tdb_munmap(tdb); + tdb->map_size += size; if (tdb_mmap(tdb) != 0) { goto fail; } } - /* form a new freelist record */ - memset(&rec,'\0',sizeof(rec)); - rec.rec_len = size - sizeof(rec); - /* link it into the free list */ - offset = tdb->map_size - size; if (tdb_free(tdb, offset, &rec) == -1) goto fail; -- cgit