torture-krb5: Provide a generic handler to catch and print unexpected KRB_ERROR packets
[kai/samba-autobuild/.git] / lib / ntdb / io.c
index b20141cc8fc677de7a176efcf47652aab190c4e4..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)
@@ -92,17 +136,13 @@ enum NTDB_ERROR ntdb_mmap(struct ntdb_context *ntdb)
 
    If probe is true, len being too large isn't a failure.
 */
-static enum NTDB_ERROR ntdb_oob(struct ntdb_context *ntdb,
-                             ntdb_off_t off, ntdb_len_t len, bool probe)
+static enum NTDB_ERROR ntdb_normal_oob(struct ntdb_context *ntdb,
+                                      ntdb_off_t off, ntdb_len_t len,
+                                      bool probe)
 {
        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;
@@ -112,8 +152,6 @@ static enum NTDB_ERROR ntdb_oob(struct ntdb_context *ntdb,
                                  (long long)off, (long long)len);
        }
 
-       if (len + off <= ntdb->file->map_size)
-               return NTDB_SUCCESS;
        if (ntdb->flags & NTDB_INTERNAL) {
                if (probe)
                        return NTDB_SUCCESS;
@@ -151,7 +189,10 @@ static enum NTDB_ERROR ntdb_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);
@@ -239,27 +280,6 @@ enum NTDB_ERROR zero_out(struct ntdb_context *ntdb, ntdb_off_t off, ntdb_len_t l
        return ecode;
 }
 
-ntdb_off_t ntdb_read_off(struct ntdb_context *ntdb, ntdb_off_t off)
-{
-       ntdb_off_t ret;
-       enum NTDB_ERROR ecode;
-
-       if (likely(!(ntdb->flags & NTDB_CONVERT))) {
-               ntdb_off_t *p = ntdb->io->direct(ntdb, off, sizeof(*p), false);
-               if (NTDB_PTR_IS_ERR(p)) {
-                       return NTDB_ERR_TO_OFF(NTDB_PTR_ERR(p));
-               }
-               if (p)
-                       return *p;
-       }
-
-       ecode = ntdb_read_convert(ntdb, off, &ret, sizeof(ret));
-       if (ecode != NTDB_SUCCESS) {
-               return NTDB_ERR_TO_OFF(ecode);
-       }
-       return ret;
-}
-
 /* write a lump of data at a specified offset */
 static enum NTDB_ERROR ntdb_write(struct ntdb_context *ntdb, ntdb_off_t off,
                                const void *buf, ntdb_len_t len)
@@ -271,7 +291,7 @@ static enum NTDB_ERROR ntdb_write(struct ntdb_context *ntdb, ntdb_off_t off,
                                  "Write to read-only database");
        }
 
-       ecode = ntdb->io->oob(ntdb, off, len, false);
+       ecode = ntdb_oob(ntdb, off, len, false);
        if (ecode != NTDB_SUCCESS) {
                return ecode;
        }
@@ -305,7 +325,7 @@ static enum NTDB_ERROR ntdb_read(struct ntdb_context *ntdb, ntdb_off_t off,
 {
        enum NTDB_ERROR ecode;
 
-       ecode = ntdb->io->oob(ntdb, off, len, false);
+       ecode = ntdb_oob(ntdb, off, len, false);
        if (ecode != NTDB_SUCCESS) {
                return ecode;
        }
@@ -360,27 +380,6 @@ enum NTDB_ERROR ntdb_read_convert(struct ntdb_context *ntdb, ntdb_off_t off,
        return ecode;
 }
 
-enum NTDB_ERROR ntdb_write_off(struct ntdb_context *ntdb,
-                            ntdb_off_t off, ntdb_off_t val)
-{
-       if (ntdb->flags & NTDB_RDONLY) {
-               return ntdb_logerr(ntdb, NTDB_ERR_RDONLY, NTDB_LOG_USE_ERROR,
-                                 "Write to read-only database");
-       }
-
-       if (likely(!(ntdb->flags & NTDB_CONVERT))) {
-               ntdb_off_t *p = ntdb->io->direct(ntdb, off, sizeof(*p), true);
-               if (NTDB_PTR_IS_ERR(p)) {
-                       return NTDB_PTR_ERR(p);
-               }
-               if (p) {
-                       *p = val;
-                       return NTDB_SUCCESS;
-               }
-       }
-       return ntdb_write_convert(ntdb, off, &val, sizeof(val));
-}
-
 static void *_ntdb_alloc_read(struct ntdb_context *ntdb, ntdb_off_t offset,
                             ntdb_len_t len, unsigned int prefix)
 {
@@ -391,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);
@@ -449,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");
@@ -462,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))
@@ -505,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;
 }
@@ -544,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;
 }
 
@@ -569,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)
@@ -587,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;
        }
 
@@ -608,6 +633,63 @@ static void *ntdb_direct(struct ntdb_context *ntdb, ntdb_off_t off, size_t len,
        return (char *)ntdb->file->map_ptr + off;
 }
 
+static ntdb_off_t ntdb_read_normal_off(struct ntdb_context *ntdb,
+                                      ntdb_off_t off)
+{
+       ntdb_off_t ret;
+       enum NTDB_ERROR ecode;
+       ntdb_off_t *p;
+
+       p = ntdb_direct(ntdb, off, sizeof(*p), false);
+       if (NTDB_PTR_IS_ERR(p)) {
+               return NTDB_ERR_TO_OFF(NTDB_PTR_ERR(p));
+       }
+       if (likely(p)) {
+               return *p;
+       }
+
+       ecode = ntdb_read(ntdb, off, &ret, sizeof(ret));
+       if (ecode != NTDB_SUCCESS) {
+               return NTDB_ERR_TO_OFF(ecode);
+       }
+       return ret;
+}
+
+static ntdb_off_t ntdb_read_convert_off(struct ntdb_context *ntdb,
+                                       ntdb_off_t off)
+{
+       ntdb_off_t ret;
+       enum NTDB_ERROR ecode;
+
+       ecode = ntdb_read_convert(ntdb, off, &ret, sizeof(ret));
+       if (ecode != NTDB_SUCCESS) {
+               return NTDB_ERR_TO_OFF(ecode);
+       }
+       return ret;
+}
+
+static enum NTDB_ERROR ntdb_write_normal_off(struct ntdb_context *ntdb,
+                                            ntdb_off_t off, ntdb_off_t val)
+{
+       ntdb_off_t *p;
+
+       p = ntdb_direct(ntdb, off, sizeof(*p), true);
+       if (NTDB_PTR_IS_ERR(p)) {
+               return NTDB_PTR_ERR(p);
+       }
+       if (likely(p)) {
+               *p = val;
+               return NTDB_SUCCESS;
+       }
+       return ntdb_write(ntdb, off, &val, sizeof(val));
+}
+
+static enum NTDB_ERROR ntdb_write_convert_off(struct ntdb_context *ntdb,
+                                             ntdb_off_t off, ntdb_off_t val)
+{
+       return ntdb_write_convert(ntdb, off, &val, sizeof(val));
+}
+
 void ntdb_inc_seqnum(struct ntdb_context *ntdb)
 {
        ntdb_off_t seq;
@@ -639,9 +721,21 @@ void ntdb_inc_seqnum(struct ntdb_context *ntdb)
 static const struct ntdb_methods io_methods = {
        ntdb_read,
        ntdb_write,
-       ntdb_oob,
+       ntdb_normal_oob,
        ntdb_expand_file,
        ntdb_direct,
+       ntdb_read_normal_off,
+       ntdb_write_normal_off,
+};
+
+static const struct ntdb_methods io_convert_methods = {
+       ntdb_read,
+       ntdb_write,
+       ntdb_normal_oob,
+       ntdb_expand_file,
+       ntdb_direct,
+       ntdb_read_convert_off,
+       ntdb_write_convert_off,
 };
 
 /*
@@ -649,5 +743,8 @@ static const struct ntdb_methods io_methods = {
 */
 void ntdb_io_init(struct ntdb_context *ntdb)
 {
-       ntdb->io = &io_methods;
+       if (ntdb->flags & NTDB_CONVERT)
+               ntdb->io = &io_convert_methods;
+       else
+               ntdb->io = &io_methods;
 }