diff options
author | Jeremy Allison <jra@samba.org> | 2001-05-04 22:23:37 +0000 |
---|---|---|
committer | Jeremy Allison <jra@samba.org> | 2001-05-04 22:23:37 +0000 |
commit | 4c6a8273c6dd3e2aeda5a63c4a62aa55bc133099 (patch) | |
tree | c25503b6dba7578d1259d1c00a527c7226a57c5b | |
parent | a4a4c02b12f030a3b9e6225b999c90689dfc4719 (diff) | |
download | samba-4c6a8273c6dd3e2aeda5a63c4a62aa55bc133099.tar.gz samba-4c6a8273c6dd3e2aeda5a63c4a62aa55bc133099.tar.xz samba-4c6a8273c6dd3e2aeda5a63c4a62aa55bc133099.zip |
Fix problem with OpenBSD mmap and write not being coherent.
Jeremy.
-rw-r--r-- | source/tdb/tdb.c | 37 |
1 files changed, 29 insertions, 8 deletions
diff --git a/source/tdb/tdb.c b/source/tdb/tdb.c index b1335728ab5..bf94e4cbd3f 100644 --- a/source/tdb/tdb.c +++ b/source/tdb/tdb.c @@ -429,6 +429,7 @@ static int tdb_expand(TDB_CONTEXT *tdb, tdb_off size) struct list_struct rec; tdb_off offset; char b = 0; + void *old_map_ptr; if (tdb_lock(tdb, -1, F_WRLCK) == -1) return 0; @@ -439,20 +440,43 @@ static int tdb_expand(TDB_CONTEXT *tdb, tdb_off size) the database up to a multiple of TDB_PAGE_SIZE */ size = TDB_ALIGN(tdb->map_size + size*10, TDB_PAGE_SIZE) - tdb->map_size; - /* expand the file itself */ - if (!(tdb->flags & TDB_INTERNAL)) { - lseek(tdb->fd, tdb->map_size + size - 1, SEEK_SET); - if (write(tdb->fd, &b, 1) != 1) goto fail; - } + old_map_ptr = tdb->map_ptr; if (!(tdb->flags & TDB_INTERNAL) && tdb->map_ptr) tdb->map_ptr = tdb_munmap(tdb->map_ptr, tdb->map_size); + /* + * 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 (lseek(tdb->fd, tdb->map_size + size - 1, SEEK_SET)!=tdb->map_size + size - 1) + goto fail; + if (write(tdb->fd, &b, 1) != 1) + goto fail; + } + tdb->map_size += size; if (tdb->flags & TDB_INTERNAL) tdb->map_ptr = realloc(tdb->map_ptr, tdb->map_size); + /* + * 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. + */ + + if (!(tdb->flags & TDB_NOMMAP)) { + tdb->map_ptr = tdb_mmap(tdb->map_size, 0, tdb->fd); + /* if old_map_ptr was != NULL but the new one is, we have an error. */ + if (old_map_ptr && (tdb->map_ptr == NULL)) + goto fail; + } + /* form a new freelist record */ memset(&rec,'\0',sizeof(rec)); rec.rec_len = size - sizeof(rec); @@ -461,9 +485,6 @@ static int tdb_expand(TDB_CONTEXT *tdb, tdb_off size) offset = tdb->map_size - size; if (tdb_free(tdb, offset, &rec) == -1) goto fail; - if (!(tdb->flags & TDB_NOMMAP)) - tdb->map_ptr = tdb_mmap(tdb->map_size, 0, tdb->fd); - tdb_unlock(tdb, -1, F_WRLCK); return 0; fail: |