]> git.ozlabs.org Git - ccan/blobdiff - ccan/tdb2/io.c
failtest: add --trace to replace --tracepath
[ccan] / ccan / tdb2 / io.c
index 71238afea9aeed1e5ee10b23a038670d2aeab436..afab0c1a4cc37879abd9ffcd626dc9b4a49d20e0 100644 (file)
 #include <assert.h>
 #include <ccan/likely/likely.h>
 
-void tdb_munmap(struct tdb_context *tdb)
+void tdb_munmap(struct tdb_file *file)
 {
-       if (tdb->flags & TDB_INTERNAL)
+       if (file->fd == -1)
                return;
 
-       if (tdb->map_ptr) {
-               munmap(tdb->map_ptr, tdb->map_size);
-               tdb->map_ptr = NULL;
+       if (file->map_ptr) {
+               munmap(file->map_ptr, file->map_size);
+               file->map_ptr = NULL;
        }
 }
 
 void tdb_mmap(struct tdb_context *tdb)
 {
+       int mmap_flags;
+
        if (tdb->flags & TDB_INTERNAL)
                return;
 
        if (tdb->flags & TDB_NOMMAP)
                return;
 
-       tdb->map_ptr = mmap(NULL, tdb->map_size, tdb->mmap_flags,
-                           MAP_SHARED, tdb->fd, 0);
+       if ((tdb->open_flags & O_ACCMODE) == O_RDONLY)
+               mmap_flags = PROT_READ;
+       else
+               mmap_flags = PROT_READ | PROT_WRITE;
+
+       /* size_t can be smaller than off_t. */
+       if ((size_t)tdb->file->map_size == tdb->file->map_size) {
+               tdb->file->map_ptr = mmap(NULL, tdb->file->map_size,
+                                         mmap_flags,
+                                         MAP_SHARED, tdb->file->fd, 0);
+       } else
+               tdb->file->map_ptr = MAP_FAILED;
 
        /*
         * NB. When mmap fails it returns MAP_FAILED *NOT* NULL !!!!
         */
-       if (tdb->map_ptr == MAP_FAILED) {
-               tdb->map_ptr = NULL;
+       if (tdb->file->map_ptr == MAP_FAILED) {
+               tdb->file->map_ptr = NULL;
                tdb_logerr(tdb, TDB_SUCCESS, TDB_LOG_WARNING,
                           "tdb_mmap failed for size %lld (%s)",
-                          (long long)tdb->map_size, strerror(errno));
+                          (long long)tdb->file->map_size, strerror(errno));
        }
 }
 
 /* check for an out of bounds access - if it is out of bounds then
    see if the database has been expanded by someone else and expand
    if necessary
-   note that "len" is the minimum length needed for the db
+   note that "len" is the minimum length needed for the db.
+
+   If probe is true, len being too large isn't a failure.
 */
 static enum TDB_ERROR tdb_oob(struct tdb_context *tdb, tdb_off_t len,
                              bool probe)
@@ -74,20 +88,21 @@ static enum TDB_ERROR tdb_oob(struct tdb_context *tdb, tdb_off_t len,
        enum TDB_ERROR ecode;
 
        /* We can't hold pointers during this: we could unmap! */
-       assert(!tdb->direct_access
+       assert(!tdb->tdb2.direct_access
               || (tdb->flags & TDB_NOLOCK)
               || tdb_has_expansion_lock(tdb));
 
-       if (len <= tdb->map_size)
-               return 0;
+       if (len <= tdb->file->map_size)
+               return TDB_SUCCESS;
        if (tdb->flags & TDB_INTERNAL) {
-               if (!probe) {
-                       tdb_logerr(tdb, TDB_ERR_IO, TDB_LOG_ERROR,
-                                "tdb_oob len %lld beyond internal"
-                                " malloc size %lld",
-                                (long long)len,
-                                (long long)tdb->map_size);
-               }
+               if (probe)
+                       return TDB_SUCCESS;
+
+               tdb_logerr(tdb, TDB_ERR_IO, TDB_LOG_ERROR,
+                          "tdb_oob len %lld beyond internal"
+                          " malloc size %lld",
+                          (long long)len,
+                          (long long)tdb->file->map_size);
                return TDB_ERR_IO;
        }
 
@@ -96,7 +111,7 @@ static enum TDB_ERROR tdb_oob(struct tdb_context *tdb, tdb_off_t len,
                return ecode;
        }
 
-       if (fstat(tdb->fd, &st) != 0) {
+       if (fstat(tdb->file->fd, &st) != 0) {
                tdb_logerr(tdb, TDB_ERR_IO, TDB_LOG_ERROR,
                           "Failed to fstat file: %s", strerror(errno));
                tdb_unlock_expand(tdb, F_RDLCK);
@@ -106,18 +121,19 @@ static enum TDB_ERROR tdb_oob(struct tdb_context *tdb, tdb_off_t len,
        tdb_unlock_expand(tdb, F_RDLCK);
 
        if (st.st_size < (size_t)len) {
-               if (!probe) {
-                       tdb_logerr(tdb, TDB_ERR_IO, TDB_LOG_ERROR,
-                                  "tdb_oob len %zu beyond eof at %zu",
-                                  (size_t)len, st.st_size);
-               }
+               if (probe)
+                       return TDB_SUCCESS;
+
+               tdb_logerr(tdb, TDB_ERR_IO, TDB_LOG_ERROR,
+                          "tdb_oob len %zu beyond eof at %zu",
+                          (size_t)len, st.st_size);
                return TDB_ERR_IO;
        }
 
        /* Unmap, update size, remap */
-       tdb_munmap(tdb);
+       tdb_munmap(tdb->file);
 
-       tdb->map_size = st.st_size;
+       tdb->file->map_size = st.st_size;
        tdb_mmap(tdb);
        return TDB_SUCCESS;
 }
@@ -125,6 +141,7 @@ static enum TDB_ERROR tdb_oob(struct tdb_context *tdb, tdb_off_t len,
 /* Endian conversion: we only ever deal with 8 byte quantities */
 void *tdb_convert(const struct tdb_context *tdb, void *buf, tdb_len_t size)
 {
+       assert(size % 8 == 0);
        if (unlikely((tdb->flags & TDB_CONVERT)) && buf) {
                uint64_t i, *p = (uint64_t *)buf;
                for (i = 0; i < size / 8; i++)
@@ -133,6 +150,7 @@ void *tdb_convert(const struct tdb_context *tdb, void *buf, tdb_len_t size)
        return buf;
 }
 
+/* Return first non-zero offset in offset array, or end, or -ve error. */
 /* FIXME: Return the off? */
 uint64_t tdb_find_nonzero_off(struct tdb_context *tdb,
                              tdb_off_t base, uint64_t start, uint64_t end)
@@ -143,8 +161,9 @@ uint64_t tdb_find_nonzero_off(struct tdb_context *tdb,
        /* Zero vs non-zero is the same unconverted: minor optimization. */
        val = tdb_access_read(tdb, base + start * sizeof(tdb_off_t),
                              (end - start) * sizeof(tdb_off_t), false);
-       if (!val)
-               return end;
+       if (TDB_PTR_IS_ERR(val)) {
+               return TDB_ERR_TO_OFF(TDB_PTR_ERR(val));
+       }
 
        for (i = 0; i < (end - start); i++) {
                if (val[i])
@@ -154,7 +173,7 @@ uint64_t tdb_find_nonzero_off(struct tdb_context *tdb,
        return start + i;
 }
 
-/* Return first zero offset in num offset array, or num. */
+/* Return first zero offset in num offset array, or num, or -ve error. */
 uint64_t tdb_find_zero_off(struct tdb_context *tdb, tdb_off_t off,
                           uint64_t num)
 {
@@ -163,8 +182,9 @@ uint64_t tdb_find_zero_off(struct tdb_context *tdb, tdb_off_t off,
 
        /* Zero vs non-zero is the same unconverted: minor optimization. */
        val = tdb_access_read(tdb, off, num * sizeof(tdb_off_t), false);
-       if (!val)
-               return num;
+       if (TDB_PTR_IS_ERR(val)) {
+               return TDB_ERR_TO_OFF(TDB_PTR_ERR(val));
+       }
 
        for (i = 0; i < num; i++) {
                if (!val[i])
@@ -177,17 +197,20 @@ uint64_t tdb_find_zero_off(struct tdb_context *tdb, tdb_off_t off,
 enum TDB_ERROR zero_out(struct tdb_context *tdb, tdb_off_t off, tdb_len_t len)
 {
        char buf[8192] = { 0 };
-       void *p = tdb->methods->direct(tdb, off, len, true);
+       void *p = tdb->tdb2.io->direct(tdb, off, len, true);
        enum TDB_ERROR ecode = TDB_SUCCESS;
 
-       assert(!tdb->read_only);
+       assert(!(tdb->flags & TDB_RDONLY));
+       if (TDB_PTR_IS_ERR(p)) {
+               return TDB_PTR_ERR(p);
+       }
        if (p) {
                memset(p, 0, len);
                return ecode;
        }
        while (len) {
                unsigned todo = len < sizeof(buf) ? len : sizeof(buf);
-               ecode = tdb->methods->twrite(tdb, off, buf, todo);
+               ecode = tdb->tdb2.io->twrite(tdb, off, buf, todo);
                if (ecode != TDB_SUCCESS) {
                        break;
                }
@@ -203,16 +226,18 @@ tdb_off_t tdb_read_off(struct tdb_context *tdb, tdb_off_t off)
        enum TDB_ERROR ecode;
 
        if (likely(!(tdb->flags & TDB_CONVERT))) {
-               tdb_off_t *p = tdb->methods->direct(tdb, off, sizeof(*p),
+               tdb_off_t *p = tdb->tdb2.io->direct(tdb, off, sizeof(*p),
                                                    false);
+               if (TDB_PTR_IS_ERR(p)) {
+                       return TDB_ERR_TO_OFF(TDB_PTR_ERR(p));
+               }
                if (p)
                        return *p;
        }
 
        ecode = tdb_read_convert(tdb, off, &ret, sizeof(ret));
        if (ecode != TDB_SUCCESS) {
-               tdb->ecode = ecode;
-               return TDB_OFF_ERR;
+               return TDB_ERR_TO_OFF(ecode);
        }
        return ret;
 }
@@ -223,27 +248,22 @@ static enum TDB_ERROR tdb_write(struct tdb_context *tdb, tdb_off_t off,
 {
        enum TDB_ERROR ecode;
 
-       if (tdb->read_only) {
+       if (tdb->flags & TDB_RDONLY) {
                return tdb_logerr(tdb, TDB_ERR_RDONLY, TDB_LOG_USE_ERROR,
                                  "Write to read-only database");
        }
 
-       /* FIXME: Bogus optimization? */
-       if (len == 0) {
-               return TDB_SUCCESS;
-       }
-
-       ecode = tdb->methods->oob(tdb, off + len, 0);
+       ecode = tdb->tdb2.io->oob(tdb, off + len, false);
        if (ecode != TDB_SUCCESS) {
                return ecode;
        }
 
-       if (tdb->map_ptr) {
-               memcpy(off + (char *)tdb->map_ptr, buf, len);
+       if (tdb->file->map_ptr) {
+               memcpy(off + (char *)tdb->file->map_ptr, buf, len);
        } else {
                ssize_t ret;
-               ret = pwrite(tdb->fd, buf, len, off);
-               if (ret < len) {
+               ret = pwrite(tdb->file->fd, buf, len, off);
+               if (ret != len) {
                        /* This shouldn't happen: we avoid sparse files. */
                        if (ret >= 0)
                                errno = ENOSPC;
@@ -263,22 +283,22 @@ static enum TDB_ERROR tdb_read(struct tdb_context *tdb, tdb_off_t off,
 {
        enum TDB_ERROR ecode;
 
-       ecode = tdb->methods->oob(tdb, off + len, 0);
+       ecode = tdb->tdb2.io->oob(tdb, off + len, false);
        if (ecode != TDB_SUCCESS) {
                return ecode;
        }
 
-       if (tdb->map_ptr) {
-               memcpy(buf, off + (char *)tdb->map_ptr, len);
+       if (tdb->file->map_ptr) {
+               memcpy(buf, off + (char *)tdb->file->map_ptr, len);
        } else {
-               ssize_t r = pread(tdb->fd, buf, len, off);
+               ssize_t r = pread(tdb->file->fd, buf, len, off);
                if (r != len) {
                        return tdb_logerr(tdb, TDB_ERR_IO, TDB_LOG_ERROR,
                                          "tdb_read failed with %zi at %zu "
                                          "len=%zu (%s) map_size=%zu",
                                          r, (size_t)off, (size_t)len,
                                          strerror(errno),
-                                         (size_t)tdb->map_size);
+                                         (size_t)tdb->file->map_size);
                }
        }
        return TDB_SUCCESS;
@@ -297,11 +317,11 @@ enum TDB_ERROR tdb_write_convert(struct tdb_context *tdb, tdb_off_t off,
                                          " %zu bytes", len);
                }
                memcpy(conv, rec, len);
-               ecode = tdb->methods->twrite(tdb, off,
+               ecode = tdb->tdb2.io->twrite(tdb, off,
                                           tdb_convert(tdb, conv, len), len);
                free(conv);
        } else {
-               ecode = tdb->methods->twrite(tdb, off, rec, len);
+               ecode = tdb->tdb2.io->twrite(tdb, off, rec, len);
        }
        return ecode;
 }
@@ -309,7 +329,7 @@ enum TDB_ERROR tdb_write_convert(struct tdb_context *tdb, tdb_off_t off,
 enum TDB_ERROR tdb_read_convert(struct tdb_context *tdb, tdb_off_t off,
                                void *rec, size_t len)
 {
-       enum TDB_ERROR ecode = tdb->methods->tread(tdb, off, rec, len);
+       enum TDB_ERROR ecode = tdb->tdb2.io->tread(tdb, off, rec, len);
        tdb_convert(tdb, rec, len);
        return ecode;
 }
@@ -317,14 +337,17 @@ enum TDB_ERROR tdb_read_convert(struct tdb_context *tdb, tdb_off_t off,
 enum TDB_ERROR tdb_write_off(struct tdb_context *tdb,
                             tdb_off_t off, tdb_off_t val)
 {
-       if (tdb->read_only) {
+       if (tdb->flags & TDB_RDONLY) {
                return tdb_logerr(tdb, TDB_ERR_RDONLY, TDB_LOG_USE_ERROR,
                                  "Write to read-only database");
        }
 
        if (likely(!(tdb->flags & TDB_CONVERT))) {
-               tdb_off_t *p = tdb->methods->direct(tdb, off, sizeof(*p),
+               tdb_off_t *p = tdb->tdb2.io->direct(tdb, off, sizeof(*p),
                                                    true);
+               if (TDB_PTR_IS_ERR(p)) {
+                       return TDB_PTR_ERR(p);
+               }
                if (p) {
                        *p = val;
                        return TDB_SUCCESS;
@@ -336,7 +359,7 @@ enum TDB_ERROR tdb_write_off(struct tdb_context *tdb,
 static void *_tdb_alloc_read(struct tdb_context *tdb, tdb_off_t offset,
                             tdb_len_t len, unsigned int prefix)
 {
-       void *buf;
+       unsigned char *buf;
        enum TDB_ERROR ecode;
 
        /* some systems don't like zero length malloc */
@@ -345,12 +368,12 @@ static void *_tdb_alloc_read(struct tdb_context *tdb, tdb_off_t offset,
                tdb_logerr(tdb, TDB_ERR_OOM, TDB_LOG_USE_ERROR,
                           "tdb_alloc_read malloc failed len=%zu",
                           (size_t)(prefix + len));
+               return TDB_ERR_PTR(TDB_ERR_OOM);
        } else {
-               ecode = tdb->methods->tread(tdb, offset, buf+prefix, len);
+               ecode = tdb->tdb2.io->tread(tdb, offset, buf+prefix, len);
                if (unlikely(ecode != TDB_SUCCESS)) {
-                       tdb->ecode = ecode;
                        free(buf);
-                       buf = NULL;
+                       return TDB_ERR_PTR(ecode);
                }
        }
        return buf;
@@ -368,8 +391,8 @@ static enum TDB_ERROR fill(struct tdb_context *tdb,
 {
        while (len) {
                size_t n = len > size ? size : len;
-               ssize_t ret = pwrite(tdb->fd, buf, n, off);
-               if (ret < n) {
+               ssize_t ret = pwrite(tdb->file->fd, buf, n, off);
+               if (ret != n) {
                        if (ret >= 0)
                                errno = ENOSPC;
 
@@ -393,36 +416,38 @@ static enum TDB_ERROR tdb_expand_file(struct tdb_context *tdb,
        char buf[8192];
        enum TDB_ERROR ecode;
 
-       if (tdb->read_only) {
+       if (tdb->flags & TDB_RDONLY) {
                return tdb_logerr(tdb, TDB_ERR_RDONLY, TDB_LOG_USE_ERROR,
                                  "Expand on read-only database");
        }
 
        if (tdb->flags & TDB_INTERNAL) {
-               char *new = realloc(tdb->map_ptr, tdb->map_size + addition);
+               char *new = realloc(tdb->file->map_ptr,
+                                   tdb->file->map_size + addition);
                if (!new) {
                        return tdb_logerr(tdb, TDB_ERR_OOM, TDB_LOG_ERROR,
                                          "No memory to expand database");
                }
-               tdb->map_ptr = new;
-               tdb->map_size += addition;
+               tdb->file->map_ptr = new;
+               tdb->file->map_size += addition;
        } else {
                /* Unmap before trying to write; old TDB claimed OpenBSD had
                 * problem with this otherwise. */
-               tdb_munmap(tdb);
+               tdb_munmap(tdb->file);
 
                /* If this fails, we try to fill anyway. */
-               if (ftruncate(tdb->fd, tdb->map_size + addition))
+               if (ftruncate(tdb->file->fd, tdb->file->map_size + addition))
                        ;
 
                /* now fill the file with something. This ensures that the
                   file isn't sparse, which would be very bad if we ran out of
                   disk. This must be done with write, not via mmap */
                memset(buf, 0x43, sizeof(buf));
-               ecode = fill(tdb, buf, sizeof(buf), tdb->map_size, addition);
+               ecode = fill(tdb, buf, sizeof(buf), tdb->file->map_size,
+                            addition);
                if (ecode != TDB_SUCCESS)
                        return ecode;
-               tdb->map_size += addition;
+               tdb->file->map_size += addition;
                tdb_mmap(tdb);
        }
        return TDB_SUCCESS;
@@ -431,23 +456,29 @@ static enum TDB_ERROR tdb_expand_file(struct tdb_context *tdb,
 const void *tdb_access_read(struct tdb_context *tdb,
                            tdb_off_t off, tdb_len_t len, bool convert)
 {
-       const void *ret = NULL;
+       void *ret = NULL;
 
-       if (likely(!(tdb->flags & TDB_CONVERT)))
-               ret = tdb->methods->direct(tdb, off, len, false);
+       if (likely(!(tdb->flags & TDB_CONVERT))) {
+               ret = tdb->tdb2.io->direct(tdb, off, len, false);
 
+               if (TDB_PTR_IS_ERR(ret)) {
+                       return ret;
+               }
+       }
        if (!ret) {
                struct tdb_access_hdr *hdr;
                hdr = _tdb_alloc_read(tdb, off, len, sizeof(*hdr));
-               if (hdr) {
-                       hdr->next = tdb->access;
-                       tdb->access = hdr;
-                       ret = hdr + 1;
-                       if (convert)
-                               tdb_convert(tdb, (void *)ret, len);
+               if (TDB_PTR_IS_ERR(hdr)) {
+                       return hdr;
+               }
+               hdr->next = tdb->tdb2.access;
+               tdb->tdb2.access = hdr;
+               ret = hdr + 1;
+               if (convert) {
+                       tdb_convert(tdb, (void *)ret, len);
                }
        } else
-               tdb->direct_access++;
+               tdb->tdb2.direct_access++;
 
        return ret;
 }
@@ -457,30 +488,36 @@ void *tdb_access_write(struct tdb_context *tdb,
 {
        void *ret = NULL;
 
-       if (tdb->read_only) {
+       if (tdb->flags & TDB_RDONLY) {
                tdb_logerr(tdb, TDB_ERR_RDONLY, TDB_LOG_USE_ERROR,
                           "Write to read-only database");
-               return NULL;
+               return TDB_ERR_PTR(TDB_ERR_RDONLY);
        }
 
-       if (likely(!(tdb->flags & TDB_CONVERT)))
-               ret = tdb->methods->direct(tdb, off, len, true);
+       if (likely(!(tdb->flags & TDB_CONVERT))) {
+               ret = tdb->tdb2.io->direct(tdb, off, len, true);
+
+               if (TDB_PTR_IS_ERR(ret)) {
+                       return ret;
+               }
+       }
 
        if (!ret) {
                struct tdb_access_hdr *hdr;
                hdr = _tdb_alloc_read(tdb, off, len, sizeof(*hdr));
-               if (hdr) {
-                       hdr->next = tdb->access;
-                       tdb->access = hdr;
-                       hdr->off = off;
-                       hdr->len = len;
-                       hdr->convert = convert;
-                       ret = hdr + 1;
-                       if (convert)
-                               tdb_convert(tdb, (void *)ret, len);
+               if (TDB_PTR_IS_ERR(hdr)) {
+                       return hdr;
                }
+               hdr->next = tdb->tdb2.access;
+               tdb->tdb2.access = hdr;
+               hdr->off = off;
+               hdr->len = len;
+               hdr->convert = convert;
+               ret = hdr + 1;
+               if (convert)
+                       tdb_convert(tdb, (void *)ret, len);
        } else
-               tdb->direct_access++;
+               tdb->tdb2.direct_access++;
 
        return ret;
 }
@@ -489,7 +526,7 @@ static struct tdb_access_hdr **find_hdr(struct tdb_context *tdb, const void *p)
 {
        struct tdb_access_hdr **hp;
 
-       for (hp = &tdb->access; *hp; hp = &(*hp)->next) {
+       for (hp = &tdb->tdb2.access; *hp; hp = &(*hp)->next) {
                if (*hp + 1 == p)
                        return hp;
        }
@@ -505,7 +542,7 @@ void tdb_access_release(struct tdb_context *tdb, const void *p)
                *hp = hdr->next;
                free(hdr);
        } else
-               tdb->direct_access--;
+               tdb->tdb2.direct_access--;
 }
 
 enum TDB_ERROR tdb_access_commit(struct tdb_context *tdb, void *p)
@@ -522,7 +559,7 @@ enum TDB_ERROR tdb_access_commit(struct tdb_context *tdb, void *p)
                *hp = hdr->next;
                free(hdr);
        } else {
-               tdb->direct_access--;
+               tdb->tdb2.direct_access--;
                ecode = TDB_SUCCESS;
        }
 
@@ -532,18 +569,49 @@ enum TDB_ERROR tdb_access_commit(struct tdb_context *tdb, void *p)
 static void *tdb_direct(struct tdb_context *tdb, tdb_off_t off, size_t len,
                        bool write_mode)
 {
-       if (unlikely(!tdb->map_ptr))
-               return NULL;
+       enum TDB_ERROR ecode;
 
-       if (unlikely(tdb_oob(tdb, off + len, true) != TDB_SUCCESS))
+       if (unlikely(!tdb->file->map_ptr))
                return NULL;
-       return (char *)tdb->map_ptr + off;
+
+       ecode = tdb_oob(tdb, off + len, false);
+       if (unlikely(ecode != TDB_SUCCESS))
+               return TDB_ERR_PTR(ecode);
+       return (char *)tdb->file->map_ptr + off;
 }
 
-void add_stat_(struct tdb_context *tdb, uint64_t *s, size_t val)
+void tdb_inc_seqnum(struct tdb_context *tdb)
 {
-       if ((uintptr_t)s < (uintptr_t)tdb->stats + tdb->stats->size)
-               *s += val;
+       tdb_off_t seq;
+
+       if (tdb->flags & TDB_VERSION1) {
+               tdb1_increment_seqnum_nonblock(tdb);
+               return;
+       }
+
+       if (likely(!(tdb->flags & TDB_CONVERT))) {
+               int64_t *direct;
+
+               direct = tdb->tdb2.io->direct(tdb,
+                                             offsetof(struct tdb_header,
+                                                      seqnum),
+                                             sizeof(*direct), true);
+               if (likely(direct)) {
+                       /* Don't let it go negative, even briefly */
+                       if (unlikely((*direct) + 1) < 0)
+                               *direct = 0;
+                       (*direct)++;
+                       return;
+               }
+       }
+
+       seq = tdb_read_off(tdb, offsetof(struct tdb_header, seqnum));
+       if (!TDB_OFF_IS_ERR(seq)) {
+               seq++;
+               if (unlikely((int64_t)seq < 0))
+                       seq = 0;
+               tdb_write_off(tdb, offsetof(struct tdb_header, seqnum), seq);
+       }
 }
 
 static const struct tdb_methods io_methods = {
@@ -559,5 +627,5 @@ static const struct tdb_methods io_methods = {
 */
 void tdb_io_init(struct tdb_context *tdb)
 {
-       tdb->methods = &io_methods;
+       tdb->tdb2.io = &io_methods;
 }