diff --git a/src/backend/access/transam/xlog.c b/src/backend/access/transam/xlog.c index 3cb866f..6689360 100644 --- a/src/backend/access/transam/xlog.c +++ b/src/backend/access/transam/xlog.c @@ -855,6 +855,22 @@ begin:; elog(PANIC, "invalid xlog record length %u", len); /* + * Calculate CRC of the data but not the backup blocks. + * + * We calculate the checksum for each backup block separately, then + * include the block checksum within the main checksum. + * + * Note that the record header isn't added into the CRC initially since we + * don't know the prev-link yet. Thus, the CRC will represent the CRC of + * the whole record in the order: rdata, then record header. + * + * End result is that all data in the WAL record is covered by checksum. + */ + INIT_CRC32(rdata_crc); + for (rdt = rdata; rdt != NULL; rdt = rdt->next) + COMP_CRC32(rdata_crc, rdt->data, rdt->len); + + /* * Make additional rdata chain entries for the backup blocks, so that we * don't need to special-case them in the write loop. This modifies the * original rdata chain, but we keep a pointer to the last regular entry, @@ -882,6 +898,23 @@ begin:; bkpb = &(dtbuf_xlg[i]); page = (char *) BufferGetBlock(dtbuf[i]); + /* + * Set the checksum on each of the backup blocks. We do this instead + * of including the backup blocks inside the main checksum. So the WAL + * record is protected by a CRC32 check, while the backup blocks are + * protected by a 16-bit checksum. We don't use the block number as + * part of the checksum, so we leave that set at zero. + * + * Note that this is unconditional. We want every WAL record to be + * covered by a checksum, even if page_checksum option is not enabled. + * This calculation forms part of the WAL checksum. + * + * First field on each page is pd_lsn which is an XLogRecPtr, then we + * have pd_checksum which is an uint16. + */ + PageSetChecksumInplace(page, 0); + COMP_CRC32(rdata_crc, page + sizeof(XLogRecPtr), sizeof(uint16)); + rdt->next = &(dtbuf_rdt1[i]); rdt = rdt->next; @@ -917,18 +950,6 @@ begin:; } /* - * Calculate CRC of the data, including all the backup blocks - * - * Note that the record header isn't added into the CRC initially since we - * don't know the prev-link yet. Thus, the CRC will represent the CRC of - * the whole record in the order: rdata, then backup blocks, then record - * header. - */ - INIT_CRC32(rdata_crc); - for (rdt = rdata; rdt != NULL; rdt = rdt->next) - COMP_CRC32(rdata_crc, rdt->data, rdt->len); - - /* * Construct record header (prev-link and CRC are filled in later), and * make that the first chunk in the chain. */