Re: Shared buffer access rule violations?

Tom Lane <tgl@sss.pgh.pa.us>

From: Tom Lane <tgl@sss.pgh.pa.us>
To: Asim R P <apraveen@pivotal.io>
Cc: PostgreSQL mailing lists <pgsql-hackers@postgresql.org>
Date: 2018-07-12T22:30:34Z
Lists: pgsql-hackers
Asim R P <apraveen@pivotal.io> writes:
> On Tue, Jul 10, 2018 at 8:33 PM, Tom Lane <tgl@sss.pgh.pa.us> wrote:
>> Asim R P <apraveen@pivotal.io> writes:
>>> One can find several PageInit() calls with no content lock held.  See,
>>> for example:
>>> fill_seq_with_data()

>> That would be for a relation that no one else can even see yet, no?

> Yes, when the sequence is being created.  No, when the sequence is
> being reset, in ResetSequence().

ResetSequence creates a new relfilenode, which no one else will be able
to see until it commits, so the case is effectively the same as for
creation.

>>> vm_readbuf()
>>> fsm_readbuf()

>> In these cases I'd imagine that the I/O completion interlock is what
>> is preventing other backends from accessing the buffer.

> What is I/O completion interlock?

Oh ... the RBM_ZERO_ON_ERROR action should be done under the I/O lock,
but the ReadBuffer caller isn't holding that lock anymore, so I see your
point here.  Probably, nobody's noticed because it's a corner case that
shouldn't happen under normal use, but it's not safe.  I think what we
want is more like

	if (PageIsNew(BufferGetPage(buf)))
	{
		LockBuffer(buf, BUFFER_LOCK_EXCLUSIVE);
		if (PageIsNew(BufferGetPage(buf)))
			PageInit(BufferGetPage(buf), BLCKSZ, 0);
		UnlockReleaseBuffer(buf);
	}

to ensure that the page is initialized once and only once, even if
several backends do this concurrently.

			regards, tom lane


Commits

  1. Fix inadequate buffer locking in FSM and VM page re-initialization.