summaryrefslogtreecommitdiff
path: root/lib/tdb/common/io.c
diff options
context:
space:
mode:
authorRusty Russell <rusty@rustcorp.com.au>2012-10-06 13:23:05 +0200
committerVolker Lendecke <vl@samba.org>2012-10-06 13:23:41 +0200
commit37fd93194db10fc832ed3fa1ec880ebc26be904b (patch)
tree6ee8e6ef1d15123fc4775cc687c872f6d77ea842 /lib/tdb/common/io.c
parent828793852f3785c620f2716c60f8b1640880ee50 (diff)
downloadsamba-37fd93194db10fc832ed3fa1ec880ebc26be904b.tar.gz
tdb: Make robust against shrinking tdbs
When probing for a size change (eg. just before tdb_expand, tdb_check, tdb_rescue) we call tdb_oob(tdb, tdb->map_size, 1, 1). Unfortunately this does nothing if the tdb has actually shrunk, which as Volker demonstrated, can actually happen if a "longlived" parent crashes. So move the map/update size/remap before the limit check. Signed-off-by: Rusty Russell <rusty@rustcorp.com.au>
Diffstat (limited to 'lib/tdb/common/io.c')
-rw-r--r--lib/tdb/common/io.c32
1 files changed, 20 insertions, 12 deletions
diff --git a/lib/tdb/common/io.c b/lib/tdb/common/io.c
index 3131f4fa0af..25968bfef2d 100644
--- a/lib/tdb/common/io.c
+++ b/lib/tdb/common/io.c
@@ -63,16 +63,6 @@ static int tdb_oob(struct tdb_context *tdb, tdb_off_t off, tdb_len_t len,
return -1;
}
- if (st.st_size < (size_t)off + len) {
- if (!probe) {
- /* Ensure ecode is set for log fn. */
- tdb->ecode = TDB_ERR_IO;
- TDB_LOG((tdb, TDB_DEBUG_FATAL,"tdb_oob len %u beyond eof at %u\n",
- (int)(off + len), (int)st.st_size));
- }
- return -1;
- }
-
/* Beware >4G files! */
if ((tdb_off_t)st.st_size != st.st_size) {
/* Ensure ecode is set for log fn. */
@@ -82,13 +72,31 @@ static int tdb_oob(struct tdb_context *tdb, tdb_off_t off, tdb_len_t len,
return -1;
}
- /* Unmap, update size, remap */
+ /* Unmap, update size, remap. We do this unconditionally, to handle
+ * the unusual case where the db is truncated.
+ *
+ * This can happen to a child using tdb_reopen_all(true) on a
+ * TDB_CLEAR_IF_FIRST tdb whose parent crashes: the next
+ * opener will truncate the database. */
if (tdb_munmap(tdb) == -1) {
tdb->ecode = TDB_ERR_IO;
return -1;
}
tdb->map_size = st.st_size;
- return tdb_mmap(tdb);
+ if (tdb_mmap(tdb) != 0) {
+ return - 1;
+ }
+
+ if (st.st_size < (size_t)off + len) {
+ if (!probe) {
+ /* Ensure ecode is set for log fn. */
+ tdb->ecode = TDB_ERR_IO;
+ TDB_LOG((tdb, TDB_DEBUG_FATAL,"tdb_oob len %u beyond eof at %u\n",
+ (int)(off + len), (int)st.st_size));
+ }
+ return -1;
+ }
+ return 0;
}
/* write a lump of data at a specified offset */