Skip to content

Commit 01745fb

Browse files
committed
Avoid "you don't own a lock of type ExclusiveLock" in GRANT TABLESPACE.
This WARNING appeared because SearchSysCacheLocked1() read cc_relisshared before catcache initialization, when the field is false unconditionally. On the basis of reading false there, it constructed a locktag as though pg_tablespace weren't relisshared. Only shared catalogs could be affected, and only GRANT TABLESPACE was affected in practice. SearchSysCacheLocked1() callers use one other shared-relation syscache, DATABASEOID. DATABASEOID is initialized by the end of CheckMyDatabase(), making the problem unreachable for pg_database. Back-patch to v13 (all supported versions). This has no known impact before v16, where ExecGrant_common() first appeared. Earlier branches avoid trouble by having a separate ExecGrant_Tablespace() that doesn't use LOCKTAG_TUPLE. However, leaving this unfixed in v15 could ensnare a future back-patch of a SearchSysCacheLocked1() call. Reported by Aya Iwata. Discussion: https://postgr.es/m/OS7PR01MB11964507B5548245A7EE54E70EA212@OS7PR01MB11964.jpnprd01.prod.outlook.com
1 parent 32057a0 commit 01745fb

File tree

3 files changed

+21
-5
lines changed

3 files changed

+21
-5
lines changed

src/backend/utils/cache/syscache.c

+10-5
Original file line numberDiff line numberDiff line change
@@ -1185,11 +1185,9 @@ HeapTuple
11851185
SearchSysCacheLocked1(int cacheId,
11861186
Datum key1)
11871187
{
1188+
CatCache *cache = SysCache[cacheId];
11881189
ItemPointerData tid;
11891190
LOCKTAG tag;
1190-
Oid dboid =
1191-
SysCache[cacheId]->cc_relisshared ? InvalidOid : MyDatabaseId;
1192-
Oid reloid = cacheinfo[cacheId].reloid;
11931191

11941192
/*----------
11951193
* Since inplace updates may happen just before our LockTuple(), we must
@@ -1241,8 +1239,15 @@ SearchSysCacheLocked1(int cacheId,
12411239

12421240
tid = tuple->t_self;
12431241
ReleaseSysCache(tuple);
1244-
/* like: LockTuple(rel, &tid, lockmode) */
1245-
SET_LOCKTAG_TUPLE(tag, dboid, reloid,
1242+
1243+
/*
1244+
* Do like LockTuple(rel, &tid, lockmode). While cc_relisshared won't
1245+
* change from one iteration to another, it may have been a temporary
1246+
* "false" until our first SearchSysCache1().
1247+
*/
1248+
SET_LOCKTAG_TUPLE(tag,
1249+
cache->cc_relisshared ? InvalidOid : MyDatabaseId,
1250+
cache->cc_reloid,
12461251
ItemPointerGetBlockNumber(&tid),
12471252
ItemPointerGetOffsetNumber(&tid));
12481253
(void) LockAcquire(&tag, lockmode, false, false);

src/test/regress/input/tablespace.source

+6
Original file line numberDiff line numberDiff line change
@@ -255,6 +255,12 @@ ALTER INDEX testschema.part_a_idx SET TABLESPACE pg_default;
255255
-- Fail, not empty
256256
DROP TABLESPACE regress_tblspace;
257257

258+
-- Adequate cache initialization before GRANT
259+
\c -
260+
BEGIN;
261+
GRANT ALL ON TABLESPACE regress_tblspace TO PUBLIC;
262+
ROLLBACK;
263+
258264
CREATE ROLE regress_tablespace_user1 login;
259265
CREATE ROLE regress_tablespace_user2 login;
260266
GRANT USAGE ON SCHEMA testschema TO regress_tablespace_user2;

src/test/regress/output/tablespace.source

+5
Original file line numberDiff line numberDiff line change
@@ -720,6 +720,11 @@ ALTER INDEX testschema.part_a_idx SET TABLESPACE pg_default;
720720
-- Fail, not empty
721721
DROP TABLESPACE regress_tblspace;
722722
ERROR: tablespace "regress_tblspace" is not empty
723+
-- Adequate cache initialization before GRANT
724+
\c -
725+
BEGIN;
726+
GRANT ALL ON TABLESPACE regress_tblspace TO PUBLIC;
727+
ROLLBACK;
723728
CREATE ROLE regress_tablespace_user1 login;
724729
CREATE ROLE regress_tablespace_user2 login;
725730
GRANT USAGE ON SCHEMA testschema TO regress_tablespace_user2;

0 commit comments

Comments
 (0)