]> git.ipfire.org Git - thirdparty/postgresql.git/commitdiff
Avoid using potentially-under-aligned page buffers.
authorTom Lane <tgl@sss.pgh.pa.us>
Sat, 1 Sep 2018 19:27:14 +0000 (15:27 -0400)
committerTom Lane <tgl@sss.pgh.pa.us>
Sat, 1 Sep 2018 19:27:14 +0000 (15:27 -0400)
There's a project policy against using plain "char buf[BLCKSZ]" local
or static variables as page buffers; preferred style is to palloc or
malloc each buffer to ensure it is MAXALIGN'd.  However, that policy's
been ignored in an increasing number of places.  We've apparently got
away with it so far, probably because (a) relatively few people use
platforms on which misalignment causes core dumps and/or (b) the
variables chance to be sufficiently aligned anyway.  But this is not
something to rely on.  Moreover, even if we don't get a core dump,
we might be paying a lot of cycles for misaligned accesses.

To fix, invent new union types PGAlignedBlock and PGAlignedXLogBlock
that the compiler must allocate with sufficient alignment, and use
those in place of plain char arrays.

I used these types even for variables where there's no risk of a
misaligned access, since ensuring proper alignment should make
kernel data transfers faster.  I also changed some places where
we had been palloc'ing short-lived buffers, for coding style
uniformity and to save palloc/pfree overhead.

Since this seems to be a live portability hazard (despite the lack
of field reports), back-patch to all supported versions.

Patch by me; thanks to Michael Paquier for review.

Discussion: https://postgr.es/m/1535618100.1286.3.camel@credativ.de

13 files changed:
src/backend/access/gin/ginentrypage.c
src/backend/access/gin/ginfast.c
src/backend/access/hash/hashpage.c
src/backend/access/heap/heapam.c
src/backend/access/heap/visibilitymap.c
src/backend/access/transam/xlog.c
src/backend/commands/tablecmds.c
src/backend/replication/walsender.c
src/backend/storage/file/buffile.c
src/backend/storage/freespace/freespace.c
src/bin/pg_basebackup/receivelog.c
src/bin/pg_resetxlog/pg_resetxlog.c
src/include/c.h

index bd9908e3482d8833bdb310caa0f2044adc2f61c9..2f3894f6ade7d5af4ed0f7b918323515408192c3 100644 (file)
@@ -557,7 +557,7 @@ entrySplitPage(GinBtree btree, Buffer lbuf, Buffer rbuf, OffsetNumber off, XLogR
        /* these must be static so they can be returned to caller */
        static XLogRecData rdata[2];
        static ginxlogSplit data;
-       static char tupstore[2 * BLCKSZ];
+       static PGAlignedBlock tupstore[2];
 
        *prdata = rdata;
        data.leftChildBlkno = (GinPageIsLeaf(lpage)) ?
@@ -565,7 +565,7 @@ entrySplitPage(GinBtree btree, Buffer lbuf, Buffer rbuf, OffsetNumber off, XLogR
        data.updateBlkno = entryPreparePage(btree, lpage, off);
 
        maxoff = PageGetMaxOffsetNumber(lpage);
-       ptr = tupstore;
+       ptr = tupstore[0].data;
 
        for (i = FirstOffsetNumber; i <= maxoff; i++)
        {
@@ -595,7 +595,7 @@ entrySplitPage(GinBtree btree, Buffer lbuf, Buffer rbuf, OffsetNumber off, XLogR
        GinInitPage(rpage, GinPageGetOpaque(lpage)->flags, pageSize);
        GinInitPage(lpage, GinPageGetOpaque(rpage)->flags, pageSize);
 
-       ptr = tupstore;
+       ptr = tupstore[0].data;
        maxoff++;
        lsize = 0;
 
@@ -643,7 +643,7 @@ entrySplitPage(GinBtree btree, Buffer lbuf, Buffer rbuf, OffsetNumber off, XLogR
        rdata[0].next = &rdata[1];
 
        rdata[1].buffer = InvalidBuffer;
-       rdata[1].data = tupstore;
+       rdata[1].data = tupstore[0].data;
        rdata[1].len = MAXALIGN(totalsize);
        rdata[1].next = NULL;
 
index 5f8beb56f70baebaeddf2d6af07e24deeb73b1e1..ad8059c1ab1f12eb34f5455ab9c6ca1bdcd6b451 100644 (file)
@@ -52,18 +52,15 @@ writeListPage(Relation index, Buffer buffer,
                                size = 0;
        OffsetNumber l,
                                off;
-       char       *workspace;
+       PGAlignedBlock workspace;
        char       *ptr;
 
-       /* workspace could be a local array; we use palloc for alignment */
-       workspace = palloc(BLCKSZ);
-
        START_CRIT_SECTION();
 
        GinInitBuffer(buffer, GIN_LIST);
 
        off = FirstOffsetNumber;
-       ptr = workspace;
+       ptr = workspace.data;
 
        for (i = 0; i < ntuples; i++)
        {
@@ -120,7 +117,7 @@ writeListPage(Relation index, Buffer buffer,
                rdata[0].next = rdata + 1;
 
                rdata[1].buffer = InvalidBuffer;
-               rdata[1].data = workspace;
+               rdata[1].data = workspace.data;
                rdata[1].len = size;
                rdata[1].next = NULL;
 
@@ -135,8 +132,6 @@ writeListPage(Relation index, Buffer buffer,
 
        END_CRIT_SECTION();
 
-       pfree(workspace);
-
        return freesize;
 }
 
index 29ed7c233935001e72813594b989051a94000d49..4dbda292789bdc1b66e06ff041fdc327bbcafc84 100644 (file)
@@ -710,7 +710,7 @@ static bool
 _hash_alloc_buckets(Relation rel, BlockNumber firstblock, uint32 nblocks)
 {
        BlockNumber lastblock;
-       char            zerobuf[BLCKSZ];
+       PGAlignedBlock zerobuf;
 
        lastblock = firstblock + nblocks - 1;
 
@@ -721,10 +721,10 @@ _hash_alloc_buckets(Relation rel, BlockNumber firstblock, uint32 nblocks)
        if (lastblock < firstblock || lastblock == InvalidBlockNumber)
                return false;
 
-       MemSet(zerobuf, 0, sizeof(zerobuf));
+       MemSet(zerobuf.data, 0, sizeof(zerobuf));
 
        RelationOpenSmgr(rel);
-       smgrextend(rel->rd_smgr, MAIN_FORKNUM, lastblock, zerobuf, false);
+       smgrextend(rel->rd_smgr, MAIN_FORKNUM, lastblock, zerobuf.data, false);
 
        return true;
 }
index 5641a85a1936330cf42dbd348e874e33469a4a62..af8624e9b7d940b915f18b5aa40ced9bd65aefdb 100644 (file)
@@ -2258,7 +2258,7 @@ heap_multi_insert(Relation relation, HeapTuple *tuples, int ntuples,
        HeapTuple  *heaptuples;
        int                     i;
        int                     ndone;
-       char       *scratch = NULL;
+       PGAlignedBlock scratch;
        Page            page;
        bool            needwal;
        Size            saveFreeSpace;
@@ -2273,14 +2273,6 @@ heap_multi_insert(Relation relation, HeapTuple *tuples, int ntuples,
                heaptuples[i] = heap_prepare_insert(relation, tuples[i],
                                                                                        xid, cid, options);
 
-       /*
-        * Allocate some memory to use for constructing the WAL record. Using
-        * palloc() within a critical section is not safe, so we allocate this
-        * beforehand.
-        */
-       if (needwal)
-               scratch = palloc(BLCKSZ);
-
        /*
         * We're about to do the actual inserts -- but check for conflict first,
         * to minimize the possibility of having to roll back work we've just
@@ -2365,7 +2357,7 @@ heap_multi_insert(Relation relation, HeapTuple *tuples, int ntuples,
                        uint8           info = XLOG_HEAP2_MULTI_INSERT;
                        char       *tupledata;
                        int                     totaldatalen;
-                       char       *scratchptr = scratch;
+                       char       *scratchptr = scratch.data;
                        bool            init;
 
                        /*
@@ -2425,10 +2417,10 @@ heap_multi_insert(Relation relation, HeapTuple *tuples, int ntuples,
                                scratchptr += datalen;
                        }
                        totaldatalen = scratchptr - tupledata;
-                       Assert((scratchptr - scratch) < BLCKSZ);
+                       Assert((scratchptr - scratch.data) < BLCKSZ);
 
                        rdata[0].data = (char *) xlrec;
-                       rdata[0].len = tupledata - scratch;
+                       rdata[0].len = tupledata - scratch.data;
                        rdata[0].buffer = InvalidBuffer;
                        rdata[0].next = &rdata[1];
 
index e918b7a61c9b04029a07c836e97e7d6aa6c74943..5b88ef2906d3b7586e3ccf52bdbd435ca7e9630d 100644 (file)
@@ -610,10 +610,9 @@ static void
 vm_extend(Relation rel, BlockNumber vm_nblocks)
 {
        BlockNumber vm_nblocks_now;
-       Page            pg;
+       PGAlignedBlock pg;
 
-       pg = (Page) palloc(BLCKSZ);
-       PageInit(pg, BLCKSZ, 0);
+       PageInit((Page) pg.data, BLCKSZ, 0);
 
        /*
         * We use the relation extension lock to lock out other backends trying to
@@ -644,10 +643,10 @@ vm_extend(Relation rel, BlockNumber vm_nblocks)
        /* Now extend the file */
        while (vm_nblocks_now < vm_nblocks)
        {
-               PageSetChecksumInplace(pg, vm_nblocks_now);
+               PageSetChecksumInplace((Page) pg.data, vm_nblocks_now);
 
                smgrextend(rel->rd_smgr, VISIBILITYMAP_FORKNUM, vm_nblocks_now,
-                                  (char *) pg, false);
+                                  pg.data, false);
                vm_nblocks_now++;
        }
 
@@ -664,6 +663,4 @@ vm_extend(Relation rel, BlockNumber vm_nblocks)
        rel->rd_smgr->smgr_vm_nblocks = vm_nblocks_now;
 
        UnlockRelationForExtension(rel, ExclusiveLock);
-
-       pfree(pg);
 }
index 7ea597177e1a1e7a686a72d3d7c9f29b404900cd..cbfb3296c0cd2dca756755d60dc75d6777a9c62e 100644 (file)
@@ -2306,8 +2306,7 @@ XLogFileInit(XLogSegNo logsegno, bool *use_existent, bool use_lock)
 {
        char            path[MAXPGPATH];
        char            tmppath[MAXPGPATH];
-       char            zbuffer_raw[XLOG_BLCKSZ + MAXIMUM_ALIGNOF];
-       char       *zbuffer;
+       PGAlignedXLogBlock zbuffer;
        XLogSegNo       installed_segno;
        int                     max_advance;
        int                     fd;
@@ -2361,16 +2360,12 @@ XLogFileInit(XLogSegNo logsegno, bool *use_existent, bool use_lock)
         * fsync below) that all the indirect blocks are down on disk.  Therefore,
         * fdatasync(2) or O_DSYNC will be sufficient to sync future writes to the
         * log file.
-        *
-        * Note: ensure the buffer is reasonably well-aligned; this may save a few
-        * cycles transferring data to the kernel.
         */
-       zbuffer = (char *) MAXALIGN(zbuffer_raw);
-       memset(zbuffer, 0, XLOG_BLCKSZ);
+       memset(zbuffer.data, 0, XLOG_BLCKSZ);
        for (nbytes = 0; nbytes < XLogSegSize; nbytes += XLOG_BLCKSZ)
        {
                errno = 0;
-               if ((int) write(fd, zbuffer, XLOG_BLCKSZ) != (int) XLOG_BLCKSZ)
+               if ((int) write(fd, zbuffer.data, XLOG_BLCKSZ) != (int) XLOG_BLCKSZ)
                {
                        int                     save_errno = errno;
 
@@ -2461,7 +2456,7 @@ XLogFileCopy(XLogSegNo destsegno, TimeLineID srcTLI, XLogSegNo srcsegno)
 {
        char            path[MAXPGPATH];
        char            tmppath[MAXPGPATH];
-       char            buffer[XLOG_BLCKSZ];
+       PGAlignedXLogBlock buffer;
        int                     srcfd;
        int                     fd;
        int                     nbytes;
@@ -2497,7 +2492,7 @@ XLogFileCopy(XLogSegNo destsegno, TimeLineID srcTLI, XLogSegNo srcsegno)
        for (nbytes = 0; nbytes < XLogSegSize; nbytes += sizeof(buffer))
        {
                errno = 0;
-               if ((int) read(srcfd, buffer, sizeof(buffer)) != (int) sizeof(buffer))
+               if ((int) read(srcfd, buffer.data, sizeof(buffer)) != (int) sizeof(buffer))
                {
                        if (errno != 0)
                                ereport(ERROR,
@@ -2508,7 +2503,7 @@ XLogFileCopy(XLogSegNo destsegno, TimeLineID srcTLI, XLogSegNo srcsegno)
                                                (errmsg("not enough data in file \"%s\"", path)));
                }
                errno = 0;
-               if ((int) write(fd, buffer, sizeof(buffer)) != (int) sizeof(buffer))
+               if ((int) write(fd, buffer.data, sizeof(buffer)) != (int) sizeof(buffer))
                {
                        int                     save_errno = errno;
 
@@ -8017,7 +8012,7 @@ XLogSaveBufferForHint(Buffer buffer, bool buffer_std)
         */
        if (XLogCheckBuffer(rdata, false, &lsn, &bkpb))
        {
-               char            copied_buffer[BLCKSZ];
+               PGAlignedBlock copied_buffer;
                char       *origdata = (char *) BufferGetBlock(buffer);
 
                /*
@@ -8028,8 +8023,8 @@ XLogSaveBufferForHint(Buffer buffer, bool buffer_std)
                 * With buffer_std set to false, XLogCheckBuffer() sets hole_length and
                 * hole_offset to 0; so the following code is safe for either case.
                 */
-               memcpy(copied_buffer, origdata, bkpb.hole_offset);
-               memcpy(copied_buffer + bkpb.hole_offset,
+               memcpy(copied_buffer.data, origdata, bkpb.hole_offset);
+               memcpy(copied_buffer.data + bkpb.hole_offset,
                           origdata + bkpb.hole_offset + bkpb.hole_length,
                           BLCKSZ - bkpb.hole_offset - bkpb.hole_length);
 
@@ -8044,7 +8039,7 @@ XLogSaveBufferForHint(Buffer buffer, bool buffer_std)
                /*
                 * Save copy of the buffer.
                 */
-               rdata[1].data = copied_buffer;
+               rdata[1].data = copied_buffer.data;
                rdata[1].len = BLCKSZ - bkpb.hole_length;
                rdata[1].buffer = InvalidBuffer;
                rdata[1].next = NULL;
index fd457ab1b56f1d7e505a203431dc6fc4bf8d2329..7ad6ae036ac5f851af627130a4c792e83b5f91c4 100644 (file)
@@ -8983,21 +8983,14 @@ static void
 copy_relation_data(SMgrRelation src, SMgrRelation dst,
                                   ForkNumber forkNum, char relpersistence)
 {
-       char       *buf;
+       PGAlignedBlock buf;
        Page            page;
        bool            use_wal;
        bool            copying_initfork;
        BlockNumber nblocks;
        BlockNumber blkno;
 
-       /*
-        * palloc the buffer so that it's MAXALIGN'd.  If it were just a local
-        * char[] array, the compiler might align it on any byte boundary, which
-        * can seriously hurt transfer speed to and from the kernel; not to
-        * mention possibly making log_newpage's accesses to the page header fail.
-        */
-       buf = (char *) palloc(BLCKSZ);
-       page = (Page) buf;
+       page = (Page) buf.data;
 
        /*
         * The init fork for an unlogged relation in many respects has to be
@@ -9021,7 +9014,7 @@ copy_relation_data(SMgrRelation src, SMgrRelation dst,
                /* If we got a cancel signal during the copy of the data, quit */
                CHECK_FOR_INTERRUPTS();
 
-               smgrread(src, forkNum, blkno, buf);
+               smgrread(src, forkNum, blkno, buf.data);
 
                if (!PageIsVerified(page, blkno))
                        ereport(ERROR,
@@ -9043,11 +9036,9 @@ copy_relation_data(SMgrRelation src, SMgrRelation dst,
                 * rel, because there's no need for smgr to schedule an fsync for this
                 * write; we'll do it ourselves below.
                 */
-               smgrextend(dst, forkNum, blkno, buf, true);
+               smgrextend(dst, forkNum, blkno, buf.data, true);
        }
 
-       pfree(buf);
-
        /*
         * If the rel is WAL-logged, must fsync before commit.  We use heap_sync
         * to ensure that the toast table gets fsync'd too.  (For a temp or
index c9438954099829a034fc3cdafd7d638016f7c998..a0fa8520e6e7e1e4148cabe55834f217b5e5b7c7 100644 (file)
@@ -381,16 +381,16 @@ SendTimeLineHistory(TimeLineHistoryCmd *cmd)
        bytesleft = histfilelen;
        while (bytesleft > 0)
        {
-               char            rbuf[BLCKSZ];
+               PGAlignedBlock rbuf;
                int                     nread;
 
-               nread = read(fd, rbuf, sizeof(rbuf));
+               nread = read(fd, rbuf.data, sizeof(rbuf));
                if (nread <= 0)
                        ereport(ERROR,
                                        (errcode_for_file_access(),
                                         errmsg("could not read file \"%s\": %m",
                                                        path)));
-               pq_sendbytes(&buf, rbuf, nread);
+               pq_sendbytes(&buf, rbuf.data, nread);
                bytesleft -= nread;
        }
        CloseTransientFile(fd);
index 81a30a5273e586f59da8464d8de5541ac1d33e97..791dfff07a8720c4aa0c44be2072d9478bbb4769 100644 (file)
@@ -86,7 +86,7 @@ struct BufFile
        off_t           curOffset;              /* offset part of current pos */
        int                     pos;                    /* next read/write position in buffer */
        int                     nbytes;                 /* total # of valid bytes in buffer */
-       char            buffer[BLCKSZ];
+       PGAlignedBlock buffer;
 };
 
 static BufFile *makeBufFile(File firstfile);
@@ -254,7 +254,7 @@ BufFileLoadBuffer(BufFile *file)
        /*
         * Read whatever we can get, up to a full bufferload.
         */
-       file->nbytes = FileRead(thisfile, file->buffer, sizeof(file->buffer));
+       file->nbytes = FileRead(thisfile, file->buffer.data, sizeof(file->buffer));
        if (file->nbytes < 0)
                file->nbytes = 0;
        file->offsets[file->curFile] += file->nbytes;
@@ -317,7 +317,7 @@ BufFileDumpBuffer(BufFile *file)
                                return;                 /* seek failed, give up */
                        file->offsets[file->curFile] = file->curOffset;
                }
-               bytestowrite = FileWrite(thisfile, file->buffer + wpos, bytestowrite);
+               bytestowrite = FileWrite(thisfile, file->buffer.data + wpos, bytestowrite);
                if (bytestowrite <= 0)
                        return;                         /* failed to write */
                file->offsets[file->curFile] += bytestowrite;
@@ -385,7 +385,7 @@ BufFileRead(BufFile *file, void *ptr, size_t size)
                        nthistime = size;
                Assert(nthistime > 0);
 
-               memcpy(ptr, file->buffer + file->pos, nthistime);
+               memcpy(ptr, file->buffer.data + file->pos, nthistime);
 
                file->pos += nthistime;
                ptr = (void *) ((char *) ptr + nthistime);
@@ -432,7 +432,7 @@ BufFileWrite(BufFile *file, void *ptr, size_t size)
                        nthistime = size;
                Assert(nthistime > 0);
 
-               memcpy(file->buffer + file->pos, ptr, nthistime);
+               memcpy(file->buffer.data + file->pos, ptr, nthistime);
 
                file->dirty = true;
                file->pos += nthistime;
index e4d1ef6f8f564a22db34f25af6945b3d4a273c50..d6f872cf6519ba860269360779a94e63764e3726 100644 (file)
@@ -588,10 +588,9 @@ static void
 fsm_extend(Relation rel, BlockNumber fsm_nblocks)
 {
        BlockNumber fsm_nblocks_now;
-       Page            pg;
+       PGAlignedBlock pg;
 
-       pg = (Page) palloc(BLCKSZ);
-       PageInit(pg, BLCKSZ, 0);
+       PageInit((Page) pg.data, BLCKSZ, 0);
 
        /*
         * We use the relation extension lock to lock out other backends trying to
@@ -621,10 +620,10 @@ fsm_extend(Relation rel, BlockNumber fsm_nblocks)
 
        while (fsm_nblocks_now < fsm_nblocks)
        {
-               PageSetChecksumInplace(pg, fsm_nblocks_now);
+               PageSetChecksumInplace((Page) pg.data, fsm_nblocks_now);
 
                smgrextend(rel->rd_smgr, FSM_FORKNUM, fsm_nblocks_now,
-                                  (char *) pg, false);
+                                  pg.data, false);
                fsm_nblocks_now++;
        }
 
@@ -632,8 +631,6 @@ fsm_extend(Relation rel, BlockNumber fsm_nblocks)
        rel->rd_smgr->smgr_fsm_nblocks = fsm_nblocks_now;
 
        UnlockRelationForExtension(rel, ExclusiveLock);
-
-       pfree(pg);
 }
 
 /*
index b2891431eae000330a70dd6af6a3af3130d655b2..628e2ab73e0fae6327488531ca78a16330b71430 100644 (file)
@@ -89,7 +89,7 @@ open_walfile(XLogRecPtr startpoint, uint32 timeline, char *basedir,
        int                     f;
        char            fn[MAXPGPATH];
        struct stat statbuf;
-       char       *zerobuf;
+       PGAlignedXLogBlock zerobuf;
        int                     bytes;
        XLogSegNo       segno;
 
@@ -135,11 +135,11 @@ open_walfile(XLogRecPtr startpoint, uint32 timeline, char *basedir,
        }
 
        /* New, empty, file. So pad it to 16Mb with zeroes */
-       zerobuf = pg_malloc0(XLOG_BLCKSZ);
+       memset(zerobuf.data, 0, XLOG_BLCKSZ);
        for (bytes = 0; bytes < XLogSegSize; bytes += XLOG_BLCKSZ)
        {
                errno = 0;
-               if (write(f, zerobuf, XLOG_BLCKSZ) != XLOG_BLCKSZ)
+               if (write(f, zerobuf.data, XLOG_BLCKSZ) != XLOG_BLCKSZ)
                {
                        /* if write didn't set errno, assume problem is no disk space */
                        if (errno == 0)
@@ -147,13 +147,11 @@ open_walfile(XLogRecPtr startpoint, uint32 timeline, char *basedir,
                        fprintf(stderr,
                                        _("%s: could not pad transaction log file \"%s\": %s\n"),
                                        progname, fn, strerror(errno));
-                       free(zerobuf);
                        close(f);
                        unlink(fn);
                        return false;
                }
        }
-       free(zerobuf);
 
        if (lseek(f, SEEK_SET, 0) != 0)
        {
index 2c8b92f58aef76b7dfa2d486dcca78592d515f22..d6b62dd7be4d3f3b867eb50ea1ee8c919e94fe0b 100644 (file)
@@ -1016,7 +1016,7 @@ KillExistingArchiveStatus(void)
 static void
 WriteEmptyXLOG(void)
 {
-       char       *buffer;
+       PGAlignedXLogBlock buffer;
        XLogPageHeader page;
        XLogLongPageHeader longpage;
        XLogRecord *record;
@@ -1025,12 +1025,10 @@ WriteEmptyXLOG(void)
        int                     fd;
        int                     nbytes;
 
-       /* Use malloc() to ensure buffer is MAXALIGNED */
-       buffer = (char *) pg_malloc(XLOG_BLCKSZ);
-       page = (XLogPageHeader) buffer;
-       memset(buffer, 0, XLOG_BLCKSZ);
+       memset(buffer.data, 0, XLOG_BLCKSZ);
 
        /* Set up the XLOG page header */
+       page = (XLogPageHeader) buffer.data;
        page->xlp_magic = XLOG_PAGE_MAGIC;
        page->xlp_info = XLP_LONG_HEADER;
        page->xlp_tli = ControlFile.checkPointCopy.ThisTimeLineID;
@@ -1072,7 +1070,7 @@ WriteEmptyXLOG(void)
        }
 
        errno = 0;
-       if (write(fd, buffer, XLOG_BLCKSZ) != XLOG_BLCKSZ)
+       if (write(fd, buffer.data, XLOG_BLCKSZ) != XLOG_BLCKSZ)
        {
                /* if write didn't set errno, assume problem is no disk space */
                if (errno == 0)
@@ -1083,11 +1081,11 @@ WriteEmptyXLOG(void)
        }
 
        /* Fill the rest of the file with zeroes */
-       memset(buffer, 0, XLOG_BLCKSZ);
+       memset(buffer.data, 0, XLOG_BLCKSZ);
        for (nbytes = XLOG_BLCKSZ; nbytes < XLogSegSize; nbytes += XLOG_BLCKSZ)
        {
                errno = 0;
-               if (write(fd, buffer, XLOG_BLCKSZ) != XLOG_BLCKSZ)
+               if (write(fd, buffer.data, XLOG_BLCKSZ) != XLOG_BLCKSZ)
                {
                        if (errno == 0)
                                errno = ENOSPC;
index adfb9122a4891a3fecae2c8031345aee182d0243..fcd86885db5802472b0ce145d83f9c81f74053a5 100644 (file)
@@ -858,6 +858,32 @@ typedef NameData *Name;
  * ----------------------------------------------------------------
  */
 
+/*
+ * Use this, not "char buf[BLCKSZ]", to declare a field or local variable
+ * holding a page buffer, if that page might be accessed as a page and not
+ * just a string of bytes.  Otherwise the variable might be under-aligned,
+ * causing problems on alignment-picky hardware.  (In some places, we use
+ * this to declare buffers even though we only pass them to read() and
+ * write(), because copying to/from aligned buffers is usually faster than
+ * using unaligned buffers.)  We include both "double" and "int64" in the
+ * union to ensure that the compiler knows the value must be MAXALIGN'ed
+ * (cf. configure's computation of MAXIMUM_ALIGNOF).
+ */
+typedef union PGAlignedBlock
+{
+       char            data[BLCKSZ];
+       double          force_align_d;
+       int64           force_align_i64;
+} PGAlignedBlock;
+
+/* Same, but for an XLOG_BLCKSZ-sized buffer */
+typedef union PGAlignedXLogBlock
+{
+       char            data[XLOG_BLCKSZ];
+       double          force_align_d;
+       int64           force_align_i64;
+} PGAlignedXLogBlock;
+
 /* msb for char */
 #define HIGHBIT                                        (0x80)
 #define IS_HIGHBIT_SET(ch)             ((unsigned char)(ch) & HIGHBIT)