]> git.ozlabs.org Git - ccan/commitdiff
tdb2: handle non-transaction-page-aligned sizes in recovery.
authorRusty Russell <rusty@rustcorp.com.au>
Thu, 21 Apr 2011 01:46:35 +0000 (11:16 +0930)
committerRusty Russell <rusty@rustcorp.com.au>
Thu, 21 Apr 2011 01:46:35 +0000 (11:16 +0930)
tdb1 always makes the tdb a multiple of the transaction page size,
tdb2 doesn't.  This means that if a transaction hits the exact end of
the file, we might need to save off a partial page.

So that we don't have to rewrite tdb_recovery_size() too, we simply do
a short read and memset the unused section to 0 (to keep valgrind
happy).

ccan/tdb2/transaction.c

index 7a2ebbe9a3bb111e0a2c7ea2c4573a6ac2f82b44..73ceb9620265ee70b86320871c57aba0488c429f 100644 (file)
@@ -815,6 +815,7 @@ static enum TDB_ERROR transaction_setup_recovery(struct tdb_context *tdb,
                if (offset >= old_map_size) {
                        continue;
                }
+
                if (offset + length > tdb->file->map_size) {
                        free(data);
                        return tdb_logerr(tdb, TDB_ERR_CORRUPT, TDB_LOG_ERROR,
@@ -829,9 +830,19 @@ static enum TDB_ERROR transaction_setup_recovery(struct tdb_context *tdb,
                /* the recovery area contains the old data, not the
                   new data, so we have to call the original tdb_read
                   method to get it */
-               ecode = methods->tread(tdb, offset,
-                                      p + sizeof(offset) + sizeof(length),
-                                      length);
+               if (offset + length > old_map_size) {
+                       /* Short read at EOF, and zero fill. */
+                       unsigned int len = old_map_size - offset;
+                       ecode = methods->tread(tdb, offset,
+                                              p + sizeof(offset) + sizeof(length),
+                                              len);
+                       memset(p + sizeof(offset) + sizeof(length) + len, 0,
+                              length - len);
+               } else {
+                       ecode = methods->tread(tdb, offset,
+                                              p + sizeof(offset) + sizeof(length),
+                                              length);
+               }
                if (ecode != TDB_SUCCESS) {
                        free(data);
                        return ecode;