Skip to content

Commit fe35c0b

Browse files
committed
Fix potential corruption of lock table in CREATE/DROP INDEX CONCURRENTLY.
If VirtualXactLock() has to wait for a transaction that holds its VXID lock as a fast-path lock, it must first convert the fast-path lock to a regular lock. It failed to take the required "partition" lock on the main shared-memory lock table while doing so. This is the direct cause of the assert failure in GetLockStatusData() recently observed in the buildfarm, but more worryingly it could result in arbitrary corruption of the shared lock table if some other process were concurrently engaged in modifying the same partition of the lock table. Fortunately, VirtualXactLock() is only used by CREATE INDEX CONCURRENTLY and DROP INDEX CONCURRENTLY, so the opportunities for failure are fewer than they might have been. In passing, improve some comments and be a bit more consistent about order of operations.
1 parent a17da19 commit fe35c0b

File tree

1 file changed

+25
-4
lines changed
  • src/backend/storage/lmgr

1 file changed

+25
-4
lines changed

src/backend/storage/lmgr/lock.c

Lines changed: 25 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -923,6 +923,12 @@ LockAcquireExtended(const LOCKTAG *locktag,
923923
/*
924924
* Find or create LOCK and PROCLOCK objects as needed for a new lock
925925
* request.
926+
*
927+
* Returns the PROCLOCK object, or NULL if we failed to create the objects
928+
* for lack of shared memory.
929+
*
930+
* The appropriate partition lock must be held at entry, and will be
931+
* held at exit.
926932
*/
927933
static PROCLOCK *
928934
SetupLockInTable(LockMethod lockMethodTable, PGPROC *proc,
@@ -2265,6 +2271,8 @@ FastPathUnGrantRelationLock(Oid relid, LOCKMODE lockmode)
22652271
* FastPathTransferRelationLocks
22662272
* Transfer locks matching the given lock tag from per-backend fast-path
22672273
* arrays to the shared hash table.
2274+
*
2275+
* Returns true if successful, false if ran out of shared memory.
22682276
*/
22692277
static bool
22702278
FastPathTransferRelationLocks(LockMethod lockMethodTable, const LOCKTAG *locktag,
@@ -2380,6 +2388,7 @@ FastPathGetRelationLockEntry(LOCALLOCK *locallock)
23802388
locallock->hashcode, lockmode);
23812389
if (!proclock)
23822390
{
2391+
LWLockRelease(partitionLock);
23832392
ereport(ERROR,
23842393
(errcode(ERRCODE_OUT_OF_MEMORY),
23852394
errmsg("out of shared memory"),
@@ -3273,9 +3282,6 @@ GetRunningTransactionLocks(int *nlocks)
32733282
for (i = 0; i < NUM_LOCK_PARTITIONS; i++)
32743283
LWLockAcquire(FirstLockMgrLock + i, LW_SHARED);
32753284

3276-
/* Now scan the tables to copy the data */
3277-
hash_seq_init(&seqstat, LockMethodProcLockHash);
3278-
32793285
/* Now we can safely count the number of proclocks */
32803286
els = hash_get_num_entries(LockMethodProcLockHash);
32813287

@@ -3285,6 +3291,9 @@ GetRunningTransactionLocks(int *nlocks)
32853291
*/
32863292
accessExclusiveLocks = palloc(els * sizeof(xl_standby_lock));
32873293

3294+
/* Now scan the tables to copy the data */
3295+
hash_seq_init(&seqstat, LockMethodProcLockHash);
3296+
32883297
/*
32893298
* If lock is a currently granted AccessExclusiveLock then it will have
32903299
* just one proclock holder, so locks are never accessed twice in this
@@ -3829,22 +3838,34 @@ VirtualXactLock(VirtualTransactionId vxid, bool wait)
38293838

38303839
/*
38313840
* OK, we're going to need to sleep on the VXID. But first, we must set
3832-
* up the primary lock table entry, if needed.
3841+
* up the primary lock table entry, if needed (ie, convert the proc's
3842+
* fast-path lock on its VXID to a regular lock).
38333843
*/
38343844
if (proc->fpVXIDLock)
38353845
{
38363846
PROCLOCK *proclock;
38373847
uint32 hashcode;
3848+
LWLockId partitionLock;
38383849

38393850
hashcode = LockTagHashCode(&tag);
3851+
3852+
partitionLock = LockHashPartitionLock(hashcode);
3853+
LWLockAcquire(partitionLock, LW_EXCLUSIVE);
3854+
38403855
proclock = SetupLockInTable(LockMethods[DEFAULT_LOCKMETHOD], proc,
38413856
&tag, hashcode, ExclusiveLock);
38423857
if (!proclock)
3858+
{
3859+
LWLockRelease(partitionLock);
38433860
ereport(ERROR,
38443861
(errcode(ERRCODE_OUT_OF_MEMORY),
38453862
errmsg("out of shared memory"),
38463863
errhint("You might need to increase max_locks_per_transaction.")));
3864+
}
38473865
GrantLock(proclock->tag.myLock, proclock, ExclusiveLock);
3866+
3867+
LWLockRelease(partitionLock);
3868+
38483869
proc->fpVXIDLock = false;
38493870
}
38503871

0 commit comments

Comments
 (0)