torture-krb5: Provide a generic handler to catch and print unexpected KRB_ERROR packets
[kai/samba-autobuild/.git] / lib / ntdb / io.c
index b0588132e038068d79e95fef079e435aba52f647..7645cddc373f2f8228e734f6fa82769a76e58ad2 100644 (file)
    License along with this library; if not, see <http://www.gnu.org/licenses/>.
 */
 #include "private.h"
-#include <assert.h>
 #include <ccan/likely/likely.h>
 
-void ntdb_munmap(struct ntdb_file *file)
+static void free_old_mmaps(struct ntdb_context *ntdb)
 {
-       if (file->fd == -1)
-               return;
+       struct ntdb_old_mmap *i;
 
-       if (file->map_ptr) {
-               munmap(file->map_ptr, file->map_size);
-               file->map_ptr = NULL;
+       assert(ntdb->file->direct_count == 0);
+
+       while ((i = ntdb->file->old_mmaps) != NULL) {
+               ntdb->file->old_mmaps = i->next;
+               if (ntdb->flags & NTDB_INTERNAL) {
+                       ntdb->free_fn(i->map_ptr, ntdb->alloc_data);
+               } else {
+                       munmap(i->map_ptr, i->map_size);
+               }
+               ntdb->free_fn(i, ntdb->alloc_data);
        }
 }
 
+static enum NTDB_ERROR save_old_map(struct ntdb_context *ntdb)
+{
+       struct ntdb_old_mmap *old;
+
+       assert(ntdb->file->direct_count);
+
+       old = ntdb->alloc_fn(ntdb->file, sizeof(*old), ntdb->alloc_data);
+       if (!old) {
+               return ntdb_logerr(ntdb, NTDB_ERR_OOM, NTDB_LOG_ERROR,
+                                  "save_old_map alloc failed");
+       }
+       old->next = ntdb->file->old_mmaps;
+       old->map_ptr = ntdb->file->map_ptr;
+       old->map_size = ntdb->file->map_size;
+       ntdb->file->old_mmaps = old;
+
+       return NTDB_SUCCESS;
+}
+
+enum NTDB_ERROR ntdb_munmap(struct ntdb_context *ntdb)
+{
+       if (ntdb->file->fd == -1) {
+               return NTDB_SUCCESS;
+       }
+
+       if (!ntdb->file->map_ptr) {
+               return NTDB_SUCCESS;
+       }
+
+       /* We can't unmap now if there are accessors. */
+       if (ntdb->file->direct_count) {
+               return save_old_map(ntdb);
+       } else {
+               munmap(ntdb->file->map_ptr, ntdb->file->map_size);
+               ntdb->file->map_ptr = NULL;
+       }
+       return NTDB_SUCCESS;
+}
+
 enum NTDB_ERROR ntdb_mmap(struct ntdb_context *ntdb)
 {
        int mmap_flags;
@@ -99,11 +143,6 @@ static enum NTDB_ERROR ntdb_normal_oob(struct ntdb_context *ntdb,
        struct stat st;
        enum NTDB_ERROR ecode;
 
-       /* We can't hold pointers during this: we could unmap! */
-       assert(!ntdb->direct_access
-              || (ntdb->flags & NTDB_NOLOCK)
-              || ntdb_has_expansion_lock(ntdb));
-
        if (len + off < len) {
                if (probe)
                        return NTDB_SUCCESS;
@@ -150,7 +189,10 @@ static enum NTDB_ERROR ntdb_normal_oob(struct ntdb_context *ntdb,
        }
 
        /* Unmap, update size, remap */
-       ntdb_munmap(ntdb->file);
+       ecode = ntdb_munmap(ntdb);
+       if (ecode) {
+               return ecode;
+       }
 
        ntdb->file->map_size = st.st_size;
        return ntdb_mmap(ntdb);
@@ -348,7 +390,7 @@ static void *_ntdb_alloc_read(struct ntdb_context *ntdb, ntdb_off_t offset,
        buf = ntdb->alloc_fn(ntdb, prefix + len ? prefix + len : 1,
                          ntdb->alloc_data);
        if (!buf) {
-               ntdb_logerr(ntdb, NTDB_ERR_OOM, NTDB_LOG_USE_ERROR,
+               ntdb_logerr(ntdb, NTDB_ERR_OOM, NTDB_LOG_ERROR,
                           "ntdb_alloc_read alloc failed len=%zu",
                           (size_t)(prefix + len));
                return NTDB_ERR_PTR(NTDB_ERR_OOM);
@@ -406,9 +448,26 @@ static enum NTDB_ERROR ntdb_expand_file(struct ntdb_context *ntdb,
        }
 
        if (ntdb->flags & NTDB_INTERNAL) {
-               char *new = ntdb->expand_fn(ntdb->file->map_ptr,
-                                       ntdb->file->map_size + addition,
-                                       ntdb->alloc_data);
+               char *new;
+
+               /* Can't free it if we have direct accesses. */
+               if (ntdb->file->direct_count) {
+                       ecode = save_old_map(ntdb);
+                       if (ecode) {
+                               return ecode;
+                       }
+                       new = ntdb->alloc_fn(ntdb->file,
+                                            ntdb->file->map_size + addition,
+                                            ntdb->alloc_data);
+                       if (new) {
+                               memcpy(new, ntdb->file->map_ptr,
+                                      ntdb->file->map_size);
+                       }
+               } else {
+                       new = ntdb->expand_fn(ntdb->file->map_ptr,
+                                             ntdb->file->map_size + addition,
+                                             ntdb->alloc_data);
+               }
                if (!new) {
                        return ntdb_logerr(ntdb, NTDB_ERR_OOM, NTDB_LOG_ERROR,
                                          "No memory to expand database");
@@ -419,7 +478,10 @@ static enum NTDB_ERROR ntdb_expand_file(struct ntdb_context *ntdb,
        } else {
                /* Unmap before trying to write; old NTDB claimed OpenBSD had
                 * problem with this otherwise. */
-               ntdb_munmap(ntdb->file);
+               ecode = ntdb_munmap(ntdb);
+               if (ecode) {
+                       return ecode;
+               }
 
                /* If this fails, we try to fill anyway. */
                if (ftruncate(ntdb->file->fd, ntdb->file->map_size + addition))
@@ -462,8 +524,9 @@ const void *ntdb_access_read(struct ntdb_context *ntdb,
                if (convert) {
                        ntdb_convert(ntdb, (void *)ret, len);
                }
-       } else
-               ntdb->direct_access++;
+       } else {
+               ntdb->file->direct_count++;
+       }
 
        return ret;
 }
@@ -501,9 +564,9 @@ void *ntdb_access_write(struct ntdb_context *ntdb,
                ret = hdr + 1;
                if (convert)
                        ntdb_convert(ntdb, (void *)ret, len);
-       } else
-               ntdb->direct_access++;
-
+       } else {
+               ntdb->file->direct_count++;
+       }
        return ret;
 }
 
@@ -526,8 +589,11 @@ void ntdb_access_release(struct ntdb_context *ntdb, const void *p)
                hdr = *hp;
                *hp = hdr->next;
                ntdb->free_fn(hdr, ntdb->alloc_data);
-       } else
-               ntdb->direct_access--;
+       } else {
+               if (--ntdb->file->direct_count == 0) {
+                       free_old_mmaps(ntdb);
+               }
+       }
 }
 
 enum NTDB_ERROR ntdb_access_commit(struct ntdb_context *ntdb, void *p)
@@ -544,7 +610,9 @@ enum NTDB_ERROR ntdb_access_commit(struct ntdb_context *ntdb, void *p)
                *hp = hdr->next;
                ntdb->free_fn(hdr, ntdb->alloc_data);
        } else {
-               ntdb->direct_access--;
+               if (--ntdb->file->direct_count == 0) {
+                       free_old_mmaps(ntdb);
+               }
                ecode = NTDB_SUCCESS;
        }