From fc4976644ff28f66bea3f45614148934a5d43035 Mon Sep 17 00:00:00 2001 From: Masahiko Sawada Date: Fri, 28 Jun 2019 18:05:14 +0900 Subject: [PATCH 5/9] Encrypt and decrypt data on encrypted tablespace when disk I/O. All page pertainig encrypted tablespace are encrypted when writing to the disk and are decrypted when reading from disk. Also when relation copying and relation rewriting the source relation and destination relation are encrypted with different tweak even if using the same key. --- src/backend/access/heap/rewriteheap.c | 23 +++++++++- src/backend/access/heap/visibilitymap.c | 12 ++++- src/backend/access/nbtree/nbtree.c | 5 +++ src/backend/access/nbtree/nbtsort.c | 11 +++++ src/backend/catalog/storage.c | 12 +++++ src/backend/storage/buffer/bufmgr.c | 60 ++++++++++++++++++++++++- src/backend/storage/file/copydir.c | 75 +++++++++++++++++++++++++++++++ src/backend/storage/freespace/freespace.c | 13 +++++- src/backend/storage/page/bufpage.c | 14 ++++++ src/backend/storage/smgr/md.c | 27 +++++++++++ src/backend/storage/smgr/smgr.c | 20 +++++++++ src/common/relpath.c | 66 +++++++++++++++++++++++++++ src/include/common/relpath.h | 3 ++ src/include/storage/buf_internals.h | 16 ++++--- src/include/storage/bufpage.h | 3 ++ src/include/storage/md.h | 4 ++ src/include/storage/smgr.h | 4 ++ 17 files changed, 354 insertions(+), 14 deletions(-) diff --git a/src/backend/access/heap/rewriteheap.c b/src/backend/access/heap/rewriteheap.c index 369694f..4c57fd6 100644 --- a/src/backend/access/heap/rewriteheap.c +++ b/src/backend/access/heap/rewriteheap.c @@ -130,6 +130,7 @@ #include "utils/memutils.h" #include "utils/rel.h" +#include "utils/spccache.h" #include "storage/procarray.h" @@ -161,6 +162,7 @@ typedef struct RewriteStateData HTAB *rs_old_new_tid_map; /* unmatched B tuples */ HTAB *rs_logical_mappings; /* logical remapping files */ uint32 rs_num_rewrite_mappings; /* # in memory mappings */ + bool rs_encryption; } RewriteStateData; /* @@ -276,6 +278,7 @@ begin_heap_rewrite(Relation old_heap, Relation new_heap, TransactionId oldest_xm state->rs_freeze_xid = freeze_xid; state->rs_cutoff_multi = cutoff_multi; state->rs_cxt = rw_cxt; + state->rs_encryption = tablespace_is_encrypted(new_heap->rd_node.spcNode); /* Initialize hash tables used to track update chains */ memset(&hash_ctl, 0, sizeof(hash_ctl)); @@ -330,6 +333,8 @@ end_heap_rewrite(RewriteState state) /* Write the last page, if any */ if (state->rs_buffer_valid) { + char *bufToWrite = state->rs_buffer; + if (state->rs_use_wal) log_newpage(&state->rs_new_rel->rd_node, MAIN_FORKNUM, @@ -340,8 +345,14 @@ end_heap_rewrite(RewriteState state) PageSetChecksumInplace(state->rs_buffer, state->rs_blockno); + if (state->rs_encryption) + bufToWrite = PageEncryptCopy(state->rs_buffer, + state->rs_new_rel->rd_smgr, + MAIN_FORKNUM, + state->rs_blockno); + smgrextend(state->rs_new_rel->rd_smgr, MAIN_FORKNUM, state->rs_blockno, - (char *) state->rs_buffer, true); + (char *) bufToWrite, true); } /* @@ -692,6 +703,8 @@ raw_heap_insert(RewriteState state, HeapTuple tup) if (len + saveFreeSpace > pageFreeSpace) { + char *bufToWrite = page; + /* Doesn't fit, so write out the existing page */ /* XLOG stuff */ @@ -712,8 +725,14 @@ raw_heap_insert(RewriteState state, HeapTuple tup) PageSetChecksumInplace(page, state->rs_blockno); + if (state->rs_encryption) + bufToWrite = PageEncryptCopy(page, + state->rs_new_rel->rd_smgr, + MAIN_FORKNUM, + state->rs_blockno); + smgrextend(state->rs_new_rel->rd_smgr, MAIN_FORKNUM, - state->rs_blockno, (char *) page, true); + state->rs_blockno, (char *) bufToWrite, true); state->rs_blockno++; state->rs_buffer_valid = false; diff --git a/src/backend/access/heap/visibilitymap.c b/src/backend/access/heap/visibilitymap.c index 64dfe06..e39bbf9 100644 --- a/src/backend/access/heap/visibilitymap.c +++ b/src/backend/access/heap/visibilitymap.c @@ -94,6 +94,7 @@ #include "storage/lmgr.h" #include "storage/smgr.h" #include "utils/inval.h" +#include "utils/spccache.h" /*#define TRACE_VISIBILITYMAP */ @@ -627,8 +628,6 @@ vm_extend(Relation rel, BlockNumber vm_nblocks) BlockNumber vm_nblocks_now; PGAlignedBlock pg; - PageInit((Page) pg.data, BLCKSZ, 0); - /* * We use the relation extension lock to lock out other backends trying to * extend the visibility map at the same time. It also locks out extension @@ -658,8 +657,17 @@ vm_extend(Relation rel, BlockNumber vm_nblocks) /* Now extend the file */ while (vm_nblocks_now < vm_nblocks) { + /* + * initialize page each time as the page has modified at previous + * cycle. + */ + PageInit((Page) pg.data, BLCKSZ, 0); PageSetChecksumInplace((Page) pg.data, vm_nblocks_now); + if (tablespace_is_encrypted(rel->rd_smgr->smgr_rnode.node.spcNode)) + smgrencrypt(rel->rd_smgr, VISIBILITYMAP_FORKNUM, vm_nblocks_now, + pg.data); + smgrextend(rel->rd_smgr, VISIBILITYMAP_FORKNUM, vm_nblocks_now, pg.data, false); vm_nblocks_now++; diff --git a/src/backend/access/nbtree/nbtree.c b/src/backend/access/nbtree/nbtree.c index 85e54ac..47faf2d 100644 --- a/src/backend/access/nbtree/nbtree.c +++ b/src/backend/access/nbtree/nbtree.c @@ -36,6 +36,7 @@ #include "utils/builtins.h" #include "utils/index_selfuncs.h" #include "utils/memutils.h" +#include "utils/spccache.h" /* Working state needed by btvacuumpage */ @@ -162,6 +163,10 @@ btbuildempty(Relation index) metapage = (Page) palloc(BLCKSZ); _bt_initmetapage(metapage, P_NONE, 0); + if (tablespace_is_encrypted(index->rd_node.spcNode)) + smgrencrypt(index->rd_smgr, INIT_FORKNUM, BTREE_METAPAGE, + (char *) metapage); + /* * Write the page and log it. It might seem that an immediate sync would * be sufficient to guarantee that the file exists on disk, but recovery diff --git a/src/backend/access/nbtree/nbtsort.c b/src/backend/access/nbtree/nbtsort.c index d0b9013..64d4cfb 100644 --- a/src/backend/access/nbtree/nbtsort.c +++ b/src/backend/access/nbtree/nbtsort.c @@ -73,6 +73,7 @@ #include "tcop/tcopprot.h" /* pgrminclude ignore */ #include "utils/rel.h" #include "utils/sortsupport.h" +#include "utils/spccache.h" #include "utils/tuplesort.h" @@ -269,6 +270,7 @@ typedef struct BTWriteState BlockNumber btws_pages_alloced; /* # pages allocated */ BlockNumber btws_pages_written; /* # pages written out */ Page btws_zeropage; /* workspace for filling zeroes */ + bool btws_need_encryption; } BTWriteState; @@ -583,6 +585,8 @@ _bt_leafbuild(BTSpool *btspool, BTSpool *btspool2) wstate.btws_pages_alloced = BTREE_METAPAGE + 1; wstate.btws_pages_written = 0; wstate.btws_zeropage = NULL; /* until needed */ + wstate.btws_need_encryption = + tablespace_is_encrypted(btspool->index->rd_node.spcNode); pgstat_progress_update_param(PROGRESS_CREATEIDX_SUBPHASE, PROGRESS_BTREE_PHASE_LEAF_LOAD); @@ -679,6 +683,13 @@ _bt_blwritepage(BTWriteState *wstate, Page page, BlockNumber blkno) true); } + /* + * Encrypt page if enabled. Since the page is allocated in local buffer + * we can overwrite buffer by encrypted data. + */ + if (wstate->btws_need_encryption) + smgrencrypt(wstate->index->rd_smgr, MAIN_FORKNUM, blkno, page); + PageSetChecksumInplace(page, blkno); /* diff --git a/src/backend/catalog/storage.c b/src/backend/catalog/storage.c index 3cc886f..3302e0b 100644 --- a/src/backend/catalog/storage.c +++ b/src/backend/catalog/storage.c @@ -32,6 +32,7 @@ #include "storage/smgr.h" #include "utils/memutils.h" #include "utils/rel.h" +#include "utils/spccache.h" /* * We keep a list of all relations (represented as RelFileNode values) @@ -311,6 +312,8 @@ RelationCopyStorage(SMgrRelation src, SMgrRelation dst, bool copying_initfork; BlockNumber nblocks; BlockNumber blkno; + bool need_decrypt; + bool need_encrypt; page = (Page) buf.data; @@ -331,6 +334,9 @@ RelationCopyStorage(SMgrRelation src, SMgrRelation dst, nblocks = smgrnblocks(src, forkNum); + need_decrypt = tablespace_is_encrypted(src->smgr_rnode.node.spcNode); + need_encrypt = tablespace_is_encrypted(dst->smgr_rnode.node.spcNode); + for (blkno = 0; blkno < nblocks; blkno++) { /* If we got a cancel signal during the copy of the data, quit */ @@ -338,6 +344,9 @@ RelationCopyStorage(SMgrRelation src, SMgrRelation dst, smgrread(src, forkNum, blkno, buf.data); + if (need_decrypt) + smgrdecrypt(src, forkNum, blkno, buf.data); + if (!PageIsVerified(page, blkno)) ereport(ERROR, (errcode(ERRCODE_DATA_CORRUPTED), @@ -357,6 +366,9 @@ RelationCopyStorage(SMgrRelation src, SMgrRelation dst, PageSetChecksumInplace(page, blkno); + if (need_encrypt) + smgrencrypt(dst, forkNum, blkno, buf.data); + /* * Now write the page. We say isTemp = true even if it's not a temp * rel, because there's no need for smgr to schedule an fsync for this diff --git a/src/backend/storage/buffer/bufmgr.c b/src/backend/storage/buffer/bufmgr.c index 7332e6b..5f2f6ee 100644 --- a/src/backend/storage/buffer/bufmgr.c +++ b/src/backend/storage/buffer/bufmgr.c @@ -51,6 +51,7 @@ #include "storage/standby.h" #include "utils/rel.h" #include "utils/resowner_private.h" +#include "utils/spccache.h" #include "utils/timestamp.h" @@ -866,11 +867,37 @@ ReadBuffer_common(SMgrRelation smgr, char relpersistence, ForkNumber forkNum, if (isExtend) { + bool encrypt = false; + /* new buffers are zero-filled */ MemSet((char *) bufBlock, 0, BLCKSZ); + + /* If the tablespace is encrypted, encrypt buffer and mark */ + if (tablespace_is_encrypted(smgr->smgr_rnode.node.spcNode)) + encrypt = true; + + /* + * If we need to encrypt the block, encrypt bufBlock and write it to + * the disk, and then initialize it to 0 again and mark buffer header + * as need to be encrypted. + */ + if (encrypt) + smgrencrypt(smgr, forkNum, blockNum, bufBlock); + /* don't set checksum for all-zero page */ smgrextend(smgr, forkNum, blockNum, (char *) bufBlock, false); + if (encrypt) + { + uint32 buf_state; + + /* Intialize to 0 again since bufBlock has an encrypted data */ + MemSet((char *) bufBlock, 0, BLCKSZ); + + buf_state = LockBufHdr(bufHdr); + buf_state |= BM_ENCRYPTION_NEEDED; + UnlockBufHdr(bufHdr, buf_state); + } /* * NB: we're *not* doing a ScheduleBufferTagForWriteback here; * although we're essentially performing a write. At least on linux @@ -904,6 +931,20 @@ ReadBuffer_common(SMgrRelation smgr, char relpersistence, ForkNumber forkNum, INSTR_TIME_ADD(pgBufferUsage.blk_read_time, io_time); } + /* + * If the tablespace is encrypted, decrypt the block, and mark the + * buffer as needing to be encrypted when flush. + */ + if (tablespace_is_encrypted(smgr->smgr_rnode.node.spcNode)) + { + uint32 buf_state; + + smgrdecrypt(smgr, forkNum, blockNum, bufBlock); + buf_state = LockBufHdr(bufHdr); + buf_state |= BM_ENCRYPTION_NEEDED; + UnlockBufHdr(bufHdr, buf_state); + } + /* check for garbage data */ if (!PageIsVerified((Page) bufBlock, blockNum)) { @@ -1308,7 +1349,7 @@ BufferAlloc(SMgrRelation smgr, char relpersistence, ForkNumber forkNum, buf->tag = newTag; buf_state &= ~(BM_VALID | BM_DIRTY | BM_JUST_DIRTIED | BM_CHECKPOINT_NEEDED | BM_IO_ERROR | BM_PERMANENT | - BUF_USAGECOUNT_MASK); + BUF_USAGECOUNT_MASK | BM_ENCRYPTION_NEEDED); if (relpersistence == RELPERSISTENCE_PERMANENT || forkNum == INIT_FORKNUM) buf_state |= BM_TAG_VALID | BM_PERMANENT | BUF_USAGECOUNT_ONE; else @@ -2749,6 +2790,16 @@ FlushBuffer(BufferDesc *buf, SMgrRelation reln) */ bufToWrite = PageSetChecksumCopy((Page) bufBlock, buf->tag.blockNum); + /* + * Encrypt page if needed. Since pages in shared buffer must not be + * encrypted we copy the page and encrypt it. + */ + if (buf_state & BM_ENCRYPTION_NEEDED) + bufToWrite = PageEncryptCopy(bufToWrite, + reln, + buf->tag.forkNum, + buf->tag.blockNum); + if (track_io_timing) INSTR_TIME_SET_CURRENT(io_start); @@ -3212,6 +3263,13 @@ FlushRelationBuffers(Relation rel) localpage = (char *) LocalBufHdrGetBlock(bufHdr); + /* Encrypt buffer and then update checksum */ + if (buf_state & BM_ENCRYPTION_NEEDED) + smgrencrypt(rel->rd_smgr, + bufHdr->tag.forkNum, + bufHdr->tag.blockNum, + localpage); + /* Setup error traceback support for ereport() */ errcallback.callback = local_buffer_write_error_callback; errcallback.arg = (void *) bufHdr; diff --git a/src/backend/storage/file/copydir.c b/src/backend/storage/file/copydir.c index 30f6200..d0d21f7 100644 --- a/src/backend/storage/file/copydir.c +++ b/src/backend/storage/file/copydir.c @@ -23,10 +23,16 @@ #include #include "storage/copydir.h" +#include "storage/encryption.h" #include "storage/fd.h" +#include "storage/kmgr.h" #include "miscadmin.h" #include "pgstat.h" +#include "utils/spccache.h" +static void reencrypt_copy_buffer(char *buffer, int nbytes, RelFileNode srcNode, + RelFileNode dstNode, BlockNumber blkno_inseg, + ForkNumber forknum); /* * copydir: copy a directory * @@ -132,6 +138,12 @@ copy_file(char *fromfile, char *tofile) int nbytes; off_t offset; off_t flush_offset; + RelFileNode fromNode; + RelFileNode toNode; + ForkNumber forknum; + BlockNumber segment; + bool is_relfile; + bool need_encryption; /* Size of copy buffer (read and write requests) */ #define COPY_BUF_SIZE (8 * BLCKSZ) @@ -167,6 +179,23 @@ copy_file(char *fromfile, char *tofile) errmsg("could not create file \"%s\": %m", tofile))); /* + * Encryption while copying is needed when the target file is a relation file + * and either from file or to file is encrypted. + */ + is_relfile = ParseRelationPath(fromfile, &(fromNode.dbNode), + &(fromNode.spcNode), + &(fromNode.relNode), + &forknum, &segment); + ParseRelationPath(tofile, &(toNode.dbNode), + &(toNode.spcNode), &(toNode.relNode), + &forknum, &segment); + + if (is_relfile && + (tablespace_is_encrypted(fromNode.spcNode) || + tablespace_is_encrypted(toNode.spcNode))) + need_encryption = true; + + /* * Do the data copying. */ flush_offset = 0; @@ -196,6 +225,16 @@ copy_file(char *fromfile, char *tofile) if (nbytes == 0) break; errno = 0; + + /* Encrypt buffer data */ + if (TransparentEncryptionEnabled() && need_encryption) + { + BlockNumber blkno_inseg = offset / BLCKSZ; + + reencrypt_copy_buffer(buffer, nbytes, fromNode, toNode, + blkno_inseg, forknum); + } + pgstat_report_wait_start(WAIT_EVENT_COPY_FILE_WRITE); if ((int) write(dstfd, buffer, nbytes) != nbytes) { @@ -224,3 +263,39 @@ copy_file(char *fromfile, char *tofile) pfree(buffer); } + +/* + * 'buffer' has 'nbytes' data of block data starting from 'blkno' block number + */ +static void +reencrypt_copy_buffer(char *buffer, int nbytes, RelFileNode srcNode, + RelFileNode dstNode, BlockNumber blkno_inseg, + ForkNumber forknum) +{ + BlockNumber curblkno = blkno_inseg; + BlockNumber nblocks = nbytes / BLCKSZ; + char srcTweak[ENCRYPTION_TWEAK_SIZE] = {0}; + char dstTweak[ENCRYPTION_TWEAK_SIZE] = {0}; + char *cur; + bool srcisencrypted = tablespace_is_encrypted(srcNode.spcNode); + bool dstisencrypted = tablespace_is_encrypted(dstNode.spcNode); + + Assert(nbytes % BLCKSZ == 0); + + for (cur = buffer; cur < buffer + (nblocks * BLCKSZ); + cur += BLCKSZ) + { + if (srcisencrypted) + { + BufferEncryptionTweak(srcTweak, &srcNode, forknum, curblkno); + DecryptBufferBlock(srcNode.spcNode, srcTweak, cur, cur); + } + + if (dstisencrypted) + { + BufferEncryptionTweak(dstTweak, &dstNode, forknum, curblkno); + EncryptBufferBlock(dstNode.spcNode, dstTweak, cur, cur); + } + curblkno++; + } +} diff --git a/src/backend/storage/freespace/freespace.c b/src/backend/storage/freespace/freespace.c index c17b3f4..2952f0b 100644 --- a/src/backend/storage/freespace/freespace.c +++ b/src/backend/storage/freespace/freespace.c @@ -30,6 +30,7 @@ #include "storage/fsm_internals.h" #include "storage/lmgr.h" #include "storage/smgr.h" +#include "utils/spccache.h" /* @@ -617,8 +618,6 @@ fsm_extend(Relation rel, BlockNumber fsm_nblocks) BlockNumber fsm_nblocks_now; PGAlignedBlock pg; - PageInit((Page) pg.data, BLCKSZ, 0); - /* * We use the relation extension lock to lock out other backends trying to * extend the FSM at the same time. It also locks out extension of the @@ -647,8 +646,18 @@ fsm_extend(Relation rel, BlockNumber fsm_nblocks) while (fsm_nblocks_now < fsm_nblocks) { + /* + * initialize page each time as the page has modified at previous + * cycle. + */ + PageInit((Page) pg.data, BLCKSZ, 0); + PageSetChecksumInplace((Page) pg.data, fsm_nblocks_now); + if (tablespace_is_encrypted(rel->rd_smgr->smgr_rnode.node.spcNode)) + smgrencrypt(rel->rd_smgr, FSM_FORKNUM, fsm_nblocks_now, + pg.data); + smgrextend(rel->rd_smgr, FSM_FORKNUM, fsm_nblocks_now, pg.data, false); fsm_nblocks_now++; diff --git a/src/backend/storage/page/bufpage.c b/src/backend/storage/page/bufpage.c index 6b49810..db3848a 100644 --- a/src/backend/storage/page/bufpage.c +++ b/src/backend/storage/page/bufpage.c @@ -1203,3 +1203,17 @@ PageSetChecksumInplace(Page page, BlockNumber blkno) ((PageHeader) page)->pd_checksum = pg_checksum_page((char *) page, blkno); } + +char * +PageEncryptCopy(char *page, SMgrRelation reln, ForkNumber forknum, + BlockNumber blocknum) +{ + static char *pageCopy = NULL; + + if (pageCopy == NULL) + pageCopy = MemoryContextAlloc(TopMemoryContext, BLCKSZ); + + memcpy(pageCopy, (char *) page, BLCKSZ); + smgrencrypt(reln, forknum, blocknum, (char *) pageCopy); + return pageCopy; +} diff --git a/src/backend/storage/smgr/md.c b/src/backend/storage/smgr/md.c index 64acc3f..bf2edd5 100644 --- a/src/backend/storage/smgr/md.c +++ b/src/backend/storage/smgr/md.c @@ -30,6 +30,7 @@ #include "access/xlog.h" #include "pgstat.h" #include "postmaster/bgwriter.h" +#include "storage/encryption.h" #include "storage/fd.h" #include "storage/bufmgr.h" #include "storage/md.h" @@ -38,6 +39,7 @@ #include "storage/sync.h" #include "utils/hsearch.h" #include "utils/memutils.h" +#include "utils/spccache.h" #include "pg_trace.h" /* @@ -86,6 +88,11 @@ typedef struct _MdfdVec static MemoryContext MdCxt; /* context for all MdfdVec objects */ +/* + * encryption_buffer from encryption.h is not used here because of the special + * memory context. + */ +static char md_encryption_tweak[ENCRYPTION_TWEAK_SIZE]; /* Populate a file tag describing an md.c segment file. */ #define INIT_MD_FILETAG(a,xx_rnode,xx_forknum,xx_segno) \ @@ -1315,3 +1322,23 @@ mdfiletagmatches(const FileTag *ftag, const FileTag *candidate) */ return ftag->rnode.dbNode == candidate->rnode.dbNode; } + +void +mdencrypt(SMgrRelation reln, ForkNumber forknum, BlockNumber blocknum, + char *buffer) +{ + BufferEncryptionTweak(md_encryption_tweak, &(reln->smgr_rnode.node), + forknum, blocknum); + EncryptBufferBlock(reln->smgr_rnode.node.spcNode, md_encryption_tweak, + buffer, buffer); +} + +void +mddecrypt(SMgrRelation reln, ForkNumber forknum, BlockNumber blocknum, + char *buffer) +{ + BufferEncryptionTweak(md_encryption_tweak, &(reln->smgr_rnode.node), + forknum, blocknum); + DecryptBufferBlock(reln->smgr_rnode.node.spcNode, md_encryption_tweak, + buffer, buffer); +} diff --git a/src/backend/storage/smgr/smgr.c b/src/backend/storage/smgr/smgr.c index dba8c39..e4f67d9 100644 --- a/src/backend/storage/smgr/smgr.c +++ b/src/backend/storage/smgr/smgr.c @@ -61,6 +61,10 @@ typedef struct f_smgr void (*smgr_truncate) (SMgrRelation reln, ForkNumber forknum, BlockNumber nblocks); void (*smgr_immedsync) (SMgrRelation reln, ForkNumber forknum); + void (*smgr_encrypt) (SMgrRelation reln, ForkNumber forknum, + BlockNumber blocknum, char *buffer); + void (*smgr_decrypt) (SMgrRelation reln, ForkNumber forknum, + BlockNumber blocknum, char *buffer); } f_smgr; static const f_smgr smgrsw[] = { @@ -80,6 +84,8 @@ static const f_smgr smgrsw[] = { .smgr_nblocks = mdnblocks, .smgr_truncate = mdtruncate, .smgr_immedsync = mdimmedsync, + .smgr_encrypt = mdencrypt, + .smgr_decrypt = mddecrypt, } }; @@ -698,6 +704,20 @@ smgrimmedsync(SMgrRelation reln, ForkNumber forknum) smgrsw[reln->smgr_which].smgr_immedsync(reln, forknum); } +void +smgrencrypt(SMgrRelation reln, ForkNumber forknum, BlockNumber blocknum, + char *buffer) +{ + smgrsw[reln->smgr_which].smgr_encrypt(reln, forknum, blocknum, buffer); +} + +void +smgrdecrypt(SMgrRelation reln, ForkNumber forknum, BlockNumber blocknum, + char *buffer) +{ + smgrsw[reln->smgr_which].smgr_decrypt(reln, forknum, blocknum, buffer); +} + /* * AtEOXact_SMgr * diff --git a/src/common/relpath.c b/src/common/relpath.c index 62b9553..9342ece 100644 --- a/src/common/relpath.c +++ b/src/common/relpath.c @@ -205,3 +205,69 @@ GetRelationPath(Oid dbNode, Oid spcNode, Oid relNode, } return path; } + +bool +ParseRelationPath(const char *path, Oid *dbNode, Oid *spcNode, Oid *relNode, + ForkNumber *forknum, uint32 *segment) + +{ + char *ptr; + + /* Parse spcNode, dbNode and relNode */ + if (strncmp(path, "global", 6) == 0) + { + *spcNode = GLOBALTABLESPACE_OID; + if (sscanf(path, "global/%u/%u", dbNode, relNode) != 2) + return false; + } + else if (strncmp(path, "base", 4) == 0) + { + *spcNode = DEFAULTTABLESPACE_OID; + if (sscanf(path, "base/%u/%u", dbNode, relNode) != 2) + return false; + } + else if (strncmp(path, "pg_tblspc", 9) == 0) + { + if (sscanf(path, "pg_tblspc/%u/"TABLESPACE_VERSION_DIRECTORY"/%u/%u", + spcNode, dbNode, relNode) != 3) + return false; + } + + /* Skip to the end of relNode */ + ptr = last_dir_separator(path) + 1; + for (; isdigit(*ptr); ptr++) + ; + + /* Parse fork number */ + if (*ptr != '_') + *forknum = MAIN_FORKNUM; + else + { + int forkchar; + + forkchar = forkname_chars(ptr, forknum); + if (forkchar <= 0) + return false; + ptr += forkchar + 1; + } + + /* Parse segment number */ + if (*ptr == '.') + { + int segchar; + + for (segchar = 1; isdigit(*(ptr + segchar)); segchar++) + ; + if (segchar <= 1) + return false; + *segment = atoi(ptr + 1); + ptr += segchar; + } + else + segment = 0; + + if (ptr == '\0') + return false; + + return true; +} diff --git a/src/include/common/relpath.h b/src/include/common/relpath.h index 8ac3929..3db1670 100644 --- a/src/include/common/relpath.h +++ b/src/include/common/relpath.h @@ -68,6 +68,9 @@ extern char *GetDatabasePath(Oid dbNode, Oid spcNode); extern char *GetRelationPath(Oid dbNode, Oid spcNode, Oid relNode, int backendId, ForkNumber forkNumber); +extern bool ParseRelationPath(const char *path, Oid *dbNode, Oid *spcNode, + Oid *relNode, ForkNumber *forknum, + uint32 *segment); /* * Wrapper macros for GetRelationPath. Beware of multiple diff --git a/src/include/storage/buf_internals.h b/src/include/storage/buf_internals.h index df2dda7..231bb50 100644 --- a/src/include/storage/buf_internals.h +++ b/src/include/storage/buf_internals.h @@ -29,9 +29,9 @@ /* * Buffer state is a single 32-bit variable where following data is combined. * - * - 18 bits refcount + * - 17 bits refcount * - 4 bits usage count - * - 10 bits of flags + * - 11 bits of flags * * Combining these values allows to perform some operations without locking * the buffer header, by modifying them together with a CAS loop. @@ -39,11 +39,11 @@ * The definition of buffer state components is below. */ #define BUF_REFCOUNT_ONE 1 -#define BUF_REFCOUNT_MASK ((1U << 18) - 1) -#define BUF_USAGECOUNT_MASK 0x003C0000U -#define BUF_USAGECOUNT_ONE (1U << 18) -#define BUF_USAGECOUNT_SHIFT 18 -#define BUF_FLAG_MASK 0xFFC00000U +#define BUF_REFCOUNT_MASK ((1U << 17) - 1) +#define BUF_USAGECOUNT_MASK 0x003E0000U +#define BUF_USAGECOUNT_ONE (1U << 17) +#define BUF_USAGECOUNT_SHIFT 17 +#define BUF_FLAG_MASK 0xFFE00000U /* Get refcount and usagecount from buffer state */ #define BUF_STATE_GET_REFCOUNT(state) ((state) & BUF_REFCOUNT_MASK) @@ -55,6 +55,8 @@ * Note: TAG_VALID essentially means that there is a buffer hashtable * entry associated with the buffer's tag. */ +#define BM_ENCRYPTION_NEEDED (1U << 21) /* buffer need encryption before + * write */ #define BM_LOCKED (1U << 22) /* buffer header is locked */ #define BM_DIRTY (1U << 23) /* data needs writing */ #define BM_VALID (1U << 24) /* data is valid */ diff --git a/src/include/storage/bufpage.h b/src/include/storage/bufpage.h index 34b68ad..e62204b 100644 --- a/src/include/storage/bufpage.h +++ b/src/include/storage/bufpage.h @@ -18,6 +18,7 @@ #include "storage/block.h" #include "storage/item.h" #include "storage/off.h" +#include "storage/smgr.h" /* * A postgres disk page is an abstraction layered on top of a postgres @@ -438,5 +439,7 @@ extern bool PageIndexTupleOverwrite(Page page, OffsetNumber offnum, Item newtup, Size newsize); extern char *PageSetChecksumCopy(Page page, BlockNumber blkno); extern void PageSetChecksumInplace(Page page, BlockNumber blkno); +extern char *PageEncryptCopy(char *page, SMgrRelation reln, + ForkNumber forknum, BlockNumber blocknum); #endif /* BUFPAGE_H */ diff --git a/src/include/storage/md.h b/src/include/storage/md.h index df24b93..e003c30 100644 --- a/src/include/storage/md.h +++ b/src/include/storage/md.h @@ -39,6 +39,10 @@ extern BlockNumber mdnblocks(SMgrRelation reln, ForkNumber forknum); extern void mdtruncate(SMgrRelation reln, ForkNumber forknum, BlockNumber nblocks); extern void mdimmedsync(SMgrRelation reln, ForkNumber forknum); +extern void mdencrypt(SMgrRelation reln, ForkNumber forknum, + BlockNumber blocknum, char *buffer); +extern void mddecrypt(SMgrRelation reln, ForkNumber forknum, + BlockNumber blocknum, char *buffer); extern void ForgetDatabaseSyncRequests(Oid dbid); extern void DropRelationFiles(RelFileNode *delrels, int ndelrels, bool isRedo); diff --git a/src/include/storage/smgr.h b/src/include/storage/smgr.h index d286c8c..7018329 100644 --- a/src/include/storage/smgr.h +++ b/src/include/storage/smgr.h @@ -105,6 +105,10 @@ extern BlockNumber smgrnblocks(SMgrRelation reln, ForkNumber forknum); extern void smgrtruncate(SMgrRelation reln, ForkNumber forknum, BlockNumber nblocks); extern void smgrimmedsync(SMgrRelation reln, ForkNumber forknum); +extern void smgrencrypt(SMgrRelation reln, ForkNumber forknum, + BlockNumber blocknum, char *buffer); +extern void smgrdecrypt(SMgrRelation reln, ForkNumber forknum, + BlockNumber blocknum, char *buffer); extern void AtEOXact_SMgr(void); #endif /* SMGR_H */ -- 1.8.3.1