Hello, I was reading GiST core codes when I found an XLogInsert() call that can produce a corrupt WAL record.
== Summary == There is an execution path that produces a WAL record whose xl_info indicates XLOG_GIST_PAGE_UPDATE while the record actually contains a gistxlogPageSplit structure. == Details == (Line numbers are for HEAD as of Wed Dec 23 19:42:15 2009 +0000.) The problematic XLogInsert() call is on gistxlog.c, line 770: recptr = XLogInsert(RM_GIST_ID, XLOG_GIST_PAGE_UPDATE, rdata); where the last argument rdata has a pointer assigned either on line 741 or on line 752. When rdata comes from formSplitRdata() at line 741, rdata contains a reference to a gistxlogPageSplit structure. This is inconsistent with the second argument XLOG_GIST_PAGE_UPDATE. == Importance == I think this poses possible data loss under multiple consequent crashes. == Fix == I attach a simple patch (for HEAD as of the datetime above) that, I suppose, prevents the corrupt WAL production. I would be glad if you liked it. Please note that the problematic execution path exists at least in current HEAD, REL8_2_STABLE and the branches in between. Sincerely, -- Yoichi Hirai Dept. of Computer Science, The University of Tokyo.
diff --git a/src/backend/access/gist/gistxlog.c b/src/backend/access/gist/gistxlog.c index adf27ff..74e72f0 100644 --- a/src/backend/access/gist/gistxlog.c +++ b/src/backend/access/gist/gistxlog.c @@ -654,6 +654,7 @@ gistContinueInsert(gistIncompleteInsert *insert) XLogRecPtr recptr; Buffer tempbuffer = InvalidBuffer; int ntodelete = 0; + uint8 info; numbuffer = 1; buffers[0] = ReadBuffer(index, insert->path[i]); @@ -738,6 +739,7 @@ gistContinueInsert(gistIncompleteInsert *insert) for (j = 0; j < ntodelete; j++) PageIndexTupleDelete(pages[0], todelete[j]); + info = XLOG_GIST_PAGE_SPLIT; rdata = formSplitRdata(index->rd_node, insert->path[i], false, &(insert->key), gistMakePageLayout(buffers, numbuffer)); @@ -751,6 +753,7 @@ gistContinueInsert(gistIncompleteInsert *insert) PageIndexTupleDelete(pages[0], todelete[j]); gistfillbuffer(pages[0], itup, lenitup, InvalidOffsetNumber); + info = XLOG_GIST_PAGE_UPDATE; rdata = formUpdateRdata(index->rd_node, buffers[0], todelete, ntodelete, itup, lenitup, &(insert->key)); @@ -767,7 +770,7 @@ gistContinueInsert(gistIncompleteInsert *insert) GistPageGetOpaque(pages[j])->rightlink = InvalidBlockNumber; MarkBufferDirty(buffers[j]); } - recptr = XLogInsert(RM_GIST_ID, XLOG_GIST_PAGE_UPDATE, rdata); + recptr = XLogInsert(RM_GIST_ID, info, rdata); for (j = 0; j < numbuffer; j++) { PageSetLSN(pages[j], recptr);
-- Sent via pgsql-hackers mailing list (pgsql-hackers@postgresql.org) To make changes to your subscription: http://www.postgresql.org/mailpref/pgsql-hackers