]> git.ozlabs.org Git - ccan/blobdiff - ccan/tdb2/free.c
tdb2: rework some io.c functions to encode errors in their pointer returns.
[ccan] / ccan / tdb2 / free.c
index ba14dfcd70747b8ad6789ba08487d30b91cbc6fc..4f9a52a1873d4e64a5f399b12dddb825b0bc3a95 100644 (file)
@@ -1,7 +1,7 @@
- /* 
+ /*
    Trivial Database 2: free list/block handling
    Copyright (C) Rusty Russell 2010
-   
+
    This library is free software; you can redistribute it and/or
    modify it under the terms of the GNU Lesser General Public
    License as published by the Free Software Foundation; either
@@ -108,6 +108,7 @@ static int remove_from_list(struct tdb_context *tdb,
                            const struct tdb_free_record *r)
 {
        tdb_off_t off;
+       enum TDB_ERROR ecode;
 
        /* Front of list? */
        if (frec_prev(r) == 0) {
@@ -118,7 +119,7 @@ static int remove_from_list(struct tdb_context *tdb,
 
 #ifdef CCAN_TDB2_DEBUG
        if (tdb_read_off(tdb, off) != r_off) {
-               tdb_logerr(tdb, TDB_ERR_CORRUPT, TDB_DEBUG_FATAL,
+               tdb_logerr(tdb, TDB_ERR_CORRUPT, TDB_LOG_ERROR,
                         "remove_from_list: %llu bad prev in list %llu",
                         (long long)r_off, (long long)b_off);
                return -1;
@@ -126,7 +127,9 @@ static int remove_from_list(struct tdb_context *tdb,
 #endif
 
        /* r->prev->next = r->next */
-       if (tdb_write_off(tdb, off, r->next)) {
+       ecode = tdb_write_off(tdb, off, r->next);
+       if (ecode != TDB_SUCCESS) {
+               tdb->ecode = ecode;
                return -1;
        }
 
@@ -136,14 +139,16 @@ static int remove_from_list(struct tdb_context *tdb,
 
 #ifdef CCAN_TDB2_DEBUG
                if (tdb_read_off(tdb, off) & TDB_OFF_MASK != r_off) {
-                       tdb_logerr(tdb, TDB_ERR_CORRUPT, TDB_DEBUG_FATAL,
+                       tdb_logerr(tdb, TDB_ERR_CORRUPT, TDB_LOG_ERROR,
                                   "remove_from_list: %llu bad list %llu",
                                   (long long)r_off, (long long)b_off);
                        return -1;
                }
 #endif
 
-               if (tdb_write_off(tdb, off, r->magic_and_prev)) {
+               ecode = tdb_write_off(tdb, off, r->magic_and_prev);
+               if (ecode != TDB_SUCCESS) {
+                       tdb->ecode = ecode;
                        return -1;
                }
        }
@@ -157,6 +162,7 @@ static int enqueue_in_free(struct tdb_context *tdb,
                           tdb_len_t len)
 {
        struct tdb_free_record new;
+       enum TDB_ERROR ecode;
        uint64_t magic = (TDB_FREE_MAGIC << (64 - TDB_OFF_UPPER_STEAL));
 
        /* We only need to set ftable_and_len; rest is set in enqueue_in_free */
@@ -176,7 +182,7 @@ static int enqueue_in_free(struct tdb_context *tdb,
                                 new.next + offsetof(struct tdb_free_record,
                                                     magic_and_prev))
                    != magic) {
-                       tdb_logerr(tdb, TDB_ERR_CORRUPT, TDB_DEBUG_FATAL,
+                       tdb_logerr(tdb, TDB_ERR_CORRUPT, TDB_LOG_ERROR,
                                   "enqueue_in_free: %llu bad head"
                                   " prev %llu",
                                   (long long)new.next, (long long)b_off);
@@ -184,17 +190,28 @@ static int enqueue_in_free(struct tdb_context *tdb,
                }
 #endif
                /* next->prev = new. */
-               if (tdb_write_off(tdb, new.next
-                                 + offsetof(struct tdb_free_record,
-                                            magic_and_prev),
-                                 off | magic) != 0)
+               ecode = tdb_write_off(tdb, new.next
+                                     + offsetof(struct tdb_free_record,
+                                                magic_and_prev),
+                                     off | magic);
+               if (ecode != TDB_SUCCESS) {
+                       tdb->ecode = ecode;
                        return -1;
+               }
        }
        /* head = new */
-       if (tdb_write_off(tdb, b_off, off) != 0)
+       ecode = tdb_write_off(tdb, b_off, off);
+       if (ecode != TDB_SUCCESS) {
+               tdb->ecode = ecode;
                return -1;
+       }
 
-       return tdb_write_convert(tdb, off, &new, sizeof(new));
+       ecode = tdb_write_convert(tdb, off, &new, sizeof(new));
+       if (ecode != TDB_SUCCESS) {
+               tdb->ecode = ecode;
+               return -1;
+       }
+       return 0;
 }
 
 /* List need not be locked. */
@@ -204,14 +221,18 @@ int add_free_record(struct tdb_context *tdb,
        tdb_off_t b_off;
        tdb_len_t len;
        int ret;
+       enum TDB_ERROR ecode;
 
        assert(len_with_header >= sizeof(struct tdb_free_record));
 
        len = len_with_header - sizeof(struct tdb_used_record);
 
        b_off = bucket_off(tdb->ftable_off, size_to_bucket(len));
-       if (tdb_lock_free_bucket(tdb, b_off, TDB_LOCK_WAIT) != 0)
+       ecode = tdb_lock_free_bucket(tdb, b_off, TDB_LOCK_WAIT);
+       if (ecode != TDB_SUCCESS) {
+               tdb->ecode = ecode;
                return -1;
+       }
 
        ret = enqueue_in_free(tdb, b_off, off, len);
        tdb_unlock_free_bucket(tdb, b_off);
@@ -265,6 +286,7 @@ static int coalesce(struct tdb_context *tdb,
 {
        tdb_off_t end;
        struct tdb_free_record rec;
+       enum TDB_ERROR ecode;
 
        add_stat(tdb, alloc_coalesce_tried, 1);
        end = off + sizeof(struct tdb_used_record) + data_len;
@@ -275,8 +297,10 @@ static int coalesce(struct tdb_context *tdb,
                unsigned ftable, bucket;
 
                r = tdb_access_read(tdb, end, sizeof(*r), true);
-               if (!r)
+               if (TDB_PTR_IS_ERR(r)) {
+                       tdb->ecode = TDB_PTR_ERR(r);
                        goto err;
+               }
 
                if (frec_magic(r) != TDB_FREE_MAGIC
                    || frec_ftable(r) == TDB_FTABLE_NONE) {
@@ -290,13 +314,16 @@ static int coalesce(struct tdb_context *tdb,
                tdb_access_release(tdb, r);
 
                /* We may be violating lock order here, so best effort. */
-               if (tdb_lock_free_bucket(tdb, nb_off, TDB_LOCK_NOWAIT) == -1) {
+               if (tdb_lock_free_bucket(tdb, nb_off, TDB_LOCK_NOWAIT)
+                   != TDB_SUCCESS) {
                        add_stat(tdb, alloc_coalesce_lockfail, 1);
                        break;
                }
 
                /* Now we have lock, re-check. */
-               if (tdb_read_convert(tdb, end, &rec, sizeof(rec))) {
+               ecode = tdb_read_convert(tdb, end, &rec, sizeof(rec));
+               if (ecode != TDB_SUCCESS) {
+                       tdb->ecode = ecode;
                        tdb_unlock_free_bucket(tdb, nb_off);
                        goto err;
                }
@@ -329,11 +356,14 @@ static int coalesce(struct tdb_context *tdb,
                return 0;
 
        /* OK, expand initial record */
-       if (tdb_read_convert(tdb, off, &rec, sizeof(rec)))
+       ecode = tdb_read_convert(tdb, off, &rec, sizeof(rec));
+       if (ecode != TDB_SUCCESS) {
+               tdb->ecode = ecode;
                goto err;
+       }
 
        if (frec_len(&rec) != data_len) {
-               tdb_logerr(tdb, TDB_ERR_CORRUPT, TDB_DEBUG_FATAL,
+               tdb_logerr(tdb, TDB_ERR_CORRUPT, TDB_LOG_ERROR,
                           "coalesce: expected data len %zu not %zu",
                           (size_t)data_len, (size_t)frec_len(&rec));
                goto err;
@@ -346,10 +376,13 @@ static int coalesce(struct tdb_context *tdb,
         * doesn't get coalesced by someone else! */
        rec.ftable_and_len = (TDB_FTABLE_NONE << (64 - TDB_OFF_UPPER_STEAL))
                | (end - off - sizeof(struct tdb_used_record));
-       if (tdb_write_off(tdb, off + offsetof(struct tdb_free_record,
-                                             ftable_and_len),
-                         rec.ftable_and_len) != 0)
+       ecode = tdb_write_off(tdb, off + offsetof(struct tdb_free_record,
+                                                 ftable_and_len),
+                             rec.ftable_and_len);
+       if (ecode != TDB_SUCCESS) {
+               tdb->ecode = ecode;
                goto err;
+       }
 
        add_stat(tdb, alloc_coalesce_succeeded, 1);
        tdb_unlock_free_bucket(tdb, b_off);
@@ -377,6 +410,7 @@ static tdb_off_t lock_and_alloc(struct tdb_context *tdb,
        struct tdb_free_record best = { 0 };
        double multiplier;
        size_t size = adjust_size(keylen, datalen);
+       enum TDB_ERROR ecode;
 
        add_stat(tdb, allocs, 1);
 again:
@@ -384,7 +418,9 @@ again:
 
        /* FIXME: Try non-blocking wait first, to measure contention. */
        /* Lock this bucket. */
-       if (tdb_lock_free_bucket(tdb, b_off, TDB_LOCK_WAIT) == -1) {
+       ecode = tdb_lock_free_bucket(tdb, b_off, TDB_LOCK_WAIT);
+       if (ecode != TDB_SUCCESS) {
+               tdb->ecode = ecode;
                return TDB_OFF_ERR;
        }
 
@@ -409,12 +445,14 @@ again:
                tdb_off_t next;
 
                r = tdb_access_read(tdb, off, sizeof(*r), true);
-               if (!r)
+               if (TDB_PTR_IS_ERR(r)) {
+                       tdb->ecode = TDB_PTR_ERR(r);
                        goto unlock_err;
+               }
 
                if (frec_magic(r) != TDB_FREE_MAGIC) {
                        tdb_access_release(tdb, r);
-                       tdb_logerr(tdb, TDB_ERR_CORRUPT, TDB_DEBUG_FATAL,
+                       tdb_logerr(tdb, TDB_ERR_CORRUPT, TDB_LOG_ERROR,
                                 "lock_and_alloc: %llu non-free 0x%llx",
                                 (long long)off, (long long)r->magic_and_prev);
                        goto unlock_err;
@@ -467,8 +505,11 @@ again:
                               frec_len(&best) - leftover, hashlow) != 0)
                        goto unlock_err;
 
-               if (tdb_write_convert(tdb, best_off, &rec, sizeof(rec)) != 0)
+               ecode = tdb_write_convert(tdb, best_off, &rec, sizeof(rec));
+               if (ecode != TDB_SUCCESS) {
+                       tdb->ecode = ecode;
                        goto unlock_err;
+               }
 
                /* Bucket of leftover will be <= current bucket, so nested
                 * locking is allowed. */
@@ -567,7 +608,7 @@ int set_header(struct tdb_context *tdb,
        if (rec_key_length(rec) != keylen
            || rec_data_length(rec) != datalen
            || rec_extra_padding(rec) != actuallen - (keylen + datalen)) {
-               tdb_logerr(tdb, TDB_ERR_IO, TDB_DEBUG_ERROR,
+               tdb_logerr(tdb, TDB_ERR_IO, TDB_LOG_ERROR,
                         "Could not encode k=%llu,d=%llu,a=%llu",
                         (long long)keylen, (long long)datalen,
                         (long long)actuallen);
@@ -581,6 +622,7 @@ static int tdb_expand(struct tdb_context *tdb, tdb_len_t size)
 {
        uint64_t old_size;
        tdb_len_t wanted;
+       enum TDB_ERROR ecode;
 
        /* We need room for the record header too. */
        wanted = sizeof(struct tdb_used_record) + size;
@@ -588,7 +630,7 @@ static int tdb_expand(struct tdb_context *tdb, tdb_len_t size)
        /* Need to hold a hash lock to expand DB: transactions rely on it. */
        if (!(tdb->flags & TDB_NOLOCK)
            && !tdb->allrecord_lock.count && !tdb_has_hash_locks(tdb)) {
-               tdb_logerr(tdb, TDB_ERR_LOCK, TDB_DEBUG_ERROR,
+               tdb_logerr(tdb, TDB_ERR_LOCK, TDB_LOG_ERROR,
                           "tdb_expand: must hold lock during expand");
                return -1;
        }
@@ -602,8 +644,11 @@ static int tdb_expand(struct tdb_context *tdb, tdb_len_t size)
        wanted = adjust_size(0, wanted);
 
        /* Only one person can expand file at a time. */
-       if (tdb_lock_expand(tdb, F_WRLCK) != 0)
+       ecode = tdb_lock_expand(tdb, F_WRLCK);
+       if (ecode != TDB_SUCCESS) {
+               tdb->ecode = ecode;
                return -1;
+       }
 
        /* Someone else may have expanded the file, so retry. */
        old_size = tdb->map_size;
@@ -613,7 +658,9 @@ static int tdb_expand(struct tdb_context *tdb, tdb_len_t size)
                return 0;
        }
 
-       if (tdb->methods->expand_file(tdb, wanted) == -1) {
+       ecode = tdb->methods->expand_file(tdb, wanted);
+       if (ecode != TDB_SUCCESS) {
+               tdb->ecode = ecode;
                tdb_unlock_expand(tdb, F_WRLCK);
                return -1;
        }