Browse Source

tdb2: rework some io.c functions to return enum TDB_ERROR.

Rusty Russell 15 years ago
parent
commit
7d6312518b
8 changed files with 275 additions and 124 deletions
  1. 47 12
      ccan/tdb2/check.c
  2. 43 14
      ccan/tdb2/free.c
  3. 102 28
      ccan/tdb2/hash.c
  4. 45 48
      ccan/tdb2/io.c
  5. 8 7
      ccan/tdb2/private.h
  6. 7 1
      ccan/tdb2/tdb.c
  7. 5 3
      ccan/tdb2/test/run-03-coalesce.c
  8. 18 11
      ccan/tdb2/transaction.c

+ 47 - 12
ccan/tdb2/check.c

@@ -34,9 +34,13 @@ static bool check_header(struct tdb_context *tdb, tdb_off_t *recovery)
 {
 {
 	uint64_t hash_test;
 	uint64_t hash_test;
 	struct tdb_header hdr;
 	struct tdb_header hdr;
+	enum TDB_ERROR ecode;
 
 
-	if (tdb_read_convert(tdb, 0, &hdr, sizeof(hdr)) == -1)
+	ecode = tdb_read_convert(tdb, 0, &hdr, sizeof(hdr));
+	if (ecode != TDB_SUCCESS) {
+		tdb->ecode = ecode;
 		return false;
 		return false;
+	}
 	/* magic food should not be converted, so convert back. */
 	/* magic food should not be converted, so convert back. */
 	tdb_convert(tdb, hdr.magic_food, sizeof(hdr.magic_food));
 	tdb_convert(tdb, hdr.magic_food, sizeof(hdr.magic_food));
 
 
@@ -91,9 +95,13 @@ static bool check_hash_chain(struct tdb_context *tdb,
 			     void *private_data)
 			     void *private_data)
 {
 {
 	struct tdb_used_record rec;
 	struct tdb_used_record rec;
+	enum TDB_ERROR ecode;
 
 
-	if (tdb_read_convert(tdb, off, &rec, sizeof(rec)) == -1)
+	ecode = tdb_read_convert(tdb, off, &rec, sizeof(rec));
+	if (ecode != TDB_SUCCESS) {
+		tdb->ecode = ecode;
 		return false;
 		return false;
+	}
 
 
 	if (rec_magic(&rec) != TDB_CHAIN_MAGIC) {
 	if (rec_magic(&rec) != TDB_CHAIN_MAGIC) {
 		tdb_logerr(tdb, TDB_ERR_CORRUPT, TDB_LOG_ERROR,
 		tdb_logerr(tdb, TDB_ERR_CORRUPT, TDB_LOG_ERROR,
@@ -148,13 +156,17 @@ static bool check_hash_record(struct tdb_context *tdb,
 			      void *private_data)
 			      void *private_data)
 {
 {
 	struct tdb_used_record rec;
 	struct tdb_used_record rec;
+	enum TDB_ERROR ecode;
 
 
 	if (hprefix_bits >= 64)
 	if (hprefix_bits >= 64)
 		return check_hash_chain(tdb, off, hprefix, used, num_used,
 		return check_hash_chain(tdb, off, hprefix, used, num_used,
 					num_found, check, private_data);
 					num_found, check, private_data);
 
 
-	if (tdb_read_convert(tdb, off, &rec, sizeof(rec)) == -1)
+	ecode = tdb_read_convert(tdb, off, &rec, sizeof(rec));
+	if (ecode != TDB_SUCCESS) {
+		tdb->ecode = ecode;
 		return false;
 		return false;
+	}
 
 
 	if (rec_magic(&rec) != TDB_HTABLE_MAGIC) {
 	if (rec_magic(&rec) != TDB_HTABLE_MAGIC) {
 		tdb_logerr(tdb, TDB_ERR_CORRUPT, TDB_LOG_ERROR,
 		tdb_logerr(tdb, TDB_ERR_CORRUPT, TDB_LOG_ERROR,
@@ -219,6 +231,7 @@ static bool check_hash_tree(struct tdb_context *tdb,
 	unsigned int g, b;
 	unsigned int g, b;
 	const tdb_off_t *hash;
 	const tdb_off_t *hash;
 	struct tdb_used_record rec;
 	struct tdb_used_record rec;
+	enum TDB_ERROR ecode;
 
 
 	hash = tdb_access_read(tdb, off,
 	hash = tdb_access_read(tdb, off,
 			       sizeof(tdb_off_t)
 			       sizeof(tdb_off_t)
@@ -269,9 +282,12 @@ static bool check_hash_tree(struct tdb_context *tdb,
 						   (long long)hprefix);
 						   (long long)hprefix);
 					goto fail;
 					goto fail;
 				}
 				}
-				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 fail;
 					goto fail;
+				}
 				goto check;
 				goto check;
 			}
 			}
 
 
@@ -346,8 +362,11 @@ static bool check_hash_tree(struct tdb_context *tdb,
 				}
 				}
 			}
 			}
 
 
-			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 fail;
 				goto fail;
+			}
 
 
 			/* Bottom bits must match header. */
 			/* Bottom bits must match header. */
 			if ((h & ((1 << 11)-1)) != rec_hash(&rec)) {
 			if ((h & ((1 << 11)-1)) != rec_hash(&rec)) {
@@ -466,9 +485,13 @@ static bool check_free_table(struct tdb_context *tdb,
 	struct tdb_freetable ft;
 	struct tdb_freetable ft;
 	tdb_off_t h;
 	tdb_off_t h;
 	unsigned int i;
 	unsigned int i;
+	enum TDB_ERROR ecode;
 
 
-	if (tdb_read_convert(tdb, ftable_off, &ft, sizeof(ft)) == -1)
+	ecode = tdb_read_convert(tdb, ftable_off, &ft, sizeof(ft));
+	if (ecode != TDB_SUCCESS) {
+		tdb->ecode = ecode;
 		return false;
 		return false;
+	}
 
 
 	if (rec_magic(&ft.hdr) != TDB_FTABLE_MAGIC
 	if (rec_magic(&ft.hdr) != TDB_FTABLE_MAGIC
 	    || rec_key_length(&ft.hdr) != 0
 	    || rec_key_length(&ft.hdr) != 0
@@ -487,8 +510,11 @@ static bool check_free_table(struct tdb_context *tdb,
 		for (off = tdb_read_off(tdb, h); off; off = f.next) {
 		for (off = tdb_read_off(tdb, h); off; off = f.next) {
 			if (off == TDB_OFF_ERR)
 			if (off == TDB_OFF_ERR)
 				return false;
 				return false;
-			if (tdb_read_convert(tdb, off, &f, sizeof(f)))
+			ecode = tdb_read_convert(tdb, off, &f, sizeof(f));
+			if (ecode != TDB_SUCCESS) {
+				tdb->ecode = ecode;
 				return false;
 				return false;
+			}
 			if (!check_free(tdb, off, &f, prev, ftable_num, i))
 			if (!check_free(tdb, off, &f, prev, ftable_num, i))
 				return false;
 				return false;
 
 
@@ -537,6 +563,7 @@ static bool check_linear(struct tdb_context *tdb,
 {
 {
 	tdb_off_t off;
 	tdb_off_t off;
 	tdb_len_t len;
 	tdb_len_t len;
+	enum TDB_ERROR ecode;
 	bool found_recovery = false;
 	bool found_recovery = false;
 
 
 	for (off = sizeof(struct tdb_header); off < tdb->map_size; off += len) {
 	for (off = sizeof(struct tdb_header); off < tdb->map_size; off += len) {
@@ -546,15 +573,20 @@ static bool check_linear(struct tdb_context *tdb,
 			struct tdb_recovery_record r;
 			struct tdb_recovery_record r;
 		} rec;
 		} rec;
 		/* r is larger: only get that if we need to. */
 		/* r is larger: only get that if we need to. */
-		if (tdb_read_convert(tdb, off, &rec, sizeof(rec.f)) == -1)
+		ecode = tdb_read_convert(tdb, off, &rec, sizeof(rec.f));
+		if (ecode != TDB_SUCCESS) {
+			tdb->ecode = ecode;
 			return false;
 			return false;
+		}
 
 
 		/* If we crash after ftruncate, we can get zeroes or fill. */
 		/* If we crash after ftruncate, we can get zeroes or fill. */
 		if (rec.r.magic == TDB_RECOVERY_INVALID_MAGIC
 		if (rec.r.magic == TDB_RECOVERY_INVALID_MAGIC
 		    || rec.r.magic ==  0x4343434343434343ULL) {
 		    || rec.r.magic ==  0x4343434343434343ULL) {
-			if (tdb_read_convert(tdb, off, &rec, sizeof(rec.r)))
+			ecode = tdb_read_convert(tdb, off, &rec, sizeof(rec.r));
+			if (ecode != TDB_SUCCESS) {
+				tdb->ecode = ecode;
 				return false;
 				return false;
-
+			}
 			if (recovery == off) {
 			if (recovery == off) {
 				found_recovery = true;
 				found_recovery = true;
 				len = sizeof(rec.r) + rec.r.max_len;
 				len = sizeof(rec.r) + rec.r.max_len;
@@ -575,8 +607,11 @@ static bool check_linear(struct tdb_context *tdb,
 					   (size_t)tdb->map_size);
 					   (size_t)tdb->map_size);
 			}
 			}
 		} else if (rec.r.magic == TDB_RECOVERY_MAGIC) {
 		} else if (rec.r.magic == TDB_RECOVERY_MAGIC) {
-			if (tdb_read_convert(tdb, off, &rec, sizeof(rec.r)))
+			ecode = tdb_read_convert(tdb, off, &rec, sizeof(rec.r));
+			if (ecode != TDB_SUCCESS) {
+				tdb->ecode = ecode;
 				return false;
 				return false;
+			}
 			if (recovery != off) {
 			if (recovery != off) {
 				tdb_logerr(tdb, TDB_ERR_CORRUPT,
 				tdb_logerr(tdb, TDB_ERR_CORRUPT,
 					   TDB_LOG_ERROR,
 					   TDB_LOG_ERROR,

+ 43 - 14
ccan/tdb2/free.c

@@ -108,6 +108,7 @@ static int remove_from_list(struct tdb_context *tdb,
 			    const struct tdb_free_record *r)
 			    const struct tdb_free_record *r)
 {
 {
 	tdb_off_t off;
 	tdb_off_t off;
+	enum TDB_ERROR ecode;
 
 
 	/* Front of list? */
 	/* Front of list? */
 	if (frec_prev(r) == 0) {
 	if (frec_prev(r) == 0) {
@@ -126,7 +127,9 @@ static int remove_from_list(struct tdb_context *tdb,
 #endif
 #endif
 
 
 	/* r->prev->next = r->next */
 	/* 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;
 		return -1;
 	}
 	}
 
 
@@ -143,7 +146,9 @@ static int remove_from_list(struct tdb_context *tdb,
 		}
 		}
 #endif
 #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;
 			return -1;
 		}
 		}
 	}
 	}
@@ -157,6 +162,7 @@ static int enqueue_in_free(struct tdb_context *tdb,
 			   tdb_len_t len)
 			   tdb_len_t len)
 {
 {
 	struct tdb_free_record new;
 	struct tdb_free_record new;
+	enum TDB_ERROR ecode;
 	uint64_t magic = (TDB_FREE_MAGIC << (64 - TDB_OFF_UPPER_STEAL));
 	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 */
 	/* We only need to set ftable_and_len; rest is set in enqueue_in_free */
@@ -184,17 +190,28 @@ static int enqueue_in_free(struct tdb_context *tdb,
 		}
 		}
 #endif
 #endif
 		/* next->prev = new. */
 		/* 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;
 			return -1;
+		}
 	}
 	}
 	/* head = new */
 	/* 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 -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. */
 /* List need not be locked. */
@@ -269,6 +286,7 @@ static int coalesce(struct tdb_context *tdb,
 {
 {
 	tdb_off_t end;
 	tdb_off_t end;
 	struct tdb_free_record rec;
 	struct tdb_free_record rec;
+	enum TDB_ERROR ecode;
 
 
 	add_stat(tdb, alloc_coalesce_tried, 1);
 	add_stat(tdb, alloc_coalesce_tried, 1);
 	end = off + sizeof(struct tdb_used_record) + data_len;
 	end = off + sizeof(struct tdb_used_record) + data_len;
@@ -301,7 +319,9 @@ static int coalesce(struct tdb_context *tdb,
 		}
 		}
 
 
 		/* Now we have lock, re-check. */
 		/* 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);
 			tdb_unlock_free_bucket(tdb, nb_off);
 			goto err;
 			goto err;
 		}
 		}
@@ -334,8 +354,11 @@ static int coalesce(struct tdb_context *tdb,
 		return 0;
 		return 0;
 
 
 	/* OK, expand initial record */
 	/* 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;
 		goto err;
+	}
 
 
 	if (frec_len(&rec) != data_len) {
 	if (frec_len(&rec) != data_len) {
 		tdb_logerr(tdb, TDB_ERR_CORRUPT, TDB_LOG_ERROR,
 		tdb_logerr(tdb, TDB_ERR_CORRUPT, TDB_LOG_ERROR,
@@ -351,10 +374,13 @@ static int coalesce(struct tdb_context *tdb,
 	 * doesn't get coalesced by someone else! */
 	 * doesn't get coalesced by someone else! */
 	rec.ftable_and_len = (TDB_FTABLE_NONE << (64 - TDB_OFF_UPPER_STEAL))
 	rec.ftable_and_len = (TDB_FTABLE_NONE << (64 - TDB_OFF_UPPER_STEAL))
 		| (end - off - sizeof(struct tdb_used_record));
 		| (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;
 		goto err;
+	}
 
 
 	add_stat(tdb, alloc_coalesce_succeeded, 1);
 	add_stat(tdb, alloc_coalesce_succeeded, 1);
 	tdb_unlock_free_bucket(tdb, b_off);
 	tdb_unlock_free_bucket(tdb, b_off);
@@ -475,8 +501,11 @@ again:
 			       frec_len(&best) - leftover, hashlow) != 0)
 			       frec_len(&best) - leftover, hashlow) != 0)
 			goto unlock_err;
 			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;
 			goto unlock_err;
+		}
 
 
 		/* Bucket of leftover will be <= current bucket, so nested
 		/* Bucket of leftover will be <= current bucket, so nested
 		 * locking is allowed. */
 		 * locking is allowed. */

+ 102 - 28
ccan/tdb2/hash.c

@@ -110,6 +110,7 @@ static bool match(struct tdb_context *tdb,
 		  struct tdb_used_record *rec)
 		  struct tdb_used_record *rec)
 {
 {
 	tdb_off_t off;
 	tdb_off_t off;
+	enum TDB_ERROR ecode;
 
 
 	add_stat(tdb, compares, 1);
 	add_stat(tdb, compares, 1);
 	/* Desired bucket must match. */
 	/* Desired bucket must match. */
@@ -127,8 +128,11 @@ static bool match(struct tdb_context *tdb,
 	}
 	}
 
 
 	off = val & TDB_OFF_MASK;
 	off = val & TDB_OFF_MASK;
-	if (tdb_read_convert(tdb, off, rec, sizeof(*rec)) == -1)
+	ecode = tdb_read_convert(tdb, off, rec, sizeof(*rec));
+	if (ecode != TDB_SUCCESS) {
+		tdb->ecode = ecode;
 		return false;
 		return false;
+	}
 
 
 	if ((h->h & ((1 << 11)-1)) != rec_hash(rec)) {
 	if ((h->h & ((1 << 11)-1)) != rec_hash(rec)) {
 		add_stat(tdb, compare_wrong_rechash, 1);
 		add_stat(tdb, compare_wrong_rechash, 1);
@@ -164,6 +168,7 @@ static tdb_off_t COLD find_in_chain(struct tdb_context *tdb,
 				    struct traverse_info *tinfo)
 				    struct traverse_info *tinfo)
 {
 {
 	tdb_off_t off, next;
 	tdb_off_t off, next;
+	enum TDB_ERROR ecode;
 
 
 	/* In case nothing is free, we set these to zero. */
 	/* In case nothing is free, we set these to zero. */
 	h->home_bucket = h->found_bucket = 0;
 	h->home_bucket = h->found_bucket = 0;
@@ -172,8 +177,11 @@ static tdb_off_t COLD find_in_chain(struct tdb_context *tdb,
 		unsigned int i;
 		unsigned int i;
 
 
 		h->group_start = off;
 		h->group_start = off;
-		if (tdb_read_convert(tdb, off, h->group, sizeof(h->group)))
+		ecode = tdb_read_convert(tdb, off, h->group, sizeof(h->group));
+		if (ecode != TDB_SUCCESS) {
+			tdb->ecode = ecode;
 			return TDB_OFF_ERR;
 			return TDB_OFF_ERR;
+		}
 
 
 		for (i = 0; i < (1 << TDB_HASH_GROUP_BITS); i++) {
 		for (i = 0; i < (1 << TDB_HASH_GROUP_BITS); i++) {
 			tdb_off_t recoff;
 			tdb_off_t recoff;
@@ -186,8 +194,12 @@ static tdb_off_t COLD find_in_chain(struct tdb_context *tdb,
 			/* We can insert extra bits via add_to_hash
 			/* We can insert extra bits via add_to_hash
 			 * empty bucket logic. */
 			 * empty bucket logic. */
 			recoff = h->group[i] & TDB_OFF_MASK;
 			recoff = h->group[i] & TDB_OFF_MASK;
-			if (tdb_read_convert(tdb, recoff, rec, sizeof(*rec)))
+			ecode = tdb_read_convert(tdb, recoff, rec,
+						 sizeof(*rec));
+			if (ecode != TDB_SUCCESS) {
+				tdb->ecode = ecode;
 				return TDB_OFF_ERR;
 				return TDB_OFF_ERR;
+			}
 
 
 			if (key_matches(tdb, rec, recoff, &key)) {
 			if (key_matches(tdb, rec, recoff, &key)) {
 				h->home_bucket = h->found_bucket = i;
 				h->home_bucket = h->found_bucket = i;
@@ -259,9 +271,12 @@ tdb_off_t find_and_lock(struct tdb_context *tdb,
 		h->group_start = hashtable
 		h->group_start = hashtable
 			+ group * (sizeof(tdb_off_t) << TDB_HASH_GROUP_BITS);
 			+ group * (sizeof(tdb_off_t) << TDB_HASH_GROUP_BITS);
 
 
-		if (tdb_read_convert(tdb, h->group_start, &h->group,
-				     sizeof(h->group)) == -1)
+		ecode = tdb_read_convert(tdb, h->group_start, &h->group,
+					 sizeof(h->group));
+		if (ecode != TDB_SUCCESS) {
+			tdb->ecode = ecode;
 			goto fail;
 			goto fail;
+		}
 
 
 		/* Pointer to another hash table?  Go down... */
 		/* Pointer to another hash table?  Go down... */
 		if (is_subhash(h->group[h->home_bucket])) {
 		if (is_subhash(h->group[h->home_bucket])) {
@@ -393,8 +408,15 @@ int replace_in_hash(struct tdb_context *tdb,
 		    struct hash_info *h,
 		    struct hash_info *h,
 		    tdb_off_t new_off)
 		    tdb_off_t new_off)
 {
 {
-	return tdb_write_off(tdb, hbucket_off(h->group_start, h->found_bucket),
-			     encode_offset(new_off, h));
+	enum TDB_ERROR ecode;
+
+	ecode = tdb_write_off(tdb, hbucket_off(h->group_start, h->found_bucket),
+			      encode_offset(new_off, h));
+	if (ecode != TDB_SUCCESS) {
+		tdb->ecode = ecode;
+		return -1;
+	}
+	return 0;
 }
 }
 
 
 /* We slot in anywhere that's empty in the chain. */
 /* We slot in anywhere that's empty in the chain. */
@@ -403,6 +425,7 @@ static int COLD add_to_chain(struct tdb_context *tdb,
 			     tdb_off_t new_off)
 			     tdb_off_t new_off)
 {
 {
 	size_t entry = tdb_find_zero_off(tdb, subhash, 1<<TDB_HASH_GROUP_BITS);
 	size_t entry = tdb_find_zero_off(tdb, subhash, 1<<TDB_HASH_GROUP_BITS);
+	enum TDB_ERROR ecode;
 
 
 	if (entry == 1 << TDB_HASH_GROUP_BITS) {
 	if (entry == 1 << TDB_HASH_GROUP_BITS) {
 		tdb_off_t next;
 		tdb_off_t next;
@@ -417,19 +440,32 @@ static int COLD add_to_chain(struct tdb_context *tdb,
 				     TDB_CHAIN_MAGIC, false);
 				     TDB_CHAIN_MAGIC, false);
 			if (next == TDB_OFF_ERR)
 			if (next == TDB_OFF_ERR)
 				return -1;
 				return -1;
-			if (zero_out(tdb, next+sizeof(struct tdb_used_record),
-				     sizeof(struct tdb_chain)))
+			ecode = zero_out(tdb,
+					 next+sizeof(struct tdb_used_record),
+					 sizeof(struct tdb_chain));
+			if (ecode != TDB_SUCCESS) {
+				tdb->ecode = ecode;
 				return -1;
 				return -1;
-			if (tdb_write_off(tdb, subhash
-					  + offsetof(struct tdb_chain, next),
-					  next) != 0)
+			}
+			ecode = tdb_write_off(tdb, subhash
+					      + offsetof(struct tdb_chain,
+							 next),
+					      next);
+			if (ecode != TDB_SUCCESS) {
+				tdb->ecode = ecode;
 				return -1;
 				return -1;
+			}
 		}
 		}
 		return add_to_chain(tdb, next, new_off);
 		return add_to_chain(tdb, next, new_off);
 	}
 	}
 
 
-	return tdb_write_off(tdb, subhash + entry * sizeof(tdb_off_t),
-			     new_off);
+	ecode = tdb_write_off(tdb, subhash + entry * sizeof(tdb_off_t),
+			      new_off);
+	if (ecode != TDB_SUCCESS) {
+		tdb->ecode = ecode;
+		return -1;
+	}
+	return 0;
 }
 }
 
 
 /* Add into a newly created subhash. */
 /* Add into a newly created subhash. */
@@ -439,6 +475,7 @@ static int add_to_subhash(struct tdb_context *tdb, tdb_off_t subhash,
 	tdb_off_t off = (val & TDB_OFF_MASK), *group;
 	tdb_off_t off = (val & TDB_OFF_MASK), *group;
 	struct hash_info h;
 	struct hash_info h;
 	unsigned int gnum;
 	unsigned int gnum;
+	enum TDB_ERROR ecode;
 
 
 	h.hash_used = hash_used;
 	h.hash_used = hash_used;
 
 
@@ -456,7 +493,12 @@ static int add_to_subhash(struct tdb_context *tdb, tdb_off_t subhash,
 	if (!group)
 	if (!group)
 		return -1;
 		return -1;
 	force_into_group(group, h.home_bucket, encode_offset(off, &h));
 	force_into_group(group, h.home_bucket, encode_offset(off, &h));
-	return tdb_access_commit(tdb, group);
+	ecode = tdb_access_commit(tdb, group);
+	if (ecode != TDB_SUCCESS) {
+		tdb->ecode = ecode;
+		return -1;
+	}
+	return 0;
 }
 }
 
 
 static int expand_group(struct tdb_context *tdb, struct hash_info *h)
 static int expand_group(struct tdb_context *tdb, struct hash_info *h)
@@ -465,6 +507,7 @@ static int expand_group(struct tdb_context *tdb, struct hash_info *h)
 	size_t subsize;
 	size_t subsize;
 	tdb_off_t subhash;
 	tdb_off_t subhash;
 	tdb_off_t vals[1 << TDB_HASH_GROUP_BITS];
 	tdb_off_t vals[1 << TDB_HASH_GROUP_BITS];
+	enum TDB_ERROR ecode;
 
 
 	/* Attach new empty subhash under fullest bucket. */
 	/* Attach new empty subhash under fullest bucket. */
 	bucket = fullest_bucket(tdb, h->group, h->home_bucket);
 	bucket = fullest_bucket(tdb, h->group, h->home_bucket);
@@ -483,8 +526,12 @@ static int expand_group(struct tdb_context *tdb, struct hash_info *h)
 	if (subhash == TDB_OFF_ERR)
 	if (subhash == TDB_OFF_ERR)
 		return -1;
 		return -1;
 
 
-	if (zero_out(tdb, subhash + sizeof(struct tdb_used_record), subsize))
+	ecode = zero_out(tdb, subhash + sizeof(struct tdb_used_record),
+			 subsize);
+	if (ecode != TDB_SUCCESS) {
+		tdb->ecode = ecode;
 		return -1;
 		return -1;
+	}
 
 
 	/* Remove any which are destined for bucket or are in wrong place. */
 	/* Remove any which are destined for bucket or are in wrong place. */
 	num_vals = 0;
 	num_vals = 0;
@@ -525,6 +572,7 @@ int delete_from_hash(struct tdb_context *tdb, struct hash_info *h)
 {
 {
 	unsigned int i, num_movers = 0;
 	unsigned int i, num_movers = 0;
 	tdb_off_t movers[1 << TDB_HASH_GROUP_BITS];
 	tdb_off_t movers[1 << TDB_HASH_GROUP_BITS];
+	enum TDB_ERROR ecode;
 
 
 	h->group[h->found_bucket] = 0;
 	h->group[h->found_bucket] = 0;
 	for (i = 1; i < (1 << TDB_HASH_GROUP_BITS); i++) {
 	for (i = 1; i < (1 << TDB_HASH_GROUP_BITS); i++) {
@@ -554,18 +602,30 @@ int delete_from_hash(struct tdb_context *tdb, struct hash_info *h)
 	}
 	}
 
 
 	/* Now we write back the hash group */
 	/* Now we write back the hash group */
-	return tdb_write_convert(tdb, h->group_start,
-				 h->group, sizeof(h->group));
+	ecode = tdb_write_convert(tdb, h->group_start,
+				  h->group, sizeof(h->group));
+	if (ecode != TDB_SUCCESS) {
+		tdb->ecode = ecode;
+		return -1;
+	}
+	return 0;
 }
 }
 
 
 int add_to_hash(struct tdb_context *tdb, struct hash_info *h, tdb_off_t new_off)
 int add_to_hash(struct tdb_context *tdb, struct hash_info *h, tdb_off_t new_off)
 {
 {
+	enum TDB_ERROR ecode;
+
 	/* We hit an empty bucket during search?  That's where it goes. */
 	/* We hit an empty bucket during search?  That's where it goes. */
 	if (!h->group[h->found_bucket]) {
 	if (!h->group[h->found_bucket]) {
 		h->group[h->found_bucket] = encode_offset(new_off, h);
 		h->group[h->found_bucket] = encode_offset(new_off, h);
 		/* Write back the modified group. */
 		/* Write back the modified group. */
-		return tdb_write_convert(tdb, h->group_start,
-					 h->group, sizeof(h->group));
+		ecode = tdb_write_convert(tdb, h->group_start,
+					  h->group, sizeof(h->group));
+		if (ecode != TDB_SUCCESS) {
+			tdb->ecode = ecode;
+			return -1;
+		}
+		return 0;
 	}
 	}
 
 
 	if (h->hash_used > 64)
 	if (h->hash_used > 64)
@@ -581,9 +641,12 @@ int add_to_hash(struct tdb_context *tdb, struct hash_info *h, tdb_off_t new_off)
 		unsigned int gnum;
 		unsigned int gnum;
 
 
 		/* Write back the modified group. */
 		/* Write back the modified group. */
-		if (tdb_write_convert(tdb, h->group_start, h->group,
-				      sizeof(h->group)))
+		ecode = tdb_write_convert(tdb, h->group_start, h->group,
+					  sizeof(h->group));
+		if (ecode != TDB_SUCCESS) {
+			tdb->ecode = ecode;
 			return -1;
 			return -1;
+		}
 
 
 		/* Move hashinfo down a level. */
 		/* Move hashinfo down a level. */
 		hashtable = (h->group[h->home_bucket] & TDB_OFF_MASK)
 		hashtable = (h->group[h->home_bucket] & TDB_OFF_MASK)
@@ -592,16 +655,25 @@ int add_to_hash(struct tdb_context *tdb, struct hash_info *h, tdb_off_t new_off)
 		h->home_bucket = use_bits(h, TDB_HASH_GROUP_BITS);
 		h->home_bucket = use_bits(h, TDB_HASH_GROUP_BITS);
 		h->group_start = hashtable
 		h->group_start = hashtable
 			+ gnum * (sizeof(tdb_off_t) << TDB_HASH_GROUP_BITS);
 			+ gnum * (sizeof(tdb_off_t) << TDB_HASH_GROUP_BITS);
-		if (tdb_read_convert(tdb, h->group_start, &h->group,
-				     sizeof(h->group)) == -1)
+		ecode = tdb_read_convert(tdb, h->group_start, &h->group,
+					 sizeof(h->group));
+		if (ecode != TDB_SUCCESS) {
+			tdb->ecode = ecode;
 			return -1;
 			return -1;
+		}
 	}
 	}
 
 
 	/* Expanding the group must have made room if it didn't choose this
 	/* Expanding the group must have made room if it didn't choose this
 	 * bucket. */
 	 * bucket. */
-	if (put_into_group(h->group, h->home_bucket, encode_offset(new_off, h)))
-		return tdb_write_convert(tdb, h->group_start,
-					 h->group, sizeof(h->group));
+	if (put_into_group(h->group, h->home_bucket, encode_offset(new_off,h))){
+		ecode = tdb_write_convert(tdb, h->group_start,
+					  h->group, sizeof(h->group));
+		if (ecode != TDB_SUCCESS) {
+			tdb->ecode = ecode;
+			return -1;
+		}
+		return 0;
+	}
 
 
 	/* This can happen if all hashes in group (and us) dropped into same
 	/* This can happen if all hashes in group (and us) dropped into same
 	 * group in subhash. */
 	 * group in subhash. */
@@ -705,7 +777,9 @@ int next_in_hash(struct tdb_context *tdb,
 		if (off) {
 		if (off) {
 			struct tdb_used_record rec;
 			struct tdb_used_record rec;
 
 
-			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;
 				tdb_unlock_hashes(tdb,
 				tdb_unlock_hashes(tdb,
 						  hl_start, hl_range, F_RDLCK);
 						  hl_start, hl_range, F_RDLCK);
 				return -1;
 				return -1;

+ 45 - 48
ccan/tdb2/io.c

@@ -174,33 +174,33 @@ uint64_t tdb_find_zero_off(struct tdb_context *tdb, tdb_off_t off,
 	return i;
 	return i;
 }
 }
 
 
-int zero_out(struct tdb_context *tdb, tdb_off_t off, tdb_len_t len)
+enum TDB_ERROR zero_out(struct tdb_context *tdb, tdb_off_t off, tdb_len_t len)
 {
 {
 	char buf[8192] = { 0 };
 	char buf[8192] = { 0 };
 	void *p = tdb->methods->direct(tdb, off, len, true);
 	void *p = tdb->methods->direct(tdb, off, len, true);
-	enum TDB_ERROR ecode;
+	enum TDB_ERROR ecode = TDB_SUCCESS;
 
 
 	assert(!tdb->read_only);
 	assert(!tdb->read_only);
 	if (p) {
 	if (p) {
 		memset(p, 0, len);
 		memset(p, 0, len);
-		return 0;
+		return ecode;
 	}
 	}
 	while (len) {
 	while (len) {
 		unsigned todo = len < sizeof(buf) ? len : sizeof(buf);
 		unsigned todo = len < sizeof(buf) ? len : sizeof(buf);
 		ecode = tdb->methods->twrite(tdb, off, buf, todo);
 		ecode = tdb->methods->twrite(tdb, off, buf, todo);
 		if (ecode != TDB_SUCCESS) {
 		if (ecode != TDB_SUCCESS) {
-			tdb->ecode = ecode;
-			return -1;
+			break;
 		}
 		}
 		len -= todo;
 		len -= todo;
 		off += todo;
 		off += todo;
 	}
 	}
-	return 0;
+	return ecode;
 }
 }
 
 
 tdb_off_t tdb_read_off(struct tdb_context *tdb, tdb_off_t off)
 tdb_off_t tdb_read_off(struct tdb_context *tdb, tdb_off_t off)
 {
 {
 	tdb_off_t ret;
 	tdb_off_t ret;
+	enum TDB_ERROR ecode;
 
 
 	if (likely(!(tdb->flags & TDB_CONVERT))) {
 	if (likely(!(tdb->flags & TDB_CONVERT))) {
 		tdb_off_t *p = tdb->methods->direct(tdb, off, sizeof(*p),
 		tdb_off_t *p = tdb->methods->direct(tdb, off, sizeof(*p),
@@ -209,8 +209,11 @@ tdb_off_t tdb_read_off(struct tdb_context *tdb, tdb_off_t off)
 			return *p;
 			return *p;
 	}
 	}
 
 
-	if (tdb_read_convert(tdb, off, &ret, sizeof(ret)) == -1)
+	ecode = tdb_read_convert(tdb, off, &ret, sizeof(ret));
+	if (ecode != TDB_SUCCESS) {
+		tdb->ecode = ecode;
 		return TDB_OFF_ERR;
 		return TDB_OFF_ERR;
+	}
 	return ret;
 	return ret;
 }
 }
 
 
@@ -281,18 +284,17 @@ static enum TDB_ERROR tdb_read(struct tdb_context *tdb, tdb_off_t off,
 	return TDB_SUCCESS;
 	return TDB_SUCCESS;
 }
 }
 
 
-int tdb_write_convert(struct tdb_context *tdb, tdb_off_t off,
-		      const void *rec, size_t len)
+enum TDB_ERROR tdb_write_convert(struct tdb_context *tdb, tdb_off_t off,
+				 const void *rec, size_t len)
 {
 {
 	enum TDB_ERROR ecode;
 	enum TDB_ERROR ecode;
 
 
 	if (unlikely((tdb->flags & TDB_CONVERT))) {
 	if (unlikely((tdb->flags & TDB_CONVERT))) {
 		void *conv = malloc(len);
 		void *conv = malloc(len);
 		if (!conv) {
 		if (!conv) {
-			tdb_logerr(tdb, TDB_ERR_OOM, TDB_LOG_ERROR,
-				   "tdb_write: no memory converting"
-				   " %zu bytes", len);
-			return -1;
+			return tdb_logerr(tdb, TDB_ERR_OOM, TDB_LOG_ERROR,
+					  "tdb_write: no memory converting"
+					  " %zu bytes", len);
 		}
 		}
 		memcpy(conv, rec, len);
 		memcpy(conv, rec, len);
 		ecode = tdb->methods->twrite(tdb, off,
 		ecode = tdb->methods->twrite(tdb, off,
@@ -301,32 +303,23 @@ int tdb_write_convert(struct tdb_context *tdb, tdb_off_t off,
 	} else {
 	} else {
 		ecode = tdb->methods->twrite(tdb, off, rec, len);
 		ecode = tdb->methods->twrite(tdb, off, rec, len);
 	}
 	}
-
-	if (ecode != TDB_SUCCESS) {
-		tdb->ecode = ecode;
-		return -1;
-	}
-	return 0;
+	return ecode;
 }
 }
 
 
-int tdb_read_convert(struct tdb_context *tdb, tdb_off_t off,
-		      void *rec, size_t len)
+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->methods->tread(tdb, off, rec, len);
 	tdb_convert(tdb, rec, len);
 	tdb_convert(tdb, rec, len);
-	if (ecode != TDB_SUCCESS) {
-		tdb->ecode = ecode;
-		return -1;
-	}
-	return 0;
+	return ecode;
 }
 }
 
 
-int tdb_write_off(struct tdb_context *tdb, tdb_off_t off, tdb_off_t val)
+enum TDB_ERROR tdb_write_off(struct tdb_context *tdb,
+			     tdb_off_t off, tdb_off_t val)
 {
 {
 	if (tdb->read_only) {
 	if (tdb->read_only) {
-		tdb_logerr(tdb, TDB_ERR_RDONLY, TDB_LOG_USE_ERROR,
-			   "Write to read-only database");
-		return -1;
+		return tdb_logerr(tdb, TDB_ERR_RDONLY, TDB_LOG_USE_ERROR,
+				  "Write to read-only database");
 	}
 	}
 
 
 	if (likely(!(tdb->flags & TDB_CONVERT))) {
 	if (likely(!(tdb->flags & TDB_CONVERT))) {
@@ -334,7 +327,7 @@ int tdb_write_off(struct tdb_context *tdb, tdb_off_t off, tdb_off_t val)
 						    true);
 						    true);
 		if (p) {
 		if (p) {
 			*p = val;
 			*p = val;
-			return 0;
+			return TDB_SUCCESS;
 		}
 		}
 	}
 	}
 	return tdb_write_convert(tdb, off, &val, sizeof(val));
 	return tdb_write_convert(tdb, off, &val, sizeof(val));
@@ -369,9 +362,9 @@ void *tdb_alloc_read(struct tdb_context *tdb, tdb_off_t offset, tdb_len_t len)
 	return _tdb_alloc_read(tdb, offset, len, 0);
 	return _tdb_alloc_read(tdb, offset, len, 0);
 }
 }
 
 
-static int fill(struct tdb_context *tdb,
-		const void *buf, size_t size,
-		tdb_off_t off, tdb_len_t len)
+static enum TDB_ERROR fill(struct tdb_context *tdb,
+			   const void *buf, size_t size,
+			   tdb_off_t off, tdb_len_t len)
 {
 {
 	while (len) {
 	while (len) {
 		size_t n = len > size ? size : len;
 		size_t n = len > size ? size : len;
@@ -380,16 +373,16 @@ static int fill(struct tdb_context *tdb,
 			if (ret >= 0)
 			if (ret >= 0)
 				errno = ENOSPC;
 				errno = ENOSPC;
 
 
-			tdb_logerr(tdb, TDB_ERR_IO, TDB_LOG_ERROR,
-				   "fill failed: %zi at %zu len=%zu (%s)",
-				   ret, (size_t)off, (size_t)len,
-				   strerror(errno));
-			return -1;
+			return tdb_logerr(tdb, TDB_ERR_IO, TDB_LOG_ERROR,
+					  "fill failed:"
+					  " %zi at %zu len=%zu (%s)",
+					  ret, (size_t)off, (size_t)len,
+					  strerror(errno));
 		}
 		}
 		len -= n;
 		len -= n;
 		off += n;
 		off += n;
 	}
 	}
-	return 0;
+	return TDB_SUCCESS;
 }
 }
 
 
 /* expand a file.  we prefer to use ftruncate, as that is what posix
 /* expand a file.  we prefer to use ftruncate, as that is what posix
@@ -398,6 +391,7 @@ static enum TDB_ERROR tdb_expand_file(struct tdb_context *tdb,
 				      tdb_len_t addition)
 				      tdb_len_t addition)
 {
 {
 	char buf[8192];
 	char buf[8192];
+	enum TDB_ERROR ecode;
 
 
 	if (tdb->read_only) {
 	if (tdb->read_only) {
 		return tdb_logerr(tdb, TDB_ERR_RDONLY, TDB_LOG_USE_ERROR,
 		return tdb_logerr(tdb, TDB_ERR_RDONLY, TDB_LOG_USE_ERROR,
@@ -425,8 +419,9 @@ static enum TDB_ERROR tdb_expand_file(struct tdb_context *tdb,
 		   file isn't sparse, which would be very bad if we ran out of
 		   file isn't sparse, which would be very bad if we ran out of
 		   disk. This must be done with write, not via mmap */
 		   disk. This must be done with write, not via mmap */
 		memset(buf, 0x43, sizeof(buf));
 		memset(buf, 0x43, sizeof(buf));
-		if (fill(tdb, buf, sizeof(buf), tdb->map_size, addition) == -1)
-			return tdb->ecode;
+		ecode = fill(tdb, buf, sizeof(buf), tdb->map_size, addition);
+		if (ecode != TDB_SUCCESS)
+			return ecode;
 		tdb->map_size += addition;
 		tdb->map_size += addition;
 		tdb_mmap(tdb);
 		tdb_mmap(tdb);
 	}
 	}
@@ -513,23 +508,25 @@ void tdb_access_release(struct tdb_context *tdb, const void *p)
 		tdb->direct_access--;
 		tdb->direct_access--;
 }
 }
 
 
-int tdb_access_commit(struct tdb_context *tdb, void *p)
+enum TDB_ERROR tdb_access_commit(struct tdb_context *tdb, void *p)
 {
 {
 	struct tdb_access_hdr *hdr, **hp = find_hdr(tdb, p);
 	struct tdb_access_hdr *hdr, **hp = find_hdr(tdb, p);
-	int ret = 0;
+	enum TDB_ERROR ecode;
 
 
 	if (hp) {
 	if (hp) {
 		hdr = *hp;
 		hdr = *hp;
 		if (hdr->convert)
 		if (hdr->convert)
-			ret = tdb_write_convert(tdb, hdr->off, p, hdr->len);
+			ecode = tdb_write_convert(tdb, hdr->off, p, hdr->len);
 		else
 		else
-			ret = tdb_write(tdb, hdr->off, p, hdr->len);
+			ecode = tdb_write(tdb, hdr->off, p, hdr->len);
 		*hp = hdr->next;
 		*hp = hdr->next;
 		free(hdr);
 		free(hdr);
-	} else
+	} else {
 		tdb->direct_access--;
 		tdb->direct_access--;
+		ecode = TDB_SUCCESS;
+	}
 
 
-	return ret;
+	return ecode;
 }
 }
 
 
 static void *tdb_direct(struct tdb_context *tdb, tdb_off_t off, size_t len,
 static void *tdb_direct(struct tdb_context *tdb, tdb_off_t off, size_t len,

+ 8 - 7
ccan/tdb2/private.h

@@ -476,16 +476,17 @@ void *tdb_access_write(struct tdb_context *tdb,
 /* Release result of tdb_access_read/write. */
 /* Release result of tdb_access_read/write. */
 void tdb_access_release(struct tdb_context *tdb, const void *p);
 void tdb_access_release(struct tdb_context *tdb, const void *p);
 /* Commit result of tdb_acces_write. */
 /* Commit result of tdb_acces_write. */
-int tdb_access_commit(struct tdb_context *tdb, void *p);
+enum TDB_ERROR tdb_access_commit(struct tdb_context *tdb, void *p);
 
 
 /* Convenience routine to get an offset. */
 /* Convenience routine to get an offset. */
 tdb_off_t tdb_read_off(struct tdb_context *tdb, tdb_off_t off);
 tdb_off_t tdb_read_off(struct tdb_context *tdb, tdb_off_t off);
 
 
 /* Write an offset at an offset. */
 /* Write an offset at an offset. */
-int tdb_write_off(struct tdb_context *tdb, tdb_off_t off, tdb_off_t val);
+enum TDB_ERROR tdb_write_off(struct tdb_context *tdb, tdb_off_t off,
+			     tdb_off_t val);
 
 
 /* Clear an ondisk area. */
 /* Clear an ondisk area. */
-int zero_out(struct tdb_context *tdb, tdb_off_t off, tdb_len_t len);
+enum TDB_ERROR zero_out(struct tdb_context *tdb, tdb_off_t off, tdb_len_t len);
 
 
 /* Return a non-zero offset between >= start < end in this array (or end). */
 /* Return a non-zero offset between >= start < end in this array (or end). */
 tdb_off_t tdb_find_nonzero_off(struct tdb_context *tdb,
 tdb_off_t tdb_find_nonzero_off(struct tdb_context *tdb,
@@ -501,12 +502,12 @@ tdb_off_t tdb_find_zero_off(struct tdb_context *tdb, tdb_off_t off,
 void *tdb_alloc_read(struct tdb_context *tdb, tdb_off_t offset, tdb_len_t len);
 void *tdb_alloc_read(struct tdb_context *tdb, tdb_off_t offset, tdb_len_t len);
 
 
 /* Writes a converted copy of a record. */
 /* Writes a converted copy of a record. */
-int tdb_write_convert(struct tdb_context *tdb, tdb_off_t off,
-		      const void *rec, size_t len);
+enum TDB_ERROR tdb_write_convert(struct tdb_context *tdb, tdb_off_t off,
+				 const void *rec, size_t len);
 
 
 /* Reads record and converts it */
 /* Reads record and converts it */
-int tdb_read_convert(struct tdb_context *tdb, tdb_off_t off,
-		     void *rec, size_t len);
+enum TDB_ERROR tdb_read_convert(struct tdb_context *tdb, tdb_off_t off,
+				void *rec, size_t len);
 
 
 /* Adds a stat, if it's in range. */
 /* Adds a stat, if it's in range. */
 void add_stat_(struct tdb_context *tdb, uint64_t *stat, size_t val);
 void add_stat_(struct tdb_context *tdb, uint64_t *stat, size_t val);

+ 7 - 1
ccan/tdb2/tdb.c

@@ -413,12 +413,18 @@ static int update_rec_hdr(struct tdb_context *tdb,
 			  uint64_t h)
 			  uint64_t h)
 {
 {
 	uint64_t dataroom = rec_data_length(rec) + rec_extra_padding(rec);
 	uint64_t dataroom = rec_data_length(rec) + rec_extra_padding(rec);
+	enum TDB_ERROR ecode;
 
 
 	if (set_header(tdb, rec, TDB_USED_MAGIC, keylen, datalen,
 	if (set_header(tdb, rec, TDB_USED_MAGIC, keylen, datalen,
 		       keylen + dataroom, h))
 		       keylen + dataroom, h))
 		return -1;
 		return -1;
 
 
-	return tdb_write_convert(tdb, off, rec, sizeof(*rec));
+	ecode = tdb_write_convert(tdb, off, rec, sizeof(*rec));
+	if (ecode != TDB_SUCCESS) {
+		tdb->ecode = ecode;
+		return -1;
+	}
+	return 0;
 }
 }
 
 
 /* Returns -1 on error, 0 on OK */
 /* Returns -1 on error, 0 on OK */

+ 5 - 3
ccan/tdb2/test/run-03-coalesce.c

@@ -12,11 +12,13 @@
 static tdb_len_t free_record_length(struct tdb_context *tdb, tdb_off_t off)
 static tdb_len_t free_record_length(struct tdb_context *tdb, tdb_off_t off)
 {
 {
 	struct tdb_free_record f;
 	struct tdb_free_record f;
+	enum TDB_ERROR ecode;
 
 
-	if (tdb_read_convert(tdb, off, &f, sizeof(f)) != 0)
-		return TDB_OFF_ERR;
+	ecode = tdb_read_convert(tdb, off, &f, sizeof(f));
+	if (ecode != TDB_SUCCESS)
+		return ecode;
 	if (frec_magic(&f) != TDB_FREE_MAGIC)
 	if (frec_magic(&f) != TDB_FREE_MAGIC)
-		return TDB_OFF_ERR;
+		return TDB_ERR_CORRUPT;
 	return frec_len(&f);
 	return frec_len(&f);
 }
 }
 
 

+ 18 - 11
ccan/tdb2/transaction.c

@@ -1121,8 +1121,9 @@ int tdb_transaction_recover(struct tdb_context *tdb)
 	}
 	}
 
 
 	/* read the recovery record */
 	/* read the recovery record */
-	if (tdb_read_convert(tdb, recovery_head, &rec, sizeof(rec)) == -1) {
-		tdb_logerr(tdb, tdb->ecode, TDB_LOG_ERROR,
+	ecode = tdb_read_convert(tdb, recovery_head, &rec, sizeof(rec));
+	if (ecode != TDB_SUCCESS) {
+		tdb_logerr(tdb, ecode, TDB_LOG_ERROR,
 			   "tdb_transaction_recover:"
 			   "tdb_transaction_recover:"
 			   " failed to read recovery record");
 			   " failed to read recovery record");
 		return -1;
 		return -1;
@@ -1193,9 +1194,11 @@ int tdb_transaction_recover(struct tdb_context *tdb)
 
 
 	/* if the recovery area is after the recovered eof then remove it */
 	/* if the recovery area is after the recovered eof then remove it */
 	if (recovery_eof <= recovery_head) {
 	if (recovery_eof <= recovery_head) {
-		if (tdb_write_off(tdb, offsetof(struct tdb_header,recovery), 0)
-		    == -1) {
-			tdb_logerr(tdb, tdb->ecode, TDB_LOG_ERROR,
+		ecode = tdb_write_off(tdb, offsetof(struct tdb_header,
+						    recovery),
+				      0);
+		if (ecode != TDB_SUCCESS) {
+			tdb_logerr(tdb, ecode, TDB_LOG_ERROR,
 				 "tdb_transaction_recover:"
 				 "tdb_transaction_recover:"
 				 " failed to remove recovery head");
 				 " failed to remove recovery head");
 			return -1;
 			return -1;
@@ -1203,11 +1206,12 @@ int tdb_transaction_recover(struct tdb_context *tdb)
 	}
 	}
 
 
 	/* remove the recovery magic */
 	/* remove the recovery magic */
-	if (tdb_write_off(tdb,
-			  recovery_head
-			  + offsetof(struct tdb_recovery_record, magic),
-			  TDB_RECOVERY_INVALID_MAGIC) == -1) {
-		tdb_logerr(tdb, tdb->ecode, TDB_LOG_ERROR,
+	ecode = tdb_write_off(tdb,
+			      recovery_head
+			      + offsetof(struct tdb_recovery_record, magic),
+			      TDB_RECOVERY_INVALID_MAGIC);
+	if (ecode != TDB_SUCCESS) {
+		tdb_logerr(tdb, ecode, TDB_LOG_ERROR,
 			 "tdb_transaction_recover:"
 			 "tdb_transaction_recover:"
 			 " failed to remove recovery magic");
 			 " failed to remove recovery magic");
 		return -1;
 		return -1;
@@ -1233,6 +1237,7 @@ bool tdb_needs_recovery(struct tdb_context *tdb)
 {
 {
 	tdb_off_t recovery_head;
 	tdb_off_t recovery_head;
 	struct tdb_recovery_record rec;
 	struct tdb_recovery_record rec;
+	enum TDB_ERROR ecode;
 
 
 	/* find the recovery area */
 	/* find the recovery area */
 	recovery_head = tdb_read_off(tdb, offsetof(struct tdb_header,recovery));
 	recovery_head = tdb_read_off(tdb, offsetof(struct tdb_header,recovery));
@@ -1246,7 +1251,9 @@ bool tdb_needs_recovery(struct tdb_context *tdb)
 	}
 	}
 
 
 	/* read the recovery record */
 	/* read the recovery record */
-	if (tdb_read_convert(tdb, recovery_head, &rec, sizeof(rec)) == -1) {
+	ecode = tdb_read_convert(tdb, recovery_head, &rec, sizeof(rec));
+	if (ecode != TDB_SUCCESS) {
+		tdb->ecode = ecode;
 		return true;
 		return true;
 	}
 	}