- tdb_len_t recovery_size;
- unsigned char *data, *p;
- const struct tdb_methods *methods = tdb->transaction->io_methods;
- struct tdb_recovery_record *rec;
- tdb_off_t recovery_offset, recovery_max_size;
- tdb_off_t old_map_size = tdb->transaction->old_map_size;
- uint64_t magic, tailer;
- int i;
-
- /*
- check that the recovery area has enough space
- */
- if (tdb_recovery_allocate(tdb, &recovery_size,
- &recovery_offset, &recovery_max_size) == -1) {
- return -1;
- }
-
- data = (unsigned char *)malloc(recovery_size + sizeof(*rec));
- if (data == NULL) {
- tdb_logerr(tdb, TDB_ERR_OOM, TDB_DEBUG_FATAL,
- "transaction_setup_recovery: cannot allocate");
- return -1;
- }
-
- rec = (struct tdb_recovery_record *)data;
- set_recovery_header(rec, TDB_RECOVERY_INVALID_MAGIC,
- recovery_size, recovery_max_size, old_map_size);
- tdb_convert(tdb, rec, sizeof(*rec));
-
- /* build the recovery data into a single blob to allow us to do a single
- large write, which should be more efficient */
- p = data + sizeof(*rec);
- for (i=0;i<tdb->transaction->num_blocks;i++) {
- tdb_off_t offset;
- tdb_len_t length;
-
- if (tdb->transaction->blocks[i] == NULL) {
- continue;
- }
+ tdb_len_t recovery_size = 0;
+ tdb_off_t recovery_off = 0;
+ tdb_off_t old_map_size = tdb->tdb2.transaction->old_map_size;
+ struct tdb_recovery_record *recovery;
+ const struct tdb_methods *methods = tdb->tdb2.transaction->io_methods;
+ uint64_t magic;
+ enum TDB_ERROR ecode;
+
+ recovery = alloc_recovery(tdb, &recovery_size);
+ if (TDB_PTR_IS_ERR(recovery))
+ return TDB_PTR_ERR(recovery);
+
+ ecode = tdb_recovery_area(tdb, methods, &recovery_off, recovery);
+ if (ecode) {
+ free(recovery);
+ return ecode;
+ }
+
+ if (recovery->max_len < recovery_size) {
+ /* Not large enough. Free up old recovery area. */
+ if (recovery_off) {
+ tdb->stats.frees++;
+ ecode = add_free_record(tdb, recovery_off,
+ sizeof(*recovery)
+ + recovery->max_len,
+ TDB_LOCK_WAIT, true);
+ free(recovery);
+ if (ecode != TDB_SUCCESS) {
+ return tdb_logerr(tdb, ecode, TDB_LOG_ERROR,
+ "tdb_recovery_allocate:"
+ " failed to free previous"
+ " recovery area");
+ }