diff options
-rw-r--r-- | lib/tdb/common/io.c | 49 | ||||
-rw-r--r-- | lib/tdb/common/open.c | 4 | ||||
-rw-r--r-- | lib/tdb/common/tdb_private.h | 2 | ||||
-rw-r--r-- | lib/tdb/test/run-3G-file.c | 27 |
4 files changed, 58 insertions, 24 deletions
diff --git a/lib/tdb/common/io.c b/lib/tdb/common/io.c index ac21e3f67a..24c2d615ab 100644 --- a/lib/tdb/common/io.c +++ b/lib/tdb/common/io.c @@ -88,8 +88,7 @@ static int tdb_oob(struct tdb_context *tdb, tdb_off_t off, tdb_len_t len, return -1; } tdb->map_size = st.st_size; - tdb_mmap(tdb); - return 0; + return tdb_mmap(tdb); } /* write a lump of data at a specified offset */ @@ -111,6 +110,10 @@ static int tdb_write(struct tdb_context *tdb, tdb_off_t off, if (tdb->map_ptr) { memcpy(off + (char *)tdb->map_ptr, buf, len); } else { +#ifdef HAVE_INCOHERENT_MMAP + tdb->ecode = TDB_ERR_IO; + return -1; +#else ssize_t written = pwrite(tdb->fd, buf, len, off); if ((written != (ssize_t)len) && (written != -1)) { /* try once more */ @@ -135,6 +138,7 @@ static int tdb_write(struct tdb_context *tdb, tdb_off_t off, len, off)); return -1; } +#endif } return 0; } @@ -160,6 +164,10 @@ static int tdb_read(struct tdb_context *tdb, tdb_off_t off, void *buf, if (tdb->map_ptr) { memcpy(buf, off + (char *)tdb->map_ptr, len); } else { +#ifdef HAVE_INCOHERENT_MMAP + tdb->ecode = TDB_ERR_IO; + return -1; +#else ssize_t ret = pread(tdb->fd, buf, len, off); if (ret != (ssize_t)len) { /* Ensure ecode is set for log fn. */ @@ -170,6 +178,7 @@ static int tdb_read(struct tdb_context *tdb, tdb_off_t off, void *buf, (int)tdb->map_size)); return -1; } +#endif } if (cv) { tdb_convert(buf, len); @@ -222,13 +231,23 @@ int tdb_munmap(struct tdb_context *tdb) return 0; } -void tdb_mmap(struct tdb_context *tdb) +/* If mmap isn't coherent, *everyone* must always mmap. */ +static bool should_mmap(const struct tdb_context *tdb) +{ +#ifdef HAVE_INCOHERENT_MMAP + return true; +#else + return !(tdb->flags & TDB_NOMMAP); +#endif +} + +int tdb_mmap(struct tdb_context *tdb) { if (tdb->flags & TDB_INTERNAL) return; #ifdef HAVE_MMAP - if (!(tdb->flags & TDB_NOMMAP)) { + if (should_mmap(tdb)) { tdb->map_ptr = mmap(NULL, tdb->map_size, PROT_READ|(tdb->read_only? 0:PROT_WRITE), MAP_SHARED|MAP_FILE, tdb->fd, 0); @@ -241,6 +260,10 @@ void tdb_mmap(struct tdb_context *tdb) tdb->map_ptr = NULL; TDB_LOG((tdb, TDB_DEBUG_WARNING, "tdb_mmap failed for size %d (%s)\n", tdb->map_size, strerror(errno))); +#ifdef HAVE_INCOHERENT_MMAP + tdb->ecode = TDB_ERR_IO; + return -1; +#endif } } else { tdb->map_ptr = NULL; @@ -248,6 +271,7 @@ void tdb_mmap(struct tdb_context *tdb) #else tdb->map_ptr = NULL; #endif + return 0; } /* expand a file. we prefer to use ftruncate, as that is what posix @@ -360,12 +384,6 @@ int tdb_expand(struct tdb_context *tdb, tdb_off_t size) if (!(tdb->flags & TDB_INTERNAL)) tdb_munmap(tdb); - /* - * We must ensure the file is unmapped before doing this - * to ensure consistency with systems like OpenBSD where - * writes and mmaps are not consistent. - */ - /* expand the file itself */ if (!(tdb->flags & TDB_INTERNAL)) { if (tdb->methods->tdb_expand_file(tdb, tdb->map_size, size) != 0) @@ -383,14 +401,9 @@ int tdb_expand(struct tdb_context *tdb, tdb_off_t size) } tdb->map_ptr = new_map_ptr; } else { - /* - * We must ensure the file is remapped before adding the space - * to ensure consistency with systems like OpenBSD where - * writes and mmaps are not consistent. - */ - - /* We're ok if the mmap fails as we'll fallback to read/write */ - tdb_mmap(tdb); + if (tdb_mmap(tdb) != 0) { + goto fail; + } } /* form a new freelist record */ diff --git a/lib/tdb/common/open.c b/lib/tdb/common/open.c index 2965ea77b5..8836f8442e 100644 --- a/lib/tdb/common/open.c +++ b/lib/tdb/common/open.c @@ -587,7 +587,9 @@ static int tdb_reopen_internal(struct tdb_context *tdb, bool active_lock) TDB_LOG((tdb, TDB_DEBUG_FATAL, "tdb_reopen: file dev/inode has changed!\n")); goto fail; } - tdb_mmap(tdb); + if (tdb_mmap(tdb) != 0) { + goto fail; + } #endif /* fake pread or pwrite */ /* We may still think we hold the active lock. */ diff --git a/lib/tdb/common/tdb_private.h b/lib/tdb/common/tdb_private.h index 9913284f3c..0441fb287f 100644 --- a/lib/tdb/common/tdb_private.h +++ b/lib/tdb/common/tdb_private.h @@ -222,7 +222,7 @@ struct tdb_context { internal prototypes */ int tdb_munmap(struct tdb_context *tdb); -void tdb_mmap(struct tdb_context *tdb); +int tdb_mmap(struct tdb_context *tdb); int tdb_lock(struct tdb_context *tdb, int list, int ltype); int tdb_lock_nonblock(struct tdb_context *tdb, int list, int ltype); int tdb_nest_lock(struct tdb_context *tdb, uint32_t offset, int ltype, diff --git a/lib/tdb/test/run-3G-file.c b/lib/tdb/test/run-3G-file.c index cc700c2676..3b4e45739a 100644 --- a/lib/tdb/test/run-3G-file.c +++ b/lib/tdb/test/run-3G-file.c @@ -70,6 +70,7 @@ int main(int argc, char *argv[]) uint32_t hash; tdb_off_t rec_ptr; struct tdb_record rec; + int ret; plan_tests(24); tdb = tdb_open_ex("run-36-file.tdb", 1024, TDB_CLEAR_IF_FIRST, @@ -78,15 +79,33 @@ int main(int argc, char *argv[]) ok1(tdb); tdb->methods = &large_io_methods; - /* Enlarge the file (internally multiplies by 2). */ - ok1(tdb_expand(tdb, 1500000000) == 0); - - /* Put an entry in, and check it. */ key.dsize = strlen("hi"); key.dptr = (void *)"hi"; orig_data.dsize = strlen("world"); orig_data.dptr = (void *)"world"; + /* Enlarge the file (internally multiplies by 2). */ + ret = tdb_expand(tdb, 1500000000); +#ifdef HAVE_INCOHERENT_MMAP + /* This can fail due to mmap failure on 32 bit systems. */ + if (ret == -1) { + /* These should now fail. */ + ok1(tdb_store(tdb, key, orig_data, TDB_INSERT) == -1); + data = tdb_fetch(tdb, key); + ok1(data.dptr == NULL); + ok1(tdb_traverse(tdb, test_traverse, &orig_data) == -1); + ok1(tdb_delete(tdb, key) == -1); + ok1(tdb_traverse(tdb, test_traverse, NULL) == -1); + /* Skip the rest... */ + for (ret = 0; ret < 24 - 6; ret++) + ok1(1); + tdb_close(tdb); + return exit_status(); + } +#endif + ok1(ret == 0); + + /* Put an entry in, and check it. */ ok1(tdb_store(tdb, key, orig_data, TDB_INSERT) == 0); data = tdb_fetch(tdb, key); |