1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 106 107 108 109 110 111 112 113 114 115 116 117 118 119 120 121 122 123 124 125 126 127 128 129 130 131 132 133 134 135 136 137 138 139 140 141 142 143 144 145 146 147 148 149 150 151 152 153 154 155 156 157 158 159 160 161 162 163 164 165 166 167 168 169 170 171 172 173 174 175 176 177 178 179 180 181 182 183 184 185 186 187 188 189 190 191 192 193 194 195 196 197 198 199 200 201 202 203 204 205 206 207 208 209 210
|
/****************************************************************
* *
* Copyright (c) 2005-2024 Fidelity National Information *
* Services, Inc. and/or its subsidiaries. All rights reserved. *
* *
* This source code contains the intellectual property *
* of its copyright holder(s), and is made available *
* under a license. If you do not know the terms of *
* the license, please stop and do not read further. *
* *
****************************************************************/
#include "mdef.h"
#include <sys/sem.h>
#include <sys/shm.h>
#include "errno.h"
#include "gtm_ipc.h"
#include "gtm_stdlib.h"
#include "gtm_string.h"
#include "gtm_stat.h"
#include "gtm_fcntl.h"
#include "error.h"
#include "send_msg.h"
#include "gtmio.h"
#include "iosp.h"
#include "gdsroot.h"
#include "v15_gdsroot.h"
#include "gtm_facility.h"
#include "fileinfo.h"
#include "gdsbt.h"
#include "v15_gdsbt.h"
#include "gdsfhead.h"
#include "v15_gdsfhead.h"
#include "gdsblk.h"
#include "gtm_c_stack_trace.h"
#include "eintr_wrappers.h"
#include "eintr_wrapper_semop.h"
#include "hugetlbfs_overrides.h"
#include "mu_all_version_standalone.h"
#ifdef __MVS__
#include "gtm_zos_io.h"
#endif
static int ftok_ids[FTOK_ID_CNT] = {1, 43, 43};
static int ftok_ver[FTOK_ID_CNT] = {0, 0, 1};
error_def(ERR_MUSTANDALONE);
error_def(ERR_DBOPNERR);
error_def(ERR_FTOKKEY);
error_def(ERR_SEMID);
error_def(ERR_SYSCALL);
error_def(ERR_TEXT);
/* Aquire semaphores that on on all V4.x releases are the access control semaphores. In pre V4.2 releases
they were based on an FTOK of the database name with an ID of '1'. In V4.2 and later, they are based on
the FTOK of the database name with an ID of '43'. Since we do not know which flavor of database we are
dealing with, we must create and acquire both flavors of semaphore and hold them for the duration of
the phase 2 run. But just holding these semaphore is not sufficient to guarrantee standalone access. We
also must attempt to attach to the shared memory for the segment. If it is found, standalone access
is not achieved. Early V4 versions (prior to V4.2) created the shared memory with the same FTOK id as the
semaphore. Later versions would have had the key of the created private section in the file-header. Use
both approaches and fail our attempt if either succeeds.
*/
void mu_all_version_get_standalone(char_ptr_t db_fn, sem_info *sem_inf)
{
int i, rc, save_errno, shmget_errno, fd;
struct sembuf sop[4];
int shmid;
ZOS_ONLY(int realfiletag;)
v15_sgmnt_data v15_csd;
/* Both semaphores must have value 0 and then all will be
incremented to completely lockout any other potential users
until we are done
*/
sop[0].sem_num = 0; sop[0].sem_op = 0; /* First check all semaphore have 0 value */
sop[1].sem_num = 1; sop[1].sem_op = 0;
sop[2].sem_num = 0; sop[2].sem_op = 1; /* Increment all semaphores */
sop[3].sem_num = 1; sop[3].sem_op = 1;
sop[0].sem_flg = sop[1].sem_flg = sop[2].sem_flg = sop[3].sem_flg = SEM_UNDO | IPC_NOWAIT;
memset(sem_inf, 0, (SIZEOF(sem_inf) * FTOK_ID_CNT)); /* Zero all fields so we know what to clean up */
for (i = 0; FTOK_ID_CNT > i; ++i)
{ /* Once through for both ftok key'd semaphores, and both FTOKs for the new semaphore */
if (ftok_ver[i] == 0)
sem_inf[i].ftok_key = FTOK_OLD(db_fn, ftok_ids[i]);
else
sem_inf[i].ftok_key = FTOK(db_fn, ftok_ids[i]);
if (-1 == sem_inf[i].ftok_key)
{
save_errno = errno;
mu_all_version_release_standalone(sem_inf);
RTS_ERROR_CSA_ABT(NULL, VARLSTCNT(8) ERR_SYSCALL, 5, RTS_ERROR_LITERAL("ftok()"), CALLFROM, save_errno);
}
sem_inf[i].sem_id = semget(sem_inf[i].ftok_key, 3, RWDALL | IPC_CREAT | IPC_EXCL);
if (-1 == sem_inf[i].sem_id)
{
save_errno = errno;
mu_all_version_release_standalone(sem_inf);
/* Different platforms seem to make different checks in different order here so if the
semaphore exists but is locked, on some platforms we get EAGAIN, if the semaphore exists
but has fewer semaphores in the set that we are requesting we get EINVAL, but if all that
is ok and the semaphore just already exists, we get EEXIST which is all we wanted to
check anyway..
*/
if (EEXIST == save_errno || EAGAIN == save_errno || EINVAL == save_errno)
/* Semaphore already exists and/or is locked-- likely rundown needed */
RTS_ERROR_CSA_ABT(NULL, VARLSTCNT(9)
MAKE_MSG_TYPE(ERR_MUSTANDALONE, ERROR), 2, RTS_ERROR_TEXT(db_fn),
save_errno, 0, ERR_FTOKKEY, 1, sem_inf[i].ftok_key);
else
RTS_ERROR_CSA_ABT(NULL, VARLSTCNT(12)
ERR_SYSCALL, 5, RTS_ERROR_LITERAL("semget()"), CALLFROM, save_errno, 0,
ERR_FTOKKEY, 1, sem_inf[i].ftok_key);
}
SEMOP(sem_inf[i].sem_id, sop, 4, rc, NO_WAIT);
if (-1 == rc)
{
save_errno = errno;
mu_all_version_release_standalone(sem_inf);
if (EAGAIN == save_errno)
RTS_ERROR_CSA_ABT(NULL, VARLSTCNT(12)
MAKE_MSG_TYPE(ERR_MUSTANDALONE, ERROR), 2, RTS_ERROR_TEXT(db_fn),
save_errno, 0, ERR_FTOKKEY, 1, sem_inf[i].ftok_key,
ERR_SEMID, 1, sem_inf[i].sem_id);
else
RTS_ERROR_CSA_ABT(NULL, VARLSTCNT(15)
ERR_SYSCALL, 5, RTS_ERROR_LITERAL("semop()"), CALLFROM, save_errno, 0,
ERR_FTOKKEY, 1, sem_inf[i].ftok_key, ERR_SEMID, 1, sem_inf[i].sem_id);
}
}
/* First try to access shared memory based on the database FTOK id. Only need to do the ftok returned by the first
FTOK done above as it was the only method where the shared memory and semaphore had the same key.
Detailed description: The first semaphore (for project id 1) is for early V4 versions. In these versions, the
database had the same shmid as the semaphore did. Given that we can try to attach to it and if it is found, we
assume we do not have a standalone lock. The other option is this is a later database so we open it up and pull
the shmid field out of the file-header (it was in the same place in all versions that had the shmid). Whatever
that field is (regardless of version), if we are able to attach to shared memory, then we consider standalone
a failure. This is not a 100% valid check but it is good enough for the few times this will actually be run
(upgrade and downgrade).
*/
shmid = gtm_shmget(sem_inf[0].ftok_key, 0, RWDALL, FALSE, DATABASE_FILE, (char*)db_fn);
shmget_errno = errno;
if (-1 == shmid)
{ /* That failed, second check is if shmid stored in file-header (if any) exists */
fd = OPEN(db_fn, O_RDONLY); /* udi not available so OPENFILE_DB not used */
if (FD_INVALID == fd)
{
save_errno = errno;
mu_all_version_release_standalone(sem_inf);
RTS_ERROR_CSA_ABT(NULL, VARLSTCNT(5) ERR_DBOPNERR, 2, RTS_ERROR_TEXT(db_fn), save_errno);
}
# ifdef __MVS__
if (-1 == gtm_zos_tag_to_policy(fd, TAG_BINARY, &realfiletag))
TAG_POLICY_GTM_PUTMSG(db_fn, errno, realfiletag, TAG_BINARY);
# endif
LSEEKREAD(fd, 0, &v15_csd, SIZEOF(v15_csd), rc);
if (0 != rc)
{
mu_all_version_release_standalone(sem_inf);
RTS_ERROR_CSA_ABT(NULL, VARLSTCNT(8) ERR_SYSCALL, 5, RTS_ERROR_LITERAL("LSEEKREAD()"), CALLFROM, rc);
}
CLOSEFILE_RESET(fd, rc); /* resets "fd" to FD_INVALID */
if (0 != v15_csd.shmid && INVALID_SHMID != v15_csd.shmid)
{
shmid = gtm_shmget(v15_csd.shmid, 0, RWDALL, FALSE, DATABASE_FILE, (char*)db_fn);
if (-1 == shmid)
shmget_errno = errno;
}
}
if (-1 != shmid)
{
mu_all_version_release_standalone(sem_inf);
RTS_ERROR_CSA_ABT(NULL, VARLSTCNT(9) MAKE_MSG_TYPE(ERR_MUSTANDALONE, ERROR), 2, RTS_ERROR_TEXT(db_fn),
shmget_errno, 0, ERR_FTOKKEY, 1, sem_inf[i].ftok_key);
}
}
/* The input array (filled out by mu_all_version_get_standalone()) should tell us which resources we specifically
allocated so we can then free those resources (and no other).
*/
void mu_all_version_release_standalone(sem_info *sem_inf)
{
int i, rc, save_errno;
/* Note that we ignore most errors in this routine as we may get called with the alleged semaphores in
* just about any state.
*/
for (i = 0; FTOK_ID_CNT > i; ++i)
{ /* release/delete any held semaphores in this set */
if (sem_inf[i].sem_id && -1 != sem_inf[i].sem_id)
{
rc = semctl(sem_inf[i].sem_id, 0, IPC_RMID);
if (-1 == rc)
{
save_errno = errno;
if (!SEM_REMOVED(save_errno))
{ /* Don't care if semaphore already removed (probably by a concurrent mupip rundown) */
send_msg_csa(CSA_ARG(NULL) VARLSTCNT(8)
ERR_SYSCALL, 5, RTS_ERROR_LITERAL("semctl(remid)"), CALLFROM, save_errno);
}
}
sem_inf[i].sem_id = 0; /* Clear so we don't repeat if redriven */
}
}
}
|